summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
author_Tradam <[email protected]>2023-09-08 01:29:47 +0000
committerGitHub <[email protected]>2023-09-08 01:29:47 +0000
commit3c76c7f3d5db3f9586a90d03f8fbb02d79de9acd (patch)
treeafbe4b540967223911f7c5de36559b82154f02f3
parent0841165881871ee01b782129be681209aeed2423 (diff)
parent1a72205fe05c2375cfd380dd8381a8460d9ed8d1 (diff)
downloadSTC-modified-3c76c7f3d5db3f9586a90d03f8fbb02d79de9acd.tar.gz
STC-modified-3c76c7f3d5db3f9586a90d03f8fbb02d79de9acd.zip
Merge branch 'stclib:master' into modifiedHEADmodified
-rw-r--r--.github/workflows/workflow.yml4
-rw-r--r--CMakeLists.txt1
-rw-r--r--README.md293
-rw-r--r--docs/algorithm_api.md (renamed from docs/ccommon_api.md)194
-rw-r--r--docs/carc_api.md57
-rw-r--r--docs/cbox_api.md69
-rw-r--r--docs/cdeq_api.md94
-rw-r--r--docs/clist_api.md83
-rw-r--r--docs/cmap_api.md84
-rw-r--r--docs/coroutine_api.md292
-rw-r--r--docs/cpque_api.md38
-rw-r--r--docs/cqueue_api.md41
-rw-r--r--docs/crandom_api.md60
-rw-r--r--docs/crawstr_api.md101
-rw-r--r--docs/cregex_api.md40
-rw-r--r--docs/cset_api.md31
-rw-r--r--docs/csmap_api.md59
-rw-r--r--docs/cspan_api.md295
-rw-r--r--docs/csset_api.md28
-rw-r--r--docs/cstack_api.md47
-rw-r--r--docs/cstr_api.md38
-rw-r--r--docs/csview_api.md166
-rw-r--r--docs/cvec_api.md96
-rw-r--r--docs/pics/Figure_1.pngbin0 -> 60722 bytes
-rw-r--r--docs/pics/coroutine.jpgbin0 -> 81539 bytes
-rw-r--r--include/c11/fmt.h (renamed from include/c11/print.h)119
-rw-r--r--include/stc/algo/coroutine.h117
-rw-r--r--include/stc/algo/crange.h25
-rw-r--r--include/stc/algo/csort.h89
-rw-r--r--include/stc/algo/filter.h35
-rw-r--r--include/stc/algo/raii.h51
-rw-r--r--include/stc/algo/sort.h123
-rw-r--r--include/stc/algorithm.h (renamed from include/stc/calgo.h)2
-rw-r--r--include/stc/carc.h147
-rw-r--r--include/stc/cbits.h104
-rw-r--r--include/stc/cbox.h132
-rw-r--r--include/stc/ccommon.h180
-rw-r--r--include/stc/cdeq.h459
-rw-r--r--include/stc/clist.h239
-rw-r--r--include/stc/cmap.h458
-rw-r--r--include/stc/coroutine.h288
-rw-r--r--include/stc/cpque.h97
-rw-r--r--include/stc/cqueue.h51
-rw-r--r--include/stc/crand.h65
-rw-r--r--include/stc/crandom.h197
-rw-r--r--include/stc/crawstr.h108
-rw-r--r--include/stc/cregex.h37
-rw-r--r--include/stc/cset.h3
-rw-r--r--include/stc/csmap.h423
-rw-r--r--include/stc/cspan.h262
-rw-r--r--include/stc/csset.h3
-rw-r--r--include/stc/cstack.h138
-rw-r--r--include/stc/cstr.h217
-rw-r--r--include/stc/csview.h146
-rw-r--r--include/stc/cvec.h332
-rw-r--r--include/stc/extend.h17
-rw-r--r--include/stc/forward.h79
-rw-r--r--include/stc/priv/cqueue_hdr.h116
-rw-r--r--include/stc/priv/cqueue_imp.h129
-rw-r--r--include/stc/priv/linkage.h (renamed from include/stc/priv/altnames.h)30
-rw-r--r--include/stc/priv/raii.h27
-rw-r--r--include/stc/priv/template.h132
-rw-r--r--include/stc/priv/template2.h14
-rw-r--r--include/stc/utf8.h43
-rw-r--r--misc/benchmarks/external/ankerl/unordered_dense.h418
-rw-r--r--misc/benchmarks/external/emhash/hash_table7.hpp44
-rw-r--r--misc/benchmarks/plotbench/cdeq_benchmark.cpp15
-rw-r--r--misc/benchmarks/plotbench/clist_benchmark.cpp8
-rw-r--r--misc/benchmarks/plotbench/cmap_benchmark.cpp8
-rw-r--r--misc/benchmarks/plotbench/cpque_benchmark.cpp5
-rw-r--r--misc/benchmarks/plotbench/csmap_benchmark.cpp8
-rw-r--r--misc/benchmarks/plotbench/cvec_benchmark.cpp21
-rw-r--r--misc/benchmarks/plotbench/plot.py11
-rw-r--r--misc/benchmarks/plotbench/run_all.bat6
-rw-r--r--misc/benchmarks/plotbench/run_clang.sh12
-rw-r--r--misc/benchmarks/plotbench/run_gcc.sh12
-rw-r--r--misc/benchmarks/plotbench/run_vc.bat6
-rw-r--r--misc/benchmarks/shootout_hashmaps.cpp4
-rw-r--r--misc/benchmarks/various/csort_bench.c46
-rw-r--r--misc/benchmarks/various/cspan_bench.c97
-rw-r--r--misc/benchmarks/various/prng_bench.cpp33
-rw-r--r--misc/benchmarks/various/rust_cmap.c2
-rw-r--r--misc/benchmarks/various/sso_bench.cpp156
-rw-r--r--misc/benchmarks/various/string_bench_STC.cpp7
-rw-r--r--misc/benchmarks/various/string_bench_STD.cpp3
-rw-r--r--misc/examples/algorithms/forfilter.c (renamed from misc/examples/forfilter.c)17
-rw-r--r--misc/examples/algorithms/forloops.c (renamed from misc/examples/forloops.c)134
-rw-r--r--misc/examples/algorithms/random.c42
-rw-r--r--misc/examples/algorithms/shape.c (renamed from misc/examples/shape.c)16
-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)12
-rw-r--r--misc/examples/bitsets/bits2.c (renamed from misc/examples/bits2.c)6
-rw-r--r--misc/examples/bitsets/prime.c (renamed from misc/examples/prime.c)32
-rw-r--r--misc/examples/coread.c39
-rw-r--r--misc/examples/coroutines.c106
-rw-r--r--misc/examples/coroutines/cointerleave.c62
-rw-r--r--misc/examples/coroutines/coread.c41
-rw-r--r--misc/examples/coroutines/coroutines.c112
-rw-r--r--misc/examples/coroutines/cotasks1.c100
-rw-r--r--misc/examples/coroutines/cotasks2.c98
-rw-r--r--misc/examples/coroutines/dining_philosophers.c105
-rw-r--r--misc/examples/coroutines/filetask.c80
-rw-r--r--misc/examples/coroutines/generator.c66
-rw-r--r--misc/examples/coroutines/scheduler.c67
-rw-r--r--misc/examples/coroutines/triples.c75
-rw-r--r--misc/examples/generator.c53
-rw-r--r--misc/examples/hashmaps/birthday.c (renamed from misc/examples/birthday.c)6
-rw-r--r--misc/examples/hashmaps/books.c (renamed from misc/examples/books.c)3
-rw-r--r--misc/examples/hashmaps/hashmap.c (renamed from misc/examples/hashmap.c)1
-rw-r--r--misc/examples/hashmaps/new_map.c (renamed from misc/examples/new_map.c)15
-rw-r--r--misc/examples/hashmaps/phonebook.c (renamed from misc/examples/phonebook.c)4
-rw-r--r--misc/examples/hashmaps/unordered_set.c (renamed from misc/examples/unordered_set.c)3
-rw-r--r--misc/examples/hashmaps/vikings.c (renamed from misc/examples/vikings.c)15
-rw-r--r--misc/examples/linkedlists/intrusive.c (renamed from misc/examples/intrusive.c)9
-rw-r--r--misc/examples/linkedlists/list.c (renamed from misc/examples/list.c)13
-rw-r--r--misc/examples/linkedlists/list_erase.c (renamed from misc/examples/list_erase.c)6
-rw-r--r--misc/examples/linkedlists/list_splice.c (renamed from misc/examples/list_splice.c)9
-rw-r--r--misc/examples/linkedlists/new_list.c70
-rwxr-xr-xmisc/examples/make.sh37
-rw-r--r--misc/examples/mixed/astar.c (renamed from misc/examples/astar.c)8
-rw-r--r--misc/examples/mixed/complex.c (renamed from misc/examples/complex.c)12
-rw-r--r--misc/examples/mixed/convert.c (renamed from misc/examples/convert.c)10
-rw-r--r--misc/examples/mixed/demos.c (renamed from misc/examples/demos.c)31
-rw-r--r--misc/examples/mixed/inits.c (renamed from misc/examples/inits.c)16
-rw-r--r--misc/examples/mixed/read.c (renamed from misc/examples/read.c)10
-rw-r--r--misc/examples/multidim.c68
-rw-r--r--misc/examples/new_list.c68
-rw-r--r--misc/examples/printspan.c57
-rw-r--r--misc/examples/priorityqueues/functor.c (renamed from misc/examples/functor.c)39
-rw-r--r--misc/examples/priorityqueues/new_pque.c (renamed from misc/examples/new_pque.c)8
-rw-r--r--misc/examples/priorityqueues/priority.c (renamed from misc/examples/priority.c)10
-rw-r--r--misc/examples/queues/new_queue.c (renamed from misc/examples/new_queue.c)14
-rw-r--r--misc/examples/queues/queue.c (renamed from misc/examples/queue.c)14
-rw-r--r--misc/examples/random.c45
-rw-r--r--misc/examples/rawptr_elements.c59
-rw-r--r--misc/examples/regularexpressions/regex1.c (renamed from misc/examples/regex1.c)2
-rw-r--r--misc/examples/regularexpressions/regex2.c (renamed from misc/examples/regex2.c)6
-rw-r--r--misc/examples/regularexpressions/regex_match.c (renamed from misc/examples/regex_match.c)13
-rw-r--r--misc/examples/regularexpressions/regex_replace.c (renamed from misc/examples/regex_replace.c)8
-rw-r--r--misc/examples/sidebyside.cpp57
-rw-r--r--misc/examples/smartpointers/arc_containers.c (renamed from misc/examples/arc_containers.c)16
-rw-r--r--misc/examples/smartpointers/arc_demo.c (renamed from misc/examples/arc_demo.c)23
-rw-r--r--misc/examples/smartpointers/arcvec_erase.c (renamed from misc/examples/arcvec_erase.c)16
-rw-r--r--misc/examples/smartpointers/box.c (renamed from misc/examples/box.c)10
-rw-r--r--misc/examples/smartpointers/box2.c (renamed from misc/examples/box2.c)15
-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)31
-rw-r--r--misc/examples/smartpointers/new_sptr.c (renamed from misc/examples/new_sptr.c)19
-rw-r--r--misc/examples/smartpointers/person_arc.c (renamed from misc/examples/person_arc.c)13
-rw-r--r--misc/examples/sortedmaps/csmap_erase.c (renamed from misc/examples/csmap_erase.c)5
-rw-r--r--misc/examples/sortedmaps/csmap_find.c (renamed from misc/examples/csmap_find.c)20
-rw-r--r--misc/examples/sortedmaps/csmap_insert.c (renamed from misc/examples/csmap_insert.c)20
-rw-r--r--misc/examples/sortedmaps/csset_erase.c (renamed from misc/examples/csset_erase.c)6
-rw-r--r--misc/examples/sortedmaps/gauss2.c (renamed from misc/examples/gauss2.c)11
-rw-r--r--misc/examples/sortedmaps/listmap.c (renamed from misc/examples/mmap.c)5
-rw-r--r--misc/examples/sortedmaps/mapmap.c (renamed from misc/examples/mapmap.c)2
-rw-r--r--misc/examples/sortedmaps/multimap.c (renamed from misc/examples/multimap.c)6
-rw-r--r--misc/examples/sortedmaps/new_smap.c (renamed from misc/examples/new_smap.c)9
-rw-r--r--misc/examples/sortedmaps/sorted_map.c (renamed from misc/examples/sorted_map.c)4
-rw-r--r--misc/examples/spans/matmult.c90
-rw-r--r--misc/examples/spans/mdspan.c51
-rw-r--r--misc/examples/spans/multidim.c76
-rw-r--r--misc/examples/spans/printspan.c41
-rw-r--r--misc/examples/spans/submdspan.c44
-rw-r--r--misc/examples/strings/cstr_match.c (renamed from misc/examples/cstr_match.c)5
-rw-r--r--misc/examples/strings/replace.c (renamed from misc/examples/replace.c)3
-rw-r--r--misc/examples/strings/splitstr.c (renamed from misc/examples/splitstr.c)5
-rw-r--r--misc/examples/strings/sso_map.c (renamed from misc/examples/sso_map.c)3
-rw-r--r--misc/examples/strings/sso_substr.c (renamed from misc/examples/sso_substr.c)12
-rw-r--r--misc/examples/strings/sview_split.c (renamed from misc/examples/sview_split.c)4
-rw-r--r--misc/examples/strings/utf8replace_c.c (renamed from misc/examples/utf8replace_c.c)5
-rw-r--r--misc/examples/strings/utf8replace_rs.rs (renamed from misc/examples/utf8replace_rs.rs)0
-rw-r--r--misc/examples/triples.c69
-rw-r--r--misc/examples/vectors/lower_bound.c (renamed from misc/examples/lower_bound.c)11
-rw-r--r--misc/examples/vectors/new_vec.c (renamed from misc/examples/new_vec.c)23
-rw-r--r--misc/examples/vectors/stack.c (renamed from misc/examples/stack.c)6
-rw-r--r--misc/tests/cregex_test.c25
-rw-r--r--misc/tests/cspan_test.c38
-rw-r--r--misc/tests/ctest.h3
-rw-r--r--src/cregex.c126
-rw-r--r--src/libstc.c9
-rw-r--r--src/singleheader.py18
-rw-r--r--src/singleupdate.sh57
-rw-r--r--src/utf8code.c52
185 files changed, 6623 insertions, 4828 deletions
diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml
index 5ceacd43..b1443a0d 100644
--- a/.github/workflows/workflow.yml
+++ b/.github/workflows/workflow.yml
@@ -7,8 +7,8 @@ jobs:
build_and_test:
runs-on: ubuntu-latest
env:
- CFLAGS: -Wall -Wno-unused-function -ggdb3 -fsanitize=address -fsanitize=undefined -fsanitize=pointer-compare -fsanitize=pointer-subtract
- CXXFLAGS: -Wall -Wno-unused-function -ggdb3 -fsanitize=address -fsanitize=undefined -fsanitize=pointer-compare -fsanitize=pointer-subtract
+ CFLAGS: -DSTC_STATIC -Wall -Wno-unused-function -ggdb3 -fsanitize=address -fsanitize=undefined -fsanitize=pointer-compare -fsanitize=pointer-subtract
+ CXXFLAGS: -DSTC_STATIC -Wall -Wno-unused-function -ggdb3 -fsanitize=address -fsanitize=undefined -fsanitize=pointer-compare -fsanitize=pointer-subtract
steps:
- name: 'Checkout'
uses: actions/checkout@v2
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 87662318..3edd39cd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,6 +18,7 @@ if(BUILD_TESTING)
get_filename_component(name "${file}" NAME_WE)
add_executable(${name} ${file})
#target_compile_options(${name} PRIVATE "-pthread")
+ target_compile_options(${name} PRIVATE "-DSTC_STATIC")
if(CMAKE_THREAD_LIBS_INIT)
target_link_libraries(${name} PRIVATE "${CMAKE_THREAD_LIBS_INIT}")
endif()
diff --git a/README.md b/README.md
index 65d00324..d99d8a76 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,8 @@
STC - Smart Template Containers
===============================
-### [Version 4.2](#version-history)
-
+### [Version 4.3 Pre-release](#version-history)
+- See details for breaking changes.
---
Description
-----------
@@ -18,25 +18,26 @@ Containers
- [***cbox*** - **std::unique_ptr** alike type](docs/cbox_api.md)
- [***cbits*** - **std::bitset** alike type](docs/cbits_api.md)
- [***clist*** - **std::forward_list** alike type](docs/clist_api.md)
+- [***cstack*** - **std::stack** alike type](docs/cstack_api.md)
+- [***cvec*** - **std::vector** alike type](docs/cvec_api.md)
- [***cqueue*** - **std::queue** alike type](docs/cqueue_api.md)
+- [***cdeq*** - **std::deque** alike type](docs/cdeq_api.md)
- [***cpque*** - **std::priority_queue** alike type](docs/cpque_api.md)
- [***cmap*** - **std::unordered_map** alike type](docs/cmap_api.md)
- [***cset*** - **std::unordered_set** alike type](docs/cset_api.md)
- [***csmap*** - **std::map** sorted map alike type](docs/csmap_api.md)
- [***csset*** - **std::set** sorted set alike type](docs/csset_api.md)
-- [***cstack*** - **std::stack** alike type](docs/cstack_api.md)
- [***cstr*** - **std::string** alike type](docs/cstr_api.md)
- [***csview*** - **std::string_view** alike type](docs/csview_api.md)
-- [***cspan*** - **std::span/std::mdspan** alike type](docs/cspan_api.md)
-- [***cdeq*** - **std::deque** alike type](docs/cdeq_api.md)
-- [***cvec*** - **std::vector** alike type](docs/cvec_api.md)
+- [***crawstr*** - null-terminated string view type](docs/crawstr_api.md)
+- [***cspan*** - **std::span** + **std::mdspan** alike type](docs/cspan_api.md)
Algorithms
----------
-- [***Ranged for-loops*** - c_foreach, c_forpair, c_forlist](docs/ccommon_api.md#ranged-for-loops)
-- [***Range algorithms*** - c_forrange, crange, c_forfilter](docs/ccommon_api.md#range-algorithms)
-- [***Generic algorithms*** - c_make, c_find_if, c_erase_if, csort, etc.](docs/ccommon_api.md#generic-algorithms)
-- [***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,15 +62,14 @@ 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.
+- **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the [installation section](#installation).
- **No callback functions** - All passed template argument functions/macros are directly called from the implementation, no slow callbacks which requires storage.
- **Compiles with C++ and C99** - C code can be compiled with C++ (container element types must be POD).
- **Forward declaration** - Templated containers may be [forward declared](#forward-declarations) without including the full API/implementation.
@@ -81,9 +81,9 @@ List of contents
1. ***Centralized analysis of template parameters***. The analyser assigns values to all
non-specified template parameters (based on the specified ones) using meta-programming, so
that you don't have to! You may specify a set of "standard" template parameters for each
-container, but as a minimum *only one is required*: `i_val` (+ `i_key` for maps). In this
+container, but as a minimum *only one is required*: `i_key` (+ `i_val` for maps). In this
case, STC assumes that the elements are of basic types. For non-trivial types, additional
-template parameters must be given.
+template parameters must be given.
2. ***Alternative insert/lookup type***. You may specify an alternative type to use for
lookup in containers. E.g., containers with STC string elements (**cstr**) uses `const char*`
as lookup type, so constructing a `cstr` (which may allocate memory) for the lookup
@@ -95,21 +95,21 @@ 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.
-- **find()**: not executed for *forward_list*, *deque*, and *vector* because these c++ containers does not have native *find()*.
+- Iterations and access are repeated 4 times over n elements.
+- access: no entryfor *forward_list*, *deque*, and *vector* because these c++ containers does not have native *find()*.
- **deque**: *insert*: n/3 push_front(), n/3 push_back()+pop_front(), n/3 push_back().
- **map and unordered map**: *insert*: n/2 random numbers, n/2 sequential numbers. *erase*: n/2 keys in the map, n/2 random keys.
@@ -117,8 +117,8 @@ Benchmark notes:
## Naming conventions
- Container names are prefixed by `c`, e.g. `cvec`, `cstr`.
-- Public STC macros are prefixed by `c_`, e.g. `c_foreach`, `c_make`.
-- Template parameter macros are prefixed by `i_`, e.g. `i_val`, `i_type`.
+- Public STC macros are prefixed by `c_`, e.g. `c_foreach`, `c_init`.
+- Template parameter macros are prefixed by `i_`, e.g. `i_key`, `i_type`.
- All containers can be initialized with `{0}`, i.e. no heap allocation used by default init.
- Common types for a container type Con:
- Con
@@ -147,10 +147,10 @@ Benchmark notes:
STC containers have similar functionality to C++ STL standard containers. All containers except for a few,
like **cstr** and **cbits** are generic/templated. No type casting is used, so containers are type-safe like
templated types in C++. However, to specify template parameters with STC, you define them as macros prior to
-including the container:
+including the container.
```c
-#define i_type Floats // Container type name; unless defined name would be cvec_float
-#define i_val float // Container element type
+#define i_type Floats // Container type name (optional); if not defined name would be cvec_float
+#define i_key float // Container element type
#include <stc/cvec.h> // "instantiate" the desired container type
#include <stdio.h>
@@ -164,39 +164,44 @@ int main(void)
for (int i = 0; i < Floats_size(&nums); ++i)
printf(" %g", nums.data[i]);
- Floats_sort(&nums);
-
c_foreach (i, Floats, nums) // Alternative and recommended way to iterate.
printf(" %g", *i.ref); // i.ref is a pointer to the current element.
Floats_drop(&nums); // cleanup memory
}
```
-You may switch to a different container type, e.g. a sorted set (csset):
+Note that `i_val*` template parameters can be used instead of `i_key*` for *non-map* containers.
+
+Switching to a different container type, e.g. a sorted set (csset):
[ [Run this code](https://godbolt.org/z/qznfa65e1) ]
```c
#define i_type Floats
-#define i_val float
+#define i_key float
#include <stc/csset.h> // Use a sorted set instead
#include <stdio.h>
-int main()
+int main(void)
{
Floats nums = {0};
Floats_push(&nums, 30.f);
Floats_push(&nums, 10.f);
Floats_push(&nums, 20.f);
- // already sorted, print the numbers
+ // print the numbers (sorted)
c_foreach (i, Floats, nums)
printf(" %g", *i.ref);
Floats_drop(&nums);
}
```
-For user-defined struct elements, `i_cmp` compare function should be defined as the default `<` and `==`
-only works for integral types. *Alternatively, `#define i_opt c_no_cmp` to disable sorting and searching*. Similarily, if an element destructor `i_valdrop` is defined, `i_valclone` function is required.
+Comparison/lookup functions are enabled by default for associative containers and priority queue (cmap, cset, csmap, csset, cpque). To enable it for the remaining containers, define `i_cmp` or `i_less` (and optionally `i_eq`) on the element type. If the element is an integral type, simply define `i_use_cmp` to use `<` and `==` operators for comparisons.
+
+Note that for `#define i_keyclass Type`, defining `i_use_cmp` means that *Type_cmp()* function is expected to exist (along with *Type_clone()* and *Type_drop()*).
+
+To summarize, `i_use_cmp` is only needed to enable comparison (sort/search) functions when defining cstack, cvec, cqueue, cdeq, carc, cbox. With built-in types, it enables the comparison operators, whereas for keyclass types, it binds comparison to its Type_cmp() function.
+
+If an element destructor `i_keydrop` is defined, `i_keyclone` function is required.
*Alternatively `#define i_opt c_no_clone` to disable container cloning.*
Let's make a vector of vectors, which can be cloned. All of its element vectors will be destroyed when destroying the Vec2D.
@@ -206,12 +211,11 @@ Let's make a vector of vectors, which can be cloned. All of its element vectors
#include <stdio.h>
#define i_type Vec
-#define i_val float
+#define i_key float
#include <stc/cvec.h>
#define i_type Vec2D
-#define i_valclass Vec // Use i_valclass when element type has "members" _clone(), _drop() and _cmp().
-#define i_opt c_no_cmp // Disable cmp (search/sort) for Vec2D because Vec_cmp() is not defined.
+#define i_keyclass Vec // Use i_keyclass instead i_key when element type has "members" _clone(), _drop() and _cmp().
#include <stc/cvec.h>
int main(void)
@@ -237,21 +241,22 @@ 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/j68od14hv) ]
```c
#include <stdio.h>
#define i_key int
-#include <stc/cset.h> // cset_int: unordered set
+#include <stc/cset.h> // cset_int: unordered set (assume i_key is basic type, uses `==` operator)
struct Point { float x, y; };
// Define cvec_pnt with a less-comparison function for Point.
-#define i_val struct Point
-#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y)
+#define i_key struct Point
+#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y) // enable sort/search
#define i_tag pnt
#include <stc/cvec.h> // cvec_pnt: vector of struct Point
-#define i_val int
+#define i_key int
+#define i_use_cmp // enable sort/search. Use native `<` and `==` operators
#include <stc/clist.h> // clist_int: singly linked list
#define i_key int
@@ -333,49 +338,29 @@ After erasing the elements found:
---
## Installation
-Because it is headers-only, headers can simply be included in your program. By default, functions are static
-(some inlined). You may add the *include* folder to the **CPATH** environment variable to
-let GCC, Clang, and TinyC locate the headers.
+STC is primarily a "headers-only" library, so most headers can simply be included in your program. By default,
+all "templated" functions are static (many inlined). If you add the STC *include* folder to the **CPATH**
+environment variable, GCC, Clang, and TinyC will locate the headers automatically.
-If containers are used across several translation units with common instantiated container types, it is
-recommended to build as a "library" with external linking to minimize executable size. To enable this,
-specify `-DSTC_HEADER` as compiler option in your build environment. Next, place all the instantiations
-of the containers used inside a single C-source file as in the example below, and `#define STC_IMPLEMENT` at top.
-You may also cherry-pick shared linking mode on individual containers by `#define i_header` and
-`#define i_implement`, or force static symbols by `#define i_static` before container includes.
-
-As a special case, there may be non-templated functions in templated containers that should be implemented only
-once and if needed. Currently, define `i_extern` before including **clist** for its sorting function, and before
-**cregex** or **utf8** to implement them (global `STC_EXTERN` can alternatively be defined).
-
-It is possible to generate single headers by executing the python script `src/singleheader.py header-file > single`.
-
-Conveniently, `src\libstc.c` implements non-templated functions as shared symbols for **cstr**, **csview**,
-**cbits** and **crand**. When building in shared mode (-DSTC_HEADER), you may include this file in your project,
-or define your own as descibed above.
+The templated container functions are defined with static linking by default, which is normally optimal
+for both performance and compiled binary size. However, some common container type instances, e.g. `cvec_int`
+may be used in several translation units. When they are used in more than 3-4, consider creating a separate
+header file for them [as described here](#1-include-as-a-header-file). Now it will use shared
+linking, so *one* c-file must implement the templated container, e.g.:
```c
-// stc_libs.c
-#define STC_IMPLEMENT
-
-#include <stc/cstr.h>
-#include "Point.h"
-
-#define i_key int
-#define i_val int
-#define i_tag ii
-#include <stc/cmap.h> // cmap_ii: int => int
+#define i_implement
+#include "cvec_int.h"
+```
+The non-templated string type **cstr** uses shared linking by default, but can have static linking instead by
+`#define i_static`. Same for the string-view type **csview**, but most of its functions are static inlined, so
+linking specifications and implementation are only needed for a few lesser used functions.
-#define i_key int64_t
-#define i_tag ix
-#include <stc/cset.h> // cset_ix
+Conveniently, `src\libstc.c` implements all the non-templated functions with shared linking for **cstr**,
+**csview**, **cregex**, **utf8**, and **crand**.
-#define i_val int
-#include <stc/cvec.h> // cvec_int
+As a special case, you can `#define i_import` before including **cregex** or **cstr** to implement the dependent
+**utf8** functions (proper utf8 case conversions, etc.). Or link with src\libstc.
-#define i_val Point
-#define i_tag pnt
-#include <stc/clist.h> // clist_pnt
-```
---
## Specifying template parameters
@@ -383,16 +368,16 @@ Each templated type requires one `#include`, even if it's the same container bas
The template parameters are given by a `#define i_xxxx` statement, where *xxxx* is the parameter name.
The list of template parameters:
-- `i_key` *Type* - Element key type for map/set only. **[required]**.
-- `i_val` *Type* - Element value type. **[required for]** cmap/csmap, it is the mapped value type.
-- `i_cmp` *Func* - Three-way comparison of two *i_keyraw*\* or *i_valraw*\* - **[required for]** non-integral *i_keyraw* elements unless *i_opt* is defined with *c_no_cmp*.
+- `i_key` *Type* - Element key type. **[required]**. Note: `i_val` *may* be used instead for non-maps (not recommended).
+- `i_val` *Type* - Element value type. **[required for]** cmap/csmap as the mapped value type.
+- `i_cmp` *Func* - Three-way comparison of two *i_keyraw*\* or *i_valraw*\* - **[required for]** non-integral *i_keyraw* elements.
- `i_hash` *Func* - Hash function taking *i_keyraw*\* - defaults to *c_default_hash*. **[required for]** ***cmap/cset*** with non-POD *i_keyraw* elements.
- `i_eq` *Func* - Equality comparison of two *i_keyraw*\* - defaults to *!i_cmp*. Companion with *i_hash*.
Properties:
- `i_tag` *Name* - Container type name tag. Defaults to *i_key* name.
- `i_type` *Name* - Full container type name. Alternative to *i_tag*.
-- `i_opt` *Flags* - Boolean properties: may combine *c_no_cmp*, *c_no_clone*, *c_no_atomic*, *c_is_forward*, *c_static*, *c_header* with the *|* separator.
+- `i_opt` *Flags* - Boolean properties: may combine *c_no_clone*, *c_no_atomic*, *c_is_forward*, *c_static*, *c_header* with the *|* separator.
Key:
- `i_keydrop` *Func* - Destroy map/set key func - defaults to empty destructor.
@@ -413,7 +398,7 @@ Specials: Meta-template parameters. Use instead of `i_key` / `i_val`.
If `i_keyraw` is defined, it sets `i_keyto` = *Type_toraw()* and `i_keyfrom` = *Type_from()*.
Only functions required by the container type is required to be defined. E.g.:
- *Type_hash()* and *Type_eq()* are only required by **cmap**, **cset** and smart pointers.
- - *Type_cmp()* is not used by **cstack** and **cmap/cset**, or if *#define i_opt c_no_cmp* is specified.
+ - *Type_cmp()* is not used by **cstack** and **cmap/cset**.
- *Type_clone()* is not used if *#define i_opt c_no_clone* is specified.
- `i_key_str` - Sets `i_keyclass` = *cstr*, `i_tag` = *str*, and `i_keyraw` = *const char*\*. Defines both type convertion
`i_keyfrom`, `i_keyto`, and sets `i_cmp`, `i_eq`, `i_hash` functions with *const char\*\** as argument.
@@ -424,7 +409,6 @@ NB: Do not use when defining carc/cbox types themselves.
- `i_valclass` *Type*, `i_val_str`, `i_val_ssv`, `i_valboxed` - Similar rules as for ***key***.
**Notes**:
-- Instead of defining `i_cmp`, you may define *i_opt c_no_cmp* to disable *searching and sorting* functions.
- Instead of defining `i_*clone`, you may define *i_opt c_no_clone* to disable *clone* functionality.
- For `i_keyclass`, if *i_keyraw* is defined along with it, *i_keyfrom* may also be defined to enable the *emplace*-functions. NB: the signature for ***cmp***, ***eq***, and ***hash*** uses *i_keyraw* as input.
@@ -458,7 +442,7 @@ and non-emplace methods:
#define i_implement // define in ONE file to implement longer functions in cstr
#include <stc/cstr.h>
-#define i_val_str // special macro to enable container of cstr
+#define i_key_str // special macro to enable container of cstr
#include <stc/cvec.h> // vector of string (cstr)
...
cvec_str vec = {0};
@@ -518,36 +502,93 @@ last example on the **cmap** page demonstrates how to specify a map with non-tri
Define `i_type` instead of `i_tag`:
```c
#define i_type MyVec
-#define i_val int
+#define i_key int
#include <stc/cvec.h>
-myvec vec = MyVec_init();
-MyVec_push_back(&vec, 1);
+MyVec vec = {0};
+MyVec_push(&vec, 42);
...
```
---
## Forward declarations
-It is possible to forward declare containers. This is useful when a container is part of a struct,
-but still not expose or include the full implementation / API of the container.
+There are two ways to pre-declare templated containers in header files:
+
+1. Include the templated container type instance as a header file. This also exposes all container
+functions, which can be used by client code. It requires that the element type is complete.
+2. Or, pre-declare the container type only. In this case, the container can be a "private" member of a
+user struct (the container functions will not be available to the user).
+
+### 1. Include as a header file
+
+Create a dedicated header for the container type instance:
+```c
+#ifndef PointVec_H_
+#define PointVec_H_
+// Do not to include user defined headers here if they use templated containers themselves
+
+#define i_type PointVec
+#define i_val struct Point // NB! Element type must be complete at this point!
+#define i_header // Do not implement, only expose API
+#include <stc/cvec.h>
+
+#endif
+```
+Usage from e.g. other headers is trivial:
```c
-// Header file
-#include <stc/forward.h> // only include data structures
-forward_cstack(cstack_pnt, struct Point); // declare cstack_pnt (and cstack_pnt_value, cstack_pnt_iter);
- // struct Point may be an incomplete type.
+#ifndef Dataset_H_
+#define Dataset_H_
+#include "Point.h" // include element type separately
+#include "PointVec.h"
+
typedef struct Dataset {
- cstack_pnt vertices;
- cstack_pnt colors;
+ PointVec vertices;
+ PointVec colors;
} Dataset;
+...
+#endif
+```
-// Implementation
-#define i_is_forward // flag that the container was forward declared.
-#define i_val struct Point
-#define i_tag pnt
-#include <stc/cstack.h>
+Implement PointVec in a c-file:
+```c
+#include "Point.h"
+#define i_implement // define immediately before PointVec.h
+#include "PointVec.h"
+...
```
+### 2. Forward declare only
+```c
+// Dataset.h
+#ifndef Dataset_H_
+#define Dataset_H_
+#include <stc/forward.h> // include various container data structure templates
+
+// declare PointVec. Note: struct Point may be an incomplete/undeclared type.
+forward_cvec(PointVec, struct Point);
+
+typedef struct Dataset {
+ PointVec vertices;
+ PointVec colors;
+} Dataset;
+
+void Dataset_drop(Dataset* self);
+...
+#endif
+```
+Define and use the "private" container in the c-file:
+```c
+// Dataset.c
+#include "Dataset.h"
+#include "Point.h" // Point must be defined here.
+
+#define i_is_forward // flag that the container was forward declared.
+#define i_type PointVec
+#define i_val struct Point
+#include <stc/cvec.h> // Implements PointVec with static linking by default
+...
+```
---
## Per container-instance customization
Sometimes it is useful to extend a container type to store extra data, e.g. a comparison
@@ -564,8 +605,8 @@ It adds a MemoryContext to each container by defining the `i_extend` template pa
the by inclusion of `<stc/extend.h>`.
```c
// stcpgs.h
-#define pgs_malloc(sz) MemoryContextAlloc(c_getcon(self)->memctx, sz)
-#define pgs_calloc(n, sz) MemoryContextAllocZero(c_getcon(self)->memctx, (n)*(sz))
+#define pgs_malloc(sz) MemoryContextAlloc(c_extend(self)->memctx, sz)
+#define pgs_calloc(n, sz) MemoryContextAllocZero(c_extend(self)->memctx, (n)*(sz))
#define pgs_realloc(p, sz) (p ? repalloc(p, sz) : pgs_malloc(sz))
#define pgs_free(p) (p ? pfree(p) : (void)0) // pfree/repalloc does not accept NULL.
@@ -574,12 +615,12 @@ the by inclusion of `<stc/extend.h>`.
#define i_extend MemoryContext memctx;
#include <stc/extend.h>
```
-To use it, define both `i_type` and `i_con` (the container type) before including the custom header:
+To use it, define both `i_type` and `i_base` (the container type) before including the custom header:
```c
#define i_type IMap
+#define i_base csmap
#define i_key int
#define i_val int
-#define i_con csmap
#include "stcpgs.h"
// Note the wrapper struct type is IMap_ext. IMap is accessed by .get
@@ -611,6 +652,29 @@ STC is generally very memory efficient. Memory usage for the different container
---
# Version History
+
+## Version 4.3
+- Breaking changes:
+ - **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including.
+ - Renamed <stc/calgo.h> => `<stc/algorithm.h>`
+ - Moved <stc/algo/coroutine.h> => `<stc/coroutine.h>`
+ - Much improved with some new API and added features.
+ - Removed deprecated <stc/crandom.h>. Use `<stc/crand.h>` with the new API.
+ - Reverted names _unif and _norm back to `_uniform` and `_normal`.
+ - Removed default comparison for **clist**, **cvec** and **cdeq**:
+ - Define `i_use_cmp` to enable comparison for built-in i_key types (<, ==).
+ - Use of `i_keyclass` still expects comparison functions to be defined.
+ - Use of `i_keyboxed` compares stored pointers instead of pointed to values if comparison not defined.
+ - Renamed input enum flags for ***cregex***-functions.
+- **cspan**: Added **column-major** order (fortran) multidimensional spans and transposed views (changed representation of strides).
+- All new faster and smaller **cqueue** and **cdeq** implementations, using a circular buffer.
+- Renamed i_extern => `i_import` (i_extern deprecated).
+ - Define `i_import` before `#include <stc/cstr.h>` will also define full 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. c_make deprecated.
+- Removed deprecated uppercase flow-control macro names.
+- Other smaller additions, bug fixes and improved documentation.
+
## Version 4.2
- New home! And online single headers for https://godbolt.org
- Library: https://github.com/stclib/STC
@@ -620,7 +684,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()
@@ -634,9 +697,9 @@ 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.
- - [csort](include/stc/algo/csort.h) - [fast quicksort](misc/benchmarks/various/csort_bench.c) with custom inline comparison.
+ - [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.
- Some API changes in **cregex** and **cstr**.
@@ -696,10 +759,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: `i_opt` template parameter: compile-time options: `c_no_clone`, `c_no_atomic`, `c_is_forward`; may be combined with `|`
- Added: [**cbox**](docs/cbox_api.md) type: smart pointer, similar to [Rust Box](https://doc.rust-lang.org/rust-by-example/std/box.html) and [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr).
-- Added: [**c_forpair**](docs/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 7a3c3196..63bced22 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
@@ -18,7 +20,7 @@
#define i_tag ii
#include <stc/csmap.h>
...
-csmap_ii map = c_make(csmap_ii, { {23,1}, {3,2}, {7,3}, {5,4}, {12,5} });
+csmap_ii map = c_init(csmap_ii, { {23,1}, {3,2}, {7,3}, {5,4}, {12,5} });
c_foreach (i, csmap_ii, map)
printf(" %d", i.ref->first);
@@ -40,7 +42,7 @@ c_forpair (id, count, csmap_ii, map)
```
### c_forlist
-Iterate compound literal array elements. Additional to `i.ref`, you can access `i.data`, `i.size`, and `i.index` of the input list/element.
+Iterate compound literal array elements. Additional to `i.ref`, you can access `i.size` and `i.index` for the input list/element.
```c
// apply multiple push_backs
c_forlist (i, int, {1, 2, 3})
@@ -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,20 +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_obj(...) // create a compound literal crange object
-crange crange_make(stop); // will generate 0, 1, ..., stop-1
-crange crange_make(start, stop); // will generate start, start+1, ... stop-1
-crange crange_make(start, stop, step); // will generate start, start+step, ... upto-not-including stop
+crange crange_init(stop); // will generate 0, 1, ..., stop-1
+crange crange_init(start, stop); // will generate start, start+1, ... stop-1
+crange crange_init(start, stop, step); // will generate start, start+step, ... upto-not-including stop
// note that step may be negative.
crange_iter crange_begin(crange* self);
crange_iter crange_end(crange* self);
void crange_next(crange_iter* it);
// 1. All primes less than 32:
-crange r1 = crange_make(3, 32, 2);
+crange r1 = crange_init(3, 32, 2);
printf("2"); // first prime
c_forfilter (i, crange, r1, isPrime(*i.ref))
printf(" %lld", *i.ref);
@@ -100,7 +101,8 @@ c_forfilter (i, crange, r1, isPrime(*i.ref))
// 2. The first 11 primes:
printf("2");
-c_forfilter (i, crange, crange_obj(3, INT64_MAX, 2),
+crange range = crange_init(3, INT64_MAX, 2);
+c_forfilter (i, crange, range,
isPrime(*i.ref) &&
c_flt_take(10)
){
@@ -110,12 +112,12 @@ c_forfilter (i, crange, crange_obj(3, INT64_MAX, 2),
```
### 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 |
|:----------------------------------|:-------------------------------------------|
@@ -126,9 +128,9 @@ Iterate a container/range with chained range filtering.
| `c_flt_counter(it)` | Increment current and return count |
| `c_flt_getcount(it)` | Number of items passed skip*/take*/counter |
-[ [Run this example](https://godbolt.org/z/n9aYrYPv8) ]
+[ [Run this example](https://godbolt.org/z/exqYEK6qa) ]
```c
-#include <stc/calgo.h>
+#include <stc/algorithm.h>
#include <stdio.h>
bool isPrime(long long i) {
@@ -137,10 +139,10 @@ bool isPrime(long long i) {
return true;
}
-int main() {
+int main(void) {
// Get 10 prime numbers starting from 1000. Skip the first 15 primes,
// then select every 25th prime (including the initial).
- crange R = crange_make(1001, INT64_MAX, 2); // 1001, 1003, ...
+ crange R = crange_init(1001, INT64_MAX, 2); // 1001, 1003, ...
c_forfilter (i, crange, R,
isPrime(*i.ref) &&
@@ -158,11 +160,11 @@ Note that `c_flt_take()` and `c_flt_takewhile()` breaks the loop on false.
---
## Generic algorithms
-### c_make, c_drop
+### c_init, c_drop
Make any container from an initializer list:
```c
-#define i_val_str // owned cstr string value type
+#define i_key_str // owned cstr string value type
#include <stc/cset.h>
#define i_key int
@@ -170,11 +172,10 @@ Make any container from an initializer list:
#include <stc/cmap.h>
...
// Initializes with const char*, internally converted to cstr!
-cset_str myset = c_make(cset_str, {"This", "is", "the", "story"});
-cset_str myset2 = c_clone(myset);
+cset_str myset = c_init(cset_str, {"This", "is", "the", "story"});
int x = 7, y = 8;
-cmap_int mymap = c_make(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} });
+cmap_int mymap = c_init(cmap_int, { {1, 2}, {3, 4}, {5, 6}, {x, y} });
```
Drop multiple containers of the same type:
```c
@@ -204,22 +205,40 @@ if (it.ref) cmap_str_erase_at(&map, it);
c_erase_if(i, csmap_str, map, cstr_contains(i.ref, "hello"));
```
-### csort - two times faster qsort
+### sort_n_ - two times faster qsort
-When very fast array sorting is required, **csort** is about twice as fast as *qsort()*, and often simpler to use.
+The **sort_n**, **sort_ij** algorithm is about twice as fast as *qsort()*, and often simpler to use.
You may customize `i_tag` and the comparison function `i_cmp` or `i_less`.
There is a [benchmark/test file here](../misc/benchmarks/various/csort_bench.c).
```c
-#define i_val int
-#include <stc/algo/csort.h>
+#define i_key int
+#include <stc/algo/sort.h>
+#include <stdio.h>
-int main() {
- int array[] = {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4};
- csort_int(array, c_arraylen(array));
+int main(void) {
+ int nums[] = {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4};
+ ints_sort_n(nums, c_arraylen(nums)); // note: function name derived from i_key
+ c_forrange (i, c_arraylen(arr)) printf(" %d", arr[i]);
}
```
+Containers with random access may also be sorted. Even sorting cdeq/cqueue (with ring buffer) is
+possible and very fast. Note that `i_more` must be defined to retain specified template parameters for use by sort:
+```c
+#define i_type MyDeq
+#define i_key int
+#define i_more
+#include <stc/cdeq.h> // deque
+#include <stc/algo/sort.h>
+#include <stdio.h>
+int main(void) {
+ MyDeq deq = c_init(MyDeq, {5, 3, 5, 9, 7, 4, 7, 2, 4, 9, 3, 1, 2, 6, 4});
+ MyDeq_sort_n(&deq, MyDeq_size(&deq));
+ c_foreach (i, MyDeq, deq) printf(" %d", *i.ref);
+ MyDeq_drop(&deq);
+}
+```
### c_new, c_delete
@@ -256,12 +275,13 @@ int* ip = c_const_cast(int*, cs); // issues a warning!
### Predefined template parameter functions
-**crawstr** - Non-owned `const char*` "class" element type: `#define i_valclass crawstr`
+**ccharptr** - Non-owning `const char*` "class" element type: `#define i_keyclass ccharptr`
```c
-typedef const char* crawstr;
-int crawstr_cmp(const crawstr* x, const crawstr* y);
-bool crawstr_eq(const crawstr* x, const crawstr* y);
-uint64_t crawstr_hash(const crawstr* x);
+typedef const char* ccharptr;
+int ccharptr_cmp(const ccharptr* x, const ccharptr* y);
+uint64_t ccharptr_hash(const ccharptr* x);
+ccharptr ccharptr_clone(ccharptr sp);
+void ccharptr_drop(ccharptr* x);
```
Default implementations
```c
@@ -273,100 +293,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>
-
-struct triples {
- int n; // input: max number of triples to be generated.
- int a, b, c;
- int cco_state; // required member
-};
-
-bool triples_next(struct triples* i) { // coroutine
- cco_begin(i);
- for (i->c = 5; i->n; ++i->c) {
- for (i->a = 1; i->a < i->c; ++i->a) {
- for (i->b = i->a + 1; i->b < i->c; ++i->b) {
- if ((int64_t)i->a*i->a + (int64_t)i->b*i->b == (int64_t)i->c*i->c) {
- cco_yield(true);
- if (--i->n == 0) cco_return;
- }
- }
- }
- }
- cco_final: // required label
- puts("done");
- cco_end(false);
-}
-
-int gcd(int a, int b) { // greatest common denominator
- while (b) {
- int t = a % b;
- a = b;
- b = t;
- }
- return a;
-}
-
-int main()
-{
- struct triples t = {.n=INT32_MAX};
- int n = 0;
-
- while (triples_next(&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
-**Note**: *cco_yield()* may not be called inside a `switch` statement. Use `if-else-if` constructs instead.
-To resume the coroutine from where it was suspended with *cco_yield()*, simply call the coroutine again.
-
-| | Function / operator | Description |
-|:----------|:-------------------------------------|:----------------------------------------|
-| | `cco_final:` | Obligatory label in coroutine |
-| | `cco_return;` | Early return from the coroutine |
-| `bool` | `cco_alive(ctx)` | Is coroutine in initial or suspended state? |
-| `bool` | `cco_suspended(ctx)` | Is coroutine in suspended state? |
-| `void` | `cco_begin(ctx)` | Begin coroutine block |
-| `rettype` | `cco_end(retval)` | End coroutine block with return value |
-| `void` | `cco_end()` | End coroutine block |
-| `rettype` | `cco_yield(retval)` | Suspend execution and return a value |
-| `void` | `cco_yield()` | Suspend execution |
-| `rettype` | `cco_yield(corocall2, ctx2, retval)` | Yield from another coroutine and return val |
-| `void` | `cco_yield(corocall2, ctx2)` | Yield from another coroutine |
-| | From the caller side: | |
-| `void` | `cco_stop(ctx)` | Next call of coroutine returns `cco_end()` |
-| `void` | `cco_reset(ctx)` | Reset state to initial (for reuse) |
-
---
## RAII scope macros
General ***defer*** mechanics for resource acquisition. These macros allows you to specify the
@@ -385,6 +311,7 @@ The **checkauto** utility described below, ensures that the `c_auto*` macros are
```c
// `c_defer` executes the expression(s) when leaving scope.
+// Note: does not require inclusion of "raii.h".
cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world");
c_defer (cstr_drop(&s1), cstr_drop(&s2))
{
@@ -431,9 +358,10 @@ return ok;
**Example 2**: Load each line of a text file into a vector of strings:
```c
#include <errno.h>
+#define i_implement
#include <stc/cstr.h>
-#define i_val_str
+#define i_key_str
#include <stc/cvec.h>
// receiver should check errno variable
@@ -447,7 +375,7 @@ cvec_str readFile(const char* name)
return vec;
}
-int main()
+int main(void)
{
c_with (cvec_str vec = readFile(__FILE__), cvec_str_drop(&vec))
c_foreach (i, cvec_str, vec)
diff --git a/docs/carc_api.md b/docs/carc_api.md
index 48b64ff0..3e394378 100644
--- a/docs/carc_api.md
+++ b/docs/carc_api.md
@@ -6,29 +6,35 @@ deallocated when the last remaining **carc** owning the object is destroyed with
The object is destroyed using *carc_X_drop()*. A **carc** may also own no objects, in which
case it is called empty. The *carc_X_cmp()*, *carc_X_drop()* methods are defined based on
-the `i_cmp` and `i_valdrop` macros specified. Use *carc_X_clone(p)* when sharing ownership of
+the `i_cmp` and `i_keydrop` macros specified. Use *carc_X_clone(p)* when sharing ownership of
the pointed-to object.
All **carc** functions can be called by multiple threads on different instances of **carc** without
additional synchronization even if these instances are copies and share ownership of the same object.
**carc** uses thread-safe atomic reference counting, through the *carc_X_clone()* and *carc_X_drop()* methods.
-When declaring a container with shared pointers, define `i_valboxed` with the carc type, see example.
+When declaring a container with shared pointers, define `i_keyboxed` with the carc type, see example.
See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr) for a functional reference, or Rust [std::sync::Arc](https://doc.rust-lang.org/std/sync/struct.Arc.html) / [std::rc::Rc](https://doc.rust-lang.org/std/rc/struct.Rc.html).
## Header file and declaration
```c
-#define i_type // full typename of the carc
-#define i_val // value: REQUIRED
-
-#define i_valraw // convertion "raw" type - defaults to i_val
-#define i_valto // convertion func i_val* => i_valraw: REQUIRED IF i_valraw defined.
-#define i_valfrom // convertion func i_valraw => i_val
-
-#define i_opt c_no_atomic // Non-atomic reference counting, like Rust Rc.
-#define i_tag // alternative typename: carc_{i_tag}. i_tag defaults to i_val
+#define i_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_use_cmp // 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.
@@ -36,9 +42,9 @@ See similar c++ class [std::shared_ptr](https://en.cppreference.com/w/cpp/memory
## Methods
```c
carc_X carc_X_init(); // empty shared pointer
-carc_X carc_X_from(i_valraw raw); // create an carc from raw type (available if i_valraw defined by user).
-carc_X carc_X_from_ptr(i_val* p); // create an carc from raw pointer. Takes ownership of p.
-carc_X carc_X_make(i_val val); // create an carc from constructed val object. Faster than from_ptr().
+carc_X carc_X_from(i_keyraw raw); // create an carc from raw type (available if i_keyraw defined by user).
+carc_X carc_X_from_ptr(i_key* p); // create an carc from raw pointer. Takes ownership of p.
+carc_X carc_X_make(i_key key); // create an carc from constructed key object. Faster than from_ptr().
carc_X carc_X_clone(carc_X other); // return other with increased use count
carc_X carc_X_move(carc_X* self); // transfer ownership to receiver; self becomes NULL
@@ -49,7 +55,7 @@ void carc_X_drop(carc_X* self); // destruct (decr
long carc_X_use_count(const carc_X* self);
void carc_X_reset(carc_X* self);
-void carc_X_reset_to(carc_X* self, i_val* p); // assign new carc from ptr. Takes ownership of p.
+void carc_X_reset_to(carc_X* self, i_key* p); // assign new carc from ptr. Takes ownership of p.
uint64_t carc_X_hash(const carc_X* x); // hash value
int carc_X_cmp(const carc_X* x, const carc_X* y); // compares pointer addresses if no `i_cmp` is specified.
@@ -58,19 +64,19 @@ bool carc_X_eq(const carc_X* x, const carc_X* y); // carc_X_cmp() =
// functions on pointed to objects.
-uint64_t carc_X_value_hash(const i_val* x);
-int carc_X_value_cmp(const i_val* x, const i_val* y);
-bool carc_X_value_eq(const i_val* x, const i_val* y);
+uint64_t carc_X_value_hash(const i_key* x);
+int carc_X_value_cmp(const i_key* x, const i_key* y);
+bool carc_X_value_eq(const i_key* x, const i_key* y);
```
## Types and constants
| Type name | Type definition | Used to represent... |
|:------------------|:--------------------------------------------------|:-----------------------|
-| `carc_NULL` | `{NULL, NULL}` | Init nullptr const |
+| `carc_null` | `{0}` | Init nullptr const |
| `carc_X` | `struct { carc_X_value* get; long* use_count; }` | The carc type |
-| `carc_X_value` | `i_val` | The carc element type |
-| `carc_X_raw` | `i_valraw` | Convertion type |
+| `carc_X_value` | `i_key` | The carc element type |
+| `carc_X_raw` | `i_keyraw` | Convertion type |
## Example
@@ -78,6 +84,7 @@ bool carc_X_value_eq(const i_val* x, const i_val* y);
// Create two stacks with carcs to maps.
// Demonstrate sharing and cloning of maps.
// Show elements dropped.
+#define i_implement
#include <stc/cstr.h>
#define i_type Map
@@ -88,15 +95,15 @@ bool carc_X_value_eq(const i_val* x, const i_val* y);
#include <stc/csmap.h>
#define i_type Arc // (atomic) ref. counted pointer
-#define i_val Map
-#define i_valdrop(p) (printf("drop Arc:\n"), Map_drop(p))
+#define i_key Map
+#define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p))
#include <stc/carc.h>
#define i_type Stack
-#define i_valboxed Arc // Note: use i_valboxed for carc or cbox value types
+#define i_keyboxed Arc // Note: use i_keyboxed for carc or cbox value types
#include <stc/cstack.h>
-int main()
+int main(void)
{
Stack s1 = {0}, s2 = {0};
Map *map;
diff --git a/docs/cbox_api.md b/docs/cbox_api.md
index ca4d90da..7d25aed8 100644
--- a/docs/cbox_api.md
+++ b/docs/cbox_api.md
@@ -2,11 +2,11 @@
**cbox** is a smart pointer to a heap allocated value of type X. A **cbox** can
be empty. The *cbox_X_cmp()*, *cbox_X_drop()* methods are defined based on the `i_cmp`
-and `i_valdrop` macros specified. Use *cbox_X_clone(p)* to make a deep copy, which uses the
-`i_valclone` macro if defined.
+and `i_keydrop` macros specified. Use *cbox_X_clone(p)* to make a deep copy, which uses the
+`i_keyclone` macro if defined.
-When declaring a container of **cbox** values, define `i_valboxed` with the
-cbox type instead of defining `i_val`. This will auto-set `i_valdrop`, `i_valclone`, and `i_cmp` using
+When declaring a container of **cbox** values, define `i_keyboxed` with the
+cbox type instead of defining `i_key`. This will auto-set `i_keydrop`, `i_keyclone`, and `i_cmp` using
functions defined by the specified **cbox**.
See similar c++ class [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr) for a functional reference, or Rust [std::boxed::Box](https://doc.rust-lang.org/std/boxed/struct.Box.html)
@@ -14,30 +14,35 @@ 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_val // value: REQUIRED
-#define i_cmp // three-way compare two i_val* : REQUIRED IF i_val is a non-integral type
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED if i_valdrop is defined, unless 'i_opt c_no_clone' is defined.
-
-#define i_valraw // convertion type (lookup): default to {i_val}
-#define i_valto // convertion func i_val* => i_valraw: REQUIRED IF i_valraw defined.
-#define i_valfrom // from-raw func.
-
-#define i_valclass // alt. to i_val: REQUIRES that {i_val}_clone, {i_val}_drop, {i_valraw}_cmp exist.
-#define i_tag // alternative typename: cbox_{i_tag}. i_tag defaults to i_val
+#define i_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_use_cmp // 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.
-Define `i_opt` with `c_no_cmp` if comparison between i_val's is not needed/available. Will then
+Unless `c_use_cmp` is defined, comparison between i_key's is not needed/available. Will then
compare the pointer addresses when used. Additionally, `c_no_clone` or `i_is_fwd` may be defined.
## Methods
```c
cbox_X cbox_X_init(); // return an empty cbox
-cbox_X cbox_X_from(i_valraw raw); // create a cbox from raw type. Avail if i_valraw user defined.
-cbox_X cbox_X_from_ptr(i_val* ptr); // create a cbox from a pointer. Takes ownership of ptr.
-cbox_X cbox_X_make(i_val val); // create a cbox from unowned val object.
+cbox_X cbox_X_from(i_keyraw raw); // create a cbox from raw type. Avail if i_keyraw user defined.
+cbox_X cbox_X_from_ptr(i_key* ptr); // create a cbox from a pointer. Takes ownership of ptr.
+cbox_X cbox_X_make(i_key val); // create a cbox from unowned val object.
cbox_X cbox_X_clone(cbox_X other); // return deep copied clone
cbox_X cbox_X_move(cbox_X* self); // transfer ownership to receiving cbox returned. self becomes NULL.
@@ -46,7 +51,7 @@ void cbox_X_assign(cbox_X* self, cbox_X* moved); // transfer owners
void cbox_X_drop(cbox_X* self); // destruct the contained object and free its heap memory.
void cbox_X_reset(cbox_X* self);
-void cbox_X_reset_to(cbox_X* self, i_val* p); // assign new cbox from ptr. Takes ownership of p.
+void cbox_X_reset_to(cbox_X* self, i_key* p); // assign new cbox from ptr. Takes ownership of p.
uint64_t cbox_X_hash(const cbox_X* x); // hash value
int cbox_X_cmp(const cbox_X* x, const cbox_X* y); // compares pointer addresses if no `i_cmp` is specified.
@@ -55,18 +60,18 @@ bool cbox_X_eq(const cbox_X* x, const cbox_X* y); // cbox_X_cmp() ==
// functions on pointed to objects.
-uint64_t cbox_X_value_hash(const i_val* x);
-int cbox_X_value_cmp(const i_val* x, const i_val* y);
-bool cbox_X_value_eq(const i_val* x, const i_val* y);
+uint64_t cbox_X_value_hash(const i_key* x);
+int cbox_X_value_cmp(const i_key* x, const i_key* y);
+bool cbox_X_value_eq(const i_key* x, const i_key* y);
```
## Types and constants
| Type name | Type definition | Used to represent... |
|:-------------------|:--------------------------------|:------------------------|
-| `cbox_NULL` | `{NULL}` | Init nullptr const |
+| `cbox_null` | `{0}` | Init nullptr const |
| `cbox_X` | `struct { cbox_X_value* get; }` | The cbox type |
-| `cbox_X_value` | `i_val` | The cbox element type |
+| `cbox_X_value` | `i_key` | The cbox element type |
## Example
@@ -77,9 +82,9 @@ void int_drop(int* x) {
}
#define i_type IBox
-#define i_val int
-#define i_valdrop int_drop // optional func, just to display elements destroyed
-#define i_valclone(x) x // must specified when i_valdrop is defined.
+#define i_key int
+#define i_keydrop int_drop // optional func, just to display elements destroyed
+#define i_keyclone(x) x // must specified when i_keydrop is defined.
#include <stc/cbox.h>
#define i_type ISet
@@ -87,12 +92,12 @@ void int_drop(int* x) {
#include <stc/csset.h> // ISet : std::set<std::unique_ptr<int>>
#define i_type IVec
-#define i_valboxed IBox // NB: use i_valboxed instead of i_val
+#define i_keyboxed IBox // NB: use i_keyboxed instead of i_key
#include <stc/cvec.h> // IVec : std::vector<std::unique_ptr<int>>
-int main()
+int main(void)
{
- IVec vec = c_make(Vec, {2021, 2012, 2022, 2015});
+ IVec vec = c_init(Vec, {2021, 2012, 2022, 2015});
ISet set = {0};
c_defer(
IVec_drop(&vec),
diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md
index fc11fe66..3ce58e78 100644
--- a/docs/cdeq_api.md
+++ b/docs/cdeq_api.md
@@ -1,24 +1,27 @@
# STC [cdeq](../include/stc/cdeq.h): Double Ended Queue
![Deque](pics/deque.jpg)
-A **cdeq** is an indexed sequence container that allows fast insertion and deletion at both its beginning and its end. Note that this container is implemented similar to a vector, but has the same performance profile for both *push_back()* and *push_front()* as *cdeq_X_push_back()*. Iterators may be invalidated after push-operations.
+A **cdeq** is an indexed sequence container that allows fast insertion and deletion at both
+its beginning and its end, but has also fast random access to elements. The container is
+implemented as a circular dynamic buffer. Iterators may be invalidated after push-operations.
See the c++ class [std::deque](https://en.cppreference.com/w/cpp/container/deque) for a functional description.
## Header file and declaration
```c
-#define i_type // full typename of the container
-#define i_val // value: REQUIRED
-#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop defined
-
-#define i_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: cdeq_{i_tag}. i_tag defaults to i_val
+#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_use_cmp // 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.
@@ -32,81 +35,76 @@ cdeq_X cdeq_X_clone(cdeq_X deq);
void cdeq_X_clear(cdeq_X* self);
void cdeq_X_copy(cdeq_X* self, const cdeq_X* other);
-cdeq_X_iter cdeq_X_copy_range(cdeq_X* self, i_val* pos, const i_val* p1, const i_val* p2);
bool cdeq_X_reserve(cdeq_X* self, intptr_t cap);
void cdeq_X_shrink_to_fit(cdeq_X* self);
-void cdeq_X_drop(cdeq_X* self); // destructor
+void cdeq_X_drop(cdeq_X* self); // destructor
bool cdeq_X_empty(const cdeq_X* self);
intptr_t cdeq_X_size(const cdeq_X* self);
intptr_t cdeq_X_capacity(const cdeq_X* self);
const cdeq_X_value* cdeq_X_at(const cdeq_X* self, intptr_t idx);
-const cdeq_X_value* cdeq_X_get(const cdeq_X* self, i_valraw raw); // return NULL if not found
-cdeq_X_value* cdeq_X_get_mut(cdeq_X* self, i_valraw raw); // mutable get
-cdeq_X_iter cdeq_X_find(const cdeq_X* self, i_valraw raw);
-cdeq_X_iter cdeq_X_find_in(cdeq_X_iter i1, cdeq_X_iter i2, i_valraw raw); // return cvec_X_end() if not found
+cdeq_X_value* cdeq_X_at_mut(cdeq_X* self, intptr_t idx);
+const cdeq_X_value* cdeq_X_get(const cdeq_X* self, i_keyraw raw); // return NULL if not found
+cdeq_X_value* cdeq_X_get_mut(cdeq_X* self, i_keyraw raw); // mutable get
+cdeq_X_iter cdeq_X_find(const cdeq_X* self, i_keyraw raw);
+cdeq_X_iter cdeq_X_find_in(cdeq_X_iter i1, cdeq_X_iter i2, i_keyraw raw); // return cvec_X_end() if not found
cdeq_X_value* cdeq_X_front(const cdeq_X* self);
cdeq_X_value* cdeq_X_back(const cdeq_X* self);
-cdeq_X_value* cdeq_X_push_front(cdeq_X* self, i_val value);
-cdeq_X_value* cdeq_X_emplace_front(cdeq_X* self, i_valraw raw);
+cdeq_X_value* cdeq_X_push_front(cdeq_X* self, i_key value);
+cdeq_X_value* cdeq_X_emplace_front(cdeq_X* self, i_keyraw raw);
void cdeq_X_pop_front(cdeq_X* self);
+cdeq_X_value cdeq_X_pull_front(cdeq_X* self); // move out front element
-cdeq_X_value* cdeq_X_push_back(cdeq_X* self, i_val value);
-cdeq_X_value* cdeq_X_push(cdeq_X* self, i_val value); // alias for push_back()
-cdeq_X_value* cdeq_X_emplace_back(cdeq_X* self, i_valraw raw);
-cdeq_X_value* cdeq_X_emplace(cdeq_X* self, i_valraw raw); // alias for emplace_back()
+cdeq_X_value* cdeq_X_push_back(cdeq_X* self, i_key value);
+cdeq_X_value* cdeq_X_push(cdeq_X* self, i_key value); // alias for push_back()
+cdeq_X_value* cdeq_X_emplace_back(cdeq_X* self, i_keyraw raw);
+cdeq_X_value* cdeq_X_emplace(cdeq_X* self, i_keyraw raw); // alias for emplace_back()
void cdeq_X_pop_back(cdeq_X* self);
+cdeq_X_value cdeq_X_pull_back(cdeq_X* self); // move out last element
-cdeq_X_iter cdeq_X_insert(cdeq_X* self, intptr_t idx, i_val value); // move value
-cdeq_X_iter cdeq_X_insert_n(cdeq_X* self, intptr_t idx, const i_val[] arr, intptr_t n); // move arr values
-cdeq_X_iter cdeq_X_insert_at(cdeq_X* self, cdeq_X_iter it, i_val value); // move value
-cdeq_X_iter cdeq_X_insert_range(cdeq_X* self, i_val* pos,
- const i_val* p1, const i_val* p2);
+cdeq_X_iter cdeq_X_insert_n(cdeq_X* self, intptr_t idx, const i_key[] arr, intptr_t n); // move values
+cdeq_X_iter cdeq_X_insert_at(cdeq_X* self, cdeq_X_iter it, i_key value); // move value
+cdeq_X_iter cdeq_X_insert_uninit(cdeq_X* self, intptr_t idx, intptr_t n); // uninitialized data
+ // copy values:
+cdeq_X_iter cdeq_X_emplace_n(cdeq_X* self, intptr_t idx, const i_keyraw[] arr, intptr_t n);
+cdeq_X_iter cdeq_X_emplace_at(cdeq_X* self, cdeq_X_iter it, i_keyraw raw);
-cdeq_X_iter cdeq_X_emplace_n(cdeq_X* self, intptr_t idx, const i_valraw[] arr, intptr_t n); // clone values
-cdeq_X_iter cdeq_X_emplace_at(cdeq_X* self, cdeq_X_iter it, i_valraw raw);
-cdeq_X_iter cdeq_X_emplace_range(cdeq_X* self, i_val* pos,
- const i_valraw* p1, const i_valraw* p2);
-
-cdeq_X_iter cdeq_X_erase_n(cdeq_X* self, intptr_t idx, intptr_t n);
+void cdeq_X_erase_n(cdeq_X* self, intptr_t idx, intptr_t n);
cdeq_X_iter cdeq_X_erase_at(cdeq_X* self, cdeq_X_iter it);
cdeq_X_iter cdeq_X_erase_range(cdeq_X* self, cdeq_X_iter it1, cdeq_X_iter it2);
-cdeq_X_iter cdeq_X_erase_range_p(cdeq_X* self, i_val* p1, i_val* p2);
-
-void cdeq_X_sort(cdeq_X* self);
-void cdeq_X_sort_range(cdeq_X_iter i1, cdeq_X_iter i2,
- int(*cmp)(const i_val*, const i_val*));
cdeq_X_iter cdeq_X_begin(const cdeq_X* self);
cdeq_X_iter cdeq_X_end(const cdeq_X* self);
void cdeq_X_next(cdeq_X_iter* it);
-cdeq_X_iter cdeq_X_advance(cdeq_X_iter it, size_t n);
+cdeq_X_iter cdeq_X_advance(cdeq_X_iter it, intptr_t n);
-cdeq_X_raw cdeq_X_value_toraw(cdeq_X_value* pval);
+bool cdeq_X_eq(const cdeq_X* c1, const cdeq_X* c2); // require i_eq/i_cmp/i_less.
cdeq_X_value cdeq_X_value_clone(cdeq_X_value val);
+cdeq_X_raw cdeq_X_value_toraw(const cdeq_X_value* pval);
+void cdeq_X_value_drop(cdeq_X_value* pval);
```
## Types
| Type name | Type definition | Used to represent... |
|:-------------------|:------------------------------------|:-----------------------|
-| `cdeq_X` | `struct { cdeq_X_value* data; }` | The cdeq type |
-| `cdeq_X_value` | `i_val` | The cdeq value type |
-| `cdeq_X_raw` | `i_valraw` | The raw value type |
-| `cdeq_X_iter` | `struct { cdeq_X_value* ref; }` | The iterator type |
+| `cdeq_X` | `struct { cdeq_X_value* data; }` | The cdeq type |
+| `cdeq_X_value` | `i_key` | The cdeq value type |
+| `cdeq_X_raw` | `i_keyraw` | The raw value type |
+| `cdeq_X_iter` | `struct { cdeq_X_value* ref; }` | The iterator type |
## Examples
```c
-#define i_val int
+#define i_key int
#define i_tag i
#include <stc/cdeq.h>
#include <stdio.h>
-int main() {
+int main(void) {
cdeq_i q = cdeq_i_init();
cdeq_i_push_front(&q, 10);
c_foreach (i, cdeq_i, q)
diff --git a/docs/clist_api.md b/docs/clist_api.md
index a1dbe105..a24d813b 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_val})
-#define i_val // value: REQUIRED
-#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop defined
-
-#define i_valraw // convertion "raw" type (default: {i_val})
-#define i_valto // convertion func i_val* => i_valraw
-#define i_valfrom // convertion func i_valraw => i_val
-#define i_tag // alternative typename: cpque_{i_tag}. i_tag defaults to i_val
+#define i_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_use_cmp // 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>
```
@@ -53,50 +54,53 @@ intptr_t clist_X_count(const clist_X* list);
clist_X_value* clist_X_back(const clist_X* self);
clist_X_value* clist_X_front(const clist_X* self);
-void clist_X_push_back(clist_X* self, i_val value); // note: no pop_back()
-void clist_X_push_front(clist_X* self, i_val value);
-void clist_X_push(clist_X* self, i_val value); // alias for push_back()
+void clist_X_push_back(clist_X* self, i_key value); // note: no pop_back()
+void clist_X_push_front(clist_X* self, i_key value);
+void clist_X_push(clist_X* self, i_key value); // alias for push_back()
-void clist_X_emplace_back(clist_X* self, i_valraw raw);
-void clist_X_emplace_front(clist_X* self, i_valraw raw);
-void clist_X_emplace(clist_X* self, i_valraw raw); // alias for emplace_back()
+void clist_X_emplace_back(clist_X* self, i_keyraw raw);
+void clist_X_emplace_front(clist_X* self, i_keyraw raw);
+void clist_X_emplace(clist_X* self, i_keyraw raw); // alias for emplace_back()
-clist_X_iter clist_X_insert_at(clist_X* self, clist_X_iter it, i_val value); // return iter to new elem
-clist_X_iter clist_X_emplace_at(clist_X* self, clist_X_iter it, i_valraw raw);
+clist_X_iter clist_X_insert_at(clist_X* self, clist_X_iter it, i_key value); // return iter to new elem
+clist_X_iter clist_X_emplace_at(clist_X* self, clist_X_iter it, i_keyraw raw);
void clist_X_pop_front(clist_X* self);
clist_X_iter clist_X_erase_at(clist_X* self, clist_X_iter it); // return iter after it
clist_X_iter clist_X_erase_range(clist_X* self, clist_X_iter it1, clist_X_iter it2);
-intptr_t clist_X_remove(clist_X* self, i_valraw raw); // removes all matches
+intptr_t clist_X_remove(clist_X* self, i_keyraw raw); // removes all matches
clist_X clist_X_split_off(clist_X* self, clist_X_iter i1, clist_X_iter i2); // split off [i1, i2)
clist_X_iter clist_X_splice(clist_X* self, clist_X_iter it, clist_X* other); // return updated valid it
clist_X_iter clist_X_splice_range(clist_X* self, clist_X_iter it, // return updated valid it
clist_X* other, clist_X_iter it1, clist_X_iter it2);
-clist_X_iter clist_X_find(const clist_X* self, i_valraw raw);
-clist_X_iter clist_X_find_in(clist_X_iter it1, clist_X_iter it2, i_valraw raw);
-const i_val* clist_X_get(const clist_X* self, i_valraw raw);
-i_val* clist_X_get_mut(clist_X* self, i_valraw raw);
+clist_X_iter clist_X_find(const clist_X* self, i_keyraw raw);
+clist_X_iter clist_X_find_in(clist_X_iter it1, clist_X_iter it2, i_keyraw raw);
+const i_key* clist_X_get(const clist_X* self, i_keyraw raw);
+i_key* clist_X_get_mut(clist_X* self, i_keyraw raw);
void clist_X_reverse(clist_X* self);
void clist_X_sort(clist_X* self);
void clist_X_sort_with(clist_X* self, int(*cmp)(const clist_X_value*, const clist_X_value*));
// Node API
-clist_X_node* clist_X_get_node(clist_X_value* val); // get the enclosing node
+clist_X_node* clist_X_get_node(clist_X_value* val); // get enclosing node
clist_X_value* clist_X_push_back_node(clist_X* self, clist_X_node* node);
clist_X_value* clist_X_insert_after_node(clist_X* self, clist_X_node* ref, clist_X_node* node);
-clist_X_node* clist_X_unlink_after_node(clist_X* self, clist_X_node* ref); // return the unlinked node
+clist_X_node* clist_X_unlink_after_node(clist_X* self, clist_X_node* ref); // return unlinked node
+clist_X_node* clist_X_unlink_front_node(clist_X* self); // return unlinked node
void clist_X_erase_after_node(clist_X* self, clist_X_node* node);
clist_X_iter clist_X_begin(const clist_X* self);
clist_X_iter clist_X_end(const clist_X* self);
void clist_X_next(clist_X_iter* it);
-clist_X_iter clist_X_advance(clist_X_iter it, size_t n); // return n elements ahead.
+clist_X_iter clist_X_advance(clist_X_iter it, size_t n); // return n elements ahead.
-clist_X_raw clist_X_value_toraw(clist_X_value* pval);
+bool clist_X_eq(const clist_X* c1, const clist_X* c2); // equality test
clist_X_value clist_X_value_clone(clist_X_value val);
+clist_X_raw clist_X_value_toraw(const clist_X_value* pval);
+void clist_X_value_drop(clist_X_value* pval);
```
## Types
@@ -105,8 +109,8 @@ clist_X_value clist_X_value_clone(clist_X_value val);
|:--------------------|:------------------------------------|:-----------------------------------------|
| `clist_X` | `struct { clist_X_node* last; }` | The clist type |
| `clist_X_node` | `struct { clist_X_node* next; clist_X_value value; }` | The clist node type |
-| `clist_X_value` | `i_val` | The clist element type |
-| `clist_X_raw` | `i_valraw` | clist raw value type |
+| `clist_X_value` | `i_key` | The clist element type |
+| `clist_X_raw` | `i_keyraw` | clist raw value type |
| `clist_X_iter` | `struct { clist_value *ref; ... }` | clist iterator |
## Example
@@ -114,14 +118,13 @@ clist_X_value clist_X_value_clone(clist_X_value val);
Interleave *push_front()* / *push_back()* then *sort()*:
```c
#define i_type DList
-#define i_val double
-#define i_extern // link with sort() fn.
+#define i_key double
#include <stc/clist.h>
#include <stdio.h>
-int main() {
- DList list = c_make(DList, {10., 20., 30., 40., 50., 60., 70., 80., 90.});
+int main(void) {
+ DList list = c_init(DList, {10., 20., 30., 40., 50., 60., 70., 80., 90.});
c_forrange (i, 1, 10) {
if (i & 1) DList_push_front(&list, (double) i);
@@ -152,14 +155,14 @@ Use of *erase_at()* and *erase_range()*:
```c
// erasing from clist
#define i_tag i
-#define i_val int
+#define i_key int
#include <stc/clist.h>
#include <stdio.h>
-int main ()
+int main(void)
{
- clist_i L = c_make(clist_i, {10, 20, 30, 40, 50});
+ clist_i L = c_init(clist_i, {10, 20, 30, 40, 50});
// 10 20 30 40 50
clist_i_iter it = clist_i_begin(&L); // ^
clist_i_next(&it);
@@ -187,14 +190,14 @@ mylist contains: 10 30
Splice `[30, 40]` from *L2* into *L1* before `3`:
```c
#define i_tag i
-#define i_val int
+#define i_key int
#include <stc/clist.h>
#include <stdio.h>
-int main() {
- clist_i L1 = c_make(clist_i, {1, 2, 3, 4, 5});
- clist_i L2 = c_make(clist_i, {10, 20, 30, 40, 50});
+int main(void) {
+ clist_i L1 = c_init(clist_i, {1, 2, 3, 4, 5});
+ clist_i L2 = c_init(clist_i, {10, 20, 30, 40, 50});
clist_i_iter i = clist_i_advance(clist_i_begin(&L1), 2);
clist_i_iter j1 = clist_i_advance(clist_i_begin(&L2), 2), j2 = clist_i_advance(j1, 2);
diff --git a/docs/cmap_api.md b/docs/cmap_api.md
index d2a94ee8..8e29efe1 100644
--- a/docs/cmap_api.md
+++ b/docs/cmap_api.md
@@ -9,34 +9,33 @@ hashing (aka open addressing) with linear probing, and without leaving tombstone
***Iterator invalidation***: References and iterators are invalidated after erase. No iterators are invalidated after insert,
unless the hash-table need to be extended. The hash table size can be reserved prior to inserts if the total max size is known.
-The order of elements is preserved after erase and insert. This makes it possible to erase individual elements while iterating
-through the container by using the returned iterator from *erase_at()*, which references the next element.
+The order of elements may not be preserved after erase. It is still possible to erase elements when iterating through
+the container by setting the iterator to the value returned from *erase_at()*, which references the next element. Note that a small number of elements may be visited twice when doing this, but all elements will be visited.
See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/container/unordered_map) for a functional description.
## 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_ssize // internal; default int32_t. If defined, 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.
@@ -72,7 +71,8 @@ cmap_X_result cmap_X_insert_or_assign(cmap_X* self, i_key key, i_val map
cmap_X_result cmap_X_push(cmap_X* self, cmap_X_value entry); // similar to insert
cmap_X_result cmap_X_emplace(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // no change if rkey in map
-cmap_X_result cmap_X_emplace_or_assign(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update
+cmap_X_result cmap_X_emplace_or_assign(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update mapped
+cmap_X_result cmap_X_emplace_key(cmap_X* self, i_keyraw rkey); // see example 1.
int cmap_X_erase(cmap_X* self, i_keyraw rkey); // return 0 or 1
cmap_X_iter cmap_X_erase_at(cmap_X* self, cmap_X_iter it); // return iter after it
@@ -86,13 +86,14 @@ cmap_X_iter cmap_X_advance(cmap_X_iter it, cmap_X_ssize n);
cmap_X_value cmap_X_value_clone(cmap_X_value val);
cmap_X_raw cmap_X_value_toraw(cmap_X_value* pval);
```
-Helpers:
+Free helper functions:
```c
-uint64_t c_default_hash(const X *obj); // macro, calls cfasthash(obj, sizeof *obj)
-uint64_t cstrhash(const char *str); // string hash funcion, uses strlen()
-uint64_t cfasthash(const void *data, intptr_t len); // base hash function
+uint64_t stc_hash(const void *data, intptr_t len); // base hash function
+uint64_t stc_strhash(const char *str); // string hash funcion, uses strlen()
+uint64_t stc_nextpow2(intptr_t i); // get next power of 2 >= i
-// equalto template parameter functions:
+// hash/equal template default functions:
+uint64_t c_default_hash(const X *obj); // macro, calls stc_hash(obj, sizeof *obj)
bool c_default_eq(const i_keyraw* a, const i_keyraw* b); // *a == *b
bool c_memcmp_eq(const i_keyraw* a, const i_keyraw* b); // !memcmp(a, b, sizeof *a)
```
@@ -114,16 +115,17 @@ bool c_memcmp_eq(const i_keyraw* a, const i_keyraw* b); // !
## Examples
```c
+#define i_implement
#include <stc/cstr.h>
#define i_key_str
#define i_val_str
#include <stc/cmap.h>
-int main()
+int main(void)
{
// Create an unordered_map of three strings (that map to strings)
- cmap_str umap = c_make(cmap_str, {
+ cmap_str umap = c_init(cmap_str, {
{"RED", "#FF0000"},
{"GREEN", "#00FF00"},
{"BLUE", "#0000FF"}
@@ -138,6 +140,11 @@ int main()
cmap_str_emplace(&umap, "BLACK", "#000000");
cmap_str_emplace(&umap, "WHITE", "#FFFFFF");
+ // Insert only if "CYAN" is not in the map: create mapped value when needed only.
+ cmap_str_result res = cmap_str_emplace_key(&umap, "CYAN");
+ if (res.inserted)
+ res.ref->second = cstr_from("#00FFFF"); // must assign second if key was inserted.
+
// Output values by key
printf("The HEX of color RED is:[%s]\n", cstr_str(cmap_str_at(&umap, "RED")));
printf("The HEX of color BLACK is:[%s]\n", cstr_str(cmap_str_at(&umap, "BLACK")));
@@ -157,13 +164,14 @@ The HEX of color BLACK is:[#000000]
### Example 2
This example uses a cmap with cstr as mapped value.
```c
+#define i_implement
#include <stc/cstr.h>
#define i_type IDMap
#define i_key int
#define i_val_str
#include <stc/cmap.h>
-int main()
+int main(void)
{
uint32_t col = 0xcc7744ff;
@@ -206,7 +214,7 @@ typedef struct { int x, y, z; } Vec3i;
#define i_tag vi
#include <stc/cmap.h>
-int main()
+int main(void)
{
// Define map with defered destruct
cmap_vi vecs = {0};
@@ -241,7 +249,7 @@ typedef struct { int x, y, z; } Vec3i;
#define i_tag iv
#include <stc/cmap.h>
-int main()
+int main(void)
{
cmap_iv vecs = {0}
@@ -267,6 +275,7 @@ Output:
### Example 5: Advanced
Key type is struct.
```c
+#define i_implement
#include <stc/cstr.h>
typedef struct {
@@ -274,7 +283,7 @@ typedef struct {
cstr country;
} Viking;
-#define Viking_init() ((Viking){cstr_NULL, cstr_NULL})
+#define Viking_init() ((Viking){.name={0}, .country={0}})
static inline int Viking_cmp(const Viking* a, const Viking* b) {
int c = cstr_cmp(&a->name, &b->name);
@@ -301,7 +310,7 @@ static inline void Viking_drop(Viking* vk) {
#define i_val int
#include <stc/cmap.h>
-int main()
+int main(void)
{
// Use a HashMap to store the vikings' health points.
Vikings vikings = {0};
@@ -335,6 +344,7 @@ In example 5 we needed to construct a lookup key which allocated strings, and th
In this example we use rawtype feature to make it even simpler to use. Note that we must use the emplace() methods
to add "raw" type entries (otherwise compile error):
```c
+#define i_implement
#include <stc/cstr.h>
typedef struct Viking {
@@ -372,11 +382,11 @@ static inline RViking Viking_toraw(const Viking* vp) {
#define i_keyraw RViking
#define i_keyfrom Viking_from
#define i_opt c_no_clone // disable map cloning
-#define i_hash(rp) (cstrhash(rp->name) ^ cstrhash(rp->country))
+#define i_hash(rp) (stc_strhash(rp->name) ^ stc_strhash(rp->country))
#define i_val int
#include <stc/cmap.h>
-int main()
+int main(void)
{
Vikings vikings = {0};
diff --git a/docs/coroutine_api.md b/docs/coroutine_api.md
new file mode 100644
index 00000000..b917e0a1
--- /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_final:` | Label for cleanup position in coroutine |
+| `bool` | `cco_done(co)` | Is coroutine done? |
+| | `cco_routine(co) {}` | The coroutine scope |
+| | `cco_yield();` | Yield/suspend execution (return CCO_YIELD)|
+| | `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_await_call(cocall);` | Await for subcoro to finish (returns its ret value) |
+| | `cco_await_call(cocall, retbit);` | Await for subcoro's return to be in (retbit \| CCO_DONE) |
+| | `cco_return;` | Return from coroutine (inside cco_routine) |
+| | Task objects: | |
+| | `cco_task_struct(Name, ...);` | Define a coroutine task struct |
+| | `cco_await_task(task, cco_runtime* rt);`| Await for task to finish |
+| | `cco_await_task(task, rt, retbit);` | Await for task's return to be in (retbit \| CCO_DONE) |
+|`cco_result`| `cco_resume_task(task, rt);` | Resume suspended task |
+| | Semaphores: | |
+| | `cco_sem` | Semaphore type |
+| | `cco_await_sem(sem)` | Await for the semaphore count > 0 |
+| `cco_sem` | `cco_sem_from(long value)` | Create semaphore |
+| | `cco_sem_set(sem, long value)` | Set semaphore value |
+
+| | `cco_sem_release(sem)` | Signal the semaphore (count += 1) |
+| | Timers: | |
+| | `cco_timer` | Timer type |
+| | `cco_await_timer(tm, double sec)` | Await secs for timer to expire (usec prec.)|
+| | `cco_timer_start(tm, double sec)` | Start timer for secs duration |
+| | `cco_timer_restart(tm)` | Restart timer with same duration |
+| `bool` | `cco_timer_expired(tm)` | Return true if timer is expired |
+| `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_blocking_call(cocall) {}` | Run blocking until cocall is finished |
+| | `cco_blocking_task(task) {}` | Run blocking until task is finished |
+| | `cco_blocking_task(task, rt, STACKSZ) {}`| Run blocking until task is finished |
+| | Time functions: | |
+| `double` | `cco_time(void)` | Return secs with usec prec. since Epoch |
+| | `cco_sleep(double sec)` | Sleep for seconds (msec or usec prec.) |
+
+
+## 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/d5zW3f9Gv) ]
+```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_final if defined, else exit scope.
+ cco_yield();
+ }
+ }
+ }
+ }
+ cco_final:
+ puts("done");
+ }
+ return 0; // CCO_DONE
+}
+
+int main(void) {
+ struct triples co = {.max_c = 25};
+ int n = 0;
+
+ cco_blocking_call(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/a7da9M8P5) ]
+```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_final:
+ 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_blocking_call(gcd1_triples(&co)) {
+ printf("%d: [%d, %d, %d]\n", ++n, co.tri.a, co.tri.b, co.tri.c);
+ }
+}
+```
+When using ***cco_blocking_call()***, the coroutine is continuously resumed after each yield suspension.
+However, this means that it first calls ***gcd1_triples()***, which immediately jumps to after the `cco_yield`
+-statement and calls ***triples()***, which again jumps and resumes after its `cco_yield`-statement. This
+is efficient only when yielding or awaiting from the top- or second-level call like here, but naturally not
+when couroutine calls are more deeply nested or recursive.
+
+The STC coroutine implementation therefore also contains task-objects (`cco_task`), which are base-coroutine
+objects/enclosures. These can be executed using ***cco_blocking_task()*** instead of ***cco_blocking_call()***.
+Inner coroutine calls are done by ***cco_await_task()***, where you may await for a certain return value, normally CCO_YIELD or just CCO_DONE. It uses a stack of pointers of task-enclosures to call the current
+inner-level function directly. The task-objects have the added benefit that coroutines can be managed
+by a scheduler, which is useful when dealing with large numbers of coroutines (like in many games and
+simulations).
+
+Note that these two modes may be mixed, and that for short-lived coroutines (only a few suspends),
+it is often beneficial to call the sub-coroutine directly rather than via ***cco_await_task()***
+(which pushes the task on top of the runtime stack and yields - then executed on next resume).
+
+The following example uses task-objects with 3-levels deep coroutine calls. It emulates an async generator
+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_await_timer(&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 text;
+);
+
+int produce_items(struct produce_items* p, cco_runtime* rt)
+{
+ cco_routine (p) {
+ p->text = cstr_init();
+ p->next.cco_func = next_value;
+ while (true)
+ {
+ // await for CCO_YIELD (or CCO_DONE)
+ cco_await_task(&p->next, rt, CCO_YIELD);
+ cstr_printf(&p->text, "item %d", p->next.val);
+ print_time();
+ printf("produced %s\n", cstr_str(&p->text));
+ cco_yield();
+ }
+ cco_final:
+ cstr_drop(&p->text);
+ 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_await_task(&c->produce, rt, CCO_YIELD);
+ print_time();
+ printf("consumed %s\n", cstr_str(&c->produce.text));
+ }
+ cco_final:
+ cco_stop(&c->produce);
+ cco_resume_task(&c->produce, rt);
+ puts("done consume");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct consume_items consume = {
+ .n = 5,
+ .cco_func = consume_items,
+ };
+ cco_blocking_task(&consume);
+}
+```
diff --git a/docs/cpque_api.md b/docs/cpque_api.md
index 962ee162..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_val})
-#define i_val // value: REQUIRED
-#define i_less // compare two i_val* : REQUIRED IF i_val/i_valraw is a non-integral type
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop defined
+#define i_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_valraw // convertion type
-#define i_valfrom // convertion func i_valraw => i_val
-#define i_valto // convertion func i_val* => i_valraw.
+#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_val
+#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.
@@ -28,7 +28,7 @@ See the c++ class [std::priority_queue](https://en.cppreference.com/w/cpp/contai
```c
cpque_X cpque_X_init(void); // create empty pri-queue.
cpque_X cpque_X_with_capacity(intptr_t cap);
-cpque_X cpque_X_with_size(intptr_t size, i_val null);
+cpque_X cpque_X_with_size(intptr_t size, i_key null);
cpque_X cpque_X_clone(cpque_X pq);
void cpque_X_clear(cpque_X* self);
@@ -39,16 +39,16 @@ void cpque_X_drop(cpque_X* self); // destructor
intptr_t cpque_X_size(const cpque_X* self);
bool cpque_X_empty(const cpque_X* self);
-i_val* cpque_X_top(const cpque_X* self);
+i_key* cpque_X_top(const cpque_X* self);
void cpque_X_make_heap(cpque_X* self); // heapify the vector.
-void cpque_X_push(cpque_X* self, i_val value);
-void cpque_X_emplace(cpque_X* self, i_valraw raw); // converts from raw
+void cpque_X_push(cpque_X* self, i_key value);
+void cpque_X_emplace(cpque_X* self, i_keyraw raw); // converts from raw
void cpque_X_pop(cpque_X* self);
void cpque_X_erase_at(cpque_X* self, intptr_t idx);
-i_val cpque_X_value_clone(i_val value);
+i_key cpque_X_value_clone(i_key value);
```
## Types
@@ -56,30 +56,30 @@ i_val cpque_X_value_clone(i_val value);
| Type name | Type definition | Used to represent... |
|:-------------------|:--------------------------------------|:------------------------|
| `cpque_X` | `struct {cpque_X_value* data; ...}` | The cpque type |
-| `cpque_X_value` | `i_val` | The cpque element type |
+| `cpque_X_value` | `i_key` | The cpque element type |
## Example
```c
#include <stc/crand.h>
#include <stdio.h>
-#define i_val int64_t
+#define i_key int64_t
#define i_cmp -c_default_cmp // min-heap
#define i_tag i
#include <stc/cpque.h>
-int main()
+int main(void)
{
intptr_t N = 10000000;
crand_t rng = crand_init(1234);
- 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 9ea4b148..ba4411b7 100644
--- a/docs/cqueue_api.md
+++ b/docs/cqueue_api.md
@@ -7,16 +7,16 @@ See the c++ class [std::queue](https://en.cppreference.com/w/cpp/container/queue
## Header file and declaration
```c
-#define i_type // container type name (default: cset_{i_key})
-#define i_val // value: REQUIRED
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop defined
+#define i_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_valraw // convertion "raw" type - defaults to i_val
-#define i_valfrom // convertion func i_valraw => i_val
-#define i_valto // convertion func i_val* => i_valraw
+#define i_keyraw <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_val
+#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.
@@ -26,27 +26,36 @@ See the c++ class [std::queue](https://en.cppreference.com/w/cpp/container/queue
```c
cqueue_X cqueue_X_init(void);
+cqueue_X cqueue_X_with_capacity(intptr_t size);
cqueue_X cqueue_X_clone(cqueue_X q);
void cqueue_X_clear(cqueue_X* self);
void cqueue_X_copy(cqueue_X* self, const cqueue_X* other);
+bool cqueue_X_reserve(cqueue_X* self, intptr_t cap);
+void cqueue_X_shrink_to_fit(cqueue_X* self);
void cqueue_X_drop(cqueue_X* self); // destructor
intptr_t cqueue_X_size(const cqueue_X* self);
+intptr_t cqueue_X_capacity(const cqueue_X* self);
bool cqueue_X_empty(const cqueue_X* self);
+
cqueue_X_value* cqueue_X_front(const cqueue_X* self);
cqueue_X_value* cqueue_X_back(const cqueue_X* self);
-cqueue_X_value* cqueue_X_push(cqueue_X* self, i_val value);
-cqueue_X_value* cqueue_X_emplace(cqueue_X* self, i_valraw raw);
-
+cqueue_X_value* cqueue_X_push(cqueue_X* self, i_key value);
+cqueue_X_value* cqueue_X_emplace(cqueue_X* self, i_keyraw raw);
void cqueue_X_pop(cqueue_X* self);
+cqueue_X_value cqueue_X_pull(cqueue_X* self); // move out last element
cqueue_X_iter cqueue_X_begin(const cqueue_X* self);
cqueue_X_iter cqueue_X_end(const cqueue_X* self);
void cqueue_X_next(cqueue_X_iter* it);
+cqueue_X_iter cqueue_X_advance(cqueue_X_iter it, intptr_t n);
-i_val cqueue_X_value_clone(i_val value);
+bool cqueue_X_eq(const cqueue_X* c1, const cqueue_X* c2); // require i_eq/i_cmp/i_less.
+i_key cqueue_X_value_clone(i_key value);
+cqueue_X_raw cqueue_X_value_toraw(const cqueue_X_value* pval);
+void cqueue_X_value_drop(cqueue_X_value* pval);
```
## Types
@@ -54,19 +63,19 @@ i_val cqueue_X_value_clone(i_val value);
| Type name | Type definition | Used to represent... |
|:--------------------|:---------------------|:-------------------------|
| `cqueue_X` | `cdeq_X` | The cqueue type |
-| `cqueue_X_value` | `i_val` | The cqueue element type |
-| `cqueue_X_raw` | `i_valraw` | cqueue raw value type |
+| `cqueue_X_value` | `i_key` | The cqueue element type |
+| `cqueue_X_raw` | `i_keyraw` | cqueue raw value type |
| `cqueue_X_iter` | `cdeq_X_iter` | cqueue iterator |
## Examples
```c
-#define i_val int
+#define i_key int
#define i_tag i
#include <stc/cqueue.h>
#include <stdio.h>
-int main() {
+int main(void) {
cqueue_i Q = cqueue_i_init();
// push() and pop() a few.
diff --git a/docs/crandom_api.md b/docs/crandom_api.md
index 7281b2d7..c6491243 100644
--- a/docs/crandom_api.md
+++ b/docs/crandom_api.md
@@ -1,35 +1,30 @@
# 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
-and state size.
+**crand64** is a very fast PRNG, suited for parallel usage. It is based on *sfc64*, but has a
+different output function and state size. It features a Weyl-sequence as part of its state.
-**sfc64** is the fastest among *pcg*, *xoshiro`**`*, and *lehmer*. It is equally fast 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.
+**crand64** is faster or equally fast as *wyrand*, *xoshiro\*\**, *sfc64*, and *romu_trio*
+with both **clang 16.0** and **gcc 13.1** from the [prng_bench.c](../misc/benchmarks/various/prng_bench.cpp)
+on windows 11, Ryzen 7 5700X. (clang does not optimize *xoshiro\*\** and *sfc64* as well as gcc does).
-**stc64** does not require multiplication or 128-bit integer operations. It has 320 bit state,
-but updates only 256 bit per generated number.
+**crand64** has no jump *function*, but each odd number Weyl-increment (state[4]) starts a new
+unique 2^64 *minimum* length period, i.e. virtually unlimitied number of unique threads.
+In contrast, *wyrand* and *sfc64* have only a (total) minimum period of 2^64 (*romu_trio* has
+no guarantees), and may therefore not be suited for massive parallel usage (for purists).
-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.
+**crand64** does not require multiplication or 128-bit integer operations. It has 320 bit state,
+where 64-bits are constant per instance.
-**stc64** 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.
-
-For more, see the PRNG shootout by Vigna: http://prng.di.unimi.it and a debate between the authors of
-xoshiro and pcg (Vigna/O'Neill) PRNGs: https://www.pcg-random.org/posts/on-vignas-pcg-critique.html
+**crand64** passes *PractRand* (tested up to 8TB output), Vigna's Hamming weight test, and simple
+correlation tests. The 16- and 32-bit variants also passes PractRand up to their size limits.
## Header file
@@ -41,32 +36,33 @@ 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
#include <time.h>
#include <stc/crand.h>
+#define i_implement
#include <stc/cstr.h>
// Declare int -> int sorted map. Uses typetag 'i' for ints.
@@ -75,7 +71,7 @@ double crand_norm(crand_t* rng, crand_norm_t* dist);
#define i_tag i
#include <stc/csmap.h>
-int main()
+int main(void)
{
enum {N = 10000000};
const double Mean = -12.0, StdDev = 6.0, Scale = 74;
@@ -85,17 +81,17 @@ int main()
// 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/crawstr_api.md b/docs/crawstr_api.md
new file mode 100644
index 00000000..b63e532f
--- /dev/null
+++ b/docs/crawstr_api.md
@@ -0,0 +1,101 @@
+# STC [crawstr](../include/stc/crawstr.h): Null-terminated UTF8 String View
+![String](pics/string.jpg)
+
+The type **crawstr** is a ***null-terminated*** string view and refers to a constant contiguous sequence of
+char-elements with the first element of the sequence at position zero. The implementation holds two
+members: a pointer to constant char and a size. See [csview](csview_api.md) for a ***non null-terminated***
+string view/span type.
+
+Because **crawstr** is null-terminated, it can be an efficient replacent for `const char*`. It never
+allocates memory, and therefore need not be destructed. Its lifetime is limited by the source string
+storage. It keeps the length of the string, i.e. no need to call *strlen()* for various operations.
+
+## Header file
+
+All crawstr definitions and prototypes are available by including a single header file.
+
+```c
+#include <stc/crawstr.h>
+```
+## Methods
+
+```c
+crawstr crawstr_from(const char* str); // construct from const char*
+crawstr c_rs(const char literal_only[]); // construct from literal, no strlen()
+
+intptr_t crawstr_size(crawstr rs);
+bool crawstr_empty(crawstr rs); // check if size == 0
+void crawstr_clear(crawstr* self);
+csview crawstr_sv(crawstr rs); // convert to csview type
+
+bool crawstr_equals(crawstr rs, const char* str);
+intptr_t crawstr_find(crawstr rs, const char* str);
+bool crawstr_contains(crawstr rs, const char* str);
+bool crawstr_starts_with(crawstr rs, const char* str);
+bool crawstr_ends_with(crawstr rs, const char* str);
+
+crawstr_iter crawstr_begin(const crawstr* self);
+crawstr_iter crawstr_end(const crawstr* self);
+void crawstr_next(crawstr_iter* it); // utf8 codepoint step, not byte!
+crawstr_iter crawstr_advance(crawstr_iter it, intptr_t n);
+```
+
+#### Helper methods for usage in containers
+```c
+int crawstr_cmp(const crawstr* x, const crawstr* y);
+int crawstr_icmp(const crawstr* x, const crawstr* y); // depends on src/utf8code.c:
+bool crawstr_eq(const crawstr* x, const crawstr* y);
+uint64_t crawstr_hash(const crawstr* x);
+```
+
+#### UTF8 methods
+```c
+ // from utf8.h
+intptr_t utf8_size(const char *s);
+intptr_t utf8_size_n(const char *s, intptr_t nbytes); // number of UTF8 codepoints within n bytes
+const char* utf8_at(const char *s, intptr_t index); // from UTF8 index to char* position
+intptr_t utf8_pos(const char* s, intptr_t index); // from UTF8 index to byte index position
+unsigned utf8_chr_size(const char* s); // UTF8 character size: 1-4
+ // implemented in src/utf8code.c:
+bool utf8_valid(const char* s);
+bool utf8_valid_n(const char* s, intptr_t nbytes);
+uint32_t utf8_decode(utf8_decode_t *d, uint8_t byte); // decode next byte to utf8, return state.
+unsigned utf8_encode(char *out, uint32_t codepoint); // encode unicode cp into out buffer
+uint32_t utf8_peek(const char* s); // codepoint value of character at s
+uint32_t utf8_peek_off(const char* s, int offset); // codepoint value at utf8 pos (may be negative)
+```
+
+## Types
+
+| Type name | Type definition | Used to represent... |
+|:----------------|:---------------------------------------------|:-------------------------|
+| `crawstr` | `struct { const char *str; intptr_t size; }` | The string view type |
+| `crawstr_value` | `const char` | The element type |
+| `crawstr_iter` | `union { crawstr_value *ref; csview chr; }` | UTF8 iterator |
+
+## Example: UTF8 iteration and case conversion
+```c
+#define i_import
+#include <stc/cstr.h>
+#include <stc/crawstr.h>
+
+int main(void)
+{
+ crawstr rs = c_rs("Liberté, égalité, fraternité.");
+ printf("%s\n", rs.str);
+
+ c_foreach (i, crawstr, rs)
+ printf("%.*s ", c_SV(i.chr));
+ puts("");
+
+ cstr str = cstr_toupper_sv(crawstr_sv(rs));
+ printf("%s\n", cstr_str(&str));
+ cstr_drop(&str);
+}
+```
+Output:
+```
+Liberté, égalité, fraternité.
+L i b e r t é , é g a l i t é , f r a t e r n i t é .
+LIBERTÉ, ÉGALITÉ, FRATERNITÉ.
+```
diff --git a/docs/cregex_api.md b/docs/cregex_api.md
index 9a15a869..52476e09 100644
--- a/docs/cregex_api.md
+++ b/docs/cregex_api.md
@@ -12,16 +12,16 @@ The API is simple and includes powerful string pattern matches and replace funct
```c
enum {
// compile-flags
- CREG_C_DOTALL = 1<<0, // dot matches newline too: can be set/overridden by (?s) and (?-s) in RE
- CREG_C_ICASE = 1<<1, // ignore case mode: can be set/overridden by (?i) and (?-i) in RE
+ CREG_DOTALL = 1<<0, // dot matches newline too: can be set/overridden by (?s) and (?-s) in RE
+ CREG_ICASE = 1<<1, // ignore case mode: can be set/overridden by (?i) and (?-i) in RE
// match-flags
- CREG_M_FULLMATCH = 1<<2, // like start-, end-of-line anchors were in pattern: "^ ... $"
- CREG_M_NEXT = 1<<3, // use end of previous match[0] as start of input
- CREG_M_STARTEND = 1<<4, // use match[0] as start+end of input
+ CREG_FULLMATCH = 1<<2, // like start-, end-of-line anchors were in pattern: "^ ... $"
+ CREG_NEXT = 1<<3, // use end of previous match[0] as start of input
+ CREG_STARTEND = 1<<4, // use match[0] as start+end of input
// replace-flags
- CREG_R_STRIP = 1<<5, // only keep the replaced matches, strip the rest
+ CREG_STRIP = 1<<5, // only keep the replaced matches, strip the rest
};
cregex cregex_init(void);
@@ -29,7 +29,7 @@ cregex cregex_from(const char* pattern, int cflags = CREG_DEFAULT);
// return CREG_OK, or negative error code on failure
int cregex_compile(cregex *self, const char* pattern, int cflags = CREG_DEFAULT);
- // num. of capture groups in regex. 0 if RE is invalid. First group is the full match
+ // num. of capture groups in regex, excluding the 0th group which is the full match
int cregex_captures(const cregex* self);
// return CREG_OK, CREG_NOMATCH, or CREG_MATCHERROR
@@ -44,15 +44,15 @@ bool cregex_is_match(const cregex* re, const char* input);
// Replace all matches in input
cstr cregex_replace(const cregex* re, const char* input, const char* replace, int count = INT_MAX);
- // Replace count matches in input string-view. Optionally transform replacement with mfun.
+ // Replace count matches in input string-view. Optionally transform replacement.
cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count = INT_MAX);
cstr cregex_replace_sv(const cregex* re, csview input, const char* replace, int count,
- bool(*mfun)(int capgrp, csview match, cstr* mstr), int rflags);
+ bool(*transform)(int group, csview match, cstr* result), int rflags);
// All-in-one replacement (compile + find/replace + drop)
cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count = INT_MAX);
cstr cregex_replace_pattern(const char* pattern, const char* input, const char* replace, int count,
- bool(*mfun)(int capgrp, csview match, cstr* mstr), int rflags);
+ bool(*transform)(int group, csview match, cstr* result), int rflags);
// destroy
void cregex_drop(cregex* self);
```
@@ -99,10 +99,10 @@ If an error occurs ```cregex_compile``` returns a negative error code stored in
[ [Run this code](https://godbolt.org/z/z434TMKfo) ]
```c
-#define i_extern // include external cstr, utf8, cregex functions implementation.
+#define i_import // include dependent cstr, utf8 and cregex function definitions.
#include <stc/cregex.h>
-int main() {
+int main(void) {
const char* input = "start date is 2023-03-01, end date 2025-12-31.";
const char* pattern = "\\b(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)\\b";
@@ -138,20 +138,20 @@ In order to use a callback function in the replace call, see `examples/regex_rep
To iterate multiple matches in an input string, you may use
```c
csview match[5] = {0};
-while (cregex_find(&re, input, match, CREG_M_NEXT) == CREG_OK)
- c_forrange (k, cregex_captures(&re))
- printf("submatch %lld: %.*s\n", k, c_SV(match[k]));
+while (cregex_find(&re, input, match, CREG_NEXT) == CREG_OK)
+ for (int k = 1; i <= cregex_captures(&re); ++k)
+ printf("submatch %d: %.*s\n", k, c_SV(match[k]));
```
There is also a for-loop macro to simplify it:
```c
c_formatch (it, &re, input)
- c_forrange (k, cregex_captures(&re))
- printf("submatch %lld: %.*s\n", k, c_SV(it.match[k]));
+ for (int k = 1; i <= cregex_captures(&re); ++k)
+ printf("submatch %d: %.*s\n", k, c_SV(it.match[k]));
```
## Using cregex in a project
-The easiest is to `#define i_extern` before `#include <stc/cregex.h>`. Make sure to do that in one translation unit only.
+The easiest is to `#define i_import` before `#include <stc/cregex.h>`. Make sure to do that in one translation unit only.
For reference, **cregex** uses the following files:
- `stc/cregex.h`, `stc/utf8.h`, `stc/csview.h`, `stc/cstr.h`, `stc/ccommon.h`, `stc/forward.h`
@@ -181,8 +181,8 @@ For reference, **cregex** uses the following files:
| \B | Not UTF8 word boundary | * |
| \Q | Start literal input mode | * |
| \E | End literal input mode | * |
-| (?i) (?-i) | Ignore case on/off (override CREG_C_ICASE) | * |
-| (?s) (?-s) | Dot matches newline on/off (override CREG_C_DOTALL) | * |
+| (?i) (?-i) | Ignore case on/off (override CREG_ICASE) | * |
+| (?s) (?-s) | Dot matches newline on/off (override CREG_DOTALL) | * |
| \n \t \r | Match UTF8 newline, tab, carriage return | |
| \d \s \w | Match UTF8 digit, whitespace, alphanumeric character | |
| \D \S \W | Do not match the groups described above | |
diff --git a/docs/cset_api.md b/docs/cset_api.md
index 026d7462..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_val
-#define i_ssize // default int32_t. If defined, 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.
@@ -77,16 +77,17 @@ cset_X_value cset_X_value_clone(cset_X_value val);
## Example
```c
+#define i_implement
#include <stc/cstr.h>
#define i_type Strset
#define i_key_str
#include <stc/cset.h>
-int main ()
+int main(void)
{
Strset first, second={0}, third={0}, fourth={0}, fifth;
- first = c_make(Strset, {"red", "green", "blue"});
+ first = c_init(Strset, {"red", "green", "blue"});
fifth = Strset_clone(second);
c_forlist (i, const char*, {"orange", "pink", "yellow"})
diff --git a/docs/csmap_api.md b/docs/csmap_api.md
index 93faa4f9..d739283b 100644
--- a/docs/csmap_api.md
+++ b/docs/csmap_api.md
@@ -15,25 +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_ssize // internal size rep. defaults to int32_t
+#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.
@@ -73,6 +72,7 @@ csmap_X_result csmap_X_push(csmap_X* self, csmap_X_value entry);
csmap_X_result csmap_X_emplace(csmap_X* self, i_keyraw rkey, i_valraw rmapped); // no change if rkey in map
csmap_X_result csmap_X_emplace_or_assign(csmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update rmapped
+csmap_X_result csmap_X_emplace_key(csmap_X* self, i_keyraw rkey); // if key not in map, mapped is left unassigned
int csmap_X_erase(csmap_X* self, i_keyraw rkey);
csmap_X_iter csmap_X_erase_at(csmap_X* self, csmap_X_iter it); // returns iter after it
@@ -84,7 +84,8 @@ void csmap_X_next(csmap_X_iter* iter);
csmap_X_iter csmap_X_advance(csmap_X_iter it, intptr_t n);
csmap_X_value csmap_X_value_clone(csmap_X_value val);
-csmap_X_raw csmap_X_value_toraw(csmap_X_value* pval);
+csmap_X_raw csmap_X_value_toraw(const csmap_X_value* pval);
+void csmap_X_value_drop(csmap_X_value* pval);
```
## Types
@@ -102,16 +103,16 @@ csmap_X_raw csmap_X_value_toraw(csmap_X_value* pval);
## Examples
```c
+#define i_implement
#include <stc/cstr.h>
-
#define i_key_str // special macro for i_key = cstr, i_tag = str
#define i_val_str // ditto
#include <stc/csmap.h>
-int main()
+int main(void)
{
// Create a sorted map of three strings (maps to string)
- csmap_str colors = c_make(csmap_str, {
+ csmap_str colors = c_init(csmap_str, {
{"RED", "#FF0000"},
{"GREEN", "#00FF00"},
{"BLUE", "#0000FF"}
@@ -148,8 +149,9 @@ 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>
#define i_type strmap
#define i_key_str
@@ -165,7 +167,7 @@ static void print_result(strmap_result result) {
print_node(result.ref);
}
-int main()
+int main(void)
{
strmap m = {0};
@@ -182,6 +184,7 @@ int main()
### Example 3
This example uses a csmap with cstr as mapped value.
```c
+#define i_implement
#include <stc/cstr.h>
#define i_type IDSMap
@@ -189,10 +192,10 @@ This example uses a csmap with cstr as mapped value.
#define i_val_str
#include <stc/csmap.h>
-int main()
+int main(void)
{
uint32_t col = 0xcc7744ff;
- IDSMap idnames = c_make(IDSMap, { {100, "Red"}, {110, "Blue"} });
+ IDSMap idnames = c_init(IDSMap, { {100, "Red"}, {110, "Blue"} });
// Assign/overwrite an existing mapped value with a const char*
IDSMap_emplace_or_assign(&idnames, 110, "White");
@@ -235,7 +238,7 @@ static int Vec3i_cmp(const Vec3i* a, const Vec3i* b) {
#include <stc/csmap.h>
#include <stdio.h>
-int main()
+int main(void)
{
csmap_vi vmap = {0};
diff --git a/docs/cspan_api.md b/docs/cspan_api.md
index 10565b0f..4875e021 100644
--- a/docs/cspan_api.md
+++ b/docs/cspan_api.md
@@ -1,9 +1,14 @@
# STC [cspan](../include/stc/cspan.h): Multi-dimensional Array View
![Array](pics/array.jpg)
-The **cspan** is templated non-owning *single* and *multi-dimensional* view of an array. It has similarities
-with Python's numpy array slicing and C++ [std::span](https://en.cppreference.com/w/cpp/container/span) /
-[std::mdspan](https://en.cppreference.com/w/cpp/container/mdspan), and others.
+The **cspan** types are templated non-owning *single* and *multi-dimensional* views of an array.
+It supports both row-major and column-major layout efficiently, in a addition to slicing
+capabilities similar to [python's numpy arrays](https://numpy.org/doc/stable/user/basics.indexing.html).
+Note that each dimension is currently limited to int32_t sizes and 8 dimensions (can be extended).
+
+See also C++
+[std::span](https://en.cppreference.com/w/cpp/container/span) /
+[std::mdspan](https://en.cppreference.com/w/cpp/container/mdspan) for similar functionality.
## Header file and declaration
**cspan** types are defined by the *using_cspan()* macro after the header is included.
@@ -21,182 +26,226 @@ using_cspan4(S, ValueType); // define span types S, S2, S3, S4 with
```
## Methods
-All functions are type-safe. Note that the span argument itself is generally not side-effect safe,
-i.e., it may be expanded multiple times. However, all integer arguments are safe, e.g.
-`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_make(T SpanType, {v1, v2, ...}); // make a 1-d cspan from values
-SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from compatible STC container
-SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from C array
-SpanTypeN cspan_md(ValueType* data, intptr_t xdim, ...); // make a multi-dimensional cspan
+SpanType cspan_init(TYPE SpanType, {v1, v2, ...}); // make a 1-d cspan from values
+SpanType cspan_from(STCContainer* cnt); // make a 1-d cspan from a cvec, cstack, cpque (heap)
+SpanType cspan_from_n(ValueType* ptr, int32_t n); // make a 1-d cspan from a pointer and length
+SpanType cspan_from_array(ValueType array[]); // make a 1-d cspan from a C array
intptr_t cspan_size(const SpanTypeN* self); // return number of elements
intptr_t cspan_rank(const SpanTypeN* self); // dimensions; compile time constant
-intptr_t cspan_index(const SpanTypeN* self, intptr_t x, ..); // index of element
-
-ValueType* cspan_at(const SpanTypeN* self, intptr_t x, ...); // #args must match input span rank
+intptr_t cspan_index(const SpanTypeN* self, int32_t x, ..); // offset index at i, j, ..
+
+ValueType* cspan_at(const SpanTypeN* self, int32_t x, ...); // num args is compile-time checked
ValueType* cspan_front(const SpanTypeN* self);
ValueType* cspan_back(const SpanTypeN* self);
- // general index slicing to create a subspan.
- // {i} reduces rank. {i,c_END} slice to end. {c_ALL} use the full extent.
-SpanTypeR cspan_slice(T SpanTypeR, const SpanTypeN* self, {x0,x1}, {y0,y1}.., {N0,N1});
-
- // create a subspan of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL});
-SpanType cspan_submd2(const SpanType2* self, intptr_t x); // return a 1d subspan from a 2d span.
-SpanTypeN cspan_submd3(const SpanType3* self, intptr_t x, ...); // return a 1d or 2d subspan from a 3d span.
-SpanTypeN cspan_submd4(const SpanType4* self, intptr_t x, ...); // number of args determines rank of output span.
-
- // create a subspan of same rank. Like e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL});
-SpanType cspan_subspan(const SpanType* self, intptr_t offset, intptr_t count);
-SpanType2 cspan_subspan2(const SpanType2 self, intptr_t offset, intptr_t count);
-SpanType3 cspan_subspan3(const SpanType3 self, intptr_t offset, intptr_t count);
-
SpanTypeN_iter SpanType_begin(const SpanTypeN* self);
SpanTypeN_iter SpanType_end(const SpanTypeN* self);
void SpanType_next(SpanTypeN_iter* it);
+
+ // make a multi-dim cspan
+SpanTypeN cspan_md(ValueType* data, int32_t d1, int32_t d2, ...); // row-major layout
+SpanTypeN cspan_md_layout(cspan_layout layout, ValueType* data, int32_t d1, d2, ...);
+
+ // transpose a md span. Inverses layout and axes only.
+void cspan_transpose(const SpanTypeN* self);
+cspan_layout cspan_get_layout(const SpanTypeN* self);
+bool cspan_is_rowmajor(const SpanTypeN* self);
+bool cspan_is_colmajor(const SpanTypeN* self);
+
+ // create a subspan of input span rank. Like e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL});
+SpanType cspan_subspan(const SpanType* span, int32_t offset, int32_t count);
+SpanType2 cspan_subspan2(const SpanType2* span, int32_t offset, int32_t count);
+SpanType3 cspan_subspan3(const SpanType3* span, int32_t offset, int32_t count);
+
+ // create a sub md span of lower rank. Like e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL});
+OutSpan cspan_submd2(const SpanType2* parent, int32_t x); // return a 1d subspan from a 2d span.
+OutSpanN cspan_submd3(const SpanType3* parent, int32_t x, ...); // return a 1d or 2d subspan from a 3d span.
+OutSpanN cspan_submd4(const SpanType4* parent, int32_t x, ...); // number of args decides rank of output span.
+
+ // general slicing of an md span.
+ // {i}: reduce rank. {i,c_END}: slice to end. {c_ALL}: use full extent.
+OutSpanN cspan_slice(TYPE OutSpanN, const SpanTypeM* parent, {x0,x1}, {y0,y1}.., {N0,N1});
```
## Types
-
-| Type name | Type definition | Used to represent... |
+| Type name | Type definition / usage | Used to represent... |
|:------------------|:----------------------------------------------------|:---------------------|
-| SpanTypeN | `struct { ValueType *data; uint32_t shape[N]; .. }` | SpanType with rank N |
-| SpanTypeN`_value` | `ValueType` | The ValueType |
-| `c_ALL` | | Full extent |
-| `c_END` | | End of extent |
-
+| SpanTypeN_value | `ValueType` | The ValueType |
+| SpanTypeN | `struct { ValueType *data; int32_t shape[N]; .. }` | SpanType with rank N |
+| `cspan_tupleN` | `struct { intptr_t d[N]; }` | Strides for each rank |
+| `cspan_layout` | `enum { c_ROWMAJOR, c_COLMAJOR }` | Multi-dim layout |
+| `c_ALL` | `cspan_slice(&md, {1,3}, {c_ALL})` | Full extent |
+| `c_END` | `cspan_slice(&md, {1,c_END}, {2,c_END})` | End of extent |
+
## Example 1
-Dimension slicing in python, C, and C++:
+[ [Run this code](https://godbolt.org/z/Tv9d1T3TM) ]
+```c
+#include <stdio.h>
+#define i_key int
+#include <stc/cvec.h>
+
+#define i_key int
+#include <stc/cstack.h>
+
+#include <stc/cspan.h>
+using_cspan(intspan, int);
+
+void printMe(intspan container) {
+ printf("%d:", (int)cspan_size(&container));
+ c_foreach (e, intspan, container)
+ printf(" %d", *e.ref);
+ puts("");
+}
+
+int main(void)
+{
+ printMe( c_init(intspan, {1, 2, 3, 4}) );
+
+ int arr[] = {1, 2, 3, 4, 5};
+ printMe( (intspan)cspan_from_array(arr) );
+
+ cvec_int vec = c_init(cvec_int, {1, 2, 3, 4, 5, 6});
+ printMe( (intspan)cspan_from(&vec) );
+
+ cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7});
+ printMe( (intspan)cspan_from(&stk) );
+
+ intspan spn = c_init(intspan, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
+ printMe( (intspan)cspan_subspan(&spn, 2, 8) );
+
+ // cleanup
+ cvec_int_drop(&vec);
+ cstack_int_drop(&stk);
+}
+```
+
+## Example 2
+
+Multi-dimension slicing (first in python):
```py
import numpy as np
+def print_span(s2):
+ for i in range(s2.shape[0]):
+ for j in range(s2.shape[1]):
+ print(" {}".format(s2[i, j]), end='')
+ print('')
+ print('')
+
if __name__ == '__main__':
ms3 = np.array((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24), int)
- ms3 = np.reshape(ms3, (2, 3, 4))
- ss3 = ms3[:, 1:3, 2:]
- ss2 = ss3[1]
-
- for i in range(ss2.shape[0]):
- for j in range(ss2.shape[1]):
- print(" {}".format(ss2[i, j]), end='')
- print('')
+ ms3 = np.reshape(ms3, (2, 3, 4), order='C')
+ ss3 = ms3[:, 0:3, 2:]
+ a = ss3[1]
+ b = np.transpose(a)
- for i in ss2.flat:
- print(" {}".format(i), end='')
+ print_span(ms3[1])
+ print_span(a)
+ print_span(b)
-# 19 20 23 24
-# 19 20 23 24
+ for i in a.flat: print(" {}".format(i), end='')
+ print('')
+ for i in b.flat: print(" {}".format(i), end='')
+'''
+ 13 14 15 16
+ 17 18 19 20
+ 21 22 23 24
+
+ 15 16
+ 19 20
+ 23 24
+
+ 15 19 23
+ 16 20 24
+
+ 15 16 19 20 23 24
+ 15 19 23 16 20 24
+'''
```
-... can be written in C using cspan:
+... in C with STC cspan:
+
+[ [Run this code](https://godbolt.org/z/e3PeWe7e9) ]
```c
#include <stdio.h>
#include <stc/cspan.h>
-using_cspan3(myspan, int); // define myspan, myspan2, myspan3.
-
-int main() {
- int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24};
- myspan3 ms3 = cspan_md(arr, 2, 3, 4);
- myspan3 ss3 = cspan_slice(myspan3, &ms3, {c_ALL}, {1,3}, {2,c_END});
- myspan2 ss2 = cspan_submd3(&ss3, 1);
+using_cspan3(myspan, int); // define myspan, myspan2, myspan3.
- c_forrange (i, ss2.shape[0])
- c_forrange (j, ss2.shape[1])
- printf(" %d", *cspan_at(&ss2, i, j));
+void print_span(myspan2 ms) {
+ for (int i=0; i < ms.shape[0]; ++i) {
+ for (int j=0; j < ms.shape[1]; ++j)
+ printf(" %2d", *cspan_at(&ms, i, j));
+ puts("");
+ }
puts("");
-
- c_foreach (i, myspan2, ss2)
- printf(" %d", *i.ref);
}
-```
-... and (almost) in C++23:
-```c++
-#include <print>
-#include <mdspan>
-#include <tuple>
-int main() {
+int main(void) {
int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24};
- std::mdspan ms3(arr, 2, 3, 4);
- auto ss3 = std::submdspan(ms3, std::full_extent, std::tuple{1,3}, std::tuple{2,4});
- auto ss2 = std::submdspan(ss3, 1, std::full_extent, std::full_extent);
+ myspan3 ms3 = cspan_md(arr, 2, 3, 4); // row-major layout
+ myspan3 ss3 = cspan_slice(myspan3, &ms3, {c_ALL}, {0,3}, {2,c_END});
+ myspan2 a = cspan_submd3(&ss3, 1);
+ myspan2 b = a;
+ cspan_transpose(&b);
- for (std::size_t i = 0; i < ss2.extent(0); ++i)
- for (std::size_t j = 0; j < ss2.extent(1); ++j)
- std::print(" {}", ss2[i, j]);
- std::println();
+ print_span((myspan2)cspan_submd3(&ms3, 1));
+ print_span(a);
+ print_span(b);
- // std::mdspan can't be iterated joined/flat!
+ c_foreach (i, myspan2, a) printf(" %d", *i.ref);
+ puts("");
+ c_foreach (i, myspan2, b) printf(" %d", *i.ref);
}
```
-## Example 2
+
+## Example 3
Slicing cspan without and with reducing the rank:
+
+[ [Run this code](https://godbolt.org/z/jjzcvPPxW) ]
```c
-#include <c11/print.h>
+#include <stdio.h>
#include <stc/cspan.h>
+#define i_key int
+#include <stc/cvec.h>
+#define i_key int
+#include <stc/cstack.h>
using_cspan3(Span, int); // Shorthand to define Span, Span2, and Span3
-int main()
+int main(void)
{
- // c_make() can create any STC container/span from an initializer list:
- Span span = c_make(Span, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ Span span = c_init(Span, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24});
- // create a 3d cspan:
Span3 span3 = cspan_md(span.data, 2, 4, 3);
- // reduce rank: (i.e. span3[1])
- Span2 span2 = cspan_submd3(&span3, 1);
-
- puts("\niterate span2 flat:");
- c_foreach (i, Span2, span2)
- print(" {}", *i.ref);
- puts("");
-
// slice without reducing rank:
Span3 ss3 = cspan_slice(Span3, &span3, {c_ALL}, {3,4}, {c_ALL});
- puts("\niterate ss3 by dimensions:");
- c_forrange (i, ss3.shape[0]) {
- c_forrange (j, ss3.shape[1]) {
- c_forrange (k, ss3.shape[2])
- print(" {:2}", *cspan_at(&ss3, i, j, k));
- print(" |");
+ for (int i=0; i < ss3.shape[0]; ++i) {
+ for (int j=0; j < ss3.shape[1]; ++j) {
+ for (int k=0; k < ss3.shape[2]; ++k)
+ printf(" %2d", *cspan_at(&ss3, i, j, k));
+ puts("");
}
+ puts("");
}
+
// slice and reduce rank:
Span2 ss2 = cspan_slice(Span2, &span3, {c_ALL}, {3}, {c_ALL});
- puts("\niterate ss2 by dimensions:");
- c_forrange (i, ss2.shape[0]) {
- c_forrange (j, ss2.shape[1])
- print(" {:2}", *cspan_at(&ss2, i, j));
- print(" |");
+ for (int i=0; i < ss2.shape[0]; ++i) {
+ for (int j=0; j < ss2.shape[1]; ++j)
+ printf(" %2d", *cspan_at(&ss2, i, j));
+ puts("");
}
-
- puts("\niterate ss2 flat:");
- c_foreach (i, Span2, ss2)
- print(" {:2}", *i.ref);
- puts("");
}
```
-Output:
-```
-iterate span2 flat:
- 13 14 15 16 17 18 19 20 21 22 23 24
-
-iterate ss3 by dimensions:
- 10 11 12 |
- 22 23 24 |
-
-iterate ss2 by dimensions:
- 10 | 11 | 12 |
- 22 | 23 | 24 |
-
-iterate ss2 flat:
- 10 11 12 22 23 24
-```
diff --git a/docs/csset_api.md b/docs/csset_api.md
index e83ab857..21e38f61 100644
--- a/docs/csset_api.md
+++ b/docs/csset_api.md
@@ -8,18 +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_keyraw // convertion "raw" type - defaults to i_key
-#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy
-#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
-
-#define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_val
-#define i_ssize // defaults to int32_t
+#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 <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: csset_{i_tag}. i_tag defaults to i_key
#include <stc/csset.h>
```
`X` should be replaced by the value of `i_tag` in all of the following documentation.
@@ -77,17 +76,18 @@ csset_X_value csset_X_value_clone(csset_X_value val);
## Example
```c
+#define i_implement
#include <stc/cstr.h>
#define i_type SSet
#define i_key_str
#include <stc/csset.h>
-int main ()
+int main(void)
{
SSet second={0}, third={0}, fourth={0}, fifth={0};
- second = c_make(SSet, {"red", "green", "blue"});
+ second = c_init(SSet, {"red", "green", "blue"});
c_forlist (i, const char*, {"orange", "pink", "yellow"})
SSet_emplace(&third, *i.ref);
diff --git a/docs/cstack_api.md b/docs/cstack_api.md
index b1371f4e..da0bc954 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_val // value: REQUIRED
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop 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_valraw // convertion "raw" type - defaults to i_val
-#define i_valfrom // convertion func i_valraw => i_val
-#define i_valto // convertion func i_val* => i_valraw
+#define i_keyraw <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_val
+#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.
@@ -27,13 +27,13 @@ See the c++ class [std::stack](https://en.cppreference.com/w/cpp/container/stack
```c
cstack_X cstack_X_init(void);
cstack_X cstack_X_with_capacity(intptr_t cap);
-cstack_X cstack_X_with_size(intptr_t size, i_val fill);
+cstack_X cstack_X_with_size(intptr_t size, i_key fill);
cstack_X cstack_X_clone(cstack_X st);
void cstack_X_clear(cstack_X* self);
bool cstack_X_reserve(cstack_X* self, intptr_t n);
void cstack_X_shrink_to_fit(cstack_X* self);
-i_val* cstack_X_append_uninit(cstack_X* self, intptr_t n);
+i_key* cstack_X_append_uninit(cstack_X* self, intptr_t n);
void cstack_X_copy(cstack_X* self, const cstack_X* other);
void cstack_X_drop(cstack_X* self); // destructor
@@ -41,21 +41,24 @@ intptr_t cstack_X_size(const cstack_X* self);
intptr_t cstack_X_capacity(const cstack_X* self);
bool cstack_X_empty(const cstack_X* self);
-i_val* cstack_X_top(const cstack_X* self);
-const i_val* cstack_X_at(const cstack_X* self, intptr_t idx);
-i_val* cstack_X_at_mut(cstack_X* self, intptr_t idx);
+i_key* cstack_X_top(const cstack_X* self);
+const i_key* cstack_X_at(const cstack_X* self, intptr_t idx);
+i_key* cstack_X_at_mut(cstack_X* self, intptr_t idx);
-i_val* cstack_X_push(cstack_X* self, i_val value);
-i_val* cstack_X_emplace(cstack_X* self, i_valraw raw);
+i_key* cstack_X_push(cstack_X* self, i_key value);
+i_key* cstack_X_emplace(cstack_X* self, i_keyraw raw);
-void cstack_X_pop(cstack_X* self);
+void cstack_X_pop(cstack_X* self); // destroy last element
+cstack_X_value cstack_X_pull(cstack_X* self); // move out last element
cstack_X_iter cstack_X_begin(const cstack_X* self);
cstack_X_iter cstack_X_end(const cstack_X* self);
void cstack_X_next(cstack_X_iter* it);
-i_valraw cstack_X_value_toraw(cvec_X_value* pval);
-i_val cstack_X_value_clone(i_val value);
+bool cstack_X_eq(const cstack_X* c1, const cstack_X* c2); // require i_eq/i_cmp/i_less.
+i_key cstack_X_value_clone(i_key value);
+i_keyraw cstack_X_value_toraw(const cvec_X_value* pval);
+void cstack_X_value_drop(cvec_X_value* pval);
```
## Types
@@ -63,19 +66,19 @@ i_val cstack_X_value_clone(i_val value);
| Type name | Type definition | Used to represent... |
|:--------------------|:-------------------------------------|:----------------------------|
| `cstack_X` | `struct { cstack_value *data; ... }` | The cstack type |
-| `cstack_X_value` | `i_val` | The cstack element type |
-| `cstack_X_raw` | `i_valraw` | cstack raw value type |
+| `cstack_X_value` | `i_key` | The cstack element type |
+| `cstack_X_raw` | `i_keyraw` | cstack raw value type |
| `cstack_X_iter` | `struct { cstack_value *ref; }` | cstack iterator |
## Example
```c
#define i_type IStack
-#define i_val int
+#define i_key int
#include <stc/cstack.h>
#include <stdio.h>
-int main() {
+int main(void) {
IStack stk = IStack_init();
for (int i=0; i < 100; ++i)
diff --git a/docs/cstr_api.md b/docs/cstr_api.md
index 64ad002c..29dfe464 100644
--- a/docs/cstr_api.md
+++ b/docs/cstr_api.md
@@ -1,11 +1,17 @@
# STC [cstr](../include/stc/cstr.h): String
![String](pics/string.jpg)
-A **cstr** object represent sequences of characters. It supports an interface similar to that of a standard container of bytes, but adding features specifically designed to operate with strings of single-byte characters, terminated by the null character.
+A **cstr** object represent sequences of characters. It supports an interface similar
+to that of a standard container of bytes, but adding features specifically designed to
+operate with strings of single-byte characters, terminated by the null character.
-**cstr** has basic support for *UTF8* encoded strings, and has a set of compact and efficient functions for handling case-foldings and comparisons of UTF strings.
+**cstr** has basic support for *UTF8* encoded strings, and has a set of compact and
+efficient functions for handling case-conversion, iteration and indexing into UTF8
+codepoints.
-**cstr** uses short strings optimization (sso), which eliminates heap memory allocation for string capacity less than 24 bytes. `sizeof(cstr)` is also 24. In comparison, c++ `sizeof(std::string)` is typically 32, but sso capacity is only 15 bytes.
+**cstr** uses short strings optimization (sso), which eliminates heap memory allocation
+for string capacity up to 22 bytes. `sizeof(cstr)` is 24. In comparison, C++
+`sizeof(std::string)` is typically 32, but sso capacity is only 15 bytes.
## Header file
@@ -18,11 +24,12 @@ All cstr definitions and prototypes are available by including a single header f
## Methods
```c
-cstr cstr_init(void); // constructor; same as cstr_NULL.
+cstr cstr_init(void); // constructor; empty string
cstr cstr_lit(const char literal_only[]); // cstr from literal; no strlen() call.
cstr cstr_from(const char* str); // constructor using strlen()
cstr cstr_from_n(const char* str, intptr_t n); // constructor with n first bytes of str
cstr cstr_from_sv(csview sv); // construct cstr from csview
+cstr cstr_from_rs(crawstr rs); // construct cstr from crawstr
cstr cstr_with_capacity(intptr_t cap);
cstr cstr_with_size(intptr_t len, char fill); // repeat fill len times
cstr cstr_from_fmt(const char* fmt, ...); // printf() formatting
@@ -32,10 +39,11 @@ cstr* cstr_take(cstr* self, cstr s); // take owne
cstr cstr_move(cstr* self); // move string to caller, leave self empty
void cstr_drop(cstr* self); // destructor
-const char* cstr_str(const cstr* self); // cast to const char*
-char* cstr_data(cstr* self); // cast to mutable char*
-csview cstr_sv(const cstr* self); // cast to string view
-cstr_buf cstr_buffer(cstr* self); // cast to mutable buffer (with capacity)
+const char* cstr_str(const cstr* self); // to const char*
+csview cstr_sv(const cstr* self); // to csview
+crawstr cstr_rs(const cstr* self); // to crawstr
+char* cstr_data(cstr* self); // to mutable char*
+cstr_buf cstr_buffer(cstr* self); // to mutable buffer (with capacity)
intptr_t cstr_size(const cstr* self);
intptr_t cstr_capacity(const cstr* self);
@@ -132,11 +140,11 @@ Note that all methods with arguments `(..., const char* str, intptr_t n)`, `n` m
#### Helper methods:
```c
-int cstr_cmp(const cstr* s1, const cstr* s2);
-bool cstr_eq(const cstr* s1, const cstr* s2);
-bool cstr_hash(const cstr* self);
+int cstr_cmp(const cstr* s1, const cstr* s2);
+bool cstr_eq(const cstr* s1, const cstr* s2);
+uint64_t cstr_hash(const cstr* self);
-char* cstrnstrn(const char* str, const char* search, intptr_t slen, intptr_t nlen);
+char* stc_strnstrn(const char* str, intptr_t slen, const char* needle, intptr_t nlen);
```
## Types
@@ -145,7 +153,7 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt
|:----------------|:---------------------------------------------|:---------------------|
| `cstr` | `struct { ... }` | The string type |
| `cstr_value` | `char` | String element type |
-| `csview` | `struct { const char *str; intptr_t size; }` | String view type |
+| `cstr_iter` | `union { cstr_value *ref; csview chr; }` | String iterator |
| `cstr_buf` | `struct { char *data; intptr_t size, cap; }` | String buffer type |
## Constants and macros
@@ -153,13 +161,13 @@ char* cstrnstrn(const char* str, const char* search, intptr_t slen, intpt
| Name | Value |
|:------------------|:------------------|
| `c_NPOS` | `INTPTR_MAX` |
-| `cstr_NULL` | cstr null value |
## Example
```c
+#define i_implement
#include <stc/cstr.h>
-int main() {
+int main(void) {
cstr s0, s1, full_path;
c_defer(
cstr_drop(&s0),
diff --git a/docs/csview_api.md b/docs/csview_api.md
index ec3bf121..76a803a8 100644
--- a/docs/csview_api.md
+++ b/docs/csview_api.md
@@ -1,87 +1,79 @@
-# STC [csview](../include/stc/csview.h): String View
+# STC [csview](../include/stc/csview.h): Sub-string View
![String](pics/string.jpg)
-The type **csview** is a string view and can refer to a constant contiguous sequence of char-elements with the first
-element of the sequence at position zero. The implementation holds two members: a pointer to constant char and a size.
+The type **csview** is a non-null terminated string view and can refer to a constant contiguous
+sequence of char-elements with the first element of the sequence at position zero. The implementation
+holds two members: a pointer to constant char and a size.
-**csview** is an efficient replacent for `const char*`. It never allocates memory, and therefore need not be destructed.
-Its lifetime is limited by the source string storage. It keeps the length of the string, and does not call *strlen()*
-when passing it around. It is faster when using`csview` as convertion type (raw) than `const char*` in associative
-containers with cstr keys.
+Because **csview** is non-null terminated, it cannot be a replacent view for `const char*` -
+see [crawstr](crawstr_api.md) for that. **csview** never allocates memory, and therefore need not be
+destructed. Its lifetime is limited by the source string storage. It keeps the length of the string,
+and does not need to call *strlen()* to acquire the length.
-Note: a **csview** may ***not be null-terminated***, and must therefore be printed like:
-`printf("%.*s", csview_ARG(sv))`.
+- **csview** iterators works on UTF8 codepoints - like **cstr** and **crawstr** (see Example 2).
+- Because it is null-terminated, it must be printed the following way:
+```c
+printf("%.*s", c_SV(sstr));
+```
-See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view) for a functional
-description.
+See the c++ class [std::basic_string_view](https://en.cppreference.com/w/cpp/string/basic_string_view)
+for a functional description.
## Header file
All csview definitions and prototypes are available by including a single header file.
```c
-#include <stc/cstr.h> // optional, include cstr+csview functionality
-#include <stc/csview.h>
+#define i_implement
+#include <stc/cstr.h>
+#include <stc/csview.h> // after cstr.h: include extra cstr-csview functions
```
## Methods
```c
-csview c_sv(const char literal_only[]); // construct from literal, no strlen()
-csview c_sv(const char* str, intptr_t n); // construct from str and length n
-csview csview_lit(const char literal_only[]); // alias for c_sv(lit)
-csview csview_from(const char* str); // construct from const char*
-csview csview_from_n(const char* str, intptr_t n); // alias for c_sv(str, n)
-
-intptr_t csview_size(csview sv);
-bool csview_empty(csview sv);
-void csview_clear(csview* self);
-
-bool csview_equals(csview sv, csview sv2);
-intptr_t csview_find(csview sv, const char* str);
-intptr_t csview_find_sv(csview sv, csview find);
-bool csview_contains(csview sv, const char* str);
-bool csview_starts_with(csview sv, const char* str);
-bool csview_ends_with(csview sv, const char* str);
-
-csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); // negative pos count from end
-csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); // negative p1, p2 count from end
-csview csview_token(csview sv, const char* sep, intptr_t* start); // *start > sv.size after last token
+csview c_sv(const char literal_only[]); // construct from literal, no strlen()
+csview c_sv(const char* str, intptr_t n); // construct from str and length n
+csview csview_from(const char* str); // construct from const char*
+csview csview_from_n(const char* str, intptr_t n); // alias for c_sv(str, n)
+
+intptr_t csview_size(csview sv);
+bool csview_empty(csview sv);
+void csview_clear(csview* self);
+
+bool csview_equals(csview sv, const char* str);
+intptr_t csview_equals_sv(csview sv, csview find);
+intptr_t csview_find(csview sv, const char* str);
+intptr_t csview_find_sv(csview sv, csview find);
+bool csview_contains(csview sv, const char* str);
+bool csview_starts_with(csview sv, const char* str);
+bool csview_ends_with(csview sv, const char* str);
+csview csview_substr(csview sv, intptr_t pos, intptr_t n);
+csview csview_slice(csview sv, intptr_t pos1, intptr_t pos2);
+
+csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n); // negative pos count from end
+csview csview_slice_ex(csview sv, intptr_t pos1, intptr_t pos2); // negative pos1, pos2 count from end
+csview csview_token(csview sv, const char* sep, intptr_t* start); // *start > sv.size after last token
```
#### UTF8 methods
```c
-intptr_t csview_u8_size(csview sv);
-csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len);
-bool csview_valid_utf8(csview sv); // requires linking with src/utf8code.c
-
-csview_iter csview_begin(const csview* self);
-csview_iter csview_end(const csview* self);
-void csview_next(csview_iter* it); // utf8 codepoint step, not byte!
-csview_iter csview_advance(csview_iter it, intptr_t n);
-
- // from utf8.h
-intptr_t utf8_size(const char *s);
-intptr_t utf8_size_n(const char *s, intptr_t nbytes); // number of UTF8 codepoints within n bytes
-const char* utf8_at(const char *s, intptr_t index); // from UTF8 index to char* position
-intptr_t utf8_pos(const char* s, intptr_t index); // from UTF8 index to byte index position
-unsigned utf8_chr_size(const char* s); // UTF8 character size: 1-4
- // implemented in src/utf8code.c:
-bool utf8_valid(const char* s);
-bool utf8_valid_n(const char* s, intptr_t nbytes);
-uint32_t utf8_decode(utf8_decode_t *d, uint8_t byte); // decode next byte to utf8, return state.
-unsigned utf8_encode(char *out, uint32_t codepoint); // encode unicode cp into out buffer
-uint32_t utf8_peek(const char* s); // codepoint value of character at s
-uint32_t utf8_peek_off(const char* s, int offset); // codepoint value at utf8 pos (may be negative)
-```
-
-#### Extended cstr methods
-```c
-csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n);
-csview cstr_substr_ex(const cstr* s, intptr_t pos, intptr_t n); // negative pos count from end
-csview cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len);
+intptr_t csview_u8_size(csview sv);
+csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len);
+bool csview_valid_utf8(csview sv); // requires linking with src/utf8code.c
+
+csview_iter csview_begin(const csview* self);
+csview_iter csview_end(const csview* self);
+void csview_next(csview_iter* it); // utf8 codepoint step, not byte!
+csview_iter csview_advance(csview_iter it, intptr_t n);
+```
-csview cstr_slice(const cstr* self, intptr_t p1, intptr_t p2);
-csview cstr_slice_ex(const cstr* s, intptr_t p, intptr_t q); // negative p or q count from end
+#### cstr methods returning csview
+```c
+csview cstr_slice(const cstr* self, intptr_t pos1, intptr_t pos2);
+csview cstr_slice_ex(const cstr* self, intptr_t pos1, intptr_t pos2); // see csview_slice_ex()
+csview cstr_substr(const cstr* self, intptr_t pos, intptr_t n);
+csview cstr_substr_ex(const cstr* self, intptr_t pos, intptr_t n); // see csview_substr_ex()
+csview cstr_u8_substr(const cstr* self, intptr_t bytepos, intptr_t u8len);
```
#### Iterate tokens with *c_fortoken*, *c_fortoken_sv*
@@ -93,46 +85,46 @@ c_fortoken (i, "hello, one, two, three", ", ")
#### Helper methods
```c
-int csview_cmp(const csview* x, const csview* y);
-int csview_icmp(const csview* x, const csview* y);
-bool csview_eq(const csview* x, const csview* y);
-uint64_t csview_hash(const csview* x);
+int csview_cmp(const csview* x, const csview* y);
+int csview_icmp(const csview* x, const csview* y);
+bool csview_eq(const csview* x, const csview* y);
+uint64_t csview_hash(const csview* x);
```
## Types
| Type name | Type definition | Used to represent... |
|:----------------|:-------------------------------------------|:-------------------------|
-| `csview` | `struct { const char *str; intptr_t size; }` | The string view type |
-| `csview_value` | `char` | The string element type |
-| `csview_iter` | `struct { csview_value *ref; }` | UTF8 iterator |
+| `csview` | `struct { const char *buf; intptr_t size; }` | The string view type |
+| `csview_value` | `const char` | The string element type |
+| `csview_iter` | `union { csview_value *ref; csview chr; }` | UTF8 iterator |
## Constants and macros
| Name | Value | Usage |
|:---------------|:---------------------|:---------------------------------------------|
-| `csview_NULL` | same as `c_sv("")` | `sview = csview_NULL;` |
| `c_SV(sv)` | printf argument | `printf("sv: %.*s\n", c_SV(sv));` |
## Example
```c
+#define i_implement
#include <stc/cstr.h>
#include <stc/csview.h>
-int main ()
+int main(void)
{
- cstr str1 = cstr_lit("We think in generalities, but we live in details.");
+ cstr str1 = cstr_from("We think in generalities, but we live in details.");
// (quoting Alfred N. Whitehead)
- csview sv1 = cstr_substr(&str1, 3, 5); // "think"
- intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1
- csview sv2 = cstr_substr(&str1, pos, 4); // get "live"
- csview sv3 = cstr_slice(&str1, -8, -1); // get "details"
+ csview ss1 = cstr_substr_ex(&str1, 3, 5); // "think"
+ intptr_t pos = cstr_find(&str1, "live"); // position of "live" in str1
+ csview ss2 = cstr_substr_ex(&str1, pos, 4); // get "live"
+ csview ss3 = cstr_slice_ex(&str1, -8, -1); // get "details"
printf("%.*s %.*s %.*s\n",
- c_SV(sv1), c_SV(sv2), c_SV(sv3));
+ c_SV(ss1), c_SV(ss2), c_SV(ss3));
cstr s1 = cstr_lit("Apples are red");
- cstr s2 = cstr_from_sv(cstr_substr(&s1, -3, 3)); // "red"
- cstr s3 = cstr_from_sv(cstr_substr(&s1, 0, 6)); // "Apples"
+ cstr s2 = cstr_from_sv(cstr_substr_ex(&s1, -3, 3)); // "red"
+ cstr s3 = cstr_from_sv(cstr_substr_ex(&s1, 0, 6)); // "Apples"
printf("%s %s\n", cstr_str(&s2), cstr_str(&s3));
c_drop(cstr, &str1, &s1, &s2, &s3);
@@ -146,10 +138,10 @@ red Apples
### Example 2: UTF8 handling
```c
+#define i_import // include dependent cstr, utf8 and cregex function definitions.
#include <stc/cstr.h>
-#include <stc/csview.h>
-int main()
+int main(void)
{
cstr s1 = cstr_lit("hell😀 w😀rld");
@@ -157,7 +149,7 @@ int main()
printf("%s\n", cstr_str(&s1));
c_foreach (i, cstr, s1)
- printf("%.*s,", c_SV(i.u8.chr));
+ printf("%.*s,", c_SV(i.chr));
cstr_drop(&s1);
}
@@ -181,9 +173,9 @@ void print_split(csview input, const char* sep)
printf("[%.*s]\n", c_SV(i.token));
puts("");
}
-
+#define i_implement
#include <stc/cstr.h>
-#define i_val_str
+#define i_key_str
#include <stc/cstack.h>
cstack_str string_split(csview input, const char* sep)
@@ -196,7 +188,7 @@ cstack_str string_split(csview input, const char* sep)
return out;
}
-int main()
+int main(void)
{
print_split(c_sv("//This is a//double-slash//separated//string"), "//");
print_split(c_sv("This has no matching separator"), "xx");
diff --git a/docs/cvec_api.md b/docs/cvec_api.md
index 5879bc1f..8997ed51 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_val // value: REQUIRED
-#define i_cmp // three-way compare two i_valraw* : REQUIRED IF i_valraw is a non-integral type
-#define i_valdrop // destroy value func - defaults to empty destruct
-#define i_valclone // REQUIRED IF i_valdrop defined
-
-#define i_valraw // convertion "raw" type - 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: cvec_{i_tag}. i_tag defaults to i_val
+#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_use_cmp // 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.
@@ -31,16 +32,15 @@ See the c++ class [std::vector](https://en.cppreference.com/w/cpp/container/vect
```c
cvec_X cvec_X_init(void);
-cvec_X cvec_X_with_size(intptr_t size, i_val null);
+cvec_X cvec_X_with_size(intptr_t size, i_key null);
cvec_X cvec_X_with_capacity(intptr_t size);
cvec_X cvec_X_clone(cvec_X vec);
void cvec_X_clear(cvec_X* self);
void cvec_X_copy(cvec_X* self, const cvec_X* other);
-cvec_X_iter cvec_X_copy_range(cvec_X* self, i_val* pos, const i_val* p1, const i_val* p2);
+cvec_X_iter cvec_X_copy_n(cvec_X* self, intptr_t idx, const i_key* arr, intptr_t n);
bool cvec_X_reserve(cvec_X* self, intptr_t cap);
-bool cvec_X_resize(cvec_X* self, intptr_t size, i_val null);
-cvec_X_iter cvec_X_insert_uninit(cvec_X* self, i_val* pos, intptr_t n); // return pos iter
+bool cvec_X_resize(cvec_X* self, intptr_t size, i_key null);
void cvec_X_shrink_to_fit(cvec_X* self);
void cvec_X_drop(cvec_X* self); // destructor
@@ -49,55 +49,53 @@ intptr_t cvec_X_size(const cvec_X* self);
intptr_t cvec_X_capacity(const cvec_X* self);
const cvec_X_value* cvec_X_at(const cvec_X* self, intptr_t idx);
-const cvec_X_value* cvec_X_get(const cvec_X* self, i_valraw raw); // return NULL if not found
-cvec_X_value* cvec_X_at_mut(cvec_X* self, intptr_t idx);
-cvec_X_value* cvec_X_get_mut(cvec_X* self, i_valraw raw); // find mutable value, return value ptr
-cvec_X_iter cvec_X_find(const cvec_X* self, i_valraw raw);
-cvec_X_iter cvec_X_find_in(cvec_X_iter i1, cvec_X_iter i2, i_valraw raw); // return cvec_X_end() if not found
+const cvec_X_value* cvec_X_get(const cvec_X* self, i_keyraw raw); // return NULL if not found
+cvec_X_value* cvec_X_at_mut(cvec_X* self, intptr_t idx); // return mutable at idx
+cvec_X_value* cvec_X_get_mut(cvec_X* self, i_keyraw raw); // find mutable value
+cvec_X_iter cvec_X_find(const cvec_X* self, i_keyraw raw);
+cvec_X_iter cvec_X_find_in(cvec_X_iter i1, cvec_X_iter i2, i_keyraw raw); // return cvec_X_end() if not found
// On sorted vectors:
-cvec_X_iter cvec_X_binary_search(const cvec_X* self, i_valraw raw); // at elem == raw, else end
-cvec_X_iter cvec_X_lower_bound(const cvec_X* self, i_valraw raw); // at first elem >= raw, else end
+cvec_X_iter cvec_X_binary_search(const cvec_X* self, i_keyraw raw); // at elem == raw, else end
+cvec_X_iter cvec_X_lower_bound(const cvec_X* self, i_keyraw raw); // at first elem >= raw, else end
cvec_X_iter cvec_X_binary_search_in(cvec_X_iter i1, cvec_X_iter i2,
- i_valraw raw, cvec_X_iter* lower_bound);
+ i_keyraw raw, cvec_X_iter* lower_bound);
cvec_X_value* cvec_X_front(const cvec_X* self);
cvec_X_value* cvec_X_back(const cvec_X* self);
-cvec_X_value* cvec_X_push(cvec_X* self, i_val value);
-cvec_X_value* cvec_X_emplace(cvec_X* self, i_valraw raw);
-cvec_X_value* cvec_X_push_back(cvec_X* self, i_val value); // alias for push
-cvec_X_value* cvec_X_emplace_back(cvec_X* self, i_valraw raw); // alias for emplace
+cvec_X_value* cvec_X_push(cvec_X* self, i_key value);
+cvec_X_value* cvec_X_emplace(cvec_X* self, i_keyraw raw);
+cvec_X_value* cvec_X_push_back(cvec_X* self, i_key value); // alias for push
+cvec_X_value* cvec_X_emplace_back(cvec_X* self, i_keyraw raw); // alias for emplace
-void cvec_X_pop(cvec_X* self);
+void cvec_X_pop(cvec_X* self); // destroy last element
void cvec_X_pop_back(cvec_X* self); // alias for pop
+cvec_X_value cvec_X_pull(cvec_X* self); // move out last element
-cvec_X_iter cvec_X_insert(cvec_X* self, intptr_t idx, i_val value); // move value
-cvec_X_iter cvec_X_insert_n(cvec_X* self, intptr_t idx, const i_val[] arr, intptr_t n); // move n values
-cvec_X_iter cvec_X_insert_at(cvec_X* self, cvec_X_iter it, i_val value); // move value
-cvec_X_iter cvec_X_insert_range(cvec_X* self, i_val* pos,
- const i_val* p1, const i_val* p2);
+cvec_X_iter cvec_X_insert_n(cvec_X* self, intptr_t idx, const i_key arr[], intptr_t n); // move values
+cvec_X_iter cvec_X_insert_at(cvec_X* self, cvec_X_iter it, i_key value); // move value
+cvec_X_iter cvec_X_insert_uninit(cvec_X* self, intptr_t idx, intptr_t n); // return iter at idx
-cvec_X_iter cvec_X_emplace_n(cvec_X* self, intptr_t idx, const i_valraw[] arr, intptr_t n); // clone values
-cvec_X_iter cvec_X_emplace_at(cvec_X* self, cvec_X_iter it, i_valraw raw);
-cvec_X_iter cvec_X_emplace_range(cvec_X* self, i_val* pos,
- const i_valraw* p1, const i_valraw* p2);
+cvec_X_iter cvec_X_emplace_n(cvec_X* self, intptr_t idx, const i_keyraw raw[], intptr_t n);
+cvec_X_iter cvec_X_emplace_at(cvec_X* self, cvec_X_iter it, i_keyraw raw);
cvec_X_iter cvec_X_erase_n(cvec_X* self, intptr_t idx, intptr_t n);
cvec_X_iter cvec_X_erase_at(cvec_X* self, cvec_X_iter it);
cvec_X_iter cvec_X_erase_range(cvec_X* self, cvec_X_iter it1, cvec_X_iter it2);
-cvec_X_iter cvec_X_erase_range_p(cvec_X* self, i_val* p1, i_val* p2);
void cvec_X_sort(cvec_X* self);
void cvec_X_sort_range(cvec_X_iter i1, cvec_X_iter i2,
- int(*cmp)(const i_val*, const i_val*));
+ int(*cmp)(const i_key*, const i_key*));
cvec_X_iter cvec_X_begin(const cvec_X* self);
cvec_X_iter cvec_X_end(const cvec_X* self);
void cvec_X_next(cvec_X_iter* iter);
cvec_X_iter cvec_X_advance(cvec_X_iter it, size_t n);
-cvec_X_raw cvec_X_value_toraw(cvec_X_value* pval);
+bool cvec_X_eq(const cvec_X* c1, const cvec_X* c2); // equality comp.
cvec_X_value cvec_X_value_clone(cvec_X_value val);
+cvec_X_raw cvec_X_value_toraw(const cvec_X_value* pval);
+cvec_X_raw cvec_X_value_drop(cvec_X_value* pval);
```
## Types
@@ -105,18 +103,18 @@ cvec_X_value cvec_X_value_clone(cvec_X_value val);
| Type name | Type definition | Used to represent... |
|:-------------------|:----------------------------------|:-----------------------|
| `cvec_X` | `struct { cvec_X_value* data; }` | The cvec type |
-| `cvec_X_value` | `i_val` | The cvec value type |
-| `cvec_X_raw` | `i_valraw` | The raw value type |
+| `cvec_X_value` | `i_key` | The cvec value type |
+| `cvec_X_raw` | `i_keyraw` | The raw value type |
| `cvec_X_iter` | `struct { cvec_X_value* ref; }` | The iterator type |
## Examples
```c
-#define i_val int
+#define i_key int
#include <stc/cvec.h>
#include <stdio.h>
-int main()
+int main(void)
{
// Create a vector containing integers
cvec_int vec = {0};
@@ -151,12 +149,13 @@ sorted: 5 7 8 13 16 25
```
### Example 2
```c
+#define i_implement
#include <stc/cstr.h>
-#define i_val_str
+#define i_key_str
#include <stc/cvec.h>
-int main() {
+int main(void) {
cvec_str names = cvec_str_init();
cvec_str_emplace(&names, "Mary");
@@ -187,6 +186,7 @@ item: 2 elements so far
Container with elements of structs:
```c
+#define i_implement
#include <stc/cstr.h>
typedef struct {
@@ -208,7 +208,7 @@ User User_clone(User user) {
// Declare a managed, clonable vector of users.
#define i_type UVec
-#define i_valclass User // User is a "class" as it has _cmp, _clone and _drop functions.
+#define i_keyclass User // User is a "class" as it has _cmp, _clone and _drop functions.
#include <stc/cvec.h>
int main(void) {
@@ -224,4 +224,4 @@ int main(void) {
c_drop(UVec, &vec, &vec2); // cleanup
}
-``` \ No newline at end of file
+```
diff --git a/docs/pics/Figure_1.png b/docs/pics/Figure_1.png
new file mode 100644
index 00000000..46a1478f
--- /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/c11/print.h b/include/c11/fmt.h
index 7c155875..7787bdb0 100644
--- a/include/c11/print.h
+++ b/include/c11/fmt.h
@@ -1,39 +1,39 @@
#ifndef FMT_H_INCLUDED
#define FMT_H_INCLUDED
/*
-VER 2.1: NEW API:
-void print(fmt, ...);
-void println(fmt, ...);
-void printd(dest, fmt, ...);
-
+VER 2.2: NEW API:
void fmt_print(fmt, ...);
void fmt_println(fmt, ...);
void fmt_printd(dest, fmt, ...);
-void fmt_destroy(fmt_buffer* buf);
+const char* fmt_tm(fmt, struct tm* tp);
+void fmt_close(fmt_stream* ss);
dest - destination, one of:
FILE* fp Write to a file
char* strbuf Write to a pre-allocated string buffer
- fmt_buffer* buf Auto realloc the needed memory (safe).
- Set buf->stream=1 for stream-mode.
- Call fmt_destroy(buf) after usage.
+ fmt_stream* ss Write to a string-stream (auto allocated).
+ Set ss->overwrite=1 for overwrite-mode.
+ Call fmt_close(ss) after usage.
- fmt - format string
+ fmt - format string (const char*)
{} Auto-detected format. If :MOD is not specified,
float will use ".8g" format, and double ".16g".
- {:MOD} Format modifiers: < left align (replaces -), default for char*, char.
- > right align, default for numbers.
- Other than that MOD can be normal printf format modifiers.
- {{, }} Print chars {, and }. (note: a single % prints %).
+ {:MODS} Format modifiers: '<' left align (replaces '-'). Default for char* and char.
+ '>' right align. Default for numbers.
+ Other than that MODS can be regular printf() format modifiers.
+ {{ }} % Print the '{', '}', and '%' characters.
* C11 or higher required.
* MAX 255 chars fmt string by default. MAX 12 arguments after fmt string.
-* Static linking by default, shared symbols by defining FMT_HEADER / FMT_IMPLEMENT.
+* Define FMT_IMPLEMENT, STC_IMPLEMENT or i_implement prior to #include in one translation unit.
+* Define FMT_SHORTS to add print(), println() and printd() macros, without fmt_ prefix.
* (c) operamint, 2022, MIT License.
-----------------------------------------------------------------------------------
-#include "c11/print.h"
+#define FMT_IMPLEMENT
+#define FMT_SHORTS
+#include "c11/fmt.h"
-int main() {
+int main(void) {
const double pi = 3.141592653589793;
const size_t x = 1234567890;
const char* string = "Hello world";
@@ -50,19 +50,26 @@ int main() {
printd(stdout, "{:10} {:10} {:10}\n", "Hello", "Mad", "World");
printd(stderr, "100%: {:<20} {:.*} {}\n", string, 4, pi, x);
printd(buffer, "Precision: {} {:.10} {}", string, pi, x);
- println("{}", buffer);
- println("Vector: ({}, {}, {})", 3.2, 3.3, pi);
+ fmt_println("{}", buffer);
+ fmt_println("Vector: ({}, {}, {})", 3.2, 3.3, pi);
- fmt_buffer out[1] = {{.stream=1}};
- printd(out, "{} {}", "Pi is:", pi);
- print("{}, len={}, cap={}\n", out->data, out->len, out->cap);
- printd(out, "{} {}", ", Pi squared is:", pi*pi);
- print("{}, len={}, cap={}\n", out->data, out->len, out->cap);
- fmt_destroy(out);
+ fmt_stream ss[1] = {0};
+ printd(ss, "{} {}", "Pi is:", pi);
+ print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap);
+ printd(ss, "{} {}", ", Pi squared is:", pi*pi);
+ print("{}, len={}, cap={}\n", ss->data, ss->len, ss->cap);
+ fmt_close(ss);
+
+ time_t now = time(NULL);
+ struct tm t1 = *localtime(&now), t2 = t1;
+ t2.tm_year += 2;
+ fmt_print("Dates:\n {}\n {}\n", fmt_tm("%Y-%m-%d %X %Z", &t1),
+ fmt_tm("%Y-%m-%d %X %Z", &t2));
}
*/
#include <stdio.h>
#include <stdint.h>
+#include <stddef.h>
#include <assert.h>
#define fmt_OVERLOAD(name, ...) \
@@ -77,12 +84,7 @@ int main() {
#define _fmt_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
_14, _15, _16, N, ...) N
-#if defined FMT_HEADER || defined FMT_IMPLEMENT
-# define FMT_API
-#else
-# define FMT_API static inline
-#endif
-#if defined FMT_NDEBUG || defined NDEBUG
+#if defined FMT_NDEBUG || defined STC_NDEBUG || defined NDEBUG
# define fmt_OK(exp) (void)(exp)
#else
# define fmt_OK(exp) assert(exp)
@@ -91,25 +93,27 @@ int main() {
typedef struct {
char* data;
intptr_t cap, len;
- _Bool stream;
-} fmt_buffer;
+ _Bool overwrite;
+} fmt_stream;
-FMT_API void fmt_destroy(fmt_buffer* buf);
-FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...);
-FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...);
+struct tm; /* Max 2 usages. Buffer = 64 chars. */
+const char* fmt_tm(const char *fmt, const struct tm *tp);
+void fmt_close(fmt_stream* ss);
+int _fmt_parse(char* p, int nargs, const char *fmt, ...);
+void _fmt_bprint(fmt_stream*, const char* fmt, ...);
#ifndef FMT_MAX
-#define FMT_MAX 256
+#define FMT_MAX 128
#endif
-#ifndef FMT_NOSHORTS
+#ifdef FMT_SHORTS
#define print(...) fmt_printd(stdout, __VA_ARGS__)
-#define println(...) fmt_printd((fmt_buffer*)0, __VA_ARGS__)
+#define println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__)
#define printd fmt_printd
#endif
#define fmt_print(...) fmt_printd(stdout, __VA_ARGS__)
-#define fmt_println(...) fmt_printd((fmt_buffer*)0, __VA_ARGS__)
+#define fmt_println(...) fmt_printd((fmt_stream*)0, __VA_ARGS__)
#define fmt_printd(...) fmt_OVERLOAD(fmt_printd, __VA_ARGS__)
/* Primary function. */
@@ -161,7 +165,7 @@ FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...);
#define _fmt_fn(x) _Generic ((x), \
FILE*: fprintf, \
char*: sprintf, \
- fmt_buffer*: _fmt_bprint)
+ fmt_stream*: _fmt_bprint)
#if defined(_MSC_VER) && !defined(__clang__)
# define _signed_char_hhd
@@ -192,38 +196,46 @@ FMT_API void _fmt_bprint(fmt_buffer*, const char* fmt, ...);
const wchar_t*: "ls", \
const void*: "p")
-#if defined FMT_IMPLEMENT || !(defined FMT_HEADER || defined FMT_IMPLEMENT)
+#if defined FMT_IMPLEMENT || defined STC_IMPLEMENT || defined i_implement
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
+#include <time.h>
+
+void fmt_close(fmt_stream* ss) {
+ free(ss->data);
+}
-FMT_API void fmt_destroy(fmt_buffer* buf) {
- free(buf->data);
+const char* fmt_tm(const char *fmt, const struct tm *tp) {
+ static char buf[2][64];
+ static int i;
+ strftime(buf[(i = !i)], sizeof buf[0], fmt, tp);
+ return buf[i];
}
-FMT_API void _fmt_bprint(fmt_buffer* buf, const char* fmt, ...) {
+void _fmt_bprint(fmt_stream* ss, const char* fmt, ...) {
va_list args, args2;
va_start(args, fmt);
- if (buf == NULL) {
+ if (ss == NULL) {
vprintf(fmt, args); putchar('\n');
goto done1;
}
va_copy(args2, args);
const int n = vsnprintf(NULL, 0U, fmt, args);
if (n < 0) goto done2;
- const intptr_t pos = buf->stream ? buf->len : 0;
- buf->len = pos + n;
- if (buf->len > buf->cap) {
- buf->cap = buf->len + buf->cap/2;
- buf->data = (char*)realloc(buf->data, (size_t)buf->cap + 1U);
+ const intptr_t pos = ss->overwrite ? 0 : ss->len;
+ ss->len = pos + n;
+ if (ss->len > ss->cap) {
+ ss->cap = ss->len + ss->cap/2;
+ ss->data = (char*)realloc(ss->data, (size_t)ss->cap + 1U);
}
- vsprintf(buf->data + pos, fmt, args2);
+ vsprintf(ss->data + pos, fmt, args2);
done2: va_end(args2);
done1: va_end(args);
}
-FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...) {
+int _fmt_parse(char* p, int nargs, const char *fmt, ...) {
char *arg, *p0, ch;
int n = 0, empty;
va_list args;
@@ -273,3 +285,4 @@ FMT_API int _fmt_parse(char* p, int nargs, const char *fmt, ...) {
}
#endif
#endif
+#undef i_implement
diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h
deleted file mode 100644
index b0ecd6b7..00000000
--- a/include/stc/algo/coroutine.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/* MIT License
- *
- * Copyright (c) 2023 Tyge Løvset
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef STC_COROUTINE_INCLUDED
-#define STC_COROUTINE_INCLUDED
-/*
-#include <stdio.h>
-#include <stc/algo/coroutine.h>
-
-struct iterate {
- int max_x, max_y;
- int x, y;
- int cco_state; // required member
-};
-
-bool iterate(struct iterate* I) {
- cco_begin(I);
- for (I->x = 0; I->x < I->max_x; I->x++)
- for (I->y = 0; I->y < I->max_y; I->y++)
- cco_yield(true);
-
- cco_final:
- puts("final");
- cco_end(false);
-}
-
-int main(void) {
- struct iterate it = {.max_x=3, .max_y=3};
- int n = 0;
- while (iterate(&it))
- {
- printf("%d %d\n", it.x, it.y);
- // example of early stop:
- if (++n == 20) cco_stop(&it); // signal to stop at next
- }
- return 0;
-}
-*/
-#include <stc/ccommon.h>
-
-enum {
- cco_state_final = -1,
- cco_state_done = -2,
-};
-
-#define cco_suspended(ctx) ((ctx)->cco_state > 0)
-#define cco_alive(ctx) ((ctx)->cco_state != cco_state_done)
-
-#define cco_begin(ctx) \
- int *_state = &(ctx)->cco_state; \
- switch (*_state) { \
- case 0:
-
-#define cco_end(retval) \
- *_state = cco_state_done; break; \
- case -99: goto _cco_final_; \
- } \
- return retval
-
-#define cco_yield(...) c_MACRO_OVERLOAD(cco_yield, __VA_ARGS__)
-#define cco_yield_1(retval) \
- do { \
- *_state = __LINE__; return retval; \
- case __LINE__:; \
- } while (0)
-
-#define cco_yield_2(corocall2, ctx2) \
- cco_yield_3(corocall2, ctx2, )
-
-#define cco_yield_3(corocall2, ctx2, retval) \
- do { \
- *_state = __LINE__; \
- do { \
- corocall2; if (cco_suspended(ctx2)) return retval; \
- case __LINE__:; \
- } while (cco_alive(ctx2)); \
- } while (0)
-
-#define cco_final \
- case cco_state_final: \
- _cco_final_
-
-#define cco_return \
- goto _cco_final_
-
-#define cco_stop(ctx) \
- do { \
- int* _state = &(ctx)->cco_state; \
- if (*_state > 0) *_state = cco_state_final; \
- } while (0)
-
-#define cco_reset(ctx) \
- do { \
- int* _state = &(ctx)->cco_state; \
- if (*_state == cco_state_done) *_state = 0; \
- } while (0)
-
-#endif
diff --git a/include/stc/algo/crange.h b/include/stc/algo/crange.h
index ca06c258..faeda162 100644
--- a/include/stc/algo/crange.h
+++ b/include/stc/algo/crange.h
@@ -25,16 +25,17 @@
#include <stc/algo/filter.h>
#include <stc/algo/crange.h>
-int main()
+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;
- c_forfilter (i, crange, crange_obj(a, b, 8),
+ crange r2 = crange_init(a, b, 8);
+ c_forfilter (i, crange, r2,
c_flt_skip(i, 10) &&
c_flt_take(i, 3))
printf(" %lld", *i.ref);
@@ -44,29 +45,27 @@ int main()
#ifndef STC_CRANGE_H_INCLUDED
#define STC_CRANGE_H_INCLUDED
-#include <stc/ccommon.h>
-
-#define crange_obj(...) \
- (*(crange[]){crange_make(__VA_ARGS__)})
+#include "../ccommon.h"
typedef long long crange_value;
typedef struct { crange_value start, end, step, value; } crange;
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)
{ self->value = self->start; crange_iter it = {&self->value, self->end, self->step}; return it; }
-STC_INLINE crange_iter crange_end(crange* self)
+STC_INLINE crange_iter crange_end(crange* self)
{ crange_iter it = {NULL}; return it; }
-STC_INLINE void crange_next(crange_iter* it)
+STC_INLINE void crange_next(crange_iter* it)
{ *it->ref += it->step; if ((it->step > 0) == (*it->ref > it->end)) it->ref = NULL; }
#endif
diff --git a/include/stc/algo/csort.h b/include/stc/algo/csort.h
deleted file mode 100644
index 53fe9fcc..00000000
--- a/include/stc/algo/csort.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* MIT License
- *
- * Copyright (c) 2023 Tyge Løvset
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include "../ccommon.h"
-#include "../priv/template.h"
-
-/* Generic Quicksort in C, performs as fast as c++ std::sort().
-template params:
-#define i_val - value type [required]
-#define i_less - less function. default: *x < *y
-#define i_tag NAME - define csort_NAME(). default {i_val}
-
-// test:
-#include <stdio.h>
-#define i_val int
-#include <stc/algo/csort.h>
-
-int main() {
- int arr[] = {23, 321, 5434, 25, 245, 1, 654, 33, 543, 21};
-
- csort_int(arr, c_arraylen(arr));
-
- for (int i = 0; i < c_arraylen(arr); i++)
- printf(" %d", arr[i]);
- puts("");
-}
-*/
-
-typedef i_val c_PASTE(c_CONCAT(csort_, i_tag), _value);
-
-static inline void c_PASTE(cisort_, i_tag)(i_val arr[], intptr_t lo, intptr_t hi) {
- for (intptr_t j = lo, i = lo + 1; i <= hi; j = i, ++i) {
- i_val key = arr[i];
- while (j >= 0 && (i_less((&key), (&arr[j])))) {
- arr[j + 1] = arr[j];
- --j;
- }
- arr[j + 1] = key;
- }
-}
-
-static inline void c_PASTE(cqsort_, i_tag)(i_val arr[], intptr_t lo, intptr_t hi) {
- intptr_t i = lo, j;
- while (lo < hi) {
- i_val pivot = arr[lo + (hi - lo)*7/16];
- j = hi;
-
- while (i <= j) {
- while (i_less((&arr[i]), (&pivot))) ++i;
- while (i_less((&pivot), (&arr[j]))) --j;
- if (i <= j) {
- c_swap(i_val, arr+i, arr+j);
- ++i; --j;
- }
- }
- if (j - lo > hi - i) {
- c_swap(intptr_t, &lo, &i);
- c_swap(intptr_t, &hi, &j);
- }
-
- if (j - lo > 64) c_PASTE(cqsort_, i_tag)(arr, lo, j);
- else if (j > lo) c_PASTE(cisort_, i_tag)(arr, lo, j);
- lo = i;
- }
-}
-
-static inline void c_PASTE(csort_, i_tag)(i_val arr[], intptr_t n)
- { c_PASTE(cqsort_, i_tag)(arr, 0, n - 1); }
-
-#include "../priv/template2.h"
diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h
index e133577c..320cd50d 100644
--- a/include/stc/algo/filter.h
+++ b/include/stc/algo/filter.h
@@ -24,11 +24,11 @@
#include <stdio.h>
#define i_val int
#include <stc/cstack.h>
-#include <stc/calgo.h>
+#include <stc/algorithm.h>
-int main()
+int main(void)
{
- cstack_int stk = c_make(cstack_int, {1, 2, 3, 4, 5, 6, 7, 8, 9});
+ cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7, 8, 9});
c_foreach (i, cstack_int, stk)
printf(" %d", *i.ref);
@@ -47,7 +47,7 @@ int main()
#ifndef STC_FILTER_H_INCLUDED
#define STC_FILTER_H_INCLUDED
-#include <stc/ccommon.h>
+#include "../ccommon.h"
// c_forfilter:
@@ -85,29 +85,42 @@ int main()
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 { \
C* _cnt = &cnt; \
- intptr_t _index = 0; \
- for (C##_iter it = C##_begin(_cnt); it.ref; ++_index) { \
+ for (C##_iter it = C##_begin(_cnt); it.ref; ) { \
if (pred) it = C##_erase_at(_cnt, it); \
else C##_next(&it); \
} \
} while (0)
-
// Use with: cstack, cvec, cdeq, cqueue:
#define c_eraseremove_if(it, C, cnt, pred) do { \
C* _cnt = &cnt; \
- intptr_t _n = 0, _index = 0; \
+ intptr_t _n = 0; \
C##_iter it = C##_begin(_cnt), _i; \
while (it.ref && !(pred)) \
- C##_next(&it), ++_index; \
- for (_i = it; it.ref; C##_next(&it), ++_index) \
+ C##_next(&it); \
+ for (_i = it; it.ref; C##_next(&it)) \
if (pred) C##_value_drop(it.ref), ++_n; \
else *_i.ref = *it.ref, C##_next(&_i); \
- _cnt->_len -= _n; \
+ C##_adjust_end_(_cnt, -_n); \
} while (0)
// ------------------------ private -------------------------
diff --git a/include/stc/algo/raii.h b/include/stc/algo/raii.h
new file mode 100644
index 00000000..584f5c59
--- /dev/null
+++ b/include/stc/algo/raii.h
@@ -0,0 +1,51 @@
+/* MIT License
+ *
+ * Copyright (c) 2023 Tyge Løvset
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+*/
+#ifndef STC_RAII_INCLUDED
+#define STC_RAII_INCLUDED
+
+#define c_with(...) c_MACRO_OVERLOAD(c_with, __VA_ARGS__)
+#define c_with_2(declvar, drop) \
+ for (declvar, *_i, **_ip = &_i; _ip; _ip = 0, drop)
+#define c_with_3(declvar, pred, drop) \
+ for (declvar, *_i, **_ip = &_i; _ip && (pred); _ip = 0, drop)
+
+#define c_scope(...) c_MACRO_OVERLOAD(c_scope, __VA_ARGS__)
+#define c_scope_2(init, drop) \
+ for (int _i = (init, 1); _i; _i = 0, drop)
+#define c_scope_3(init, pred, drop) \
+ for (int _i = (init, 1); _i && (pred); _i = 0, drop)
+
+#define c_auto(...) c_MACRO_OVERLOAD(c_auto, __VA_ARGS__)
+#define c_auto_2(C, a) \
+ c_with_2(C a = C##_init(), C##_drop(&a))
+#define c_auto_3(C, a, b) \
+ c_with_2(c_EXPAND(C a = C##_init(), b = C##_init()), \
+ (C##_drop(&b), C##_drop(&a)))
+#define c_auto_4(C, a, b, c) \
+ c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init()), \
+ (C##_drop(&c), C##_drop(&b), C##_drop(&a)))
+#define c_auto_5(C, a, b, c, d) \
+ c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init(), d = C##_init()), \
+ (C##_drop(&d), C##_drop(&c), C##_drop(&b), C##_drop(&a)))
+
+#endif
diff --git a/include/stc/algo/sort.h b/include/stc/algo/sort.h
new file mode 100644
index 00000000..86c9b9f1
--- /dev/null
+++ b/include/stc/algo/sort.h
@@ -0,0 +1,123 @@
+/* MIT License
+ *
+ * Copyright (c) 2023 Tyge Løvset
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* Generic Quicksort in C, performs as fast as c++ std::sort().
+template params:
+#define i_key - value type [required]
+#define i_less - less function. default: *x < *y
+#define i_type name - define {{name}}_sort_n(), else {{i_key}}array_sort_n().
+
+// ex1:
+#include <stdio.h>
+#define i_key int
+#include <stc/algo/sort.h>
+
+int main(void) {
+ int nums[] = {23, 321, 5434, 25, 245, 1, 654, 33, 543, 21};
+
+ intarray_sort_n(nums, c_arraylen(nums));
+
+ for (int i = 0; i < c_arraylen(nums); i++)
+ printf(" %d", nums[i]);
+ puts("");
+}
+
+// ex2:
+#define i_key int
+#define i_type IDeq
+#define i_more // retain input template params to be reused by sort.h
+#include <stc/cdeq.h>
+#include <stc/algo/sort.h>
+
+int main(void) {
+ IDeq nums = c_init(IDeq, {5434, 25, 245, 1, 654, 33, 543, 21});
+ IDeq_push_front(&nums, 23);
+ IDeq_push_front(&nums, 321);
+
+ IDeq_sort_n(&nums, IDeq_size(&nums));
+
+ c_foreach (i, IDeq, nums)
+ printf(" %d", *i.ref);
+ IDeq_drop(&nums);
+}
+*/
+#include "../ccommon.h"
+
+#if !defined i_key && defined i_val
+ #define i_key i_val
+#endif
+#ifndef i_type
+ #define i_at(arr, idx) (&arr[idx])
+ #ifndef i_tag
+ #define i_tag i_key
+ #endif
+ #define i_type c_PASTE(i_tag, s)
+ typedef i_key i_type;
+#endif
+#ifndef i_at
+ #define i_at(arr, idx) _cx_MEMB(_at_mut)(arr, idx)
+#endif
+#include "../priv/template.h"
+
+
+static inline void _cx_MEMB(_insertsort_ij)(_cx_Self* arr, intptr_t lo, intptr_t hi) {
+ for (intptr_t j = lo, i = lo + 1; i <= hi; j = i, ++i) {
+ i_key key = *i_at(arr, i);
+ while (j >= 0 && (i_less((&key), i_at(arr, j)))) {
+ *i_at(arr, j + 1) = *i_at(arr, j);
+ --j;
+ }
+ *i_at(arr, j + 1) = key;
+ }
+}
+
+static inline void _cx_MEMB(_sort_ij)(_cx_Self* arr, intptr_t lo, intptr_t hi) {
+ intptr_t i = lo, j;
+ while (lo < hi) {
+ i_key pivot = *i_at(arr, lo + (hi - lo)*7/16);
+ j = hi;
+
+ while (i <= j) {
+ while (i_less(i_at(arr, i), (&pivot))) ++i;
+ while (i_less((&pivot), i_at(arr, j))) --j;
+ if (i <= j) {
+ c_swap(i_key, i_at(arr, i), i_at(arr, j));
+ ++i; --j;
+ }
+ }
+ if (j - lo > hi - i) {
+ c_swap(intptr_t, &lo, &i);
+ c_swap(intptr_t, &hi, &j);
+ }
+
+ if (j - lo > 64) _cx_MEMB(_sort_ij)(arr, lo, j);
+ else if (j > lo) _cx_MEMB(_insertsort_ij)(arr, lo, j);
+ lo = i;
+ }
+}
+
+static inline void _cx_MEMB(_sort_n)(_cx_Self* arr, intptr_t len) {
+ _cx_MEMB(_sort_ij)(arr, 0, len - 1);
+}
+
+#include "../priv/template2.h"
+#undef i_at
diff --git a/include/stc/calgo.h b/include/stc/algorithm.h
index 21e73faf..cf3ab328 100644
--- a/include/stc/calgo.h
+++ b/include/stc/algorithm.h
@@ -1,8 +1,8 @@
#ifndef STC_CALGO_INCLUDED
#define STC_CALGO_INCLUDED
+#include "algo/raii.h"
#include "algo/crange.h"
#include "algo/filter.h"
-#include "algo/coroutine.h"
#endif
diff --git a/include/stc/carc.h b/include/stc/carc.h
index 8ef80b12..b617e1ca 100644
--- a/include/stc/carc.h
+++ b/include/stc/carc.h
@@ -22,6 +22,7 @@
*/
/* carc: atomic reference counted shared_ptr
+#define i_implement
#include <stc/cstr.h>
typedef struct { cstr name, last; } Person;
@@ -29,6 +30,11 @@ typedef struct { cstr name, last; } Person;
Person Person_make(const char* name, const char* last) {
return (Person){.name = cstr_from(name), .last = cstr_from(last)};
}
+Person Person_clone(Person p) {
+ p.name = cstr_clone(p.name);
+ p.last = cstr_clone(p.last);
+ return p;
+}
void Person_drop(Person* p) {
printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
cstr_drop(&p->name);
@@ -36,11 +42,10 @@ void Person_drop(Person* p) {
}
#define i_type ArcPers
-#define i_key Person
-#define i_keydrop Person_drop
+#define i_valclass Person // clone, drop, cmp, hash
#include <stc/carc.h>
-int main() {
+int main(void) {
ArcPers p = ArcPers_from(Person_make("John", "Smiths"));
ArcPers q = ArcPers_clone(p); // share the pointer
@@ -48,10 +53,11 @@ int main() {
c_drop(ArcPers, &p, &q);
}
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CARC_H_INCLUDED
#define CARC_H_INCLUDED
+#include "ccommon.h"
#include "forward.h"
#include <stdlib.h>
@@ -71,19 +77,18 @@ int main() {
#define c_atomic_dec_and_test(v) (atomic_fetch_sub(v, 1) == 1)
#endif
-#define carc_NULL {NULL, NULL}
+#define carc_null {0}
#endif // CARC_H_INCLUDED
-#ifndef _i_prefix
#define _i_prefix carc_
-#endif
-#ifdef i_eq
-#define _i_eq
-#endif
+#define _i_carc
#include "priv/template.h"
typedef i_keyraw _cx_raw;
-#if !c_option(c_no_atomic)
+#if c_option(c_no_atomic)
+ #define i_no_atomic
+#endif
+#if !defined i_no_atomic
#define _i_atomic_inc(v) c_atomic_inc(v)
#define _i_atomic_dec_and_test(v) c_atomic_dec_and_test(v)
#else
@@ -91,123 +96,127 @@ typedef i_keyraw _cx_raw;
#define _i_atomic_dec_and_test(v) !(--*(v))
#endif
#ifndef i_is_forward
-_cx_deftypes(_c_carc_types, _cx_self, i_key);
+_cx_DEFTYPES(_c_carc_types, _cx_Self, i_key);
#endif
-struct _cx_memb(_rep_) { catomic_long counter; i_key value; };
+struct _cx_MEMB(_rep_) { catomic_long counter; i_key value; };
-STC_INLINE _cx_self _cx_memb(_init)(void)
- { return c_LITERAL(_cx_self){NULL, NULL}; }
+STC_INLINE _cx_Self _cx_MEMB(_init)(void)
+ { return c_LITERAL(_cx_Self){NULL, NULL}; }
-STC_INLINE long _cx_memb(_use_count)(const _cx_self* self)
+STC_INLINE long _cx_MEMB(_use_count)(const _cx_Self* self)
{ return self->use_count ? *self->use_count : 0; }
-STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p) {
- _cx_self ptr = {p};
+STC_INLINE _cx_Self _cx_MEMB(_from_ptr)(_cx_value* p) {
+ _cx_Self ptr = {p};
if (p)
*(ptr.use_count = _i_alloc(catomic_long)) = 1;
return ptr;
}
// c++: std::make_shared<_cx_value>(val)
-STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) {
- _cx_self ptr;
- struct _cx_memb(_rep_)* rep = _i_alloc(struct _cx_memb(_rep_));
+STC_INLINE _cx_Self _cx_MEMB(_make)(_cx_value val) {
+ _cx_Self ptr;
+ struct _cx_MEMB(_rep_)* rep = _i_alloc(struct _cx_MEMB(_rep_));
*(ptr.use_count = &rep->counter) = 1;
*(ptr.get = &rep->value) = val;
return ptr;
}
-STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self)
+STC_INLINE _cx_raw _cx_MEMB(_toraw)(const _cx_Self* self)
{ return i_keyto(self->get); }
-STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) {
- _cx_self ptr = *self;
+STC_INLINE _cx_Self _cx_MEMB(_move)(_cx_Self* self) {
+ _cx_Self ptr = *self;
self->get = NULL, self->use_count = NULL;
return ptr;
}
-STC_INLINE void _cx_memb(_drop)(_cx_self* self) {
+STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self) {
if (self->use_count && _i_atomic_dec_and_test(self->use_count)) {
i_keydrop(self->get);
- if ((char *)self->get != (char *)self->use_count + offsetof(struct _cx_memb(_rep_), value))
+ if ((char *)self->get != (char *)self->use_count + offsetof(struct _cx_MEMB(_rep_), value))
i_free(self->get);
i_free((long*)self->use_count);
}
}
-STC_INLINE void _cx_memb(_reset)(_cx_self* self) {
- _cx_memb(_drop)(self);
+STC_INLINE void _cx_MEMB(_reset)(_cx_Self* self) {
+ _cx_MEMB(_drop)(self);
self->use_count = NULL, self->get = NULL;
}
-STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) {
- _cx_memb(_drop)(self);
- *self = _cx_memb(_from_ptr)(p);
+STC_INLINE void _cx_MEMB(_reset_to)(_cx_Self* self, _cx_value* p) {
+ _cx_MEMB(_drop)(self);
+ *self = _cx_MEMB(_from_ptr)(p);
}
#ifndef i_no_emplace
-STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw)
- { return _cx_memb(_make)(i_keyfrom(raw)); }
+STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_raw raw)
+ { return _cx_MEMB(_make)(i_keyfrom(raw)); }
#else
-STC_INLINE _cx_self _cx_memb(_from)(_cx_value val)
- { return _cx_memb(_make)(val); }
+STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_value val)
+ { return _cx_MEMB(_make)(val); }
#endif
// does not use i_keyclone, so OK to always define.
-STC_INLINE _cx_self _cx_memb(_clone)(_cx_self ptr) {
+STC_INLINE _cx_Self _cx_MEMB(_clone)(_cx_Self ptr) {
if (ptr.use_count)
_i_atomic_inc(ptr.use_count);
return ptr;
}
// take ownership of unowned
-STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self unowned) {
- _cx_memb(_drop)(self);
+STC_INLINE void _cx_MEMB(_take)(_cx_Self* self, _cx_Self unowned) {
+ _cx_MEMB(_drop)(self);
*self = unowned;
}
// share ownership with ptr
-STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self ptr) {
+STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) {
if (ptr.use_count)
_i_atomic_inc(ptr.use_count);
- _cx_memb(_drop)(self);
+ _cx_MEMB(_drop)(self);
*self = ptr;
}
-#ifndef i_no_cmp
-STC_INLINE int _cx_memb(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_cmp(rx, ry); }
+#if defined i_use_cmp
+ STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry)
+ { return i_cmp(rx, ry); }
-STC_INLINE int _cx_memb(_cmp)(const _cx_self* self, const _cx_self* other) {
- _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
- return i_cmp((&rx), (&ry));
-}
-#endif
+ STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) {
+ _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
+ return i_cmp((&rx), (&ry));
+ }
-#ifdef _i_eq
-STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_eq(rx, ry); }
+ STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
+ { return i_eq(rx, ry); }
-STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
- _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
- return i_eq((&rx), (&ry));
-}
-#elif !defined i_no_cmp
-STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_cmp(rx, ry) == 0; }
+ STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
+ return i_eq((&rx), (&ry));
+ }
-STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other)
- { return _cx_memb(_cmp)(self, other) == 0; }
-#endif
+ #ifndef i_no_hash
+ STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx)
+ { return i_hash(rx); }
-#ifndef i_no_hash
-STC_INLINE uint64_t _cx_memb(_raw_hash)(const _cx_raw* rx)
- { return i_hash(rx); }
+ STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self)
+ { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); }
+ #endif // i_no_hash
-STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* self)
- { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); }
-#endif
+#else
-#undef _i_eq
+ STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) {
+ return c_default_cmp(&self->get, &other->get);
+ }
+ STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ return self->get == other->get;
+ }
+ STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self)
+ { return c_default_hash(&self->get); }
+#endif // i_use_cmp
+
+#include "priv/template2.h"
+#undef i_no_atomic
#undef _i_atomic_inc
#undef _i_atomic_dec_and_test
-#include "priv/template2.h"
+#undef _i_carc
diff --git a/include/stc/cbits.h b/include/stc/cbits.h
index 826df847..3b5785d3 100644
--- a/include/stc/cbits.h
+++ b/include/stc/cbits.h
@@ -26,12 +26,12 @@ Similar to boost::dynamic_bitset / std::bitset
#include <stdio.h>
#include "cbits.h"
-int main() {
+int main(void) {
cbits bset = cbits_with_size(23, true);
cbits_reset(&bset, 9);
cbits_resize(&bset, 43, false);
- printf("%4zu: ", cbits_size(&bset));
+ printf("%4lld: ", cbits_size(&bset));
c_forrange (i, cbits_size(&bset))
printf("%d", cbits_at(&bset, i));
puts("");
@@ -41,7 +41,7 @@ int main() {
cbits_resize(&bset, 102, true);
cbits_set_value(&bset, 99, false);
- printf("%4zu: ", cbits_size(&bset));
+ printf("%4lld: ", cbits_size(&bset));
c_forrange (i, cbits_size(&bset))
printf("%d", cbits_at(&bset, i));
puts("");
@@ -54,11 +54,8 @@ int main() {
#include <stdlib.h>
#include <string.h>
-#ifndef i_ssize
-#define i_ssize intptr_t
-#endif
#define _cbits_bit(i) ((uint64_t)1 << ((i) & 63))
-#define _cbits_words(n) (i_ssize)(((n) + 63)>>6)
+#define _cbits_words(n) (_llong)(((n) + 63)>>6)
#define _cbits_bytes(n) (_cbits_words(n) * c_sizeof(uint64_t))
#if defined(__GNUC__)
@@ -80,23 +77,23 @@ int main() {
}
#endif
-STC_INLINE i_ssize _cbits_count(const uint64_t* set, const i_ssize sz) {
- const i_ssize n = sz>>6;
- i_ssize count = 0;
- for (i_ssize i = 0; i < n; ++i)
+STC_INLINE _llong _cbits_count(const uint64_t* set, const _llong sz) {
+ const _llong n = sz>>6;
+ _llong count = 0;
+ for (_llong i = 0; i < n; ++i)
count += cpopcount64(set[i]);
if (sz & 63)
count += cpopcount64(set[n] & (_cbits_bit(sz) - 1));
return count;
}
-STC_INLINE char* _cbits_to_str(const uint64_t* set, const i_ssize sz,
- char* out, i_ssize start, i_ssize stop) {
+STC_INLINE char* _cbits_to_str(const uint64_t* set, const _llong sz,
+ char* out, _llong start, _llong stop) {
if (stop > sz) stop = sz;
- assert(start <= stop);
+ c_assert(start <= stop);
c_memset(out, '0', stop - start);
- for (i_ssize i = start; i < stop; ++i)
+ for (_llong i = start; i < stop; ++i)
if ((set[i>>6] & _cbits_bit(i)) != 0)
out[i - start] = '1';
out[stop - start] = '\0';
@@ -104,8 +101,8 @@ STC_INLINE char* _cbits_to_str(const uint64_t* set, const i_ssize sz,
}
#define _cbits_OPR(OPR, VAL) \
- const i_ssize n = sz>>6; \
- for (i_ssize i = 0; i < n; ++i) \
+ const _llong n = sz>>6; \
+ for (_llong i = 0; i < n; ++i) \
if ((set[i] OPR other[i]) != VAL) \
return false; \
if (!(sz & 63)) \
@@ -113,10 +110,10 @@ STC_INLINE char* _cbits_to_str(const uint64_t* set, const i_ssize sz,
const uint64_t i = (uint64_t)n, m = _cbits_bit(sz) - 1; \
return ((set[i] OPR other[i]) & m) == (VAL & m)
-STC_INLINE bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, const i_ssize sz)
+STC_INLINE bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, const _llong sz)
{ _cbits_OPR(|, set[i]); }
-STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, const i_ssize sz)
+STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, const _llong sz)
{ _cbits_OPR(&, 0); }
#endif // CBITS_H_INCLUDED
@@ -125,15 +122,14 @@ STC_INLINE bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, cons
#if !defined i_capacity // DYNAMIC SIZE BITARRAY
-#define _i_assert(x) assert(x)
+#define _i_assert(x) c_assert(x)
#define i_type cbits
-struct { uint64_t *data64; i_ssize _size; } typedef i_type;
+typedef struct { uint64_t *data64; _llong _size; } i_type;
STC_INLINE cbits cbits_init(void) { return c_LITERAL(cbits){NULL}; }
-STC_INLINE void cbits_create(cbits* self) { self->data64 = NULL; self->_size = 0; }
STC_INLINE void cbits_drop(cbits* self) { c_free(self->data64); }
-STC_INLINE i_ssize cbits_size(const cbits* self) { return self->_size; }
+STC_INLINE _llong cbits_size(const cbits* self) { return self->_size; }
STC_INLINE cbits* cbits_take(cbits* self, cbits other) {
if (self->data64 != other.data64) {
@@ -144,7 +140,7 @@ STC_INLINE cbits* cbits_take(cbits* self, cbits other) {
}
STC_INLINE cbits cbits_clone(cbits other) {
- const i_ssize bytes = _cbits_bytes(other._size);
+ const _llong bytes = _cbits_bytes(other._size);
cbits set = {(uint64_t *)c_memcpy(c_malloc(bytes), other.data64, bytes), other._size};
return set;
}
@@ -158,16 +154,16 @@ STC_INLINE cbits* cbits_copy(cbits* self, const cbits* other) {
return self;
}
-STC_INLINE void cbits_resize(cbits* self, const i_ssize size, const bool value) {
- const i_ssize new_n = _cbits_words(size), osize = self->_size, old_n = _cbits_words(osize);
+STC_INLINE void cbits_resize(cbits* self, const _llong size, const bool value) {
+ const _llong new_n = _cbits_words(size), osize = self->_size, old_n = _cbits_words(osize);
self->data64 = (uint64_t *)c_realloc(self->data64, new_n*8);
self->_size = size;
if (new_n >= old_n) {
c_memset(self->data64 + old_n, -(int)value, (new_n - old_n)*8);
if (old_n > 0) {
- uint64_t m = _cbits_bit(osize) - 1; /* mask */
- value ? (self->data64[old_n - 1] |= ~m)
- : (self->data64[old_n - 1] &= m);
+ uint64_t mask = _cbits_bit(osize) - 1;
+ if (value) self->data64[old_n - 1] |= ~mask;
+ else self->data64[old_n - 1] &= mask;
}
}
}
@@ -181,13 +177,13 @@ STC_INLINE cbits cbits_move(cbits* self) {
return tmp;
}
-STC_INLINE cbits cbits_with_size(const i_ssize size, const bool value) {
+STC_INLINE cbits cbits_with_size(const _llong size, const bool value) {
cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size};
cbits_set_all(&set, value);
return set;
}
-STC_INLINE cbits cbits_with_pattern(const i_ssize size, const uint64_t pattern) {
+STC_INLINE cbits cbits_with_pattern(const _llong size, const uint64_t pattern) {
cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size};
cbits_set_pattern(&set, pattern);
return set;
@@ -200,12 +196,11 @@ STC_INLINE cbits cbits_with_pattern(const i_ssize size, const uint64_t pattern)
#define i_type c_PASTE(cbits, i_capacity)
#endif
-struct { uint64_t data64[(i_capacity - 1)/64 + 1]; } typedef i_type;
+typedef struct { uint64_t data64[(i_capacity - 1)/64 + 1]; } i_type;
-STC_INLINE i_type _i_memb(_init)(void) { return c_LITERAL(i_type){0}; }
-STC_INLINE void _i_memb(_create)(i_type* self) {}
+STC_INLINE void _i_memb(_init)(i_type* self) { memset(self->data64, 0, i_capacity*8); }
STC_INLINE void _i_memb(_drop)(i_type* self) {}
-STC_INLINE i_ssize _i_memb(_size)(const i_type* self) { return i_capacity; }
+STC_INLINE _llong _i_memb(_size)(const i_type* self) { return i_capacity; }
STC_INLINE i_type _i_memb(_move)(i_type* self) { return *self; }
STC_INLINE i_type* _i_memb(_take)(i_type* self, i_type other)
@@ -216,18 +211,18 @@ STC_INLINE i_type _i_memb(_clone)(i_type other)
STC_INLINE i_type* _i_memb(_copy)(i_type* self, const i_type* other)
{ *self = *other; return self; }
-
+
STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value);
STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern);
-STC_INLINE i_type _i_memb(_with_size)(const i_ssize size, const bool value) {
- assert(size <= i_capacity);
+STC_INLINE i_type _i_memb(_with_size)(const _llong size, const bool value) {
+ c_assert(size <= i_capacity);
i_type set; _i_memb(_set_all)(&set, value);
return set;
}
-STC_INLINE i_type _i_memb(_with_pattern)(const i_ssize size, const uint64_t pattern) {
- assert(size <= i_capacity);
+STC_INLINE i_type _i_memb(_with_pattern)(const _llong size, const uint64_t pattern) {
+ c_assert(size <= i_capacity);
i_type set; _i_memb(_set_pattern)(&set, pattern);
return set;
}
@@ -239,36 +234,36 @@ STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value)
{ c_memset(self->data64, value? ~0 : 0, _cbits_bytes(_i_memb(_size)(self))); }
STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern) {
- i_ssize n = _cbits_words(_i_memb(_size)(self));
+ _llong n = _cbits_words(_i_memb(_size)(self));
while (n--) self->data64[n] = pattern;
}
-STC_INLINE bool _i_memb(_test)(const i_type* self, const i_ssize i)
+STC_INLINE bool _i_memb(_test)(const i_type* self, const _llong i)
{ return (self->data64[i>>6] & _cbits_bit(i)) != 0; }
-STC_INLINE bool _i_memb(_at)(const i_type* self, const i_ssize i)
+STC_INLINE bool _i_memb(_at)(const i_type* self, const _llong i)
{ return (self->data64[i>>6] & _cbits_bit(i)) != 0; }
-STC_INLINE void _i_memb(_set)(i_type *self, const i_ssize i)
+STC_INLINE void _i_memb(_set)(i_type *self, const _llong i)
{ self->data64[i>>6] |= _cbits_bit(i); }
-STC_INLINE void _i_memb(_reset)(i_type *self, const i_ssize i)
+STC_INLINE void _i_memb(_reset)(i_type *self, const _llong i)
{ self->data64[i>>6] &= ~_cbits_bit(i); }
-STC_INLINE void _i_memb(_set_value)(i_type *self, const i_ssize i, const bool b) {
+STC_INLINE void _i_memb(_set_value)(i_type *self, const _llong i, const bool b) {
self->data64[i>>6] ^= ((uint64_t)-(int)b ^ self->data64[i>>6]) & _cbits_bit(i);
}
-STC_INLINE void _i_memb(_flip)(i_type *self, const i_ssize i)
+STC_INLINE void _i_memb(_flip)(i_type *self, const _llong i)
{ self->data64[i>>6] ^= _cbits_bit(i); }
STC_INLINE void _i_memb(_flip_all)(i_type *self) {
- i_ssize n = _cbits_words(_i_memb(_size)(self));
+ _llong n = _cbits_words(_i_memb(_size)(self));
while (n--) self->data64[n] ^= ~(uint64_t)0;
}
STC_INLINE i_type _i_memb(_from)(const char* str) {
- int64_t n = c_strlen(str);
+ _llong n = c_strlen(str);
i_type set = _i_memb(_with_size)(n, false);
while (n--) if (str[n] == '1') _i_memb(_set)(&set, n);
return set;
@@ -277,26 +272,26 @@ STC_INLINE i_type _i_memb(_from)(const char* str) {
/* Intersection */
STC_INLINE void _i_memb(_intersect)(i_type *self, const i_type* other) {
_i_assert(self->_size == other->_size);
- i_ssize n = _cbits_words(_i_memb(_size)(self));
+ _llong n = _cbits_words(_i_memb(_size)(self));
while (n--) self->data64[n] &= other->data64[n];
}
/* Union */
STC_INLINE void _i_memb(_union)(i_type *self, const i_type* other) {
_i_assert(self->_size == other->_size);
- i_ssize n = _cbits_words(_i_memb(_size)(self));
+ _llong n = _cbits_words(_i_memb(_size)(self));
while (n--) self->data64[n] |= other->data64[n];
}
/* Exclusive disjunction */
STC_INLINE void _i_memb(_xor)(i_type *self, const i_type* other) {
_i_assert(self->_size == other->_size);
- i_ssize n = _cbits_words(_i_memb(_size)(self));
+ _llong n = _cbits_words(_i_memb(_size)(self));
while (n--) self->data64[n] ^= other->data64[n];
}
-STC_INLINE int64_t _i_memb(_count)(const i_type* self)
+STC_INLINE _llong _i_memb(_count)(const i_type* self)
{ return _cbits_count(self->data64, _i_memb(_size)(self)); }
-STC_INLINE char* _i_memb(_to_str)(const i_type* self, char* out, int64_t start, int64_t stop)
+STC_INLINE char* _i_memb(_to_str)(const i_type* self, char* out, _llong start, _llong stop)
{ return _cbits_to_str(self->data64, _i_memb(_size)(self), out, start, stop); }
STC_INLINE bool _i_memb(_subset_of)(const i_type* self, const i_type* other) {
@@ -312,7 +307,6 @@ STC_INLINE bool _i_memb(_disjoint)(const i_type* self, const i_type* other) {
#pragma GCC diagnostic pop
#endif
#define CBITS_H_INCLUDED
-#undef _i_size
#undef _i_memb
#undef _i_assert
#undef i_capacity
diff --git a/include/stc/cbox.h b/include/stc/cbox.h
index ca88fc66..55ce9711 100644
--- a/include/stc/cbox.h
+++ b/include/stc/cbox.h
@@ -23,7 +23,9 @@
*/
/* cbox: heap allocated boxed type
+#define i_implement
#include <stc/cstr.h>
+#include <stc/algo/raii.h> // c_auto
typedef struct { cstr name, email; } Person;
@@ -40,11 +42,11 @@ void Person_drop(Person* p) {
c_drop(cstr, &p->name, &p->email);
}
-#define i_keyclass Person // bind Person clone+drop fn's
#define i_type PBox
+#define i_valclass Person // bind Person clone+drop fn's
#include <stc/cbox.h>
-int main() {
+int main(void) {
c_auto (PBox, p, q)
{
p = PBox_from(Person_from("John Smiths", "[email protected]"));
@@ -56,142 +58,142 @@ int main() {
}
}
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CBOX_H_INCLUDED
#define CBOX_H_INCLUDED
+#include "ccommon.h"
#include "forward.h"
#include <stdlib.h>
#include <string.h>
-#define cbox_NULL {NULL}
+#define cbox_null {0}
#endif // CBOX_H_INCLUDED
-#ifndef _i_prefix
#define _i_prefix cbox_
-#endif
-#ifdef i_eq
-#define _i_eq
-#endif
+#define _i_cbox
#include "priv/template.h"
typedef i_keyraw _cx_raw;
#ifndef i_is_forward
-_cx_deftypes(_c_cbox_types, _cx_self, i_key);
+_cx_DEFTYPES(_c_cbox_types, _cx_Self, i_key);
#endif
// constructors (take ownership)
-STC_INLINE _cx_self _cx_memb(_init)(void)
- { return c_LITERAL(_cx_self){NULL}; }
+STC_INLINE _cx_Self _cx_MEMB(_init)(void)
+ { return c_LITERAL(_cx_Self){NULL}; }
-STC_INLINE long _cx_memb(_use_count)(const _cx_self* self)
+STC_INLINE long _cx_MEMB(_use_count)(const _cx_Self* self)
{ return (long)(self->get != NULL); }
-STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p)
- { return c_LITERAL(_cx_self){p}; }
+STC_INLINE _cx_Self _cx_MEMB(_from_ptr)(_cx_value* p)
+ { return c_LITERAL(_cx_Self){p}; }
// c++: std::make_unique<i_key>(val)
-STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) {
- _cx_self ptr = {_i_alloc(_cx_value)};
+STC_INLINE _cx_Self _cx_MEMB(_make)(_cx_value val) {
+ _cx_Self ptr = {_i_alloc(_cx_value)};
*ptr.get = val; return ptr;
}
-STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self)
+STC_INLINE _cx_raw _cx_MEMB(_toraw)(const _cx_Self* self)
{ return i_keyto(self->get); }
// destructor
-STC_INLINE void _cx_memb(_drop)(_cx_self* self) {
+STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self) {
if (self->get) {
i_keydrop(self->get);
i_free(self->get);
}
}
-STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) {
- _cx_self ptr = *self;
+STC_INLINE _cx_Self _cx_MEMB(_move)(_cx_Self* self) {
+ _cx_Self ptr = *self;
self->get = NULL;
return ptr;
}
-STC_INLINE _cx_value* _cx_memb(_release)(_cx_self* self)
- { return _cx_memb(_move)(self).get; }
+STC_INLINE _cx_value* _cx_MEMB(_release)(_cx_Self* self)
+ { return _cx_MEMB(_move)(self).get; }
-STC_INLINE void _cx_memb(_reset)(_cx_self* self) {
- _cx_memb(_drop)(self);
+STC_INLINE void _cx_MEMB(_reset)(_cx_Self* self) {
+ _cx_MEMB(_drop)(self);
self->get = NULL;
}
// take ownership of p
-STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) {
- _cx_memb(_drop)(self);
+STC_INLINE void _cx_MEMB(_reset_to)(_cx_Self* self, _cx_value* p) {
+ _cx_MEMB(_drop)(self);
self->get = p;
}
#ifndef i_no_emplace
-STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw)
- { return _cx_memb(_make)(i_keyfrom(raw)); }
+STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_raw raw)
+ { return _cx_MEMB(_make)(i_keyfrom(raw)); }
#else
-STC_INLINE _cx_self _cx_memb(_from)(_cx_value val)
- { return _cx_memb(_make)(val); }
+STC_INLINE _cx_Self _cx_MEMB(_from)(_cx_value val)
+ { return _cx_MEMB(_make)(val); }
#endif
#if !defined i_no_clone
- STC_INLINE _cx_self _cx_memb(_clone)(_cx_self other) {
+ STC_INLINE _cx_Self _cx_MEMB(_clone)(_cx_Self other) {
if (!other.get)
return other;
- _cx_self out = {_i_alloc(i_key)};
+ _cx_Self out = {_i_alloc(i_key)};
*out.get = i_keyclone((*other.get));
return out;
}
#endif // !i_no_clone
// take ownership of unowned
-STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self unowned) {
- _cx_memb(_drop)(self);
+STC_INLINE void _cx_MEMB(_take)(_cx_Self* self, _cx_Self unowned) {
+ _cx_MEMB(_drop)(self);
*self = unowned;
}
// transfer ownership from moved; set moved to NULL
-STC_INLINE void _cx_memb(_assign)(_cx_self* self, _cx_self* moved) {
+STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self* moved) {
if (moved->get == self->get)
return;
- _cx_memb(_drop)(self);
+ _cx_MEMB(_drop)(self);
*self = *moved;
moved->get = NULL;
}
-#ifndef i_no_cmp
-STC_INLINE int _cx_memb(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_cmp(rx, ry); }
+#if defined i_use_cmp
+ STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry)
+ { return i_cmp(rx, ry); }
-STC_INLINE int _cx_memb(_cmp)(const _cx_self* self, const _cx_self* other) {
- _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
- return i_cmp((&rx), (&ry));
-}
-#endif
+ STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) {
+ _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
+ return i_cmp((&rx), (&ry));
+ }
-#ifdef _i_eq
-STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_eq(rx, ry); }
+ STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
+ { return i_eq(rx, ry); }
-STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
- _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
- return i_eq((&rx), (&ry));
-}
-#elif !defined i_no_cmp
-STC_INLINE bool _cx_memb(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_cmp(rx, ry) == 0; }
+ STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
+ return i_eq((&rx), (&ry));
+ }
-STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other)
- { return _cx_memb(_cmp)(self, other) == 0; }
-#endif
+ #ifndef i_no_hash
+ STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx)
+ { return i_hash(rx); }
-#ifndef i_no_hash
-STC_INLINE uint64_t _cx_memb(_raw_hash)(const _cx_raw* rx)
- { return i_hash(rx); }
+ STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self)
+ { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); }
+ #endif // i_no_hash
-STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* self)
- { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); }
-#endif
+#else
+
+ STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) {
+ return c_default_cmp(&self->get, &other->get);
+ }
+ STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ return self->get == other->get;
+ }
+ STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self)
+ { return c_default_hash(&self->get); }
+#endif // i_use_cmp
-#undef _i_eq
#include "priv/template2.h"
+#undef _i_cbox
diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h
index d5508807..0a8c439a 100644
--- a/include/stc/ccommon.h
+++ b/include/stc/ccommon.h
@@ -29,17 +29,11 @@
#include <stdbool.h>
#include <string.h>
#include <assert.h>
-#include "priv/altnames.h"
-#include "priv/raii.h"
+typedef long long _llong;
#define c_NPOS INTPTR_MAX
#define c_ZI PRIiPTR
#define c_ZU PRIuPTR
-#if defined STC_NDEBUG || defined NDEBUG
- #define c_ASSERT(expr) (void)(0)
-#else
- #define c_ASSERT(expr) assert(expr)
-#endif
#if defined(_MSC_VER)
#pragma warning(disable: 4116 4996) // unnamed type definition in parentheses
@@ -63,7 +57,7 @@
#define _c_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
_14, _15, _16, N, ...) N
-#ifdef __cplusplus
+#ifdef __cplusplus
#include <new>
#define _i_alloc(T) static_cast<T*>(i_malloc(c_sizeof(T)))
#define _i_new(T, ...) new (_i_alloc(T)) T(__VA_ARGS__)
@@ -71,39 +65,45 @@
#define c_LITERAL(T) T
#else
#define _i_alloc(T) ((T*)i_malloc(c_sizeof(T)))
- #define _i_new(T, ...) ((T*)memcpy(_i_alloc(T), (T[]){__VA_ARGS__}, sizeof(T)))
- #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), (T[]){__VA_ARGS__}, sizeof(T)))
+ #define _i_new(T, ...) ((T*)memcpy(_i_alloc(T), ((T[]){__VA_ARGS__}), sizeof(T)))
+ #define c_new(T, ...) ((T*)memcpy(malloc(sizeof(T)), ((T[]){__VA_ARGS__}), sizeof(T)))
#define c_LITERAL(T) (T)
#endif
-#define c_malloc(sz) malloc(c_i2u(sz))
-#define c_calloc(n, sz) calloc(c_i2u(n), c_i2u(sz))
-#define c_realloc(p, sz) realloc(p, c_i2u(sz))
+#define c_new_n(T, n) ((T*)malloc(sizeof(T)*c_i2u_size(n)))
+#define c_malloc(sz) malloc(c_i2u_size(sz))
+#define c_calloc(n, sz) calloc(c_i2u_size(n), c_i2u_size(sz))
+#define c_realloc(p, sz) realloc(p, c_i2u_size(sz))
#define c_free(p) free(p)
#define c_delete(T, ptr) do { T *_tp = ptr; T##_drop(_tp); free(_tp); } while (0)
-#define c_static_assert(b) ((int)(0*sizeof(int[(b) ? 1 : -1])))
+#define c_static_assert(expr) (1 ? 0 : (int)sizeof(int[(expr) ? 1 : -1]))
+#if defined STC_NDEBUG || defined NDEBUG
+ #define c_assert(expr) ((void)0)
+#else
+ #define c_assert(expr) assert(expr)
+#endif
#define c_container_of(p, C, m) ((C*)((char*)(1 ? (p) : &((C*)0)->m) - offsetof(C, m)))
-#define c_const_cast(T, p) ((T)(p) + 0*sizeof((T)0 == (p)))
+#define c_const_cast(T, p) ((T)(1 ? (p) : (T)0))
#define c_swap(T, xp, yp) do { T *_xp = xp, *_yp = yp, \
_tv = *_xp; *_xp = *_yp; *_yp = _tv; } while (0)
+// use with gcc -Wconversion
#define c_sizeof (intptr_t)sizeof
#define c_strlen(s) (intptr_t)strlen(s)
-#define c_strncmp(a, b, ilen) strncmp(a, b, c_i2u(ilen))
-#define c_memcpy(d, s, ilen) memcpy(d, s, c_i2u(ilen))
-#define c_memmove(d, s, ilen) memmove(d, s, c_i2u(ilen))
-#define c_memset(d, val, ilen) memset(d, val, c_i2u(ilen))
-#define c_memcmp(a, b, ilen) memcmp(a, b, c_i2u(ilen))
-
-#define c_u2i(u) ((intptr_t)((u) + 0*sizeof((u) == 1U)))
-#define c_i2u(i) ((size_t)(i) + 0*sizeof((i) == 1))
-#define c_LTu(a, b) ((size_t)(a) < (size_t)(b))
+#define c_strncmp(a, b, ilen) strncmp(a, b, c_i2u_size(ilen))
+#define c_memcpy(d, s, ilen) memcpy(d, s, c_i2u_size(ilen))
+#define c_memmove(d, s, ilen) memmove(d, s, c_i2u_size(ilen))
+#define c_memset(d, val, ilen) memset(d, val, c_i2u_size(ilen))
+#define c_memcmp(a, b, ilen) memcmp(a, b, c_i2u_size(ilen))
+#define c_u2i_size(u) (intptr_t)(1 ? (u) : (size_t)1)
+#define c_i2u_size(i) (size_t)(1 ? (i) : -1)
+#define c_less_unsigned(a, b) ((size_t)(a) < (size_t)(b))
// x and y are i_keyraw* type, defaults to i_key*:
#define c_default_cmp(x, y) (c_default_less(y, x) - c_default_less(x, y))
#define c_default_less(x, y) (*(x) < *(y))
#define c_default_eq(x, y) (*(x) == *(y))
#define c_memcmp_eq(x, y) (memcmp(x, y, sizeof *(x)) == 0)
-#define c_default_hash(x) cfasthash(x, c_sizeof(*(x)))
+#define c_default_hash(x) stc_hash(x, c_sizeof(*(x)))
#define c_default_clone(v) (v)
#define c_default_toraw(vp) (*(vp))
@@ -114,32 +114,31 @@
#define c_no_atomic (1<<1)
#define c_no_clone (1<<2)
#define c_no_emplace (1<<3)
-#define c_no_cmp (1<<4)
-#define c_no_hash (1<<5)
-
+#define c_no_hash (1<<4)
+#define c_use_cmp (1<<5)
/* Function macros and others */
-#define c_make(C, ...) \
- C##_from_n((C##_raw[])__VA_ARGS__, c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw))
-
#define c_litstrlen(literal) (c_sizeof("" literal) - 1)
#define c_arraylen(a) (intptr_t)(sizeof(a)/sizeof 0[a])
-// Non-owning c-string
-typedef const char* crawstr;
-#define crawstr_clone(s) (s)
-#define crawstr_drop(p) ((void)p)
-#define crawstr_cmp(xp, yp) strcmp(*(xp), *(yp))
-#define crawstr_hash(p) cstrhash(*(p))
+// Non-owning c-string "class"
+typedef const char* ccharptr;
+#define ccharptr_cmp(xp, yp) strcmp(*(xp), *(yp))
+#define ccharptr_hash(p) stc_strhash(*(p))
+#define ccharptr_clone(s) (s)
+#define ccharptr_drop(p) ((void)p)
#define c_sv(...) c_MACRO_OVERLOAD(c_sv, __VA_ARGS__)
-#define c_sv_1(lit) c_sv_2(lit, c_litstrlen(lit))
+#define c_sv_1(literal) c_sv_2(literal, c_litstrlen(literal))
#define c_sv_2(str, n) (c_LITERAL(csview){str, n})
+#define c_SV(sv) (int)(sv).size, (sv).buf // printf("%.*s\n", c_SV(sv));
+
+#define c_rs(literal) c_rs_2(literal, c_litstrlen(literal))
+#define c_rs_2(str, n) (c_LITERAL(crawstr){str, n})
-#define c_SV(sv) (int)(sv).size, (sv).str // print csview: use format "%.*s"
#define c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k)))
-STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) {
+STC_INLINE uint64_t stc_hash(const void* key, intptr_t len) {
uint32_t u4; uint64_t u8;
switch (len) {
case 8: memcpy(&u8, key, 8); return u8*0xc6a4a7935bd1e99d;
@@ -147,21 +146,21 @@ STC_INLINE uint64_t cfasthash(const void* key, intptr_t len) {
case 0: return 1;
}
const uint8_t *x = (const uint8_t*)key;
- uint64_t h = *x, n = (uint64_t)len >> 3;
+ uint64_t h = (uint64_t)*x << 7, n = (uint64_t)len >> 3;
len &= 7;
while (n--) {
memcpy(&u8, x, 8), x += 8;
- h += u8*0xc6a4a7935bd1e99d;
+ h = (h ^ u8)*0xc6a4a7935bd1e99d;
}
- while (len--) h = (h << 10) - h - *x++;
- return c_ROTL(h, 26) ^ h;
+ while (len--) h = (h ^ *x++)*0x100000001b3;
+ return h ^ c_ROTL(h, 26);
}
-STC_INLINE uint64_t cstrhash(const char *str)
- { return cfasthash(str, c_strlen(str)); }
+STC_INLINE uint64_t stc_strhash(const char *str)
+ { return stc_hash(str, c_strlen(str)); }
-STC_INLINE char* cstrnstrn(const char *str, const char *needle,
- intptr_t slen, const intptr_t nlen) {
+STC_INLINE char* stc_strnstrn(const char *str, intptr_t slen,
+ const char *needle, intptr_t nlen) {
if (!nlen) return (char *)str;
if (nlen > slen) return NULL;
slen -= nlen;
@@ -173,6 +172,16 @@ STC_INLINE char* cstrnstrn(const char *str, const char *needle,
return NULL;
}
+STC_INLINE intptr_t stc_nextpow2(intptr_t n) {
+ n--;
+ n |= n >> 1, n |= n >> 2;
+ n |= n >> 4, n |= n >> 8;
+ n |= n >> 16;
+ #if INTPTR_MAX == INT64_MAX
+ n |= n >> 32;
+ #endif
+ return n + 1;
+}
/* Control block macros */
#define c_foreach(...) c_MACRO_OVERLOAD(c_foreach, __VA_ARGS__)
@@ -182,57 +191,56 @@ STC_INLINE char* cstrnstrn(const char *str, const char *needle,
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) \
; C##_next(&_.it))
-#define c_forrange(...) c_MACRO_OVERLOAD(c_forrange, __VA_ARGS__)
-#define c_forrange_1(stop) c_forrange_3(_c_i, 0, stop)
-#define c_forrange_2(i, stop) c_forrange_3(i, 0, stop)
-#define c_forrange_3(i, start, stop) \
- for (long long i=start, _end=(long long)(stop); i < _end; ++i)
-#define c_forrange_4(i, start, stop, step) \
- for (long long i=start, _inc=step, _end=(long long)(stop) - (_inc > 0) \
+#define c_forrange(...) c_for(long long, __VA_ARGS__)
+#define c_for(...) c_MACRO_OVERLOAD(c_for, __VA_ARGS__)
+#define c_for_2(T, stop) c_for_4(T, _c_i, 0, stop)
+#define c_for_3(T, i, stop) c_for_4(T, i, 0, stop)
+#define c_for_4(T, i, start, stop) \
+ for (T i=start, _end=stop; i < _end; ++i)
+#define c_for_5(T, i, start, stop, step) \
+ for (T i=start, _inc=step, _end=(T)(stop) - (_inc > 0) \
; (_inc > 0) ^ (i > _end); i += _inc)
#ifndef __cplusplus
+ #define c_init(C, ...) \
+ C##_from_n((C##_raw[])__VA_ARGS__, c_sizeof((C##_raw[])__VA_ARGS__)/c_sizeof(C##_raw))
#define c_forlist(it, T, ...) \
- for (struct {T* ref; int size, index;} \
- it = {.ref=(T[])__VA_ARGS__, .size=(int)(sizeof((T[])__VA_ARGS__)/sizeof(T))} \
- ; it.index < it.size; ++it.ref, ++it.index)
+ for (struct {T* ref; int size, index;} \
+ it = {.ref=(T[])__VA_ARGS__, .size=(int)(sizeof((T[])__VA_ARGS__)/sizeof(T))} \
+ ; it.index < it.size; ++it.ref, ++it.index)
#else
- #include <initializer_list>
- #define c_forlist(it, T, ...) \
- for (struct {std::initializer_list<T> _il; std::initializer_list<T>::iterator data, ref; size_t size, index;} \
- it = {._il=__VA_ARGS__, .data=it._il.begin(), .ref=it.data, .size=it._il.size()} \
- ; it.index < it.size; ++it.ref, ++it.index)
+ #include <initializer_list>
+ template <class C, class T>
+ inline C _from_n(C (*func)(const T[], intptr_t), std::initializer_list<T> il)
+ { return func(&*il.begin(), il.size()); }
+
+ #define c_init(C, ...) _from_n<C,C##_raw>(C##_from_n, __VA_ARGS__)
+ #define c_forlist(it, T, ...) \
+ for (struct {std::initializer_list<T> _il; std::initializer_list<T>::iterator ref; size_t size, index;} \
+ it = {._il=__VA_ARGS__, .ref=it._il.begin(), .size=it._il.size()} \
+ ; it.index < it.size; ++it.ref, ++it.index)
#endif
+#define c_defer(...) \
+ for (int _i = 1; _i; _i = 0, __VA_ARGS__)
#define c_drop(C, ...) \
do { c_forlist (_i, C*, {__VA_ARGS__}) C##_drop(*_i.ref); } while(0)
-#endif // CCOMMON_H_INCLUDED
-
-#undef STC_API
-#undef STC_DEF
-
-#if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \
- defined(i_implement) || defined(STC_IMPLEMENT))
- #define STC_API extern
- #define STC_DEF
-#else
- #define i_static
- #define STC_API static inline
- #define STC_DEF static inline
-#endif
-#if defined(STC_EXTERN)
- #define i_extern
-#endif
-#if defined(i_static) || defined(STC_IMPLEMENT)
- #define i_implement
+#if defined(__SIZEOF_INT128__)
+ #define c_umul128(a, b, lo, hi) \
+ do { __uint128_t _z = (__uint128_t)(a)*(b); \
+ *(lo) = (uint64_t)_z, *(hi) = (uint64_t)(_z >> 64U); } while(0)
+#elif defined(_MSC_VER) && defined(_WIN64)
+ #include <intrin.h>
+ #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi)))
+#elif defined(__x86_64__)
+ #define c_umul128(a, b, lo, hi) \
+ asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b))
#endif
+
+#endif // CCOMMON_H_INCLUDED
diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h
index ff6e744f..4730721c 100644
--- a/include/stc/cdeq.h
+++ b/include/stc/cdeq.h
@@ -20,427 +20,184 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CDEQ_H_INCLUDED
+#include "ccommon.h"
#include "forward.h"
#include <stdlib.h>
#include <string.h>
-
-#define _it2_ptr(it1, it2) (it1.ref && !it2.ref ? it2.end : it2.ref)
-#define _it_ptr(it) (it.ref ? it.ref : it.end)
#endif // CDEQ_H_INCLUDED
-#ifndef _i_prefix
#define _i_prefix cdeq_
-#endif
-#include "priv/template.h"
-
-#ifndef i_is_forward
-_cx_deftypes(_c_cdeq_types, _cx_self, i_key);
-#endif
-typedef i_keyraw _cx_raw;
+#define _pop _pop_front
+#define _pull _pull_front
+#include "priv/cqueue_hdr.h"
+#undef _pop
+#undef _pull
-STC_API _cx_self _cx_memb(_init)(void);
-STC_API _cx_self _cx_memb(_with_capacity)(const intptr_t n);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, const intptr_t n);
-STC_API void _cx_memb(_clear)(_cx_self* self);
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value);
-STC_API void _cx_memb(_shrink_to_fit)(_cx_self *self);
-STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n)
- { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); }
-STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n)
- { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; }
-STC_INLINE void _cx_memb(_value_drop)(_cx_value* val) { i_keydrop(val); }
-#if !defined _i_queue
-#if !defined i_no_emplace
-STC_API _cx_iter _cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos,
- const _cx_raw* p1, const _cx_raw* p2);
-#endif // i_no_emplace
-
-#if !defined i_no_cmp || defined _i_has_eq
-STC_API _cx_iter _cx_memb(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw);
-#endif
-#ifndef i_no_cmp
-STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y);
-#endif
-STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value);
-STC_API _cx_iter _cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2);
-STC_API _cx_iter _cx_memb(_insert_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
-#endif // !_i_queue
+STC_API _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value);
+STC_API _cx_iter _cx_MEMB(_insert_n)(_cx_Self* self, intptr_t idx, const _cx_value* arr, intptr_t n);
+STC_API _cx_iter _cx_MEMB(_insert_uninit)(_cx_Self* self, intptr_t idx, intptr_t n);
+STC_API void _cx_MEMB(_erase_n)(_cx_Self* self, intptr_t idx, intptr_t n);
-#if !defined i_no_emplace
-STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-#endif
+STC_INLINE const _cx_value*
+_cx_MEMB(_at)(const _cx_Self* self, intptr_t idx)
+ { return self->data + _cdeq_topos(self, idx); }
-#if !defined i_no_clone
-#if !defined _i_queue
-STC_API _cx_iter _cx_memb(_copy_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
+STC_INLINE _cx_value*
+_cx_MEMB(_at_mut)(_cx_Self* self, intptr_t idx)
+ { return self->data + _cdeq_topos(self, idx); }
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) {
- if (self->data == other->data) return;
- _cx_memb(_clear)(self);
- _cx_memb(_copy_range)(self, self->data,
- other->data, other->data + other->_len);
- }
-#endif // !_i_queue
-STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
-STC_INLINE i_key _cx_memb(_value_clone)(i_key val)
- { return i_keyclone(val); }
-#endif // !i_no_clone
-STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* self) { return self->_len; }
-STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* self) { return self->_cap; }
-STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) { return !self->_len; }
-STC_INLINE _cx_raw _cx_memb(_value_toraw)(const _cx_value* pval) { return i_keyto(pval); }
-STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->data; }
-STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self)
- { return self->data + self->_len - 1; }
-STC_INLINE void _cx_memb(_pop_front)(_cx_self* self) // == _pop() when _i_queue
- { i_keydrop(self->data); ++self->data; --self->_len; }
+STC_INLINE _cx_value*
+_cx_MEMB(_push_back)(_cx_Self* self, _cx_value val)
+ { return _cx_MEMB(_push)(self, val); }
-STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) {
- intptr_t n = self->_len;
- return c_LITERAL(_cx_iter){n ? self->data : NULL, self->data + n};
+STC_INLINE void
+_cx_MEMB(_pop_back)(_cx_Self* self) {
+ c_assert(!_cx_MEMB(_empty)(self));
+ self->end = (self->end - 1) & self->capmask;
+ i_keydrop((self->data + self->end));
}
-STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
- { return c_LITERAL(_cx_iter){NULL, self->data + self->_len}; }
-
-STC_INLINE void _cx_memb(_next)(_cx_iter* it)
- { if (++it->ref == it->end) it->ref = NULL; }
-
-STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n)
- { if ((it.ref += n) >= it.end) it.ref = NULL; return it; }
-
-#if !defined _i_queue
-
-STC_INLINE intptr_t _cx_memb(_index)(const _cx_self* self, _cx_iter it)
- { return (it.ref - self->data); }
-STC_INLINE void _cx_memb(_pop_back)(_cx_self* self)
- { _cx_value* p = &self->data[--self->_len]; i_keydrop(p); }
-
-STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, const intptr_t idx) {
- assert(idx < self->_len); return self->data + idx;
-}
-STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, const intptr_t idx) {
- assert(idx < self->_len); return self->data + idx;
+STC_INLINE _cx_value _cx_MEMB(_pull_back)(_cx_Self* self) { // move back out of deq
+ c_assert(!_cx_MEMB(_empty)(self));
+ self->end = (self->end - 1) & self->capmask;
+ return self->data[self->end];
}
-STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value) {
- return _cx_memb(_push)(self, value);
-}
STC_INLINE _cx_iter
-_cx_memb(_insert)(_cx_self* self, const intptr_t idx, i_key value) {
- return _cx_memb(_insert_range)(self, self->data + idx, &value, &value + 1);
-}
-STC_INLINE _cx_iter
-_cx_memb(_insert_n)(_cx_self* self, const intptr_t idx, const _cx_value arr[], const intptr_t n) {
- return _cx_memb(_insert_range)(self, self->data + idx, arr, arr + n);
-}
-STC_INLINE _cx_iter
-_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
- return _cx_memb(_insert_range)(self, _it_ptr(it), &value, &value + 1);
+_cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, const _cx_value val) {
+ intptr_t idx = _cdeq_toidx(self, it.pos);
+ return _cx_MEMB(_insert_n)(self, idx, &val, 1);
}
STC_INLINE _cx_iter
-_cx_memb(_erase_n)(_cx_self* self, const intptr_t idx, const intptr_t n) {
- return _cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n);
-}
-STC_INLINE _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- return _cx_memb(_erase_range_p)(self, it.ref, it.ref + 1);
+_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) {
+ _cx_MEMB(_erase_n)(self, _cdeq_toidx(self, it.pos), 1);
+ if (it.pos == self->end) it.ref = NULL;
+ return it;
}
+
STC_INLINE _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter i1, _cx_iter i2) {
- return _cx_memb(_erase_range_p)(self, i1.ref, _it2_ptr(i1, i2));
+_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2) {
+ intptr_t idx1 = _cdeq_toidx(self, it1.pos);
+ intptr_t idx2 = _cdeq_toidx(self, it2.pos);
+ _cx_MEMB(_erase_n)(self, idx1, idx2 - idx1);
+ if (it1.pos == self->end) it1.ref = NULL;
+ return it1;
}
#if !defined i_no_emplace
+STC_API _cx_iter
+_cx_MEMB(_emplace_n)(_cx_Self* self, intptr_t idx, const _cx_raw* raw, intptr_t n);
+
STC_INLINE _cx_value*
-_cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw) {
- return _cx_memb(_push_front)(self, i_keyfrom(raw));
-}
+_cx_MEMB(_emplace_front)(_cx_Self* self, const _cx_raw raw)
+ { return _cx_MEMB(_push_front)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) {
- return _cx_memb(_push)(self, i_keyfrom(raw));
-}
+STC_INLINE _cx_value*
+_cx_MEMB(_emplace_back)(_cx_Self* self, const _cx_raw raw)
+ { return _cx_MEMB(_push)(self, i_keyfrom(raw)); }
STC_INLINE _cx_iter
-_cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw arr[], const intptr_t n) {
- return _cx_memb(_emplace_range)(self, self->data + idx, arr, arr + n);
-}
-STC_INLINE _cx_iter
-_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) {
- return _cx_memb(_emplace_range)(self, _it_ptr(it), &raw, &raw + 1);
-}
-#endif // !i_no_emplace
+_cx_MEMB(_emplace_at)(_cx_Self* self, _cx_iter it, const _cx_raw raw)
+ { return _cx_MEMB(_insert_at)(self, it, i_keyfrom(raw)); }
+#endif
-#if !defined i_no_cmp || defined _i_has_eq
+#if defined _i_has_eq || defined _i_has_cmp
+STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw);
STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_raw raw) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw);
+_cx_MEMB(_find)(const _cx_Self* self, _cx_raw raw) {
+ return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw);
}
STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_raw raw) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw).ref;
+_cx_MEMB(_get)(const _cx_Self* self, _cx_raw raw) {
+ return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw).ref;
}
STC_INLINE _cx_value*
-_cx_memb(_get_mut)(_cx_self* self, _cx_raw raw)
- { return (_cx_value *) _cx_memb(_get)(self, raw); }
-
-STC_INLINE bool
-_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
- if (self->_len != other->_len) return false;
- for (intptr_t i = 0; i < self->_len; ++i) {
- const _cx_raw _rx = i_keyto(self->data+i), _ry = i_keyto(other->data+i);
- if (!(i_eq((&_rx), (&_ry)))) return false;
- }
- return true;
-}
+_cx_MEMB(_get_mut)(_cx_Self* self, _cx_raw raw)
+ { return (_cx_value *) _cx_MEMB(_get)(self, raw); }
#endif
-#ifndef i_no_cmp
-
-STC_INLINE void
-_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2, int(*cmp)(const _cx_value*, const _cx_value*)) {
- qsort(i1.ref, (size_t)(_it2_ptr(i1, i2) - i1.ref), sizeof *i1.ref,
- (int(*)(const void*, const void*)) cmp);
-}
-
-STC_INLINE void
-_cx_memb(_sort)(_cx_self* self) {
- _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp));
-}
-#endif // !c_no_cmp
-#endif // _i_queue
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-#define _cdeq_nfront(self) ((self)->data - (self)->_base)
-
-STC_DEF _cx_self
-_cx_memb(_init)(void) {
- _cx_self cx = {NULL};
- return cx;
-}
-
-STC_DEF void
-_cx_memb(_clear)(_cx_self* self) {
- if (self->_cap) {
- for (_cx_value *p = self->data, *q = p + self->_len; p != q; )
- { --q; i_keydrop(q); }
- self->_len = 0;
- self->data = self->_base;
- }
-}
-
-STC_DEF void
-_cx_memb(_shrink_to_fit)(_cx_self *self) {
- if (self->_len != self->_cap) {
- c_memmove(self->_base, self->data, self->_len*c_sizeof(i_key));
- _cx_value* d = (_cx_value*)i_realloc(self->_base, self->_len*c_sizeof(i_key));
- if (d) {
- self->_base = d;
- self->_cap = self->_len;
- }
- self->data = self->_base;
- }
-}
-
-STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
- if (self->_base) {
- _cx_memb(_clear)(self);
- i_free(self->_base);
- }
-}
-
-static intptr_t
-_cx_memb(_realloc_)(_cx_self* self, const intptr_t n) {
- const intptr_t cap = (intptr_t)((float)self->_len*1.7f) + n + 7;
- const intptr_t nfront = _cdeq_nfront(self);
- _cx_value* d = (_cx_value*)i_realloc(self->_base, cap*c_sizeof(i_key));
- if (!d)
- return 0;
- self->_cap = cap;
- self->_base = d;
- self->data = d + nfront;
- return cap;
-}
-
-static bool
-_cx_memb(_expand_right_half_)(_cx_self* self, const intptr_t idx, const intptr_t n) {
- const intptr_t sz = self->_len, cap = self->_cap;
- const intptr_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront;
- if (nback >= n || (intptr_t)((float)sz*1.3f) + n > cap) {
- if (!_cx_memb(_realloc_)(self, n))
- return false;
- c_memmove(self->data + idx + n, self->data + idx, (sz - idx)*c_sizeof(i_key));
- } else {
-#if !defined _i_queue
- const intptr_t unused = cap - (sz + n);
- const intptr_t pos = (nfront*2 < unused) ? nfront : unused/2;
-#else
- const intptr_t pos = 0;
-#endif
- c_memmove(self->_base + pos, self->data, idx*c_sizeof(i_key));
- c_memmove(self->data + pos + idx + n, self->data + idx, (sz - idx)*c_sizeof(i_key));
- self->data = self->_base + pos;
- }
- return true;
-}
-
-STC_DEF _cx_self
-_cx_memb(_with_capacity)(const intptr_t n) {
- _cx_self cx = _cx_memb(_init)();
- _cx_memb(_expand_right_half_)(&cx, 0, n);
- return cx;
-}
+#if defined(i_implement) || defined(i_static)
-STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const intptr_t n) {
- const intptr_t sz = self->_len;
- return n <= sz || _cx_memb(_expand_right_half_)(self, sz, n - sz);
-}
+#include "priv/cqueue_imp.h"
STC_DEF _cx_value*
-_cx_memb(_push)(_cx_self* self, i_key value) {
- if (_cdeq_nfront(self) + self->_len == self->_cap)
- _cx_memb(_expand_right_half_)(self, self->_len, 1);
- _cx_value *v = self->data + self->_len++;
+_cx_MEMB(_push_front)(_cx_Self* self, i_key value) {
+ intptr_t start = (self->start - 1) & self->capmask;
+ if (start == self->end) { // full
+ _cx_MEMB(_reserve)(self, self->capmask + 3); // => 2x expand
+ start = (self->start - 1) & self->capmask;
+ }
+ _cx_value *v = self->data + start;
+ self->start = start;
*v = value;
return v;
}
-#if !defined i_no_clone
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self cx) {
- _cx_self out = _cx_memb(_with_capacity)(cx._len);
- if (out._base)
- for (intptr_t i = 0; i < cx._len; ++i)
- out.data[i] = i_keyclone(cx.data[i]);
- return out;
-}
-#endif
-
-#if !defined _i_queue
-
-static void
-_cx_memb(_expand_left_half_)(_cx_self* self, const intptr_t idx, const intptr_t n) {
- intptr_t cap = self->_cap;
- const intptr_t sz = self->_len;
- const intptr_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront;
- if (nfront >= n) {
- self->data = (_cx_value *)c_memmove(self->data - n, self->data, idx*c_sizeof(i_key));
- } else {
- if ((intptr_t)((float)sz*1.3f) + n > cap)
- cap = _cx_memb(_realloc_)(self, n);
- const intptr_t unused = cap - (sz + n);
- const intptr_t pos = (nback*2 < unused) ? unused - nback : unused/2;
- c_memmove(self->_base + pos + idx + n, self->data + idx, (sz - idx)*c_sizeof(i_key));
- self->data = (_cx_value *)c_memmove(self->_base + pos, self->data, idx*c_sizeof(i_key));
- }
-}
-
-static _cx_iter
-_cx_memb(_insert_uninit)(_cx_self* self, _cx_value* pos, const intptr_t n) {
- if (n) {
- if (!pos) pos = self->data + self->_len;
- const intptr_t idx = (pos - self->data);
- if (idx*2 < self->_len)
- _cx_memb(_expand_left_half_)(self, idx, n);
- else
- _cx_memb(_expand_right_half_)(self, idx, n);
- self->_len += n;
- pos = self->data + idx;
- }
- return c_LITERAL(_cx_iter){pos, self->data + self->_len};
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push_front)(_cx_self* self, i_key value) {
- if (self->data == self->_base)
- _cx_memb(_expand_left_half_)(self, 0, 1);
- else
- --self->data;
- ++self->_len;
- *self->data = value;
- return self->data;
+STC_DEF void
+_cx_MEMB(_erase_n)(_cx_Self* self, const intptr_t idx, const intptr_t n) {
+ const intptr_t len = _cx_MEMB(_size)(self);
+ for (intptr_t i = idx + n - 1; i >= idx; --i)
+ i_keydrop(_cx_MEMB(_at_mut)(self, i));
+ for (intptr_t i = idx, j = i + n; j < len; ++i, ++j)
+ *_cx_MEMB(_at_mut)(self, i) = *_cx_MEMB(_at)(self, j);
+ self->end = (self->end - n) & self->capmask;
}
STC_DEF _cx_iter
-_cx_memb(_insert_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1));
- if (it.ref)
- c_memcpy(it.ref, p1, (p2 - p1)*c_sizeof *p1);
+_cx_MEMB(_insert_uninit)(_cx_Self* self, const intptr_t idx, const intptr_t n) {
+ const intptr_t len = _cx_MEMB(_size)(self);
+ _cx_iter it = {._s=self};
+ if (len + n > self->capmask)
+ if (!_cx_MEMB(_reserve)(self, len*5/4 + n))
+ return it;
+ it.pos = _cdeq_topos(self, idx);
+ it.ref = self->data + it.pos;
+ self->end = (self->end + n) & self->capmask;
+
+ if (it.pos < self->end) // common case because of reserve policy
+ c_memmove(it.ref + n, it.ref, (len - idx)*c_sizeof *it.ref);
+ else for (intptr_t i = len - 1, j = i + n; i >= idx; --i, --j)
+ *_cx_MEMB(_at_mut)(self, j) = *_cx_MEMB(_at)(self, i);
return it;
}
STC_DEF _cx_iter
-_cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2) {
- assert(p1 && p2);
- intptr_t len = p2 - p1;
- _cx_value* p = p1, *end = self->data + self->_len;
- for (; p != p2; ++p)
- { i_keydrop(p); }
- c_memmove(p1, p2, (end - p2)*c_sizeof *p1);
- self->_len -= len;
- return c_LITERAL(_cx_iter){p2 == end ? NULL : p1, end - len};
-}
-
-#if !defined i_no_clone
-STC_DEF _cx_iter
-_cx_memb(_copy_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1));
- if (it.ref)
- for (_cx_value* p = it.ref; p1 != p2; ++p1)
- *p++ = i_keyclone((*p1));
+_cx_MEMB(_insert_n)(_cx_Self* self, const intptr_t idx, const _cx_value* arr, const intptr_t n) {
+ _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n);
+ for (intptr_t i = idx, j = 0; j < n; ++i, ++j)
+ *_cx_MEMB(_at_mut)(self, i) = arr[j];
return it;
}
-#endif // !i_no_clone
#if !defined i_no_emplace
STC_DEF _cx_iter
-_cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos,
- const _cx_raw* p1, const _cx_raw* p2) {
- _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1));
- if (it.ref)
- for (_cx_value* p = it.ref; p1 != p2; ++p1)
- *p++ = i_keyfrom((*p1));
+_cx_MEMB(_emplace_n)(_cx_Self* self, const intptr_t idx, const _cx_raw* raw, const intptr_t n) {
+ _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n);
+ for (intptr_t i = idx, j = 0; j < n; ++i, ++j)
+ *_cx_MEMB(_at_mut)(self, i) = i_keyfrom(raw[j]);
return it;
}
-#endif // !i_no_emplace
+#endif
-#if !defined i_no_cmp || defined _i_has_eq
+#if defined _i_has_eq || defined _i_has_cmp
STC_DEF _cx_iter
-_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
- const _cx_value* p2 = _it2_ptr(i1, i2);
- for (; i1.ref != p2; ++i1.ref) {
+_cx_MEMB(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
+ for (; i1.pos != i2.pos; _cx_MEMB(_next)(&i1)) {
const _cx_raw r = i_keyto(i1.ref);
if (i_eq((&raw), (&r)))
- return i1;
+ break;
}
- i2.ref = NULL;
- return i2;
+ return i1;
}
#endif
-#ifndef i_no_cmp
-STC_DEF int
-_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- const _cx_raw rx = i_keyto(x);
- const _cx_raw ry = i_keyto(y);
- return i_cmp((&rx), (&ry));
-}
-#endif // !c_no_cmp
-#endif // !_i_queue
#endif // IMPLEMENTATION
#define CDEQ_H_INCLUDED
#include "priv/template2.h"
diff --git a/include/stc/clist.h b/include/stc/clist.h
index f7fb4152..6a205c2b 100644
--- a/include/stc/clist.h
+++ b/include/stc/clist.h
@@ -32,7 +32,7 @@
#define i_tag ix
#include <stc/clist.h>
- int main()
+ int main(void)
{
c_auto (clist_ix, list)
{
@@ -51,9 +51,10 @@
}
}
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CLIST_H_INCLUDED
+#include "ccommon.h"
#include "forward.h"
#include <stdlib.h>
#include <string.h>
@@ -77,82 +78,81 @@
#endif // CLIST_H_INCLUDED
-#ifndef _i_prefix
#define _i_prefix clist_
-#endif
#include "priv/template.h"
#ifndef i_is_forward
- _cx_deftypes(_c_clist_types, _cx_self, i_key);
+ _cx_DEFTYPES(_c_clist_types, _cx_Self, i_key);
#endif
-_cx_deftypes(_c_clist_complete_types, _cx_self, dummy);
+_cx_DEFTYPES(_c_clist_complete_types, _cx_Self, dummy);
typedef i_keyraw _cx_raw;
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value);
-STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value);
-STC_API _cx_iter _cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value);
-STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it);
-STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2);
-#if !defined i_no_cmp || defined _i_has_eq
-STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val);
-STC_API intptr_t _cx_memb(_remove)(_cx_self* self, _cx_raw val);
+STC_API void _cx_MEMB(_drop)(_cx_Self* self);
+STC_API _cx_value* _cx_MEMB(_push_back)(_cx_Self* self, i_key value);
+STC_API _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value);
+STC_API _cx_iter _cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, i_key value);
+STC_API _cx_iter _cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it);
+STC_API _cx_iter _cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2);
+#if defined _i_has_eq || defined _i_has_cmp
+STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val);
+STC_API intptr_t _cx_MEMB(_remove)(_cx_Self* self, _cx_raw val);
#endif
-#ifndef i_no_cmp
-STC_API bool _cx_memb(_sort_with)(_cx_self* self, int(*cmp)(const _cx_value*, const _cx_value*));
-STC_API int _cx_memb(_sort_cmp_)(const _cx_value*, const _cx_value*);
-STC_INLINE bool _cx_memb(_sort)(_cx_self* self)
- { return _cx_memb(_sort_with)(self, _cx_memb(_sort_cmp_)); }
+#if defined _i_has_cmp
+STC_API bool _cx_MEMB(_sort_with)(_cx_Self* self, int(*cmp)(const _cx_value*, const _cx_value*));
+STC_API int _cx_MEMB(_sort_cmp_)(const _cx_value*, const _cx_value*);
+STC_INLINE bool _cx_MEMB(_sort)(_cx_Self* self)
+ { return _cx_MEMB(_sort_with)(self, _cx_MEMB(_sort_cmp_)); }
#endif
-STC_API void _cx_memb(_reverse)(_cx_self* self);
-STC_API _cx_iter _cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other);
-STC_API _cx_self _cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2);
-STC_API _cx_value* _cx_memb(_push_back_node)(_cx_self* self, _cx_node* node);
-STC_API _cx_value* _cx_memb(_insert_after_node)(_cx_self* self, _cx_node* ref, _cx_node* node);
-STC_API _cx_node* _cx_memb(_unlink_after_node)(_cx_self* self, _cx_node* ref);
-STC_API void _cx_memb(_erase_after_node)(_cx_self* self, _cx_node* ref);
-STC_INLINE _cx_node* _cx_memb(_get_node)(_cx_value* vp) { return _clist_tonode(vp); }
-
+STC_API void _cx_MEMB(_reverse)(_cx_Self* self);
+STC_API _cx_iter _cx_MEMB(_splice)(_cx_Self* self, _cx_iter it, _cx_Self* other);
+STC_API _cx_Self _cx_MEMB(_split_off)(_cx_Self* self, _cx_iter it1, _cx_iter it2);
+STC_API _cx_value* _cx_MEMB(_push_back_node)(_cx_Self* self, _cx_node* node);
+STC_API _cx_value* _cx_MEMB(_insert_after_node)(_cx_Self* self, _cx_node* ref, _cx_node* node);
+STC_API _cx_node* _cx_MEMB(_unlink_after_node)(_cx_Self* self, _cx_node* ref);
+STC_API void _cx_MEMB(_erase_after_node)(_cx_Self* self, _cx_node* ref);
+STC_INLINE _cx_node* _cx_MEMB(_get_node)(_cx_value* pval) { return _clist_tonode(pval); }
+STC_INLINE _cx_node* _cx_MEMB(_unlink_front_node)(_cx_Self* self)
+ { return _cx_MEMB(_unlink_after_node)(self, self->last); }
#if !defined i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
-STC_INLINE i_key _cx_memb(_value_clone)(i_key val) { return i_keyclone(val); }
+STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx);
+STC_INLINE i_key _cx_MEMB(_value_clone)(i_key val) { return i_keyclone(val); }
STC_INLINE void
-_cx_memb(_copy)(_cx_self *self, const _cx_self* other) {
+_cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) {
if (self->last == other->last) return;
- _cx_memb(_drop)(self); *self = _cx_memb(_clone)(*other);
+ _cx_MEMB(_drop)(self); *self = _cx_MEMB(_clone)(*other);
}
#endif // !i_no_clone
#if !defined i_no_emplace
-STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push_back)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push_front)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_iter _cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw)
- { return _cx_memb(_insert_at)(self, it, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push_back)(self, i_keyfrom(raw)); }
+STC_INLINE _cx_value* _cx_MEMB(_emplace_back)(_cx_Self* self, _cx_raw raw)
+ { return _cx_MEMB(_push_back)(self, i_keyfrom(raw)); }
+STC_INLINE _cx_value* _cx_MEMB(_emplace_front)(_cx_Self* self, _cx_raw raw)
+ { return _cx_MEMB(_push_front)(self, i_keyfrom(raw)); }
+STC_INLINE _cx_iter _cx_MEMB(_emplace_at)(_cx_Self* self, _cx_iter it, _cx_raw raw)
+ { return _cx_MEMB(_insert_at)(self, it, i_keyfrom(raw)); }
+STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw)
+ { return _cx_MEMB(_push_back)(self, i_keyfrom(raw)); }
#endif // !i_no_emplace
-STC_INLINE _cx_self _cx_memb(_init)(void) { return c_LITERAL(_cx_self){NULL}; }
-STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n)
- { while (n--) _cx_memb(_push_back)(self, i_keyfrom(*raw++)); }
-STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n)
- { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; }
-STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, intptr_t n) { (void)(self + n); return true; }
-STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) { return self->last == NULL; }
-STC_INLINE void _cx_memb(_clear)(_cx_self* self) { _cx_memb(_drop)(self); }
-STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, i_key value)
- { return _cx_memb(_push_back)(self, value); }
-STC_INLINE void _cx_memb(_pop_front)(_cx_self* self)
- { assert(!_cx_memb(_empty)(self)); _cx_memb(_erase_after_node)(self, self->last); }
-STC_INLINE _cx_node* _cx_memb(_unlink_node_front)(_cx_self* self)
- { return _cx_memb(_unlink_after_node)(self, self->last); }
-STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return &self->last->next->value; }
-STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) { return &self->last->value; }
+STC_INLINE _cx_Self _cx_MEMB(_init)(void) { return c_LITERAL(_cx_Self){NULL}; }
+STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n)
+ { while (n--) _cx_MEMB(_push_back)(self, i_keyfrom(*raw++)); }
+STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n)
+ { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; }
+STC_INLINE bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t n) { (void)(self + n); return true; }
+STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) { return self->last == NULL; }
+STC_INLINE void _cx_MEMB(_clear)(_cx_Self* self) { _cx_MEMB(_drop)(self); }
+STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value)
+ { return _cx_MEMB(_push_back)(self, value); }
+STC_INLINE void _cx_MEMB(_pop_front)(_cx_Self* self)
+ { c_assert(!_cx_MEMB(_empty)(self)); _cx_MEMB(_erase_after_node)(self, self->last); }
+STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) { return &self->last->next->value; }
+STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self) { return &self->last->value; }
+STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* pval) { return i_keyto(pval); }
+STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* pval) { i_keydrop(pval); }
STC_INLINE intptr_t
-_cx_memb(_count)(const _cx_self* self) {
+_cx_MEMB(_count)(const _cx_Self* self) {
intptr_t n = 1; const _cx_node *node = self->last;
if (!node) return 0;
while ((node = node->next) != self->last) ++n;
@@ -160,53 +160,53 @@ _cx_memb(_count)(const _cx_self* self) {
}
STC_INLINE _cx_iter
-_cx_memb(_begin)(const _cx_self* self) {
+_cx_MEMB(_begin)(const _cx_Self* self) {
_cx_value* head = self->last ? &self->last->next->value : NULL;
return c_LITERAL(_cx_iter){head, &self->last, self->last};
}
STC_INLINE _cx_iter
-_cx_memb(_end)(const _cx_self* self)
+_cx_MEMB(_end)(const _cx_Self* self)
{ return c_LITERAL(_cx_iter){NULL}; }
STC_INLINE void
-_cx_memb(_next)(_cx_iter* it) {
+_cx_MEMB(_next)(_cx_iter* it) {
_cx_node* node = it->prev = _clist_tonode(it->ref);
it->ref = (node == *it->_last ? NULL : &node->next->value);
}
STC_INLINE _cx_iter
-_cx_memb(_advance)(_cx_iter it, size_t n) {
- while (n-- && it.ref) _cx_memb(_next)(&it);
+_cx_MEMB(_advance)(_cx_iter it, size_t n) {
+ while (n-- && it.ref) _cx_MEMB(_next)(&it);
return it;
}
STC_INLINE _cx_iter
-_cx_memb(_splice_range)(_cx_self* self, _cx_iter it,
- _cx_self* other, _cx_iter it1, _cx_iter it2) {
- _cx_self tmp = _cx_memb(_split_off)(other, it1, it2);
- return _cx_memb(_splice)(self, it, &tmp);
+_cx_MEMB(_splice_range)(_cx_Self* self, _cx_iter it,
+ _cx_Self* other, _cx_iter it1, _cx_iter it2) {
+ _cx_Self tmp = _cx_MEMB(_split_off)(other, it1, it2);
+ return _cx_MEMB(_splice)(self, it, &tmp);
}
-#if !defined i_no_cmp || defined _i_has_eq
+#if defined _i_has_eq || defined _i_has_cmp
STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_raw val) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val);
+_cx_MEMB(_find)(const _cx_Self* self, _cx_raw val) {
+ return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), val);
}
STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_raw val) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref;
+_cx_MEMB(_get)(const _cx_Self* self, _cx_raw val) {
+ return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), val).ref;
}
STC_INLINE _cx_value*
-_cx_memb(_get_mut)(_cx_self* self, _cx_raw val) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref;
+_cx_MEMB(_get_mut)(_cx_Self* self, _cx_raw val) {
+ return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), val).ref;
}
-STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
- _cx_iter i = _cx_memb(_begin)(self), j = _cx_memb(_begin)(other);
- for (; i.ref && j.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) {
+STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ _cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other);
+ for (; i.ref && j.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j)) {
const _cx_raw _rx = i_keyto(i.ref), _ry = i_keyto(j.ref);
if (!(i_eq((&_rx), (&_ry)))) return false;
}
@@ -215,32 +215,32 @@ STC_INLINE bool _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
#endif
// -------------------------- IMPLEMENTATION -------------------------
-#if defined(i_implement)
+#if defined(i_implement) || defined(i_static)
#if !defined i_no_clone
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self cx) {
- _cx_self out = _cx_memb(_init)();
- c_foreach (it, _cx_self, cx)
- _cx_memb(_push_back)(&out, i_keyclone((*it.ref)));
+STC_DEF _cx_Self
+_cx_MEMB(_clone)(_cx_Self cx) {
+ _cx_Self out = _cx_MEMB(_init)();
+ c_foreach (it, _cx_Self, cx)
+ _cx_MEMB(_push_back)(&out, i_keyclone((*it.ref)));
return out;
}
#endif
STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
- while (self->last) _cx_memb(_erase_after_node)(self, self->last);
+_cx_MEMB(_drop)(_cx_Self* self) {
+ while (self->last) _cx_MEMB(_erase_after_node)(self, self->last);
}
STC_DEF _cx_value*
-_cx_memb(_push_back)(_cx_self* self, i_key value) {
+_cx_MEMB(_push_back)(_cx_Self* self, i_key value) {
_c_clist_insert_entry_after(self->last, value);
self->last = entry;
return &entry->value;
}
STC_DEF _cx_value*
-_cx_memb(_push_front)(_cx_self* self, i_key value) {
+_cx_MEMB(_push_front)(_cx_Self* self, i_key value) {
_c_clist_insert_entry_after(self->last, value);
if (!self->last)
self->last = entry;
@@ -248,14 +248,14 @@ _cx_memb(_push_front)(_cx_self* self, i_key value) {
}
STC_DEF _cx_value*
-_cx_memb(_push_back_node)(_cx_self* self, _cx_node* node) {
+_cx_MEMB(_push_back_node)(_cx_Self* self, _cx_node* node) {
_c_clist_insert_after_node(self->last, node);
self->last = node;
return &node->value;
}
STC_DEF _cx_value*
-_cx_memb(_insert_after_node)(_cx_self* self, _cx_node* ref, _cx_node* node) {
+_cx_MEMB(_insert_after_node)(_cx_Self* self, _cx_node* ref, _cx_node* node) {
_c_clist_insert_after_node(ref, node);
if (!self->last)
self->last = node;
@@ -263,7 +263,7 @@ _cx_memb(_insert_after_node)(_cx_self* self, _cx_node* ref, _cx_node* node) {
}
STC_DEF _cx_iter
-_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
+_cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, i_key value) {
_cx_node* node = it.ref ? it.prev : self->last;
_c_clist_insert_entry_after(node, value);
if (!self->last || !it.ref) {
@@ -275,32 +275,32 @@ _cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
}
STC_DEF _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
+_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) {
_cx_node *node = _clist_tonode(it.ref);
it.ref = (node == self->last) ? NULL : &node->next->value;
- _cx_memb(_erase_after_node)(self, it.prev);
+ _cx_MEMB(_erase_after_node)(self, it.prev);
return it;
}
STC_DEF _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
+_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2) {
_cx_node *end = it2.ref ? _clist_tonode(it2.ref) : self->last->next;
if (it1.ref != it2.ref) do {
- _cx_memb(_erase_after_node)(self, it1.prev);
+ _cx_MEMB(_erase_after_node)(self, it1.prev);
if (!self->last) break;
} while (it1.prev->next != end);
return it2;
}
STC_DEF void
-_cx_memb(_erase_after_node)(_cx_self* self, _cx_node* ref) {
- _cx_node* node = _cx_memb(_unlink_after_node)(self, ref);
+_cx_MEMB(_erase_after_node)(_cx_Self* self, _cx_node* ref) {
+ _cx_node* node = _cx_MEMB(_unlink_after_node)(self, ref);
i_keydrop((&node->value));
i_free(node);
}
STC_DEF _cx_node*
-_cx_memb(_unlink_after_node)(_cx_self* self, _cx_node* ref) {
+_cx_MEMB(_unlink_after_node)(_cx_Self* self, _cx_node* ref) {
_cx_node* node = ref->next, *next = node->next;
ref->next = next;
if (node == next)
@@ -311,17 +311,17 @@ _cx_memb(_unlink_after_node)(_cx_self* self, _cx_node* ref) {
}
STC_DEF void
-_cx_memb(_reverse)(_cx_self* self) {
- _cx_self rev = {NULL};
+_cx_MEMB(_reverse)(_cx_Self* self) {
+ _cx_Self rev = {NULL};
while (self->last) {
- _cx_node* node = _cx_memb(_unlink_after_node)(self, self->last);
- _cx_memb(_insert_after_node)(&rev, rev.last, node);
+ _cx_node* node = _cx_MEMB(_unlink_after_node)(self, self->last);
+ _cx_MEMB(_insert_after_node)(&rev, rev.last, node);
}
*self = rev;
}
STC_DEF _cx_iter
-_cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other) {
+_cx_MEMB(_splice)(_cx_Self* self, _cx_iter it, _cx_Self* other) {
if (!self->last)
self->last = other->last;
else if (other->last) {
@@ -335,9 +335,9 @@ _cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other) {
return it;
}
-STC_DEF _cx_self
-_cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
- _cx_self lst = {NULL};
+STC_DEF _cx_Self
+_cx_MEMB(_split_off)(_cx_Self* self, _cx_iter it1, _cx_iter it2) {
+ _cx_Self lst = {NULL};
if (it1.ref == it2.ref)
return lst;
_cx_node *p1 = it1.prev,
@@ -350,11 +350,10 @@ _cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
return lst;
}
-#if !defined i_no_cmp || defined _i_has_eq
-
+#if defined _i_has_eq || defined _i_has_cmp
STC_DEF _cx_iter
-_cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) {
- c_foreach (it, _cx_self, it1, it2) {
+_cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) {
+ c_foreach (it, _cx_Self, it1, it2) {
_cx_raw r = i_keyto(it.ref);
if (i_eq((&r), (&val)))
return it;
@@ -363,14 +362,14 @@ _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) {
}
STC_DEF intptr_t
-_cx_memb(_remove)(_cx_self* self, _cx_raw val) {
+_cx_MEMB(_remove)(_cx_Self* self, _cx_raw val) {
intptr_t n = 0;
_cx_node *prev = self->last, *node;
if (prev) do {
node = prev->next;
_cx_raw r = i_keyto((&node->value));
if (i_eq((&r), (&val))) {
- _cx_memb(_erase_after_node)(self, prev), ++n;
+ _cx_MEMB(_erase_after_node)(self, prev), ++n;
if (!self->last) break;
} else
prev = node;
@@ -379,29 +378,29 @@ _cx_memb(_remove)(_cx_self* self, _cx_raw val) {
}
#endif
-#ifndef i_no_cmp
-STC_DEF int _cx_memb(_sort_cmp_)(const _cx_value* x, const _cx_value* y) {
+#if defined _i_has_cmp
+STC_DEF int _cx_MEMB(_sort_cmp_)(const _cx_value* x, const _cx_value* y) {
const _cx_raw a = i_keyto(x), b = i_keyto(y);
return i_cmp((&a), (&b));
}
-STC_DEF bool _cx_memb(_sort_with)(_cx_self* self, int(*cmp)(const _cx_value*, const _cx_value*)) {
- size_t len = 0, cap = 0;
+STC_DEF bool _cx_MEMB(_sort_with)(_cx_Self* self, int(*cmp)(const _cx_value*, const _cx_value*)) {
+ intptr_t len = 0, cap = 0;
_cx_value *a = NULL, *p = NULL;
_cx_iter i;
- for (i = _cx_memb(_begin)(self); i.ref; _cx_memb(_next)(&i)) {
+ for (i = _cx_MEMB(_begin)(self); i.ref; _cx_MEMB(_next)(&i)) {
if (len == cap) {
- if ((p = (_cx_value *)i_realloc(a, (cap += cap/2 + 4)*sizeof *a))) a = p;
+ if ((p = (_cx_value *)i_realloc(a, (cap += cap/2 + 4)*c_sizeof *a))) a = p;
else { i_free(a); return false; }
}
a[len++] = *i.ref;
}
- qsort(a, len, sizeof *a, (int(*)(const void*, const void*))cmp);
- for (i = _cx_memb(_begin)(self); i.ref; _cx_memb(_next)(&i), ++p)
+ qsort(a, (size_t)len, sizeof *a, (int(*)(const void*, const void*))cmp);
+ for (i = _cx_MEMB(_begin)(self); i.ref; _cx_MEMB(_next)(&i), ++p)
*i.ref = *p;
i_free(a); return true;
}
-#endif // !c_no_cmp
+#endif // _i_has_cmp
#endif // i_implement
#define CLIST_H_INCLUDED
#include "priv/template2.h"
diff --git a/include/stc/cmap.h b/include/stc/cmap.h
index 14782b71..c069fbd8 100644
--- a/include/stc/cmap.h
+++ b/include/stc/cmap.h
@@ -47,43 +47,32 @@ int main(void) {
cmap_ichar_drop(&m);
}
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CMAP_H_INCLUDED
+#include "ccommon.h"
#include "forward.h"
#include <stdlib.h>
#include <string.h>
-typedef struct { int64_t idx; uint8_t hx; } chash_bucket_t;
+struct chash_slot { uint8_t hashx; };
#endif // CMAP_H_INCLUDED
#ifndef _i_prefix
-#define _i_prefix cmap_
-#endif
-#ifdef _i_isset
- #define _i_MAP_ONLY c_false
- #define _i_SET_ONLY c_true
- #define _i_keyref(vp) (vp)
-#else
+ #define _i_prefix cmap_
#define _i_ismap
#define _i_MAP_ONLY c_true
#define _i_SET_ONLY c_false
#define _i_keyref(vp) (&(vp)->first)
-#endif
-#define _i_ishash
-#ifndef i_max_load_factor
- #define i_max_load_factor 0.85f
-#endif
-#ifndef i_ssize
- #define i_ssize int32_t
- #define _i_size intptr_t
- #define _i_expandby 1
#else
- #define _i_expandby 2
- #define _i_size i_ssize
+ #define _i_isset
+ #define _i_MAP_ONLY c_false
+ #define _i_SET_ONLY c_true
+ #define _i_keyref(vp) (vp)
#endif
+#define _i_ishash
#include "priv/template.h"
#ifndef i_is_forward
- _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY);
+ _cx_DEFTYPES(_c_chash_types, _cx_Self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY);
#endif
_i_MAP_ONLY( struct _cx_value {
@@ -92,61 +81,61 @@ _i_MAP_ONLY( struct _cx_value {
}; )
typedef i_keyraw _cx_keyraw;
-typedef i_valraw _cx_memb(_rmapped);
+typedef i_valraw _cx_MEMB(_rmapped);
typedef _i_SET_ONLY( i_keyraw )
_i_MAP_ONLY( struct { i_keyraw first;
i_valraw second; } )
_cx_raw;
-STC_API _cx_self _cx_memb(_with_capacity)(_i_size cap);
+STC_API _cx_Self _cx_MEMB(_with_capacity)(intptr_t cap);
#if !defined i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self map);
+STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self map);
#endif
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API void _cx_memb(_clear)(_cx_self* self);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, _i_size capacity);
-STC_API chash_bucket_t _cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr);
-STC_API _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey);
-STC_API void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* val);
-
-STC_INLINE _cx_self _cx_memb(_init)(void) { _cx_self map = {0}; return map; }
-STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) { _cx_memb(_reserve)(self, self->size); }
-STC_INLINE float _cx_memb(_max_load_factor)(const _cx_self* self) { return (float)(i_max_load_factor); }
-STC_INLINE bool _cx_memb(_empty)(const _cx_self* map) { return !map->size; }
-STC_INLINE _i_size _cx_memb(_size)(const _cx_self* map) { return map->size; }
-STC_INLINE _i_size _cx_memb(_bucket_count)(_cx_self* map) { return map->bucket_count; }
-STC_INLINE _i_size _cx_memb(_capacity)(const _cx_self* map)
- { return (_i_size)((float)map->bucket_count * (i_max_load_factor)); }
-STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey)
- { return self->size && self->_hashx[_cx_memb(_bucket_)(self, &rkey).idx]; }
-
-#ifndef _i_isset
- STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped);
+STC_API void _cx_MEMB(_drop)(_cx_Self* self);
+STC_API void _cx_MEMB(_clear)(_cx_Self* self);
+STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t capacity);
+STC_API _cx_result _cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr);
+STC_API _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey);
+STC_API void _cx_MEMB(_erase_entry)(_cx_Self* self, _cx_value* val);
+STC_API float _cx_MEMB(_max_load_factor)(const _cx_Self* self);
+STC_API intptr_t _cx_MEMB(_capacity)(const _cx_Self* map);
+
+STC_INLINE _cx_Self _cx_MEMB(_init)(void) { _cx_Self map = {0}; return map; }
+STC_INLINE void _cx_MEMB(_shrink_to_fit)(_cx_Self* self) { _cx_MEMB(_reserve)(self, (intptr_t)self->size); }
+STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* map) { return !map->size; }
+STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* map) { return (intptr_t)map->size; }
+STC_INLINE intptr_t _cx_MEMB(_bucket_count)(_cx_Self* map) { return map->bucket_count; }
+STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rkey)
+ { return self->size && !_cx_MEMB(_bucket_)(self, &rkey).inserted; }
+
+#ifdef _i_ismap
+ STC_API _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key key, i_val mapped);
#if !defined i_no_emplace
- STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped);
+ STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped);
#endif
STC_INLINE const _cx_mapped*
- _cx_memb(_at)(const _cx_self* self, _cx_keyraw rkey) {
- chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey);
- assert(self->_hashx[b.idx]);
- return &self->table[b.idx].second;
+ _cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey) {
+ _cx_result b = _cx_MEMB(_bucket_)(self, &rkey);
+ c_assert(!b.inserted);
+ return &b.ref->second;
}
+
STC_INLINE _cx_mapped*
- _cx_memb(_at_mut)(_cx_self* self, _cx_keyraw rkey)
- { return (_cx_mapped*)_cx_memb(_at)(self, rkey); }
-#endif // !_i_isset
+ _cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey)
+ { return (_cx_mapped*)_cx_MEMB(_at)(self, rkey); }
+#endif // _i_ismap
#if !defined i_no_clone
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) {
- if (self->table == other->table)
+STC_INLINE void _cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) {
+ if (self->data == other->data)
return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(*other);
+ _cx_MEMB(_drop)(self);
+ *self = _cx_MEMB(_clone)(*other);
}
STC_INLINE _cx_value
-_cx_memb(_value_clone)(_cx_value _val) {
+_cx_MEMB(_value_clone)(_cx_value _val) {
*_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val)));
_i_MAP_ONLY( _val.second = i_valclone(_val.second); )
return _val;
@@ -155,31 +144,39 @@ _cx_memb(_value_clone)(_cx_value _val) {
#if !defined i_no_emplace
STC_INLINE _cx_result
-_cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, rkey);
+_cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey);
if (_res.inserted) {
*_i_keyref(_res.ref) = i_keyfrom(rkey);
_i_MAP_ONLY( _res.ref->second = i_valfrom(rmapped); )
}
return _res;
}
+
+#ifdef _i_ismap
+ STC_INLINE _cx_result
+ _cx_MEMB(_emplace_key)(_cx_Self* self, _cx_keyraw rkey) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey);
+ if (_res.inserted)
+ _res.ref->first = i_keyfrom(rkey);
+ return _res;
+ }
+#endif // _i_ismap
#endif // !i_no_emplace
-STC_INLINE _cx_raw
-_cx_memb(_value_toraw)(const _cx_value* val) {
+STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* val) {
return _i_SET_ONLY( i_keyto(val) )
_i_MAP_ONLY( c_LITERAL(_cx_raw){i_keyto((&val->first)), i_valto((&val->second))} );
}
-STC_INLINE void
-_cx_memb(_value_drop)(_cx_value* _val) {
+STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* _val) {
i_keydrop(_i_keyref(_val));
_i_MAP_ONLY( i_valdrop((&_val->second)); )
}
STC_INLINE _cx_result
-_cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key)));
+_cx_MEMB(_insert)(_cx_Self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key)));
if (_res.inserted)
{ *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )}
else
@@ -187,157 +184,150 @@ _cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) {
return _res;
}
-STC_INLINE _cx_result
-_cx_memb(_push)(_cx_self* self, _cx_value _val) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
+STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, _cx_value _val) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
if (_res.inserted)
*_res.ref = _val;
else
- _cx_memb(_value_drop)(&_val);
- return _res;
+ _cx_MEMB(_value_drop)(&_val);
+ return _res.ref;
}
-STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, _i_size n) {
+STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) {
while (n--)
#if defined _i_isset && defined i_no_emplace
- _cx_memb(_insert)(self, *raw++);
+ _cx_MEMB(_insert)(self, *raw++);
#elif defined _i_isset
- _cx_memb(_emplace)(self, *raw++);
+ _cx_MEMB(_emplace)(self, *raw++);
#elif defined i_no_emplace
- _cx_memb(_insert_or_assign)(self, raw->first, raw->second), ++raw;
+ _cx_MEMB(_insert_or_assign)(self, raw->first, raw->second), ++raw;
#else
- _cx_memb(_emplace_or_assign)(self, raw->first, raw->second), ++raw;
+ _cx_MEMB(_emplace_or_assign)(self, raw->first, raw->second), ++raw;
#endif
}
-STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, _i_size n)
- { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; }
+STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n)
+ { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; }
-STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) {
- _cx_iter it = {self->table, self->table+self->bucket_count, self->_hashx};
- if (it._hx)
- while (*it._hx == 0)
- ++it.ref, ++it._hx;
- if (it.ref == it._end) it.ref = NULL;
- return it;
-}
+STC_API _cx_iter _cx_MEMB(_begin)(const _cx_Self* self);
-STC_INLINE _cx_iter
-_cx_memb(_end)(const _cx_self* self)
+STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self)
{ return c_LITERAL(_cx_iter){NULL}; }
-STC_INLINE void
-_cx_memb(_next)(_cx_iter* it) {
- while ((++it->ref, *++it->_hx == 0)) ;
+STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) {
+ while ((++it->ref, (++it->sref)->hashx == 0)) ;
if (it->ref == it->_end) it->ref = NULL;
}
-STC_INLINE _cx_iter
-_cx_memb(_advance)(_cx_iter it, size_t n) {
- while (n-- && it.ref) _cx_memb(_next)(&it);
+STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n) {
+ while (n-- && it.ref) _cx_MEMB(_next)(&it);
return it;
}
STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_keyraw rkey) {
- int64_t idx;
- if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx])
- return c_LITERAL(_cx_iter){self->table + idx,
- self->table + self->bucket_count,
- self->_hashx + idx};
- return _cx_memb(_end)(self);
+_cx_MEMB(_find)(const _cx_Self* self, _cx_keyraw rkey) {
+ _cx_result b;
+ if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted)
+ return c_LITERAL(_cx_iter){b.ref,
+ self->data + self->bucket_count,
+ self->slot + (b.ref - self->data)};
+ return _cx_MEMB(_end)(self);
}
STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_keyraw rkey) {
- int64_t idx;
- if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx])
- return self->table + idx;
+_cx_MEMB(_get)(const _cx_Self* self, _cx_keyraw rkey) {
+ _cx_result b;
+ if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted)
+ return b.ref;
return NULL;
}
STC_INLINE _cx_value*
-_cx_memb(_get_mut)(_cx_self* self, _cx_keyraw rkey)
- { return (_cx_value*)_cx_memb(_get)(self, rkey); }
+_cx_MEMB(_get_mut)(_cx_Self* self, _cx_keyraw rkey)
+ { return (_cx_value*)_cx_MEMB(_get)(self, rkey); }
STC_INLINE int
-_cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) {
- if (self->size == 0)
- return 0;
- chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey);
- return self->_hashx[b.idx] ? _cx_memb(_erase_entry)(self, self->table + b.idx), 1 : 0;
+_cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey) {
+ _cx_result b;
+ if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted)
+ { _cx_MEMB(_erase_entry)(self, b.ref); return 1; }
+ return 0;
}
STC_INLINE _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- _cx_memb(_erase_entry)(self, it.ref);
- if (*it._hx == 0)
- _cx_memb(_next)(&it);
+_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) {
+ _cx_MEMB(_erase_entry)(self, it.ref);
+ if (it.sref->hashx == 0)
+ _cx_MEMB(_next)(&it);
return it;
}
STC_INLINE bool
-_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
- if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false;
- for (_cx_iter i = _cx_memb(_begin)(self); i.ref; _cx_memb(_next)(&i)) {
+_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false;
+ for (_cx_iter i = _cx_MEMB(_begin)(self); i.ref; _cx_MEMB(_next)(&i)) {
const _cx_keyraw _raw = i_keyto(_i_keyref(i.ref));
- if (!_cx_memb(_contains)(other, _raw)) return false;
+ if (!_cx_MEMB(_contains)(other, _raw)) return false;
}
return true;
}
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+#if defined(i_implement) || defined(i_static)
+#ifndef i_max_load_factor
+ #define i_max_load_factor 0.80f
+#endif
+#define fastrange_2(x, n) (intptr_t)((x) & (size_t)((n) - 1)) // n power of 2.
-#ifndef CMAP_H_INCLUDED
-STC_INLINE int64_t fastrange_1(uint64_t x, uint64_t n)
- { return (int64_t)((uint32_t)x*n >> 32); } // n < 2^32
-
-STC_INLINE int64_t fastrange_2(uint64_t x, uint64_t n)
- { return (int64_t)(x & (n - 1)); } // n power of 2.
-
-STC_INLINE uint64_t next_power_of_2(uint64_t n) {
- n--;
- n |= n >> 1, n |= n >> 2;
- n |= n >> 4, n |= n >> 8;
- n |= n >> 16, n |= n >> 32;
- return n + 1;
+STC_DEF _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) {
+ _cx_iter it = {self->data, self->data+self->bucket_count, self->slot};
+ if (it.sref)
+ while (it.sref->hashx == 0)
+ ++it.ref, ++it.sref;
+ if (it.ref == it._end) it.ref = NULL;
+ return it;
+}
+
+STC_DEF float _cx_MEMB(_max_load_factor)(const _cx_Self* self) {
+ return (float)(i_max_load_factor);
+}
+
+STC_DEF intptr_t _cx_MEMB(_capacity)(const _cx_Self* map) {
+ return (intptr_t)((float)map->bucket_count * (i_max_load_factor));
}
-#endif // CMAP_H_INCLUDED
-STC_DEF _cx_self
-_cx_memb(_with_capacity)(const _i_size cap) {
- _cx_self h = {0};
- _cx_memb(_reserve)(&h, cap);
- return h;
+STC_DEF _cx_Self _cx_MEMB(_with_capacity)(const intptr_t cap) {
+ _cx_Self map = {0};
+ _cx_MEMB(_reserve)(&map, cap);
+ return map;
}
-STC_INLINE void _cx_memb(_wipe_)(_cx_self* self) {
+STC_INLINE void _cx_MEMB(_wipe_)(_cx_Self* self) {
if (self->size == 0)
return;
- _cx_value* e = self->table, *end = e + self->bucket_count;
- uint8_t *hx = self->_hashx;
- for (; e != end; ++e)
- if (*hx++)
- _cx_memb(_value_drop)(e);
+ _cx_value* d = self->data, *_end = d + self->bucket_count;
+ struct chash_slot* s = self->slot;
+ for (; d != _end; ++d)
+ if ((s++)->hashx)
+ _cx_MEMB(_value_drop)(d);
}
-STC_DEF void _cx_memb(_drop)(_cx_self* self) {
- _cx_memb(_wipe_)(self);
- i_free(self->_hashx);
- i_free((void *) self->table);
+STC_DEF void _cx_MEMB(_drop)(_cx_Self* self) {
+ _cx_MEMB(_wipe_)(self);
+ i_free(self->slot);
+ i_free(self->data);
}
-STC_DEF void _cx_memb(_clear)(_cx_self* self) {
- _cx_memb(_wipe_)(self);
+STC_DEF void _cx_MEMB(_clear)(_cx_Self* self) {
+ _cx_MEMB(_wipe_)(self);
self->size = 0;
- c_memset(self->_hashx, 0, self->bucket_count);
+ c_memset(self->slot, 0, c_sizeof(struct chash_slot)*self->bucket_count);
}
-#ifndef _i_isset
+#ifdef _i_ismap
STC_DEF _cx_result
- _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key)));
+ _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key _key, i_val _mapped) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key)));
_cx_mapped* _mp = _res.ref ? &_res.ref->second : &_mapped;
if (_res.inserted)
_res.ref->first = _key;
@@ -349,8 +339,8 @@ STC_DEF void _cx_memb(_clear)(_cx_self* self) {
#if !defined i_no_emplace
STC_DEF _cx_result
- _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, rkey);
+ _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey);
if (_res.inserted)
_res.ref->first = i_keyfrom(rkey);
else {
@@ -361,119 +351,117 @@ STC_DEF void _cx_memb(_clear)(_cx_self* self) {
return _res;
}
#endif // !i_no_emplace
-#endif // !_i_isset
+#endif // _i_ismap
-STC_DEF chash_bucket_t
-_cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) {
+STC_DEF _cx_result
+_cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr) {
const uint64_t _hash = i_hash(rkeyptr);
- int64_t _cap = self->bucket_count;
- chash_bucket_t b = {c_PASTE(fastrange_,_i_expandby)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)};
- const uint8_t* _hx = self->_hashx;
- while (_hx[b.idx]) {
- if (_hx[b.idx] == b.hx) {
- const _cx_keyraw _raw = i_keyto(_i_keyref(self->table + b.idx));
- if (i_eq((&_raw), rkeyptr))
+ intptr_t _cap = self->bucket_count;
+ intptr_t _idx = fastrange_2(_hash, _cap);
+ _cx_result b = {NULL, true, (uint8_t)(_hash | 0x80)};
+ const struct chash_slot* s = self->slot;
+ while (s[_idx].hashx) {
+ if (s[_idx].hashx == b.hashx) {
+ const _cx_keyraw _raw = i_keyto(_i_keyref(self->data + _idx));
+ if (i_eq((&_raw), rkeyptr)) {
+ b.inserted = false;
break;
+ }
}
- if (++b.idx == _cap)
- b.idx = 0;
+ if (++_idx == _cap) _idx = 0;
}
+ b.ref = self->data + _idx;
return b;
}
STC_DEF _cx_result
-_cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) {
- _cx_result res = {NULL};
- if (self->size + 2 > (i_ssize)((float)self->bucket_count * (i_max_load_factor)))
- if (!_cx_memb(_reserve)(self, self->size*3/2))
- return res;
-
- chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey);
- res.ref = &self->table[b.idx];
- if ((res.inserted = !self->_hashx[b.idx])) {
- self->_hashx[b.idx] = b.hx;
+_cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) {
+ if (self->size >= (intptr_t)((float)self->bucket_count * (i_max_load_factor)))
+ if (!_cx_MEMB(_reserve)(self, (intptr_t)(self->size*3/2 + 2)))
+ return c_LITERAL(_cx_result){NULL};
+
+ _cx_result b = _cx_MEMB(_bucket_)(self, &rkey);
+ if (b.inserted) {
+ self->slot[b.ref - self->data].hashx = b.hashx;
++self->size;
}
- return res;
+ return b;
}
#if !defined i_no_clone
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self m) {
- if (m.table) {
- _cx_value *t = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket_count),
- *dst = t, *m_end = m.table + m.bucket_count;
- uint8_t *h = (uint8_t *)c_memcpy(i_malloc(m.bucket_count + 1), m._hashx, m.bucket_count + 1);
- if (!(t && h))
- { i_free(t), i_free(h), t = 0, h = 0, m.bucket_count = 0; }
+STC_DEF _cx_Self
+_cx_MEMB(_clone)(_cx_Self m) {
+ if (m.data) {
+ _cx_value *d = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket_count),
+ *_dst = d, *_end = m.data + m.bucket_count;
+ const intptr_t _mem = c_sizeof(struct chash_slot)*(m.bucket_count + 1);
+ struct chash_slot *s = (struct chash_slot *)c_memcpy(i_malloc(_mem), m.slot, _mem);
+ if (!(d && s))
+ { i_free(d), i_free(s), d = 0, s = 0, m.bucket_count = 0; }
else
- for (; m.table != m_end; ++m.table, ++m._hashx, ++dst)
- if (*m._hashx)
- *dst = _cx_memb(_value_clone)(*m.table);
- m.table = t, m._hashx = h;
+ for (; m.data != _end; ++m.data, ++m.slot, ++_dst)
+ if (m.slot->hashx)
+ *_dst = _cx_MEMB(_value_clone)(*m.data);
+ m.data = d, m.slot = s;
}
return m;
}
#endif
STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const _i_size newcap) {
- const i_ssize _oldbuckets = self->bucket_count, _newcap = (i_ssize)newcap;
- if (_newcap != self->size && _newcap <= _oldbuckets)
+_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t _newcap) {
+ const intptr_t _oldbucks = self->bucket_count;
+ if (_newcap != self->size && _newcap <= _oldbucks)
return true;
- i_ssize _nbuckets = (i_ssize)((float)_newcap / (i_max_load_factor)) + 4;
- #if _i_expandby == 2
- _nbuckets = (i_ssize)next_power_of_2(_nbuckets);
- #else
- _nbuckets |= 1;
- #endif
- _cx_self m = {
- (_cx_value *)i_malloc(c_sizeof(_cx_value)*_nbuckets),
- (uint8_t *)i_calloc(_nbuckets + 1, 1),
- self->size, _nbuckets,
+ intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) + 4;
+ _newbucks = stc_nextpow2(_newbucks);
+ _cx_Self m = {
+ (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)),
+ (struct chash_slot *)i_calloc(_newbucks + 1, c_sizeof(struct chash_slot)),
+ self->size, _newbucks
};
- bool ok = m.table && m._hashx;
- if (ok) { /* Rehash: */
- m._hashx[_nbuckets] = 0xff;
- const _cx_value* e = self->table;
- const uint8_t* h = self->_hashx;
- for (i_ssize i = 0; i < _oldbuckets; ++i, ++e) if (*h++) {
- _cx_keyraw r = i_keyto(_i_keyref(e));
- chash_bucket_t b = _cx_memb(_bucket_)(&m, &r);
- m.table[b.idx] = *e;
- m._hashx[b.idx] = b.hx;
+ bool ok = m.data && m.slot;
+ if (ok) { // Rehash:
+ m.slot[_newbucks].hashx = 0xff;
+ const _cx_value* d = self->data;
+ const struct chash_slot* s = self->slot;
+ for (intptr_t i = 0; i < _oldbucks; ++i, ++d) if ((s++)->hashx) {
+ _cx_keyraw r = i_keyto(_i_keyref(d));
+ _cx_result b = _cx_MEMB(_bucket_)(&m, &r);
+ m.slot[b.ref - m.data].hashx = b.hashx;
+ *b.ref = *d; // move
}
- c_swap(_cx_self, self, &m);
+ c_swap(_cx_Self, self, &m);
}
- i_free(m._hashx);
- i_free(m.table);
+ i_free(m.slot);
+ i_free(m.data);
return ok;
}
STC_DEF void
-_cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) {
- i_ssize i = (i_ssize)(_val - self->table), j = i, k;
- const i_ssize _cap = self->bucket_count;
- _cx_value* _slot = self->table;
- uint8_t* _hashx = self->_hashx;
- _cx_memb(_value_drop)(_val);
- for (;;) { /* delete without leaving tombstone */
- if (++j == _cap)
- j = 0;
- if (! _hashx[j])
+_cx_MEMB(_erase_entry)(_cx_Self* self, _cx_value* _val) {
+ _cx_value* d = self->data;
+ struct chash_slot* s = self->slot;
+ intptr_t i = _val - d, j = i, k;
+ const intptr_t _cap = self->bucket_count;
+ _cx_MEMB(_value_drop)(_val);
+ for (;;) { // delete without leaving tombstone
+ if (++j == _cap) j = 0;
+ if (! s[j].hashx)
break;
- const _cx_keyraw _raw = i_keyto(_i_keyref(_slot + j));
- k = (i_ssize)c_PASTE(fastrange_,_i_expandby)(i_hash((&_raw)), (uint64_t)_cap);
- if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */
- _slot[i] = _slot[j], _hashx[i] = _hashx[j], i = j;
+ const _cx_keyraw _raw = i_keyto(_i_keyref(d + j));
+ k = fastrange_2(i_hash((&_raw)), _cap);
+ if ((j < i) ^ (k <= i) ^ (k > j)) { // is k outside (i, j]?
+ d[i] = d[j];
+ s[i] = s[j];
+ i = j;
+ }
}
- _hashx[i] = 0;
+ s[i].hashx = 0;
--self->size;
}
-
#endif // i_implement
#undef i_max_load_factor
-#undef _i_size
#undef _i_isset
#undef _i_ismap
#undef _i_ishash
diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h
new file mode 100644
index 00000000..5f06e7b8
--- /dev/null
+++ b/include/stc/coroutine.h
@@ -0,0 +1,288 @@
+/* MIT License
+ *
+ * Copyright (c) 2023 Tyge Løvset
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef STC_COROUTINE_INCLUDED
+#define STC_COROUTINE_INCLUDED
+/*
+#include <stdio.h>
+#include <stc/coroutine.h>
+
+struct iterpair {
+ int max_x, max_y;
+ int x, y;
+ int cco_state; // required member
+};
+
+int iterpair(struct iterpair* I) {
+ cco_routine(I) {
+ for (I->x = 0; I->x < I->max_x; I->x++)
+ for (I->y = 0; I->y < I->max_y; I->y++)
+ cco_yield();
+
+ cco_final: // required if there is cleanup code
+ puts("final");
+ }
+ return 0; // CCO_DONE
+}
+
+int main(void) {
+ struct iterpair it = {.max_x=3, .max_y=3};
+ int n = 0;
+ while (iterpair(&it))
+ {
+ printf("%d %d\n", it.x, it.y);
+ // example of early stop:
+ if (++n == 7) cco_stop(&it); // signal to stop/finalize in next
+ }
+ return 0;
+}
+*/
+#include "ccommon.h"
+
+enum {
+ CCO_STATE_CLEANUP = -1,
+ CCO_STATE_DONE = -2,
+};
+typedef enum {
+ CCO_DONE = 0,
+ CCO_AWAIT = 1<<0,
+ CCO_YIELD = 1<<1,
+} cco_result;
+
+#define cco_initial(co) ((co)->cco_state == 0)
+#define cco_suspended(co) ((co)->cco_state > 0)
+#define cco_done(co) ((co)->cco_state == CCO_STATE_DONE)
+
+#define cco_routine(co) \
+ for (int* _state = &(co)->cco_state; *_state != CCO_STATE_DONE; *_state = CCO_STATE_DONE) \
+ _resume: switch (*_state) case 0: // thanks, @liigo!
+
+#define cco_yield() cco_yield_v(CCO_YIELD)
+#define cco_yield_v(ret) \
+ do { \
+ *_state = __LINE__; return ret; goto _resume; \
+ case __LINE__:; \
+ } while (0)
+
+#define cco_await(promise) cco_await_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_call(): assumes coroutine returns a cco_result value (int) */
+#define cco_await_call(...) c_MACRO_OVERLOAD(cco_await_call, __VA_ARGS__)
+#define cco_await_call_1(corocall) cco_await_call_2(corocall, CCO_DONE)
+#define cco_await_call_2(corocall, awaitbits) \
+ do { \
+ *_state = __LINE__; \
+ case __LINE__: { int _r = corocall; if (_r & ~(awaitbits)) {return _r; goto _resume;} } \
+ } while (0)
+
+/* cco_blocking_call(): assumes coroutine returns a cco_result value (int) */
+#define cco_blocking_call(corocall) while ((corocall) != CCO_DONE)
+
+#define cco_cleanup cco_final // [deprecated]
+#define cco_final \
+ *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP
+
+#define cco_return \
+ do { \
+ *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \
+ goto _resume; \
+ } while (0)
+
+#define cco_yield_final() cco_yield_final_v(CCO_YIELD)
+#define cco_yield_final_v(value) \
+ do { \
+ *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \
+ return value; \
+ } while (0)
+
+#define cco_stop(co) \
+ do { \
+ int* _s = &(co)->cco_state; \
+ if (*_s > 0) *_s = CCO_STATE_CLEANUP; \
+ else if (*_s == 0) *_s = CCO_STATE_DONE; \
+ } while (0)
+
+#define cco_reset(co) \
+ (void)((co)->cco_state = 0)
+
+/*
+ * Iterator (for generators)
+ * User define: Gen must be an existing typedef struct:
+ * Gen_iter Gen_begin(Gen* g); // function
+ * int Gen_next(Gen_iter* it); // coroutine
+ */
+
+#define cco_iter_struct(Gen, ...) \
+ typedef Gen Gen##_value; \
+ typedef struct Gen##_iter { \
+ Gen##_value* ref; \
+ int cco_state; \
+ __VA_ARGS__ \
+ } Gen##_iter
+
+/*
+ * Tasks
+ */
+
+struct cco_runtime;
+
+#define cco_task_struct(Task, ...) \
+ struct Task { \
+ int (*cco_func)(struct Task*, struct cco_runtime*); \
+ int cco_state, cco_expect; \
+ __VA_ARGS__ \
+ }
+
+typedef cco_task_struct(cco_task, /**/) cco_task;
+
+typedef struct cco_runtime {
+ int result, top; cco_task* stack[];
+} cco_runtime;
+
+#define cco_cast_task(task) \
+ ((cco_task *)(task) + 0*sizeof((task)->cco_func(task, (cco_runtime*)0) + ((int*)0 == &(task)->cco_state)))
+
+#define cco_resume_task(task, rt) \
+ (task)->cco_func(task, rt)
+
+#define cco_await_task(...) c_MACRO_OVERLOAD(cco_await_task, __VA_ARGS__)
+#define cco_await_task_2(task, rt) cco_await_task_3(task, rt, CCO_DONE)
+#define cco_await_task_3(task, rt, awaitbits) \
+ do { \
+ cco_runtime* _rt = rt; \
+ (_rt->stack[++_rt->top] = cco_cast_task(task))->cco_expect = (awaitbits); \
+ cco_yield_v(CCO_AWAIT); \
+ } while (0)
+
+#define cco_blocking_task(...) c_MACRO_OVERLOAD(cco_blocking_task, __VA_ARGS__)
+#define cco_blocking_task_1(task) cco_blocking_task_3(task, _rt, 16)
+#define cco_blocking_task_3(task, rt, STACKDEPTH) \
+ for (struct { int result, top; cco_task* stack[STACKDEPTH]; } rt = {.stack={cco_cast_task(task)}}; \
+ (((rt.result = cco_resume_task(rt.stack[rt.top], (cco_runtime*)&rt)) & \
+ ~rt.stack[rt.top]->cco_expect) || --rt.top >= 0); )
+
+/*
+ * Semaphore
+ */
+
+typedef struct { intptr_t count; } cco_sem;
+
+#define cco_await_sem(sem) cco_await_sem_and_return(sem, CCO_AWAIT)
+#define cco_await_sem_v(sem) cco_await_sem_and_return(sem, )
+#define cco_await_sem_and_return(sem, ret) \
+ do { \
+ cco_await_and_return((sem)->count > 0, ret); \
+ --(sem)->count; \
+ } while (0)
+
+#define cco_sem_release(sem) ++(sem)->count
+#define cco_sem_from(value) ((cco_sem){value})
+#define cco_sem_set(sem, value) ((sem)->count = value)
+
+/*
+ * Timer
+ */
+
+#ifdef _WIN32
+ #ifdef __cplusplus
+ #define _c_LINKC extern "C" __declspec(dllimport)
+ #else
+ #define _c_LINKC __declspec(dllimport)
+ #endif
+ #if 1 // _WIN32_WINNT < _WIN32_WINNT_WIN8 || defined __TINYC__
+ #define _c_getsystime GetSystemTimeAsFileTime
+ #else
+ #define _c_getsystime GetSystemTimePreciseAsFileTime
+ #endif
+ struct _FILETIME;
+ _c_LINKC void _c_getsystime(struct _FILETIME*);
+ _c_LINKC void Sleep(unsigned long);
+
+ static inline double cco_time(void) { /* seconds since epoch */
+ unsigned long long quad; /* 64-bit value representing 1/10th usecs since Jan 1 1601, 00:00 UTC */
+ _c_getsystime((struct _FILETIME*)&quad);
+ return (double)(quad - 116444736000000000ULL)*1e-7; /* time diff Jan 1 1601-Jan 1 1970 in 1/10th usecs */
+ }
+
+ static inline void cco_sleep(double sec) {
+ Sleep((unsigned long)(sec*1000.0));
+ }
+#else
+ #include <sys/time.h>
+ static inline double cco_time(void) { /* seconds since epoch */
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (double)tv.tv_sec + (double)tv.tv_usec*1e-6;
+ }
+
+ static inline void cco_sleep(double sec) {
+ struct timeval tv;
+ tv.tv_sec = (time_t)sec;
+ tv.tv_usec = (suseconds_t)((sec - (double)(long)sec)*1e6);
+ select(0, NULL, NULL, NULL, &tv);
+ }
+#endif
+
+typedef struct { double interval, start; } cco_timer;
+
+#define cco_await_timer(tm, sec) cco_await_timer_v_3(tm, sec, CCO_AWAIT)
+#define cco_await_timer_v(...) c_MACRO_OVERLOAD(cco_await_timer_v, __VA_ARGS__)
+#define cco_await_timer_v_2(tm, sec) cco_await_timer_v_3(tm, sec, )
+#define cco_await_timer_v_3(tm, sec, ret) \
+ do { \
+ cco_timer_start(tm, sec); \
+ cco_await_and_return(cco_timer_expired(tm), ret); \
+ } while (0)
+
+static inline void cco_timer_start(cco_timer* tm, double sec) {
+ tm->interval = sec;
+ tm->start = cco_time();
+}
+
+static inline cco_timer cco_timer_from(double sec) {
+ cco_timer tm = {.interval=sec, .start=cco_time()};
+ return tm;
+}
+
+static inline void cco_timer_restart(cco_timer* tm) {
+ tm->start = cco_time();
+}
+
+static inline bool cco_timer_expired(cco_timer* tm) {
+ return cco_time() - tm->start >= tm->interval;
+}
+
+static inline double cco_timer_elapsed(cco_timer* tm) {
+ return cco_time() - tm->start;
+}
+
+static inline double cco_timer_remaining(cco_timer* tm) {
+ return tm->start + tm->interval - cco_time();
+}
+
+#endif
diff --git a/include/stc/cpque.h b/include/stc/cpque.h
index b95b5020..520514ef 100644
--- a/include/stc/cpque.h
+++ b/include/stc/cpque.h
@@ -20,101 +20,100 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CPQUE_H_INCLUDED
+#include "ccommon.h"
#include <stdlib.h>
#include "forward.h"
#endif
-#ifndef _i_prefix
#define _i_prefix cpque_
-#endif
-
+#define _i_ispque
#include "priv/template.h"
#ifndef i_is_forward
- _cx_deftypes(_c_cpque_types, _cx_self, i_key);
+ _cx_DEFTYPES(_c_cpque_types, _cx_Self, i_key);
#endif
typedef i_keyraw _cx_raw;
-STC_API void _cx_memb(_make_heap)(_cx_self* self);
-STC_API void _cx_memb(_erase_at)(_cx_self* self, intptr_t idx);
-STC_API void _cx_memb(_push)(_cx_self* self, _cx_value value);
+STC_API void _cx_MEMB(_make_heap)(_cx_Self* self);
+STC_API void _cx_MEMB(_erase_at)(_cx_Self* self, intptr_t idx);
+STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, _cx_value value);
-STC_INLINE _cx_self _cx_memb(_init)(void)
- { return c_LITERAL(_cx_self){NULL}; }
+STC_INLINE _cx_Self _cx_MEMB(_init)(void)
+ { return c_LITERAL(_cx_Self){NULL}; }
-STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n)
- { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); }
+STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n)
+ { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); }
-STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n)
- { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; }
+STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n)
+ { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; }
-STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, const intptr_t cap) {
+STC_INLINE bool _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t cap) {
if (cap != self->_len && cap <= self->_cap) return true;
_cx_value *d = (_cx_value *)i_realloc(self->data, cap*c_sizeof *d);
return d ? (self->data = d, self->_cap = cap, true) : false;
}
-STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self)
- { _cx_memb(_reserve)(self, self->_len); }
+STC_INLINE void _cx_MEMB(_shrink_to_fit)(_cx_Self* self)
+ { _cx_MEMB(_reserve)(self, self->_len); }
-STC_INLINE _cx_self _cx_memb(_with_capacity)(const intptr_t cap) {
- _cx_self out = {NULL}; _cx_memb(_reserve)(&out, cap);
+STC_INLINE _cx_Self _cx_MEMB(_with_capacity)(const intptr_t cap) {
+ _cx_Self out = {NULL}; _cx_MEMB(_reserve)(&out, cap);
return out;
}
-STC_INLINE _cx_self _cx_memb(_with_size)(const intptr_t size, i_key null) {
- _cx_self out = {NULL}; _cx_memb(_reserve)(&out, size);
+STC_INLINE _cx_Self _cx_MEMB(_with_size)(const intptr_t size, i_key null) {
+ _cx_Self out = {NULL}; _cx_MEMB(_reserve)(&out, size);
while (out._len < size) out.data[out._len++] = null;
return out;
}
-STC_INLINE void _cx_memb(_clear)(_cx_self* self) {
+STC_INLINE void _cx_MEMB(_clear)(_cx_Self* self) {
intptr_t i = self->_len; self->_len = 0;
while (i--) { i_keydrop((self->data + i)); }
}
-STC_INLINE void _cx_memb(_drop)(_cx_self* self)
- { _cx_memb(_clear)(self); i_free(self->data); }
+STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self)
+ { _cx_MEMB(_clear)(self); i_free(self->data); }
-STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* q)
+STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* q)
{ return q->_len; }
-STC_INLINE bool _cx_memb(_empty)(const _cx_self* q)
+STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* q)
{ return !q->_len; }
-STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* q)
+STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* q)
{ return q->_cap; }
-STC_INLINE const _cx_value* _cx_memb(_top)(const _cx_self* self)
+STC_INLINE const _cx_value* _cx_MEMB(_top)(const _cx_Self* self)
{ return &self->data[0]; }
-STC_INLINE void _cx_memb(_pop)(_cx_self* self)
- { assert(!_cx_memb(_empty)(self)); _cx_memb(_erase_at)(self, 0); }
+STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self)
+ { c_assert(!_cx_MEMB(_empty)(self)); _cx_MEMB(_erase_at)(self, 0); }
#if !defined i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self q);
+STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self q);
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) {
+STC_INLINE void _cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) {
if (self->data == other->data) return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(*other);
+ _cx_MEMB(_drop)(self);
+ *self = _cx_MEMB(_clone)(*other);
}
-STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val)
+STC_INLINE i_key _cx_MEMB(_value_clone)(_cx_value val)
{ return i_keyclone(val); }
#endif // !i_no_clone
#if !defined i_no_emplace
-STC_INLINE void _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { _cx_memb(_push)(self, i_keyfrom(raw)); }
+STC_INLINE void _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw)
+ { _cx_MEMB(_push)(self, i_keyfrom(raw)); }
#endif // !i_no_emplace
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+#if defined(i_implement) || defined(i_static)
STC_DEF void
-_cx_memb(_sift_down_)(_cx_self* self, const intptr_t idx, const intptr_t n) {
+_cx_MEMB(_sift_down_)(_cx_Self* self, const intptr_t idx, const intptr_t n) {
_cx_value t, *arr = self->data - 1;
for (intptr_t r = idx, c = idx*2; c <= n; c *= 2) {
c += i_less((&arr[c]), (&arr[c + (c < n)]));
@@ -124,15 +123,15 @@ _cx_memb(_sift_down_)(_cx_self* self, const intptr_t idx, const intptr_t n) {
}
STC_DEF void
-_cx_memb(_make_heap)(_cx_self* self) {
+_cx_MEMB(_make_heap)(_cx_Self* self) {
intptr_t n = self->_len;
for (intptr_t k = n/2; k != 0; --k)
- _cx_memb(_sift_down_)(self, k, n);
+ _cx_MEMB(_sift_down_)(self, k, n);
}
#if !defined i_no_clone
-STC_DEF _cx_self _cx_memb(_clone)(_cx_self q) {
- _cx_self out = _cx_memb(_with_capacity)(q._len);
+STC_DEF _cx_Self _cx_MEMB(_clone)(_cx_Self q) {
+ _cx_Self out = _cx_MEMB(_with_capacity)(q._len);
for (; out._len < out._cap; ++q.data)
out.data[out._len++] = i_keyclone((*q.data));
return out;
@@ -140,24 +139,26 @@ STC_DEF _cx_self _cx_memb(_clone)(_cx_self q) {
#endif
STC_DEF void
-_cx_memb(_erase_at)(_cx_self* self, const intptr_t idx) {
+_cx_MEMB(_erase_at)(_cx_Self* self, const intptr_t idx) {
i_keydrop((self->data + idx));
const intptr_t n = --self->_len;
self->data[idx] = self->data[n];
- _cx_memb(_sift_down_)(self, idx + 1, n);
+ _cx_MEMB(_sift_down_)(self, idx + 1, n);
}
-STC_DEF void
-_cx_memb(_push)(_cx_self* self, _cx_value value) {
+STC_DEF _cx_value*
+_cx_MEMB(_push)(_cx_Self* self, _cx_value value) {
if (self->_len == self->_cap)
- _cx_memb(_reserve)(self, self->_len*3/2 + 4);
+ _cx_MEMB(_reserve)(self, self->_len*3/2 + 4);
_cx_value *arr = self->data - 1; /* base 1 */
intptr_t c = ++self->_len;
for (; c > 1 && (i_less((&arr[c/2]), (&value))); c /= 2)
arr[c] = arr[c/2];
arr[c] = value;
+ return arr + c;
}
#endif
#define CPQUE_H_INCLUDED
#include "priv/template2.h"
+#undef _i_ispque \ No newline at end of file
diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h
index 1934305a..8a609b96 100644
--- a/include/stc/cqueue.h
+++ b/include/stc/cqueue.h
@@ -20,46 +20,23 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-// STC queue
-/*
-#include <stc/crand.h>
-#include <stdio.h>
+#include "priv/linkage.h"
-#define i_key int
-#include <stc/cqueue.h>
-
-int main() {
- int n = 10000000;
- crand_t rng = crand_init(1234);
- crand_unif_t dist = crand_unif_init(0, n);
-
- c_auto (cqueue_int, Q)
- {
- // Push ten million random numbers onto the queue.
- for (int i=0; i<n; ++i)
- cqueue_int_push(&Q, crand_unif(&rng, &dist));
-
- // Push or pop on the queue ten million times
- printf("before: size, capacity: %d, %d\n", n, cqueue_int_size(&Q), cqueue_int_capacity(&Q));
- for (int i=n; i>0; --i) {
- int r = crand_unif(&rng, &dist);
- if (r & 1)
- ++n, cqueue_int_push(&Q, r);
- else
- --n, cqueue_int_pop(&Q);
- }
- printf("after: size, capacity: %d, %d\n", n, cqueue_int_size(&Q), cqueue_int_capacity(&Q));
- }
-}
-*/
+#ifndef CQUEUE_H_INCLUDED
+#include "ccommon.h"
+#include "forward.h"
+#include <stdlib.h>
+#include <string.h>
+#endif // CQUEUE_H_INCLUDED
#ifndef _i_prefix
#define _i_prefix cqueue_
#endif
-#define _i_queue
-#define _pop_front _pop
-
-#include "cdeq.h"
+#include "priv/cqueue_hdr.h"
-#undef _pop_front
-#undef _i_queue
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if defined(i_implement) || defined(i_static)
+#include "priv/cqueue_imp.h"
+#endif // IMPLEMENTATION
+#define CQUEUE_H_INCLUDED
+#include "priv/template2.h"
diff --git a/include/stc/crand.h b/include/stc/crand.h
index a1b7250d..32722762 100644
--- a/include/stc/crand.h
+++ b/include/stc/crand.h
@@ -20,31 +20,32 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CRAND_H_INCLUDED
#define CRAND_H_INCLUDED
+#include "ccommon.h"
/*
// crand: Pseudo-random number generator
#include "stc/crand.h"
-int main() {
+int main(void) {
uint64_t seed = 123456789;
crand_t rng = crand_init(seed);
- crand_unif_t dist1 = crand_unif_init(1, 6);
- 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.
@@ -66,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) {
@@ -92,13 +93,12 @@ STC_INLINE double crand_f64(crand_t* rng) {
}
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+#if defined(i_implement) || defined(i_static)
-/* Global random() */
-static crand_t crand_global = {{
- 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)
@@ -115,32 +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;
}
-#if defined(__SIZEOF_INT128__)
- #define c_umul128(a, b, lo, hi) \
- do { __uint128_t _z = (__uint128_t)(a)*(b); \
- *(lo) = (uint64_t)_z, *(hi) = (uint64_t)(_z >> 64U); } while(0)
-#elif defined(_MSC_VER) && defined(_WIN64)
- #include <intrin.h>
- #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi)))
-#elif defined(__x86_64__)
- #define c_umul128(a, b, lo, hi) \
- asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b))
-#endif
-
/* Int64 uniform distributed RNG, range [low, high]. */
-STC_DEF int64_t crand_unif(crand_t* rng, crand_unif_t* d) {
+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);
@@ -151,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;
@@ -164,11 +152,10 @@ STC_DEF double crand_norm(crand_t* rng, crand_norm_t* dist) {
dist->next = u2*m;
return (u1*m)*dist->stddev + dist->mean;
}
-
#endif
#endif
#undef i_opt
#undef i_static
#undef i_header
#undef i_implement
-#undef i_extern
+#undef i_import
diff --git a/include/stc/crandom.h b/include/stc/crandom.h
deleted file mode 100644
index a9374602..00000000
--- a/include/stc/crandom.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/* MIT License
- *
- * Copyright (c) 2023 Tyge Løvset
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include "ccommon.h"
-
-#ifndef CRANDOM_H_INCLUDED
-#define CRANDOM_H_INCLUDED
-/*
-// crandom: Pseudo-random number generator
-#include "stc/crandom.h"
-int main() {
- uint64_t seed = 123456789;
- stc64_t rng = stc64_new(seed);
- stc64_uniform_t dist1 = stc64_uniform_new(1, 6);
- stc64_uniformf_t dist2 = stc64_uniformf_new(1.0, 10.0);
- stc64_normalf_t dist3 = stc64_normalf_new(1.0, 10.0);
-
- uint64_t i = stc64_rand(&rng);
- int64_t iu = stc64_uniform(&rng, &dist1);
- double xu = stc64_uniformf(&rng, &dist2);
- double xn = stc64_normalf(&rng, &dist3);
-}
-*/
-#include <string.h>
-#include <math.h>
-
-typedef struct stc64 { uint64_t state[5]; } stc64_t;
-typedef struct stc64_uniform { int64_t lower; uint64_t range, threshold; } stc64_uniform_t;
-typedef struct stc64_uniformf { double lower, range; } stc64_uniformf_t;
-typedef struct stc64_normalf { double mean, stddev, next; int has_next; } stc64_normalf_t;
-
-/* PRNG stc64.
- * Very fast PRNG suited for parallel usage with Weyl-sequence parameter.
- * 320-bit state, 256 bit is mutable.
- * Noticable faster than xoshiro and pcg, slighly slower than wyrand64 and
- * Romu, but these have restricted capacity for larger parallel jobs or unknown minimum periods.
- * stc64 supports 2^63 unique threads with a minimum 2^64 period lengths each.
- * Passes all statistical tests, e.g PractRand and correlation tests, i.e. interleaved
- * streams with one-bit diff state. Even the 16-bit version (LR=6, RS=5, LS=3) passes
- * PractRand to multiple TB input.
- */
-
-/* Global stc64 PRNGs */
-STC_API void csrandom(uint64_t seed);
-STC_API uint64_t crandom(void);
-STC_API double crandomf(void);
-
-/* Init stc64 prng with and without sequence number */
-STC_API stc64_t stc64_with_seq(uint64_t seed, uint64_t seq);
-STC_INLINE stc64_t stc64_new(uint64_t seed)
- { return stc64_with_seq(seed, seed + 0x3504f333d3aa0b37); }
-
-/* Unbiased bounded uniform distribution. range [low, high] */
-STC_API stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high);
-STC_API int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* dist);
-
-/* Normal distribution PRNG */
-STC_API double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist);
-
-
-/* Main stc64 prng */
-STC_INLINE uint64_t stc64_rand(stc64_t* rng) {
- uint64_t *s = rng->state; enum {LR=24, RS=11, LS=3};
- const uint64_t result = (s[0] ^ (s[3] += s[4])) + s[1];
- s[0] = s[1] ^ (s[1] >> RS);
- s[1] = s[2] + (s[2] << LS);
- s[2] = ((s[2] << LR) | (s[2] >> (64 - LR))) + result;
- return result;
-}
-
-/* Float64 random number in range [0.0, 1.0). */
-STC_INLINE double stc64_randf(stc64_t* rng) {
- union {uint64_t i; double f;} u = {0x3FF0000000000000ull | (stc64_rand(rng) >> 12)};
- return u.f - 1.0;
-}
-
-/* Float64 uniform distributed RNG, range [low, high). */
-STC_INLINE double stc64_uniformf(stc64_t* rng, stc64_uniformf_t* dist) {
- return stc64_randf(rng)*dist->range + dist->lower;
-}
-
-/* Init uniform distributed float64 RNG, range [low, high). */
-STC_INLINE stc64_uniformf_t stc64_uniformf_new(double low, double high) {
- return c_LITERAL(stc64_uniformf_t){low, high - low};
-}
-
-/* Marsaglia polar method for gaussian/normal distribution, float64. */
-STC_INLINE stc64_normalf_t stc64_normalf_new(double mean, double stddev) {
- return c_LITERAL(stc64_normalf_t){mean, stddev, 0.0, 0};
-}
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-/* Global random() */
-static stc64_t stc64_global = {{
- 0x26aa069ea2fb1a4d, 0x70c72c95cd592d04,
- 0x504f333d3aa0b359, 0x9e3779b97f4a7c15,
- 0x6a09e667a754166b
-}};
-
-STC_DEF void csrandom(uint64_t seed) {
- stc64_global = stc64_new(seed);
-}
-
-STC_DEF uint64_t crandom(void) {
- return stc64_rand(&stc64_global);
-}
-
-STC_DEF double crandomf(void) {
- return stc64_randf(&stc64_global);
-}
-
-/* rng.state[4] must be odd */
-STC_DEF stc64_t stc64_with_seq(uint64_t seed, uint64_t seq) {
- stc64_t rng = {{seed+0x26aa069ea2fb1a4d, seed+0x70c72c95cd592d04,
- seed+0x504f333d3aa0b359, seed, seq<<1 | 1}};
- for (int i = 0; i < 6; ++i) stc64_rand(&rng);
- return rng;
-}
-
-/* Init unbiased uniform uint RNG with bounds [low, high] */
-STC_DEF stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high) {
- stc64_uniform_t dist = {low, (uint64_t) (high - low + 1)};
- dist.threshold = (uint64_t)(0 - dist.range) % dist.range;
- return dist;
-}
-
-#if defined(__SIZEOF_INT128__)
- #define c_umul128(a, b, lo, hi) \
- do { __uint128_t _z = (__uint128_t)(a)*(b); \
- *(lo) = (uint64_t)_z, *(hi) = (uint64_t)(_z >> 64U); } while(0)
-#elif defined(_MSC_VER) && defined(_WIN64)
- #include <intrin.h>
- #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi)))
-#elif defined(__x86_64__)
- #define c_umul128(a, b, lo, hi) \
- asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b))
-#endif
-
-/* Int uniform distributed RNG, range [low, high]. */
-STC_DEF int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* d) {
-#ifdef c_umul128
- uint64_t lo, hi;
- do { c_umul128(stc64_rand(rng), d->range, &lo, &hi); } while (lo < d->threshold);
- return d->lower + (int64_t)hi;
-#else
- uint64_t x, r;
- do {
- x = stc64_rand(rng);
- r = x % d->range;
- } while (x - r > -d->range);
- return d->lower + r;
-#endif
-}
-
-/* Normal distribution PRNG */
-STC_DEF double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist) {
- double u1, u2, s, m;
- if (dist->has_next++ & 1)
- return dist->next * dist->stddev + dist->mean;
- do {
- u1 = 2.0 * stc64_randf(rng) - 1.0;
- u2 = 2.0 * stc64_randf(rng) - 1.0;
- s = u1*u1 + u2*u2;
- } while (s >= 1.0 || s == 0.0);
- m = sqrt(-2.0 * log(s) / s);
- dist->next = u2 * m;
- return (u1 * m) * dist->stddev + dist->mean;
-}
-
-#endif
-#endif
-#undef i_opt
-#undef i_static
-#undef i_header
-#undef i_implement
-#undef i_extern
diff --git a/include/stc/crawstr.h b/include/stc/crawstr.h
new file mode 100644
index 00000000..9dbdb6f7
--- /dev/null
+++ b/include/stc/crawstr.h
@@ -0,0 +1,108 @@
+/* MIT License
+ *
+ * Copyright (c) 2023 Tyge Løvset
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#define _i_inc_utf8
+#include "utf8.h"
+
+#ifndef CRAWSTR_H_INCLUDED
+#define CRAWSTR_H_INCLUDED
+
+#define crawstr_init() c_rs("")
+#define crawstr_clone(rs) c_default_clone(rs)
+#define crawstr_drop(self) c_default_drop(self)
+#define crawstr_toraw(self) (self)->str
+
+STC_INLINE crawstr crawstr_from(const char* str)
+ { return c_rs_2(str, c_strlen(str)); }
+STC_INLINE void crawstr_clear(crawstr* self) { *self = c_rs(""); }
+STC_INLINE csview crawstr_sv(crawstr rs) { return c_sv_2(rs.str, rs.size); }
+
+STC_INLINE intptr_t crawstr_size(crawstr rs) { return rs.size; }
+STC_INLINE bool crawstr_empty(crawstr rs) { return rs.size == 0; }
+
+STC_INLINE bool crawstr_equals(crawstr rs, const char* str) {
+ intptr_t n = c_strlen(str);
+ return rs.size == n && !c_memcmp(rs.str, str, n);
+}
+
+STC_INLINE intptr_t crawstr_find(crawstr rs, const char* search) {
+ char* res = strstr(rs.str, search);
+ return res ? (res - rs.str) : c_NPOS;
+}
+
+STC_INLINE bool crawstr_contains(crawstr rs, const char* str)
+ { return crawstr_find(rs, str) != c_NPOS; }
+
+STC_INLINE bool crawstr_starts_with(crawstr rs, const char* str) {
+ intptr_t n = c_strlen(str);
+ return n > rs.size ? false : !c_memcmp(rs.str, str, n);
+}
+
+STC_INLINE bool crawstr_ends_with(crawstr rs, const char* str) {
+ intptr_t n = c_strlen(str);
+ return n > rs.size ? false : !c_memcmp(rs.str + rs.size - n, str, n);
+}
+
+/* utf8 iterator */
+STC_INLINE crawstr_iter crawstr_begin(const crawstr* self) {
+ if (!self->size) return c_LITERAL(crawstr_iter){.ref = NULL};
+ return c_LITERAL(crawstr_iter){.u8 = {{self->str, utf8_chr_size(self->str)}}};
+}
+STC_INLINE crawstr_iter crawstr_end(const crawstr* self) {
+ (void)self; return c_LITERAL(crawstr_iter){.ref = NULL};
+}
+STC_INLINE void crawstr_next(crawstr_iter* it) {
+ it->ref += it->chr.size;
+ it->chr.size = utf8_chr_size(it->ref);
+ if (!*it->ref) it->ref = NULL;
+}
+STC_INLINE crawstr_iter crawstr_advance(crawstr_iter it, intptr_t pos) {
+ int inc = -1;
+ if (pos > 0) pos = -pos, inc = 1;
+ while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80;
+ it.chr.size = utf8_chr_size(it.ref);
+ if (!*it.ref) it.ref = NULL;
+ return it;
+}
+
+/* utf8 ignore case cmp: depends on src/utf8code.c */
+STC_INLINE int crawstr_icmp(const crawstr* x, const crawstr* y)
+ { return utf8_icmp_sv(c_sv_2(x->str, x->size), c_sv_2(y->str, y->size)); }
+
+STC_INLINE int crawstr_cmp(const crawstr* x, const crawstr* y) {
+ intptr_t n = x->size < y->size ? x->size : y->size;
+ int c = c_memcmp(x->str, y->str, n);
+ return c ? c : (int)(x->size - y->size);
+}
+
+STC_INLINE bool crawstr_eq(const crawstr* x, const crawstr* y)
+ { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); }
+
+STC_INLINE uint64_t crawstr_hash(const crawstr *self)
+ { return stc_hash(self->str, self->size); }
+
+#endif // CRAWSTR_H_INCLUDED
+#undef i_static
+#undef i_header
+#undef i_implement
+#undef i_import
+#undef i_opt
diff --git a/include/stc/cregex.h b/include/stc/cregex.h
index a48b4c49..c8ad6dbe 100644
--- a/include/stc/cregex.h
+++ b/include/stc/cregex.h
@@ -22,6 +22,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
+#include "priv/linkage.h"
+
#ifndef CREGEX_H_INCLUDED
#define CREGEX_H_INCLUDED
/*
@@ -37,15 +39,19 @@ THE SOFTWARE.
enum {
CREG_DEFAULT = 0,
+
/* compile-flags */
- CREG_C_DOTALL = 1<<0, /* dot matches newline too */
- CREG_C_ICASE = 1<<1, /* ignore case */
+ CREG_DOTALL = 1<<0, /* dot matches newline too */
+ CREG_ICASE = 1<<1, /* ignore case */
+
/* match-flags */
- CREG_M_FULLMATCH = 1<<2, /* like start-, end-of-line anchors were in pattern: "^ ... $" */
- CREG_M_NEXT = 1<<3, /* use end of previous match[0] as start of input */
- CREG_M_STARTEND = 1<<4, /* use match[0] as start+end of input */
+ CREG_FULLMATCH = 1<<2, /* like start-, end-of-line anchors were in pattern: "^ ... $" */
+ CREG_NEXT = 1<<3, /* use end of previous match[0] as start of input */
+ CREG_STARTEND = 1<<4, /* use match[0] as start+end of input */
+
/* replace-flags */
- CREG_R_STRIP = 1<<5, /* only keep the matched strings, strip rest */
+ CREG_STRIP = 1<<5, /* only keep the matched strings, strip rest */
+
/* limits */
CREG_MAX_CLASSES = 16,
CREG_MAX_CAPTURES = 32,
@@ -53,7 +59,6 @@ enum {
typedef enum {
CREG_OK = 0,
- CREG_SUCCESS = 0, /* [deprecated] */
CREG_NOMATCH = -1,
CREG_MATCHERROR = -2,
CREG_OUTOFMEMORY = -3,
@@ -82,7 +87,7 @@ typedef struct {
#define c_formatch(it, Re, Input) \
for (cregex_iter it = {Re, Input}; \
- cregex_find_4(it.re, it.input, it.match, CREG_M_NEXT) == CREG_OK; )
+ cregex_find_4(it.re, it.input, it.match, CREG_NEXT) == CREG_OK; )
STC_INLINE cregex cregex_init(void) {
cregex re = {0};
@@ -104,7 +109,7 @@ STC_INLINE cregex cregex_from_2(const char* pattern, int cflags) {
return re;
}
-/* number of capture groups in a regex pattern including full the match capture, 0 if regex is invalid */
+/* number of capture groups in a regex pattern, excluding the full match capture (0) */
int cregex_captures(const cregex* re);
/* return CREG_OK, CREG_NOMATCH or CREG_MATCHERROR. */
@@ -116,7 +121,7 @@ int cregex_find_4(const cregex* re, const char* input, csview match[], int mflag
STC_INLINE int cregex_find_sv(const cregex* re, csview input, csview match[]) {
csview *mp = NULL;
if (match) { match[0] = input; mp = match; }
- return cregex_find(re, input.str, mp, CREG_M_STARTEND);
+ return cregex_find(re, input.buf, mp, CREG_STARTEND);
}
/* match + compile RE pattern */
@@ -136,7 +141,7 @@ STC_INLINE bool cregex_is_match(const cregex* re, const char* input)
#define cregex_replace_sv_4(pattern, input, replace, count) \
cregex_replace_sv_6(pattern, input, replace, count, NULL, CREG_DEFAULT)
cstr cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count,
- bool (*mfun)(int i, csview match, cstr* mstr), int rflags);
+ bool (*transform)(int group, csview match, cstr* result), int rflags);
/* replace input with replace using regular expression */
#define cregex_replace(...) c_MACRO_OVERLOAD(cregex_replace, __VA_ARGS__)
@@ -154,18 +159,20 @@ STC_INLINE cstr cregex_replace_4(const cregex* re, const char* input, const char
#define cregex_replace_pattern_4(pattern, input, replace, count) \
cregex_replace_pattern_6(pattern, input, replace, count, NULL, CREG_DEFAULT)
cstr cregex_replace_pattern_6(const char* pattern, const char* input, const char* replace, int count,
- bool (*mfun)(int i, csview match, cstr* mstr), int crflags);
+ bool (*transform)(int group, csview match, cstr* result), int crflags);
/* destroy regex */
void cregex_drop(cregex* re);
-
#endif // CREGEX_H_INCLUDED
-#if defined(i_extern)
+
+#if defined i_implement
# include "../../src/cregex.c"
+#endif
+#if defined i_import
# include "../../src/utf8code.c"
-# undef i_extern
#endif
#undef i_opt
#undef i_header
#undef i_static
+#undef i_import
#undef i_implement
diff --git a/include/stc/cset.h b/include/stc/cset.h
index 58cbeb3e..c89a144d 100644
--- a/include/stc/cset.h
+++ b/include/stc/cset.h
@@ -39,8 +39,5 @@ int main(void) {
}
*/
-#ifndef _i_prefix
#define _i_prefix cset_
-#endif
-#define _i_isset
#include "cmap.h"
diff --git a/include/stc/csmap.h b/include/stc/csmap.h
index ebfe8d44..d2e1d1fc 100644
--- a/include/stc/csmap.h
+++ b/include/stc/csmap.h
@@ -24,6 +24,7 @@
// Sorted/Ordered set and map - implemented as an AA-tree.
/*
#include <stdio.h>
+#define i_implement
#include <stc/cstr.h>
#define i_tag sx // Sorted map<cstr, double>
@@ -48,9 +49,10 @@ int main(void) {
csmap_sx_drop(&m);
}
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CSMAP_H_INCLUDED
+#include "ccommon.h"
#include "forward.h"
#include <stdlib.h>
#include <string.h>
@@ -58,27 +60,20 @@ int main(void) {
#endif // CSMAP_H_INCLUDED
#ifndef _i_prefix
-#define _i_prefix csmap_
-#endif
-#ifdef _i_isset
- #define _i_MAP_ONLY c_false
- #define _i_SET_ONLY c_true
- #define _i_keyref(vp) (vp)
-#else
+ #define _i_prefix csmap_
#define _i_ismap
#define _i_MAP_ONLY c_true
#define _i_SET_ONLY c_false
#define _i_keyref(vp) (&(vp)->first)
-#endif
-#ifndef i_ssize
- #define i_ssize int32_t
- #define _i_size intptr_t
#else
- #define _i_size i_ssize
+ #define _i_isset
+ #define _i_MAP_ONLY c_false
+ #define _i_SET_ONLY c_true
+ #define _i_keyref(vp) (vp)
#endif
#include "priv/template.h"
#ifndef i_is_forward
- _cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY);
+ _cx_DEFTYPES(_c_aatree_types, _cx_Self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY);
#endif
_i_MAP_ONLY( struct _cx_value {
@@ -86,205 +81,251 @@ _i_MAP_ONLY( struct _cx_value {
_cx_mapped second;
}; )
struct _cx_node {
- i_ssize link[2];
+ int32_t link[2];
int8_t level;
_cx_value value;
};
typedef i_keyraw _cx_keyraw;
-typedef i_valraw _cx_memb(_rmapped);
+typedef i_valraw _cx_MEMB(_rmapped);
typedef _i_SET_ONLY( i_keyraw )
_i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } )
_cx_raw;
#if !defined i_no_emplace
-STC_API _cx_result _cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped));
+STC_API _cx_result _cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped));
#endif // !i_no_emplace
#if !defined i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self tree);
+STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self tree);
#endif // !i_no_clone
-STC_API _cx_result _cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped));
-STC_API _cx_result _cx_memb(_push)(_cx_self* self, _cx_value _val);
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, _i_size cap);
-STC_API _cx_value* _cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out);
-STC_API _cx_iter _cx_memb(_lower_bound)(const _cx_self* self, _cx_keyraw rkey);
-STC_API _cx_value* _cx_memb(_front)(const _cx_self* self);
-STC_API _cx_value* _cx_memb(_back)(const _cx_self* self);
-STC_API int _cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey);
-STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it);
-STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2);
-STC_API void _cx_memb(_next)(_cx_iter* it);
-
-STC_INLINE _cx_self _cx_memb(_init)(void) { _cx_self tree = {0}; return tree; }
-STC_INLINE bool _cx_memb(_empty)(const _cx_self* cx) { return cx->size == 0; }
-STC_INLINE _i_size _cx_memb(_size)(const _cx_self* cx) { return cx->size; }
-STC_INLINE _i_size _cx_memb(_capacity)(const _cx_self* cx) { return cx->cap; }
-STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, _cx_keyraw rkey)
- { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); return it; }
-STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it) != NULL; }
-STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, _cx_keyraw rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
-STC_INLINE _cx_value* _cx_memb(_get_mut)(_cx_self* self, _cx_keyraw rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
-
-STC_INLINE _cx_self
-_cx_memb(_with_capacity)(const _i_size cap) {
- _cx_self tree = _cx_memb(_init)();
- _cx_memb(_reserve)(&tree, cap);
+STC_API void _cx_MEMB(_drop)(_cx_Self* self);
+STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t cap);
+STC_API _cx_value* _cx_MEMB(_find_it)(const _cx_Self* self, _cx_keyraw rkey, _cx_iter* out);
+STC_API _cx_iter _cx_MEMB(_lower_bound)(const _cx_Self* self, _cx_keyraw rkey);
+STC_API _cx_value* _cx_MEMB(_front)(const _cx_Self* self);
+STC_API _cx_value* _cx_MEMB(_back)(const _cx_Self* self);
+STC_API int _cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey);
+STC_API _cx_iter _cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it);
+STC_API _cx_iter _cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2);
+STC_API _cx_iter _cx_MEMB(_begin)(const _cx_Self* self);
+STC_API void _cx_MEMB(_next)(_cx_iter* it);
+
+STC_INLINE _cx_Self _cx_MEMB(_init)(void) { _cx_Self tree = {0}; return tree; }
+STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* cx) { return cx->size == 0; }
+STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* cx) { return cx->size; }
+STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* cx) { return cx->cap; }
+STC_INLINE _cx_iter _cx_MEMB(_find)(const _cx_Self* self, _cx_keyraw rkey)
+ { _cx_iter it; _cx_MEMB(_find_it)(self, rkey, &it); return it; }
+STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rkey)
+ { _cx_iter it; return _cx_MEMB(_find_it)(self, rkey, &it) != NULL; }
+STC_INLINE const _cx_value* _cx_MEMB(_get)(const _cx_Self* self, _cx_keyraw rkey)
+ { _cx_iter it; return _cx_MEMB(_find_it)(self, rkey, &it); }
+STC_INLINE _cx_value* _cx_MEMB(_get_mut)(_cx_Self* self, _cx_keyraw rkey)
+ { _cx_iter it; return _cx_MEMB(_find_it)(self, rkey, &it); }
+
+STC_INLINE _cx_Self
+_cx_MEMB(_with_capacity)(const intptr_t cap) {
+ _cx_Self tree = _cx_MEMB(_init)();
+ _cx_MEMB(_reserve)(&tree, cap);
return tree;
}
STC_INLINE void
-_cx_memb(_clear)(_cx_self* self)
- { _cx_memb(_drop)(self); *self = _cx_memb(_init)(); }
+_cx_MEMB(_clear)(_cx_Self* self)
+ { _cx_MEMB(_drop)(self); *self = _cx_MEMB(_init)(); }
STC_INLINE _cx_raw
-_cx_memb(_value_toraw)(const _cx_value* val) {
+_cx_MEMB(_value_toraw)(const _cx_value* val) {
return _i_SET_ONLY( i_keyto(val) )
_i_MAP_ONLY( c_LITERAL(_cx_raw){i_keyto((&val->first)),
i_valto((&val->second))} );
}
STC_INLINE void
-_cx_memb(_value_drop)(_cx_value* val) {
+_cx_MEMB(_value_drop)(_cx_value* val) {
i_keydrop(_i_keyref(val));
_i_MAP_ONLY( i_valdrop((&val->second)); )
}
#if !defined i_no_clone
STC_INLINE _cx_value
-_cx_memb(_value_clone)(_cx_value _val) {
+_cx_MEMB(_value_clone)(_cx_value _val) {
*_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val)));
_i_MAP_ONLY( _val.second = i_valclone(_val.second); )
return _val;
}
STC_INLINE void
-_cx_memb(_copy)(_cx_self *self, const _cx_self* other) {
+_cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) {
if (self->nodes == other->nodes)
return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(*other);
+ _cx_MEMB(_drop)(self);
+ *self = _cx_MEMB(_clone)(*other);
}
STC_INLINE void
-_cx_memb(_shrink_to_fit)(_cx_self *self) {
- _cx_self tmp = _cx_memb(_clone)(*self);
- _cx_memb(_drop)(self); *self = tmp;
+_cx_MEMB(_shrink_to_fit)(_cx_Self *self) {
+ _cx_Self tmp = _cx_MEMB(_clone)(*self);
+ _cx_MEMB(_drop)(self); *self = tmp;
}
#endif // !i_no_clone
-#ifndef _i_isset
- STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped);
+STC_API _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey);
+
+#ifdef _i_ismap
+ STC_API _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key key, i_val mapped);
#if !defined i_no_emplace
- STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped);
+ STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped);
+
+ STC_INLINE _cx_result
+ _cx_MEMB(_emplace_key)(_cx_Self* self, _cx_keyraw rkey) {
+ _cx_result res = _cx_MEMB(_insert_entry_)(self, rkey);
+ if (res.inserted)
+ res.ref->first = i_keyfrom(rkey);
+ return res;
+ }
#endif
-
STC_INLINE const _cx_mapped*
- _cx_memb(_at)(const _cx_self* self, _cx_keyraw rkey)
- { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
- STC_INLINE _cx_mapped*
- _cx_memb(_at_mut)(_cx_self* self, _cx_keyraw rkey)
- { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
-#endif // !_i_isset
+ _cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey)
+ { _cx_iter it; return &_cx_MEMB(_find_it)(self, rkey, &it)->second; }
-STC_INLINE _cx_iter
-_cx_memb(_begin)(const _cx_self* self) {
- _cx_iter it;
- it.ref = NULL;
- it._d = self->nodes, it._top = 0;
- it._tn = self->root;
- if (it._tn)
- _cx_memb(_next)(&it);
- return it;
-}
+ STC_INLINE _cx_mapped*
+ _cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey)
+ { _cx_iter it; return &_cx_MEMB(_find_it)(self, rkey, &it)->second; }
+#endif // _i_ismap
STC_INLINE _cx_iter
-_cx_memb(_end)(const _cx_self* self) {
+_cx_MEMB(_end)(const _cx_Self* self) {
(void)self;
_cx_iter it; it.ref = NULL, it._top = 0, it._tn = 0;
return it;
}
STC_INLINE _cx_iter
-_cx_memb(_advance)(_cx_iter it, size_t n) {
+_cx_MEMB(_advance)(_cx_iter it, size_t n) {
while (n-- && it.ref)
- _cx_memb(_next)(&it);
+ _cx_MEMB(_next)(&it);
return it;
}
STC_INLINE bool
-_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
- if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false;
- _cx_iter i = _cx_memb(_begin)(self), j = _cx_memb(_begin)(other);
- for (; i.ref; _cx_memb(_next)(&i), _cx_memb(_next)(&j)) {
+_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false;
+ _cx_iter i = _cx_MEMB(_begin)(self), j = _cx_MEMB(_begin)(other);
+ for (; i.ref; _cx_MEMB(_next)(&i), _cx_MEMB(_next)(&j)) {
const _cx_keyraw _rx = i_keyto(_i_keyref(i.ref)), _ry = i_keyto(_i_keyref(j.ref));
if (!(i_eq((&_rx), (&_ry)))) return false;
}
return true;
}
-STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, _i_size n) {
+STC_INLINE _cx_result
+_cx_MEMB(_insert)(_cx_Self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key)));
+ if (_res.inserted)
+ { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )}
+ else
+ { i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )}
+ return _res;
+}
+
+STC_INLINE _cx_value*
+_cx_MEMB(_push)(_cx_Self* self, _cx_value _val) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
+ if (_res.inserted)
+ *_res.ref = _val;
+ else
+ _cx_MEMB(_value_drop)(&_val);
+ return _res.ref;
+}
+
+STC_INLINE void
+_cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) {
while (n--)
#if defined _i_isset && defined i_no_emplace
- _cx_memb(_insert)(self, *raw++);
+ _cx_MEMB(_insert)(self, *raw++);
#elif defined _i_isset
- _cx_memb(_emplace)(self, *raw++);
+ _cx_MEMB(_emplace)(self, *raw++);
#elif defined i_no_emplace
- _cx_memb(_insert_or_assign)(self, raw->first, raw->second), ++raw;
+ _cx_MEMB(_insert_or_assign)(self, raw->first, raw->second), ++raw;
#else
- _cx_memb(_emplace_or_assign)(self, raw->first, raw->second), ++raw;
+ _cx_MEMB(_emplace_or_assign)(self, raw->first, raw->second), ++raw;
#endif
}
-STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, _i_size n)
- { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; }
+STC_INLINE _cx_Self
+_cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n)
+ { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; }
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+#if defined(i_implement) || defined(i_static)
+
+STC_DEF void
+_cx_MEMB(_next)(_cx_iter *it) {
+ int32_t tn = it->_tn;
+ if (it->_top || tn) {
+ while (tn) {
+ it->_st[it->_top++] = tn;
+ tn = it->_d[tn].link[0];
+ }
+ tn = it->_st[--it->_top];
+ it->_tn = it->_d[tn].link[1];
+ it->ref = &it->_d[tn].value;
+ } else
+ it->ref = NULL;
+}
+
+STC_DEF _cx_iter
+_cx_MEMB(_begin)(const _cx_Self* self) {
+ _cx_iter it;
+ it.ref = NULL;
+ it._d = self->nodes, it._top = 0;
+ it._tn = self->root;
+ if (it._tn)
+ _cx_MEMB(_next)(&it);
+ return it;
+}
STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const _i_size cap) {
+_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t cap) {
if (cap <= self->cap)
return false;
_cx_node* nodes = (_cx_node*)i_realloc(self->nodes, (cap + 1)*c_sizeof(_cx_node));
if (!nodes)
return false;
- nodes[0] = c_LITERAL(_cx_node){{0, 0}, 0};
+ nodes[0] = c_LITERAL(_cx_node){0};
self->nodes = nodes;
- self->cap = (i_ssize)cap;
+ self->cap = (int32_t)cap;
return true;
}
STC_DEF _cx_value*
-_cx_memb(_front)(const _cx_self* self) {
+_cx_MEMB(_front)(const _cx_Self* self) {
_cx_node *d = self->nodes;
- i_ssize tn = self->root;
+ int32_t tn = self->root;
while (d[tn].link[0])
tn = d[tn].link[0];
return &d[tn].value;
}
STC_DEF _cx_value*
-_cx_memb(_back)(const _cx_self* self) {
+_cx_MEMB(_back)(const _cx_Self* self) {
_cx_node *d = self->nodes;
- i_ssize tn = self->root;
+ int32_t tn = self->root;
while (d[tn].link[1])
tn = d[tn].link[1];
return &d[tn].value;
}
-static i_ssize
-_cx_memb(_new_node_)(_cx_self* self, int level) {
- i_ssize tn;
+static int32_t
+_cx_MEMB(_new_node_)(_cx_Self* self, int level) {
+ int32_t tn;
if (self->disp) {
tn = self->disp;
self->disp = self->nodes[tn].link[1];
} else {
if (self->head == self->cap)
- if (!_cx_memb(_reserve)(self, self->head*3/2 + 4))
+ if (!_cx_MEMB(_reserve)(self, self->head*3/2 + 4))
return 0;
tn = ++self->head; /* start with 1, 0 is nullnode. */
}
@@ -293,32 +334,10 @@ _cx_memb(_new_node_)(_cx_self* self, int level) {
return tn;
}
-static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey);
-
-STC_DEF _cx_result
-_cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key)));
- if (_res.inserted)
- { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )}
- else
- { i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )}
- return _res;
-}
-
-STC_DEF _cx_result
-_cx_memb(_push)(_cx_self* self, _cx_value _val) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
- if (_res.inserted)
- *_res.ref = _val;
- else
- _cx_memb(_value_drop)(&_val);
- return _res;
-}
-
-#ifndef _i_isset
+#ifdef _i_ismap
STC_DEF _cx_result
- _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key)));
+ _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key _key, i_val _mapped) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key)));
_cx_mapped* _mp = _res.ref ? &_res.ref->second : &_mapped;
if (_res.inserted)
_res.ref->first = _key;
@@ -330,8 +349,8 @@ _cx_memb(_push)(_cx_self* self, _cx_value _val) {
#if !defined i_no_emplace
STC_DEF _cx_result
- _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, rkey);
+ _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey);
if (_res.inserted)
_res.ref->first = i_keyfrom(rkey);
else {
@@ -342,11 +361,11 @@ _cx_memb(_push)(_cx_self* self, _cx_value _val) {
return _res;
}
#endif // !i_no_emplace
-#endif // !_i_isset
+#endif // !_i_ismap
STC_DEF _cx_value*
-_cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out) {
- i_ssize tn = self->root;
+_cx_MEMB(_find_it)(const _cx_Self* self, _cx_keyraw rkey, _cx_iter* out) {
+ int32_t tn = self->root;
_cx_node *d = out->_d = self->nodes;
out->_top = 0;
while (tn) {
@@ -362,36 +381,21 @@ _cx_memb(_find_it)(const _cx_self* self, _cx_keyraw rkey, _cx_iter* out) {
}
STC_DEF _cx_iter
-_cx_memb(_lower_bound)(const _cx_self* self, _cx_keyraw rkey) {
+_cx_MEMB(_lower_bound)(const _cx_Self* self, _cx_keyraw rkey) {
_cx_iter it;
- _cx_memb(_find_it)(self, rkey, &it);
+ _cx_MEMB(_find_it)(self, rkey, &it);
if (!it.ref && it._top) {
- i_ssize tn = it._st[--it._top];
+ int32_t tn = it._st[--it._top];
it._tn = it._d[tn].link[1];
it.ref = &it._d[tn].value;
}
return it;
}
-STC_DEF void
-_cx_memb(_next)(_cx_iter *it) {
- i_ssize tn = it->_tn;
- if (it->_top || tn) {
- while (tn) {
- it->_st[it->_top++] = tn;
- tn = it->_d[tn].link[0];
- }
- tn = it->_st[--it->_top];
- it->_tn = it->_d[tn].link[1];
- it->ref = &it->_d[tn].value;
- } else
- it->ref = NULL;
-}
-
-STC_DEF i_ssize
-_cx_memb(_skew_)(_cx_node *d, i_ssize tn) {
+STC_DEF int32_t
+_cx_MEMB(_skew_)(_cx_node *d, int32_t tn) {
if (tn && d[d[tn].link[0]].level == d[tn].level) {
- i_ssize tmp = d[tn].link[0];
+ int32_t tmp = d[tn].link[0];
d[tn].link[0] = d[tmp].link[1];
d[tmp].link[1] = tn;
tn = tmp;
@@ -399,10 +403,10 @@ _cx_memb(_skew_)(_cx_node *d, i_ssize tn) {
return tn;
}
-STC_DEF i_ssize
-_cx_memb(_split_)(_cx_node *d, i_ssize tn) {
+STC_DEF int32_t
+_cx_MEMB(_split_)(_cx_node *d, int32_t tn) {
if (d[d[d[tn].link[1]].link[1]].level == d[tn].level) {
- i_ssize tmp = d[tn].link[1];
+ int32_t tmp = d[tn].link[1];
d[tn].link[1] = d[tmp].link[0];
d[tmp].link[0] = tn;
tn = tmp;
@@ -411,9 +415,9 @@ _cx_memb(_split_)(_cx_node *d, i_ssize tn) {
return tn;
}
-static i_ssize
-_cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_keyraw* rkey, _cx_result* _res) {
- i_ssize up[64], tx = tn;
+STC_DEF int32_t
+_cx_MEMB(_insert_entry_i_)(_cx_Self* self, int32_t tn, const _cx_keyraw* rkey, _cx_result* _res) {
+ int32_t up[64], tx = tn;
_cx_node* d = self->nodes;
int c, top = 0, dir = 0;
while (tx) {
@@ -424,7 +428,7 @@ _cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_keyraw* rkey, _
dir = (c < 0);
tx = d[tx].link[dir];
}
- if ((tx = _cx_memb(_new_node_)(self, 1)) == 0)
+ if ((tx = _cx_MEMB(_new_node_)(self, 1)) == 0)
return 0;
d = self->nodes;
_res->ref = &d[tx].value;
@@ -435,42 +439,42 @@ _cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_keyraw* rkey, _
while (top--) {
if (top)
dir = (d[up[top - 1]].link[1] == up[top]);
- up[top] = _cx_memb(_skew_)(d, up[top]);
- up[top] = _cx_memb(_split_)(d, up[top]);
+ up[top] = _cx_MEMB(_skew_)(d, up[top]);
+ up[top] = _cx_MEMB(_split_)(d, up[top]);
if (top)
d[up[top - 1]].link[dir] = up[top];
}
return up[0];
}
-static _cx_result
-_cx_memb(_insert_entry_)(_cx_self* self, _cx_keyraw rkey) {
+STC_DEF _cx_result
+_cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) {
_cx_result res = {NULL};
- i_ssize tn = _cx_memb(_insert_entry_i_)(self, self->root, &rkey, &res);
+ int32_t tn = _cx_MEMB(_insert_entry_i_)(self, self->root, &rkey, &res);
self->root = tn;
self->size += res.inserted;
return res;
}
-static i_ssize
-_cx_memb(_erase_r_)(_cx_self *self, i_ssize tn, const _cx_keyraw* rkey, int *erased) {
+STC_DEF int32_t
+_cx_MEMB(_erase_r_)(_cx_Self *self, int32_t tn, const _cx_keyraw* rkey, int *erased) {
_cx_node *d = self->nodes;
if (tn == 0)
return 0;
_cx_keyraw raw = i_keyto(_i_keyref(&d[tn].value));
- i_ssize tx; int c = i_cmp((&raw), rkey);
+ int32_t tx; int c = i_cmp((&raw), rkey);
if (c != 0)
- d[tn].link[c < 0] = _cx_memb(_erase_r_)(self, d[tn].link[c < 0], rkey, erased);
+ d[tn].link[c < 0] = _cx_MEMB(_erase_r_)(self, d[tn].link[c < 0], rkey, erased);
else {
if (!(*erased)++)
- _cx_memb(_value_drop)(&d[tn].value);
+ _cx_MEMB(_value_drop)(&d[tn].value);
if (d[tn].link[0] && d[tn].link[1]) {
tx = d[tn].link[0];
while (d[tx].link[1])
tx = d[tx].link[1];
d[tn].value = d[tx].value; /* move */
raw = i_keyto(_i_keyref(&d[tn].value));
- d[tn].link[0] = _cx_memb(_erase_r_)(self, d[tn].link[0], &raw, erased);
+ d[tn].link[0] = _cx_MEMB(_erase_r_)(self, d[tn].link[0], &raw, erased);
} else { /* unlink node */
tx = tn;
tn = d[tn].link[ d[tn].link[0] == 0 ];
@@ -483,19 +487,19 @@ _cx_memb(_erase_r_)(_cx_self *self, i_ssize tn, const _cx_keyraw* rkey, int *era
if (d[d[tn].link[0]].level < d[tn].level - 1 || d[tx].level < d[tn].level - 1) {
if (d[tx].level > --d[tn].level)
d[tx].level = d[tn].level;
- tn = _cx_memb(_skew_)(d, tn);
- tx = d[tn].link[1] = _cx_memb(_skew_)(d, d[tn].link[1]);
- d[tx].link[1] = _cx_memb(_skew_)(d, d[tx].link[1]);
- tn = _cx_memb(_split_)(d, tn);
- d[tn].link[1] = _cx_memb(_split_)(d, d[tn].link[1]);
+ tn = _cx_MEMB(_skew_)(d, tn);
+ tx = d[tn].link[1] = _cx_MEMB(_skew_)(d, d[tn].link[1]);
+ d[tx].link[1] = _cx_MEMB(_skew_)(d, d[tx].link[1]);
+ tn = _cx_MEMB(_split_)(d, tn);
+ d[tn].link[1] = _cx_MEMB(_split_)(d, d[tn].link[1]);
}
return tn;
}
STC_DEF int
-_cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) {
+_cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey) {
int erased = 0;
- i_ssize root = _cx_memb(_erase_r_)(self, self->root, &rkey, &erased);
+ int32_t root = _cx_MEMB(_erase_r_)(self, self->root, &rkey, &erased);
if (!erased)
return 0;
self->root = root;
@@ -504,23 +508,23 @@ _cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) {
}
STC_DEF _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
+_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) {
_cx_keyraw raw = i_keyto(_i_keyref(it.ref));
- _cx_memb(_next)(&it);
+ _cx_MEMB(_next)(&it);
if (it.ref) {
_cx_keyraw nxt = i_keyto(_i_keyref(it.ref));
- _cx_memb(_erase)(self, raw);
- _cx_memb(_find_it)(self, nxt, &it);
+ _cx_MEMB(_erase)(self, raw);
+ _cx_MEMB(_find_it)(self, nxt, &it);
} else
- _cx_memb(_erase)(self, raw);
+ _cx_MEMB(_erase)(self, raw);
return it;
}
STC_DEF _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
+_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2) {
if (!it2.ref) {
while (it1.ref)
- it1 = _cx_memb(_erase_at)(self, it1);
+ it1 = _cx_MEMB(_erase_at)(self, it1);
return it1;
}
_cx_key k1 = *_i_keyref(it1.ref), k2 = *_i_keyref(it2.ref);
@@ -528,30 +532,30 @@ _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
for (;;) {
if (memcmp(&k1, &k2, sizeof k1) == 0)
return it1;
- _cx_memb(_next)(&it1);
+ _cx_MEMB(_next)(&it1);
k1 = *_i_keyref(it1.ref);
- _cx_memb(_erase)(self, r1);
+ _cx_MEMB(_erase)(self, r1);
r1 = i_keyto((&k1));
- _cx_memb(_find_it)(self, r1, &it1);
+ _cx_MEMB(_find_it)(self, r1, &it1);
}
}
#if !defined i_no_clone
-static i_ssize
-_cx_memb(_clone_r_)(_cx_self* self, _cx_node* src, i_ssize sn) {
+STC_DEF int32_t
+_cx_MEMB(_clone_r_)(_cx_Self* self, _cx_node* src, int32_t sn) {
if (sn == 0)
return 0;
- i_ssize tx, tn = _cx_memb(_new_node_)(self, src[sn].level);
- self->nodes[tn].value = _cx_memb(_value_clone)(src[sn].value);
- tx = _cx_memb(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx;
- tx = _cx_memb(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx;
+ int32_t tx, tn = _cx_MEMB(_new_node_)(self, src[sn].level);
+ self->nodes[tn].value = _cx_MEMB(_value_clone)(src[sn].value);
+ tx = _cx_MEMB(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx;
+ tx = _cx_MEMB(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx;
return tn;
}
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self tree) {
- _cx_self clone = _cx_memb(_with_capacity)(tree.size);
- i_ssize root = _cx_memb(_clone_r_)(&clone, tree.nodes, tree.root);
+STC_DEF _cx_Self
+_cx_MEMB(_clone)(_cx_Self tree) {
+ _cx_Self clone = _cx_MEMB(_with_capacity)(tree.size);
+ int32_t root = _cx_MEMB(_clone_r_)(&clone, tree.nodes, tree.root);
clone.root = root;
clone.size = tree.size;
return clone;
@@ -560,8 +564,8 @@ _cx_memb(_clone)(_cx_self tree) {
#if !defined i_no_emplace
STC_DEF _cx_result
-_cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) {
- _cx_result res = _cx_memb(_insert_entry_)(self, rkey);
+_cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) {
+ _cx_result res = _cx_MEMB(_insert_entry_)(self, rkey);
if (res.inserted) {
*_i_keyref(res.ref) = i_keyfrom(rkey);
_i_MAP_ONLY(res.ref->second = i_valfrom(rmapped);)
@@ -571,24 +575,23 @@ _cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmappe
#endif // i_no_emplace
static void
-_cx_memb(_drop_r_)(_cx_node* d, i_ssize tn) {
+_cx_MEMB(_drop_r_)(_cx_node* d, int32_t tn) {
if (tn) {
- _cx_memb(_drop_r_)(d, d[tn].link[0]);
- _cx_memb(_drop_r_)(d, d[tn].link[1]);
- _cx_memb(_value_drop)(&d[tn].value);
+ _cx_MEMB(_drop_r_)(d, d[tn].link[0]);
+ _cx_MEMB(_drop_r_)(d, d[tn].link[1]);
+ _cx_MEMB(_value_drop)(&d[tn].value);
}
}
STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
+_cx_MEMB(_drop)(_cx_Self* self) {
if (self->cap) {
- _cx_memb(_drop_r_)(self->nodes, self->root);
+ _cx_MEMB(_drop_r_)(self->nodes, self->root);
i_free(self->nodes);
}
}
#endif // i_implement
-#undef _i_size
#undef _i_isset
#undef _i_ismap
#undef _i_keyref
diff --git a/include/stc/cspan.h b/include/stc/cspan.h
index ac3e9206..0875ed92 100644
--- a/include/stc/cspan.h
+++ b/include/stc/cspan.h
@@ -24,9 +24,9 @@
/*
#include <stdio.h>
#include <stc/cspan.h>
-#include <stc/algo/filter.h>
+#include <stc/algorithm.h>
using_cspan(Span2f, float, 2);
-using_cspan(Intspan, int, 1);
+using_cspan(Intspan, int);
int demo1() {
float raw[4*5];
@@ -60,209 +60,231 @@ int demo2() {
#ifndef STC_CSPAN_H_INCLUDED
#define STC_CSPAN_H_INCLUDED
+#include "priv/linkage.h"
#include "ccommon.h"
#define using_cspan(...) c_MACRO_OVERLOAD(using_cspan, __VA_ARGS__)
#define using_cspan_2(Self, T) \
- using_cspan_3(Self, T, 1)
+ using_cspan_3(Self, T, 1); \
+ STC_INLINE Self Self##_from_n(Self##_raw* raw, const intptr_t n) { \
+ return (Self){.data=raw, .shape={(int32_t)n}, .stride={.d={1}}}; \
+ } \
+ struct stc_nostruct
#define using_cspan_3(Self, T, RANK) \
typedef T Self##_value; typedef T Self##_raw; \
typedef struct { \
Self##_value *data; \
int32_t shape[RANK]; \
- cspan_idx##RANK stride; \
+ cspan_tuple##RANK stride; \
} Self; \
\
typedef struct { Self##_value *ref; int32_t pos[RANK]; const Self *_s; } Self##_iter; \
\
- 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[], \
- const int rank, const int32_t a[][2]) { \
- Self s = {.data=v}; int outrank; \
- s.data += _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \
- c_ASSERT(outrank == RANK); \
+ STC_INLINE Self Self##_slice_(Self##_value* d, const int32_t shape[], const intptr_t stri[], \
+ const int rank, const int32_t a[][3]) { \
+ Self s; int outrank; \
+ s.data = d + _cspan_slice(s.shape, s.stride.d, &outrank, shape, stri, rank, a); \
+ c_assert(outrank == RANK); \
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) { \
- it->ref += _cspan_next##RANK(RANK, it->pos, it->_s->shape, it->_s->stride.d); \
- if (it->pos[0] == it->_s->shape[0]) it->ref = NULL; \
+ int done; \
+ it->ref += _cspan_next##RANK(it->pos, it->_s->shape, it->_s->stride.d, RANK, &done); \
+ if (done) it->ref = NULL; \
} \
struct stc_nostruct
-#define using_cspan2(Self, T) using_cspan_3(Self, T, 1); using_cspan_3(Self##2, T, 2)
+#define using_cspan2(Self, T) using_cspan_2(Self, T); using_cspan_3(Self##2, T, 2)
#define using_cspan3(Self, T) using_cspan2(Self, T); using_cspan_3(Self##3, T, 3)
#define using_cspan4(Self, T) using_cspan3(Self, T); using_cspan_3(Self##4, T, 4)
-typedef struct { int32_t d[1]; } cspan_idx1;
-typedef struct { int32_t d[2]; } cspan_idx2;
-typedef struct { int32_t d[3]; } cspan_idx3;
-typedef struct { int32_t d[4]; } cspan_idx4;
-typedef struct { int32_t d[5]; } cspan_idx5;
-typedef struct { int32_t d[6]; } cspan_idx6;
-#define c_END -1
-#define c_ALL 0,-1
+#define using_cspan_tuple(N) typedef struct { intptr_t d[N]; } cspan_tuple##N
+using_cspan_tuple(1); using_cspan_tuple(2);
+using_cspan_tuple(3); using_cspan_tuple(4);
+using_cspan_tuple(5); using_cspan_tuple(6);
+using_cspan_tuple(7); using_cspan_tuple(8);
-#define cspan_md(array, ...) \
- {.data=array, .shape={__VA_ARGS__}, .stride={.d={__VA_ARGS__}}}
+#define c_END -1
+#define c_ALL 0,c_END
+typedef enum {c_ROWMAJOR, c_COLMAJOR} cspan_layout;
-/* For static initialization, use cspan_make(). c_make() for non-static only. */
-#define cspan_make(SpanType, ...) \
- {.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}}
+/* Use cspan_init() for static initialization only. c_init() for non-static init. */
+#define cspan_init(SpanType, ...) \
+ {.data=(SpanType##_value[])__VA_ARGS__, .shape={sizeof((SpanType##_value[])__VA_ARGS__)/sizeof(SpanType##_value)}, .stride={.d={1}}}
-#define cspan_slice(OutSpan, parent, ...) \
- OutSpan##_slice_((parent)->data, (parent)->shape, (parent)->stride.d, cspan_rank(parent) + \
- c_static_assert(cspan_rank(parent) == sizeof((int32_t[][2]){__VA_ARGS__})/sizeof(int32_t[2])), \
- (const int32_t[][2]){__VA_ARGS__})
-
-/* create a cspan from a cvec, cstack, cdeq, cqueue, or cpque (heap) */
+/* create a cspan from a cvec, cstack, or cpque (heap) */
#define cspan_from(container) \
- {.data=(container)->data, .shape={(int32_t)(container)->_len}}
+ {.data=(container)->data, .shape={(int32_t)(container)->_len}, .stride={.d={1}}}
+
+#define cspan_from_n(ptr, n) \
+ {.data=(ptr), .shape={n}, .stride={.d={1}}}
#define cspan_from_array(array) \
- {.data=(array) + c_static_assert(sizeof(array) != sizeof(void*)), .shape={c_arraylen(array)}}
+ cspan_from_n(array, c_arraylen(array))
#define cspan_size(self) _cspan_size((self)->shape, cspan_rank(self))
#define cspan_rank(self) c_arraylen((self)->shape)
-
-#define cspan_index(self, ...) c_PASTE(cspan_idx_, c_NUMARGS(__VA_ARGS__))(self, __VA_ARGS__)
-#define cspan_idx_1 cspan_idx_4
-#define cspan_idx_2 cspan_idx_4
-#define cspan_idx_3 cspan_idx_4
-#define cspan_idx_4(self, ...) \
- c_PASTE(_cspan_idx, c_NUMARGS(__VA_ARGS__))((self)->shape, (self)->stride, __VA_ARGS__) // small/fast
-#define cspan_idx_5(self, ...) \
- (_cspan_idxN(c_NUMARGS(__VA_ARGS__), (self)->shape, (self)->stride.d, (int32_t[]){__VA_ARGS__}) + \
- c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__))) // general
-#define cspan_idx_6 cspan_idx_5
-
+#define cspan_is_colmajor(self) ((self)->stride.d[0] < (self)->stride.d[cspan_rank(self) - 1])
+#define cspan_is_rowmajor(self) (!cspan_is_colmajor(self))
+#define cspan_get_layout(self) (cspan_is_colmajor(self) ? c_COLMAJOR : c_ROWMAJOR)
#define cspan_at(self, ...) ((self)->data + cspan_index(self, __VA_ARGS__))
#define cspan_front(self) ((self)->data)
#define cspan_back(self) ((self)->data + cspan_size(self) - 1)
+#define cspan_index(self, ...) \
+ (_cspan_index(c_NUMARGS(__VA_ARGS__), (self)->shape, (self)->stride.d, (const int32_t[]){__VA_ARGS__}) + \
+ c_static_assert(cspan_rank(self) == c_NUMARGS(__VA_ARGS__))) // general
-// cspan_subspanN. (N<4) Optimized, same as e.g. cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL});
+// cspan_subspanX: (X <= 3) optimized. Similar to cspan_slice(Span3, &ms3, {off,off+count}, {c_ALL}, {c_ALL});
#define cspan_subspan(self, offset, count) \
- {.data=cspan_at(self, offset), .shape={count}}
+ {.data=cspan_at(self, offset), .shape={count}, .stride=(self)->stride}
#define cspan_subspan2(self, offset, count) \
- {.data=cspan_at(self, offset, 0), .shape={count, (self)->shape[1]}, .stride={(self)->stride}}
+ {.data=cspan_at(self, offset, 0), .shape={count, (self)->shape[1]}, .stride=(self)->stride}
#define cspan_subspan3(self, offset, count) \
- {.data=cspan_at(self, offset, 0, 0), .shape={count, (self)->shape[1], (self)->shape[2]}, .stride={(self)->stride}}
+ {.data=cspan_at(self, offset, 0, 0), .shape={count, (self)->shape[1], (self)->shape[2]}, .stride=(self)->stride}
-// cspan_submdN: reduce rank (N<5) Optimized, same as e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL});
-#define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__)
-#define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__)
+// cspan_submd(): Reduce rank (N <= 4) Optimized, same as e.g. cspan_slice(Span2, &ms4, {x}, {y}, {c_ALL}, {c_ALL});
#define cspan_submd2(self, x) \
- {.data=cspan_at(self, x, 0), .shape={(self)->shape[1]}}
+ {.data=cspan_at(self, x, 0), .shape={(self)->shape[1]}, .stride=(cspan_tuple1){.d={(self)->stride.d[1]}}}
+#define cspan_submd3(...) c_MACRO_OVERLOAD(cspan_submd3, __VA_ARGS__)
#define cspan_submd3_2(self, x) \
{.data=cspan_at(self, x, 0, 0), .shape={(self)->shape[1], (self)->shape[2]}, \
- .stride={.d={0, (self)->stride.d[2]}}}
+ .stride=(cspan_tuple2){.d={(self)->stride.d[1], (self)->stride.d[2]}}}
#define cspan_submd3_3(self, x, y) \
- {.data=cspan_at(self, x, y, 0), .shape={(self)->shape[2]}}
+ {.data=cspan_at(self, x, y, 0), .shape={(self)->shape[2]}, .stride=(cspan_tuple1){.d={(self)->stride.d[2]}}}
+#define cspan_submd4(...) c_MACRO_OVERLOAD(cspan_submd4, __VA_ARGS__)
#define cspan_submd4_2(self, x) \
{.data=cspan_at(self, x, 0, 0, 0), .shape={(self)->shape[1], (self)->shape[2], (self)->shape[3]}, \
- .stride={.d={0, (self)->stride.d[2], (self)->stride.d[3]}}}
+ .stride=(cspan_tuple3){.d={(self)->stride.d[1], (self)->stride.d[2], (self)->stride.d[3]}}}
#define cspan_submd4_3(self, x, y) \
- {.data=cspan_at(self, x, y, 0, 0), .shape={(self)->shape[2], (self)->shape[3]}, .stride={.d={0, (self)->stride.d[3]}}}
+ {.data=cspan_at(self, x, y, 0, 0), .shape={(self)->shape[2], (self)->shape[3]}, \
+ .stride=(cspan_tuple2){.d={(self)->stride.d[2], (self)->stride.d[3]}}}
#define cspan_submd4_4(self, x, y, z) \
- {.data=cspan_at(self, x, y, z, 0), .shape={(self)->shape[3]}}
+ {.data=cspan_at(self, x, y, z, 0), .shape={(self)->shape[3]}, .stride=(cspan_tuple1){.d={(self)->stride.d[3]}}}
+
+#define cspan_md(array, ...) cspan_md_layout(c_ROWMAJOR, array, __VA_ARGS__)
+#define cspan_md_layout(layout, array, ...) \
+ {.data=array, .shape={__VA_ARGS__}, \
+ .stride=*(c_PASTE(cspan_tuple,c_NUMARGS(__VA_ARGS__))*)_cspan_shape2stride(layout, ((intptr_t[]){__VA_ARGS__}), c_NUMARGS(__VA_ARGS__))}
-// private definitions:
+#define cspan_transpose(self) \
+ _cspan_transpose((self)->shape, (self)->stride.d, cspan_rank(self))
+
+// General slicing function;
+#define cspan_slice(OutSpan, parent, ...) \
+ OutSpan##_slice_((parent)->data, (parent)->shape, (parent)->stride.d, cspan_rank(parent) + \
+ c_static_assert(cspan_rank(parent) == sizeof((int32_t[][3]){__VA_ARGS__})/sizeof(int32_t[3])), \
+ (const int32_t[][3]){__VA_ARGS__})
+
+/* ------------------- PRIVAT DEFINITIONS ------------------- */
STC_INLINE intptr_t _cspan_size(const int32_t shape[], int rank) {
intptr_t sz = shape[0];
- while (rank-- > 1) sz *= shape[rank];
+ while (--rank) sz *= shape[rank];
return sz;
}
-STC_INLINE intptr_t _cspan_idx1(const int32_t shape[1], const cspan_idx1 stri, int32_t x)
- { c_ASSERT(c_LTu(x, shape[0])); return x; }
-
-STC_INLINE intptr_t _cspan_idx2(const int32_t shape[2], const cspan_idx2 stri, int32_t x, int32_t y)
- { c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1])); return (intptr_t)stri.d[1]*x + y; }
-
-STC_INLINE intptr_t _cspan_idx3(const int32_t shape[3], const cspan_idx3 stri, int32_t x, int32_t y, int32_t z) {
- c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1]) && c_LTu(z, shape[2]));
- return (intptr_t)stri.d[2]*(stri.d[1]*x + y) + z;
+STC_INLINE void _cspan_transpose(int32_t shape[], intptr_t stride[], int rank) {
+ for (int i = 0; i < --rank; ++i) {
+ c_swap(int32_t, shape + i, shape + rank);
+ c_swap(intptr_t, stride + i, stride + rank);
+ }
}
-STC_INLINE intptr_t _cspan_idx4(const int32_t shape[4], const cspan_idx4 stri, int32_t x, int32_t y,
- int32_t z, int32_t w) {
- c_ASSERT(c_LTu(x, shape[0]) && c_LTu(y, shape[1]) && c_LTu(z, shape[2]) && c_LTu(w, shape[3]));
- return (intptr_t)stri.d[3]*(stri.d[2]*(stri.d[1]*x + y) + z) + w;
+
+STC_INLINE intptr_t _cspan_index(int rank, const int32_t shape[], const intptr_t stride[], const int32_t a[]) {
+ intptr_t off = 0;
+ while (rank--) {
+ c_assert(c_less_unsigned(a[rank], shape[rank]));
+ off += stride[rank]*a[rank];
+ }
+ return off;
}
-STC_API intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stri[], const int32_t a[]);
-STC_API intptr_t _cspan_next2(int rank, int32_t pos[], const int32_t shape[], const int32_t stride[]);
-#define _cspan_next1(r, pos, d, s) (++pos[0], 1)
+#define _cspan_next1(pos, shape, stride, rank, done) (*done = ++pos[0]==shape[0], stride[0])
+STC_API intptr_t
+ _cspan_next2(int32_t pos[], const int32_t shape[], const intptr_t stride[], int rank, int* done);
#define _cspan_next3 _cspan_next2
#define _cspan_next4 _cspan_next2
#define _cspan_next5 _cspan_next2
#define _cspan_next6 _cspan_next2
+#define _cspan_next7 _cspan_next2
+#define _cspan_next8 _cspan_next2
+
+STC_API intptr_t _cspan_slice(int32_t oshape[], intptr_t ostride[], int* orank,
+ const int32_t shape[], const intptr_t stride[],
+ int rank, const int32_t a[][3]);
+
+STC_API intptr_t* _cspan_shape2stride(cspan_layout layout, intptr_t shape[], int rank);
+#endif // STC_CSPAN_H_INCLUDED
-STC_API intptr_t _cspan_slice(int32_t odim[], int32_t ostri[], int* orank,
- const int32_t shape[], const int32_t stri[],
- int rank, const int32_t a[][2]);
+/* --------------------- IMPLEMENTATION --------------------- */
+#if defined(i_implement) || defined(i_static)
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+STC_DEF intptr_t _cspan_next2(int32_t pos[], const int32_t shape[], const intptr_t stride[], int r, int* done) {
+ intptr_t off = stride[--r];
+ ++pos[r];
-STC_DEF intptr_t _cspan_idxN(int rank, const int32_t shape[], const int32_t stri[], const int32_t a[]) {
- intptr_t off = a[0];
- c_ASSERT(c_LTu(a[0], shape[0]));
- for (int i = 1; i < rank; ++i) {
- off *= stri[i];
- off += a[i];
- c_ASSERT(c_LTu(a[i], shape[i]));
+ for (; r && pos[r] == shape[r]; --r) {
+ pos[r] = 0; ++pos[r - 1];
+ off += stride[r - 1] - stride[r]*shape[r];
}
+ *done = pos[r] == shape[r];
return off;
}
-STC_DEF intptr_t _cspan_next2(int rank, int32_t pos[], const int32_t shape[], const int32_t stride[]) {
- intptr_t off = 1, rs = 1;
- ++pos[rank - 1];
- while (--rank && pos[rank] == shape[rank]) {
- pos[rank] = 0, ++pos[rank - 1];
- const intptr_t ds = rs*shape[rank];
- rs *= stride[rank];
- off += rs - ds;
+STC_DEF intptr_t* _cspan_shape2stride(cspan_layout layout, intptr_t stride[], int rank) {
+ int i, inc;
+ if (layout == c_COLMAJOR) i = 0, inc = 1;
+ else i = rank - 1, inc = -1;
+ intptr_t k = 1, s1 = stride[i], s2;
+
+ stride[i] = 1;
+ while (--rank) {
+ i += inc;
+ s2 = stride[i];
+ stride[i] = (k *= s1);
+ s1 = s2;
}
- return off;
+ return stride;
}
-STC_DEF intptr_t _cspan_slice(int32_t odim[], int32_t ostri[], int* orank,
- const int32_t shape[], const int32_t stri[],
- int rank, const int32_t a[][2]) {
+STC_DEF intptr_t _cspan_slice(int32_t oshape[], intptr_t ostride[], int* orank,
+ const int32_t shape[], const intptr_t stride[],
+ int rank, const int32_t a[][3]) {
intptr_t off = 0;
- int i = 0, j = 0;
- int32_t t, s = 1;
+ int i = 0, oi = 0;
+ int32_t end;
+
for (; i < rank; ++i) {
- off *= stri[i];
- off += a[i][0];
- switch (a[i][1]) {
- case 0: s *= stri[i]; c_ASSERT(c_LTu(a[i][0], shape[i])); continue;
- case -1: t = shape[i]; break;
- default: t = a[i][1]; break;
+ off += stride[i]*a[i][0];
+ switch (a[i][1]) {
+ case 0: c_assert(c_less_unsigned(a[i][0], shape[i])); continue;
+ case -1: end = shape[i]; break;
+ default: end = a[i][1];
+ }
+ oshape[oi] = end - a[i][0];
+ ostride[oi] = stride[i];
+ c_assert((oshape[oi] > 0) & !c_less_unsigned(shape[i], end));
+ if (a[i][2]) {
+ ostride[oi] *= a[i][2];
+ oshape[oi] = (oshape[oi] - 1)/a[i][2] + 1;
}
- odim[j] = t - a[i][0];
- ostri[j] = s*stri[i];
- c_ASSERT(c_LTu(0, odim[j]) & !c_LTu(shape[i], t));
- s = 1; ++j;
+ ++oi;
}
- *orank = j;
+ *orank = oi;
return off;
}
-#endif
+
#endif
#undef i_opt
#undef i_header
#undef i_implement
#undef i_static
-#undef i_extern
+#undef i_import
diff --git a/include/stc/csset.h b/include/stc/csset.h
index c14d2a6a..29810c7c 100644
--- a/include/stc/csset.h
+++ b/include/stc/csset.h
@@ -42,8 +42,5 @@ int main(void) {
}
*/
-#ifndef _i_prefix
#define _i_prefix csset_
-#endif
-#define _i_isset
#include "csmap.h"
diff --git a/include/stc/cstack.h b/include/stc/cstack.h
index c2792358..8fb176e1 100644
--- a/include/stc/cstack.h
+++ b/include/stc/cstack.h
@@ -20,85 +20,79 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CSTACK_H_INCLUDED
#define CSTACK_H_INCLUDED
+#include "ccommon.h"
#include <stdlib.h>
#include "forward.h"
#endif // CSTACK_H_INCLUDED
-#ifndef _i_prefix
#define _i_prefix cstack_
-#endif
#include "priv/template.h"
#ifndef i_is_forward
#ifdef i_capacity
#define i_no_clone
- _cx_deftypes(_c_cstack_fixed, _cx_self, i_key, i_capacity);
+ _cx_DEFTYPES(_c_cstack_fixed, _cx_Self, i_key, i_capacity);
#else
- _cx_deftypes(_c_cstack_types, _cx_self, i_key);
+ _cx_DEFTYPES(_c_cstack_types, _cx_Self, i_key);
#endif
#endif
typedef i_keyraw _cx_raw;
-STC_INLINE _cx_self _cx_memb(_init)(void) {
- _cx_self cx; cx._len = 0;
-#ifndef i_capacity
- cx._cap = 0; cx.data = NULL;
-#endif
- return cx;
-}
-
#ifdef i_capacity
-STC_INLINE void _cx_memb(_create)(_cx_self* self)
+STC_INLINE void _cx_MEMB(_init)(_cx_Self* self)
{ self->_len = 0; }
#else
-STC_INLINE void _cx_memb(_create)(_cx_self* self)
- { self->_len = 0; self->_cap = 0; self->data = NULL; }
+STC_INLINE _cx_Self _cx_MEMB(_init)(void) {
+ _cx_Self out = {0};
+ return out;
+}
-STC_INLINE _cx_self _cx_memb(_with_capacity)(intptr_t cap) {
- _cx_self out = {(_cx_value *) i_malloc(cap*c_sizeof(i_key)), 0, cap};
+STC_INLINE _cx_Self _cx_MEMB(_with_capacity)(intptr_t cap) {
+ _cx_Self out = {(_cx_value *) i_malloc(cap*c_sizeof(i_key)), 0, cap};
return out;
}
-STC_INLINE _cx_self _cx_memb(_with_size)(intptr_t size, i_key null) {
- _cx_self out = {(_cx_value *) i_malloc(size*c_sizeof null), size, size};
+STC_INLINE _cx_Self _cx_MEMB(_with_size)(intptr_t size, i_key null) {
+ _cx_Self out = {(_cx_value *) i_malloc(size*c_sizeof null), size, size};
while (size) out.data[--size] = null;
return out;
}
#endif // i_capacity
-STC_INLINE void _cx_memb(_clear)(_cx_self* self) {
+STC_INLINE void _cx_MEMB(_clear)(_cx_Self* self) {
_cx_value *p = self->data + self->_len;
while (p-- != self->data) { i_keydrop(p); }
self->_len = 0;
}
-STC_INLINE void _cx_memb(_drop)(_cx_self* self) {
- _cx_memb(_clear)(self);
+STC_INLINE void _cx_MEMB(_drop)(_cx_Self* self) {
+ _cx_MEMB(_clear)(self);
#ifndef i_capacity
i_free(self->data);
#endif
}
-STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* self)
+
+STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self)
{ return self->_len; }
-STC_INLINE bool _cx_memb(_empty)(const _cx_self* self)
+STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self)
{ return !self->_len; }
-STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* self) {
+STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self) {
#ifndef i_capacity
return self->_cap;
#else
return i_capacity;
#endif
}
-STC_INLINE void _cx_memb(_value_drop)(_cx_value* val)
+STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val)
{ i_keydrop(val); }
-STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, intptr_t n) {
+STC_INLINE bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t n) {
if (n < self->_len) return true;
#ifndef i_capacity
_cx_value *t = (_cx_value *)i_realloc(self->data, n*c_sizeof *t);
@@ -107,86 +101,106 @@ STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, intptr_t n) {
return false;
}
-STC_INLINE _cx_value* _cx_memb(_append_uninit)(_cx_self *self, intptr_t n) {
+STC_INLINE _cx_value* _cx_MEMB(_append_uninit)(_cx_Self *self, intptr_t n) {
intptr_t len = self->_len;
- if (!_cx_memb(_reserve)(self, len + n)) return NULL;
+ if (!_cx_MEMB(_reserve)(self, len*3/2 + n)) return NULL;
self->_len += n;
return self->data + len;
}
-STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self)
- { _cx_memb(_reserve)(self, self->_len); }
+STC_INLINE void _cx_MEMB(_shrink_to_fit)(_cx_Self* self)
+ { _cx_MEMB(_reserve)(self, self->_len); }
-STC_INLINE const _cx_value* _cx_memb(_top)(const _cx_self* self)
+STC_INLINE const _cx_value* _cx_MEMB(_top)(const _cx_Self* self)
{ return &self->data[self->_len - 1]; }
-STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self)
+STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self)
{ return (_cx_value*) &self->data[self->_len - 1]; }
-STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self)
+STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self)
{ return (_cx_value*) &self->data[0]; }
-STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value val) {
- if (self->_len == _cx_memb(_capacity)(self))
- if (!_cx_memb(_reserve)(self, self->_len*3/2 + 4))
+STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, _cx_value val) {
+ if (self->_len == _cx_MEMB(_capacity)(self))
+ if (!_cx_MEMB(_reserve)(self, self->_len*3/2 + 4))
return NULL;
_cx_value* vp = self->data + self->_len++;
*vp = val; return vp;
}
-STC_INLINE void _cx_memb(_pop)(_cx_self* self)
- { assert(!_cx_memb(_empty)(self)); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); }
+STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self)
+ { c_assert(self->_len); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); }
-STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n)
- { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); }
+STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self)
+ { c_assert(self->_len); return self->data[--self->_len]; }
-STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n)
- { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; }
+STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n)
+ { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); }
-STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, intptr_t idx)
- { assert(idx < self->_len); return self->data + idx; }
-STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, intptr_t idx)
- { assert(idx < self->_len); return self->data + idx; }
+STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n)
+ { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; }
+
+STC_INLINE const _cx_value* _cx_MEMB(_at)(const _cx_Self* self, intptr_t idx)
+ { c_assert(idx < self->_len); return self->data + idx; }
+STC_INLINE _cx_value* _cx_MEMB(_at_mut)(_cx_Self* self, intptr_t idx)
+ { c_assert(idx < self->_len); return self->data + idx; }
#if !defined i_no_emplace
-STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
+STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw)
+ { return _cx_MEMB(_push)(self, i_keyfrom(raw)); }
#endif // !i_no_emplace
#if !defined i_no_clone
-STC_INLINE _cx_self _cx_memb(_clone)(_cx_self v) {
- _cx_self out = {(_cx_value *)i_malloc(v._len*c_sizeof(_cx_value)), v._len, v._len};
+STC_INLINE _cx_Self _cx_MEMB(_clone)(_cx_Self v) {
+ _cx_Self out = {(_cx_value *)i_malloc(v._len*c_sizeof(_cx_value)), v._len, v._len};
if (!out.data) out._cap = 0;
else for (intptr_t i = 0; i < v._len; ++v.data)
out.data[i++] = i_keyclone((*v.data));
return out;
}
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) {
+STC_INLINE void _cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) {
if (self->data == other->data) return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(*other);
+ _cx_MEMB(_drop)(self);
+ *self = _cx_MEMB(_clone)(*other);
}
-STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val)
+STC_INLINE i_key _cx_MEMB(_value_clone)(_cx_value val)
{ return i_keyclone(val); }
-STC_INLINE i_keyraw _cx_memb(_value_toraw)(const _cx_value* val)
+STC_INLINE i_keyraw _cx_MEMB(_value_toraw)(const _cx_value* val)
{ return i_keyto(val); }
#endif // !i_no_clone
-STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) {
+STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) {
return c_LITERAL(_cx_iter){self->_len ? (_cx_value*)self->data : NULL,
- (_cx_value*)self->data + self->_len};
+ (_cx_value*)self->data + self->_len};
}
-STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
+STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self)
{ return c_LITERAL(_cx_iter){NULL, (_cx_value*)self->data + self->_len}; }
-STC_INLINE void _cx_memb(_next)(_cx_iter* it)
+STC_INLINE void _cx_MEMB(_next)(_cx_iter* it)
{ if (++it->ref == it->end) it->ref = NULL; }
-STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n)
+STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n)
{ if ((it.ref += n) >= it.end) it.ref = NULL ; return it; }
+STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it)
+ { return (it.ref - self->data); }
+
+STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n)
+ { self->_len += n; }
+
+#if defined _i_has_eq || defined _i_has_cmp
+STC_INLINE bool
+_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ if (self->_len != other->_len) return false;
+ for (intptr_t i = 0; i < self->_len; ++i) {
+ const _cx_raw _rx = i_keyto(self->data+i), _ry = i_keyto(other->data+i);
+ if (!(i_eq((&_rx), (&_ry)))) return false;
+ }
+ return true;
+}
+#endif
#include "priv/template2.h"
diff --git a/include/stc/cstr.h b/include/stc/cstr.h
index eea16bc4..5a6465ff 100644
--- a/include/stc/cstr.h
+++ b/include/stc/cstr.h
@@ -24,15 +24,13 @@
/* A string type with short string optimization in C99 with good small-string
* optimization (22 characters with 24 bytes string).
*/
+#define i_header // external linkage by default. override with i_static.
+#define _i_inc_utf8
+#include "utf8.h"
+
#ifndef CSTR_H_INCLUDED
#define CSTR_H_INCLUDED
-#if defined i_extern || defined STC_EXTERN
-# define _i_extern
-#endif
-#include "ccommon.h"
-#include "forward.h"
-#include "utf8.h"
#include <stdlib.h> /* malloc */
#include <stdarg.h>
#include <stdio.h> /* vsnprintf */
@@ -70,15 +68,17 @@ STC_API char* _cstr_internal_move(cstr* self, intptr_t pos1, intptr_t pos2);
/**************************** PUBLIC API **********************************/
#define cstr_lit(literal) cstr_from_n(literal, c_litstrlen(literal))
-#define cstr_NULL (c_LITERAL(cstr){{{0}, 0}})
+#define cstr_null (c_LITERAL(cstr){0})
#define cstr_toraw(self) cstr_str(self)
STC_API char* cstr_reserve(cstr* self, intptr_t cap);
STC_API void cstr_shrink_to_fit(cstr* self);
STC_API char* cstr_resize(cstr* self, intptr_t size, char value);
STC_API intptr_t cstr_find_at(const cstr* self, intptr_t pos, const char* search);
+STC_API intptr_t cstr_find_sv(const cstr* self, csview search);
STC_API char* cstr_assign_n(cstr* self, const char* str, intptr_t len);
STC_API char* cstr_append_n(cstr* self, const char* str, intptr_t len);
+STC_API char* cstr_append_uninit(cstr *self, intptr_t len);
STC_API bool cstr_getdelim(cstr *self, int delim, FILE *fp);
STC_API void cstr_erase(cstr* self, intptr_t pos, intptr_t len);
STC_API void cstr_u8_erase(cstr* self, intptr_t bytepos, intptr_t u8len);
@@ -90,6 +90,7 @@ STC_API cstr cstr_from_vfmt(const char* fmt, va_list args);
STC_API intptr_t cstr_append_fmt(cstr* self, const char* fmt, ...);
STC_API intptr_t cstr_printf(cstr* self, const char* fmt, ...);
STC_API cstr cstr_replace_sv(csview sv, csview search, csview repl, int32_t count);
+STC_API uint64_t cstr_hash(const cstr *self);
STC_INLINE cstr_buf cstr_buffer(cstr* s) {
return cstr_is_long(s)
@@ -97,12 +98,14 @@ STC_INLINE cstr_buf cstr_buffer(cstr* s) {
: c_LITERAL(cstr_buf){s->sml.data, cstr_s_size(s), cstr_s_cap};
}
STC_INLINE csview cstr_sv(const cstr* s) {
- return cstr_is_long(s) ? c_LITERAL(csview){s->lon.data, cstr_l_size(s)}
- : c_LITERAL(csview){s->sml.data, cstr_s_size(s)};
+ return cstr_is_long(s) ? c_sv_2(s->lon.data, cstr_l_size(s))
+ : c_sv_2(s->sml.data, cstr_s_size(s));
}
+STC_INLINE crawstr cstr_rs(const cstr* s)
+ { csview sv = cstr_sv(s); return c_rs_2(sv.buf, sv.size); }
STC_INLINE cstr cstr_init(void)
- { return cstr_NULL; }
+ { return cstr_null; }
STC_INLINE cstr cstr_from_n(const char* str, const intptr_t len) {
cstr s;
@@ -114,7 +117,10 @@ STC_INLINE cstr cstr_from(const char* str)
{ return cstr_from_n(str, c_strlen(str)); }
STC_INLINE cstr cstr_from_sv(csview sv)
- { return cstr_from_n(sv.str, sv.size); }
+ { return cstr_from_n(sv.buf, sv.size); }
+
+STC_INLINE cstr cstr_from_rs(crawstr rs)
+ { return cstr_from_n(rs.str, rs.size); }
STC_INLINE cstr cstr_with_size(const intptr_t size, const char value) {
cstr s;
@@ -137,13 +143,13 @@ STC_INLINE cstr* cstr_take(cstr* self, const cstr s) {
STC_INLINE cstr cstr_move(cstr* self) {
cstr tmp = *self;
- *self = cstr_NULL;
+ *self = cstr_null;
return tmp;
}
STC_INLINE cstr cstr_clone(cstr s) {
csview sv = cstr_sv(&s);
- return cstr_from_n(sv.str, sv.size);
+ return cstr_from_n(sv.buf, sv.size);
}
STC_INLINE void cstr_drop(cstr* self) {
@@ -173,33 +179,16 @@ STC_INLINE intptr_t cstr_capacity(const cstr* self)
// utf8 methods defined in/depending on src/utf8code.c:
-extern cstr cstr_tocase(csview sv, int k);
-
-STC_INLINE cstr cstr_casefold_sv(csview sv)
- { return cstr_tocase(sv, 0); }
-
-STC_INLINE cstr cstr_tolower_sv(csview sv)
- { return cstr_tocase(sv, 1); }
-
-STC_INLINE cstr cstr_toupper_sv(csview sv)
- { return cstr_tocase(sv, 2); }
-
-STC_INLINE cstr cstr_tolower(const char* str)
- { return cstr_tolower_sv(c_sv(str, c_strlen(str))); }
-
-STC_INLINE cstr cstr_toupper(const char* str)
- { return cstr_toupper_sv(c_sv(str, c_strlen(str))); }
-
-STC_INLINE void cstr_lowercase(cstr* self)
- { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); }
-
-STC_INLINE void cstr_uppercase(cstr* self)
- { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); }
-
-STC_INLINE bool cstr_valid_utf8(const cstr* self)
- { return utf8_valid(cstr_str(self)); }
+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
+// utf8 functions not depending on src/utf8code.c:
STC_INLINE intptr_t cstr_u8_size(const cstr* self)
{ return utf8_size(cstr_str(self)); }
@@ -216,8 +205,8 @@ STC_INLINE const char* cstr_u8_at(const cstr* self, intptr_t u8idx)
STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) {
const char* str = cstr_str(self);
csview sv;
- sv.str = utf8_at(str, u8idx);
- sv.size = utf8_chr_size(sv.str);
+ sv.buf = utf8_at(str, u8idx);
+ sv.size = utf8_chr_size(sv.buf);
return sv;
}
@@ -225,22 +214,22 @@ STC_INLINE csview cstr_u8_chr(const cstr* self, intptr_t u8idx) {
STC_INLINE cstr_iter cstr_begin(const cstr* self) {
csview sv = cstr_sv(self);
- if (!sv.size) return c_LITERAL(cstr_iter){NULL};
- return c_LITERAL(cstr_iter){.u8 = {{sv.str, utf8_chr_size(sv.str)}}};
+ if (!sv.size) return c_LITERAL(cstr_iter){.ref = NULL};
+ return c_LITERAL(cstr_iter){.u8 = {{sv.buf, utf8_chr_size(sv.buf)}}};
}
STC_INLINE cstr_iter cstr_end(const cstr* self) {
(void)self; return c_LITERAL(cstr_iter){NULL};
}
STC_INLINE void cstr_next(cstr_iter* it) {
- it->ref += it->u8.chr.size;
- it->u8.chr.size = utf8_chr_size(it->ref);
+ it->ref += it->chr.size;
+ it->chr.size = utf8_chr_size(it->ref);
if (!*it->ref) it->ref = NULL;
}
STC_INLINE cstr_iter cstr_advance(cstr_iter it, intptr_t pos) {
int inc = -1;
if (pos > 0) pos = -pos, inc = 1;
while (pos && *it.ref) pos += (*(it.ref += inc) & 0xC0) != 0x80;
- it.u8.chr.size = utf8_chr_size(it.ref);
+ it.chr.size = utf8_chr_size(it.ref);
if (!*it.ref) it.ref = NULL;
return it;
}
@@ -249,14 +238,6 @@ STC_INLINE cstr_iter cstr_advance(cstr_iter it, intptr_t pos) {
STC_INLINE void cstr_clear(cstr* self)
{ _cstr_set_size(self, 0); }
-STC_INLINE char* cstr_append_uninit(cstr *self, intptr_t len) {
- intptr_t sz = cstr_size(self);
- char* d = cstr_reserve(self, sz + len);
- if (!d) return NULL;
- _cstr_set_size(self, sz + len);
- return d + sz;
-}
-
STC_INLINE int cstr_cmp(const cstr* s1, const cstr* s2)
{ return strcmp(cstr_str(s1), cstr_str(s2)); }
@@ -265,7 +246,7 @@ STC_INLINE int cstr_icmp(const cstr* s1, const cstr* s2)
STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) {
csview x = cstr_sv(s1), y = cstr_sv(s2);
- return x.size == y.size && !c_memcmp(x.str, y.str, x.size);
+ return x.size == y.size && !c_memcmp(x.buf, y.buf, x.size);
}
@@ -273,7 +254,7 @@ STC_INLINE bool cstr_equals(const cstr* self, const char* str)
{ return !strcmp(cstr_str(self), str); }
STC_INLINE bool cstr_equals_sv(const cstr* self, csview sv)
- { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.str, sv.size); }
+ { return sv.size == cstr_size(self) && !c_memcmp(cstr_str(self), sv.buf, sv.size); }
STC_INLINE bool cstr_equals_s(const cstr* self, cstr s)
{ return !cstr_cmp(self, &s); }
@@ -287,8 +268,6 @@ STC_INLINE intptr_t cstr_find(const cstr* self, const char* search) {
return res ? (res - str) : c_NPOS;
}
-STC_API intptr_t cstr_find_sv(const cstr* self, csview search);
-
STC_INLINE intptr_t cstr_find_s(const cstr* self, cstr search)
{ return cstr_find(self, cstr_str(&search)); }
@@ -305,7 +284,7 @@ STC_INLINE bool cstr_contains_s(const cstr* self, cstr search)
STC_INLINE bool cstr_starts_with_sv(const cstr* self, csview sub) {
if (sub.size > cstr_size(self)) return false;
- return !c_memcmp(cstr_str(self), sub.str, sub.size);
+ return !c_memcmp(cstr_str(self), sub.buf, sub.size);
}
STC_INLINE bool cstr_starts_with(const cstr* self, const char* sub) {
@@ -327,7 +306,7 @@ STC_INLINE bool cstr_istarts_with(const cstr* self, const char* sub) {
STC_INLINE bool cstr_ends_with_sv(const cstr* self, csview sub) {
csview sv = cstr_sv(self);
if (sub.size > sv.size) return false;
- return !c_memcmp(sv.str + sv.size - sub.size, sub.str, sub.size);
+ return !c_memcmp(sv.buf + sv.size - sub.size, sub.buf, sub.size);
}
STC_INLINE bool cstr_ends_with_s(const cstr* self, cstr sub)
@@ -339,7 +318,7 @@ STC_INLINE bool cstr_ends_with(const cstr* self, const char* sub)
STC_INLINE bool cstr_iends_with(const cstr* self, const char* sub) {
csview sv = cstr_sv(self);
intptr_t n = c_strlen(sub);
- return n <= sv.size && !utf8_icmp(sv.str + sv.size - n, sub);
+ return n <= sv.size && !utf8_icmp(sv.buf + sv.size - n, sub);
}
@@ -347,11 +326,11 @@ STC_INLINE char* cstr_assign(cstr* self, const char* str)
{ return cstr_assign_n(self, str, c_strlen(str)); }
STC_INLINE char* cstr_assign_sv(cstr* self, csview sv)
- { return cstr_assign_n(self, sv.str, sv.size); }
+ { return cstr_assign_n(self, sv.buf, sv.size); }
STC_INLINE char* cstr_copy(cstr* self, cstr s) {
csview sv = cstr_sv(&s);
- return cstr_assign_n(self, sv.str, sv.size);
+ return cstr_assign_n(self, sv.buf, sv.size);
}
@@ -360,21 +339,19 @@ STC_INLINE char* cstr_push(cstr* self, const char* chr)
STC_INLINE void cstr_pop(cstr* self) {
csview sv = cstr_sv(self);
- const char* s = sv.str + sv.size;
+ const char* s = sv.buf + sv.size;
while ((*--s & 0xC0) == 0x80) ;
- _cstr_set_size(self, (s - sv.str));
+ _cstr_set_size(self, (s - sv.buf));
}
STC_INLINE char* cstr_append(cstr* self, const char* str)
{ return cstr_append_n(self, str, c_strlen(str)); }
-STC_INLINE void cstr_append_sv(cstr* self, csview sv)
- { cstr_append_n(self, sv.str, sv.size); }
+STC_INLINE char* cstr_append_sv(cstr* self, csview sv)
+ { return cstr_append_n(self, sv.buf, sv.size); }
-STC_INLINE char* cstr_append_s(cstr* self, cstr s) {
- csview sv = cstr_sv(&s);
- return cstr_append_n(self, sv.str, sv.size);
-}
+STC_INLINE char* cstr_append_s(cstr* self, cstr s)
+ { return cstr_append_sv(self, cstr_sv(&s)); }
#define cstr_replace(...) c_MACRO_OVERLOAD(cstr_replace, __VA_ARGS__)
#define cstr_replace_3(self, search, repl) cstr_replace_4(self, search, repl, INT32_MAX)
@@ -385,7 +362,7 @@ STC_INLINE void cstr_replace_4(cstr* self, const char* search, const char* repl,
STC_INLINE void cstr_replace_at_sv(cstr* self, intptr_t pos, intptr_t len, const csview repl) {
char* d = _cstr_internal_move(self, pos + len, pos + repl.size);
- c_memcpy(d + pos, repl.str, repl.size);
+ c_memcpy(d + pos, repl.buf, repl.size);
}
STC_INLINE void cstr_replace_at(cstr* self, intptr_t pos, intptr_t len, const char* repl)
@@ -404,18 +381,18 @@ STC_INLINE void cstr_insert(cstr* self, intptr_t pos, const char* str)
STC_INLINE void cstr_insert_sv(cstr* self, intptr_t pos, csview sv)
{ cstr_replace_at_sv(self, pos, 0, sv); }
-STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s) {
- csview sv = cstr_sv(&s);
- cstr_replace_at_sv(self, pos, 0, sv);
-}
-
+STC_INLINE void cstr_insert_s(cstr* self, intptr_t pos, cstr s)
+ { cstr_replace_at_sv(self, pos, 0, cstr_sv(&s)); }
STC_INLINE bool cstr_getline(cstr *self, FILE *fp)
{ return cstr_getdelim(self, '\n', fp); }
-STC_API uint64_t cstr_hash(const cstr *self);
+#endif // CSTR_H_INCLUDED
+
+/* -------------------------- UTF8 CASE CONVERSION ------------------------- */
+#if defined(i_import) && !defined(CSTR_X_INCLUDED)
+#define CSTR_X_INCLUDED
-#ifdef _i_extern
static struct {
int (*conv_asc)(int);
uint32_t (*conv_utf)(uint32_t);
@@ -424,15 +401,15 @@ fn_tocase[] = {{tolower, utf8_casefold},
{tolower, utf8_tolower},
{toupper, utf8_toupper}};
-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;
+ const char *end = sv.buf + sv.size;
uint32_t cp; intptr_t sz = 0;
utf8_decode_t d = {.state=0};
- while (sv.str < end) {
- do { utf8_decode(&d, (uint8_t)*sv.str++); } while (d.state);
+ while (sv.buf < end) {
+ do { utf8_decode(&d, (uint8_t)*sv.buf++); } while (d.state);
if (d.codep < 128)
buf[sz++] = (char)fn_tocase[k].conv_asc((int)d.codep);
else {
@@ -444,20 +421,46 @@ cstr cstr_tocase(csview sv, int k) {
cstr_shrink_to_fit(&out);
return out;
}
-#endif
+
+cstr cstr_casefold_sv(csview sv)
+ { return cstr_tocase(sv, 0); }
+
+cstr cstr_tolower_sv(csview sv)
+ { return cstr_tocase(sv, 1); }
+
+cstr cstr_toupper_sv(csview sv)
+ { return cstr_tocase(sv, 2); }
+
+cstr cstr_tolower(const char* str)
+ { return cstr_tolower_sv(c_sv(str, c_strlen(str))); }
+
+cstr cstr_toupper(const char* str)
+ { return cstr_toupper_sv(c_sv(str, c_strlen(str))); }
+
+void cstr_lowercase(cstr* self)
+ { cstr_take(self, cstr_tolower_sv(cstr_sv(self))); }
+
+void cstr_uppercase(cstr* self)
+ { cstr_take(self, cstr_toupper_sv(cstr_sv(self))); }
+
+bool cstr_valid_utf8(const cstr* self)
+ { return utf8_valid(cstr_str(self)); }
+#endif // i_import
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+#if defined i_implement || defined i_static
+#ifndef CSTR_C_INCLUDED
+#define CSTR_C_INCLUDED
STC_DEF uint64_t cstr_hash(const cstr *self) {
csview sv = cstr_sv(self);
- return cfasthash(sv.str, sv.size);
+ return stc_hash(sv.buf, sv.size);
}
STC_DEF intptr_t cstr_find_sv(const cstr* self, csview search) {
csview sv = cstr_sv(self);
- char* res = cstrnstrn(sv.str, search.str, sv.size, search.size);
- return res ? (res - sv.str) : c_NPOS;
+ char* res = stc_strnstrn(sv.buf, sv.size, search.buf, search.size);
+ return res ? (res - sv.buf) : c_NPOS;
}
STC_DEF char* _cstr_internal_move(cstr* self, const intptr_t pos1, const intptr_t pos2) {
@@ -509,7 +512,8 @@ STC_DEF char* cstr_reserve(cstr* self, const intptr_t cap) {
if (cap > cstr_s_cap) {
char* data = (char *)c_malloc(cap + 1);
const intptr_t len = cstr_s_size(self);
- c_memcpy(data, self->sml.data, cstr_s_cap + 1);
+ /* copy full short buffer to emulate realloc() */
+ c_memcpy(data, self->sml.data, c_sizeof self->sml);
self->lon.data = data;
self->lon.size = (size_t)len;
cstr_l_set_cap(self, cap);
@@ -532,8 +536,8 @@ STC_DEF char* cstr_resize(cstr* self, const intptr_t size, const char value) {
STC_DEF intptr_t cstr_find_at(const cstr* self, const intptr_t pos, const char* search) {
csview sv = cstr_sv(self);
if (pos > sv.size) return c_NPOS;
- const char* res = strstr((char*)sv.str + pos, search);
- return res ? (res - sv.str) : c_NPOS;
+ const char* res = strstr((char*)sv.buf + pos, search);
+ return res ? (res - sv.buf) : c_NPOS;
}
STC_DEF char* cstr_assign_n(cstr* self, const char* str, const intptr_t len) {
@@ -555,6 +559,14 @@ STC_DEF char* cstr_append_n(cstr* self, const char* str, const intptr_t len) {
return r.data;
}
+STC_DEF char* cstr_append_uninit(cstr *self, intptr_t len) {
+ cstr_buf r = cstr_buffer(self);
+ if (r.size + len > r.cap && !(r.data = cstr_reserve(self, r.size*3/2 + len)))
+ return NULL;
+ _cstr_set_size(self, r.size + len);
+ return r.data + r.size;
+}
+
STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) {
int c = fgetc(fp);
if (c == EOF)
@@ -575,19 +587,18 @@ STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) {
}
}
-STC_DEF cstr
-cstr_replace_sv(csview in, csview search, csview repl, int32_t count) {
- cstr out = cstr_NULL;
+STC_DEF cstr cstr_replace_sv(csview in, csview search, csview repl, int32_t count) {
+ cstr out = cstr_null;
intptr_t from = 0; char* res;
if (!count) count = INT32_MAX;
if (search.size)
- while (count-- && (res = cstrnstrn(in.str + from, search.str, in.size - from, search.size))) {
- const intptr_t pos = (res - in.str);
- cstr_append_n(&out, in.str + from, pos - from);
- cstr_append_n(&out, repl.str, repl.size);
+ while (count-- && (res = stc_strnstrn(in.buf + from, in.size - from, search.buf, search.size))) {
+ const intptr_t pos = (res - in.buf);
+ cstr_append_n(&out, in.buf + from, pos - from);
+ cstr_append_n(&out, repl.buf, repl.size);
from = pos + search.size;
}
- cstr_append_n(&out, in.str + from, in.size - from);
+ cstr_append_n(&out, in.buf + from, in.size - from);
return out;
}
@@ -629,7 +640,7 @@ STC_DEF intptr_t cstr_vfmt(cstr* self, intptr_t start, const char* fmt, va_list
#endif
STC_DEF cstr cstr_from_fmt(const char* fmt, ...) {
- cstr s = cstr_NULL;
+ cstr s = cstr_null;
va_list args;
va_start(args, fmt);
cstr_vfmt(&s, 0, fmt, args);
@@ -663,14 +674,14 @@ STC_DEF intptr_t cstr_printf(cstr* self, const char* fmt, ...) {
va_end(args);
return n;
}
-
+#endif // CSTR_C_INCLUDED
#endif // i_implement
+
#if defined __GNUC__ && !defined __clang__
# pragma GCC diagnostic pop
#endif
-#endif // CSTR_H_INCLUDED
#undef i_opt
#undef i_header
#undef i_static
#undef i_implement
-#undef _i_extern
+#undef i_import
diff --git a/include/stc/csview.h b/include/stc/csview.h
index bba3aea3..11e42c97 100644
--- a/include/stc/csview.h
+++ b/include/stc/csview.h
@@ -20,109 +20,117 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#define i_header // external linkage by default. override with i_static.
+#define _i_inc_utf8
+#include "utf8.h"
+
#ifndef CSVIEW_H_INCLUDED
#define CSVIEW_H_INCLUDED
-#include "ccommon.h"
-#include "forward.h"
-#include "utf8.h"
-
-#define csview_NULL c_sv_1("")
-#define csview_init() csview_NULL
+#define csview_init() c_sv_1("")
#define csview_drop(p) c_default_drop(p)
#define csview_clone(sv) c_default_clone(sv)
-#define csview_lit(literal) c_sv_1(literal)
#define csview_from_n(str, n) c_sv_2(str, n)
-STC_API intptr_t csview_find_sv(csview sv, csview search);
+STC_API csview_iter csview_advance(csview_iter it, intptr_t pos);
+STC_API intptr_t csview_find_sv(csview sv, csview search);
+STC_API uint64_t csview_hash(const csview *self);
+STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2);
+STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n);
+STC_API csview csview_token(csview sv, const char* sep, intptr_t* start);
STC_INLINE csview csview_from(const char* str)
- { return c_LITERAL(csview){str, c_strlen(str)}; }
-STC_INLINE void csview_clear(csview* self) { *self = csview_NULL; }
-
-STC_INLINE intptr_t csview_size(csview sv) { return sv.size; }
+ { return c_LITERAL(csview){str, c_strlen(str)}; }
+STC_INLINE void csview_clear(csview* self) { *self = csview_init(); }
+STC_INLINE intptr_t csview_size(csview sv) { return sv.size; }
STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; }
+STC_INLINE bool csview_equals_sv(csview sv1, csview sv2)
+ { return sv1.size == sv2.size && !c_memcmp(sv1.buf, sv2.buf, sv1.size); }
+
STC_INLINE bool csview_equals(csview sv, const char* str)
- { intptr_t n = c_strlen(str); return sv.size == n && !c_memcmp(sv.str, str, n); }
+ { return csview_equals_sv(sv, c_sv_2(str, c_strlen(str))); }
STC_INLINE intptr_t csview_find(csview sv, const char* str)
- { return csview_find_sv(sv, c_sv(str, c_strlen(str))); }
+ { return csview_find_sv(sv, c_sv_2(str, c_strlen(str))); }
STC_INLINE bool csview_contains(csview sv, const char* str)
{ return csview_find(sv, str) != c_NPOS; }
STC_INLINE bool csview_starts_with(csview sv, const char* str) {
intptr_t n = c_strlen(str);
- return n > sv.size ? false : !c_memcmp(sv.str, str, n);
+ return n > sv.size ? false : !c_memcmp(sv.buf, str, n);
}
STC_INLINE bool csview_ends_with(csview sv, const char* str) {
intptr_t n = c_strlen(str);
- return n > sv.size ? false : !c_memcmp(sv.str + sv.size - n, str, n);
+ return n > sv.size ? false : !c_memcmp(sv.buf + sv.size - n, str, n);
}
STC_INLINE csview csview_substr(csview sv, intptr_t pos, intptr_t n) {
if (pos + n > sv.size) n = sv.size - pos;
- sv.str += pos, sv.size = n;
+ sv.buf += pos, sv.size = n;
return sv;
}
STC_INLINE csview csview_slice(csview sv, intptr_t p1, intptr_t p2) {
if (p2 > sv.size) p2 = sv.size;
- sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0;
+ sv.buf += p1, sv.size = p2 > p1 ? p2 - p1 : 0;
return sv;
}
/* utf8 iterator */
STC_INLINE csview_iter csview_begin(const csview* self) {
if (!self->size) return c_LITERAL(csview_iter){NULL};
- return c_LITERAL(csview_iter){.u8 = {{self->str, utf8_chr_size(self->str)},
- self->str + self->size}};
+ return c_LITERAL(csview_iter){.u8 = {{self->buf, utf8_chr_size(self->buf)},
+ self->buf + self->size}};
}
STC_INLINE csview_iter csview_end(const csview* self) {
- return c_LITERAL(csview_iter){.u8 = {{NULL}, self->str + self->size}};
+ return c_LITERAL(csview_iter){.u8 = {{NULL}, self->buf + self->size}};
}
STC_INLINE void csview_next(csview_iter* it) {
- it->ref += it->u8.chr.size;
- it->u8.chr.size = utf8_chr_size(it->ref);
+ it->ref += it->chr.size;
+ it->chr.size = utf8_chr_size(it->ref);
if (it->ref == it->u8.end) it->ref = NULL;
}
-STC_INLINE csview_iter csview_advance(csview_iter it, intptr_t pos) {
- int inc = -1;
- if (pos > 0) pos = -pos, inc = 1;
- while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80;
- it.u8.chr.size = utf8_chr_size(it.ref);
- if (it.ref == it.u8.end) it.ref = NULL;
- return it;
-}
-
/* utf8 */
STC_INLINE intptr_t csview_u8_size(csview sv)
- { return utf8_size_n(sv.str, sv.size); }
+ { return utf8_size_n(sv.buf, sv.size); }
STC_INLINE csview csview_u8_substr(csview sv, intptr_t bytepos, intptr_t u8len) {
- sv.str += bytepos;
- sv.size = utf8_pos(sv.str, u8len);
+ sv.buf += bytepos;
+ sv.size = utf8_pos(sv.buf, u8len);
return sv;
}
STC_INLINE bool csview_valid_utf8(csview sv) // depends on src/utf8code.c
- { return utf8_valid_n(sv.str, sv.size); }
-
-STC_API csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n);
-STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2);
-STC_API csview csview_token(csview sv, const char* sep, intptr_t* start);
+ { return utf8_valid_n(sv.buf, sv.size); }
#define c_fortoken_sv(it, inputsv, sep) \
for (struct { csview _inp, token, *ref; const char *_sep; intptr_t pos; } \
it = {._inp=inputsv, .token=it._inp, .ref=&it.token, ._sep=sep} \
- ; it.pos <= it._inp.size && (it.token = csview_token(it._inp, it._sep, &it.pos)).str ; )
+ ; it.pos <= it._inp.size && (it.token = csview_token(it._inp, it._sep, &it.pos)).buf ; )
#define c_fortoken(it, input, sep) \
c_fortoken_sv(it, csview_from(input), sep)
+/* ---- Container helper functions ---- */
+
+STC_INLINE int csview_cmp(const csview* x, const csview* y) {
+ intptr_t n = x->size < y->size ? x->size : y->size;
+ int c = c_memcmp(x->buf, y->buf, n);
+ return c ? c : (int)(x->size - y->size);
+}
+
+STC_INLINE int csview_icmp(const csview* x, const csview* y)
+ { return utf8_icmp_sv(*x, *y); }
+
+STC_INLINE bool csview_eq(const csview* x, const csview* y)
+ { return x->size == y->size && !c_memcmp(x->buf, y->buf, x->size); }
+
+#endif // CSVIEW_H_INCLUDED
+
/* csview interaction with cstr: */
#ifdef CSTR_H_INCLUDED
@@ -140,34 +148,29 @@ STC_INLINE csview cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2)
STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u8len)
{ return csview_u8_substr(cstr_sv(self), bytepos, u8len); }
-
#endif
-/* ---- Container helper functions ---- */
-
-STC_INLINE int csview_cmp(const csview* x, const csview* y) {
- intptr_t n = x->size < y->size ? x->size : y->size;
- int c = c_memcmp(x->str, y->str, n);
- return c ? c : (int)(x->size - y->size);
-}
-
-STC_INLINE int csview_icmp(const csview* x, const csview* y)
- { return utf8_icmp_sv(*x, *y); }
-
-STC_INLINE bool csview_eq(const csview* x, const csview* y)
- { return x->size == y->size && !c_memcmp(x->str, y->str, x->size); }
-
-STC_API uint64_t csview_hash(const csview *self);
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+#if defined i_implement || defined i_static
+#ifndef CSVIEW_C_INCLUDED
+#define CSVIEW_C_INCLUDED
+
+STC_DEF csview_iter csview_advance(csview_iter it, intptr_t pos) {
+ int inc = -1;
+ if (pos > 0) pos = -pos, inc = 1;
+ while (pos && it.ref != it.u8.end) pos += (*(it.ref += inc) & 0xC0) != 0x80;
+ it.chr.size = utf8_chr_size(it.ref);
+ if (it.ref == it.u8.end) it.ref = NULL;
+ return it;
+}
STC_DEF intptr_t csview_find_sv(csview sv, csview search) {
- char* res = cstrnstrn(sv.str, search.str, sv.size, search.size);
- return res ? (res - sv.str) : c_NPOS;
+ char* res = stc_strnstrn(sv.buf, sv.size, search.buf, search.size);
+ return res ? (res - sv.buf) : c_NPOS;
}
STC_DEF uint64_t csview_hash(const csview *self)
- { return cfasthash(self->str, self->size); }
+ { return stc_hash(self->buf, self->size); }
STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) {
if (pos < 0) {
@@ -176,7 +179,7 @@ STC_DEF csview csview_substr_ex(csview sv, intptr_t pos, intptr_t n) {
}
if (pos > sv.size) pos = sv.size;
if (pos + n > sv.size) n = sv.size - pos;
- sv.str += pos, sv.size = n;
+ sv.buf += pos, sv.size = n;
return sv;
}
@@ -187,23 +190,22 @@ STC_DEF csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) {
}
if (p2 < 0) p2 += sv.size;
if (p2 > sv.size) p2 = sv.size;
- sv.str += p1, sv.size = (p2 > p1 ? p2 - p1 : 0);
+ sv.buf += p1, sv.size = (p2 > p1 ? p2 - p1 : 0);
return sv;
}
STC_DEF csview csview_token(csview sv, const char* sep, intptr_t* start) {
intptr_t sep_size = c_strlen(sep);
- csview slice = {sv.str + *start, sv.size - *start};
- const char* res = cstrnstrn(slice.str, sep, slice.size, sep_size);
- csview tok = {slice.str, res ? (res - slice.str) : slice.size};
+ csview slice = {sv.buf + *start, sv.size - *start};
+ const char* res = stc_strnstrn(slice.buf, slice.size, sep, sep_size);
+ csview tok = {slice.buf, res ? (res - slice.buf) : slice.size};
*start += tok.size + sep_size;
return tok;
}
-
-#endif
-#endif
-#undef i_opt
+#endif // CSVIEW_C_INCLUDED
+#endif // i_implement
+#undef i_static
#undef i_header
#undef i_implement
-#undef i_static
-#undef i_extern
+#undef i_import
+#undef i_opt
diff --git a/include/stc/cvec.h b/include/stc/cvec.h
index a1aa74b2..12cd6875 100644
--- a/include/stc/cvec.h
+++ b/include/stc/cvec.h
@@ -22,6 +22,7 @@
*/
/*
+#define i_implement
#include <stc/cstr.h>
#include <stc/forward.h>
@@ -39,11 +40,11 @@ struct MyStruct {
#include <stc/cvec.h>
#define i_key int
-#define i_is_forward // forward declared
+#define i_is_forward
#define i_tag i32
#include <stc/cvec.h>
-int main() {
+int main(void) {
cvec_i32 vec = {0};
cvec_i32_push(&vec, 123);
cvec_i32_drop(&vec);
@@ -57,9 +58,10 @@ int main() {
cvec_str_drop(&svec);
}
*/
-#include "ccommon.h"
+#include "priv/linkage.h"
#ifndef CVEC_H_INCLUDED
+#include "ccommon.h"
#include "forward.h"
#include <stdlib.h>
#include <string.h>
@@ -68,173 +70,172 @@ int main() {
#define _it_ptr(it) (it.ref ? it.ref : it.end)
#endif // CVEC_H_INCLUDED
-#ifndef _i_prefix
#define _i_prefix cvec_
-#endif
#include "priv/template.h"
#ifndef i_is_forward
- _cx_deftypes(_c_cvec_types, _cx_self, i_key);
+ _cx_DEFTYPES(_c_cvec_types, _cx_Self, i_key);
#endif
typedef i_keyraw _cx_raw;
-STC_API _cx_self _cx_memb(_init)(void);
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API void _cx_memb(_clear)(_cx_self* self);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, intptr_t cap);
-STC_API bool _cx_memb(_resize)(_cx_self* self, intptr_t size, i_key null);
-STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value);
-STC_API _cx_iter _cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2);
-STC_API _cx_iter _cx_memb(_insert_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
-STC_API _cx_iter _cx_memb(_insert_uninit)(_cx_self* self, _cx_value* pos, const intptr_t n);
-#if !defined i_no_cmp || defined _i_has_eq
-STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw);
+STC_API _cx_Self _cx_MEMB(_init)(void);
+STC_API void _cx_MEMB(_drop)(_cx_Self* self);
+STC_API void _cx_MEMB(_clear)(_cx_Self* self);
+STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t cap);
+STC_API bool _cx_MEMB(_resize)(_cx_Self* self, intptr_t size, i_key null);
+STC_API _cx_iter _cx_MEMB(_erase_n)(_cx_Self* self, intptr_t idx, intptr_t n);
+STC_API _cx_iter _cx_MEMB(_insert_uninit)(_cx_Self* self, intptr_t idx, intptr_t n);
+#if defined _i_has_eq || defined _i_has_cmp
+STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw);
#endif
-#ifndef i_no_cmp
-STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y);
-STC_API _cx_iter _cx_memb(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound);
+#if defined _i_has_cmp
+STC_API int _cx_MEMB(_value_cmp)(const _cx_value* x, const _cx_value* y);
+STC_API _cx_iter _cx_MEMB(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound);
#endif
-STC_INLINE void _cx_memb(_value_drop)(_cx_value* val) { i_keydrop(val); }
+STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* val) { i_keydrop(val); }
+
+STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value) {
+ if (self->_len == self->_cap)
+ if (!_cx_MEMB(_reserve)(self, self->_len*2 + 4))
+ return NULL;
+ _cx_value *v = self->data + self->_len++;
+ *v = value;
+ return v;
+ }
#if !defined i_no_emplace
-STC_API _cx_iter _cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos,
- const _cx_raw* p1, const _cx_raw* p2);
-STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_iter
-_cx_memb(_emplace_n)(_cx_self* self, const intptr_t idx, const _cx_raw arr[], const intptr_t n) {
- return _cx_memb(_emplace_range)(self, self->data + idx, arr, arr + n);
+STC_API _cx_iter
+_cx_MEMB(_emplace_n)(_cx_Self* self, intptr_t idx, const _cx_raw raw[], intptr_t n);
+
+STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw) {
+ return _cx_MEMB(_push)(self, i_keyfrom(raw));
}
-STC_INLINE _cx_iter
-_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) {
- return _cx_memb(_emplace_range)(self, _it_ptr(it), &raw, &raw + 1);
+STC_INLINE _cx_value* _cx_MEMB(_emplace_back)(_cx_Self* self, _cx_raw raw) {
+ return _cx_MEMB(_push)(self, i_keyfrom(raw));
+}
+STC_INLINE _cx_iter _cx_MEMB(_emplace_at)(_cx_Self* self, _cx_iter it, _cx_raw raw) {
+ return _cx_MEMB(_emplace_n)(self, _it_ptr(it) - self->data, &raw, 1);
}
#endif // !i_no_emplace
#if !defined i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
-STC_API _cx_iter _cx_memb(_copy_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
-STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, intptr_t n)
- { while (n--) _cx_memb(_push)(self, i_keyfrom(*raw++)); }
-STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, intptr_t n)
- { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; }
-STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val)
+STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self cx);
+STC_API _cx_iter _cx_MEMB(_copy_n)(_cx_Self* self, intptr_t idx, const _cx_value arr[], intptr_t n);
+STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n)
+ { while (n--) _cx_MEMB(_push)(self, i_keyfrom(*raw++)); }
+STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n)
+ { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; }
+STC_INLINE i_key _cx_MEMB(_value_clone)(_cx_value val)
{ return i_keyclone(val); }
-STC_INLINE void _cx_memb(_copy)(_cx_self* self, const _cx_self* other) {
+STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) {
if (self->data == other->data) return;
- _cx_memb(_clear)(self);
- _cx_memb(_copy_range)(self, self->data, other->data,
- other->data + other->_len);
+ _cx_MEMB(_clear)(self);
+ _cx_MEMB(_copy_n)(self, 0, other->data, other->_len);
}
#endif // !i_no_clone
-STC_INLINE intptr_t _cx_memb(_size)(const _cx_self* self) { return self->_len; }
-STC_INLINE intptr_t _cx_memb(_capacity)(const _cx_self* self) { return self->_cap; }
-STC_INLINE bool _cx_memb(_empty)(const _cx_self* self) { return !self->_len; }
-STC_INLINE _cx_raw _cx_memb(_value_toraw)(const _cx_value* val) { return i_keyto(val); }
-STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->data; }
-STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self)
+STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self) { return self->_len; }
+STC_INLINE intptr_t _cx_MEMB(_capacity)(const _cx_Self* self) { return self->_cap; }
+STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* self) { return !self->_len; }
+STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* val) { return i_keyto(val); }
+STC_INLINE _cx_value* _cx_MEMB(_front)(const _cx_Self* self) { return self->data; }
+STC_INLINE _cx_value* _cx_MEMB(_back)(const _cx_Self* self)
{ return self->data + self->_len - 1; }
-STC_INLINE void _cx_memb(_pop)(_cx_self* self)
- { assert(!_cx_memb(_empty)(self)); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); }
-STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value)
- { return _cx_memb(_push)(self, value); }
-STC_INLINE void _cx_memb(_pop_back)(_cx_self* self) { _cx_memb(_pop)(self); }
-
-STC_INLINE _cx_self
-_cx_memb(_with_size)(const intptr_t size, i_key null) {
- _cx_self cx = _cx_memb(_init)();
- _cx_memb(_resize)(&cx, size, null);
+STC_INLINE void _cx_MEMB(_pop)(_cx_Self* self)
+ { c_assert(self->_len); _cx_value* p = &self->data[--self->_len]; i_keydrop(p); }
+STC_INLINE _cx_value _cx_MEMB(_pull)(_cx_Self* self)
+ { c_assert(self->_len); return self->data[--self->_len]; }
+STC_INLINE _cx_value* _cx_MEMB(_push_back)(_cx_Self* self, i_key value)
+ { return _cx_MEMB(_push)(self, value); }
+STC_INLINE void _cx_MEMB(_pop_back)(_cx_Self* self) { _cx_MEMB(_pop)(self); }
+
+STC_INLINE _cx_Self
+_cx_MEMB(_with_size)(const intptr_t size, i_key null) {
+ _cx_Self cx = _cx_MEMB(_init)();
+ _cx_MEMB(_resize)(&cx, size, null);
return cx;
}
-STC_INLINE _cx_self
-_cx_memb(_with_capacity)(const intptr_t cap) {
- _cx_self cx = _cx_memb(_init)();
- _cx_memb(_reserve)(&cx, cap);
+STC_INLINE _cx_Self
+_cx_MEMB(_with_capacity)(const intptr_t cap) {
+ _cx_Self cx = _cx_MEMB(_init)();
+ _cx_MEMB(_reserve)(&cx, cap);
return cx;
}
STC_INLINE void
-_cx_memb(_shrink_to_fit)(_cx_self* self) {
- _cx_memb(_reserve)(self, _cx_memb(_size)(self));
+_cx_MEMB(_shrink_to_fit)(_cx_Self* self) {
+ _cx_MEMB(_reserve)(self, _cx_MEMB(_size)(self));
}
-
-STC_INLINE _cx_iter
-_cx_memb(_insert)(_cx_self* self, const intptr_t idx, i_key value) {
- return _cx_memb(_insert_range)(self, self->data + idx, &value, &value + 1);
-}
STC_INLINE _cx_iter
-_cx_memb(_insert_n)(_cx_self* self, const intptr_t idx, const _cx_value arr[], const intptr_t n) {
- return _cx_memb(_insert_range)(self, self->data + idx, arr, arr + n);
+_cx_MEMB(_insert_n)(_cx_Self* self, const intptr_t idx, const _cx_value arr[], const intptr_t n) {
+ _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n);
+ if (it.ref)
+ c_memcpy(it.ref, arr, n*c_sizeof *arr);
+ return it;
}
STC_INLINE _cx_iter
-_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
- return _cx_memb(_insert_range)(self, _it_ptr(it), &value, &value + 1);
+_cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, const _cx_value value) {
+ return _cx_MEMB(_insert_n)(self, _it_ptr(it) - self->data, &value, 1);
}
STC_INLINE _cx_iter
-_cx_memb(_erase_n)(_cx_self* self, const intptr_t idx, const intptr_t n) {
- return _cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n);
+_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) {
+ return _cx_MEMB(_erase_n)(self, it.ref - self->data, 1);
}
STC_INLINE _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- return _cx_memb(_erase_range_p)(self, it.ref, it.ref + 1);
-}
-STC_INLINE _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter i1, _cx_iter i2) {
- return _cx_memb(_erase_range_p)(self, i1.ref, _it2_ptr(i1, i2));
+_cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter i1, _cx_iter i2) {
+ return _cx_MEMB(_erase_n)(self, i1.ref - self->data, _it2_ptr(i1, i2) - i1.ref);
}
STC_INLINE const _cx_value*
-_cx_memb(_at)(const _cx_self* self, const intptr_t idx) {
- assert(idx < self->_len); return self->data + idx;
+_cx_MEMB(_at)(const _cx_Self* self, const intptr_t idx) {
+ c_assert(idx < self->_len); return self->data + idx;
}
STC_INLINE _cx_value*
-_cx_memb(_at_mut)(_cx_self* self, const intptr_t idx) {
- assert(idx < self->_len); return self->data + idx;
+_cx_MEMB(_at_mut)(_cx_Self* self, const intptr_t idx) {
+ c_assert(idx < self->_len); return self->data + idx;
}
-STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) {
+STC_INLINE _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) {
intptr_t n = self->_len;
return c_LITERAL(_cx_iter){n ? self->data : NULL, self->data + n};
}
-STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
+STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self)
{ return c_LITERAL(_cx_iter){NULL, self->data + self->_len}; }
-STC_INLINE void _cx_memb(_next)(_cx_iter* it)
+STC_INLINE void _cx_MEMB(_next)(_cx_iter* it)
{ if (++it->ref == it->end) it->ref = NULL; }
-STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, size_t n)
+STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n)
{ if ((it.ref += n) >= it.end) it.ref = NULL; return it; }
-STC_INLINE intptr_t _cx_memb(_index)(const _cx_self* self, _cx_iter it)
+STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it)
{ return (it.ref - self->data); }
-#if !defined i_no_cmp || defined _i_has_eq
+STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n)
+ { self->_len += n; }
+
+#if defined _i_has_eq || defined _i_has_cmp
STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_raw raw) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw);
+_cx_MEMB(_find)(const _cx_Self* self, _cx_raw raw) {
+ return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw);
}
STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_raw raw) {
- return _cx_memb(_find)(self, raw).ref;
+_cx_MEMB(_get)(const _cx_Self* self, _cx_raw raw) {
+ return _cx_MEMB(_find)(self, raw).ref;
}
STC_INLINE _cx_value*
-_cx_memb(_get_mut)(const _cx_self* self, _cx_raw raw)
- { return (_cx_value*) _cx_memb(_get)(self, raw); }
+_cx_MEMB(_get_mut)(const _cx_Self* self, _cx_raw raw)
+ { return (_cx_value*) _cx_MEMB(_get)(self, raw); }
STC_INLINE bool
-_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
+_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
if (self->_len != other->_len) return false;
for (intptr_t i = 0; i < self->_len; ++i) {
const _cx_raw _rx = i_keyto(self->data+i), _ry = i_keyto(other->data+i);
@@ -243,42 +244,42 @@ _cx_memb(_eq)(const _cx_self* self, const _cx_self* other) {
return true;
}
#endif
-#ifndef i_no_cmp
+#if defined _i_has_cmp
STC_INLINE _cx_iter
-_cx_memb(_binary_search)(const _cx_self* self, _cx_raw raw) {
+_cx_MEMB(_binary_search)(const _cx_Self* self, _cx_raw raw) {
_cx_iter lower;
- return _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower);
+ return _cx_MEMB(_binary_search_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw, &lower);
}
STC_INLINE _cx_iter
-_cx_memb(_lower_bound)(const _cx_self* self, _cx_raw raw) {
+_cx_MEMB(_lower_bound)(const _cx_Self* self, _cx_raw raw) {
_cx_iter lower;
- _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower);
+ _cx_MEMB(_binary_search_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), raw, &lower);
return lower;
}
STC_INLINE void
-_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2, int(*cmp)(const _cx_value*, const _cx_value*)) {
+_cx_MEMB(_sort_range)(_cx_iter i1, _cx_iter i2, int(*cmp)(const _cx_value*, const _cx_value*)) {
qsort(i1.ref, (size_t)(_it2_ptr(i1, i2) - i1.ref), sizeof(_cx_value),
(int(*)(const void*, const void*)) cmp);
}
STC_INLINE void
-_cx_memb(_sort)(_cx_self* self) {
- _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp));
+_cx_MEMB(_sort)(_cx_Self* self) {
+ _cx_MEMB(_sort_range)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), _cx_MEMB(_value_cmp));
}
-#endif // !c_no_cmp
+#endif // _i_has_cmp
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
+#if defined(i_implement) || defined(i_static)
-STC_DEF _cx_self
-_cx_memb(_init)(void) {
- return c_LITERAL(_cx_self){NULL};
+STC_DEF _cx_Self
+_cx_MEMB(_init)(void) {
+ return c_LITERAL(_cx_Self){NULL};
}
STC_DEF void
-_cx_memb(_clear)(_cx_self* self) {
+_cx_MEMB(_clear)(_cx_Self* self) {
if (self->_cap) {
for (_cx_value *p = self->data, *q = p + self->_len; p != q; ) {
--q; i_keydrop(q);
@@ -288,15 +289,15 @@ _cx_memb(_clear)(_cx_self* self) {
}
STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
+_cx_MEMB(_drop)(_cx_Self* self) {
if (self->_cap == 0)
return;
- _cx_memb(_clear)(self);
+ _cx_MEMB(_clear)(self);
i_free(self->data);
}
STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const intptr_t cap) {
+_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t cap) {
if (cap > self->_cap || (cap && cap == self->_len)) {
_cx_value* d = (_cx_value*)i_realloc(self->data, cap*c_sizeof(i_key));
if (!d)
@@ -308,8 +309,8 @@ _cx_memb(_reserve)(_cx_self* self, const intptr_t cap) {
}
STC_DEF bool
-_cx_memb(_resize)(_cx_self* self, const intptr_t len, i_key null) {
- if (!_cx_memb(_reserve)(self, len))
+_cx_MEMB(_resize)(_cx_Self* self, const intptr_t len, i_key null) {
+ if (!_cx_MEMB(_reserve)(self, len))
return false;
const intptr_t n = self->_len;
for (intptr_t i = len; i < n; ++i)
@@ -320,86 +321,61 @@ _cx_memb(_resize)(_cx_self* self, const intptr_t len, i_key null) {
return true;
}
-STC_DEF _cx_value*
-_cx_memb(_push)(_cx_self* self, i_key value) {
- if (self->_len == self->_cap)
- if (!_cx_memb(_reserve)(self, self->_len*3/2 + 4))
- return NULL;
- _cx_value *v = self->data + self->_len++;
- *v = value;
- return v;
-}
-
STC_DEF _cx_iter
-_cx_memb(_insert_uninit)(_cx_self* self, _cx_value* pos, const intptr_t n) {
- if (n) {
- if (!pos) pos = self->data + self->_len;
- const intptr_t idx = (pos - self->data);
- if (self->_len + n > self->_cap) {
- if (!_cx_memb(_reserve)(self, self->_len*3/2 + n))
- return _cx_memb(_end)(self);
- pos = self->data + idx;
- }
- c_memmove(pos + n, pos, (self->_len - idx)*c_sizeof *pos);
- self->_len += n;
- }
+_cx_MEMB(_insert_uninit)(_cx_Self* self, const intptr_t idx, const intptr_t n) {
+ if (self->_len + n > self->_cap)
+ if (!_cx_MEMB(_reserve)(self, self->_len*5/4 + n))
+ return _cx_MEMB(_end)(self);
+
+ _cx_value* pos = self->data + idx;
+ c_memmove(pos + n, pos, (self->_len - idx)*c_sizeof *pos);
+ self->_len += n;
return c_LITERAL(_cx_iter){pos, self->data + self->_len};
}
STC_DEF _cx_iter
-_cx_memb(_insert_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1));
- if (it.ref)
- c_memcpy(it.ref, p1, (p2 - p1)*c_sizeof *p1);
- return it;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2) {
- intptr_t len = (p2 - p1);
- _cx_value* p = p1, *end = self->data + self->_len;
- for (; p != p2; ++p)
+_cx_MEMB(_erase_n)(_cx_Self* self, const intptr_t idx, const intptr_t len) {
+ _cx_value* d = self->data + idx, *p = d, *end = self->data + self->_len;
+ for (intptr_t i = 0; i < len; ++i, ++p)
{ i_keydrop(p); }
- c_memmove(p1, p2, (end - p2)*c_sizeof *p1);
+ c_memmove(d, p, (end - p)*c_sizeof *d);
self->_len -= len;
- return c_LITERAL(_cx_iter){p2 == end ? NULL : p1, end - len};
+ return c_LITERAL(_cx_iter){p == end ? NULL : d, end - len};
}
#if !defined i_no_clone
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self cx) {
- _cx_self out = _cx_memb(_init)();
- _cx_memb(_copy_range)(&out, out.data, cx.data, cx.data + cx._len);
+STC_DEF _cx_Self
+_cx_MEMB(_clone)(_cx_Self cx) {
+ _cx_Self out = _cx_MEMB(_init)();
+ _cx_MEMB(_copy_n)(&out, 0, cx.data, cx._len);
return out;
}
STC_DEF _cx_iter
-_cx_memb(_copy_range)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1));
+_cx_MEMB(_copy_n)(_cx_Self* self, const intptr_t idx,
+ const _cx_value arr[], const intptr_t n) {
+ _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n);
if (it.ref)
- for (_cx_value* p = it.ref; p1 != p2; ++p1)
- *p++ = i_keyclone((*p1));
+ for (_cx_value* p = it.ref, *q = p + n; p != q; ++arr)
+ *p++ = i_keyclone((*arr));
return it;
}
#endif // !i_no_clone
#if !defined i_no_emplace
STC_DEF _cx_iter
-_cx_memb(_emplace_range)(_cx_self* self, _cx_value* pos,
- const _cx_raw* p1, const _cx_raw* p2) {
- _cx_iter it = _cx_memb(_insert_uninit)(self, pos, (p2 - p1));
+_cx_MEMB(_emplace_n)(_cx_Self* self, const intptr_t idx, const _cx_raw raw[], intptr_t n) {
+ _cx_iter it = _cx_MEMB(_insert_uninit)(self, idx, n);
if (it.ref)
- for (_cx_value* p = it.ref; p1 != p2; ++p1)
- *p++ = i_keyfrom((*p1));
+ for (_cx_value* p = it.ref; n--; ++raw, ++p)
+ *p = i_keyfrom((*raw));
return it;
}
#endif // !i_no_emplace
+#if defined _i_has_eq || defined _i_has_cmp
-#if !defined i_no_cmp || defined _i_has_eq
STC_DEF _cx_iter
-_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
+_cx_MEMB(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
const _cx_value* p2 = _it2_ptr(i1, i2);
for (; i1.ref != p2; ++i1.ref) {
const _cx_raw r = i_keyto(i1.ref);
@@ -410,10 +386,10 @@ _cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
return i2;
}
#endif
-#ifndef i_no_cmp
+#if defined _i_has_cmp
STC_DEF _cx_iter
-_cx_memb(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw,
+_cx_MEMB(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw,
_cx_iter* lower_bound) {
_cx_value* w[2] = {i1.ref, _it2_ptr(i1, i2)};
_cx_iter mid = i1;
@@ -430,12 +406,12 @@ _cx_memb(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw,
i1.ref = NULL; return i1;
}
-STC_DEF int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
+STC_DEF int _cx_MEMB(_value_cmp)(const _cx_value* x, const _cx_value* y) {
const _cx_raw rx = i_keyto(x);
const _cx_raw ry = i_keyto(y);
return i_cmp((&rx), (&ry));
}
-#endif // !c_no_cmp
+#endif // _i_has_cmp
#endif // i_implement
#define CVEC_H_INCLUDED
#include "priv/template2.h"
diff --git a/include/stc/extend.h b/include/stc/extend.h
index 66b3ebd1..52d59414 100644
--- a/include/stc/extend.h
+++ b/include/stc/extend.h
@@ -43,10 +43,12 @@
#define _i_val i_val
#endif
-#ifdef _i_key
- c_PASTE(forward_, i_con)(i_type, _i_key, _i_val);
+#if defined _i_key && defined _i_val
+ c_PASTE(forward_, i_base)(i_type, _i_key, _i_val);
+#elif defined _i_key
+ c_PASTE(forward_, i_base)(i_type, _i_key);
#else
- c_PASTE(forward_, i_con)(i_type, _i_val);
+ c_PASTE(forward_, i_base)(i_type, _i_val);
#endif
typedef struct {
@@ -54,13 +56,16 @@ typedef struct {
i_type get;
} c_PASTE(i_type, _ext);
-#define c_getcon(cptr) c_container_of(cptr, _cx_memb(_ext), get)
+#define c_extend() c_container_of(self, _cx_MEMB(_ext), get)
+// Note: i_less: c_extend() accessible for cpque types
+// i_cmp: c_extend() accessible for csmap and csset types
+// i_hash/i_eq: c_extend() accessible for cmap and cset types
#define i_is_forward
-#define _i_inc <stc/i_con.h>
+#define _i_inc <stc/i_base.h>
#include _i_inc
#undef _i_inc
#undef _i_key
#undef _i_val
-#undef i_con
+#undef i_base
#undef i_extend
diff --git a/include/stc/forward.h b/include/stc/forward.h
index 31e67e7d..2fbff034 100644
--- a/include/stc/forward.h
+++ b/include/stc/forward.h
@@ -24,35 +24,50 @@
#define STC_FORWARD_H_INCLUDED
#include <stdint.h>
+#include <stddef.h>
#define forward_carc(CX, VAL) _c_carc_types(CX, VAL)
#define forward_cbox(CX, VAL) _c_cbox_types(CX, VAL)
#define forward_cdeq(CX, VAL) _c_cdeq_types(CX, VAL)
#define forward_clist(CX, VAL) _c_clist_types(CX, VAL)
-#define forward_cmap(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, int32_t, c_true, c_false)
-#define forward_cmap64(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, int64_t, c_true, c_false)
-#define forward_cset(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, int32_t, c_false, c_true)
-#define forward_cset64(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, int64_t, c_false, c_true)
-#define forward_csmap(CX, KEY, VAL) _c_aatree_types(CX, KEY, VAL, int32_t, c_true, c_false)
-#define forward_csset(CX, KEY) _c_aatree_types(CX, KEY, KEY, int32_t, c_false, c_true)
+#define forward_cmap(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, c_true, c_false)
+#define forward_cset(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, c_false, c_true)
+#define forward_csmap(CX, KEY, VAL) _c_aatree_types(CX, KEY, VAL, c_true, c_false)
+#define forward_csset(CX, KEY) _c_aatree_types(CX, KEY, KEY, c_false, c_true)
#define forward_cstack(CX, VAL) _c_cstack_types(CX, VAL)
#define forward_cpque(CX, VAL) _c_cpque_types(CX, VAL)
#define forward_cqueue(CX, VAL) _c_cdeq_types(CX, VAL)
#define forward_cvec(CX, VAL) _c_cvec_types(CX, VAL)
-// csview
+// csview : non-null terminated string view
typedef const char csview_value;
-typedef struct csview {
- csview_value* str;
+typedef struct csview {
+ csview_value* buf;
intptr_t size;
} csview;
-typedef union {
- csview_value* ref;
+typedef union {
+ csview_value* ref;
+ csview chr;
struct { csview chr; csview_value* end; } u8;
} csview_iter;
-// cstr
+
+// crawstr : null-terminated string view
+typedef csview_value crawstr_value;
+typedef struct crawstr {
+ crawstr_value* str;
+ intptr_t size;
+} crawstr;
+
+typedef union {
+ crawstr_value* ref;
+ csview chr;
+ struct { csview chr; } u8; // [deprecated]
+} crawstr_iter;
+
+
+// cstr : null-terminated string (short string optimized - sso)
typedef char cstr_value;
typedef struct { cstr_value* data; intptr_t size, cap; } cstr_buf;
typedef union cstr {
@@ -60,11 +75,13 @@ typedef union cstr {
struct { cstr_value* data; size_t size, ncap; } lon;
} cstr;
-typedef union {
- cstr_value* ref;
- struct { csview chr; } u8;
+typedef union {
+ cstr_value* ref;
+ csview chr;
+ struct { csview chr; } u8; // [deprecated]
} cstr_iter;
+
#define c_true(...) __VA_ARGS__
#define c_false(...)
@@ -83,12 +100,17 @@ typedef union {
#define _c_cdeq_types(SELF, VAL) \
typedef VAL SELF##_value; \
- typedef struct { SELF##_value *ref, *end; } SELF##_iter; \
\
typedef struct SELF { \
- SELF##_value *_base, *data; \
- intptr_t _len, _cap; \
- } SELF
+ SELF##_value *data; \
+ intptr_t start, end, capmask; \
+ } SELF; \
+\
+ typedef struct { \
+ SELF##_value *ref; \
+ intptr_t pos; \
+ const SELF* _s; \
+ } SELF##_iter
#define _c_clist_types(SELF, VAL) \
typedef VAL SELF##_value; \
@@ -103,10 +125,9 @@ typedef union {
SELF##_node *last; \
} SELF
-#define _c_chash_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \
+#define _c_chash_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \
typedef KEY SELF##_key; \
typedef VAL SELF##_mapped; \
- typedef SZ SELF##_ssize; \
\
typedef SET_ONLY( SELF##_key ) \
MAP_ONLY( struct SELF##_value ) \
@@ -115,23 +136,23 @@ typedef union {
typedef struct { \
SELF##_value *ref; \
bool inserted; \
+ uint8_t hashx; \
} SELF##_result; \
\
typedef struct { \
SELF##_value *ref, *_end; \
- uint8_t* _hx; \
+ struct chash_slot* sref; \
} SELF##_iter; \
\
typedef struct SELF { \
- SELF##_value* table; \
- uint8_t* _hashx; \
- SELF##_ssize size, bucket_count; \
+ SELF##_value* data; \
+ struct chash_slot* slot; \
+ intptr_t size, bucket_count; \
} SELF
-#define _c_aatree_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \
+#define _c_aatree_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \
typedef KEY SELF##_key; \
typedef VAL SELF##_mapped; \
- typedef SZ SELF##_ssize; \
typedef struct SELF##_node SELF##_node; \
\
typedef SET_ONLY( SELF##_key ) \
@@ -147,12 +168,12 @@ typedef union {
SELF##_value *ref; \
SELF##_node *_d; \
int _top; \
- SELF##_ssize _tn, _st[36]; \
+ int32_t _tn, _st[36]; \
} SELF##_iter; \
\
typedef struct SELF { \
SELF##_node *nodes; \
- SELF##_ssize root, disp, head, size, cap; \
+ int32_t root, disp, head, size, cap; \
} SELF
#define _c_cstack_fixed(SELF, VAL, CAP) \
diff --git a/include/stc/priv/cqueue_hdr.h b/include/stc/priv/cqueue_hdr.h
new file mode 100644
index 00000000..06f3bd74
--- /dev/null
+++ b/include/stc/priv/cqueue_hdr.h
@@ -0,0 +1,116 @@
+/* MIT License
+ *
+ * Copyright (c) 2023 Tyge Løvset
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#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); }
+STC_INLINE void _cx_MEMB(_copy)(_cx_Self* self, const _cx_Self* other) {
+ if (self->data == other->data) return;
+ _cx_MEMB(_drop)(self);
+ *self = _cx_MEMB(_clone)(*other);
+ }
+#endif // !i_no_clone
+STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* self)
+ { return _cdeq_toidx(self, self->end); }
+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 _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) {
+ return c_LITERAL(_cx_iter){
+ .ref=_cx_MEMB(_empty)(self) ? NULL : self->data + self->start,
+ .pos=self->start, ._s=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..65711fc0
--- /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_less_unsigned(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 = stc_nextpow2(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/altnames.h b/include/stc/priv/linkage.h
index 723b6a66..7f63f5f1 100644
--- a/include/stc/priv/altnames.h
+++ b/include/stc/priv/linkage.h
@@ -20,15 +20,21 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#define c_FORLIST c_forlist
-#define c_FORRANGE c_forrange
-#define c_FOREACH c_foreach
-#define c_FORPAIR c_forpair
-#define c_FORFILTER c_forfilter
-#define c_FORMATCH c_formatch
-#define c_FORTOKEN c_fortoken
-#define c_FORTOKEN_SV c_fortoken_sv
-#define c_AUTO c_auto
-#define c_WITH c_with
-#define c_SCOPE c_scope
-#define c_DEFER c_defer
+#undef STC_API
+#undef STC_DEF
+
+#ifdef i_extern // [deprecated]
+# define i_import
+#endif
+#if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \
+ defined(i_implement) || defined(STC_IMPLEMENT))
+ #define STC_API extern
+ #define STC_DEF
+#else
+ #define i_static
+ #define STC_API static inline
+ #define STC_DEF static inline
+#endif
+#if defined(STC_IMPLEMENT) || defined(i_import)
+ #define i_implement
+#endif
diff --git a/include/stc/priv/raii.h b/include/stc/priv/raii.h
deleted file mode 100644
index bb41e0d1..00000000
--- a/include/stc/priv/raii.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#define c_defer(...) \
- for (int _i = 1; _i; _i = 0, __VA_ARGS__)
-
-#define c_with(...) c_MACRO_OVERLOAD(c_with, __VA_ARGS__)
-#define c_with_2(declvar, drop) \
- for (declvar, *_i, **_ip = &_i; _ip; _ip = 0, drop)
-#define c_with_3(declvar, pred, drop) \
- for (declvar, *_i, **_ip = &_i; _ip && (pred); _ip = 0, drop)
-
-#define c_scope(...) c_MACRO_OVERLOAD(c_scope, __VA_ARGS__)
-#define c_scope_2(init, drop) \
- for (int _i = (init, 1); _i; _i = 0, drop)
-#define c_scope_3(init, pred, drop) \
- for (int _i = (init, 1); _i && (pred); _i = 0, drop)
-
-#define c_auto(...) c_MACRO_OVERLOAD(c_auto, __VA_ARGS__)
-#define c_auto_2(C, a) \
- c_with_2(C a = C##_init(), C##_drop(&a))
-#define c_auto_3(C, a, b) \
- c_with_2(c_EXPAND(C a = C##_init(), b = C##_init()), \
- (C##_drop(&b), C##_drop(&a)))
-#define c_auto_4(C, a, b, c) \
- c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init()), \
- (C##_drop(&c), C##_drop(&b), C##_drop(&a)))
-#define c_auto_5(C, a, b, c, d) \
- c_with_2(c_EXPAND(C a = C##_init(), b = C##_init(), c = C##_init(), d = C##_init()), \
- (C##_drop(&d), C##_drop(&c), C##_drop(&b), C##_drop(&a)))
diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h
index 16ef51af..38097a35 100644
--- a/include/stc/priv/template.h
+++ b/include/stc/priv/template.h
@@ -20,34 +20,28 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#ifdef _i_template
- #error template.h already included
-#endif
+#ifndef _i_template
#define _i_template
#ifndef STC_TEMPLATE_H_INCLUDED
#define STC_TEMPLATE_H_INCLUDED
- #define _cx_self i_type
- #define _cx_memb(name) c_PASTE(_cx_self, name)
- #define _cx_deftypes(macro, SELF, ...) c_EXPAND(macro(SELF, __VA_ARGS__))
- #define _cx_value _cx_memb(_value)
- #define _cx_key _cx_memb(_key)
- #define _cx_mapped _cx_memb(_mapped)
- #define _cx_raw _cx_memb(_raw)
- #define _cx_keyraw _cx_memb(_keyraw)
- #define _cx_iter _cx_memb(_iter)
- #define _cx_result _cx_memb(_result)
- #define _cx_node _cx_memb(_node)
+ #define _cx_Self i_type
+ #define _cx_MEMB(name) c_PASTE(_cx_Self, name)
+ #define _cx_DEFTYPES(macro, SELF, ...) c_EXPAND(macro(SELF, __VA_ARGS__))
+ #define _cx_value _cx_MEMB(_value)
+ #define _cx_key _cx_MEMB(_key)
+ #define _cx_mapped _cx_MEMB(_mapped)
+ #define _cx_raw _cx_MEMB(_raw)
+ #define _cx_keyraw _cx_MEMB(_keyraw)
+ #define _cx_iter _cx_MEMB(_iter)
+ #define _cx_result _cx_MEMB(_result)
+ #define _cx_node _cx_MEMB(_node)
#endif
#ifndef i_type
#define i_type c_PASTE(_i_prefix, i_tag)
#endif
-#ifndef i_ssize
- #define i_ssize intptr_t
-#endif
-
#ifndef i_allocator
#define i_allocator c
#endif
@@ -99,23 +93,22 @@
#if c_option(c_is_forward)
#define i_is_forward
#endif
-#if c_option(c_no_cmp)
- #define i_no_cmp
-#endif
#if c_option(c_no_hash)
#define i_no_hash
#endif
#if c_option(c_no_emplace)
#define i_no_emplace
#endif
-#ifdef i_eq
- #define _i_has_eq
+#if c_option(c_use_cmp) || defined _i_ismap || defined _i_isset || defined _i_ispque
+ #define i_use_cmp
+#endif
+#if c_option(c_no_clone) || defined _i_carc
+ #define i_no_clone
#endif
#if defined i_key_str
#define i_keyclass cstr
- #define i_rawclass crawstr
- #define i_keyfrom cstr_from
+ #define i_rawclass ccharptr
#ifndef i_tag
#define i_tag str
#endif
@@ -131,7 +124,7 @@
#elif defined i_keyboxed
#define i_keyclass i_keyboxed
#define i_rawclass c_PASTE(i_keyboxed, _raw)
- #ifndef i_no_cmp
+ #if defined i_use_cmp
#define i_eq c_PASTE(i_keyboxed, _raw_eq)
#endif
#endif
@@ -142,56 +135,68 @@
#define i_rawclass i_key
#endif
-#ifdef i_keyclass
+#if defined i_keyclass
#define i_key i_keyclass
#ifndef i_keyclone
#define i_keyclone c_PASTE(i_key, _clone)
#endif
- #if !defined i_keyto && defined i_keyraw
- #define i_keyto c_PASTE(i_key, _toraw)
+ #ifndef i_keydrop
+ #define i_keydrop c_PASTE(i_key, _drop)
#endif
#if !defined i_keyfrom && defined i_keyraw
#define i_keyfrom c_PASTE(i_key, _from)
#endif
- #ifndef i_keydrop
- #define i_keydrop c_PASTE(i_key, _drop)
+ #if !defined i_keyto && defined i_keyraw
+ #define i_keyto c_PASTE(i_key, _toraw)
+ #endif
+ #if !defined i_keyraw && (defined i_cmp || defined i_less || defined i_eq || defined i_hash)
+ #define i_use_cmp
#endif
#endif
-#ifdef i_rawclass
- #if !defined i_cmp && !defined i_no_cmp
+#if defined i_rawclass && defined i_use_cmp
+ #if !(defined i_cmp || defined i_less)
#define i_cmp c_PASTE(i_keyraw, _cmp)
#endif
- #if !defined i_hash && !defined i_no_hash
+ #if !(defined i_hash || defined i_no_hash)
#define i_hash c_PASTE(i_keyraw, _hash)
#endif
#endif
+#if defined i_cmp || defined i_less || defined i_use_cmp
+ #define _i_has_cmp
+#endif
+#if defined i_eq || defined i_use_cmp
+ #define _i_has_eq
+#endif
+#if !(defined i_hash || defined i_no_hash)
+ #define i_hash c_default_hash
+#endif
+
#if !defined i_key
#error "No i_key or i_val defined"
#elif defined i_keyraw ^ defined i_keyto
- #error "Both i_keyraw/valraw and i_keyto/valto must be defined, if any"
-#elif defined i_keyfrom && !defined i_keyraw
- #error "i_keyfrom/valfrom defined without i_keyraw/valraw"
+ #error "Both i_keyraw/i_valraw and i_keyto/i_valto must be defined, if any"
+#elif !defined i_no_clone && (defined i_keyclone ^ defined i_keydrop)
+ #error "Both i_keyclone/i_valclone and i_keydrop/i_valdrop must be defined, if any (unless i_no_clone defined)."
#elif defined i_from || defined i_drop
#error "i_from / i_drop not supported. Define i_keyfrom/i_valfrom and/or i_keydrop/i_valdrop instead"
+#elif defined i_keyraw && defined _i_ishash && !(defined i_hash && (defined _i_has_cmp || defined i_eq))
+ #error "For cmap/cset, both i_hash and i_eq (or i_less or i_cmp) must be defined when i_keyraw is defined."
+#elif defined i_keyraw && defined i_use_cmp && !defined _i_has_cmp
+ #error "For csmap/csset/cpque, i_cmp or i_less must be defined when i_keyraw is defined."
#endif
#ifndef i_tag
#define i_tag i_key
#endif
-#if c_option(c_no_clone)
- #define i_no_clone
-#elif !(defined i_keyclone || defined i_no_clone) && (defined i_keydrop || defined i_keyraw)
- #error i_keyclone/valclone should be defined when i_keydrop/valdrop or i_keyraw/valraw is defined
-#endif
#ifndef i_keyraw
#define i_keyraw i_key
#endif
#ifndef i_keyfrom
#define i_keyfrom c_default_clone
#else
- #define _i_has_from
+ #define i_has_emplace
#endif
#ifndef i_keyto
#define i_keyto c_default_toraw
@@ -204,32 +209,27 @@
#endif
// i_eq, i_less, i_cmp
-#if !defined i_eq && (defined i_cmp || defined i_less)
+#if !defined i_eq && defined i_cmp
#define i_eq(x, y) !(i_cmp(x, y))
#elif !defined i_eq
- #define i_eq c_default_eq
+ #define i_eq(x, y) *x == *y
#endif
-#if defined i_less && defined i_cmp
- #error "Only one of i_less and i_cmp may be defined"
-#elif !defined i_less && !defined i_cmp
- #define i_less c_default_less
-#elif !defined i_less
+#if defined i_cmp && defined i_less
+ #error "Only one of i_cmp and i_less may be defined"
+#elif defined i_cmp
#define i_less(x, y) (i_cmp(x, y)) < 0
+#elif !defined i_less
+ #define i_less(x, y) *x < *y
#endif
#ifndef i_cmp
#define i_cmp(x, y) (i_less(y, x)) - (i_less(x, y))
#endif
-#ifndef i_hash
- #define i_hash c_default_hash
-#endif
-
#if defined _i_ismap // ---- process cmap/csmap value i_val, ... ----
#ifdef i_val_str
#define i_valclass cstr
- #define i_valraw crawstr
- #define i_valfrom cstr_from
+ #define i_valraw const char*
#elif defined i_val_ssv
#define i_valclass cstr
#define i_valraw csview
@@ -245,31 +245,32 @@
#ifndef i_valclone
#define i_valclone c_PASTE(i_val, _clone)
#endif
- #if !defined i_valto && defined i_valraw
- #define i_valto c_PASTE(i_val, _toraw)
+ #ifndef i_valdrop
+ #define i_valdrop c_PASTE(i_val, _drop)
#endif
#if !defined i_valfrom && defined i_valraw
#define i_valfrom c_PASTE(i_val, _from)
#endif
- #ifndef i_valdrop
- #define i_valdrop c_PASTE(i_val, _drop)
+ #if !defined i_valto && defined i_valraw
+ #define i_valto c_PASTE(i_val, _toraw)
#endif
#endif
#ifndef i_val
#error "i_val* must be defined for maps"
+#elif defined i_valraw ^ defined i_valto
+ #error "Both i_valraw and i_valto must be defined, if any"
+#elif !defined i_no_clone && (defined i_valclone ^ defined i_valdrop)
+ #error "Both i_valclone and i_valdrop must be defined, if any"
#endif
-#if !(defined i_valclone || defined i_no_clone) && (defined i_valdrop || defined i_valraw)
- #error i_valclone should be defined when i_valdrop or i_valraw is defined
-#endif
#ifndef i_valraw
#define i_valraw i_val
#endif
#ifndef i_valfrom
#define i_valfrom c_default_clone
#else
- #define _i_has_from
+ #define i_has_emplace
#endif
#ifndef i_valto
#define i_valto c_default_toraw
@@ -289,6 +290,7 @@
#ifndef i_valraw
#define i_valraw i_keyraw
#endif
-#ifndef _i_has_from
+#ifndef i_has_emplace
#define i_no_emplace
#endif
+#endif
diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h
index 27c6a890..44254601 100644
--- a/include/stc/priv/template2.h
+++ b/include/stc/priv/template2.h
@@ -20,6 +20,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#ifdef i_more
+#undef i_more
+#else
#undef i_type
#undef i_tag
#undef i_imp
@@ -30,7 +33,6 @@
#undef i_hash
#undef i_rawclass
#undef i_capacity
-#undef i_ssize
#undef i_val
#undef i_val_str
@@ -57,7 +59,7 @@
#undef i_header
#undef i_implement
#undef i_static
-#undef i_extern
+#undef i_import
#undef i_allocator
#undef i_malloc
@@ -65,14 +67,16 @@
#undef i_realloc
#undef i_free
-#undef i_no_cmp
+#undef i_use_cmp
#undef i_no_hash
#undef i_no_clone
#undef i_no_emplace
#undef i_is_forward
+#undef i_has_emplace
+#undef _i_has_cmp
+#undef _i_has_eq
#undef _i_prefix
#undef _i_expandby
-#undef _i_has_from
-#undef _i_has_eq
#undef _i_template
+#endif
diff --git a/include/stc/utf8.h b/include/stc/utf8.h
index a4cc3846..6d12856f 100644
--- a/include/stc/utf8.h
+++ b/include/stc/utf8.h
@@ -1,11 +1,34 @@
+/* MIT License
+ *
+ * Copyright (c) 2023 Tyge Løvset
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "priv/linkage.h"
+
#ifndef UTF8_H_INCLUDED
#define UTF8_H_INCLUDED
+#include "ccommon.h"
#include <ctype.h>
#include "forward.h"
-#include "ccommon.h"
-// utf8 methods defined in src/utf8code.c:
enum {
U8G_Cc, U8G_Lt, U8G_Nd, U8G_Nl,
U8G_Pc, U8G_Pd, U8G_Pf, U8G_Pi,
@@ -16,6 +39,7 @@ enum {
U8G_SIZE
};
+// utf8 methods defined in src/utf8code.c:
extern bool utf8_isgroup(int group, uint32_t c);
extern bool utf8_isalpha(uint32_t c);
extern uint32_t utf8_casefold(uint32_t c);
@@ -51,9 +75,9 @@ STC_INLINE bool utf8_isspace(uint32_t c) {
/* decode next utf8 codepoint. https://bjoern.hoehrmann.de/utf-8/decoder/dfa */
typedef struct { uint32_t state, codep; } utf8_decode_t;
+extern const uint8_t utf8_dtab[]; /* utf8code.c */
STC_INLINE uint32_t utf8_decode(utf8_decode_t* d, const uint32_t byte) {
- extern const uint8_t utf8_dtab[]; /* utf8code.c */
const uint32_t type = utf8_dtab[byte];
d->codep = d->state ? (byte & 0x3fu) | (d->codep << 6)
: (0xffU >> type) & byte;
@@ -112,9 +136,16 @@ STC_INLINE const char* utf8_at(const char *s, intptr_t index) {
STC_INLINE intptr_t utf8_pos(const char* s, intptr_t index)
{ return (intptr_t)(utf8_at(s, index) - s); }
-
#endif // UTF8_H_INCLUDED
-#if defined(i_extern)
+
+#if defined i_import || (defined i_implement && !defined _i_inc_utf8)
# include "../../src/utf8code.c"
-# undef i_extern
#endif
+#ifndef _i_inc_utf8
+#undef i_static
+#undef i_header
+#undef i_implement
+#undef i_import
+#undef i_opt
+#endif
+#undef _i_inc_utf8
diff --git a/misc/benchmarks/external/ankerl/unordered_dense.h b/misc/benchmarks/external/ankerl/unordered_dense.h
index faad051d..b8cacea7 100644
--- a/misc/benchmarks/external/ankerl/unordered_dense.h
+++ b/misc/benchmarks/external/ankerl/unordered_dense.h
@@ -1,7 +1,7 @@
///////////////////////// ankerl::unordered_dense::{map, set} /////////////////////////
// A fast & densely stored hashmap and hashset based on robin-hood backward shift deletion.
-// Version 3.1.0
+// Version 4.0.1
// https://github.com/martinus/unordered_dense
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
@@ -30,12 +30,15 @@
#define ANKERL_UNORDERED_DENSE_H
// see https://semver.org/spec/v2.0.0.html
-#define ANKERL_UNORDERED_DENSE_VERSION_MAJOR 3 // NOLINT(cppcoreguidelines-macro-usage) incompatible API changes
-#define ANKERL_UNORDERED_DENSE_VERSION_MINOR 1 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality
-#define ANKERL_UNORDERED_DENSE_VERSION_PATCH 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible bug fixes
+#define ANKERL_UNORDERED_DENSE_VERSION_MAJOR 4 // NOLINT(cppcoreguidelines-macro-usage) incompatible API changes
+#define ANKERL_UNORDERED_DENSE_VERSION_MINOR 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality
+#define ANKERL_UNORDERED_DENSE_VERSION_PATCH 1 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible bug fixes
// API versioning with inline namespace, see https://www.foonathan.net/2018/11/inline-namespaces/
+
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define ANKERL_UNORDERED_DENSE_VERSION_CONCAT1(major, minor, patch) v##major##_##minor##_##patch
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define ANKERL_UNORDERED_DENSE_VERSION_CONCAT(major, minor, patch) ANKERL_UNORDERED_DENSE_VERSION_CONCAT1(major, minor, patch)
#define ANKERL_UNORDERED_DENSE_NAMESPACE \
ANKERL_UNORDERED_DENSE_VERSION_CONCAT( \
@@ -57,9 +60,9 @@
// exceptions
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
-# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 1
+# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 1 // NOLINT(cppcoreguidelines-macro-usage)
#else
-# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 0
+# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 0 // NOLINT(cppcoreguidelines-macro-usage)
#endif
#ifdef _MSC_VER
# define ANKERL_UNORDERED_DENSE_NOINLINE __declspec(noinline)
@@ -89,20 +92,13 @@
# include <cstdlib> // for abort
# endif
-# define ANKERL_UNORDERED_DENSE_PMR 0 // NOLINT(cppcoreguidelines-macro-usage)
# if defined(__has_include)
# if __has_include(<memory_resource>)
-# undef ANKERL_UNORDERED_DENSE_PMR
-# define ANKERL_UNORDERED_DENSE_PMR 1 // NOLINT(cppcoreguidelines-macro-usage)
-# define ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR \
- std::pmr::polymorphic_allocator // NOLINT(cppcoreguidelines-macro-usage)
-# include <memory_resource> // for polymorphic_allocator
+# define ANKERL_UNORDERED_DENSE_PMR std::pmr // NOLINT(cppcoreguidelines-macro-usage)
+# include <memory_resource> // for polymorphic_allocator
# elif __has_include(<experimental/memory_resource>)
-# undef ANKERL_UNORDERED_DENSE_PMR
-# define ANKERL_UNORDERED_DENSE_PMR 1 // NOLINT(cppcoreguidelines-macro-usage)
-# define ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR \
- std::experimental::pmr::polymorphic_allocator // NOLINT(cppcoreguidelines-macro-usage)
-# include <experimental/memory_resource> // for polymorphic_allocator
+# define ANKERL_UNORDERED_DENSE_PMR std::experimental::pmr // NOLINT(cppcoreguidelines-macro-usage)
+# include <experimental/memory_resource> // for polymorphic_allocator
# endif
# endif
@@ -428,7 +424,7 @@ constexpr bool is_map_v = !std::is_void_v<Mapped>;
// clang-format off
template <typename Hash, typename KeyEqual>
-constexpr bool is_transparent_v = is_detected_v<detect_is_transparent, Hash>&& is_detected_v<detect_is_transparent, KeyEqual>;
+constexpr bool is_transparent_v = is_detected_v<detect_is_transparent, Hash> && is_detected_v<detect_is_transparent, KeyEqual>;
// clang-format on
template <typename From, typename To1, typename To2>
@@ -446,19 +442,320 @@ struct base_table_type_map {
// base type for set doesn't have mapped_type
struct base_table_type_set {};
+} // namespace detail
+
+// Very much like std::deque, but faster for indexing (in most cases). As of now this doesn't implement the full std::vector
+// API, but merely what's necessary to work as an underlying container for ankerl::unordered_dense::{map, set}.
+// It allocates blocks of equal size and puts them into the m_blocks vector. That means it can grow simply by adding a new
+// block to the back of m_blocks, and doesn't double its size like an std::vector. The disadvantage is that memory is not
+// linear and thus there is one more indirection necessary for indexing.
+template <typename T, typename Allocator = std::allocator<T>, size_t MaxSegmentSizeBytes = 4096>
+class segmented_vector {
+ template <bool IsConst>
+ class iter_t;
+
+public:
+ using allocator_type = Allocator;
+ using pointer = typename std::allocator_traits<allocator_type>::pointer;
+ using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
+ using difference_type = typename std::allocator_traits<allocator_type>::difference_type;
+ using value_type = T;
+ using size_type = std::size_t;
+ using reference = T&;
+ using const_reference = T const&;
+ using iterator = iter_t<false>;
+ using const_iterator = iter_t<true>;
+
+private:
+ using vec_alloc = typename std::allocator_traits<Allocator>::template rebind_alloc<pointer>;
+ std::vector<pointer, vec_alloc> m_blocks{};
+ size_t m_size{};
+
+ // Calculates the maximum number for x in (s << x) <= max_val
+ static constexpr auto num_bits_closest(size_t max_val, size_t s) -> size_t {
+ auto f = size_t{0};
+ while (s << (f + 1) <= max_val) {
+ ++f;
+ }
+ return f;
+ }
+
+ using self_t = segmented_vector<T, Allocator, MaxSegmentSizeBytes>;
+ static constexpr auto num_bits = num_bits_closest(MaxSegmentSizeBytes, sizeof(T));
+ static constexpr auto num_elements_in_block = 1U << num_bits;
+ static constexpr auto mask = num_elements_in_block - 1U;
+
+ /**
+ * Iterator class doubles as const_iterator and iterator
+ */
+ template <bool IsConst>
+ class iter_t {
+ using ptr_t = typename std::conditional_t<IsConst, segmented_vector::const_pointer const*, segmented_vector::pointer*>;
+ ptr_t m_data{};
+ size_t m_idx{};
+
+ template <bool B>
+ friend class iter_t;
+
+ public:
+ using difference_type = segmented_vector::difference_type;
+ using value_type = T;
+ using reference = typename std::conditional_t<IsConst, value_type const&, value_type&>;
+ using pointer = typename std::conditional_t<IsConst, segmented_vector::const_pointer, segmented_vector::pointer>;
+ using iterator_category = std::forward_iterator_tag;
+
+ iter_t() noexcept = default;
+
+ template <bool OtherIsConst, typename = typename std::enable_if<IsConst && !OtherIsConst>::type>
+ // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
+ constexpr iter_t(iter_t<OtherIsConst> const& other) noexcept
+ : m_data(other.m_data)
+ , m_idx(other.m_idx) {}
+
+ constexpr iter_t(ptr_t data, size_t idx) noexcept
+ : m_data(data)
+ , m_idx(idx) {}
+
+ template <bool OtherIsConst, typename = typename std::enable_if<IsConst && !OtherIsConst>::type>
+ constexpr auto operator=(iter_t<OtherIsConst> const& other) noexcept -> iter_t& {
+ m_data = other.m_data;
+ m_idx = other.m_idx;
+ return *this;
+ }
+
+ constexpr auto operator++() noexcept -> iter_t& {
+ ++m_idx;
+ return *this;
+ }
+
+ constexpr auto operator+(difference_type diff) noexcept -> iter_t {
+ return {m_data, static_cast<size_t>(static_cast<difference_type>(m_idx) + diff)};
+ }
+
+ template <bool OtherIsConst>
+ constexpr auto operator-(iter_t<OtherIsConst> const& other) noexcept -> difference_type {
+ return static_cast<difference_type>(m_idx) - static_cast<difference_type>(other.m_idx);
+ }
+
+ constexpr auto operator*() const noexcept -> reference {
+ return m_data[m_idx >> num_bits][m_idx & mask];
+ }
+
+ constexpr auto operator->() const noexcept -> pointer {
+ return &m_data[m_idx >> num_bits][m_idx & mask];
+ }
+
+ template <bool O>
+ constexpr auto operator==(iter_t<O> const& o) const noexcept -> bool {
+ return m_idx == o.m_idx;
+ }
+
+ template <bool O>
+ constexpr auto operator!=(iter_t<O> const& o) const noexcept -> bool {
+ return !(*this == o);
+ }
+ };
+
+ // slow path: need to allocate a new segment every once in a while
+ void increase_capacity() {
+ auto ba = Allocator(m_blocks.get_allocator());
+ pointer block = std::allocator_traits<Allocator>::allocate(ba, num_elements_in_block);
+ m_blocks.push_back(block);
+ }
+
+ // Moves everything from other
+ void append_everything_from(segmented_vector&& other) {
+ reserve(size() + other.size());
+ for (auto&& o : other) {
+ emplace_back(std::move(o));
+ }
+ }
+
+ // Copies everything from other
+ void append_everything_from(segmented_vector const& other) {
+ reserve(size() + other.size());
+ for (auto const& o : other) {
+ emplace_back(o);
+ }
+ }
+
+ void dealloc() {
+ auto ba = Allocator(m_blocks.get_allocator());
+ for (auto ptr : m_blocks) {
+ std::allocator_traits<Allocator>::deallocate(ba, ptr, num_elements_in_block);
+ }
+ }
+
+ [[nodiscard]] static constexpr auto calc_num_blocks_for_capacity(size_t capacity) {
+ return (capacity + num_elements_in_block - 1U) / num_elements_in_block;
+ }
+
+public:
+ segmented_vector() = default;
+
+ // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
+ segmented_vector(Allocator alloc)
+ : m_blocks(vec_alloc(alloc)) {}
+
+ segmented_vector(segmented_vector&& other, Allocator alloc)
+ : m_blocks(vec_alloc(alloc)) {
+ if (other.get_allocator() == alloc) {
+ *this = std::move(other);
+ } else {
+ // Oh my, allocator is different so we need to copy everything.
+ append_everything_from(std::move(other));
+ }
+ }
+
+ segmented_vector(segmented_vector&& other) noexcept
+ : m_blocks(std::move(other.m_blocks))
+ , m_size(std::exchange(other.m_size, {})) {}
+
+ segmented_vector(segmented_vector const& other, Allocator alloc)
+ : m_blocks(vec_alloc(alloc)) {
+ append_everything_from(other);
+ }
+
+ segmented_vector(segmented_vector const& other) {
+ append_everything_from(other);
+ }
+
+ auto operator=(segmented_vector const& other) -> segmented_vector& {
+ if (this == &other) {
+ return *this;
+ }
+ clear();
+ append_everything_from(other);
+ return *this;
+ }
+
+ auto operator=(segmented_vector&& other) noexcept -> segmented_vector& {
+ clear();
+ dealloc();
+ m_blocks = std::move(other.m_blocks);
+ m_size = std::exchange(other.m_size, {});
+ return *this;
+ }
+
+ ~segmented_vector() {
+ clear();
+ dealloc();
+ }
+
+ [[nodiscard]] constexpr auto size() const -> size_t {
+ return m_size;
+ }
+
+ [[nodiscard]] constexpr auto capacity() const -> size_t {
+ return m_blocks.size() * num_elements_in_block;
+ }
+
+ // Indexing is highly performance critical
+ [[nodiscard]] constexpr auto operator[](size_t i) const noexcept -> T const& {
+ return m_blocks[i >> num_bits][i & mask];
+ }
+
+ [[nodiscard]] constexpr auto operator[](size_t i) noexcept -> T& {
+ return m_blocks[i >> num_bits][i & mask];
+ }
+
+ [[nodiscard]] constexpr auto begin() -> iterator {
+ return {m_blocks.data(), 0U};
+ }
+ [[nodiscard]] constexpr auto begin() const -> const_iterator {
+ return {m_blocks.data(), 0U};
+ }
+ [[nodiscard]] constexpr auto cbegin() const -> const_iterator {
+ return {m_blocks.data(), 0U};
+ }
+
+ [[nodiscard]] constexpr auto end() -> iterator {
+ return {m_blocks.data(), m_size};
+ }
+ [[nodiscard]] constexpr auto end() const -> const_iterator {
+ return {m_blocks.data(), m_size};
+ }
+ [[nodiscard]] constexpr auto cend() const -> const_iterator {
+ return {m_blocks.data(), m_size};
+ }
+
+ [[nodiscard]] constexpr auto back() -> reference {
+ return operator[](m_size - 1);
+ }
+ [[nodiscard]] constexpr auto back() const -> const_reference {
+ return operator[](m_size - 1);
+ }
+
+ void pop_back() {
+ back().~T();
+ --m_size;
+ }
+
+ [[nodiscard]] auto empty() const {
+ return 0 == m_size;
+ }
+
+ void reserve(size_t new_capacity) {
+ m_blocks.reserve(calc_num_blocks_for_capacity(new_capacity));
+ while (new_capacity > capacity()) {
+ increase_capacity();
+ }
+ }
+
+ [[nodiscard]] auto get_allocator() const -> allocator_type {
+ return allocator_type{m_blocks.get_allocator()};
+ }
+
+ template <class... Args>
+ auto emplace_back(Args&&... args) -> reference {
+ if (m_size == capacity()) {
+ increase_capacity();
+ }
+ auto* ptr = static_cast<void*>(&operator[](m_size));
+ auto& ref = *new (ptr) T(std::forward<Args>(args)...);
+ ++m_size;
+ return ref;
+ }
+
+ void clear() {
+ if constexpr (!std::is_trivially_destructible_v<T>) {
+ for (size_t i = 0, s = size(); i < s; ++i) {
+ operator[](i).~T();
+ }
+ }
+ m_size = 0;
+ }
+
+ void shrink_to_fit() {
+ auto ba = Allocator(m_blocks.get_allocator());
+ auto num_blocks_required = calc_num_blocks_for_capacity(m_size);
+ while (m_blocks.size() > num_blocks_required) {
+ std::allocator_traits<Allocator>::deallocate(ba, m_blocks.back(), num_elements_in_block);
+ m_blocks.pop_back();
+ }
+ m_blocks.shrink_to_fit();
+ }
+};
+
+namespace detail {
+
// This is it, the table. Doubles as map and set, and uses `void` for T when its used as a set.
template <class Key,
class T, // when void, treat it as a set.
class Hash,
class KeyEqual,
class AllocatorOrContainer,
- class Bucket>
+ class Bucket,
+ bool IsSegmented>
class table : public std::conditional_t<is_map_v<T>, base_table_type_map<T>, base_table_type_set> {
+ using underlying_value_type = typename std::conditional_t<is_map_v<T>, std::pair<Key, T>, Key>;
+ using underlying_container_type = std::conditional_t<IsSegmented,
+ segmented_vector<underlying_value_type, AllocatorOrContainer>,
+ std::vector<underlying_value_type, AllocatorOrContainer>>;
+
public:
- using value_container_type = std::conditional_t<
- is_detected_v<detect_iterator, AllocatorOrContainer>,
- AllocatorOrContainer,
- typename std::vector<typename std::conditional_t<is_map_v<T>, std::pair<Key, T>, Key>, AllocatorOrContainer>>;
+ using value_container_type = std::
+ conditional_t<is_detected_v<detect_iterator, AllocatorOrContainer>, AllocatorOrContainer, underlying_container_type>;
private:
using bucket_alloc =
@@ -492,7 +789,8 @@ private:
static_assert(std::is_trivially_copyable_v<Bucket>, "assert we can just memset / memcpy");
value_container_type m_values{}; // Contains all the key-value pairs in one densely stored container. No holes.
- typename std::allocator_traits<bucket_alloc>::pointer m_buckets{};
+ using bucket_pointer = typename std::allocator_traits<bucket_alloc>::pointer;
+ bucket_pointer m_buckets{};
size_t m_num_buckets = 0;
size_t m_max_bucket_capacity = 0;
float m_max_load_factor = default_max_load_factor;
@@ -507,8 +805,7 @@ private:
}
// Helper to access bucket through pointer types
- [[nodiscard]] static constexpr auto at(typename std::allocator_traits<bucket_alloc>::pointer bucket_ptr, size_t offset)
- -> Bucket& {
+ [[nodiscard]] static constexpr auto at(bucket_pointer bucket_ptr, size_t offset) -> Bucket& {
return *(bucket_ptr + static_cast<typename std::allocator_traits<bucket_alloc>::difference_type>(offset));
}
@@ -578,7 +875,7 @@ private:
}
[[nodiscard]] static constexpr auto calc_num_buckets(uint8_t shifts) -> size_t {
- return std::min(max_bucket_count(), size_t{1} << (64U - shifts));
+ return (std::min)(max_bucket_count(), size_t{1} << (64U - shifts));
}
[[nodiscard]] constexpr auto calc_shifts_for_size(size_t s) const -> uint8_t {
@@ -983,7 +1280,7 @@ public:
}
[[nodiscard]] static constexpr auto max_size() noexcept -> size_t {
- if constexpr (std::numeric_limits<value_idx_type>::max() == std::numeric_limits<size_t>::max()) {
+ if constexpr ((std::numeric_limits<value_idx_type>::max)() == (std::numeric_limits<size_t>::max)()) {
return size_t{1} << (sizeof(value_idx_type) * 8 - 1);
} else {
return size_t{1} << (sizeof(value_idx_type) * 8);
@@ -1272,7 +1569,7 @@ public:
auto const last_to_end = std::distance(last, cend());
// remove elements from left to right which moves elements from the end back
- auto const mid = idx_first + std::min(first_to_last, last_to_end);
+ auto const mid = idx_first + (std::min)(first_to_last, last_to_end);
auto idx = idx_first;
while (idx != mid) {
erase(begin() + idx);
@@ -1439,8 +1736,8 @@ public:
}
void rehash(size_t count) {
- count = std::min(count, max_size());
- auto shifts = calc_shifts_for_size(std::max(count, size()));
+ count = (std::min)(count, max_size());
+ auto shifts = calc_shifts_for_size((std::max)(count, size()));
if (shifts != m_shifts) {
m_shifts = shifts;
deallocate_buckets();
@@ -1451,12 +1748,12 @@ public:
}
void reserve(size_t capa) {
- capa = std::min(capa, max_size());
+ capa = (std::min)(capa, max_size());
if constexpr (has_reserve<value_container_type>) {
// std::deque doesn't have reserve(). Make sure we only call when available
m_values.reserve(capa);
}
- auto shifts = calc_shifts_for_size(std::max(capa, size()));
+ auto shifts = calc_shifts_for_size((std::max)(capa, size()));
if (0 == m_num_buckets || shifts < m_shifts) {
m_shifts = shifts;
deallocate_buckets();
@@ -1519,16 +1816,31 @@ template <class Key,
class KeyEqual = std::equal_to<Key>,
class AllocatorOrContainer = std::allocator<std::pair<Key, T>>,
class Bucket = bucket_type::standard>
-using map = detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket>;
+using map = detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, false>;
+
+template <class Key,
+ class T,
+ class Hash = hash<Key>,
+ class KeyEqual = std::equal_to<Key>,
+ class AllocatorOrContainer = std::allocator<std::pair<Key, T>>,
+ class Bucket = bucket_type::standard>
+using segmented_map = detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, true>;
+
+template <class Key,
+ class Hash = hash<Key>,
+ class KeyEqual = std::equal_to<Key>,
+ class AllocatorOrContainer = std::allocator<Key>,
+ class Bucket = bucket_type::standard>
+using set = detail::table<Key, void, Hash, KeyEqual, AllocatorOrContainer, Bucket, false>;
template <class Key,
class Hash = hash<Key>,
class KeyEqual = std::equal_to<Key>,
class AllocatorOrContainer = std::allocator<Key>,
class Bucket = bucket_type::standard>
-using set = detail::table<Key, void, Hash, KeyEqual, AllocatorOrContainer, Bucket>;
+using segmented_set = detail::table<Key, void, Hash, KeyEqual, AllocatorOrContainer, Bucket, true>;
-# if ANKERL_UNORDERED_DENSE_PMR
+# if defined(ANKERL_UNORDERED_DENSE_PMR)
namespace pmr {
@@ -1537,10 +1849,23 @@ template <class Key,
class Hash = hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Bucket = bucket_type::standard>
-using map = detail::table<Key, T, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR<std::pair<Key, T>>, Bucket>;
+using map =
+ detail::table<Key, T, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<std::pair<Key, T>>, Bucket, false>;
+
+template <class Key,
+ class T,
+ class Hash = hash<Key>,
+ class KeyEqual = std::equal_to<Key>,
+ class Bucket = bucket_type::standard>
+using segmented_map =
+ detail::table<Key, T, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<std::pair<Key, T>>, Bucket, true>;
+
+template <class Key, class Hash = hash<Key>, class KeyEqual = std::equal_to<Key>, class Bucket = bucket_type::standard>
+using set = detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<Key>, Bucket, false>;
template <class Key, class Hash = hash<Key>, class KeyEqual = std::equal_to<Key>, class Bucket = bucket_type::standard>
-using set = detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR<Key>, Bucket>;
+using segmented_set =
+ detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<Key>, Bucket, true>;
} // namespace pmr
@@ -1558,11 +1883,18 @@ using set = detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR_
namespace std { // NOLINT(cert-dcl58-cpp)
-template <class Key, class T, class Hash, class KeyEqual, class AllocatorOrContainer, class Bucket, class Pred>
+template <class Key,
+ class T,
+ class Hash,
+ class KeyEqual,
+ class AllocatorOrContainer,
+ class Bucket,
+ class Pred,
+ bool IsSegmented>
// NOLINTNEXTLINE(cert-dcl58-cpp)
-auto erase_if(ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket>& map, Pred pred)
- -> size_t {
- using map_t = ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket>;
+auto erase_if(ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, IsSegmented>& map,
+ Pred pred) -> size_t {
+ using map_t = ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, IsSegmented>;
// going back to front because erase() invalidates the end iterator
auto const old_size = map.size();
@@ -1575,7 +1907,7 @@ auto erase_if(ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, All
}
}
- return map.size() - old_size;
+ return old_size - map.size();
}
} // namespace std
diff --git a/misc/benchmarks/external/emhash/hash_table7.hpp b/misc/benchmarks/external/emhash/hash_table7.hpp
index 8f8982f9..41970d8c 100644
--- a/misc/benchmarks/external/emhash/hash_table7.hpp
+++ b/misc/benchmarks/external/emhash/hash_table7.hpp
@@ -92,7 +92,7 @@ of resizing granularity. Ignoring variance, the expected occurrences of list siz
#include "wyhash.h"
#endif
-#ifdef EMH_KEY
+#ifdef EMH_NEW
#undef EMH_KEY
#undef EMH_VAL
#undef EMH_PKV
@@ -547,10 +547,10 @@ public:
static PairT* alloc_bucket(size_type num_buckets)
{
-#if _WIN32
- auto* new_pairs = (PairT*)malloc(AllocSize(num_buckets));
-#else
+#ifdef EMH_ALLOC
auto* new_pairs = (PairT*)aligned_alloc(EMH_MALIGN, AllocSize(num_buckets));
+#else
+ auto* new_pairs = (PairT*)malloc(AllocSize(num_buckets));
#endif
return new_pairs;
}
@@ -1668,16 +1668,10 @@ private:
// key is not in this map. Find a place to put it.
size_type find_empty_bucket(const size_type bucket_from, const size_type main_bucket)
{
-#ifdef EMH_ALIGN64 // only works 64bit
- const auto boset = bucket_from % MASK_BIT;
- auto* const align = _bitmask + bucket_from / MASK_BIT;
- const auto bmask = ((size_t)align[1] << (MASK_BIT - boset)) | (align[0] >> boset);
- if (EMH_LIKELY(bmask != 0))
- return bucket_from + CTZ(bmask);
-#elif EMH_ITER_SAFE
+#if EMH_ITER_SAFE
const auto boset = bucket_from % 8;
- auto* const start = (uint8_t*)_bitmask + bucket_from / 8;
- size_t bmask; memcpy(&bmask, start + 0, sizeof(bmask)); bmask >>= boset;// bmask |= ((size_t)start[8] << (SIZE_BIT - boset));
+ auto* const align = (uint8_t*)_bitmask + bucket_from / 8;(void)main_bucket;
+ size_t bmask; memcpy(&bmask, align + 0, sizeof(bmask)); bmask >>= boset;// bmask |= ((size_t)align[8] << (SIZE_BIT - boset));
if (EMH_LIKELY(bmask != 0))
return bucket_from + CTZ(bmask);
#else
@@ -1715,21 +1709,15 @@ private:
}
// key is not in this map. Find a place to put it.
- size_type find_unique_empty(const size_type bucket_from, const size_t main_bucket)
- {
-#ifdef EMH_ALIGN64
- const auto boset = bucket_from % MASK_BIT;
- auto* const align = _bitmask + bucket_from / MASK_BIT;
- const auto bmask = ((size_t)align[1] << (MASK_BIT - boset)) | (align[0] >> boset);
- static_assert(sizeof(size_t) > 4);
-#elif EMH_ITER_SAFE
+ size_type find_unique_empty(const size_type bucket_from)
+ {
const auto boset = bucket_from % 8;
- auto* const start = (uint8_t*)_bitmask + bucket_from / 8;
- size_t bmask; memcpy(&bmask, start + 0, sizeof(bmask)); bmask >>= boset;
-#else
- const auto boset = bucket_from % 8; (void)main_bucket;
auto* const align = (uint8_t*)_bitmask + bucket_from / 8;
- const auto bmask = (*(size_t*)(align) >> boset); //maybe not aligned and warning
+
+#if EMH_ITER_SAFE
+ size_t bmask; memcpy(&bmask, align + 0, sizeof(bmask)); bmask >>= boset;
+#else
+ const auto bmask = (*(size_t*)(align) >> boset); //maybe not aligned and warning
#endif
if (EMH_LIKELY(bmask != 0))
return bucket_from + CTZ(bmask);
@@ -1789,12 +1777,12 @@ private:
next_bucket = find_last_bucket(next_bucket);
//find a new empty and link it to tail
- return EMH_BUCKET(_pairs, next_bucket) = find_unique_empty(next_bucket, bucket);
+ return EMH_BUCKET(_pairs, next_bucket) = find_empty_bucket(next_bucket, bucket);
}
#if EMH_INT_HASH
static constexpr uint64_t KC = UINT64_C(11400714819323198485);
- inline uint64_t hash64(uint64_t key)
+ inline static uint64_t hash64(uint64_t key)
{
#if __SIZEOF_INT128__ && EMH_INT_HASH == 1
__uint128_t r = key; r *= KC;
diff --git a/misc/benchmarks/plotbench/cdeq_benchmark.cpp b/misc/benchmarks/plotbench/cdeq_benchmark.cpp
index bb0e28c8..d11b4103 100644
--- a/misc/benchmarks/plotbench/cdeq_benchmark.cpp
+++ b/misc/benchmarks/plotbench/cdeq_benchmark.cpp
@@ -9,10 +9,10 @@
#endif
enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+const char* operations[] = {"insert", "erase", "access", "iter", "destruct"};
typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 50000000, S = 0x3ffc, R = 4};
+enum {SAMPLES = 2, N = 60000000, R = 4};
uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
@@ -44,14 +44,12 @@ Sample test_std_deque() {
c_forrange (N) con.push_back(crand() & mask2);
s.test[FIND].t1 = clock();
size_t sum = 0;
- // Iteration - not inherent find - skipping
- //container::iterator it;
- //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crand() & mask2)) != con.end()) sum += *it;
+ c_forrange (R) c_forrange (i, N) sum += con[i];
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con[i];
+ c_forrange (R) for (const auto i: con) sum += i;
s.test[ITER].t2 = clock();
s.test[ITER].sum = sum;
s.test[DESTRUCT].t1 = clock();
@@ -89,13 +87,12 @@ Sample test_stc_deque() {
c_forrange (N) cdeq_x_push_back(&con, crand() & mask2);
s.test[FIND].t1 = clock();
size_t sum = 0;
- //cdeq_x_iter it, end = cdeq_x_end(&con);
- //c_forrange (S) if ((it = cdeq_x_find(&con, crand() & mask2)).ref != end.ref) sum += *it.ref;
+ c_forrange (R) c_forrange (i, N) sum += *cdeq_x_at(&con, i);
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con.data[i];
+ c_forrange (R) c_foreach (i, cdeq_x, con) sum += *i.ref;
s.test[ITER].t2 = clock();
s.test[ITER].sum = sum;
s.test[DESTRUCT].t1 = clock();
diff --git a/misc/benchmarks/plotbench/clist_benchmark.cpp b/misc/benchmarks/plotbench/clist_benchmark.cpp
index 01bfbf83..8fdfddba 100644
--- a/misc/benchmarks/plotbench/clist_benchmark.cpp
+++ b/misc/benchmarks/plotbench/clist_benchmark.cpp
@@ -9,10 +9,10 @@
#endif
enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+const char* operations[] = {"insert", "erase", "access", "iter", "destruct"};
typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 10000000, S = 0x3ffc, R = 4};
+enum {SAMPLES = 2, N = 10000000, R = 4};
uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
@@ -45,7 +45,6 @@ Sample test_std_forward_list() {
size_t sum = 0;
container::iterator it;
// Iteration - not inherent find - skipping
- //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crand() & mask2)) != con.end()) sum += *it;
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
@@ -86,8 +85,7 @@ Sample test_stc_forward_list() {
c_forrange (N) clist_x_push_front(&con, crand() & mask2);
s.test[FIND].t1 = clock();
size_t sum = 0;
- //clist_x_iter it, end = clist_x_end(&con);
- //c_forrange (S) if ((it = clist_x_find(&con, crand() & mask2)).ref != end.ref) sum += *it.ref;
+ //clist iteration - skipping
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
diff --git a/misc/benchmarks/plotbench/cmap_benchmark.cpp b/misc/benchmarks/plotbench/cmap_benchmark.cpp
index 6b2edbd7..c7957bb7 100644
--- a/misc/benchmarks/plotbench/cmap_benchmark.cpp
+++ b/misc/benchmarks/plotbench/cmap_benchmark.cpp
@@ -8,7 +8,7 @@
#endif
enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+const char* operations[] = {"insert", "erase", "access", "iter", "destruct"};
typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
typedef struct { const char* name; Range test[N_TESTS]; } Sample;
enum {SAMPLES = 2, N = 2000000, R = 4};
@@ -47,12 +47,14 @@ Sample test_std_unordered_map() {
s.test[FIND].t1 = clock();
size_t sum = 0;
container::iterator it;
- c_forrange (N) if ((it = con.find(crand() & mask1)) != con.end()) sum += it->second;
+ c_forrange (N)
+ if ((it = con.find(crand() & mask1)) != con.end())
+ sum += it->second;
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
sum = 0;
- c_forrange (R) for (auto i: con) sum += i.second;
+ c_forrange (R) for (const auto& i: con) sum += i.second;
s.test[ITER].t2 = clock();
s.test[ITER].sum = sum;
s.test[DESTRUCT].t1 = clock();
diff --git a/misc/benchmarks/plotbench/cpque_benchmark.cpp b/misc/benchmarks/plotbench/cpque_benchmark.cpp
index 2d4c7a28..aafc9eb0 100644
--- a/misc/benchmarks/plotbench/cpque_benchmark.cpp
+++ b/misc/benchmarks/plotbench/cpque_benchmark.cpp
@@ -37,7 +37,8 @@ void stc_test()
{
int N = 10000000;
- c_auto (cpque_f, pq)
+ cpque_f pq = {0};
+ c_defer(cpque_f_drop(&pq))
{
csrand(seed);
clock_t start = clock();
@@ -58,7 +59,7 @@ void stc_test()
}
-int main()
+int main(void)
{
puts("STD P.QUEUE:");
std_test();
diff --git a/misc/benchmarks/plotbench/csmap_benchmark.cpp b/misc/benchmarks/plotbench/csmap_benchmark.cpp
index 60f2db49..480163ed 100644
--- a/misc/benchmarks/plotbench/csmap_benchmark.cpp
+++ b/misc/benchmarks/plotbench/csmap_benchmark.cpp
@@ -8,7 +8,7 @@
#endif
enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+const char* operations[] = {"insert", "erase", "access", "iter", "destruct"};
typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
typedef struct { const char* name; Range test[N_TESTS]; } Sample;
enum {SAMPLES = 2, N = 1000000, R = 4};
@@ -47,12 +47,14 @@ Sample test_std_map() {
s.test[FIND].t1 = clock();
size_t sum = 0;
container::iterator it;
- c_forrange (N) if ((it = con.find(crand() & mask1)) != con.end()) sum += it->second;
+ c_forrange (N)
+ if ((it = con.find(crand() & mask1)) != con.end())
+ sum += it->second;
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
sum = 0;
- c_forrange (R) for (auto i: con) sum += i.second;
+ c_forrange (R) for (const auto& i: con) sum += i.second;
s.test[ITER].t2 = clock();
s.test[ITER].sum = sum;
s.test[DESTRUCT].t1 = clock();
diff --git a/misc/benchmarks/plotbench/cvec_benchmark.cpp b/misc/benchmarks/plotbench/cvec_benchmark.cpp
index c488a01c..fb10653a 100644
--- a/misc/benchmarks/plotbench/cvec_benchmark.cpp
+++ b/misc/benchmarks/plotbench/cvec_benchmark.cpp
@@ -9,10 +9,10 @@
#endif
enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+const char* operations[] = {"insert", "erase", "access", "iter", "destruct"};
typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 80000000, S = 0x3ffc, R = 4};
+enum {SAMPLES = 2, N = 60000000, R = 4};
uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
@@ -42,14 +42,12 @@ Sample test_std_vector() {
c_forrange (N) con.push_back(crand() & mask2);
s.test[FIND].t1 = clock();
size_t sum = 0;
- //container::iterator it;
- // Iteration - not inherent find - skipping
- //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crand() & mask2)) != con.end()) sum += *it;
+ c_forrange (R) c_forrange (i, N) sum += con[i];
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con[i];
+ c_forrange (R) for (const auto i: con) sum += i;
s.test[ITER].t2 = clock();
s.test[ITER].sum = sum;
s.test[DESTRUCT].t1 = clock();
@@ -71,27 +69,26 @@ 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);
- //c_forrange (S) if ((it = cvec_x_find(&con, crand() & mask2)).ref != end.ref) sum += *it.ref;
+ c_forrange (R) c_forrange (i, N) sum += con.data[i];
s.test[FIND].t2 = clock();
s.test[FIND].sum = sum;
s.test[ITER].t1 = clock();
sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con.data[i];
+ c_forrange (R) c_foreach (i, cvec_x, con) sum += *i.ref;
s.test[ITER].t2 = clock();
s.test[ITER].sum = sum;
s.test[DESTRUCT].t1 = clock();
diff --git a/misc/benchmarks/plotbench/plot.py b/misc/benchmarks/plotbench/plot.py
index 0ba92264..4a02c6b2 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)
@@ -12,13 +12,12 @@ df = df[df.Method != 'total']
if n > 0:
df = df[df.Compiler == comp[n]]
-g = sns.catplot(data=df, x='Method', y='Seconds', hue='Library', col='C', kind='bar',
- ci=68, legend=False, col_wrap=2, sharex=False, aspect=1.4, height=3.1)
+g = sns.catplot(data=df, x='Method', y='Seconds', hue='Library', col='C', kind='bar', orient='v',
+ errorbar=('ci', 68), legend=False, col_wrap=2, sharex=False, aspect=1.4, height=3.0)
g.set_xlabels('')
-g.add_legend(bbox_to_anchor=(0.75, 0.2), borderaxespad=0.)
-
-g.fig.subplots_adjust(top=0.90, left=0.06, bottom=0.07)
+g.add_legend(bbox_to_anchor=(0.75, 0.2), borderaxespad=0)
+g.fig.subplots_adjust(top=0.90, left=0.08, right=0.98, bottom=0.04, hspace=0.4)
g.fig.suptitle('Benchmark STC vs c++ std containers: %s' % comp[n], fontsize=15, y=0.98)
plt.show()
diff --git a/misc/benchmarks/plotbench/run_all.bat b/misc/benchmarks/plotbench/run_all.bat
index 98913a50..de380531 100644
--- a/misc/benchmarks/plotbench/run_all.bat
+++ b/misc/benchmarks/plotbench/run_all.bat
@@ -1,7 +1,5 @@
-set out=plot_win.csv
+@set out=plot_win.csv
echo Compiler,Library,C,Method,Seconds,Ratio> %out%
-echo gcc
sh run_gcc.sh >> %out%
-echo clang
sh run_clang.sh >> %out%
-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 096e71be..4f649cbc 100644
--- a/misc/benchmarks/plotbench/run_clang.sh
+++ b/misc/benchmarks/plotbench/run_clang.sh
@@ -1,12 +1,12 @@
exe=''
if [ "$OS" = "Windows_NT" ] ; then exe=".exe" ; fi
-clang++ -I../include -O3 -o cdeq_benchmark$exe cdeq_benchmark.cpp
-clang++ -I../include -O3 -o clist_benchmark$exe clist_benchmark.cpp
-clang++ -I../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp
-clang++ -I../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp
-clang++ -I../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp
+clang -DNDEBUG -I../../include -O3 -o cdeq_benchmark$exe cdeq_benchmark.cpp -lstdc++
+clang -DNDEBUG -I../../include -O3 -o clist_benchmark$exe clist_benchmark.cpp -lstdc++
+clang -DNDEBUG -I../../include -O3 -o cmap_benchmark$exe cmap_benchmark.cpp -lstdc++
+clang -DNDEBUG -I../../include -O3 -o csmap_benchmark$exe csmap_benchmark.cpp -lstdc++
+clang -DNDEBUG -I../../include -O3 -o cvec_benchmark$exe cvec_benchmark.cpp -lstdc++
-c='Win-Clang-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 5249ed1e..0bd2d6ee 100644
--- a/misc/benchmarks/plotbench/run_gcc.sh
+++ b/misc/benchmarks/plotbench/run_gcc.sh
@@ -1,10 +1,10 @@
-g++ -I../include -O3 -o cdeq_benchmark cdeq_benchmark.cpp
-g++ -I../include -O3 -o clist_benchmark clist_benchmark.cpp
-g++ -I../include -O3 -o cmap_benchmark cmap_benchmark.cpp
-g++ -I../include -O3 -o csmap_benchmark csmap_benchmark.cpp
-g++ -I../include -O3 -o cvec_benchmark cvec_benchmark.cpp
+g++ -DNDEBUG -I../../include -O3 -o cdeq_benchmark cdeq_benchmark.cpp
+g++ -DNDEBUG -I../../include -O3 -o clist_benchmark clist_benchmark.cpp
+g++ -DNDEBUG -I../../include -O3 -o cmap_benchmark cmap_benchmark.cpp
+g++ -DNDEBUG -I../../include -O3 -o csmap_benchmark csmap_benchmark.cpp
+g++ -DNDEBUG -I../../include -O3 -o cvec_benchmark cvec_benchmark.cpp
-c='Mingw-g++-11.3.0'
+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..c00d059b 100644
--- a/misc/benchmarks/plotbench/run_vc.bat
+++ b/misc/benchmarks/plotbench/run_vc.bat
@@ -1,14 +1,14 @@
@echo off
-if "%VSINSTALLDIR%"=="" call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" >nul
+if "%VSINSTALLDIR%"=="" call "C:\Program Files (x86)\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" >nul
cl.exe -nologo -EHsc -std:c++latest -I../include -O2 cdeq_benchmark.cpp >nul
cl.exe -nologo -EHsc -std:c++latest -I../include -O2 clist_benchmark.cpp >nul
cl.exe -nologo -EHsc -std:c++latest -I../include -O2 cmap_benchmark.cpp >nul
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/shootout_hashmaps.cpp b/misc/benchmarks/shootout_hashmaps.cpp
index bae9a42b..c6a81777 100644
--- a/misc/benchmarks/shootout_hashmaps.cpp
+++ b/misc/benchmarks/shootout_hashmaps.cpp
@@ -2,7 +2,7 @@
#include <time.h>
#include <stc/crand.h>
-#define MAX_LOAD_FACTOR 85
+#define MAX_LOAD_FACTOR 80
#ifdef __cplusplus
#include <limits>
@@ -35,8 +35,8 @@ KHASH_MAP_INIT_INT64(ii, IValue)
// cmap template expansion
#define i_key IKey
#define i_val IValue
-#define i_ssize int32_t // enable 2^K buckets like the rest.
#define i_tag ii
+//#define i_expandby 1
#define i_max_load_factor MAX_LOAD_FACTOR / 100.0f
#include <stc/cmap.h>
diff --git a/misc/benchmarks/various/csort_bench.c b/misc/benchmarks/various/csort_bench.c
index d5d7fa7c..793a0503 100644
--- a/misc/benchmarks/various/csort_bench.c
+++ b/misc/benchmarks/various/csort_bench.c
@@ -5,8 +5,12 @@
#ifdef __cplusplus
#include <algorithm>
#endif
-#define i_val int
-#include <stc/algo/csort.h>
+#define NDEBUG
+#define i_type Ints
+#define i_key int
+#define i_more
+#include <stc/cvec.h>
+#include <stc/algo/sort.h>
#define ROTL(d,bits) ((d<<(bits)) | (d>>(8*sizeof(d)-(bits))))
uint64_t romutrio(uint64_t s[3]) {
@@ -21,14 +25,14 @@ static int cmp_int(const void* a, const void* b) {
return c_default_cmp((const int*)a, (const int*)b);
}
-void testsort(int *a, int size, const char *desc) {
+void testsort(Ints *a, int size, const char *desc) {
clock_t t = clock();
#ifdef __cplusplus
- printf("std::sort: "); std::sort(a, a + size);
+ printf("std::sort: "); std::sort(a->data, a->data + size);
#elif defined QSORT
- printf("qsort: "); qsort(a, size, sizeof *a, cmp_int);
+ printf("qsort: "); qsort(a->data, size, sizeof *a->data, cmp_int);
#else
- printf("stc_sort: "); csort_int(a, size);
+ printf("STC sort_n: "); Ints_sort_n(a, size);
#endif
t = clock() - t;
@@ -41,27 +45,27 @@ int main(int argc, char *argv[]) {
size_t i, size = argc > 1 ? strtoull(argv[1], NULL, 0) : 10000000;
uint64_t s[3] = {123456789, 3456789123, 789123456};
- int32_t *a = (int32_t*)malloc(sizeof(*a) * size);
- if (!a) return -1;
+ Ints a = Ints_with_capacity(size);
for (i = 0; i < size; i++)
- a[i] = romutrio(s) & (1U << 30) - 1;
- testsort(a, size, "random");
+ Ints_push(&a, romutrio(s) & (1U << 30) - 1);
+ testsort(&a, size, "random");
for (i = 0; i < 20; i++)
- printf(" %d", (int)a[i]);
+ printf(" %d", (int)*Ints_at(&a, i));
puts("");
for (i = 0; i < size; i++)
- a[i] = i;
- testsort(a, size, "sorted");
+ *Ints_at_mut(&a, i) = i;
+ testsort(&a, size, "sorted");
for (i = 0; i < size; i++)
- a[i] = size - i;
- testsort(a, size, "reverse sorted");
+ *Ints_at_mut(&a, i) = size - i;
+ testsort(&a, size, "reverse sorted");
for (i = 0; i < size; i++)
- a[i] = 126735;
- testsort(a, size, "constant");
+ *Ints_at_mut(&a, i) = 126735;
+ testsort(&a, size, "constant");
for (i = 0; i < size; i++)
- a[i] = i + 1;
- a[size - 1] = 0;
- testsort(a, size, "rotated");
- free(a);
+ *Ints_at_mut(&a, i) = i + 1;
+ *Ints_at_mut(&a, size - 1) = 0;
+ testsort(&a, size, "rotated");
+
+ Ints_drop(&a);
}
diff --git a/misc/benchmarks/various/cspan_bench.c b/misc/benchmarks/various/cspan_bench.c
index 589df13a..bfc0ead3 100644
--- a/misc/benchmarks/various/cspan_bench.c
+++ b/misc/benchmarks/various/cspan_bench.c
@@ -1,4 +1,5 @@
-#define STC_NDEBUG
+// ref: https://stackoverflow.com/questions/74382366/why-is-iterating-over-stdrangesviewsjoin-so-slow
+#define NDEBUG
#include <stc/cspan.h>
#include <stdio.h>
#include <time.h>
@@ -11,9 +12,9 @@ enum {
ny = 64,
nz = 64
};
+// subspan 15x5x10:
int lx = 15, ly = 10, lz = 5;
-int hx = 20, hy = 15, hz = 15;
-intptr_t n = 1000000;
+int hx = 30, hy = 15, hz = 15;
// define the contents of two nx x ny x nz arrays in and out
double Vout[nx * ny * nz];
@@ -21,36 +22,15 @@ double Vin[nx * ny * nz]; //, 1.23;
// define some slice indices for each dimension
-static void MDRanges_setup(intptr_t state)
-{
- double sum = 0;
- clock_t t = clock();
-
- for (intptr_t s = 0; s < state; ++s)
- {
- MD3 r_in = cspan_md(Vin, nx, ny, nz);
- MD3 r_out = cspan_md(Vout, nx, ny, nz);
-
- r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz});
- r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz});
- MD3_iter i = MD3_begin(&r_in); // can be iterated "flat".
- MD3_iter o = MD3_begin(&r_out);
- sum += Vin[s % nx];
- }
- t = clock() - t;
- printf("setup: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum);
-}
-
-static void TraditionalForLoop(intptr_t state)
+static void Traditional_for_loop(intptr_t n)
{
clock_t t = clock();
double sum = 0;
- for (int s = 0; s < state; ++s) {
+ for (int s = 0; s < n; ++s) {
for (int x = lx; x < hx; ++x) {
for (int y = ly; y < hy; ++y) {
- for (int z = lz; z < hz; ++z)
- {
+ for (int z = lz; z < hz; ++z) {
double d = Vin[nz*(ny*x + y) + z];
Vout[nz*(ny*x + y) + z] += d;
sum += d;
@@ -59,68 +39,65 @@ static void TraditionalForLoop(intptr_t state)
}
}
t = clock() - t;
- printf("forloop: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum);
+ printf("forloop : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum);
}
-static void MDRanges_nested_loop(intptr_t state)
+static void MDRanges_loop_over_joined(intptr_t n)
{
+ clock_t t = clock();
MD3 r_in = cspan_md(Vin, nx, ny, nz);
MD3 r_out = cspan_md(Vout, nx, ny, nz);
r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz});
r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz});
-
- // C++23: for (auto [o, i] : std::views::zip(flat(r_out), flat(r_in))) { o = i; }
- clock_t t = clock();
double sum = 0;
- for (intptr_t s = 0; s < state; ++s) {
- for (int x = 0; x < r_in.shape[0]; ++x) {
- for (int y = 0; y < r_in.shape[1]; ++y) {
- for (int z = 0; z < r_in.shape[2]; ++z)
- {
- double d = *cspan_at(&r_in, x, y, z);
- *cspan_at(&r_out, x, y, z) += d;
- sum += d;
- }
- }
+ for (intptr_t s = 0; s < n; ++s) {
+ MD3_iter i = MD3_begin(&r_in);
+ MD3_iter o = MD3_begin(&r_out);
+
+ for (; i.ref; MD3_next(&i), MD3_next(&o))
+ {
+ *o.ref += *i.ref;
+ sum += *i.ref;
}
}
t = clock() - t;
- printf("nested: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum);
+ printf("joined : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum);
}
-static void MDRanges_loop_over_joined(intptr_t state)
+static void MDRanges_nested_loop(intptr_t n)
{
+ clock_t t = clock();
MD3 r_in = cspan_md(Vin, nx, ny, nz);
MD3 r_out = cspan_md(Vout, nx, ny, nz);
r_in = cspan_slice(MD3, &r_in, {lx, hx}, {ly, hy}, {lz, hz});
r_out = cspan_slice(MD3, &r_out, {lx, hx}, {ly, hy}, {lz, hz});
-
- // C++23: for (auto [o, i] : std::views::zip(flat(r_out), flat(r_in))) { o = i; }
double sum = 0;
- clock_t t = clock();
-
- for (intptr_t s = 0; s < state; ++s) {
- MD3_iter i = MD3_begin(&r_in);
- MD3_iter o = MD3_begin(&r_out);
- for (; i.ref; MD3_next(&i), MD3_next(&o))
- {
- *o.ref += *i.ref;
- sum += *i.ref;
+ for (intptr_t s = 0; s < n; ++s) {
+ for (int x = 0; x < r_in.shape[0]; ++x) {
+ for (int y = 0; y < r_in.shape[1]; ++y) {
+ for (int z = 0; z < r_in.shape[2]; ++z)
+ {
+ double d = *cspan_at(&r_in, x,y,z);
+ *cspan_at(&r_out, x,y,z) += d;
+ sum += d;
+ }
+ }
}
}
t = clock() - t;
- printf("joined: %.1f ms, %f\n", 1000.0f * t / CLOCKS_PER_SEC, sum);
+ printf("nested : %.1f ms, %f\n", 1000.0f*t / CLOCKS_PER_SEC, sum);
}
-int main()
+
+int main(void)
{
+ intptr_t n = 100000;
for (int i = 0; i < nx * ny * nz; ++i)
Vin[i] = i + 1.23;
- MDRanges_setup(n);
- TraditionalForLoop(n);
- MDRanges_nested_loop(n);
+ Traditional_for_loop(n);
MDRanges_loop_over_joined(n);
+ MDRanges_nested_loop(n);
}
diff --git a/misc/benchmarks/various/prng_bench.cpp b/misc/benchmarks/various/prng_bench.cpp
index 234e3805..45c14d18 100644
--- a/misc/benchmarks/various/prng_bench.cpp
+++ b/misc/benchmarks/various/prng_bench.cpp
@@ -66,7 +66,7 @@ uint32_t pcg32(uint32_t s[2]) {
}
-/* xoshiro128+ */
+/* xo(ro)shiro */
uint64_t xoroshiro128plus(uint64_t s[2]) {
const uint64_t s0 = s[0];
@@ -80,9 +80,6 @@ uint64_t xoroshiro128plus(uint64_t s[2]) {
return result;
}
-
-/* xoshiro256** */
-
static inline uint64_t xoshiro256starstar(uint64_t s[4]) {
const uint64_t result = rotl64(s[1] * 5, 7) * 9;
const uint64_t t = s[1] << 17;
@@ -95,7 +92,7 @@ static inline uint64_t xoshiro256starstar(uint64_t s[4]) {
return result;
}
-// wyrand - 2020-12-07
+/* wyrand - 2020-12-07 */
static inline void _wymum(uint64_t *A, uint64_t *B){
#if defined(__SIZEOF_INT128__)
__uint128_t r = *A; r *= *B;
@@ -136,44 +133,44 @@ int main(void)
for (size_t ti = 0; ti < 2; ti++) {
init_state(rng.state, 12345123);
cout << endl << "ROUND " << ti+1 << " ---------" << endl;
-
+/*
beg = clock();
for (size_t i = 0; i < N; i++)
- recipient[i] = romu_trio(rng.state);
+ recipient[i] = sfc32((uint32_t *)rng.state);
end = clock();
- cout << "romu_trio:\t"
+ cout << "sfc32:\t\t"
<< (float(end - beg) / CLOCKS_PER_SEC)
<< "s: " << recipient[312] << endl;
beg = clock();
for (size_t i = 0; i < N; i++)
- recipient[i] = wyrand64(rng.state);
+ recipient[i] = stc32((uint32_t *)rng.state);
end = clock();
- cout << "wyrand64:\t"
+ cout << "stc32:\t\t"
<< (float(end - beg) / CLOCKS_PER_SEC)
<< "s: " << recipient[312] << endl;
beg = clock();
for (size_t i = 0; i < N; i++)
- recipient[i] = sfc32((uint32_t *)rng.state);
+ recipient[i] = pcg32((uint32_t *)rng.state);
end = clock();
- cout << "sfc32:\t\t"
+ cout << "pcg32:\t\t"
<< (float(end - beg) / CLOCKS_PER_SEC)
<< "s: " << recipient[312] << endl;
-
+*/
beg = clock();
for (size_t i = 0; i < N; i++)
- recipient[i] = stc32((uint32_t *)rng.state);
+ recipient[i] = romu_trio(rng.state);
end = clock();
- cout << "stc32:\t\t"
+ cout << "romu_trio:\t"
<< (float(end - beg) / CLOCKS_PER_SEC)
<< "s: " << recipient[312] << endl;
beg = clock();
for (size_t i = 0; i < N; i++)
- recipient[i] = pcg32((uint32_t *)rng.state);
+ recipient[i] = wyrand64(rng.state);
end = clock();
- cout << "pcg32:\t\t"
+ cout << "wyrand64:\t"
<< (float(end - beg) / CLOCKS_PER_SEC)
<< "s: " << recipient[312] << endl;
@@ -189,7 +186,7 @@ int main(void)
for (size_t i = 0; i < N; i++)
recipient[i] = crand_u64(&rng);
end = clock();
- cout << "stc64:\t\t"
+ cout << "crand64:\t"
<< (float(end - beg) / CLOCKS_PER_SEC)
<< "s: " << recipient[312] << endl;
diff --git a/misc/benchmarks/various/rust_cmap.c b/misc/benchmarks/various/rust_cmap.c
index abdb42b0..97047e0b 100644
--- a/misc/benchmarks/various/rust_cmap.c
+++ b/misc/benchmarks/various/rust_cmap.c
@@ -22,7 +22,7 @@ uint64_t romu_trio(uint64_t s[3]) {
return xp;
}
-int main()
+int main(void)
{
cmap_u64 m = {0};
diff --git a/misc/benchmarks/various/sso_bench.cpp b/misc/benchmarks/various/sso_bench.cpp
index 993ff1bb..244c1291 100644
--- a/misc/benchmarks/various/sso_bench.cpp
+++ b/misc/benchmarks/various/sso_bench.cpp
@@ -3,65 +3,82 @@
#include <chrono>
#include <stc/crand.h>
+#define i_static
#include <stc/cstr.h>
#define i_type StcVec
#define i_val_str
#include <stc/cstack.h>
-#define i_type StcSet
-#define i_val_str
-#include <stc/csset.h>
-
#include <vector>
using StdVec = std::vector<std::string>;
-#include <set>
-using StdSet = std::set<std::string>;
-static const int BENCHMARK_SIZE = 2000000;
-static const int MAX_STRING_SIZE = 50;
+#include <unordered_set>
+#include "../external/ankerl/robin_hood.h"
+
+struct string_hash {
+ using is_transparent = void;
+ [[nodiscard]] size_t operator()(const char *txt) const {
+ return std::hash<std::string_view>{}(txt);
+ }
+ [[nodiscard]] size_t operator()(std::string_view txt) const {
+ return std::hash<std::string_view>{}(txt);
+ }
+ [[nodiscard]] size_t operator()(const std::string &txt) const {
+ return std::hash<std::string>{}(txt);
+ }
+};
+using StdSet = robin_hood::unordered_flat_set<std::string, string_hash, std::equal_to<>>;
+//using StdSet = std::unordered_set<std::string>;
+
+#define i_type StcSet
+#define i_val_str
+//#define i_hash(txtp) std::hash<std::string_view>{}(*txtp)
+#include <stc/cset.h>
+
+
+static const int BENCHMARK_SIZE = 250000;
+static const int MAX_STRING_SIZE = 100;
static const char CHARS[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=+-";
using time_point = std::chrono::high_resolution_clock::time_point;
-static inline std::string randomString_STD(int strsize) {
- std::string s(strsize, 0);
- char* p = &s[0];
+static inline const char* randomString(int strsize) {
+ static char str[256];
union { uint64_t u8; uint8_t b[8]; } r;
for (int i = 0; i < strsize; ++i) {
if ((i & 7) == 0) r.u8 = crand() & 0x3f3f3f3f3f3f3f3f;
- p[i] = CHARS[r.b[i & 7]];
+ str[i] = CHARS[r.b[i & 7]];
}
- return s;
+ str[strsize] = 0;
+ return str;
}
-static inline cstr randomString_STC(int strsize) {
- cstr s = cstr_with_size(strsize, 0);
- char* p = cstr_data(&s);
- union { uint64_t u8; uint8_t b[8]; } r;
- for (int i = 0; i < strsize; ++i) {
- if ((i & 7) == 0) r.u8 = crand() & 0x3f3f3f3f3f3f3f3f;
- p[i] = CHARS[r.b[i & 7]];
- }
- return s;
+
+
+static inline void addRandomString(StdVec& vec, const char* str) {
+ vec.push_back(str);
}
+static inline void addRandomString(StcVec& vec, const char* str) {
+ StcVec_emplace(&vec, str);
+}
-void addRandomString(StdVec& vec, int strsize) {
- vec.push_back(std::move(randomString_STD(strsize)));
+static inline void addRandomString(StdSet& set, const char* str) {
+ set.insert(str);
}
-void addRandomString(StcVec& vec, int strsize) {
- StcVec_push(&vec, randomString_STC(strsize));
+static inline void addRandomString(StcSet& set, const char* str) {
+ StcSet_emplace(&set, str);
}
-void addRandomString(StdSet& set, int strsize) {
- set.insert(std::move(randomString_STD(strsize)));
+static inline bool getRandomString(const StdSet& set, const char* str) {
+ return set.find(str) != set.end();
}
-void addRandomString(StcSet& set, int strsize) {
- StcSet_insert(&set, randomString_STC(strsize));
+static inline bool getRandomString(const StcSet& set, const char* str) {
+ return StcSet_contains(&set, str);
}
@@ -70,7 +87,7 @@ int benchmark(C& container, const int n, const int strsize) {
time_point t1 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < n; i++)
- addRandomString(container, strsize);
+ addRandomString(container, randomString(strsize));
time_point t2 = std::chrono::high_resolution_clock::now();
const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
@@ -78,9 +95,25 @@ int benchmark(C& container, const int n, const int strsize) {
return (int)duration;
}
+template <class C>
+int benchmark_lookup(C& container, const int n, const int strsize) {
+ for (int i = 0; i < n; i++)
+ addRandomString(container, randomString(strsize));
+
+ time_point t1 = std::chrono::high_resolution_clock::now();
+ int found = 0;
+ for (int i = 0; i < n; i++)
+ found += (int)getRandomString(container, randomString(strsize));
+
+ time_point t2 = std::chrono::high_resolution_clock::now();
+ const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
+ std::cerr << (strsize ? strsize : 32) << "\t" << duration << '\t' << found;
+ return (int)duration;
+}
-int main() {
- uint64_t seed = 4321;
+#include <time.h>
+int main(void) {
+ uint64_t seed = time(NULL); // 4321;
int sum, n;
// VECTOR WITH STRINGS
@@ -88,48 +121,75 @@ int main() {
csrand(seed);
sum = 0, n = 0;
std::cerr << "\nstrsize\tmsecs\tstd::vector<std::string>, size=" << BENCHMARK_SIZE << "\n";
- for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) {
+ for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) {
StdVec vec; vec.reserve(BENCHMARK_SIZE);
sum += benchmark(vec, BENCHMARK_SIZE, strsize), ++n;
std::cout << '\t' << vec.front() << '\n';
}
- std::cout << "Avg:\t" << sum/n << '\n';
+ std::cout << "Avg:\t" << sum/n << "ms\n";
csrand(seed);
sum = 0, n = 0;
std::cerr << "\nstrsize\tmsecs\tcvec<cstr>, size=" << BENCHMARK_SIZE << "\n";
- for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) {
+ for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) {
StcVec vec = StcVec_with_capacity(BENCHMARK_SIZE);
sum += benchmark(vec, BENCHMARK_SIZE, strsize), ++n;
std::cout << '\t' << cstr_str(&vec.data[0]) << '\n';
StcVec_drop(&vec);
}
- std::cout << "Avg:\t" << sum/n << '\n';
+ std::cout << "Avg:\t" << sum/n << "ms\n";
+
+ // INSERT: SORTED SET WITH STRINGS
+
+ csrand(seed);
+ sum = 0, n = 0;
+ std::cerr << "\nstrsize\tmsecs\tinsert: robin_hood::unordered_flat_set<std::string>, size=" << BENCHMARK_SIZE/2 << "\n";
+ for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) {
+ StdSet set; set.reserve(BENCHMARK_SIZE/2);
+ sum += benchmark(set, BENCHMARK_SIZE/2, strsize), ++n;
+ std::cout << '\t' << *set.begin() << '\n';
+ }
+ std::cout << "Avg:\t" << sum/n << "ms\n";
- // SORTED SET WITH STRINGS
csrand(seed);
sum = 0, n = 0;
- std::cerr << "\nstrsize\tmsecs\tstd::set<std::string>, size=" << BENCHMARK_SIZE/16 << "\n";
+ std::cerr << "\nstrsize\tmsecs\tinsert: cset<cstr>, size=" << BENCHMARK_SIZE/2 << "\n";
+ for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 4) {
+ StcSet set = StcSet_with_capacity(BENCHMARK_SIZE/2);
+ sum += benchmark(set, BENCHMARK_SIZE/2, strsize), ++n;
+ std::cout << '\t' << cstr_str(StcSet_begin(&set).ref) << '\n';
+ StcSet_drop(&set);
+ }
+ std::cout << "Avg:\t" << sum/n << "ms\n";
+
+ // LOOKUP: SORTED SET WITH STRINGS
+
+ csrand(seed);
+ sum = 0, n = 0;
+ std::cerr << "\nstrsize\tmsecs\tfind: robin_hood::unordered_flat_set<std::string>, size=" << BENCHMARK_SIZE/2 << "\n";
for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) {
- StdSet set;
- sum += benchmark(set, BENCHMARK_SIZE/16, strsize), ++n;
+ StdSet set; set.reserve(BENCHMARK_SIZE/2);
+ sum += benchmark_lookup(set, BENCHMARK_SIZE/2, strsize), ++n;
std::cout << '\t' << *set.begin() << '\n';
}
- std::cout << "Avg:\t" << sum/n << '\n';
+ std::cout << "Avg:\t" << sum/n << "ms\n";
csrand(seed);
sum = 0, n = 0;
- std::cerr << "\nstrsize\tmsecs\tcsset<cstr>, size=" << BENCHMARK_SIZE/16 << "\n";
+ std::cerr << "\nstrsize\tmsecs\tfind: cset<cstr>, size=" << BENCHMARK_SIZE/2 << "\n";
for (int strsize = 1; strsize <= MAX_STRING_SIZE; strsize += 2) {
- StcSet set = StcSet_with_capacity(BENCHMARK_SIZE/16);
- sum += benchmark(set, BENCHMARK_SIZE/16, strsize), ++n;
- std::cout << '\t' << cstr_str(StcSet_front(&set)) << '\n';
+ StcSet set = StcSet_with_capacity(BENCHMARK_SIZE/2);
+ sum += benchmark_lookup(set, BENCHMARK_SIZE/2, strsize), ++n;
+ std::cout << '\t' << cstr_str(StcSet_begin(&set).ref) << '\n';
StcSet_drop(&set);
}
- std::cout << "Avg:\t" << sum/n << '\n';
+ std::cout << "Avg:\t" << sum/n << "ms\n";
+
std::cerr << "sizeof(std::string) : " << sizeof(std::string) << std::endl
- << "sizeof(cstr) : " << sizeof(cstr) << std::endl;
+ << "sizeof(cstr) : " << sizeof(cstr) << std::endl
+ << "sizeof(StdSet) : " << sizeof(StdSet) << std::endl
+ << "sizeof(StcSet) : " << sizeof(StcSet) << std::endl;
return 0;
}
diff --git a/misc/benchmarks/various/string_bench_STC.cpp b/misc/benchmarks/various/string_bench_STC.cpp
index ae8e4c38..a5dfd901 100644
--- a/misc/benchmarks/various/string_bench_STC.cpp
+++ b/misc/benchmarks/various/string_bench_STC.cpp
@@ -4,10 +4,11 @@
#include <iostream>
#include <iomanip>
#include <chrono>
-#define i_static
+#define i_implement
#include <stc/cstr.h> // string
-#define i_static
+#define i_implement
#include <stc/csview.h> // string_view
+#include <stc/algo/raii.h>
#define i_key_str
#include <stc/cvec.h> // vec of cstr with const char* lookup
@@ -183,7 +184,7 @@ void benchmark(
//const size_t MAX_LOOP = 1000000;
const size_t MAX_LOOP = 2000;
-int main()
+int main(void)
{
c_auto (cvec_str, vec_string)
c_auto (cvec_sv, vec_stringview)
diff --git a/misc/benchmarks/various/string_bench_STD.cpp b/misc/benchmarks/various/string_bench_STD.cpp
index 8bb87937..153ac02f 100644
--- a/misc/benchmarks/various/string_bench_STD.cpp
+++ b/misc/benchmarks/various/string_bench_STD.cpp
@@ -12,6 +12,7 @@
#include <unordered_map>
#define i_static
#include <stc/cstr.h>
+#include <stc/algo/raii.h>
std::vector<std::string> read_file(const char* name)
{
@@ -193,7 +194,7 @@ void benchmark(
//const size_t MAX_LOOP = 1000000;
const size_t MAX_LOOP = 2000;
-int main()
+int main(void)
{
std::vector<std::string> vec_shortstr;
std::vector<std::string_view> vec_shortstrview;
diff --git a/misc/examples/forfilter.c b/misc/examples/algorithms/forfilter.c
index fbb7280f..c1426045 100644
--- a/misc/examples/forfilter.c
+++ b/misc/examples/algorithms/forfilter.c
@@ -1,12 +1,12 @@
#include <stdio.h>
-#define i_extern
+#define i_import
#include <stc/cstr.h>
+#define i_implement
#include <stc/csview.h>
-#include <stc/algo/filter.h>
-#include <stc/algo/crange.h>
+#include <stc/algorithm.h>
#define i_type IVec
-#define i_val int
+#define i_key int
#include <stc/cstack.h>
// filters and transforms:
@@ -17,7 +17,7 @@
void demo1(void)
{
- IVec vec = c_make(IVec, {0, 1, 2, 3, 4, 5, 80, 6, 7, 80, 8, 9, 80,
+ IVec vec = c_init(IVec, {0, 1, 2, 3, 4, 5, 80, 6, 7, 80, 8, 9, 80,
10, 11, 12, 13, 14, 15, 80, 16, 17});
c_forfilter (i, IVec, vec, flt_skipValue(i, 80))
@@ -54,7 +54,8 @@ fn main() {
void demo2(void)
{
IVec vector = {0};
- c_forfilter (x, crange, crange_obj(INT64_MAX),
+ crange r = crange_init(INT64_MAX);
+ c_forfilter (x, crange, r,
c_flt_skipwhile(x, *x.ref != 11) &&
(*x.ref % 2) != 0 &&
c_flt_take(x, 5)
@@ -81,7 +82,7 @@ fn main() {
}
*/
#define i_type SVec
-#define i_valclass csview
+#define i_keyclass csview
#include <stc/cstack.h>
void demo3(void)
@@ -123,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 1fc00614..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_val int
-#include <stc/cstack.h>
-
-#define i_type IMap
-#define i_key int
-#define i_val int
-#include <stc/cmap.h>
-
-
-int main()
-{
- 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_make(IVec, {12, 23, 453, 65, 113, 215, 676, 34, 67, 20, 27, 66, 189, 45, 280, 199});
- IMap map = c_make(IMap, {{12, 23}, {453, 65}, {676, 123}, {34, 67}});
-
- 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/algorithms/random.c b/misc/examples/algorithms/random.c
new file mode 100644
index 00000000..e457d329
--- /dev/null
+++ b/misc/examples/algorithms/random.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <time.h>
+#include <stc/crand.h>
+
+int main(void)
+{
+ const long long N = 10000000, range = 1000000;
+ const uint64_t seed = (uint64_t)time(NULL);
+ crand_t rng = crand_init(seed);
+ clock_t t;
+
+ printf("Compare speed of full and unbiased ranged random numbers...\n");
+ long long sum = 0;
+ t = clock();
+ c_forrange (N) {
+ sum += (int32_t)crand_u64(&rng);
+ }
+ t = clock() - t;
+ printf("full range\t\t: %f secs, %lld, avg: %f\n",
+ (double)t/CLOCKS_PER_SEC, N, (double)(sum/N));
+
+ crand_uniform_t dist1 = crand_uniform_init(0, range);
+ rng = crand_init(seed);
+ sum = 0;
+ t = clock();
+ c_forrange (N) {
+ sum += crand_uniform(&rng, &dist1); // unbiased
+ }
+ t = clock() - t;
+ printf("unbiased 0-%lld\t: %f secs, %lld, avg: %f\n",
+ range, (double)t/CLOCKS_PER_SEC, N, (double)(sum/N));
+
+ sum = 0;
+ rng = crand_init(seed);
+ t = clock();
+ c_forrange (N) {
+ sum += (int32_t)crand_u64(&rng) % (range + 1); // biased
+ }
+ t = clock() - t;
+ printf("biased 0-%lld \t: %f secs, %lld, avg: %f\n",
+ range, (double)t/CLOCKS_PER_SEC, N, (double)(sum/N));
+}
diff --git a/misc/examples/shape.c b/misc/examples/algorithms/shape.c
index d7116039..bd4bdd5a 100644
--- a/misc/examples/shape.c
+++ b/misc/examples/algorithms/shape.c
@@ -62,9 +62,9 @@ static void Triangle_draw(const Shape* shape)
{
const Triangle* self = DYN_CAST(Triangle, shape);
printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n",
- self->p[0].x, self->p[0].y,
- self->p[1].x, self->p[1].y,
- self->p[2].x, self->p[2].y);
+ (double)self->p[0].x, (double)self->p[0].y,
+ (double)self->p[1].x, (double)self->p[1].y,
+ (double)self->p[2].x, (double)self->p[2].y);
}
struct ShapeAPI Triangle_api = {
@@ -76,7 +76,7 @@ struct ShapeAPI Triangle_api = {
// ============================================================
#define i_type PointVec
-#define i_val Point
+#define i_key Point
#include <stc/cstack.h>
typedef struct {
@@ -109,7 +109,7 @@ static void Polygon_draw(const Shape* shape)
const Polygon* self = DYN_CAST(Polygon, shape);
printf("Polygon :");
c_foreach (i, PointVec, self->points)
- printf(" (%g,%g)", i.ref->x, i.ref->y);
+ printf(" (%g,%g)", (double)i.ref->x, (double)i.ref->y);
puts("");
}
@@ -122,8 +122,8 @@ struct ShapeAPI Polygon_api = {
// ============================================================
#define i_type Shapes
-#define i_val Shape*
-#define i_valdrop(x) Shape_delete(*x)
+#define i_key Shape*
+#define i_keydrop(x) Shape_delete(*x)
#define i_no_clone
#include <stc/cstack.h>
@@ -137,7 +137,7 @@ int main(void)
{
Shapes shapes = {0};
- Triangle* tri1 = c_new(Triangle, Triangle_from((Point){5, 7}, (Point){12, 7}, (Point){12, 20}));
+ Triangle* tri1 = c_new(Triangle, Triangle_from(c_LITERAL(Point){5, 7}, c_LITERAL(Point){12, 7}, c_LITERAL(Point){12, 20}));
Polygon* pol1 = c_new(Polygon, Polygon_init());
Polygon* pol2 = c_new(Polygon, Polygon_init());
diff --git a/misc/examples/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 1323d4e7..e0a11346 100644
--- a/misc/examples/bits.c
+++ b/misc/examples/bitsets/bits.c
@@ -9,18 +9,18 @@ int main(void)
cbits_drop(&set),
cbits_drop(&s2)
){
- printf("count %" c_ZI ", %" c_ZI "\n", cbits_count(&set), cbits_size(&set));
+ printf("count %lld, %lld\n", cbits_count(&set), cbits_size(&set));
cbits s1 = cbits_from("1110100110111");
char buf[256];
cbits_to_str(&s1, buf, 0, 255);
- printf("buf: %s: %" c_ZI "\n", buf, cbits_count(&s1));
+ printf("buf: %s: %lld\n", buf, cbits_count(&s1));
cbits_drop(&s1);
cbits_reset(&set, 9);
cbits_resize(&set, 43, false);
printf(" str: %s\n", cbits_to_str(&set, buf, 0, 255));
- printf("%4" c_ZI ": ", cbits_size(&set));
+ printf("%4lld: ", cbits_size(&set));
c_forrange (i, cbits_size(&set))
printf("%d", cbits_test(&set, i));
puts("");
@@ -30,12 +30,12 @@ int main(void)
cbits_resize(&set, 93, false);
cbits_resize(&set, 102, true);
cbits_set_value(&set, 99, false);
- printf("%4" c_ZI ": ", cbits_size(&set));
+ printf("%4lld: ", cbits_size(&set));
c_forrange (i, cbits_size(&set))
printf("%d", cbits_test(&set, i));
puts("\nIterate:");
- printf("%4" c_ZI ": ", cbits_size(&set));
+ printf("%4lld: ", cbits_size(&set));
c_forrange (i, cbits_size(&set))
printf("%d", cbits_test(&set, i));
puts("");
@@ -58,7 +58,7 @@ int main(void)
puts("");
cbits_set_all(&set, false);
- printf("%4" c_ZI ": ", cbits_size(&set));
+ printf("%4lld: ", cbits_size(&set));
c_forrange (i, cbits_size(&set))
printf("%d", cbits_test(&set, i));
puts("");
diff --git a/misc/examples/bits2.c b/misc/examples/bitsets/bits2.c
index b002af3c..de2f16f4 100644
--- a/misc/examples/bits2.c
+++ b/misc/examples/bitsets/bits2.c
@@ -5,14 +5,14 @@
#define i_capacity 80 // enable fixed bitset on the stack
#include <stc/cbits.h>
-int main()
+int main(void)
{
Bits s1 = Bits_from("1110100110111");
- printf("size %" c_ZI "\n", Bits_size(&s1));
+ printf("size %lld\n", Bits_size(&s1));
char buf[256];
Bits_to_str(&s1, buf, 0, 256);
- printf("buf: %s: count=%" c_ZI "\n", buf, Bits_count(&s1));
+ printf("buf: %s: count=%lld\n", buf, Bits_count(&s1));
Bits_reset(&s1, 8);
printf(" s1: %s\n", Bits_to_str(&s1, buf, 0, 256));
diff --git a/misc/examples/prime.c b/misc/examples/bitsets/prime.c
index d0887353..7e5a2b3f 100644
--- a/misc/examples/prime.c
+++ b/misc/examples/bitsets/prime.c
@@ -2,23 +2,23 @@
#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(int64_t n)
+cbits sieveOfEratosthenes(llong n)
{
cbits bits = cbits_with_size(n/2 + 1, true);
- int64_t q = (int64_t)sqrt((double) n) + 1;
- for (int64_t i = 3; i < q; i += 2) {
- int64_t j = i;
+ llong q = (llong)sqrt((double) n) + 1;
+ for (llong i = 3; i < q; i += 2) {
+ llong j = i;
for (; j < n; j += 2) {
if (cbits_test(&bits, j>>1)) {
i = j;
break;
}
}
- for (int64_t j = i*i; j < n; j += i*2)
+ for (llong j = i*i; j < n; j += i*2)
cbits_reset(&bits, j>>1);
}
return bits;
@@ -26,15 +26,17 @@ cbits sieveOfEratosthenes(int64_t n)
int main(void)
{
- int64_t n = 1000000000;
- printf("Computing prime numbers up to %" c_ZI "\n", n);
+ llong n = 100000000;
+ printf("Computing prime numbers up to %lld\n", n);
- clock_t t1 = clock();
+ clock_t t = clock();
cbits primes = sieveOfEratosthenes(n + 1);
- int64_t np = cbits_count(&primes);
- clock_t t2 = clock();
- printf("Number of primes: %" c_ZI ", time: %f\n\n", np, (float)(t2 - t1) / (float)CLOCKS_PER_SEC);
+ llong np = cbits_count(&primes);
+ t = clock() - t;
+
+ 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");
c_forrange (i, 3, 1000, 2)
@@ -42,7 +44,9 @@ int main(void)
puts("\n");
puts("Show the last 50 primes using a temporary crange generator:");
- c_forfilter (i, crange, crange_obj(n - 1, 0, -2),
+ crange range = crange_init(n - 1, 0, -2);
+
+ c_forfilter (i, crange, range,
cbits_test(&primes, *i.ref/2) &&
c_flt_take(i, 50)
){
diff --git a/misc/examples/coread.c b/misc/examples/coread.c
deleted file mode 100644
index 0a7f4816..00000000
--- a/misc/examples/coread.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <stc/cstr.h>
-#include <stc/algo/coroutine.h>
-#include <errno.h>
-
-// Read file line by line using coroutines:
-
-struct file_nextline {
- const char* filename;
- int cco_state;
- FILE* fp;
- cstr line;
-};
-
-bool file_nextline(struct file_nextline* U)
-{
- cco_begin(U)
- U->fp = fopen(U->filename, "r");
- U->line = cstr_init();
-
- while (cstr_getline(&U->line, U->fp))
- cco_yield(true);
-
- cco_final: // this label is required.
- printf("finish\n");
- cstr_drop(&U->line);
- fclose(U->fp);
- cco_end(false);
-}
-
-int main(void)
-{
- struct file_nextline it = {__FILE__};
- int n = 0;
- while (file_nextline(&it))
- {
- printf("%3d %s\n", ++n, cstr_str(&it.line));
- //if (n == 10) cco_stop(&it);
- }
-}
diff --git a/misc/examples/coroutines.c b/misc/examples/coroutines.c
deleted file mode 100644
index b11b8532..00000000
--- a/misc/examples/coroutines.c
+++ /dev/null
@@ -1,106 +0,0 @@
-#include <stc/algo/coroutine.h>
-#include <stdio.h>
-#include <stdint.h>
-
-// Demonstrate to call another coroutine from a coroutine:
-// First create prime generator, then call fibonacci sequence:
-
-bool is_prime(int64_t i) {
- for (int64_t j=2; j*j <= i; ++j)
- if (i % j == 0) return false;
- return true;
-}
-
-struct prime {
- int count, idx;
- int64_t result, pos;
- int cco_state;
-};
-
-bool prime(struct prime* U) {
- cco_begin(U);
- if (U->result < 2) U->result = 2;
- if (U->result == 2) {
- if (U->count-- == 0) cco_return;
- ++U->idx;
- cco_yield(true);
- }
- U->result += !(U->result & 1);
- for (U->pos = U->result; U->count > 0; U->pos += 2) {
- if (is_prime(U->pos)) {
- --U->count;
- ++U->idx;
- U->result = U->pos;
- cco_yield(true);
- }
- }
- cco_final:
- printf("final prm\n");
- cco_end(false);
-}
-
-
-// Use coroutine to create a fibonacci sequence generator:
-
-struct fibonacci {
- int count, idx;
- int64_t result, b;
- int cco_state;
-};
-
-bool fibonacci(struct fibonacci* F) {
- assert(F->count < 94);
-
- cco_begin(F);
- F->idx = 0;
- F->result = 0;
- F->b = 1;
- for (;;) {
- if (F->count-- == 0)
- cco_return;
- if (++F->idx > 1) {
- int64_t sum = F->result + F->b; // NB! locals only lasts until next cco_yield!
- F->result = F->b;
- F->b = sum;
- }
- cco_yield(true);
- }
- cco_final:
- printf("final fib\n");
- cco_end(false);
-}
-
-// Combine
-
-struct combined {
- struct prime prm;
- struct fibonacci fib;
- int cco_state;
-};
-
-bool combined(struct combined* C) {
- cco_begin(C);
- cco_yield(prime(&C->prm), &C->prm, true);
- cco_yield(fibonacci(&C->fib), &C->fib, true);
-
- // Reuse the C->prm context and extend the count:
- C->prm.count = 8; C->prm.result += 2;
- cco_reset(&C->prm);
- cco_yield(prime(&C->prm), &C->prm, true);
-
- cco_final: puts("final comb");
- cco_end(false);
-}
-
-int main(void) {
- struct combined comb = {.prm={.count=8}, .fib={14}};
- if (true)
- while (combined(&comb))
- printf("Prime(%d)=%lld, Fib(%d)=%lld\n",
- comb.prm.idx, (long long)comb.prm.result,
- comb.fib.idx, (long long)comb.fib.result);
- else
- while (prime(&comb.prm))
- printf("Prime(%d)=%lld\n",
- comb.prm.idx, (long long)comb.prm.result);
-}
diff --git a/misc/examples/coroutines/cointerleave.c b/misc/examples/coroutines/cointerleave.c
new file mode 100644
index 00000000..80494176
--- /dev/null
+++ b/misc/examples/coroutines/cointerleave.c
@@ -0,0 +1,62 @@
+// https://www.youtube.com/watch?v=8sEe-4tig_A
+#include <stdio.h>
+#include <stc/coroutine.h>
+#define i_type IVec
+#define i_key int
+#include <stc/cvec.h>
+
+struct GenValue {
+ IVec *v;
+ IVec_iter it;
+ int cco_state;
+};
+
+static int get_value(struct GenValue* g)
+{
+ cco_routine(g) {
+ for (g->it = IVec_begin(g->v); g->it.ref; IVec_next(&g->it))
+ cco_yield_v(*g->it.ref);
+ }
+ return -1;
+}
+
+struct Generator {
+ struct GenValue x, y;
+ int cco_state;
+ int value;
+};
+
+cco_result interleaved(struct Generator* g)
+{
+ cco_routine(g) {
+ while (!(cco_done(&g->x) & cco_done(&g->y))) {
+ g->value = get_value(&g->x);
+ if (!cco_done(&g->x))
+ cco_yield();
+
+ g->value = get_value(&g->y);
+ if (!cco_done(&g->y))
+ cco_yield();
+ }
+ }
+ return CCO_DONE;
+}
+
+void Use(void)
+{
+ IVec a = c_init(IVec, {2, 4, 6, 8, 10, 11});
+ IVec b = c_init(IVec, {3, 5, 7, 9});
+
+ struct Generator g = {{&a}, {&b}};
+
+ cco_blocking_call(interleaved(&g)) {
+ printf("%d ", g.value);
+ }
+ puts("");
+ c_drop(IVec, &a, &b);
+}
+
+int main(void)
+{
+ Use();
+}
diff --git a/misc/examples/coroutines/coread.c b/misc/examples/coroutines/coread.c
new file mode 100644
index 00000000..6d3acdd7
--- /dev/null
+++ b/misc/examples/coroutines/coread.c
@@ -0,0 +1,41 @@
+#define i_implement
+#include <stc/cstr.h>
+#include <stc/coroutine.h>
+#include <errno.h>
+
+// Read file line by line using coroutines:
+
+struct file_read {
+ const char* filename;
+ int cco_state;
+ FILE* fp;
+ cstr line;
+};
+
+int file_read(struct file_read* g)
+{
+ cco_routine(g) {
+ g->fp = fopen(g->filename, "r");
+ if (!g->fp) cco_return;
+ g->line = cstr_init();
+
+ cco_await(!cstr_getline(&g->line, g->fp));
+
+ cco_final:
+ printf("finish\n");
+ cstr_drop(&g->line);
+ if (g->fp) fclose(g->fp);
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct file_read g = {__FILE__};
+ int n = 0;
+ cco_blocking_call(file_read(&g))
+ {
+ printf("%3d %s\n", ++n, cstr_str(&g.line));
+ //if (n == 10) cco_stop(&g);
+ }
+}
diff --git a/misc/examples/coroutines/coroutines.c b/misc/examples/coroutines/coroutines.c
new file mode 100644
index 00000000..802a976a
--- /dev/null
+++ b/misc/examples/coroutines/coroutines.c
@@ -0,0 +1,112 @@
+#include <stc/coroutine.h>
+#include <stdio.h>
+#include <stdint.h>
+
+// Demonstrate to call another coroutine from a coroutine:
+// First create prime generator, then call fibonacci sequence:
+
+bool is_prime(long long i) {
+ for (long long j=2; j*j <= i; ++j)
+ if (i % j == 0) return false;
+ return true;
+}
+
+struct prime {
+ int count, idx;
+ long long result, pos;
+ int cco_state;
+};
+
+int prime(struct prime* g) {
+ cco_routine(g) {
+ if (g->result < 2) g->result = 2;
+ if (g->result == 2) {
+ if (g->count-- == 0) cco_return;
+ ++g->idx;
+ cco_yield();
+ }
+ g->result += !(g->result & 1);
+ for (g->pos = g->result; g->count > 0; g->pos += 2) {
+ if (is_prime(g->pos)) {
+ --g->count;
+ ++g->idx;
+ g->result = g->pos;
+ cco_yield();
+ }
+ }
+ cco_final:
+ printf("final prm\n");
+ }
+ return 0;
+}
+
+
+// Use coroutine to create a fibonacci sequence generator:
+
+struct fibonacci {
+ int count, idx;
+ long long result, b;
+ int cco_state;
+};
+
+int fibonacci(struct fibonacci* g) {
+ assert(g->count < 94);
+
+ long long sum;
+ cco_routine(g) {
+ g->idx = 0;
+ g->result = 0;
+ g->b = 1;
+ for (;;) {
+ if (g->count-- == 0)
+ cco_return;
+ if (++g->idx > 1) {
+ // NB! locals lasts only until next yield/await!
+ sum = g->result + g->b;
+ g->result = g->b;
+ g->b = sum;
+ }
+ cco_yield();
+ }
+ cco_final:
+ printf("final fib\n");
+ }
+ return 0;
+}
+
+// Combine
+
+struct combined {
+ struct prime prm;
+ struct fibonacci fib;
+ int cco_state;
+};
+
+int combined(struct combined* g) {
+ cco_routine(g) {
+ cco_await_call(prime(&g->prm));
+ cco_await_call(fibonacci(&g->fib));
+
+ // Reuse the g->prm context and extend the count:
+ g->prm.count = 8, g->prm.result += 2;
+ cco_reset(&g->prm);
+ cco_await_call(prime(&g->prm));
+
+ cco_final:
+ puts("final combined");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct combined c = {.prm={.count=8}, .fib={14}};
+ int res;
+
+ cco_blocking_call(res = combined(&c)) {
+ if (res == CCO_YIELD)
+ printf("Prime(%d)=%lld, Fib(%d)=%lld\n",
+ c.prm.idx, c.prm.result,
+ c.fib.idx, c.fib.result);
+ }
+}
diff --git a/misc/examples/coroutines/cotasks1.c b/misc/examples/coroutines/cotasks1.c
new file mode 100644
index 00000000..cffd6620
--- /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_await_timer(&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 text;
+ int cco_state;
+};
+
+int produce_items(struct produce_items* p)
+{
+ cco_routine (p) {
+ p->text = cstr_init();
+ while (true)
+ {
+ cco_await(next_value(&p->next) != CCO_AWAIT);
+ cstr_printf(&p->text, "item %d", p->next.val);
+ print_time();
+ printf("produced %s\n", cstr_str(&p->text));
+ cco_yield();
+ }
+ cco_final:
+ cstr_drop(&p->text);
+ 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->text));
+ }
+ cco_final:
+ puts("done consume");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct produce_items produce = {0};
+ struct consume_items consume = {.n=5};
+ int count = 0;
+
+ cco_blocking_call(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..558df118
--- /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_await_timer(&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 text;
+);
+
+int produce_items(struct produce_items* p, cco_runtime* rt)
+{
+ cco_routine (p) {
+ p->text = cstr_init();
+ p->next.cco_func = next_value;
+ while (true)
+ {
+ // await for next CCO_YIELD (or CCO_DONE) in next_value
+ cco_await_task(&p->next, rt, CCO_YIELD);
+ cstr_printf(&p->text, "item %d", p->next.val);
+ print_time();
+ printf("produced %s\n", cstr_str(&p->text));
+ cco_yield();
+ }
+
+ cco_final:
+ cstr_drop(&p->text);
+ 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_await_task(&c->produce, rt, CCO_YIELD);
+ print_time();
+ printf("consumed %s\n", cstr_str(&c->produce.text));
+ }
+
+ cco_final:
+ cco_stop(&c->produce);
+ cco_resume_task(&c->produce, rt);
+ puts("done consume");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct consume_items consume = {
+ .cco_func = consume_items,
+ .n = 5,
+ };
+ cco_blocking_task(&consume);
+}
diff --git a/misc/examples/coroutines/dining_philosophers.c b/misc/examples/coroutines/dining_philosophers.c
new file mode 100644
index 00000000..d353b3b9
--- /dev/null
+++ b/misc/examples/coroutines/dining_philosophers.c
@@ -0,0 +1,105 @@
+// https://en.wikipedia.org/wiki/Dining_philosophers_problem
+#include <stdio.h>
+#include <time.h>
+#include <stc/crand.h>
+#include <stc/coroutine.h>
+
+// Define the number of philosophers and forks
+enum {
+ num_philosophers = 5,
+ num_forks = num_philosophers,
+};
+
+struct Philosopher {
+ int id;
+ cco_timer tm;
+ cco_sem* left_fork;
+ cco_sem* right_fork;
+ int cco_state; // required
+};
+
+struct Dining {
+ // Define semaphores for the forks
+ cco_sem forks[num_forks];
+ struct Philosopher ph[num_philosophers];
+ int cco_state; // required
+};
+
+
+// Philosopher coroutine
+int philosopher(struct Philosopher* p)
+{
+ double duration;
+ cco_routine(p) {
+ while (1) {
+ duration = 1.0 + crandf()*2.0;
+ printf("Philosopher %d is thinking for %.0f minutes...\n", p->id, duration*10);
+ cco_await_timer(&p->tm, duration);
+
+ printf("Philosopher %d is hungry...\n", p->id);
+ cco_await_sem(p->left_fork);
+ cco_await_sem(p->right_fork);
+
+ duration = 0.5 + crandf();
+ printf("Philosopher %d is eating for %.0f minutes...\n", p->id, duration*10);
+ cco_await_timer(&p->tm, duration);
+
+ cco_sem_release(p->left_fork);
+ cco_sem_release(p->right_fork);
+ }
+
+ cco_final:
+ printf("Philosopher %d finished\n", p->id);
+ }
+ return 0;
+}
+
+
+// Dining coroutine
+int dining(struct Dining* d)
+{
+ cco_routine(d) {
+ for (int i = 0; i < num_forks; ++i)
+ cco_sem_set(&d->forks[i], 1); // all forks available
+ for (int i = 0; i < num_philosophers; ++i) {
+ cco_reset(&d->ph[i]);
+ d->ph[i].id = i + 1;
+ d->ph[i].left_fork = &d->forks[i];
+ d->ph[i].right_fork = &d->forks[(i + 1) % num_forks];
+ }
+
+ while (1) {
+ // per-"frame" logic resume each philosopher
+ for (int i = 0; i < num_philosophers; ++i) {
+ philosopher(&d->ph[i]);
+ }
+ cco_yield(); // suspend, return control back to main
+ }
+
+ cco_final:
+ for (int i = 0; i < num_philosophers; ++i) {
+ cco_stop(&d->ph[i]);
+ philosopher(&d->ph[i]);
+ }
+ puts("Dining finished");
+ }
+ return 0;
+}
+
+int main(void)
+{
+ struct Dining dine;
+ cco_reset(&dine);
+ int n=0;
+ cco_timer tm = cco_timer_from(15.0); // seconds
+ csrand((uint64_t)time(NULL));
+
+ cco_blocking_call(dining(&dine))
+ {
+ if (cco_timer_expired(&tm))
+ cco_stop(&dine);
+ cco_sleep(0.001);
+ ++n;
+ }
+ printf("n=%d\n", n);
+}
diff --git a/misc/examples/coroutines/filetask.c b/misc/examples/coroutines/filetask.c
new file mode 100644
index 00000000..9650cb60
--- /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_init();
+
+ while (true) {
+ // emulate async io: await 10ms per line
+ cco_await_timer(&co->tm, 0.010);
+
+ if (!cstr_getline(&co->line, co->fp))
+ break;
+ cco_yield();
+ }
+
+ cco_final:
+ 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_await_task(&co->reader, rt, CCO_YIELD);
+ if (rt->result == CCO_DONE) break;
+ co->lineCount += 1;
+ cco_yield();
+ }
+
+ cco_final:
+ 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_blocking_task(&countTask) { ++loop; }
+
+ printf("line count = %d\n", countTask.lineCount);
+ printf("exec count = %d\n", loop);
+}
diff --git a/misc/examples/coroutines/generator.c b/misc/examples/coroutines/generator.c
new file mode 100644
index 00000000..96498498
--- /dev/null
+++ b/misc/examples/coroutines/generator.c
@@ -0,0 +1,66 @@
+// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/
+
+#include <stdio.h>
+#include <stc/coroutine.h>
+#include <stc/algorithm.h>
+
+typedef struct {
+ int max_triples;
+ int a, b, c;
+} Triple;
+
+// Create an iterable generator over Triple with count items.
+// Requires coroutine Triple_next() and function Triple_begin() to be defined.
+cco_iter_struct(Triple,
+ int count;
+);
+
+int Triple_next(Triple_iter* it) {
+ Triple* g = it->ref; // note: before cco_routine
+ cco_routine(it)
+ {
+ for (g->c = 5;; ++g->c) {
+ for (g->a = 1; g->a < g->c; ++g->a) {
+ for (g->b = g->a; g->b < g->c; ++g->b) {
+ if (g->a*g->a + g->b*g->b == g->c*g->c) {
+ if (it->count++ == g->max_triples)
+ cco_return;
+ cco_yield();
+ }
+ }
+ }
+ }
+ cco_final:
+ it->ref = NULL; // stop the iterator
+ }
+ return 0;
+}
+
+Triple_iter Triple_begin(Triple* g) {
+ Triple_iter it = {.ref=g};
+ Triple_next(&it);
+ return it;
+}
+
+
+int main(void)
+{
+ puts("Pythagorean triples.\nGet max 200 triples with c < 50:");
+ Triple triple = {.max_triples=200};
+
+ c_foreach (i, Triple, triple) {
+ if (i.ref->c < 50)
+ printf("%u: (%d, %d, %d)\n", i.count, i.ref->a, i.ref->b, i.ref->c);
+ else
+ cco_stop(&i);
+ }
+
+ puts("\nGet the 10 first triples with odd a's and a <= 20:");
+ c_forfilter (i, Triple, triple,
+ i.ref->a <= 20 &&
+ (i.ref->a & 1) &&
+ c_flt_take(i, 10)
+ ){
+ printf("%d: (%d, %d, %d)\n", c_flt_getcount(i), i.ref->a, i.ref->b, i.ref->c);
+ }
+}
diff --git a/misc/examples/coroutines/scheduler.c b/misc/examples/coroutines/scheduler.c
new file mode 100644
index 00000000..be1810d2
--- /dev/null
+++ b/misc/examples/coroutines/scheduler.c
@@ -0,0 +1,67 @@
+// https://www.youtube.com/watch?v=8sEe-4tig_A
+#include <stdio.h>
+#include <stc/coroutine.h>
+
+#define i_type cco_tasks
+#define i_key cco_task*
+#define i_keydrop(x) { puts("free task"); free(*x); }
+#define i_no_clone
+#include <stc/cqueue.h>
+
+typedef struct {
+ cco_tasks tasks;
+} cco_scheduler;
+
+void cco_scheduler_drop(cco_scheduler* sched) {
+ cco_tasks_drop(&sched->tasks);
+}
+
+int cco_scheduler_run(cco_scheduler* sched) {
+ while (!cco_tasks_empty(&sched->tasks)) {
+ cco_task* task = cco_tasks_pull(&sched->tasks);
+ if (cco_resume_task(task, NULL))
+ cco_tasks_push(&sched->tasks, task);
+ else
+ cco_tasks_value_drop(&task);
+ }
+ return 0;
+}
+
+static int taskA(cco_task* task, cco_runtime* rt) {
+ cco_routine(task) {
+ puts("Hello, from task A");
+ cco_yield();
+ puts("A is back doing work");
+ cco_yield();
+ puts("A is back doing more work");
+ cco_yield();
+ puts("A is back doing even more work");
+ }
+ return 0;
+}
+
+static int taskB(cco_task* task, cco_runtime* rt) {
+ cco_routine(task) {
+ puts("Hello, from task B");
+ cco_yield();
+ puts("B is back doing work");
+ cco_yield();
+ puts("B is back doing more work");
+ }
+ return 0;
+}
+
+void Use(void) {
+ cco_scheduler sched = {.tasks = c_init(cco_tasks, {
+ c_new(cco_task, {.cco_func=taskA}),
+ c_new(cco_task, {.cco_func=taskB}),
+ })};
+
+ cco_scheduler_run(&sched);
+ cco_scheduler_drop(&sched);
+}
+
+int main(void)
+{
+ Use();
+}
diff --git a/misc/examples/coroutines/triples.c b/misc/examples/coroutines/triples.c
new file mode 100644
index 00000000..d6ce2791
--- /dev/null
+++ b/misc/examples/coroutines/triples.c
@@ -0,0 +1,75 @@
+// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/
+
+#include <stdio.h>
+#include <stc/coroutine.h>
+
+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) {
+ if (c > max_c)
+ goto done;
+ printf("%d: {%d, %d, %d}\n", ++i, a, b, c);
+ }
+ }
+ }
+ }
+ done:;
+}
+
+struct triples {
+ int max_c;
+ int a, b, c;
+ int cco_state;
+};
+
+int triples_coro(struct triples* t) {
+ cco_routine(t) {
+ 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->c > t->max_c)
+ cco_return;
+ cco_yield();
+ }
+ }
+ }
+ }
+ cco_final:
+ puts("done");
+ }
+ 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(20);
+
+ puts("\nCoroutine triples with GCD = 1:");
+ struct triples t = {.max_c = 100};
+ int n = 0;
+
+ cco_blocking_call(triples_coro(&t)) {
+ if (gcd(t.a, t.b) > 1)
+ continue;
+ 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/generator.c b/misc/examples/generator.c
deleted file mode 100644
index 2bccc489..00000000
--- a/misc/examples/generator.c
+++ /dev/null
@@ -1,53 +0,0 @@
-// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/
-
-#include <stc/algo/coroutine.h>
-#include <stdio.h>
-
-typedef struct {
- int n;
- int a, b, c;
-} Triple_value, Triple;
-
-typedef struct {
- Triple_value* ref;
- int cco_state;
-} Triple_iter;
-
-bool Triple_next(Triple_iter* it) {
- Triple_value* t = it->ref;
- cco_begin(it);
- for (t->c = 1;; ++t->c) {
- for (t->a = 1; t->a < t->c; ++t->a) {
- for (t->b = t->a; t->b < t->c; ++t->b) {
- if (t->a*t->a + t->b*t->b == t->c*t->c) {
- if (t->n-- == 0) cco_return;
- cco_yield(true);
- }
- }
- }
- }
- cco_final:
- it->ref = NULL;
- cco_end(false);
-}
-
-Triple_iter Triple_begin(Triple* t) {
- Triple_iter it = {t};
- if (t->n > 0) Triple_next(&it);
- else it.ref = NULL;
- return it;
-}
-
-
-int main()
-{
- puts("Pythagorean triples with c < 100:");
- Triple t = {INT32_MAX};
- c_foreach (i, Triple, t)
- {
- if (i.ref->c < 100)
- printf("%u: (%d, %d, %d)\n", INT32_MAX - i.ref->n + 1, i.ref->a, i.ref->b, i.ref->c);
- else
- cco_stop(&i);
- }
-}
diff --git a/misc/examples/birthday.c b/misc/examples/hashmaps/birthday.c
index c301128a..4742cb45 100644
--- a/misc/examples/birthday.c
+++ b/misc/examples/hashmaps/birthday.c
@@ -13,8 +13,8 @@ static uint64_t seed = 12345;
static void test_repeats(void)
{
enum {BITS = 46, BITS_TEST = BITS/2 + 2};
- const static uint64_t N = 1ull << BITS_TEST;
- const static uint64_t mask = (1ull << BITS) - 1;
+ static const uint64_t N = 1ull << BITS_TEST;
+ static const uint64_t mask = (1ull << BITS) - 1;
printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST);
crand_t rng = crand_init(seed);
@@ -60,7 +60,7 @@ void test_distribution(void)
cmap_x_drop(&map);
}
-int main()
+int main(void)
{
seed = (uint64_t)time(NULL);
test_distribution();
diff --git a/misc/examples/books.c b/misc/examples/hashmaps/books.c
index a62769b0..1fd57f27 100644
--- a/misc/examples/books.c
+++ b/misc/examples/hashmaps/books.c
@@ -1,4 +1,5 @@
// https://doc.rust-lang.org/std/collections/struct.HashMap.html
+#define i_implement
#include <stc/cstr.h>
#define i_key_str
#define i_val_str
@@ -6,7 +7,7 @@
// Type inference lets us omit an explicit type signature (which
// would be `HashMap<String, String>` in this example).
-int main()
+int main(void)
{
cmap_str book_reviews = {0};
diff --git a/misc/examples/hashmap.c b/misc/examples/hashmaps/hashmap.c
index 47a3bcff..cf11b7f7 100644
--- a/misc/examples/hashmap.c
+++ b/misc/examples/hashmaps/hashmap.c
@@ -1,4 +1,5 @@
// https://doc.rust-lang.org/rust-by-example/std/hash.html
+#define i_implement
#include <stc/cstr.h>
#define i_key_str
#define i_val_str
diff --git a/misc/examples/new_map.c b/misc/examples/hashmaps/new_map.c
index 3a4f934d..de990040 100644
--- a/misc/examples/new_map.c
+++ b/misc/examples/hashmaps/new_map.c
@@ -1,12 +1,13 @@
+#define i_implement
#include <stc/cstr.h>
#include <stc/forward.h>
forward_cmap(cmap_pnt, struct Point, int);
-struct MyStruct {
+typedef struct MyStruct {
cmap_pnt pntmap;
cstr name;
-} typedef MyStruct;
+} MyStruct;
// int => int map
#define i_key int
@@ -14,7 +15,7 @@ struct MyStruct {
#include <stc/cmap.h>
// Point => int map
-struct Point { int x, y; } typedef Point;
+typedef struct Point { int x, y; } Point;
int point_cmp(const Point* a, const Point* b) {
int c = a->x - b->x;
@@ -40,20 +41,20 @@ int point_cmp(const Point* a, const Point* b) {
#include <stc/cset.h>
-int main()
+int main(void)
{
- cmap_pnt pmap = c_make(cmap_pnt, {{{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}});
+ cmap_pnt pmap = c_init(cmap_pnt, {{{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}});
c_foreach (i, cmap_pnt, pmap)
printf(" (%d, %d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second);
puts("");
- cmap_str smap = c_make(cmap_str, {
+ cmap_str smap = c_init(cmap_str, {
{"Hello, friend", "long time no see"},
{"So long", "see you around"},
});
- cset_str sset = c_make(cset_str, {
+ cset_str sset = c_init(cset_str, {
"Hello, friend",
"Nice to see you again",
"So long",
diff --git a/misc/examples/phonebook.c b/misc/examples/hashmaps/phonebook.c
index c0007cb7..faf7566e 100644
--- a/misc/examples/phonebook.c
+++ b/misc/examples/hashmaps/phonebook.c
@@ -20,7 +20,7 @@
// IN THE SOFTWARE.
// Program to emulates the phone book.
-
+#define i_implement
#include <stc/cstr.h>
#define i_key_str
@@ -38,7 +38,7 @@ void print_phone_book(cmap_str phone_book)
int main(int argc, char **argv)
{
- cmap_str phone_book = c_make(cmap_str, {
+ cmap_str phone_book = c_init(cmap_str, {
{"Lilia Friedman", "(892) 670-4739"},
{"Tariq Beltran", "(489) 600-7575"},
{"Laiba Juarez", "(303) 885-5692"},
diff --git a/misc/examples/unordered_set.c b/misc/examples/hashmaps/unordered_set.c
index 61f9cc1f..dd899d78 100644
--- a/misc/examples/unordered_set.c
+++ b/misc/examples/hashmaps/unordered_set.c
@@ -1,10 +1,11 @@
// https://iq.opengenus.org/containers-cpp-stl/
// C program to demonstrate various function of stc cset
+#define i_implement
#include <stc/cstr.h>
#define i_key_str
#include <stc/cset.h>
-int main()
+int main(void)
{
// declaring set for storing string data-type
cset_str stringSet = {0};
diff --git a/misc/examples/vikings.c b/misc/examples/hashmaps/vikings.c
index abb909c3..cef17a04 100644
--- a/misc/examples/vikings.c
+++ b/misc/examples/hashmaps/vikings.c
@@ -1,3 +1,4 @@
+#define i_implement
#include <stc/cstr.h>
typedef struct Viking {
@@ -36,19 +37,19 @@ static inline RViking Viking_toraw(const Viking* vp) {
#define i_rawclass RViking // lookup type
#define i_keyfrom Viking_from
#define i_opt c_no_clone
-#define i_hash(rp) cstrhash(rp->name) ^ cstrhash(rp->country)
+#define i_hash(rp) stc_strhash(rp->name) ^ stc_strhash(rp->country)
#define i_val int // mapped type
#include <stc/cmap.h>
-int main()
+int main(void)
{
Vikings vikings = {0};
- Vikings_emplace(&vikings, (RViking){"Einar", "Norway"}, 20);
- Vikings_emplace(&vikings, (RViking){"Olaf", "Denmark"}, 24);
- Vikings_emplace(&vikings, (RViking){"Harald", "Iceland"}, 12);
- Vikings_emplace(&vikings, (RViking){"Björn", "Sweden"}, 10);
+ Vikings_emplace(&vikings, c_LITERAL(RViking){"Einar", "Norway"}, 20);
+ Vikings_emplace(&vikings, c_LITERAL(RViking){"Olaf", "Denmark"}, 24);
+ Vikings_emplace(&vikings, c_LITERAL(RViking){"Harald", "Iceland"}, 12);
+ Vikings_emplace(&vikings, c_LITERAL(RViking){"Björn", "Sweden"}, 10);
- Vikings_value* v = Vikings_get_mut(&vikings, (RViking){"Einar", "Norway"});
+ Vikings_value* v = Vikings_get_mut(&vikings, c_LITERAL(RViking){"Einar", "Norway"});
v->second += 3; // add 3 hp points to Einar
c_forpair (vk, hp, Vikings, vikings) {
diff --git a/misc/examples/intrusive.c b/misc/examples/linkedlists/intrusive.c
index 0d503575..edb072c7 100644
--- a/misc/examples/intrusive.c
+++ b/misc/examples/linkedlists/intrusive.c
@@ -3,8 +3,9 @@
#include <stdio.h>
#define i_type List
-#define i_val int
-#include <stc/clist.h>
+#define i_key int
+#define i_use_cmp
+#include <stc/clist.h>
void printList(List list) {
printf("list:");
@@ -13,10 +14,10 @@ void printList(List list) {
puts("");
}
-int main() {
+int main(void) {
List list = {0};
c_forlist (i, int, {6, 9, 3, 1, 7, 4, 5, 2, 8})
- List_push_back_node(&list, c_new(List_node, {0, *i.ref}));
+ List_push_back_node(&list, c_new(List_node, {.value=*i.ref}));
printList(list);
diff --git a/misc/examples/list.c b/misc/examples/linkedlists/list.c
index 363d7fec..e83dc6b2 100644
--- a/misc/examples/list.c
+++ b/misc/examples/linkedlists/list.c
@@ -1,20 +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_val double
+#define i_key double
+#define i_use_cmp
#include <stc/clist.h>
-int main() {
+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);
@@ -34,7 +35,7 @@ int main() {
puts("");
DList_drop(&list);
- list = c_make(DList, {10, 20, 30, 40, 30, 50});
+ list = c_init(DList, {10, 20, 30, 40, 30, 50});
const double* v = DList_get(&list, 30);
printf("found: %f\n", *v);
diff --git a/misc/examples/list_erase.c b/misc/examples/linkedlists/list_erase.c
index 0201c2d9..211c5a5d 100644
--- a/misc/examples/list_erase.c
+++ b/misc/examples/linkedlists/list_erase.c
@@ -2,12 +2,12 @@
#include <stdio.h>
#define i_type IList
-#define i_val int
+#define i_key int
#include <stc/clist.h>
-int main ()
+int main(void)
{
- IList L = c_make(IList, {10, 20, 30, 40, 50});
+ IList L = c_init(IList, {10, 20, 30, 40, 50});
c_foreach (x, IList, L)
printf("%d ", *x.ref);
diff --git a/misc/examples/list_splice.c b/misc/examples/linkedlists/list_splice.c
index baebca29..f1fd6e1f 100644
--- a/misc/examples/list_splice.c
+++ b/misc/examples/linkedlists/list_splice.c
@@ -1,8 +1,7 @@
#include <stdio.h>
-#define i_val int
+#define i_key int
#define i_tag i
-#define i_extern // define _clist_mergesort() once
#include <stc/clist.h>
void print_ilist(const char* s, clist_i list)
@@ -14,10 +13,10 @@ void print_ilist(const char* s, clist_i list)
puts("");
}
-int main ()
+int main(void)
{
- clist_i list1 = c_make(clist_i, {1, 2, 3, 4, 5});
- clist_i list2 = c_make(clist_i, {10, 20, 30, 40, 50});
+ clist_i list1 = c_init(clist_i, {1, 2, 3, 4, 5});
+ clist_i list2 = c_init(clist_i, {10, 20, 30, 40, 50});
print_ilist("list1:", list1);
print_ilist("list2:", list2);
diff --git a/misc/examples/linkedlists/new_list.c b/misc/examples/linkedlists/new_list.c
new file mode 100644
index 00000000..7518929a
--- /dev/null
+++ b/misc/examples/linkedlists/new_list.c
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <stc/forward.h>
+
+forward_clist(clist_i32, int);
+forward_clist(clist_pnt, struct Point);
+
+typedef struct {
+ clist_i32 intlist;
+ clist_pnt pntlist;
+} MyStruct;
+
+#define i_key int
+#define i_tag i32
+#define i_is_forward
+#include <stc/clist.h>
+
+typedef struct Point { int x, y; } Point;
+int point_cmp(const Point* a, const Point* b) {
+ int c = a->x - b->x;
+ return c ? c : a->y - b->y;
+}
+
+#define i_key Point
+#define i_cmp point_cmp
+#define i_is_forward
+#define i_tag pnt
+#include <stc/clist.h>
+
+#define i_key float
+#define i_use_cmp // use < and == operators for comparison
+#include <stc/clist.h>
+
+void MyStruct_drop(MyStruct* s);
+#define i_type MyList
+#define i_key MyStruct
+#define i_keydrop MyStruct_drop // define drop function
+#define i_no_clone // must explicitely exclude or define cloning support because of drop.
+#include <stc/clist.h>
+
+void MyStruct_drop(MyStruct* s) {
+ clist_i32_drop(&s->intlist);
+ clist_pnt_drop(&s->pntlist);
+}
+
+
+int main(void)
+{
+ MyStruct my = {0};
+ clist_i32_push_back(&my.intlist, 123);
+ clist_pnt_push_back(&my.pntlist, c_LITERAL(Point){123, 456});
+ MyStruct_drop(&my);
+
+ clist_pnt plist = c_init(clist_pnt, {{42, 14}, {32, 94}, {62, 81}});
+ clist_pnt_sort(&plist);
+
+ c_foreach (i, clist_pnt, plist)
+ printf(" (%d %d)", i.ref->x, i.ref->y);
+ puts("");
+ clist_pnt_drop(&plist);
+
+
+ clist_float flist = c_init(clist_float, {123.3f, 321.2f, -32.2f, 78.2f});
+ clist_float_sort(&flist);
+
+ c_foreach (i, clist_float, flist)
+ printf(" %g", (double)*i.ref);
+
+ puts("");
+ clist_float_drop(&flist);
+}
diff --git a/misc/examples/make.sh b/misc/examples/make.sh
index 0297e5a1..b362f275 100755
--- a/misc/examples/make.sh
+++ b/misc/examples/make.sh
@@ -1,20 +1,19 @@
#!/bin/sh
if [ "$(uname)" = 'Linux' ]; then
- sanitize='-fsanitize=address'
+ sanitize='-fsanitize=address -fsanitize=undefined -fsanitize-trap'
clibs='-lm' # -pthread
oflag='-o '
fi
-cc=gcc; cflags="-s -O3 -std=c99 -Wconversion -Wpedantic -Wall -Wsign-compare -Wwrite-strings"
-#cc=gcc; cflags="-g -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall $sanitize"
-#cc=tcc; cflags="-Wall -std=c99"
-#cc=clang; cflags="-s -O2 -std=c99 -Werror -Wfatal-errors -Wpedantic -Wall -Wno-unused-function -Wsign-compare -Wwrite-strings"
-#cc=gcc; cflags="-x c++ -s -O2 -Wall -std=c++20"
-#cc=g++; cflags="-x c++ -s -O2 -Wall"
-#cc=cl; cflags="-O2 -nologo -W3 -MD"
-#cc=cl; cflags="-nologo -TP"
-#cc=cl; cflags="-nologo -std:c11"
+cc=gcc; cflags="-std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-maybe-uninitialized -Wno-implicit-fallthrough -Wno-missing-field-initializers"
+#cc=gcc; cflags="-std=c99 -g -Werror -Wfatal-errors -Wpedantic -Wall $sanitize"
+#cc=tcc; cflags="-std=c99 -Wall"
+#cc=clang; cflags="-std=c99 -s -O3 -Wall -Wextra -Wpedantic -Wconversion -Wwrite-strings -Wdouble-promotion -Wno-unused-parameter -Wno-unused-function -Wno-implicit-fallthrough -Wno-missing-field-initializers"
+#cc=gcc; cflags="-x c++ -std=c++20 -O2 -s -Wall"
+#cc=cl; cflags="-nologo -O2 -MD -W3 -wd4003"
+#cc=cl; cflags="-nologo -TP -std:c++20 -wd4003"
+#cc=cl; cflags="-nologo -std:c11 -wd4003"
if [ "$cc" = "cl" ]; then
oflag='/Fe:'
@@ -38,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 7dd12d50..d15a9ed7 100644
--- a/misc/examples/astar.c
+++ b/misc/examples/mixed/astar.c
@@ -4,6 +4,7 @@
// This is a reimplementation of the CTL example to STC:
// https://github.com/glouw/ctl/blob/master/examples/astar.c
// https://www.redblobgames.com/pathfinding/a-star/introduction.html
+#define i_implement
#include <stc/cstr.h>
#include <stdio.h>
@@ -19,7 +20,7 @@ point;
point
point_init(int x, int y, int width)
{
- return (point) { x, y, 0, width };
+ return c_LITERAL(point){ x, y, 0, width };
}
int
@@ -55,12 +56,11 @@ point_key_cmp(const point* a, const point* b)
return (i == j) ? 0 : (i < j) ? -1 : 1;
}
-#define i_val point
+#define i_key point
#define i_cmp point_cmp_priority
#include <stc/cpque.h>
-#define i_val point
-#define i_opt c_no_cmp
+#define i_key point
#include <stc/cdeq.h>
#define i_key point
diff --git a/misc/examples/complex.c b/misc/examples/mixed/complex.c
index 7dde981d..9fcbc417 100644
--- a/misc/examples/complex.c
+++ b/misc/examples/mixed/complex.c
@@ -5,17 +5,15 @@
// using StackList = std::stack<FloatStack>;
// using ListMap = std::unordered_map<int, std::forward_list<StackList>>;
// using MapMap = std::unordered_map<std::string, ListMap>;
-
+#define i_implement
#include <stc/cstr.h>
-
#define i_type FloatStack
-#define i_val float
+#define i_key float
#include <stc/cstack.h>
#define i_type StackList
-#define i_valclass FloatStack // "class" picks up _clone, _drop
-#define i_opt c_no_cmp // no FloatStack_cmp()
+#define i_keyclass FloatStack // "class" picks up _clone, _drop, _cmp
#include <stc/clist.h>
#define i_type ListMap
@@ -29,7 +27,7 @@
#include <stc/cmap.h>
-int main()
+int main(void)
{
MapMap mmap = {0};
@@ -44,7 +42,7 @@ int main()
const ListMap* lmap_p = MapMap_at(&mmap, "first");
const StackList* list_p = ListMap_at(lmap_p, 42);
const FloatStack* stack_p = StackList_back(list_p);
- printf("value is: %f\n", *FloatStack_at(stack_p, 3)); // pi
+ printf("value is: %f\n", (double)*FloatStack_at(stack_p, 3)); // pi
MapMap_drop(&mmap);
}
diff --git a/misc/examples/convert.c b/misc/examples/mixed/convert.c
index 0f09e830..fa64560e 100644
--- a/misc/examples/convert.c
+++ b/misc/examples/mixed/convert.c
@@ -1,17 +1,17 @@
+#define i_implement
#include <stc/cstr.h>
#define i_key_str
#define i_val_str
#include <stc/cmap.h>
-#define i_val_str
+#define i_key_str
#include <stc/cvec.h>
-#define i_val_str
-#define i_extern // define _clist_mergesort() once
+#define i_key_str
#include <stc/clist.h>
-int main()
+int main(void)
{
cmap_str map, mclone;
cvec_str keys = {0}, values = {0};
@@ -24,7 +24,7 @@ int main()
cvec_str_drop(&values),
clist_str_drop(&list)
){
- map = c_make(cmap_str, {
+ map = c_init(cmap_str, {
{"green", "#00ff00"},
{"blue", "#0000ff"},
{"yellow", "#ffff00"},
diff --git a/misc/examples/demos.c b/misc/examples/mixed/demos.c
index de92e378..43c9a7ae 100644
--- a/misc/examples/demos.c
+++ b/misc/examples/mixed/demos.c
@@ -1,6 +1,7 @@
+#define i_implement
#include <stc/cstr.h>
-void stringdemo1()
+void stringdemo1(void)
{
cstr cs = cstr_lit("one-nine-three-seven-five");
printf("%s.\n", cstr_str(&cs));
@@ -27,34 +28,35 @@ void stringdemo1()
cstr_drop(&cs);
}
-#define i_val int64_t
+#define i_key long long
#define i_tag ix
#include <stc/cvec.h>
-void vectordemo1()
+void vectordemo1(void)
{
cvec_ix bignums = cvec_ix_with_capacity(100);
cvec_ix_reserve(&bignums, 100);
for (int i = 10; i <= 100; i += 10)
cvec_ix_push(&bignums, i * i);
- printf("erase - %d: %" PRIu64 "\n", 3, bignums.data[3]);
+ printf("erase - %d: %lld\n", 3, bignums.data[3]);
cvec_ix_erase_n(&bignums, 3, 1); // erase index 3
cvec_ix_pop(&bignums); // erase the last
cvec_ix_erase_n(&bignums, 0, 1); // erase the first
for (int i = 0; i < cvec_ix_size(&bignums); ++i) {
- printf("%d: %" PRIu64 "\n", i, bignums.data[i]);
+ printf("%d: %lld\n", i, bignums.data[i]);
}
cvec_ix_drop(&bignums);
}
-#define i_val_str
+#define i_key_str
+#define i_use_cmp
#include <stc/cvec.h>
-void vectordemo2()
+void vectordemo2(void)
{
cvec_str names = {0};
cvec_str_emplace_back(&names, "Mary");
@@ -71,11 +73,12 @@ void vectordemo2()
cvec_str_drop(&names);
}
-#define i_val int
+#define i_key int
#define i_tag ix
+#define i_use_cmp
#include <stc/clist.h>
-void listdemo1()
+void listdemo1(void)
{
clist_ix nums = {0}, nums2 = {0};
for (int i = 0; i < 10; ++i)
@@ -107,7 +110,7 @@ void listdemo1()
#define i_tag i
#include <stc/cset.h>
-void setdemo1()
+void setdemo1(void)
{
cset_i nums = {0};
cset_i_insert(&nums, 8);
@@ -123,7 +126,7 @@ void setdemo1()
#define i_tag ii
#include <stc/cmap.h>
-void mapdemo1()
+void mapdemo1(void)
{
cmap_ii nums = {0};
cmap_ii_insert(&nums, 8, 64);
@@ -137,7 +140,7 @@ void mapdemo1()
#define i_tag si
#include <stc/cmap.h>
-void mapdemo2()
+void mapdemo2(void)
{
cmap_si nums = {0};
cmap_si_emplace_or_assign(&nums, "Hello", 64);
@@ -159,7 +162,7 @@ void mapdemo2()
#define i_val_str
#include <stc/cmap.h>
-void mapdemo3()
+void mapdemo3(void)
{
cmap_str table = {0};
cmap_str_emplace(&table, "Map", "test");
@@ -179,7 +182,7 @@ void mapdemo3()
cmap_str_drop(&table); // frees key and value cstrs, and hash table.
}
-int main()
+int main(void)
{
printf("\nSTRINGDEMO1\n"); stringdemo1();
printf("\nVECTORDEMO1\n"); vectordemo1();
diff --git a/misc/examples/inits.c b/misc/examples/mixed/inits.c
index 81bcdd3e..53a49f1f 100644
--- a/misc/examples/inits.c
+++ b/misc/examples/mixed/inits.c
@@ -1,3 +1,4 @@
+#define i_implement
#include <stc/cstr.h>
#define i_key int
@@ -17,18 +18,17 @@ inline static int ipair_cmp(const ipair_t* a, const ipair_t* b) {
}
-#define i_val ipair_t
+#define i_key ipair_t
#define i_cmp ipair_cmp
#define i_tag ip
#include <stc/cvec.h>
-#define i_val ipair_t
+#define i_key ipair_t
#define i_cmp ipair_cmp
#define i_tag ip
-#define i_extern // define _clist_mergesort() once
#include <stc/clist.h>
-#define i_val float
+#define i_key float
#define i_tag f
#include <stc/cpque.h>
@@ -45,7 +45,7 @@ int main(void)
puts("\npop and show high priorites first:");
while (! cpque_f_empty(&floats)) {
- printf("%.1f ", *cpque_f_top(&floats));
+ printf("%.1f ", (double)*cpque_f_top(&floats));
cpque_f_pop(&floats);
}
puts("\n");
@@ -66,7 +66,7 @@ int main(void)
// CMAP CNT
- cmap_cnt countries = c_make(cmap_cnt, {
+ cmap_cnt countries = c_init(cmap_cnt, {
{"Norway", 100},
{"Denmark", 50},
{"Iceland", 10},
@@ -88,7 +88,7 @@ int main(void)
// CVEC PAIR
- cvec_ip pairs1 = c_make(cvec_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
+ cvec_ip pairs1 = c_init(cvec_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
cvec_ip_sort(&pairs1);
c_foreach (i, cvec_ip, pairs1)
@@ -98,7 +98,7 @@ int main(void)
// CLIST PAIR
- clist_ip pairs2 = c_make(clist_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
+ clist_ip pairs2 = c_init(clist_ip, {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
clist_ip_sort(&pairs2);
c_foreach (i, clist_ip, pairs2)
diff --git a/misc/examples/read.c b/misc/examples/mixed/read.c
index 4efdcfeb..de04fd31 100644
--- a/misc/examples/read.c
+++ b/misc/examples/mixed/read.c
@@ -1,19 +1,21 @@
+#define i_implement
#include <stc/cstr.h>
-#define i_val_str
+#include <stc/algo/raii.h>
+#define i_key_str
#include <stc/cvec.h>
#include <errno.h>
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;
}
-int main()
+int main(void)
{
int n = 0;
c_with (cvec_str vec = read_file(__FILE__), cvec_str_drop(&vec))
diff --git a/misc/examples/multidim.c b/misc/examples/multidim.c
deleted file mode 100644
index 3980e6d8..00000000
--- a/misc/examples/multidim.c
+++ /dev/null
@@ -1,68 +0,0 @@
-// Example based on https://en.cppreference.com/w/cpp/container/mdspan
-#define i_val int
-#include <stc/cstack.h>
-#include <stc/cspan.h>
-#include <stdio.h>
-
-using_cspan3(ispan, int);
-
-int main()
-{
- cstack_int v = c_make(cstack_int, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24});
-
- // View data as contiguous memory representing 24 ints
- ispan ms1 = cspan_from(&v);
-
- // View the same data as a 3D array 2 x 3 x 4
- ispan3 ms3 = cspan_md(v.data, 2, 3, 4);
-
- puts("ms3:");
- for (int i=0; i != ms3.shape[0]; i++) {
- for (int j=0; j != ms3.shape[1]; j++) {
- for (int k=0; k != ms3.shape[2]; k++) {
- printf(" %2d", *cspan_at(&ms3, i, j, k));
- }
- puts("");
- }
- puts("");
- }
- puts("ss3 = ms3[:, 1:3, 1:3]");
- ispan3 ss3 = ms3;
- //cspan_slice(&ss3, {c_ALL}, {1,3}, {1,3});
- ss3 = cspan_slice(ispan3, &ms3, {c_ALL}, {1,3}, {1,3});
-
- for (int i=0; i != ss3.shape[0]; i++) {
- for (int j=0; j != ss3.shape[1]; j++) {
- for (int k=0; k != ss3.shape[2]; k++) {
- printf(" %2d", *cspan_at(&ss3, i, j, k));
- }
- puts("");
- }
- puts("");
- }
-
- puts("Iterate ss3 flat:");
- c_foreach (i, ispan3, ss3)
- printf(" %d", *i.ref);
- puts("");
-
- ispan2 ms2 = cspan_submd3(&ms3, 0);
-
- // write data using 2D view
- for (int i=0; i != ms2.shape[0]; i++)
- for (int j=0; j != ms2.shape[1]; j++)
- *cspan_at(&ms2, i, j) = i*1000 + j;
-
- puts("\nview data as 1D view:");
- for (int i=0; i != cspan_size(&ms1); i++)
- printf(" %d", *cspan_at(&ms1, i));
- puts("");
-
- puts("iterate subspan ms3[1]:");
- ispan2 sub = cspan_submd3(&ms3, 1);
- c_foreach (i, ispan2, sub)
- printf(" %d", *i.ref);
- puts("");
-
- cstack_int_drop(&v);
-}
diff --git a/misc/examples/new_list.c b/misc/examples/new_list.c
deleted file mode 100644
index 8b291d34..00000000
--- a/misc/examples/new_list.c
+++ /dev/null
@@ -1,68 +0,0 @@
-#include <stdio.h>
-#include <stc/forward.h>
-
-forward_clist(clist_i32, int);
-forward_clist(clist_pnt, struct Point);
-
-typedef struct {
- clist_i32 intlst;
- clist_pnt pntlst;
-} MyStruct;
-
-#define i_val int
-#define i_tag i32
-#define i_is_forward
-#include <stc/clist.h>
-
-typedef struct Point { int x, y; } Point;
-int point_cmp(const Point* a, const Point* b) {
- int c = a->x - b->x;
- return c ? c : a->y - b->y;
-}
-
-#define i_val Point
-#define i_cmp point_cmp
-#define i_is_forward
-#define i_tag pnt
-#include <stc/clist.h>
-
-#define i_val float
-#include <stc/clist.h>
-
-void MyStruct_drop(MyStruct* s);
-#define i_type MyList
-#define i_valclass MyStruct // i_valclass uses MyStruct_drop
-#define i_opt c_no_clone|c_no_cmp
-#include <stc/clist.h>
-
-void MyStruct_drop(MyStruct* s) {
- clist_i32_drop(&s->intlst);
- clist_pnt_drop(&s->pntlst);
-}
-
-
-int main()
-{
- MyStruct my = {0};
- clist_i32_push_back(&my.intlst, 123);
- clist_pnt_push_back(&my.pntlst, (Point){123, 456});
- MyStruct_drop(&my);
-
- clist_pnt plst = c_make(clist_pnt, {{42, 14}, {32, 94}, {62, 81}});
- clist_pnt_sort(&plst);
-
- c_foreach (i, clist_pnt, plst)
- printf(" (%d %d)", i.ref->x, i.ref->y);
- puts("");
- clist_pnt_drop(&plst);
-
-
- clist_float flst = c_make(clist_float, {123.3f, 321.2f, -32.2f, 78.2f});
- clist_float_sort(&flst);
-
- c_foreach (i, clist_float, flst)
- printf(" %g", *i.ref);
-
- puts("");
- clist_float_drop(&flst);
-}
diff --git a/misc/examples/printspan.c b/misc/examples/printspan.c
deleted file mode 100644
index 7459ac77..00000000
--- a/misc/examples/printspan.c
+++ /dev/null
@@ -1,57 +0,0 @@
-// printspan.c
-
-#include <stdio.h>
-#include <stc/cstr.h>
-#define i_val int
-#include <stc/cvec.h>
-#define i_val int
-#include <stc/cstack.h>
-#define i_val int
-#include <stc/cdeq.h>
-#define i_val_str
-#include <stc/csset.h>
-#include <stc/cspan.h>
-
-using_cspan(intspan, int, 1);
-
-void printMe(intspan container) {
- printf("%d:", (int)cspan_size(&container));
- c_foreach (e, intspan, container)
- printf(" %d", *e.ref);
- puts("");
-}
-
-int main()
-{
- intspan sp1 = cspan_make(intspan, {1, 2});
- printMe( sp1 );
-
- printMe( c_make(intspan, {1, 2, 3}) );
-
- int arr[] = {1, 2, 3, 4, 5, 6};
- intspan sp2 = cspan_from_array(arr);
- printMe( (intspan)cspan_subspan(&sp2, 1, 4) );
-
- cvec_int vec = c_make(cvec_int, {1, 2, 3, 4, 5});
- printMe( (intspan)cspan_from(&vec) );
-
- printMe( sp2 );
-
- cstack_int stk = c_make(cstack_int, {1, 2, 3, 4, 5, 6, 7});
- printMe( (intspan)cspan_from(&stk) );
-
- cdeq_int deq = c_make(cdeq_int, {1, 2, 3, 4, 5, 6, 7, 8});
- printMe( (intspan)cspan_from(&deq) );
-
- csset_str set = c_make(csset_str, {"5", "7", "4", "3", "8", "2", "1", "9", "6"});
- printf("%d:", (int)csset_str_size(&set));
- c_foreach (e, csset_str, set)
- printf(" %s", cstr_str(e.ref));
- puts("");
-
- // cleanup
- cvec_int_drop(&vec);
- cstack_int_drop(&stk);
- cdeq_int_drop(&deq);
- csset_str_drop(&set);
-}
diff --git a/misc/examples/functor.c b/misc/examples/priorityqueues/functor.c
index c0a4f8e8..e3bde1dd 100644
--- a/misc/examples/functor.c
+++ b/misc/examples/priorityqueues/functor.c
@@ -1,22 +1,22 @@
// Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue
// Example of per-instance less-function on a single priority queue type
//
-// Note: i_less: has self for cpque types only
-// i_cmp: has self for csmap and csset types only
-// i_hash/i_eq: has self for cmap and cset types only
#include <stdio.h>
#define i_type IPQue
-#define i_val int
-#define i_extend bool (*less)(const int*, const int*);
-#define i_less(x, y) c_getcon(self)->less(x, y)
-#define i_con cpque
+#define i_base cpque
+#define i_key int
+#define i_extend bool(*less)(const int*, const int*);
+#define i_less(x, y) c_extend()->less(x, y)
+// Note: i_less: c_extend() accessible for cpque types
+// i_cmp: c_extend() accessible for csmap and csset types
+// i_hash/i_eq: c_extend() accessible for cmap and cset types
#include <stc/extend.h>
void print_queue(const char* name, IPQue_ext q) {
// NB: make a clone because there is no way to traverse
- // priority_queue's content without erasing the queue.
+ // priority queue's content without erasing the queue.
IPQue_ext copy = {q.less, IPQue_clone(q.get)};
for (printf("%s: \t", name); !IPQue_empty(&copy.get); IPQue_pop(&copy.get))
@@ -30,28 +30,27 @@ static bool int_less(const int* x, const int* y) { return *x < *y; }
static bool int_greater(const int* x, const int* y) { return *x > *y; }
static bool int_lambda(const int* x, const int* y) { return (*x ^ 1) < (*y ^ 1); }
-int main()
+int main(void)
{
const int data[] = {1,8,5,6,3,4,0,9,7,2}, n = c_arraylen(data);
printf("data: \t");
- c_forrange (i, n)
- printf("%d ", data[i]);
+ c_forrange (i, n) printf("%d ", data[i]);
puts("");
- IPQue_ext q1 = {int_less}; // Max priority queue
- IPQue_ext minq1 = {int_greater}; // Min priority queue
- IPQue_ext q5 = {int_lambda}; // Using lambda to compare elements.
- c_forrange (i, n)
- IPQue_push(&q1.get, data[i]);
+ // Max priority queue
+ IPQue_ext q1 = {.less=int_less};
+ IPQue_put_n(&q1.get, data, n);
print_queue("q1", q1);
- c_forrange (i, n)
- IPQue_push(&minq1.get, data[i]);
+ // Min priority queue
+ IPQue_ext minq1 = {.less=int_greater};
+ IPQue_put_n(&minq1.get, data, n);
print_queue("minq1", minq1);
- c_forrange (i, n)
- IPQue_push(&q5.get, data[i]);
+ // Using lambda to compare elements.
+ IPQue_ext q5 = {.less=int_lambda};
+ IPQue_put_n(&q5.get, data, n);
print_queue("q5", q5);
c_drop(IPQue, &q1.get, &minq1.get, &q5.get);
diff --git a/misc/examples/new_pque.c b/misc/examples/priorityqueues/new_pque.c
index 9147e3f2..16823bb6 100644
--- a/misc/examples/new_pque.c
+++ b/misc/examples/priorityqueues/new_pque.c
@@ -1,16 +1,16 @@
#include <stdio.h>
-struct Point { int x, y; } typedef Point;
+typedef struct Point { int x, y; } Point;
#define i_type PointQ
-#define i_val Point
+#define i_key Point
#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y)
#include <stc/cpque.h>
-int main()
+int main(void)
{
- PointQ pque = c_make(PointQ, {{23, 80}, {12, 32}, {54, 74}, {12, 62}});
+ PointQ pque = c_init(PointQ, {{23, 80}, {12, 32}, {54, 74}, {12, 62}});
// print
for (; !PointQ_empty(&pque); PointQ_pop(&pque))
{
diff --git a/misc/examples/priority.c b/misc/examples/priorityqueues/priority.c
index 95dd3183..18684e73 100644
--- a/misc/examples/priority.c
+++ b/misc/examples/priorityqueues/priority.c
@@ -3,29 +3,29 @@
#include <time.h>
#include <stc/crand.h>
-#define i_val int64_t
+#define i_key int64_t
#define i_cmp -c_default_cmp // min-heap (increasing values)
#define i_tag i
#include <stc/cpque.h>
-int main() {
+int main(void) {
intptr_t N = 10000000;
crand_t rng = crand_init((uint64_t)time(NULL));
- crand_unif_t dist = crand_unif_init(0, N * 10);
+ 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 916f4dbc..3904c50c 100644
--- a/misc/examples/new_queue.c
+++ b/misc/examples/queues/new_queue.c
@@ -5,37 +5,37 @@
forward_cqueue(cqueue_pnt, struct Point);
-struct Point { int x, y; } typedef Point;
+typedef struct Point { int x, y; } Point;
int point_cmp(const Point* a, const Point* b) {
int c = c_default_cmp(&a->x, &b->x);
return c ? c : c_default_cmp(&a->y, &b->y);
}
-#define i_val Point
+#define i_key Point
#define i_cmp point_cmp
#define i_is_forward
#define i_tag pnt
#include <stc/cqueue.h>
#define i_type IQ
-#define i_val int
+#define i_key int
#include <stc/cqueue.h>
-int main() {
+int main(void) {
int n = 50000000;
crand_t rng = crand_init((uint64_t)time(NULL));
- crand_unif_t dist = crand_unif_init(0, n);
+ 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 83c18d09..5b1f7606 100644
--- a/misc/examples/queue.c
+++ b/misc/examples/queues/queue.c
@@ -1,26 +1,26 @@
#include <stc/crand.h>
#include <stdio.h>
-#define i_val int
+#define i_key int
#define i_tag i
#include <stc/cqueue.h>
-int main() {
- int n = 100000000;
- crand_unif_t dist;
+int main(void) {
+ int n = 1000000;
+ 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/random.c b/misc/examples/random.c
deleted file mode 100644
index ea9c483e..00000000
--- a/misc/examples/random.c
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <stdio.h>
-#include <time.h>
-#include <stc/crand.h>
-
-int main()
-{
- const size_t N = 1000000000;
- const uint64_t seed = (uint64_t)time(NULL), range = 1000000;
- crand_t rng = crand_init(seed);
-
- int64_t sum;
- clock_t diff, before;
-
- printf("Compare speed of full and unbiased ranged random numbers...\n");
- sum = 0;
- before = clock();
- c_forrange (N) {
- sum += (uint32_t)crand_u64(&rng);
- }
- diff = clock() - before;
- printf("full range\t\t: %f secs, %" c_ZI ", avg: %f\n",
- (float)diff / CLOCKS_PER_SEC, N, (float)sum / (float)N);
-
- crand_unif_t dist1 = crand_unif_init(0, range);
- rng = crand_init(seed);
- sum = 0;
- before = clock();
- c_forrange (N) {
- sum += crand_unif(&rng, &dist1); // unbiased
- }
- diff = clock() - before;
- printf("unbiased 0-%" PRIu64 "\t: %f secs, %" c_ZI ", avg: %f\n",
- range, (float)diff/CLOCKS_PER_SEC, N, (float)sum / (float)N);
-
- sum = 0;
- rng = crand_init(seed);
- before = clock();
- c_forrange (N) {
- sum += (int64_t)(crand_u64(&rng) % (range + 1)); // biased
- }
- diff = clock() - before;
- printf("biased 0-%" PRIu64 " \t: %f secs, %" c_ZI ", avg: %f\n",
- range, (float)diff / CLOCKS_PER_SEC, N, (float)sum / (float)N);
-
-}
diff --git a/misc/examples/rawptr_elements.c b/misc/examples/rawptr_elements.c
deleted file mode 100644
index 01bcdc44..00000000
--- a/misc/examples/rawptr_elements.c
+++ /dev/null
@@ -1,59 +0,0 @@
-#include <stc/ccommon.h>
-#include <stdio.h>
-
-#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_val 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()
-{
- // 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 4a56b8ac..d8032358 100644
--- a/misc/examples/regex1.c
+++ b/misc/examples/regularexpressions/regex1.c
@@ -1,4 +1,4 @@
-#define i_extern
+#define i_import
#include <stc/cregex.h>
int main(int argc, char* argv[])
diff --git a/misc/examples/regex2.c b/misc/examples/regularexpressions/regex2.c
index 3133f7c2..a798b1a1 100644
--- a/misc/examples/regex2.c
+++ b/misc/examples/regularexpressions/regex2.c
@@ -1,7 +1,7 @@
-#define i_extern
+#define i_import
#include <stc/cregex.h>
-int main()
+int main(void)
{
struct { const char *pattern, *input; } s[] = {
{"(\\d\\d\\d\\d)[-_](1[0-2]|0[1-9])[-_](3[01]|[12][0-9]|0[1-9])",
@@ -26,7 +26,7 @@ int main()
printf("\ninput: %s\n", s[i].input);
c_formatch (j, &re, s[i].input) {
- c_forrange (k, cregex_captures(&re))
+ c_forrange (k, cregex_captures(&re) + 1)
printf(" submatch %lld: %.*s\n", k, c_SV(j.match[k]));
}
}
diff --git a/misc/examples/regex_match.c b/misc/examples/regularexpressions/regex_match.c
index def0ae7a..9106ffbd 100644
--- a/misc/examples/regex_match.c
+++ b/misc/examples/regularexpressions/regex_match.c
@@ -1,11 +1,12 @@
-#define i_extern
+#define i_import
#include <stc/cregex.h>
+#define i_implement
#include <stc/csview.h>
-#define i_val float
+#define i_key float
#include <stc/cstack.h>
-int main()
+int main(void)
{
// Lets find the first sequence of digits in a string
const char *str = "Hello numeric world, there are 24 hours in a day, 3600 seconds in an hour."
@@ -21,13 +22,13 @@ int main()
// extract and convert all numbers in str to floats
c_formatch (i, &re, str)
- cstack_float_push(&vec, (float)atof(i.match[0].str));
+ cstack_float_push(&vec, (float)atof(i.match[0].buf));
c_foreach (i, cstack_float, vec)
- printf(" %g\n", *i.ref);
+ printf(" %g\n", (double)*i.ref);
// extracts the numbers only to a comma separated string.
- cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_R_STRIP);
+ cstr nums = cregex_replace_sv(&re, csview_from(str), " $0,", 0, NULL, CREG_STRIP);
printf("\n%s\n", cstr_str(&nums));
cstr_drop(&nums);
diff --git a/misc/examples/regex_replace.c b/misc/examples/regularexpressions/regex_replace.c
index d3952f50..087387d7 100644
--- a/misc/examples/regex_replace.c
+++ b/misc/examples/regularexpressions/regex_replace.c
@@ -1,18 +1,18 @@
-#define i_extern
+#define i_import
#include <stc/cregex.h>
#include <stc/csview.h>
bool add_10_years(int i, csview match, cstr* out) {
if (i == 1) { // group 1 matches year
int year;
- sscanf(match.str, "%4d", &year); // scan 4 chars only
+ sscanf(match.buf, "%4d", &year); // scan 4 chars only
cstr_printf(out, "%04d", year + 10);
return true;
}
return false;
}
-int main()
+int main(void)
{
const char* pattern = "\\b(\\d\\d\\d\\d)-(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])\\b";
const char* input = "start date: 2015-12-31, end date: 2022-02-28";
@@ -47,7 +47,7 @@ int main()
printf("euros: %s\n", cstr_str(&str));
/* Strip out everything but the matches */
- cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_R_STRIP));
+ cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP));
printf("strip: %s\n", cstr_str(&str));
/* Wrap all words in ${} */
diff --git a/misc/examples/sidebyside.cpp b/misc/examples/sidebyside.cpp
deleted file mode 100644
index a7c1008c..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() {
- {
- 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 84ba8dda..79211d2b 100644
--- a/misc/examples/arc_containers.c
+++ b/misc/examples/smartpointers/arc_containers.c
@@ -1,6 +1,6 @@
// Create a stack and a list of shared pointers to maps,
// and demonstrate sharing and cloning of maps.
-#define i_static
+#define i_implement
#include <stc/cstr.h>
#define i_type Map
#define i_key_str // strings
@@ -9,23 +9,21 @@
#include <stc/csmap.h>
#define i_type Arc // (atomic) ref. counted type
-#define i_val Map
-#define i_valdrop(p) (printf("drop Arc:\n"), Map_drop(p))
+#define i_key Map
+#define i_keydrop(p) (printf("drop Arc:\n"), Map_drop(p))
// no need for atomic ref. count in single thread:
-#define i_opt c_no_atomic|c_no_cmp|c_no_clone
+#define i_opt c_no_atomic
#include <stc/carc.h>
#define i_type Stack
-#define i_valboxed Arc // define i_valboxed for carc/cbox value (not i_val)
-#define i_opt c_no_cmp
+#define i_keyboxed Arc // use i_keyboxed for carc/cbox key
#include <stc/cvec.h>
#define i_type List
-#define i_valboxed Arc // as above
-#define i_opt c_no_cmp
+#define i_keyboxed Arc // as above
#include <stc/clist.h>
-int main()
+int main(void)
{
Stack stack = {0};
List list = {0};
diff --git a/misc/examples/arc_demo.c b/misc/examples/smartpointers/arc_demo.c
index 2339adbb..a66d84b0 100644
--- a/misc/examples/arc_demo.c
+++ b/misc/examples/smartpointers/arc_demo.c
@@ -6,27 +6,32 @@ void int_drop(int* x) {
}
// carc implements its own clone method using reference counting,
-// so 'i_valclone' is not required to be defined (ignored).
+// so 'i_keyclone' is not required to be defined (ignored).
#define i_type Arc // set type name to be defined (instead of 'carc_int')
-#define i_val int
-#define i_valdrop int_drop // optional, just to display the elements destroyed
-#define i_no_clone // required because of valdrop
+#define i_key int
+#define i_keydrop int_drop // optional, just to display the elements destroyed
+#define i_use_cmp // use int comparison (x < y, x == y).
#include <stc/carc.h> // Arc
-#define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements
+#define i_keyboxed Arc // note: use i_keyboxed instead of i_key for carc/cbox elements
#include <stc/csset.h> // csset_Arc (like: std::set<std::shared_ptr<int>>)
-#define i_valboxed Arc // note: as above.
+#define i_keyboxed Arc // note: as above.
+#define i_use_cmp
#include <stc/cvec.h> // cvec_Arc (like: std::vector<std::shared_ptr<int>>)
-int main()
+int main(void)
{
const int years[] = {2021, 2012, 2022, 2015};
cvec_Arc vec = {0};
- c_forrange (i, c_arraylen(years))
- cvec_Arc_push(&vec, Arc_from(years[i]));
+ c_forrange (i, c_arraylen(years)) {
+ cvec_Arc_emplace(&vec, years[i]);
+ // cvec_Arc_push(&vec, Arc_from(years[i])); // alt.
+ }
+
+ cvec_Arc_sort(&vec);
printf("vec:");
c_foreach (i, cvec_Arc, vec)
diff --git a/misc/examples/arcvec_erase.c b/misc/examples/smartpointers/arcvec_erase.c
index 3bf41559..0526b6a0 100644
--- a/misc/examples/arcvec_erase.c
+++ b/misc/examples/smartpointers/arcvec_erase.c
@@ -3,23 +3,25 @@
void show_drop(int* x) { printf("drop: %d\n", *x); }
#define i_type Arc
-#define i_val int
-#define i_valdrop show_drop
-#define i_no_clone // required because of valdrop
+#define i_key int
+#define i_keydrop show_drop
+#define i_use_cmp // enable sort/search for int type
#include <stc/carc.h> // Shared pointer to int
#define i_type Vec
-#define i_valboxed Arc
+#define i_keyboxed Arc
+#define i_use_cmp
#include <stc/cvec.h> // Vec: cvec<Arc>
-int main()
+int main(void)
{
- Vec vec = c_make(Vec, {2012, 1990, 2012, 2019, 2015});
+ Vec vec = c_init(Vec, {2012, 1990, 2012, 2019, 2015});
// clone the second 2012 and push it back.
// note: cloning make sure that vec.data[2] has ref count 2.
- Vec_push(&vec, Arc_clone(vec.data[2]));
+ Vec_push(&vec, Arc_clone(vec.data[2])); // => share vec.data[2]
+ Vec_emplace(&vec, *vec.data[2].get); // => deep-copy vec.data[2]
printf("vec before erase :");
c_foreach (i, Vec, vec)
diff --git a/misc/examples/box.c b/misc/examples/smartpointers/box.c
index 9954883c..5c8018d4 100644
--- a/misc/examples/box.c
+++ b/misc/examples/smartpointers/box.c
@@ -1,10 +1,11 @@
/* cbox: heap allocated boxed type */
+#define i_implement
#include <stc/cstr.h>
typedef struct { cstr name, last; } Person;
Person Person_make(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+ return c_LITERAL(Person){.name = cstr_from(name), .last = cstr_from(last)};
}
uint64_t Person_hash(const Person* a) {
@@ -28,14 +29,15 @@ void Person_drop(Person* p) {
}
#define i_type PBox
-#define i_valclass Person // "class" binds _cmp, _clone, _drop functions.
+#define i_keyclass Person // "class" binds _cmp, _clone, _drop functions.
+#define i_use_cmp
#include <stc/cbox.h>
#define i_type Persons
-#define i_valboxed PBox // "arcbox" informs that PBox is a smart pointer.
+#define i_keyboxed PBox // "arcbox" informs that PBox is a smart pointer.
#include <stc/csset.h>
-int main()
+int main(void)
{
Persons vec = {0};
PBox p = PBox_from(Person_make("Laura", "Palmer"));
diff --git a/misc/examples/box2.c b/misc/examples/smartpointers/box2.c
index cba255d2..9b782c74 100644
--- a/misc/examples/box2.c
+++ b/misc/examples/smartpointers/box2.c
@@ -13,27 +13,24 @@ typedef struct {
Point bottom_right;
} Rectangle;
-#define i_val Point
-#define i_no_cmp
+#define i_key Point
#include <stc/cbox.h> // cbox_Point
-#define i_val Rectangle
-#define i_no_cmp
+#define i_key Rectangle
#include <stc/cbox.h> // cbox_Rectangle
// Box in box:
-#define i_valboxed cbox_Point // NB: use i_valboxed when value is a cbox or carc!
#define i_type BoxBoxPoint
-#define i_no_cmp
+#define i_keyboxed cbox_Point // NB: use i_keyboxed when value is a cbox or carc!
#include <stc/cbox.h> // BoxBoxPoint
Point origin(void) {
- return (Point){ .x=1.0, .y=2.0 };
+ return c_LITERAL(Point){ .x=1.0, .y=2.0 };
}
cbox_Point boxed_origin(void) {
// Allocate this point on the heap, and return a pointer to it
- return cbox_Point_make((Point){ .x=1.0, .y=2.0 });
+ return cbox_Point_make(c_LITERAL(Point){ .x=1.0, .y=2.0 });
}
@@ -46,7 +43,7 @@ int main(void) {
};
// Heap allocated rectangle
- cbox_Rectangle boxed_rectangle = cbox_Rectangle_make((Rectangle){
+ cbox_Rectangle boxed_rectangle = cbox_Rectangle_make(c_LITERAL(Rectangle){
.top_left = origin(),
.bottom_right = { .x=3.0, .y=-4.0 }
});
diff --git a/misc/examples/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 3714e1d5..e9ebbbfe 100644
--- a/misc/examples/music_arc.c
+++ b/misc/examples/smartpointers/music_arc.c
@@ -1,5 +1,6 @@
// shared_ptr-examples.cpp
// based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160
+#define i_implement
#include <stc/cstr.h>
typedef struct
@@ -11,8 +12,8 @@ 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)
- { return (Song){cstr_from(artist), cstr_from(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) {
printf("drop: %s\n", cstr_str(&s->title));
@@ -21,21 +22,21 @@ void Song_drop(Song* s) {
// Define the shared pointer:
#define i_type SongArc
-#define i_valclass Song
-#define i_opt c_no_hash // arc require hash fn, disable as we don't need it.
+#define i_keyclass Song
+#define i_opt c_use_cmp|c_no_hash
#include <stc/carc.h>
// ... and a vector of them
#define i_type SongVec
-#define i_valboxed SongArc // use i_valboxed on carc / cbox instead of i_val
-#include <stc/cstack.h>
+#define i_keyboxed SongArc // use i_keyboxed on carc / cbox (instead of i_key)
+#include <stc/cvec.h>
-void example3()
+void example3(void)
{
- SongVec vec1 = c_make(SongVec, {
- Song_make("Bob Dylan", "The Times They Are A Changing"),
- Song_make("Aretha Franklin", "Bridge Over Troubled Water"),
- Song_make("Thalia", "Entre El Mar y Una Estrella")
+ SongVec vec1 = c_init(SongVec, {
+ 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};
@@ -46,8 +47,8 @@ void example3()
// 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}) {
@@ -60,7 +61,7 @@ void example3()
c_drop(SongVec, &vec1, &vec2);
}
-int main()
+int main(void)
{
example3();
-}
+} \ No newline at end of file
diff --git a/misc/examples/new_sptr.c b/misc/examples/smartpointers/new_sptr.c
index 1b72e4f5..50e28ae2 100644
--- a/misc/examples/new_sptr.c
+++ b/misc/examples/smartpointers/new_sptr.c
@@ -1,3 +1,4 @@
+#define i_implement
#include <stc/cstr.h>
typedef struct { cstr name, last; } Person;
@@ -8,28 +9,28 @@ int Person_cmp(const Person* a, const Person* b);
uint64_t Person_hash(const Person* p);
#define i_type PersonArc
-#define i_valclass Person // "class" ensure Person_drop will be called
-#define i_cmp Person_cmp // enable carc object comparisons (not ptr to obj)
-#define i_hash Person_hash // enable carc object hash (not ptr to obj)
+#define i_keyclass Person // "class" assume _clone, _drop, _cmp, _hash is defined.
+#define i_use_cmp
#include <stc/carc.h>
#define i_type IPtr
-#define i_val int
-#define i_valdrop(x) printf("drop: %d\n", *x)
-#define i_no_clone
+#define i_key int
+#define i_keydrop(x) printf("drop: %d\n", *x)
+#define i_use_cmp
#include <stc/carc.h>
#define i_type IPStack
-#define i_valboxed IPtr
+#define i_keyboxed IPtr
#include <stc/cstack.h>
#define i_type PASet
-#define i_valboxed PersonArc
+#define i_keyboxed PersonArc
#include <stc/cset.h>
Person Person_make(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+ Person p = {.name = cstr_from(name), .last = cstr_from(last)};
+ return p;
}
int Person_cmp(const Person* a, const Person* b) {
diff --git a/misc/examples/person_arc.c b/misc/examples/smartpointers/person_arc.c
index 620d311f..11040cd2 100644
--- a/misc/examples/person_arc.c
+++ b/misc/examples/smartpointers/person_arc.c
@@ -1,10 +1,12 @@
/* cbox: heap allocated boxed type */
+#define i_implement
#include <stc/cstr.h>
typedef struct { cstr name, last; } Person;
Person Person_make(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+ Person p = {.name = cstr_from(name), .last = cstr_from(last)};
+ return p;
}
int Person_cmp(const Person* a, const Person* b) {
@@ -28,16 +30,17 @@ void Person_drop(Person* p) {
}
#define i_type PSPtr
-#define i_valclass Person // ensure Person_drop
-#define i_cmp Person_cmp // specify object cmp, instead of ptr cmp for arc.
+#define i_keyclass Person // ensure Person_drop
+#define i_use_cmp
#include <stc/carc.h>
#define i_type Persons
-#define i_valboxed PSPtr // binds PSPtr_cmp, PSPtr_drop...
+#define i_keyboxed PSPtr // binds PSPtr_cmp, PSPtr_drop...
+#define i_use_cmp
#include <stc/cvec.h>
-int main()
+int main(void)
{
PSPtr p = PSPtr_from(Person_make("Laura", "Palmer"));
PSPtr q = PSPtr_from(Person_clone(*p.get)); // deep copy
diff --git a/misc/examples/csmap_erase.c b/misc/examples/sortedmaps/csmap_erase.c
index 697e6c09..8d4eeae3 100644
--- a/misc/examples/csmap_erase.c
+++ b/misc/examples/sortedmaps/csmap_erase.c
@@ -1,5 +1,6 @@
// map_erase.c
// From C++ example: https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-16
+#define i_implement
#include <stc/cstr.h>
#include <stdio.h>
@@ -15,7 +16,7 @@ void printmap(mymap m)
printf("\nsize() == %" c_ZI "\n\n", mymap_size(&m));
}
-int main()
+int main(void)
{
mymap m1 = {0};
@@ -34,7 +35,7 @@ int main()
printmap(m1);
// Fill in some data to test with
- mymap m2 = c_make(mymap, {
+ mymap m2 = c_init(mymap, {
{10, "Bob"},
{11, "Rob"},
{12, "Robert"},
diff --git a/misc/examples/csmap_find.c b/misc/examples/sortedmaps/csmap_find.c
index c417567a..c392338d 100644
--- a/misc/examples/csmap_find.c
+++ b/misc/examples/sortedmaps/csmap_find.c
@@ -1,5 +1,6 @@
// This implements the c++ std::map::find example at:
// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-17
+#define i_implement
#include <stc/cstr.h>
#define i_key int
@@ -7,8 +8,7 @@
#define i_tag istr
#include <stc/csmap.h>
-#define i_val csmap_istr_raw
-#define i_opt c_no_cmp
+#define i_key csmap_istr_raw
#define i_tag istr
#include <stc/cvec.h>
@@ -40,21 +40,21 @@ void findit(csmap_istr c, csmap_istr_key val)
}
}
-int main()
+int main(void)
{
- csmap_istr m1 = c_make(csmap_istr, {{40, "Zr"}, {45, "Rh"}});
+ csmap_istr m1 = c_init(csmap_istr, {{40, "Zr"}, {45, "Rh"}});
cvec_istr v = {0};
puts("The starting map m1 is (key, value):");
print_collection_csmap_istr(&m1);
typedef cvec_istr_value pair;
- cvec_istr_push(&v, (pair){43, "Tc"});
- cvec_istr_push(&v, (pair){41, "Nb"});
- cvec_istr_push(&v, (pair){46, "Pd"});
- cvec_istr_push(&v, (pair){42, "Mo"});
- cvec_istr_push(&v, (pair){44, "Ru"});
- cvec_istr_push(&v, (pair){44, "Ru"}); // attempt a duplicate
+ cvec_istr_push(&v, c_LITERAL(pair){43, "Tc"});
+ cvec_istr_push(&v, c_LITERAL(pair){41, "Nb"});
+ cvec_istr_push(&v, c_LITERAL(pair){46, "Pd"});
+ cvec_istr_push(&v, c_LITERAL(pair){42, "Mo"});
+ cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"});
+ cvec_istr_push(&v, c_LITERAL(pair){44, "Ru"}); // attempt a duplicate
puts("Inserting the following vector data into m1:");
print_collection_cvec_istr(&v);
diff --git a/misc/examples/csmap_insert.c b/misc/examples/sortedmaps/csmap_insert.c
index 3da245c7..04b8ddc6 100644
--- a/misc/examples/csmap_insert.c
+++ b/misc/examples/sortedmaps/csmap_insert.c
@@ -5,14 +5,14 @@
#define i_tag ii // Map of int => int
#include <stc/csmap.h>
+#define i_implement
#include <stc/cstr.h>
#define i_key int
#define i_val_str
#define i_tag istr // Map of int => cstr
#include <stc/csmap.h>
-#define i_val csmap_ii_raw
-#define i_opt c_no_cmp
+#define i_key csmap_ii_raw
#define i_tag ii
#include <stc/cvec.h>
@@ -28,12 +28,12 @@ void print_istr(csmap_istr map) {
puts("");
}
-int main()
+int main(void)
{
// insert single values
csmap_ii m1 = {0};
csmap_ii_insert(&m1, 1, 10);
- csmap_ii_push(&m1, (csmap_ii_value){2, 20});
+ csmap_ii_push(&m1, c_LITERAL(csmap_ii_value){2, 20});
puts("The original key and mapped values of m1 are:");
print_ii(m1);
@@ -60,11 +60,11 @@ int main()
csmap_ii m2 = {0};
cvec_ii v = {0};
typedef cvec_ii_value ipair;
- cvec_ii_push(&v, (ipair){43, 294});
- cvec_ii_push(&v, (ipair){41, 262});
- cvec_ii_push(&v, (ipair){45, 330});
- cvec_ii_push(&v, (ipair){42, 277});
- cvec_ii_push(&v, (ipair){44, 311});
+ cvec_ii_push(&v, c_LITERAL(ipair){43, 294});
+ cvec_ii_push(&v, c_LITERAL(ipair){41, 262});
+ cvec_ii_push(&v, c_LITERAL(ipair){45, 330});
+ cvec_ii_push(&v, c_LITERAL(ipair){42, 277});
+ cvec_ii_push(&v, c_LITERAL(ipair){44, 311});
puts("Inserting the following vector data into m2:");
c_foreach (e, cvec_ii, v)
@@ -96,7 +96,7 @@ int main()
csmap_ii m4 = {0};
// Insert the elements from an initializer_list
- m4 = c_make(csmap_ii, {{4, 44}, {2, 22}, {3, 33}, {1, 11}, {5, 55}});
+ m4 = c_init(csmap_ii, {{4, 44}, {2, 22}, {3, 33}, {1, 11}, {5, 55}});
puts("After initializer_list insertion, m4 contains:");
print_ii(m4);
puts("");
diff --git a/misc/examples/csset_erase.c b/misc/examples/sortedmaps/csset_erase.c
index 9fa40682..9c7f5e1a 100644
--- a/misc/examples/csset_erase.c
+++ b/misc/examples/sortedmaps/csset_erase.c
@@ -3,9 +3,9 @@
#define i_key int
#include <stc/csset.h>
-int main()
+int main(void)
{
- csset_int set = c_make(csset_int, {30, 20, 80, 40, 60, 90, 10, 70, 50});
+ csset_int set = c_init(csset_int, {30, 20, 80, 40, 60, 90, 10, 70, 50});
c_foreach (k, csset_int, set)
printf(" %d", *k.ref);
@@ -38,4 +38,4 @@ int main()
puts("");
csset_int_drop(&set);
-} \ No newline at end of file
+}
diff --git a/misc/examples/gauss2.c b/misc/examples/sortedmaps/gauss2.c
index df709d03..02ce4bc5 100644
--- a/misc/examples/gauss2.c
+++ b/misc/examples/sortedmaps/gauss2.c
@@ -1,33 +1,34 @@
#include <stdio.h>
#include <time.h>
-#include <stc/crand.h>
+#define i_implement
#include <stc/cstr.h>
+#include <stc/crand.h>
// Declare int -> int sorted map.
#define i_key int
#define i_val int
#include <stc/csmap.h>
-int main()
+int main(void)
{
enum {N = 5000000};
uint64_t seed = (uint64_t)time(NULL);
crand_t rng = crand_init(seed);
- const double Mean = round(crand_f64(&rng)*98.f - 49.f), StdDev = crand_f64(&rng)*10.f + 1.f, Scale = 74.f;
+ const double Mean = round(crand_f64(&rng)*98.0 - 49.0), StdDev = crand_f64(&rng)*10.0 + 1.0, Scale = 74.0;
printf("Demo of gaussian / normal distribution of %d random samples\n", N);
printf("Mean %f, StdDev %f\n", Mean, StdDev);
// 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 0394a2df..04a605a7 100644
--- a/misc/examples/mmap.c
+++ b/misc/examples/sortedmaps/listmap.c
@@ -2,8 +2,9 @@
// https://en.cppreference.com/w/cpp/container/multimap/insert
// Multimap entries
+#define i_implement
#include <stc/cstr.h>
-#define i_val_str
+#define i_key_str
#include <stc/clist.h>
// Map of int => clist_str.
@@ -29,7 +30,7 @@ void insert(Multimap* mmap, int key, const char* str)
clist_str_emplace_back(list, str);
}
-int main()
+int main(void)
{
Multimap mmap = {0};
diff --git a/misc/examples/mapmap.c b/misc/examples/sortedmaps/mapmap.c
index 668da5de..d3065659 100644
--- a/misc/examples/mapmap.c
+++ b/misc/examples/sortedmaps/mapmap.c
@@ -1,5 +1,5 @@
// create a structure like: std::map<std::string, std::map<std::string, std::string>>:
-
+#define i_implement
#include <stc/cstr.h>
// People: std::map<std::string, std::string>
diff --git a/misc/examples/multimap.c b/misc/examples/sortedmaps/multimap.c
index d8981a81..a4490f91 100644
--- a/misc/examples/multimap.c
+++ b/misc/examples/sortedmaps/multimap.c
@@ -1,3 +1,4 @@
+#define i_implement
#include <stc/cstr.h>
// Olympics multimap example
@@ -39,7 +40,8 @@ OlympicLoc OlympicLoc_clone(OlympicLoc loc);
void OlympicLoc_drop(OlympicLoc* self);
// Create a clist<OlympicLoc>, can be sorted by year.
-#define i_valclass OlympicLoc // binds _cmp, _clone and _drop.
+#define i_keyclass OlympicLoc // binds _cmp, _clone and _drop.
+#define i_use_cmp
#define i_tag OL
#include <stc/clist.h>
@@ -65,7 +67,7 @@ void OlympicLoc_drop(OlympicLoc* self) {
}
-int main()
+int main(void)
{
// Define the multimap with destructor defered to when block is completed.
csmap_OL multimap = {0};
diff --git a/misc/examples/new_smap.c b/misc/examples/sortedmaps/new_smap.c
index d8245b8b..ee946c9a 100644
--- a/misc/examples/new_smap.c
+++ b/misc/examples/sortedmaps/new_smap.c
@@ -1,3 +1,4 @@
+#define i_implement
#include <stc/cstr.h>
#include <stc/forward.h>
@@ -10,7 +11,7 @@ typedef struct {
} MyStruct;
// Point => int map
-struct Point { int x, y; } typedef Point;
+typedef struct Point { int x, y; } Point;
int point_cmp(const Point* a, const Point* b) {
int c = a->x - b->x;
return c ? c : a->y - b->y;
@@ -35,14 +36,14 @@ int point_cmp(const Point* a, const Point* b) {
#include <stc/csset.h>
-int main()
+int main(void)
{
- PMap pmap = c_make(PMap, {
+ PMap pmap = c_init(PMap, {
{{42, 14}, 1},
{{32, 94}, 2},
{{62, 81}, 3},
});
- SMap smap = c_make(SMap, {
+ SMap smap = c_init(SMap, {
{"Hello, friend", "this is the mapped value"},
{"The brown fox", "jumped"},
{"This is the time", "for all good things"},
diff --git a/misc/examples/sorted_map.c b/misc/examples/sortedmaps/sorted_map.c
index ae9b45a4..89381554 100644
--- a/misc/examples/sorted_map.c
+++ b/misc/examples/sortedmaps/sorted_map.c
@@ -1,11 +1,11 @@
// https://iq.opengenus.org/containers-cpp-stl/
+#include <stdio.h>
#define i_key int
#define i_val int
#include <stc/csmap.h>
-#include <stdio.h>
-int main()
+int main(void)
{
// empty map containers
diff --git a/misc/examples/spans/matmult.c b/misc/examples/spans/matmult.c
new file mode 100644
index 00000000..ec992ff9
--- /dev/null
+++ b/misc/examples/spans/matmult.c
@@ -0,0 +1,90 @@
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2642r2.html
+// C99:
+#include <stdio.h>
+#include <time.h>
+#include <stc/cspan.h>
+
+using_cspan3(Mat, double);
+typedef Mat2 OutMat;
+typedef struct { Mat2 m00, m01, m10, m11; } Partition;
+
+Partition partition(Mat2 A)
+{
+ int32_t M = A.shape[0];
+ int32_t N = A.shape[1];
+ return (Partition){
+ .m00 = cspan_slice(Mat2, &A, {0, M/2}, {0, N/2}),
+ .m01 = cspan_slice(Mat2, &A, {0, M/2}, {N/2, N}),
+ .m10 = cspan_slice(Mat2, &A, {M/2, M}, {0, N/2}),
+ .m11 = cspan_slice(Mat2, &A, {M/2, M}, {N/2, N}),
+ };
+}
+
+// Slow generic implementation
+void base_case_matrix_product(Mat2 A, Mat2 B, OutMat C)
+{
+ for (int j = 0; j < C.shape[1]; ++j) {
+ for (int i = 0; i < C.shape[0]; ++i) {
+ Mat2_value C_ij = 0;
+ for (int k = 0; k < A.shape[1]; ++k) {
+ C_ij += *cspan_at(&A, i,k) * *cspan_at(&B, k,j);
+ }
+ *cspan_at(&C, i,j) += C_ij;
+ }
+ }
+}
+
+void recursive_matrix_product(Mat2 A, Mat2 B, OutMat C)
+{
+ // Some hardware-dependent constant
+ enum {recursion_threshold = 32};
+ if (C.shape[0] <= recursion_threshold || C.shape[1] <= recursion_threshold) {
+ base_case_matrix_product(A, B, C);
+ } else {
+ Partition c = partition(C),
+ a = partition(A),
+ b = partition(B);
+ recursive_matrix_product(a.m00, b.m00, c.m00);
+ recursive_matrix_product(a.m01, b.m10, c.m00);
+ recursive_matrix_product(a.m10, b.m00, c.m10);
+ recursive_matrix_product(a.m11, b.m10, c.m10);
+ recursive_matrix_product(a.m00, b.m01, c.m01);
+ recursive_matrix_product(a.m01, b.m11, c.m01);
+ recursive_matrix_product(a.m10, b.m01, c.m11);
+ recursive_matrix_product(a.m11, b.m11, c.m11);
+ }
+}
+
+
+#define i_type Values
+#define i_val double
+#include <stc/cstack.h>
+#include <stc/crand.h>
+
+int main(void)
+{
+ enum {N = 10, D = 256};
+
+ Values values = {0};
+ for (int i=0; i < N*D*D; ++i)
+ Values_push(&values, (crandf() - 0.5)*4.0);
+
+ double out[D*D];
+ Mat3 data = cspan_md_layout(c_ROWMAJOR, values.data, N, D, D);
+ OutMat c = cspan_md_layout(c_COLMAJOR, out, D, D);
+ Mat2 a = cspan_submd3(&data, 0);
+
+ clock_t t = clock();
+ for (int i=1; i<N; ++i) {
+ Mat2 b = cspan_submd3(&data, i);
+ memset(out, 0, sizeof out);
+ recursive_matrix_product(a, b, c);
+ //base_case_matrix_product(a, b, c);
+ }
+ t = clock() - t;
+
+ double sum = 0.0;
+ c_foreach (i, Mat2, c) sum += *i.ref;
+ printf("sum=%.16g, %f ms\n", sum, (double)t*1000.0/CLOCKS_PER_SEC);
+ Values_drop(&values);
+}
diff --git a/misc/examples/spans/mdspan.c b/misc/examples/spans/mdspan.c
new file mode 100644
index 00000000..630ffddb
--- /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_layout(c_COLMAJOR, data, nx, ny, nz);
+
+ 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/spans/multidim.c b/misc/examples/spans/multidim.c
new file mode 100644
index 00000000..70fda7e2
--- /dev/null
+++ b/misc/examples/spans/multidim.c
@@ -0,0 +1,76 @@
+// Example based on https://en.cppreference.com/w/cpp/container/mdspan
+#define i_val int
+#include <stc/cstack.h>
+#define i_implement
+#include <stc/cspan.h>
+#include <stdio.h>
+
+using_cspan3(ispan, int);
+
+void print2d(ispan2 ms2) {
+ for (int i=0; i < ms2.shape[0]; i++) {
+ for (int j=0; j < ms2.shape[1]; j++)
+ printf(" %3d", *cspan_at(&ms2, i, j));
+ puts("");
+ }
+}
+
+void print3d(ispan3 ms3) {
+ for (int i=0; i < ms3.shape[0]; i++) {
+ for (int j=0; j < ms3.shape[1]; j++) {
+ for (int k=0; k < ms3.shape[2]; k++)
+ printf(" %3d", *cspan_at(&ms3, i, j, k));
+ puts("");
+ }
+ puts("");
+ }
+}
+
+int main(void)
+{
+ cstack_int v = c_init(cstack_int, {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24});
+
+ // Create 1d span from a compatibel container
+ ispan ms1 = cspan_from(&v);
+
+ // Create a 3D mdspan 2 x 3 x 4
+ ispan3 ms3 = cspan_md(v.data, 2, 3, 4);
+
+ puts("ms3:");
+ print3d(ms3);
+
+ // Take a slice of md3
+ ispan3 ss3 = cspan_slice(ispan3, &ms3, {c_ALL}, {1,3}, {1,3});
+ puts("ss3 = ms3[:, 1:3, 1:3]");
+ print3d(ss3);
+
+ puts("Iterate ss3 flat:");
+ c_foreach (i, ispan3, ss3) printf(" %d", *i.ref);
+ puts("");
+
+ // submd3 span reduces rank depending on number of arguments
+ ispan2 ms2 = cspan_submd3(&ms3, 1);
+
+ // Change data on the 2d subspan
+ for (int i=0; i != ms2.shape[0]; i++)
+ for (int j=0; j != ms2.shape[1]; j++)
+ *cspan_at(&ms2, i, j) = (i + 1)*100 + j;
+
+ puts("\nms2 = ms3[1] with updated data:");
+ print2d(ms2);
+ puts("");
+
+ puts("\nOriginal s1 span with updated data:");
+ c_foreach (i, ispan, ms1) printf(" %d", *i.ref);
+ puts("");
+
+ puts("\nOriginal ms3 span with updated data:");
+ print3d(ms3);
+
+ puts("col = ms3[1, :, 2]");
+ ispan col = cspan_slice(ispan, &ms3, {1}, {c_ALL}, {2});
+ c_foreach (i, ispan, col) printf(" %d", *i.ref);
+ puts("");
+
+ cstack_int_drop(&v);
+}
diff --git a/misc/examples/spans/printspan.c b/misc/examples/spans/printspan.c
new file mode 100644
index 00000000..b6999b61
--- /dev/null
+++ b/misc/examples/spans/printspan.c
@@ -0,0 +1,41 @@
+// https://www.modernescpp.com/index.php/c-20-std-span/
+
+#include <stdio.h>
+#define i_key int
+#include <stc/cvec.h>
+
+#define i_key int
+#include <stc/cstack.h>
+
+#include <stc/cspan.h>
+using_cspan(intspan, int);
+
+
+void printMe(intspan container) {
+ printf("%d:", (int)cspan_size(&container));
+ c_foreach (e, intspan, container)
+ printf(" %d", *e.ref);
+ puts("");
+}
+
+
+int main(void)
+{
+ printMe( c_init(intspan, {1, 2, 3, 4}) );
+
+ int arr[] = {1, 2, 3, 4, 5};
+ printMe( (intspan)cspan_from_array(arr) );
+
+ cvec_int vec = c_init(cvec_int, {1, 2, 3, 4, 5, 6});
+ printMe( (intspan)cspan_from(&vec) );
+
+ cstack_int stk = c_init(cstack_int, {1, 2, 3, 4, 5, 6, 7});
+ printMe( (intspan)cspan_from(&stk) );
+
+ intspan spn = c_init(intspan, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
+ printMe( (intspan)cspan_subspan(&spn, 2, 8) );
+
+ // cleanup
+ cvec_int_drop(&vec);
+ cstack_int_drop(&stk);
+}
diff --git a/misc/examples/spans/submdspan.c b/misc/examples/spans/submdspan.c
new file mode 100644
index 00000000..0752dfa1
--- /dev/null
+++ b/misc/examples/spans/submdspan.c
@@ -0,0 +1,44 @@
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2630r0.html
+// C99:
+#include <stdio.h>
+#include <stc/cspan.h>
+
+using_cspan3(span, double); // shorthand for defining span, span2, span3
+
+// Set all elements of a rank-2 mdspan to zero.
+void zero_2d(span2 grid2d) {
+ (void)c_static_assert(cspan_rank(&grid2d) == 2);
+ for (int i = 0; i < grid2d.shape[0]; ++i) {
+ for (int j = 0; j < grid2d.shape[1]; ++j) {
+ *cspan_at(&grid2d, i,j) = 0;
+ }
+ }
+}
+
+void zero_surface(span3 grid3d) {
+ (void)c_static_assert(cspan_rank(&grid3d) == 3);
+ zero_2d(cspan_slice(span2, &grid3d, {0}, {c_ALL}, {c_ALL}));
+ zero_2d(cspan_slice(span2, &grid3d, {c_ALL}, {0}, {c_ALL}));
+ zero_2d(cspan_slice(span2, &grid3d, {c_ALL}, {c_ALL}, {0}));
+ zero_2d(cspan_slice(span2, &grid3d, {grid3d.shape[0]-1}, {c_ALL}, {c_ALL}));
+ zero_2d(cspan_slice(span2, &grid3d, {c_ALL}, {grid3d.shape[1]-1}, {c_ALL}));
+ zero_2d(cspan_slice(span2, &grid3d, {c_ALL}, {c_ALL}, {grid3d.shape[2]-1}));
+}
+
+int main() {
+ double arr[3*4*5];
+ for (int i=0; i<c_arraylen(arr); ++i) arr[i] = i + 1.0;
+
+ span3 md = cspan_md(arr, 3, 4, 5);
+
+ zero_surface(md);
+
+ for (int i = 0; i < md.shape[0]; i++) {
+ for (int j = 0; j < md.shape[1]; j++) {
+ for (int k = 0; k < md.shape[2]; k++)
+ printf(" %2g", *cspan_at(&md, i,j,k));
+ puts("");
+ }
+ puts("");
+ }
+}
diff --git a/misc/examples/cstr_match.c b/misc/examples/strings/cstr_match.c
index 58cf8884..80013019 100644
--- a/misc/examples/cstr_match.c
+++ b/misc/examples/strings/cstr_match.c
@@ -1,10 +1,11 @@
+#define i_implement
#include <stc/cstr.h>
#include <stc/csview.h>
#include <stdio.h>
-int main()
+int main(void)
{
- cstr ss = cstr_lit("The quick brown fox jumps over the lazy dog.JPG");
+ cstr ss = cstr_from("The quick brown fox jumps over the lazy dog.JPG");
intptr_t pos = cstr_find_at(&ss, 0, "brown");
printf("%" c_ZI " [%s]\n", pos, pos == c_NPOS ? "<NULL>" : cstr_str(&ss) + pos);
diff --git a/misc/examples/replace.c b/misc/examples/strings/replace.c
index cf5b45cb..59a56bf7 100644
--- a/misc/examples/replace.c
+++ b/misc/examples/strings/replace.c
@@ -1,6 +1,7 @@
+#define i_implement
#include <stc/cstr.h>
-int main ()
+int main(void)
{
const char *base = "this is a test string.";
const char *s2 = "n example";
diff --git a/misc/examples/splitstr.c b/misc/examples/strings/splitstr.c
index 2bc6fc07..ef7ed174 100644
--- a/misc/examples/splitstr.c
+++ b/misc/examples/strings/splitstr.c
@@ -1,9 +1,10 @@
#include <stdio.h>
-#define i_extern // cstr + utf8 functions
+#define i_import // cstr + utf8 functions
#include <stc/cregex.h>
+#define i_implement
#include <stc/csview.h>
-int main()
+int main(void)
{
puts("Split with c_fortoken (csview):");
diff --git a/misc/examples/sso_map.c b/misc/examples/strings/sso_map.c
index 70450e21..4f84b651 100644
--- a/misc/examples/sso_map.c
+++ b/misc/examples/strings/sso_map.c
@@ -1,9 +1,10 @@
+#define i_implement
#include <stc/cstr.h>
#define i_key_str
#define i_val_str
#include <stc/cmap.h>
-int main()
+int main(void)
{
cmap_str m = {0};
cmap_str_emplace(&m, "Test short", "This is a short string");
diff --git a/misc/examples/sso_substr.c b/misc/examples/strings/sso_substr.c
index 4b2dbcc8..70d34440 100644
--- a/misc/examples/sso_substr.c
+++ b/misc/examples/strings/sso_substr.c
@@ -1,18 +1,20 @@
+#define i_implement
#include <stc/cstr.h>
+#define i_implement
#include <stc/csview.h>
-int main ()
+int main(void)
{
- cstr str = cstr_lit("We think in generalities, but we live in details.");
+ cstr str = cstr_from("We think in generalities, but we live in details.");
csview sv1 = cstr_substr_ex(&str, 3, 5); // "think"
- intptr_t pos = cstr_find(&str, "live"); // position of "live"
+ intptr_t pos = cstr_find(&str, "live"); // position of "live"
csview sv2 = cstr_substr_ex(&str, pos, 4); // "live"
csview sv3 = cstr_slice_ex(&str, -8, -1); // "details"
printf("%.*s, %.*s, %.*s\n", c_SV(sv1), c_SV(sv2), c_SV(sv3));
cstr_assign(&str, "apples are green or red");
- cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red"
- cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples"
+ cstr s2 = cstr_from_sv(cstr_substr_ex(&str, -3, 3)); // "red"
+ cstr s3 = cstr_from_sv(cstr_substr_ex(&str, 0, 6)); // "apples"
printf("%s %s: %d, %d\n", cstr_str(&s2), cstr_str(&s3),
cstr_is_long(&str), cstr_is_long(&s2));
c_drop (cstr, &str, &s2, &s3);
diff --git a/misc/examples/sview_split.c b/misc/examples/strings/sview_split.c
index 31a28e51..ac275da0 100644
--- a/misc/examples/sview_split.c
+++ b/misc/examples/strings/sview_split.c
@@ -1,7 +1,9 @@
+#define i_implement
#include <stc/cstr.h>
+#define i_implement
#include <stc/csview.h>
-int main()
+int main(void)
{
// No memory allocations or string length calculations!
const csview date = c_sv("2021/03/12");
diff --git a/misc/examples/utf8replace_c.c b/misc/examples/strings/utf8replace_c.c
index 3cde8701..317313b0 100644
--- a/misc/examples/utf8replace_c.c
+++ b/misc/examples/strings/utf8replace_c.c
@@ -1,6 +1,7 @@
+#define i_implement
#include <stc/cstr.h>
-int main()
+int main(void)
{
cstr hello = cstr_lit("hell😀 w😀rld");
printf("%s\n", cstr_str(&hello));
@@ -14,7 +15,7 @@ int main()
printf("%s\n", cstr_str(&hello));
c_foreach (c, cstr, hello)
- printf("%.*s,", c_SV(c.u8.chr));
+ printf("%.*s,", c_SV(c.chr));
cstr str = cstr_lit("scooby, dooby doo");
cstr_replace(&str, "oo", "00");
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/triples.c b/misc/examples/triples.c
deleted file mode 100644
index 520bf012..00000000
--- a/misc/examples/triples.c
+++ /dev/null
@@ -1,69 +0,0 @@
-// https://quuxplusone.github.io/blog/2019/03/06/pythagorean-triples/
-
-#include <stc/algo/coroutine.h>
-#include <stdio.h>
-
-void triples_vanilla(int n) {
- for (int c = 5; n; ++c) {
- for (int a = 1; a < c; ++a) {
- for (int b = a + 1; b < c; ++b) {
- if ((int64_t)a*a + (int64_t)b*b == (int64_t)c*c) {
- printf("{%d, %d, %d}\n", a, b, c);
- if (--n == 0) goto done;
- }
- }
- }
- }
- done:;
-}
-
-struct triples {
- int n;
- int a, b, c;
- int cco_state;
-};
-
-bool triples_next(struct triples* I) {
- cco_begin(I);
- for (I->c = 5; I->n; ++I->c) {
- for (I->a = 1; I->a < I->c; ++I->a) {
- for (I->b = I->a + 1; I->b < I->c; ++I->b) {
- if ((int64_t)I->a*I->a + (int64_t)I->b*I->b == (int64_t)I->c*I->c) {
- cco_yield(true);
- if (--I->n == 0) cco_return;
- }
- }
- }
- }
- cco_final:
- puts("done");
- cco_end(false);
-}
-
-int gcd(int a, int b) {
- while (b) {
- int t = a % b;
- a = b;
- b = t;
- }
- return a;
-}
-
-int main()
-{
- puts("Vanilla triples:");
- triples_vanilla(6);
-
- puts("\nCoroutine triples:");
- struct triples t = {INT32_MAX};
- int n = 0;
-
- while (triples_next(&t)) {
- if (gcd(t.a, t.b) > 1)
- continue;
- if (t.c < 100)
- printf("%d: {%d, %d, %d}\n", ++n, t.a, t.b, t.c);
- else
- cco_stop(&t);
- }
-}
diff --git a/misc/examples/lower_bound.c b/misc/examples/vectors/lower_bound.c
index 6ec7544c..09cf2008 100644
--- a/misc/examples/lower_bound.c
+++ b/misc/examples/vectors/lower_bound.c
@@ -1,17 +1,18 @@
#include <stdio.h>
-#define i_val int
+#define i_key int
+#define i_use_cmp
#include <stc/cvec.h>
-#define i_val int
+#define i_key int
#include <stc/csset.h>
-int main()
+int main(void)
{
// TEST SORTED VECTOR
{
int key, *res;
- cvec_int vec = c_make(cvec_int, {40, 600, 1, 7000, 2, 500, 30});
+ cvec_int vec = c_init(cvec_int, {40, 600, 1, 7000, 2, 500, 30});
cvec_int_sort(&vec);
@@ -40,7 +41,7 @@ int main()
// TEST SORTED SET
{
int key, *res;
- csset_int set = c_make(csset_int, {40, 600, 1, 7000, 2, 500, 30});
+ csset_int set = c_init(csset_int, {40, 600, 1, 7000, 2, 500, 30});
key = 100;
res = csset_int_lower_bound(&set, key).ref;
diff --git a/misc/examples/new_vec.c b/misc/examples/vectors/new_vec.c
index df443b7f..88efd55a 100644
--- a/misc/examples/new_vec.c
+++ b/misc/examples/vectors/new_vec.c
@@ -4,32 +4,33 @@
forward_cvec(cvec_i32, int);
forward_cvec(cvec_pnt, struct Point);
-struct MyStruct {
+typedef struct MyStruct {
cvec_i32 intvec;
cvec_pnt pntvec;
-} typedef MyStruct;
+} MyStruct;
-#define i_val int
-#define i_is_forward
+#define i_key int
#define i_tag i32
+#define i_is_forward
#include <stc/cvec.h>
typedef struct Point { int x, y; } Point;
-#define i_val Point
+#define i_key Point
+#define i_tag pnt
#define i_less(a, b) a->x < b->x || (a->x == b->x && a->y < b->y)
+#define i_eq(a, b) a->x == b->x && a->y == b->y
#define i_is_forward
-#define i_tag pnt
#include <stc/cvec.h>
-int main()
+int main(void)
{
MyStruct my = {0};
- cvec_pnt_push(&my.pntvec, (Point){42, 14});
- cvec_pnt_push(&my.pntvec, (Point){32, 94});
- cvec_pnt_push(&my.pntvec, (Point){62, 81});
- cvec_pnt_push(&my.pntvec, (Point){32, 91});
+ cvec_pnt_push(&my.pntvec, c_LITERAL(Point){42, 14});
+ cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 94});
+ cvec_pnt_push(&my.pntvec, c_LITERAL(Point){62, 81});
+ cvec_pnt_push(&my.pntvec, c_LITERAL(Point){32, 91});
cvec_pnt_sort(&my.pntvec);
diff --git a/misc/examples/stack.c b/misc/examples/vectors/stack.c
index c817e1ae..6297fb6f 100644
--- a/misc/examples/stack.c
+++ b/misc/examples/vectors/stack.c
@@ -3,14 +3,14 @@
#define i_tag i
#define i_capacity 100
-#define i_val int
+#define i_key int
#include <stc/cstack.h>
#define i_tag c
-#define i_val char
+#define i_key char
#include <stc/cstack.h>
-int main() {
+int main(void) {
cstack_i stack = {0};
cstack_c chars = {0};
diff --git a/misc/tests/cregex_test.c b/misc/tests/cregex_test.c
index aa4b2a65..a83b7593 100644
--- a/misc/tests/cregex_test.c
+++ b/misc/tests/cregex_test.c
@@ -1,9 +1,10 @@
-#define i_extern
+#define i_import
#include <stc/cregex.h>
#include <stc/csview.h>
+#include <stc/algo/raii.h>
#include "ctest.h"
-#define M_START(m) ((m).str - inp)
+#define M_START(m) ((m).buf - inp)
#define M_END(m) (M_START(m) + (m).size)
@@ -14,7 +15,7 @@ CTEST(cregex, compile_match_char)
ASSERT_EQ(re.error, 0);
csview match;
- ASSERT_EQ(cregex_find(&re, inp="äsdf", &match, CREG_M_FULLMATCH), CREG_OK);
+ ASSERT_EQ(cregex_find(&re, inp="äsdf", &match, CREG_FULLMATCH), CREG_OK);
ASSERT_EQ(M_START(match), 0);
ASSERT_EQ(M_END(match), 5); // ä is two bytes wide
@@ -192,14 +193,14 @@ CTEST(cregex, search_all)
int res;
ASSERT_EQ(re.error, CREG_OK);
inp="ab,ab,ab";
- res = cregex_find(&re, inp, &m, CREG_M_NEXT);
+ res = cregex_find(&re, inp, &m, CREG_NEXT);
ASSERT_EQ(M_START(m), 0);
- res = cregex_find(&re, inp, &m, CREG_M_NEXT);
+ res = cregex_find(&re, inp, &m, CREG_NEXT);
ASSERT_EQ(res, CREG_OK);
ASSERT_EQ(M_START(m), 3);
- res = cregex_find(&re, inp, &m, CREG_M_NEXT);
+ res = cregex_find(&re, inp, &m, CREG_NEXT);
ASSERT_EQ(M_START(m), 6);
- res = cregex_find(&re, inp, &m, CREG_M_NEXT);
+ res = cregex_find(&re, inp, &m, CREG_NEXT);
ASSERT_NE(res, CREG_OK);
}
}
@@ -208,7 +209,7 @@ CTEST(cregex, captures_len)
{
c_auto (cregex, re) {
re = cregex_from("(ab(cd))(ef)");
- ASSERT_EQ(cregex_captures(&re), 4);
+ ASSERT_EQ(cregex_captures(&re), 3);
}
}
@@ -217,7 +218,7 @@ CTEST(cregex, captures_cap)
const char* inp;
c_auto (cregex, re) {
re = cregex_from("(ab)((cd)+)");
- ASSERT_EQ(cregex_captures(&re), 4);
+ ASSERT_EQ(cregex_captures(&re), 3);
csview cap[5];
ASSERT_EQ(cregex_find(&re, inp="xxabcdcde", cap), CREG_OK);
@@ -237,7 +238,7 @@ CTEST(cregex, captures_cap)
static bool add_10_years(int i, csview match, cstr* out) {
if (i == 1) { // group 1 matches year
int year;
- sscanf(match.str, "%4d", &year); // scan 4 chars only
+ sscanf(match.buf, "%4d", &year); // scan 4 chars only
cstr_printf(out, "%04d", year + 10);
return true;
}
@@ -272,14 +273,14 @@ CTEST(cregex, replace)
// Compile RE separately
re = cregex_from(pattern);
- ASSERT_EQ(cregex_captures(&re), 4);
+ ASSERT_EQ(cregex_captures(&re), 3);
// European date format.
cstr_take(&str, cregex_replace(&re, input, "$3.$2.$1"));
ASSERT_STREQ(cstr_str(&str), "start date: 31.12.2015, end date: 28.02.2022");
// Strip out everything but the matches
- cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_R_STRIP));
+ cstr_take(&str, cregex_replace_sv(&re, csview_from(input), "$3.$2.$1;", 0, NULL, CREG_STRIP));
ASSERT_STREQ(cstr_str(&str), "31.12.2015;28.02.2022;");
}
}
diff --git a/misc/tests/cspan_test.c b/misc/tests/cspan_test.c
index 5d46f579..ce267b14 100644
--- a/misc/tests/cspan_test.c
+++ b/misc/tests/cspan_test.c
@@ -9,11 +9,11 @@ CTEST(cspan, subdim) {
int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
intspan3 m = cspan_md(array, 2, 2, 3);
- for (size_t i = 0; i < m.shape[0]; ++i) {
+ for (int i = 0; i < m.shape[0]; ++i) {
intspan2 sub_i = cspan_submd3(&m, i);
- for (size_t j = 0; j < m.shape[1]; ++j) {
+ for (int j = 0; j < m.shape[1]; ++j) {
intspan sub_i_j = cspan_submd2(&sub_i, j);
- for (size_t k = 0; k < m.shape[2]; ++k) {
+ for (int k = 0; k < m.shape[2]; ++k) {
ASSERT_EQ(*cspan_at(&sub_i_j, k), *cspan_at(&m, i, j, k));
}
}
@@ -24,18 +24,18 @@ CTEST(cspan, slice) {
int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
intspan2 m1 = cspan_md(array, 3, 4);
- size_t sum1 = 0;
- for (size_t i = 0; i < m1.shape[0]; ++i) {
- for (size_t j = 0; j < m1.shape[1]; ++j) {
+ int sum1 = 0;
+ for (int i = 0; i < m1.shape[0]; ++i) {
+ for (int j = 0; j < m1.shape[1]; ++j) {
sum1 += *cspan_at(&m1, i, j);
}
}
intspan2 m2 = cspan_slice(intspan2, &m1, {c_ALL}, {2,4});
- size_t sum2 = 0;
- for (size_t i = 0; i < m2.shape[0]; ++i) {
- for (size_t j = 0; j < m2.shape[1]; ++j) {
+ int sum2 = 0;
+ for (int i = 0; i < m2.shape[0]; ++i) {
+ for (int j = 0; j < m2.shape[1]; ++j) {
sum2 += *cspan_at(&m2, i, j);
}
}
@@ -43,11 +43,12 @@ CTEST(cspan, slice) {
ASSERT_EQ(45, sum2);
}
-#define i_val int
+#define i_key int
#include <stc/cstack.h>
CTEST(cspan, slice2) {
- c_auto (cstack_int, stack)
+ cstack_int stack = {0};
+ c_defer (cstack_int_drop(&stack))
{
c_forrange (i, 10*20*30)
cstack_int_push(&stack, i);
@@ -55,10 +56,10 @@ CTEST(cspan, slice2) {
intspan3 ms3 = cspan_md(stack.data, 10, 20, 30);
ms3 = cspan_slice(intspan3, &ms3, {1,4}, {3,7}, {20,24});
- size_t sum = 0;
- for (size_t i = 0; i < ms3.shape[0]; ++i) {
- for (size_t j = 0; j < ms3.shape[1]; ++j) {
- for (size_t k = 0; k < ms3.shape[2]; ++k) {
+ int sum = 0;
+ for (int i = 0; i < ms3.shape[0]; ++i) {
+ for (int j = 0; j < ms3.shape[1]; ++j) {
+ for (int k = 0; k < ms3.shape[2]; ++k) {
sum += *cspan_at(&ms3, i, j, k);
}
}
@@ -74,7 +75,7 @@ CTEST(cspan, slice2) {
#define i_type Tiles
-#define i_val intspan3
+#define i_key intspan3
#include <stc/cstack.h>
CTEST_FIXTURE(cspan_cube) {
@@ -112,10 +113,9 @@ CTEST_TEARDOWN(cspan_cube) {
CTEST_F(cspan_cube, slice3) {
- intptr_t n = cstack_int_size(&_self->stack);
- //printf("\ntiles: %zi, cells: %zi\n", Tiles_size(&_self->tiles), n);
+ long long n = cstack_int_size(&_self->stack);
+ long long sum = 0;
- int64_t sum = 0;
// iterate each 3d tile in sequence
c_foreach (i, Tiles, _self->tiles)
c_foreach (t, intspan3, *i.ref)
diff --git a/misc/tests/ctest.h b/misc/tests/ctest.h
index 373cda0e..6b1b1084 100644
--- a/misc/tests/ctest.h
+++ b/misc/tests/ctest.h
@@ -408,7 +408,8 @@ void assert_dbl_compare(const char* cmp, double exp, double real, double tol, co
void assert_pointers(const char* cmp, const void* exp, const void* real, const char* caller, int line) {
if ((exp == real) != (cmp[0] == '=')) {
- CTEST_ERR("%s:%d assertion failed (0x%02llx) %s (0x%02llx)", caller, line, (unsigned long long)exp , cmp, (unsigned long long)real);
+ CTEST_ERR("%s:%d assertion failed (0x%02llx) %s (0x%02llx)", caller, line,
+ (unsigned long long)(uintptr_t)exp , cmp, (unsigned long long)(uintptr_t)real);
}
}
diff --git a/src/cregex.c b/src/cregex.c
index 0688d9e1..7907ddd9 100644
--- a/src/cregex.c
+++ b/src/cregex.c
@@ -25,9 +25,24 @@ THE SOFTWARE.
*/
#ifndef CREGEX_C_INCLUDED
#define CREGEX_C_INCLUDED
-#include <stc/cstr.h>
-#include <stc/cregex.h> // header only
+
#include <setjmp.h>
+#ifdef i_import
+# define _i_import
+#endif
+#ifndef CREGEX_H_INCLUDED
+# include "../include/stc/cregex.h"
+#endif
+#ifdef _i_import
+# include "utf8code.c"
+#endif
+#ifdef _i_import
+# define i_implement
+#else
+# undef i_implement
+#endif
+#undef _i_import
+#include "../include/stc/cstr.h"
typedef uint32_t _Rune; /* Utf8 code point */
typedef int32_t _Token;
@@ -249,8 +264,8 @@ _renewmatch(_Resub *mp, int ms, _Resublist *sp, int nsubids)
{
if (mp==NULL || ms==0)
return;
- if (mp[0].str == NULL || sp->m[0].str < mp[0].str ||
- (sp->m[0].str == mp[0].str && sp->m[0].size > mp[0].size)) {
+ if (mp[0].buf == NULL || sp->m[0].buf < mp[0].buf ||
+ (sp->m[0].buf == mp[0].buf && sp->m[0].size > mp[0].size)) {
for (int i=0; i<ms && i<=nsubids; i++)
mp[i] = sp->m[i];
}
@@ -271,7 +286,7 @@ _renewthread(_Relist *lp, /* _relist to add to */
for (p=lp; p->inst; p++) {
if (p->inst == ip) {
- if (sep->m[0].str < p->se.m[0].str) {
+ if (sep->m[0].buf < p->se.m[0].buf) {
if (ms > 1)
p->se = *sep;
else
@@ -303,10 +318,10 @@ _renewemptythread(_Relist *lp, /* _relist to add to */
for (p=lp; p->inst; p++) {
if (p->inst == ip) {
- if (sp < p->se.m[0].str) {
+ if (sp < p->se.m[0].buf) {
if (ms > 1)
memset(&p->se, 0, sizeof(p->se));
- p->se.m[0].str = sp;
+ p->se.m[0].buf = sp;
}
return 0;
}
@@ -314,7 +329,7 @@ _renewemptythread(_Relist *lp, /* _relist to add to */
p->inst = ip;
if (ms > 1)
memset(&p->se, 0, sizeof(p->se));
- p->se.m[0].str = sp;
+ p->se.m[0].buf = sp;
(++p)->inst = NULL;
return p;
}
@@ -347,7 +362,7 @@ typedef struct _Parser
bool lastwasand; /* Last token was _operand */
short nbra;
short nclass;
- size_t instcap;
+ intptr_t instcap;
_Rune yyrune; /* last lex'd rune */
_Reclass *yyclassp; /* last lex'd class */
_Reclass* classp;
@@ -547,11 +562,11 @@ _optimize(_Parser *par, _Reprog *pp)
* necessary. Reallocate to the actual space used
* and then relocate the code.
*/
- if ((par->freep - pp->firstinst)*2 > (ptrdiff_t)par->instcap)
+ if ((par->freep - pp->firstinst)*2 > par->instcap)
return pp;
- intptr_t ipp = (intptr_t)pp;
- size_t size = sizeof(_Reprog) + (size_t)(par->freep - pp->firstinst)*sizeof(_Reinst);
+ intptr_t ipp = (intptr_t)pp; // convert pointer to intptr_t!
+ intptr_t size = c_sizeof(_Reprog) + (par->freep - pp->firstinst)*c_sizeof(_Reinst);
_Reprog *npp = (_Reprog *)c_realloc(pp, size);
ptrdiff_t diff = (intptr_t)npp - ipp;
@@ -842,20 +857,21 @@ _bldcclass(_Parser *par)
static _Reprog*
-_regcomp1(_Reprog *progp, _Parser *par, const char *s, int cflags)
+_regcomp1(_Reprog *pp, _Parser *par, const char *s, int cflags)
{
_Token token;
/* get memory for the program. estimated max usage */
- par->instcap = 5U + 6*strlen(s);
- _Reprog* pp = (_Reprog *)c_realloc(progp, sizeof(_Reprog) + par->instcap*sizeof(_Reinst));
- if (pp == NULL) {
+ par->instcap = 5 + 6*c_strlen(s);
+ _Reprog* old_pp = pp;
+ pp = (_Reprog *)c_realloc(pp, c_sizeof(_Reprog) + par->instcap*c_sizeof(_Reinst));
+ if (! pp) {
+ c_free(old_pp);
par->error = CREG_OUTOFMEMORY;
- c_free(progp);
return NULL;
}
- pp->flags.icase = (cflags & CREG_C_ICASE) != 0;
- pp->flags.dotall = (cflags & CREG_C_DOTALL) != 0;
+ pp->flags.icase = (cflags & CREG_ICASE) != 0;
+ pp->flags.dotall = (cflags & CREG_DOTALL) != 0;
par->freep = pp->firstinst;
par->classp = pp->cclass;
par->error = 0;
@@ -928,14 +944,14 @@ _runematch(_Rune s, _Rune r)
case ASC_LO: inv = 1; case ASC_lo: return inv ^ (islower((int)r) != 0);
case ASC_UP: inv = 1; case ASC_up: return inv ^ (isupper((int)r) != 0);
case ASC_XD: inv = 1; case ASC_xd: return inv ^ (isxdigit((int)r) != 0);
- case UTF_AN: inv = 1; case UTF_an: return inv ^ utf8_isalnum(r);
- case UTF_BL: inv = 1; case UTF_bl: return inv ^ utf8_isblank(r);
- case UTF_SP: inv = 1; case UTF_sp: return inv ^ utf8_isspace(r);
- case UTF_LL: inv = 1; case UTF_ll: return inv ^ utf8_islower(r);
- case UTF_LU: inv = 1; case UTF_lu: return inv ^ utf8_isupper(r);
- case UTF_LC: inv = 1; case UTF_lc: return inv ^ utf8_iscased(r);
- case UTF_AL: inv = 1; case UTF_al: return inv ^ utf8_isalpha(r);
- case UTF_WR: inv = 1; case UTF_wr: return inv ^ utf8_isword(r);
+ case UTF_AN: inv = 1; case UTF_an: return inv ^ (int)utf8_isalnum(r);
+ case UTF_BL: inv = 1; case UTF_bl: return inv ^ (int)utf8_isblank(r);
+ case UTF_SP: inv = 1; case UTF_sp: return inv ^ (int)utf8_isspace(r);
+ case UTF_LL: inv = 1; case UTF_ll: return inv ^ (int)utf8_islower(r);
+ case UTF_LU: inv = 1; case UTF_lu: return inv ^ (int)utf8_isupper(r);
+ case UTF_LC: inv = 1; case UTF_lc: return inv ^ (int)utf8_iscased(r);
+ case UTF_AL: inv = 1; case UTF_al: return inv ^ (int)utf8_isalpha(r);
+ case UTF_WR: inv = 1; case UTF_wr: return inv ^ (int)utf8_isword(r);
case UTF_cc: case UTF_CC:
case UTF_lt: case UTF_LT:
case UTF_nd: case UTF_ND:
@@ -956,7 +972,7 @@ _runematch(_Rune s, _Rune r)
case UTF_latin: case UTF_LATIN:
n = (int)s - UTF_GRP;
inv = n & 1;
- return inv ^ utf8_isgroup(n / 2, r);
+ return inv ^ (int)utf8_isgroup(n / 2, r);
}
return s == r;
}
@@ -989,7 +1005,7 @@ _regexec1(const _Reprog *progp, /* program to run */
checkstart = j->starttype;
if (mp)
for (i=0; i<ms; i++) {
- mp[i].str = NULL;
+ mp[i].buf = NULL;
mp[i].size = 0;
}
j->relist[0][0].inst = NULL;
@@ -1050,10 +1066,10 @@ _regexec1(const _Reprog *progp, /* program to run */
icase = inst->type == TOK_ICASE;
continue;
case TOK_LBRA:
- tlp->se.m[inst->r.subid].str = s;
+ tlp->se.m[inst->r.subid].buf = s;
continue;
case TOK_RBRA:
- tlp->se.m[inst->r.subid].size = (s - tlp->se.m[inst->r.subid].str);
+ tlp->se.m[inst->r.subid].size = (s - tlp->se.m[inst->r.subid].buf);
continue;
case TOK_ANY:
ok = (r != '\n');
@@ -1100,10 +1116,10 @@ _regexec1(const _Reprog *progp, /* program to run */
/* efficiency: advance and re-evaluate */
continue;
case TOK_END: /* Match! */
- match = !(mflags & CREG_M_FULLMATCH) ||
+ match = !(mflags & CREG_FULLMATCH) ||
((s == j->eol || r == 0 || r == '\n') &&
- (tlp->se.m[0].str == bol || tlp->se.m[0].str[-1] == '\n'));
- tlp->se.m[0].size = (s - tlp->se.m[0].str);
+ (tlp->se.m[0].buf == bol || tlp->se.m[0].buf[-1] == '\n'));
+ tlp->se.m[0].size = (s - tlp->se.m[0].buf);
if (mp != NULL)
_renewmatch(mp, ms, &tlp->se, progp->nsubids);
break;
@@ -1136,7 +1152,7 @@ _regexec2(const _Reprog *progp, /* program to run */
_Relist *relists;
/* mark space */
- relists = (_Relist *)c_malloc(2 * _BIGLISTSIZE*sizeof(_Relist));
+ relists = (_Relist *)c_malloc(2 * _BIGLISTSIZE*c_sizeof(_Relist));
if (relists == NULL)
return -1;
@@ -1168,10 +1184,10 @@ _regexec(const _Reprog *progp, /* program to run */
j.eol = NULL;
if (mp && mp[0].size) {
- if (mflags & CREG_M_STARTEND)
- j.starts = mp[0].str, j.eol = mp[0].str + mp[0].size;
- else if (mflags & CREG_M_NEXT)
- j.starts = mp[0].str + mp[0].size;
+ if (mflags & CREG_STARTEND)
+ j.starts = mp[0].buf, j.eol = mp[0].buf + mp[0].size;
+ else if (mflags & CREG_NEXT)
+ j.starts = mp[0].buf + mp[0].size;
}
j.starttype = 0;
@@ -1204,7 +1220,7 @@ _build_subst(const char* replace, int nmatch, const csview match[],
cstr_buf buf = cstr_buffer(subst);
intptr_t len = 0, cap = buf.cap;
char* dst = buf.data;
- cstr mstr = cstr_NULL;
+ cstr mstr = cstr_init();
while (*replace != '\0') {
if (*replace == '$') {
@@ -1216,12 +1232,12 @@ _build_subst(const char* replace, int nmatch, const csview match[],
g = arg - '0';
if (replace[1] >= '0' && replace[1] <= '9' && replace[2] == ';')
{ g = g*10 + (replace[1] - '0'); replace += 2; }
- if (g < (int)nmatch) {
+ if (g < nmatch) {
csview m = mfun && mfun(g, match[g], &mstr) ? cstr_sv(&mstr) : match[g];
if (len + m.size > cap)
- dst = cstr_reserve(subst, cap = cap*3/2 + m.size);
- for (int i = 0; i < (int)m.size; ++i)
- dst[len++] = m.str[i];
+ dst = cstr_reserve(subst, cap += cap/2 + m.size);
+ for (int i = 0; i < m.size; ++i)
+ dst[len++] = m.buf[i];
}
++replace;
case '\0':
@@ -1229,7 +1245,7 @@ _build_subst(const char* replace, int nmatch, const csview match[],
}
}
if (len == cap)
- dst = cstr_reserve(subst, cap = cap*3/2 + 4);
+ dst = cstr_reserve(subst, cap += cap/2 + 4);
dst[len++] = *replace++;
}
cstr_drop(&mstr);
@@ -1250,12 +1266,12 @@ cregex_compile_3(cregex *self, const char* pattern, int cflags) {
int
cregex_captures(const cregex* self) {
- return self->prog ? 1 + self->prog->nsubids : 0;
+ return self->prog ? self->prog->nsubids : 0;
}
int
cregex_find_4(const cregex* re, const char* input, csview match[], int mflags) {
- int res = _regexec(re->prog, input, cregex_captures(re), match, mflags);
+ int res = _regexec(re->prog, input, cregex_captures(re) + 1, match, mflags);
switch (res) {
case 1: return CREG_OK;
case 0: return CREG_NOMATCH;
@@ -1277,19 +1293,19 @@ cregex_find_pattern_4(const char* pattern, const char* input,
cstr
cregex_replace_sv_6(const cregex* re, csview input, const char* replace, int count,
bool (*mfun)(int, csview, cstr*), int rflags) {
- cstr out = cstr_NULL;
- cstr subst = cstr_NULL;
+ cstr out = cstr_init();
+ cstr subst = cstr_init();
csview match[CREG_MAX_CAPTURES];
- int nmatch = cregex_captures(re);
+ int nmatch = cregex_captures(re) + 1;
if (!count) count = INT32_MAX;
- bool copy = !(rflags & CREG_R_STRIP);
+ bool copy = !(rflags & CREG_STRIP);
while (count-- && cregex_find_sv(re, input, match) == CREG_OK) {
_build_subst(replace, nmatch, match, mfun, &subst);
- const intptr_t mpos = (match[0].str - input.str);
- if (copy & (mpos > 0)) cstr_append_n(&out, input.str, mpos);
+ const intptr_t mpos = (match[0].buf - input.buf);
+ if (copy & (mpos > 0)) cstr_append_n(&out, input.buf, mpos);
cstr_append_s(&out, subst);
- input.str = match[0].str + match[0].size;
+ input.buf = match[0].buf + match[0].size;
input.size -= mpos + match[0].size;
}
if (copy) cstr_append_sv(&out, input);
@@ -1303,7 +1319,7 @@ cregex_replace_pattern_6(const char* pattern, const char* input, const char* rep
cregex re = cregex_init();
if (cregex_compile(&re, pattern, crflags) != CREG_OK)
assert(0);
- csview sv = {input, c_strlen(input)};
+ csview sv = c_sv(input, c_strlen(input));
cstr out = cregex_replace_sv(&re, sv, replace, count, mfun, crflags);
cregex_drop(&re);
return out;
diff --git a/src/libstc.c b/src/libstc.c
new file mode 100644
index 00000000..1305abef
--- /dev/null
+++ b/src/libstc.c
@@ -0,0 +1,9 @@
+#define STC_IMPLEMENT
+#define i_import
+#include "../include/stc/cregex.h" /* cstr. utf8, and cregex */
+#include "../include/stc/csview.h"
+#include "../include/stc/crand.h"
+#include "../include/stc/cspan.h"
+#if __STDC_VERSION__ >= 201112L
+# include "../include/c11/fmt.h"
+#endif
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 d9a16568..8c2bba45 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/print.h > $d/../stcsingle/c11/print.h
-python singleheader.py $d/include/stc/calgo.h > $d/../stcsingle/stc/calgo.h
-python singleheader.py $d/include/stc/carc.h > $d/../stcsingle/stc/carc.h
-python singleheader.py $d/include/stc/cbits.h > $d/../stcsingle/stc/cbits.h
-python singleheader.py $d/include/stc/cbox.h > $d/../stcsingle/stc/cbox.h
-python singleheader.py $d/include/stc/ccommon.h > $d/../stcsingle/stc/ccommon.h
-python singleheader.py $d/include/stc/cdeq.h > $d/../stcsingle/stc/cdeq.h
-python singleheader.py $d/include/stc/clist.h > $d/../stcsingle/stc/clist.h
-python singleheader.py $d/include/stc/cmap.h > $d/../stcsingle/stc/cmap.h
-python singleheader.py $d/include/stc/coption.h > $d/../stcsingle/stc/coption.h
-python singleheader.py $d/include/stc/cpque.h > $d/../stcsingle/stc/cpque.h
-python singleheader.py $d/include/stc/cqueue.h > $d/../stcsingle/stc/cqueue.h
-python singleheader.py $d/include/stc/crand.h > $d/../stcsingle/stc/crand.h
-python singleheader.py $d/include/stc/cregex.h > $d/../stcsingle/stc/cregex.h
-python singleheader.py $d/include/stc/cset.h > $d/../stcsingle/stc/cset.h
-python singleheader.py $d/include/stc/csmap.h > $d/../stcsingle/stc/csmap.h
-python singleheader.py $d/include/stc/cspan.h > $d/../stcsingle/stc/cspan.h
-python singleheader.py $d/include/stc/csset.h > $d/../stcsingle/stc/csset.h
-python singleheader.py $d/include/stc/cstack.h > $d/../stcsingle/stc/cstack.h
-python singleheader.py $d/include/stc/cstr.h > $d/../stcsingle/stc/cstr.h
-python singleheader.py $d/include/stc/csview.h > $d/../stcsingle/stc/csview.h
-python singleheader.py $d/include/stc/cvec.h > $d/../stcsingle/stc/cvec.h
-python singleheader.py $d/include/stc/extend.h > $d/../stcsingle/stc/extend.h
-python singleheader.py $d/include/stc/forward.h > $d/../stcsingle/stc/forward.h
-echo "stcsingle headers updated" \ No newline at end of file
+d=$(git rev-parse --show-toplevel)
+mkdir -p $d/../stcsingle/c11 $d/../stcsingle/stc/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/crawstr.h $d/../stcsingle/stc/crawstr.h
+python singleheader.py $d/include/stc/cvec.h $d/../stcsingle/stc/cvec.h
+python singleheader.py $d/include/stc/extend.h $d/../stcsingle/stc/extend.h
+python singleheader.py $d/include/stc/forward.h $d/../stcsingle/stc/forward.h
+echo "$d/../stcsingle headers updated"
diff --git a/src/utf8code.c b/src/utf8code.c
index 496f5eef..e326e6b9 100644
--- a/src/utf8code.c
+++ b/src/utf8code.c
@@ -1,6 +1,9 @@
#ifndef UTF8_C_INCLUDED
#define UTF8_C_INCLUDED
-#include <stc/utf8.h> // header only
+
+#ifndef UTF8_H_INCLUDED
+#include "../include/stc/utf8.h" /* header only */
+#endif
#include "utf8tabs.inc"
const uint8_t utf8_dtab[] = {
@@ -102,10 +105,10 @@ int utf8_icmp_sv(const csview s1, const csview s2) {
utf8_decode_t d1 = {.state=0}, d2 = {.state=0};
intptr_t j1 = 0, j2 = 0;
while ((j1 < s1.size) & (j2 < s2.size)) {
- do { utf8_decode(&d1, (uint8_t)s1.str[j1++]); } while (d1.state);
- do { utf8_decode(&d2, (uint8_t)s2.str[j2++]); } while (d2.state);
+ do { utf8_decode(&d1, (uint8_t)s1.buf[j1++]); } while (d1.state);
+ do { utf8_decode(&d2, (uint8_t)s2.buf[j2++]); } while (d2.state);
int32_t c = (int32_t)utf8_casefold(d1.codep) - (int32_t)utf8_casefold(d2.codep);
- if (c || !s2.str[j2 - 1]) // OK if s1.size and s2.size are npos
+ if (c || !s2.buf[j2 - 1]) // OK if s1.size and s2.size are npos
return (int)c;
}
return (int)(s1.size - s2.size);
@@ -458,28 +461,31 @@ static const URange16 Latin_range16[] = {
#define UNI_ENTRY(Code) \
{ Code##_range16, sizeof(Code##_range16)/sizeof(URange16) }
-#ifndef __cplusplus
+#ifdef __cplusplus
+#define _e_arg(k, v) v
+#else
+#define _e_arg(k, v) [k] = v
static
#endif
const UGroup _utf8_unicode_groups[U8G_SIZE] = {
- [U8G_Cc] = UNI_ENTRY(Cc),
- [U8G_Lt] = UNI_ENTRY(Lt),
- [U8G_Nd] = UNI_ENTRY(Nd),
- [U8G_Nl] = UNI_ENTRY(Nl),
- [U8G_Pc] = UNI_ENTRY(Pc),
- [U8G_Pd] = UNI_ENTRY(Pd),
- [U8G_Pf] = UNI_ENTRY(Pf),
- [U8G_Pi] = UNI_ENTRY(Pi),
- [U8G_Sc] = UNI_ENTRY(Sc),
- [U8G_Zl] = UNI_ENTRY(Zl),
- [U8G_Zp] = UNI_ENTRY(Zp),
- [U8G_Zs] = UNI_ENTRY(Zs),
- [U8G_Arabic] = UNI_ENTRY(Arabic),
- [U8G_Cyrillic] = UNI_ENTRY(Cyrillic),
- [U8G_Devanagari] = UNI_ENTRY(Devanagari),
- [U8G_Greek] = UNI_ENTRY(Greek),
- [U8G_Han] = UNI_ENTRY(Han),
- [U8G_Latin] = UNI_ENTRY(Latin),
+ _e_arg(U8G_Cc, UNI_ENTRY(Cc)),
+ _e_arg(U8G_Lt, UNI_ENTRY(Lt)),
+ _e_arg(U8G_Nd, UNI_ENTRY(Nd)),
+ _e_arg(U8G_Nl, UNI_ENTRY(Nl)),
+ _e_arg(U8G_Pc, UNI_ENTRY(Pc)),
+ _e_arg(U8G_Pd, UNI_ENTRY(Pd)),
+ _e_arg(U8G_Pf, UNI_ENTRY(Pf)),
+ _e_arg(U8G_Pi, UNI_ENTRY(Pi)),
+ _e_arg(U8G_Sc, UNI_ENTRY(Sc)),
+ _e_arg(U8G_Zl, UNI_ENTRY(Zl)),
+ _e_arg(U8G_Zp, UNI_ENTRY(Zp)),
+ _e_arg(U8G_Zs, UNI_ENTRY(Zs)),
+ _e_arg(U8G_Arabic, UNI_ENTRY(Arabic)),
+ _e_arg(U8G_Cyrillic, UNI_ENTRY(Cyrillic)),
+ _e_arg(U8G_Devanagari, UNI_ENTRY(Devanagari)),
+ _e_arg(U8G_Greek, UNI_ENTRY(Greek)),
+ _e_arg(U8G_Han, UNI_ENTRY(Han)),
+ _e_arg(U8G_Latin, UNI_ENTRY(Latin)),
};
#endif