summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md219
-rw-r--r--benchmarks/cdeq_benchmark.cpp5
-rw-r--r--benchmarks/clist_benchmark.cpp5
-rw-r--r--benchmarks/cmap_benchmark.cpp7
-rw-r--r--benchmarks/cpque_benchmark.cpp8
-rw-r--r--benchmarks/csmap_benchmark.cpp6
-rw-r--r--benchmarks/cvec_benchmark.cpp5
-rw-r--r--benchmarks/others/clist_v1.h401
-rw-r--r--benchmarks/others/csmap_v1.h510
-rw-r--r--benchmarks/others/old/clist.h367
-rw-r--r--benchmarks/others/old/csmap.h404
-rw-r--r--benchmarks/shootout1_cmap.cpp18
-rw-r--r--benchmarks/shootout2_cmap.cpp8
-rw-r--r--benchmarks/shootout3_csmap.cpp17
-rw-r--r--docs/carray_api.md123
-rw-r--r--docs/ccommon_api.md14
-rw-r--r--docs/cdeq_api.md28
-rw-r--r--docs/clist_api.md59
-rw-r--r--docs/cmap_api.md161
-rw-r--r--docs/cpque_api.md27
-rw-r--r--docs/cqueue_api.md53
-rw-r--r--docs/crandom_api.md10
-rw-r--r--docs/cset_api.md24
-rw-r--r--docs/csmap_api.md69
-rw-r--r--docs/csptr_api.md142
-rw-r--r--docs/csset_api.md22
-rw-r--r--docs/cstack_api.md25
-rw-r--r--docs/cstr_api.md9
-rw-r--r--docs/csview_api.md55
-rw-r--r--docs/cvec_api.md39
-rw-r--r--examples/advanced.c18
-rw-r--r--examples/astar.c167
-rw-r--r--examples/birthday.c28
-rw-r--r--examples/complex.c55
-rw-r--r--examples/convert.c18
-rw-r--r--examples/cpque.c27
-rw-r--r--examples/csmap_erase.c10
-rw-r--r--examples/csmap_find.c16
-rw-r--r--examples/csmap_insert.c42
-rw-r--r--examples/csset_erase.c47
-rw-r--r--examples/cstr_match.c8
-rw-r--r--examples/demos.c79
-rw-r--r--examples/ex_gauss1.c14
-rw-r--r--examples/ex_gauss2.c16
-rw-r--r--examples/inits.c47
-rw-r--r--examples/list.c11
-rw-r--r--examples/list_erase.c7
-rw-r--r--examples/list_splice.c10
-rw-r--r--examples/mapmap.c42
-rw-r--r--examples/mmap.c18
-rw-r--r--examples/multimap.c43
-rw-r--r--examples/phonebook.c18
-rw-r--r--examples/priority.c12
-rw-r--r--examples/queue.c16
-rw-r--r--examples/read.c33
-rw-r--r--examples/runall.sh35
-rw-r--r--examples/sharedptr.c59
-rw-r--r--examples/splitstr.c4
-rw-r--r--examples/stack.c10
-rw-r--r--examples/stc_astar.c172
-rw-r--r--examples/words.c41
-rw-r--r--include/stc/alt/cstr.h406
-rw-r--r--include/stc/carr2.h131
-rw-r--r--include/stc/carr3.h135
-rw-r--r--include/stc/carray.h218
-rw-r--r--include/stc/cbits.h8
-rw-r--r--include/stc/ccommon.h16
-rw-r--r--include/stc/cdeq.h649
-rw-r--r--include/stc/clist.h547
-rw-r--r--include/stc/cmap.h732
-rw-r--r--include/stc/cpque.h244
-rw-r--r--include/stc/cqueue.h96
-rw-r--r--include/stc/crandom.h20
-rw-r--r--include/stc/cset.h36
-rw-r--r--include/stc/csmap.h981
-rw-r--r--include/stc/csptr.h213
-rw-r--r--include/stc/csset.h37
-rw-r--r--include/stc/cstack.h121
-rw-r--r--include/stc/cstr.h46
-rw-r--r--include/stc/csview.h12
-rw-r--r--include/stc/cvec.h639
-rw-r--r--include/stc/forward.h156
-rw-r--r--include/stc/template.h182
-rw-r--r--tests/test_new_arr.c45
-rw-r--r--tests/test_new_deq.c57
-rw-r--r--tests/test_new_list.c57
-rw-r--r--tests/test_new_map.c60
-rw-r--r--tests/test_new_pque.c63
-rw-r--r--tests/test_new_queue.c43
-rw-r--r--tests/test_new_smap.c67
-rw-r--r--tests/test_new_sptr.c45
-rw-r--r--tests/test_new_vec.c57
92 files changed, 5569 insertions, 4513 deletions
diff --git a/README.md b/README.md
index d6738938..6cff9b12 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,13 @@
STC - Standard Template Containers for C
========================================
+News
+----
+**VERSION 2.X RELEASED**: This main version uses a different way to instantiate templated containers,
+and is not compatible with v1.X, however the usage is otherwise compatible with v1.X. The new style
+has multiple advantages, e.g. implementation does no longer contain long macro definitions to generate
+code. Also, specfiying template arguments is more user friendly and flexible.
+
Introduction
------------
A modern, templated, user-friendly, fast, fully type-safe, and customizable container library for C99,
@@ -12,31 +19,31 @@ For an introduction to templated containers, please read the blog by Ian Fisher
STC is a compact, header-only library with the all the major "standard" data containers, except for the
multimap/set variants. However, there is an example how to create a multimap in the examples folder.
-- [***carray*** - **multi-dim dynamic array** type](docs/carray_api.md)
+- [***carr2, carr3*** - **2d** and **3d** dynamic **array** type](docs/carray_api.md)
- [***cbits*** - **std::bitset** alike type](docs/cbits_api.md)
- [***cdeq*** - **std::deque** alike type](docs/cdeq_api.md)
- [***clist*** - **std::forward_list** alike type](docs/clist_api.md)
- [***cmap*** - **std::unordered_map** alike type](docs/cmap_api.md)
-- [***cpque*** - **std::priority_queue** alike (adapter) type](docs/cpque_api.md)
+- [***cpque*** - **std::priority_queue** alike type](docs/cpque_api.md)
- [***csptr*** - **std::shared_ptr** alike support](docs/csptr_api.md)
-- [***cqueue*** - **std::queue** alike (adapter) type](docs/cqueue_api.md)
+- [***cqueue*** - **std::queue** alike type](docs/cqueue_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 (adapter) type](docs/cstack_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)
- [***cvec*** - **std::vector** alike type](docs/cvec_api.md)
Others:
-- [***crandom*** - A novel extremely fast *PRNG* named **stc64**](docs/crandom_api.md)
+- [***crandom*** - A novel very fast *PRNG* named **stc64**](docs/crandom_api.md)
- [***ccommon*** - Some handy macros and general definitions](docs/ccommon_api.md)
Highlights
----------
-- **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. The ***using***-declaration instantiates the container type to use. You may pass *optional* arguments to it for customization of element- *comparison*, *destruction*, *cloning*, *conversion types*, and more.
+- **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. The ***#define i_xxx***-declarations configures the container type to use. You may define various names to customize element-*comparison*, *destruction*, *cloning*, *conversion types*, and more.
- **Unparalleled performance** - The containers are about equal and often much faster than the c++ STL containers.
-- **Fully memory managed** - All containers will destruct keys/values via destructor passed as macro parameters to the ***using***-declaration. Also, shared pointers are supported and can be stored in containers, see ***csptr***.
+- **Fully memory managed** - All containers will destruct keys/values via destructor defined as macro parameters before including the container header. Also, shared pointers are supported and can be stored in containers, see ***csptr***.
- **Fully type safe** - Because of templating, it avoids error-prone casting of container types and elements back and forth from the containers.
- **Uniform, easy-to-learn API** - Methods to ***construct***, ***initialize***, ***iterate*** and ***destruct*** have uniform and intuitive usage across the various containers.
- **Small footprint** - Small source code and generated executables. The executable from the example below with six different containers is *22 kb in size* compiled with gcc -Os on linux.
@@ -62,31 +69,25 @@ The usage of the containers is similar to the c++ standard containers in STL, so
All containers are generic/templated, except for **cstr** and **cbits**. No casting is used, so containers are type-safe like
templates in c++. A basic usage example:
```c
+#define i_val float
#include <stc/cvec.h>
-using_cvec(f32, float);
-
int main(void) {
- cvec_f32 vec = cvec_f32_init();
- cvec_f32_push_back(&vec, 10.f);
- cvec_f32_push_back(&vec, 20.f);
- cvec_f32_push_back(&vec, 30.f);
+ cvec_float vec = cvec_float_init();
+ cvec_float_push_back(&vec, 10.f);
+ cvec_float_push_back(&vec, 20.f);
+ cvec_float_push_back(&vec, 30.f);
- c_foreach (i, cvec_f32, vec)
+ c_foreach (i, cvec_float, vec)
printf(" %g", *i.ref);
- cvec_f32_del(&vec);
+ cvec_float_del(&vec);
}
```
With six different containers:
```c
-#include <stc/cset.h>
-#include <stc/cvec.h>
-#include <stc/cdeq.h>
-#include <stc/clist.h>
-#include <stc/cqueue.h>
-#include <stc/csmap.h>
#include <stdio.h>
+#include <stc/ccommon.h>
struct Point { float x, y; };
@@ -95,62 +96,75 @@ int Point_compare(const struct Point* a, const struct Point* b) {
return cmp ? cmp : c_default_compare(&a->y, &b->y);
}
-// declare container types
-using_cset(i32, int); // unordered set
-using_cvec(pnt, struct Point, Point_compare); // vector, struct as elements
-using_cdeq(i32, int); // deque
-using_clist(i32, int); // singly linked list
-using_cqueue(i32, cdeq_i32); // queue, using deque as adapter
-using_csmap(i32, int, int); // sorted map
+#define i_key int
+#include <stc/cset.h> // cset_int: unordered set
+
+#define i_tag pnt
+#define i_val struct Point
+#define i_cmp Point_compare
+#include <stc/cvec.h> // cvec_pnt: vector of struct Point
+
+#define i_val int
+#include <stc/cdeq.h> // cdeq_int: deque of int
+
+#define i_val int
+#include <stc/clist.h> // clist_int: singly linked list
+
+#define i_val int
+#include <stc/cstack.h>
+
+#define i_key int
+#define i_val int
+#include <stc/csmap.h> // csmap_int: sorted map int => int
int main(void) {
// define six containers with automatic call of init and del (destruction after scope exit)
- c_forauto (cset_i32, set)
+ c_forauto (cset_int, set)
c_forauto (cvec_pnt, vec)
- c_forauto (cdeq_i32, deq)
- c_forauto (clist_i32, lst)
- c_forauto (cqueue_i32, que)
- c_forauto (csmap_i32, map)
+ c_forauto (cdeq_int, deq)
+ c_forauto (clist_int, lst)
+ c_forauto (cstack_int, stk)
+ c_forauto (csmap_int, map)
{
// add some elements to each container
- c_emplace(cset_i32, set, {10, 20, 30});
+ c_emplace(cset_int, set, {10, 20, 30});
c_emplace(cvec_pnt, vec, { {10, 1}, {20, 2}, {30, 3} });
- c_emplace(cdeq_i32, deq, {10, 20, 30});
- c_emplace(clist_i32, lst, {10, 20, 30});
- c_emplace(cqueue_i32, que, {10, 20, 30});
- c_emplace(csmap_i32, map, { {20, 2}, {10, 1}, {30, 3} });
+ c_emplace(cdeq_int, deq, {10, 20, 30});
+ c_emplace(clist_int, lst, {10, 20, 30});
+ c_emplace(cstack_int, stk, {10, 20, 30});
+ c_emplace(csmap_int, map, { {20, 2}, {10, 1}, {30, 3} });
// add one more element to each container
- cset_i32_insert(&set, 40);
+ cset_int_insert(&set, 40);
cvec_pnt_push_back(&vec, (struct Point) {40, 4});
- cdeq_i32_push_front(&deq, 5);
- clist_i32_push_front(&lst, 5);
- cqueue_i32_push(&que, 40);
- csmap_i32_emplace(&map, 40, 4);
+ cdeq_int_push_front(&deq, 5);
+ clist_int_push_front(&lst, 5);
+ cstack_int_push(&stk, 40);
+ csmap_int_insert(&map, 40, 4);
// find an element in each container
- cset_i32_iter_t i1 = cset_i32_find(&set, 20);
+ cset_int_iter_t i1 = cset_int_find(&set, 20);
cvec_pnt_iter_t i2 = cvec_pnt_find(&vec, (struct Point) {20, 2});
- cdeq_i32_iter_t i3 = cdeq_i32_find(&deq, 20);
- clist_i32_iter_t i4 = clist_i32_find(&lst, 20);
- csmap_i32_iter_t i5 = csmap_i32_find(&map, 20);
+ cdeq_int_iter_t i3 = cdeq_int_find(&deq, 20);
+ clist_int_iter_t i4 = clist_int_find(&lst, 20);
+ csmap_int_iter_t i5 = csmap_int_find(&map, 20);
printf("\nFound: %d, (%g, %g), %d, %d, [%d: %d]\n", *i1.ref, i2.ref->x, i2.ref->y,
*i3.ref, *i4.ref,
i5.ref->first, i5.ref->second);
// erase the elements found
- cset_i32_erase_at(&set, i1);
+ cset_int_erase_at(&set, i1);
cvec_pnt_erase_at(&vec, i2);
- cdeq_i32_erase_at(&deq, i3);
- clist_i32_erase_at(&lst, i4);
- csmap_i32_erase_at(&map, i5);
+ cdeq_int_erase_at(&deq, i3);
+ clist_int_erase_at(&lst, i4);
+ csmap_int_erase_at(&map, i5);
printf("After erasing elements found:");
- printf("\n set:"); c_foreach (i, cset_i32, set) printf(" %d", *i.ref);
+ printf("\n set:"); c_foreach (i, cset_int, set) printf(" %d", *i.ref);
printf("\n vec:"); c_foreach (i, cvec_pnt, vec) printf(" (%g, %g)", i.ref->x, i.ref->y);
- printf("\n deq:"); c_foreach (i, cdeq_i32, deq) printf(" %d", *i.ref);
- printf("\n lst:"); c_foreach (i, clist_i32, lst) printf(" %d", *i.ref);
- printf("\n que:"); c_foreach (i, cqueue_i32, que) printf(" %d", *i.ref);
- printf("\n map:"); c_foreach (i, csmap_i32, map) printf(" [%d: %d]", i.ref->first,
+ printf("\n deq:"); c_foreach (i, cdeq_int, deq) printf(" %d", *i.ref);
+ printf("\n lst:"); c_foreach (i, clist_int, lst) printf(" %d", *i.ref);
+ printf("\n stk:"); c_foreach (i, cstack_int, stk) printf(" %d", *i.ref);
+ printf("\n map:"); c_foreach (i, csmap_int, map) printf(" [%d: %d]", i.ref->first,
i.ref->second);
}
}
@@ -163,7 +177,7 @@ After erasing elements found:
vec: (10, 1) (30, 3) (40, 4)
deq: 5 10 30
lst: 5 10 30
- que: 10 20 30 40
+ stk: 10 20 30 40
map: [10: 1] [30: 3] [40: 4]
```
@@ -179,30 +193,38 @@ in your build environment and place all the instantiations of containers used in
// stc_libs.c
#define STC_IMPLEMENTATION
#include <stc/cstr.h>
-#include <stc/cmap.h>
-#include <stc/cvec.h>
-#include <stc/clist.h>
#include "Point.h"
-using_cmap(ii, int, int);
-using_cset(ix, int64_t);
-using_cvec(i, int);
-using_clist(p, struct Point);
+#define i_tag ii
+#define i_key int
+#define i_val int
+#include <stc/cmap.h> // cmap_ii: int => int
+
+#define i_tag ix
+#define i_key int64_t
+#include <stc/cset.h> // cset_ix
+
+#define i_val int
+#include <stc/cvec.h> // cvec_int
+
+#define i_tag pnt
+#define i_val Point
+#include <stc/clist.h> // clist_pnt
```
The *emplace* versus non-emplace container methods
--------------------------------------------------
STC, like c++ STL, has two sets of methods for adding elements to containers. One set begins
with **emplace**, e.g. **cvec_X_emplace_back()**. This is a convenient alternative to
-**cvec_X_push_back()** when dealing non-trivial container elements, e.g. smart pointers or
-elements using dynamic memory.
+**cvec_X_push_back()** when dealing non-trivial container elements, e.g. strings, shared pointers or
+other elements using dynamic memory or shared resources.
-The **emplace** methods ***construct*** or ***clone*** their own copy of the element to be added.
-In contrast, the non-emplace methods requires elements to be explicitly constructed or cloned
-before adding them. For containers of integral or trivial element types, **emplace** and
-corresponding non-emplace methods are identical, so the following does not apply for those.
+The **emplace** methods ***constructs*** or ***clones*** the given elements before they are added
+to the container. In contrast, the *non-emplace* methods ***moves*** the given elements into the
+container. For containers of integral or trivial element types, **emplace** and corresponding
+*non-emplace* methods are identical.
-| Move and insert element | Construct element in-place | Container |
+| non-emplace: Move | emplace: Clone | Container |
|:--------------------------|:-----------------------------|:--------------------------------------------|
| insert() | emplace() | cmap, cset, csmap, csset, cvec, cdeq, clist |
| insert_or_assign(), put() | emplace_or_assign() | cmap, csmap |
@@ -211,10 +233,11 @@ corresponding non-emplace methods are identical, so the following does not apply
| push_front() | emplace_front() | cdeq, clist |
Strings are the most commonly used non-trivial data type. STC containers have proper pre-defined
-**using**-declarations for cstr-elements, so they are fail-safe to use both with the **emplace**
+definitions for cstr container elements, so they are fail-safe to use both with the **emplace**
and non-emplace methods:
```c
-using_cvec_str(); // vector of string (cstr)
+#define i_val_str // special macro to enable container of cstr
+#include <stc/cvec.h> // vector of string (cstr)
...
c_forvar (cvec_str vec = cvec_str_init(), cvec_str_del(&vec)) // defer vector destructor to end of block
c_forvar (cstr s = cstr_lit("a string literal"), cstr_del(&s)) // cstr_lit() for literals; no strlen() usage
@@ -228,7 +251,7 @@ c_forvar (cstr s = cstr_lit("a string literal"), cstr_del(&s)) // cstr_lit() fo
cvec_str_emplace_back(&vec, s.str); // Ok: const char* input type.
}
```
-This is made possible because the **using**-declarations may be given an optional
+This is made possible because the type configuration may be given an optional
conversion/"rawvalue"-type as template parameter, along with a back and forth conversion
methods to the container value type. By default, *rawvalue has the same type as value*.
@@ -264,12 +287,46 @@ Erase methods
| erase_n() | index based | cvec, cdeq, cstr |
| remove() | remove all matching values | clist |
+Forward declaring containers
+----------------------------
+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.
+```
+// Header file
+#include <stc/forward.h> // only include data structures
+forward_cstack(pnt, struct Point); // declare cstack_pnt and cstack_pnt_value_t, cstack_pnt_iter_t;
+ // the element may be forward declared type as well
+typedef struct Dataset {
+ cstack_pnt vertices;
+ cstack_pnt colors;
+} Dataset;
+
+...
+// Implementation
+#define F_tag pnt // define F_tag or an empty i_fwd if the container was forward declared.
+#define i_val struct Point
+#include <stc/cstack.h>
+```
+
+User-defined container prefix
+-----------------------------
+Define either i_prefix or i_tag as empty:
+```
+#define i_prefix
+#define i_tag ivec
+#define i_val int
+#include <stc/cvec.h>
+
+ivec vec = ivec_init();
+ivec_push_back(&vec, 1);
+```
+
Memory efficiency
-----------------
-- **cstr**, **cvec**: Type size: one pointer. The size and capacity is stored as part of the heap allocation that also holds the vector elements.
-- **clist**: Type size: one pointer. Each node allocates block storing value and next pointer.
-- **cdeq**: Type size: two pointers. Otherwise like *cvec*.
-- **cmap**: Type size: 4 pointers. *cmap* uses one table of keys+value, and one table of precomputed hash-value/used bucket, which occupies only one byte per bucket. The closed hashing has a default max load factor of 85%, and hash table scales by 1.5x when reaching that.
-- **csmap**: Type size: 1 pointer. *csmap* manages its own array of tree-nodes for allocation efficiency. Each node uses two 32-bit words by default for left/right child, and one byte for `level`. *csmap* can be configured to allow more than 2^32 elements, ie. 2^64, but it will double the overhead per node.
-- **carray**: carray1, carray2 and carray3. Type size: One pointer plus one, two, or three size_t variables to store dimensions. Arrays are allocated as one contiguous block of heap memory.
-- **csptr**: a shared-pointer uses two pointers, one for the data and one for the reference counter.
+- **cstr**, **cvec**: Type size: 1 pointer. The size and capacity is stored as part of the heap allocation that also holds the vector elements.
+- **clist**: Type size: 1 pointer. Each node allocates a struct which stores the value and next pointer.
+- **cdeq**: Type size: 2 pointers. Otherwise like *cvec*.
+- **cmap**: Type size: 4 pointers. *cmap* uses one table of keys+value, and one table of precomputed hash-value/used bucket, which occupies only one byte per bucket. The closed hashing has a default max load factor of 85%, and hash table scales by 1.6x when reaching that.
+- **csmap**: Type size: 1 pointer. *csmap* manages its own array of tree-nodes for allocation efficiency. Each node uses only two 32-bit ints for child nodes, and one byte for `level`.
+- **carr2**, **carr3**: Type size: 1 pointer plus dimension variables. Arrays are allocated as one contiguous block of heap memory, and one allocation for pointers of indices to the array.
+- **csptr**: Type size: 2 pointers, one for the data and one for the reference counter.
diff --git a/benchmarks/cdeq_benchmark.cpp b/benchmarks/cdeq_benchmark.cpp
index 15e03ff0..a12dddf0 100644
--- a/benchmarks/cdeq_benchmark.cpp
+++ b/benchmarks/cdeq_benchmark.cpp
@@ -1,7 +1,6 @@
#include <stdio.h>
#include <time.h>
#include <stc/crandom.h>
-#include <stc/cdeq.h>
#ifdef __cplusplus
#include <deque>
@@ -17,7 +16,9 @@ uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-using_cdeq(x, size_t);
+#define i_tag x
+#define i_val size_t
+#include <stc/cdeq.h>
#ifdef __cplusplus
Sample test_std_deque() {
diff --git a/benchmarks/clist_benchmark.cpp b/benchmarks/clist_benchmark.cpp
index 3ed91e6c..7c1f164e 100644
--- a/benchmarks/clist_benchmark.cpp
+++ b/benchmarks/clist_benchmark.cpp
@@ -1,7 +1,6 @@
#include <stdio.h>
#include <time.h>
#include <stc/crandom.h>
-#include <stc/clist.h>
#ifdef __cplusplus
#include <forward_list>
@@ -17,7 +16,9 @@ uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-using_clist(x, size_t);
+#define i_tag x
+#define i_val size_t
+#include <stc/clist.h>
#ifdef __cplusplus
Sample test_std_forward_list() {
diff --git a/benchmarks/cmap_benchmark.cpp b/benchmarks/cmap_benchmark.cpp
index 3fb939fa..98f90479 100644
--- a/benchmarks/cmap_benchmark.cpp
+++ b/benchmarks/cmap_benchmark.cpp
@@ -1,7 +1,6 @@
#include <stdio.h>
#include <time.h>
#include <stc/crandom.h>
-#include <stc/cmap.h>
#ifdef __cplusplus
#include <unordered_map>
@@ -16,7 +15,11 @@ uint64_t seed = 1, mask1 = 0xffffffff;
static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-using_cmap(x, size_t, size_t, c_default_equals, c_default_hash64);
+#define i_tag x
+#define i_key size_t
+#define i_val size_t
+#define i_hash c_default_hash64
+#include <stc/cmap.h>
#ifdef __cplusplus
Sample test_std_unordered_map() {
diff --git a/benchmarks/cpque_benchmark.cpp b/benchmarks/cpque_benchmark.cpp
index c8d327ff..2b6445c5 100644
--- a/benchmarks/cpque_benchmark.cpp
+++ b/benchmarks/cpque_benchmark.cpp
@@ -1,11 +1,11 @@
#include <stdio.h>
#include <time.h>
#include <stc/crandom.h>
-#include <stc/cvec.h>
-#include <stc/cpque.h>
-using_cvec(f, float);
-using_cpque(f, cvec_f, -c_default_compare);
+#define i_tag x
+#define i_val float
+#define i_cmp -c_default_compare
+#include <stc/cpque.h>
int main()
{
diff --git a/benchmarks/csmap_benchmark.cpp b/benchmarks/csmap_benchmark.cpp
index 0c73ca32..cd7f5509 100644
--- a/benchmarks/csmap_benchmark.cpp
+++ b/benchmarks/csmap_benchmark.cpp
@@ -1,7 +1,6 @@
#include <stdio.h>
#include <time.h>
#include <stc/crandom.h>
-#include <stc/csmap.h>
#ifdef __cplusplus
#include <map>
@@ -16,7 +15,10 @@ uint64_t seed = 1, mask1 = 0xfffffff;
static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-using_csmap(x, size_t, size_t);
+#define i_tag x
+#define i_key size_t
+#define i_val size_t
+#include <stc/csmap.h>
#ifdef __cplusplus
Sample test_std_map() {
diff --git a/benchmarks/cvec_benchmark.cpp b/benchmarks/cvec_benchmark.cpp
index f85a02a4..755659a7 100644
--- a/benchmarks/cvec_benchmark.cpp
+++ b/benchmarks/cvec_benchmark.cpp
@@ -1,7 +1,6 @@
#include <stdio.h>
#include <time.h>
#include <stc/crandom.h>
-#include <stc/cvec.h>
#ifdef __cplusplus
#include <vector>
@@ -17,7 +16,9 @@ uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-using_cvec(x, size_t);
+#define i_tag x
+#define i_val size_t
+#include <stc/cvec.h>
#ifdef __cplusplus
Sample test_std_vector() {
diff --git a/benchmarks/others/clist_v1.h b/benchmarks/others/clist_v1.h
deleted file mode 100644
index 0dd8feef..00000000
--- a/benchmarks/others/clist_v1.h
+++ /dev/null
@@ -1,401 +0,0 @@
-/* MIT License
- *
- * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * 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 CLIST_H_INCLUDED
-#define CLIST_H_INCLUDED
-
-/* Circular Singly-linked Lists.
-
- This implements a std::forward_list-like class in C, but because it is circular,
- it also support push* and splice* at both ends of the list. This makes it ideal
- for being used as a queue, unlike std::forward_list. Basic usage is similar to cvec:
-
- #include <stdio.h>
- #include <stc/clist.h>
- #include <stc/crandom.h>
- using_clist(ix, int64_t);
-
- int main() {
- clist_ix list = clist_ix_init();
- stc64_t rng = stc64_init(12345);
- int n;
- for (int i=0; i<1000000; ++i) // one million
- clist_ix_push_back(&list, stc64_rand(&rng) >> 32);
- n = 0;
- c_foreach (i, clist_ix, list)
- if (++n % 10000 == 0) printf("%8d: %10zd\n", n, i.ref->value);
- // Sort them...
- clist_ix_sort(&list); // mergesort O(n*log n)
- n = 0;
- puts("sorted");
- c_foreach (i, clist_ix, list)
- if (++n % 10000 == 0) printf("%8d: %10zd\n", n, i.ref->value);
- clist_ix_del(&list);
- }
-*/
-#include <stc/ccommon.h>
-#include <stdlib.h>
-
-#define using_clist(...) c_MACRO_OVERLOAD(using_clist, __VA_ARGS__)
-
-#define using_clist_2(X, Value) \
- using_clist_3(X, Value, c_default_compare)
-#define using_clist_3(X, Value, valueCompare) \
- using_clist_5(X, Value, valueCompare, c_default_del, c_default_fromraw)
-#define using_clist_4(X, Value, valueCompare, valueDel) \
- using_clist_5(X, Value, valueCompare, valueDel, c_no_clone)
-#define using_clist_5(X, Value, valueCompare, valueDel, valueClone) \
- _c_using_clist(clist_##X, Value, valueCompare, valueDel, valueClone, c_default_toraw, Value)
-#define using_clist_7(X, Value, valueCompare, valueDel, valueFromRaw, valueToRaw, RawValue) \
- _c_using_clist(clist_##X, Value, valueCompare, valueDel, valueFromRaw, valueToRaw, RawValue)
-
-#define using_clist_str() \
- _c_using_clist(clist_str, cstr, c_rawstr_compare, cstr_del, cstr_from, cstr_str, const char*)
-
-
-#define _c_using_clist_types(CX, Value) \
- typedef Value CX##_value_t; \
-\
- typedef struct CX##_node { \
- struct CX##_node* next; \
- CX##_value_t value; \
- } CX##_node_t; \
-\
- typedef struct { \
- CX##_node_t* last; \
- } CX; \
-\
- typedef struct { \
- CX##_node_t* const* _last; \
- CX##_value_t* ref; \
- int _state; \
- } CX##_iter_t
-
-
-_c_using_clist_types(clist_VOID, int);
-STC_API size_t _clist_count(const clist_VOID* self);
-#define _clist_node(CX, vp) c_container_of(vp, CX##_node_t, value)
-
-#define _c_using_clist(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue) \
-\
- _c_using_clist_types(CX, Value); \
- typedef RawValue CX##_rawvalue_t; \
-\
- STC_API CX CX##_clone(CX lst); \
- STC_API void CX##_del(CX* self); \
- STC_API void CX##_push_back(CX* self, Value value); \
- STC_API void CX##_push_front(CX* self, Value value); \
- STC_API void CX##_emplace_items(CX *self, const CX##_rawvalue_t arr[], size_t n); \
- STC_API CX CX##_split_after(CX* self, CX##_iter_t pos1, CX##_iter_t pos2); \
- STC_API void CX##_splice_after(CX* self, CX##_iter_t pos, CX* other); \
- STC_DEF void CX##_splice_after_range(CX* self, CX##_iter_t pos, CX* other, CX##_iter_t i1, CX##_iter_t i2); \
- STC_API CX##_iter_t CX##_find(const CX* self, RawValue val); \
- STC_API CX##_iter_t CX##_find_before(const CX* self, RawValue val); \
- STC_API CX##_iter_t CX##_find_before_in(CX##_iter_t it1, CX##_iter_t it2, RawValue val); \
- STC_API void CX##_sort(CX* self); \
- STC_API size_t CX##_remove(CX* self, RawValue val); \
- STC_API CX##_iter_t CX##_insert_after(CX* self, CX##_iter_t pos, Value value); \
- STC_API CX##_iter_t CX##_erase_after(CX* self, CX##_iter_t pos); \
- STC_API CX##_iter_t CX##_erase_range_after(CX* self, CX##_iter_t pos, CX##_iter_t it2); \
- STC_API CX##_node_t* CX##_erase_after_(CX* self, CX##_node_t* node); \
-\
- STC_INLINE CX CX##_init(void) {CX lst = {NULL}; return lst;} \
- STC_INLINE bool CX##_empty(CX lst) {return lst.last == NULL;} \
- STC_INLINE size_t CX##_count(CX lst) {return _clist_count((const clist_VOID*) &lst);} \
- STC_INLINE Value CX##_value_fromraw(RawValue raw) {return valueFromRaw(raw);} \
- STC_INLINE Value CX##_value_clone(Value val) {return valueFromRaw(valueToRaw(&val));} \
- STC_INLINE void CX##_clear(CX* self) {CX##_del(self);} \
- STC_INLINE void CX##_emplace_back(CX* self, RawValue raw) \
- {CX##_push_back(self, valueFromRaw(raw));} \
- STC_INLINE void CX##_emplace_front(CX* self, RawValue raw) \
- {CX##_push_front(self, valueFromRaw(raw));} \
- STC_INLINE CX##_value_t* \
- CX##_front(const CX* self) {return &self->last->next->value;} \
- STC_INLINE CX##_value_t* \
- CX##_back(const CX* self) {return &self->last->value;} \
- STC_INLINE void CX##_pop_front(CX* self) {CX##_erase_after_(self, self->last);} \
- STC_INLINE void CX##_splice_front(CX* self, CX* other) \
- {CX##_splice_after(self, CX##_before_begin(self), other);} \
- STC_INLINE void CX##_splice_back(CX* self, CX* other) \
- {CX##_splice_after(self, CX##_last(self), other);} \
-\
- STC_INLINE CX##_iter_t \
- CX##_emplace_after(CX* self, CX##_iter_t pos, RawValue raw) { \
- return CX##_insert_after(self, pos, valueFromRaw(raw)); \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_before_begin(const CX* self) { \
- CX##_value_t *last = self->last ? &self->last->value : NULL; \
- CX##_iter_t it = {&self->last, last, -1}; return it; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_begin(const CX* self) { \
- CX##_value_t* head = self->last ? &self->last->next->value : NULL; \
- CX##_iter_t it = {&self->last, head, 0}; return it; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_last(const CX* self) { \
- CX##_value_t *last = self->last ? &self->last->value : NULL; \
- CX##_iter_t it = {&self->last, last, 0}; return it; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_end(const CX* self) { \
- CX##_iter_t it = {NULL, NULL}; return it; \
- } \
-\
- STC_INLINE void \
- CX##_next(CX##_iter_t* it) { \
- CX##_node_t* node = _clist_node(CX, it->ref); \
- it->ref = ((it->_state += node == *it->_last) == 1) ? NULL : &node->next->value; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_fwd(CX##_iter_t it, size_t n) { \
- while (n-- && it.ref) CX##_next(&it); return it; \
- } \
- \
- _c_implement_clist(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue) \
- struct stc_trailing_semicolon
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-
-#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
-#define _c_implement_clist(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue) \
-\
- STC_DEF CX \
- CX##_clone(CX lst) { \
- CX out = CX##_init(); \
- c_foreach_3 (i, CX, lst) \
- CX##_emplace_back(&out, valueToRaw(i.ref)); \
- return out; \
- } \
-\
- STC_DEF void \
- CX##_del(CX* self) { \
- while (self->last) CX##_erase_after_(self, self->last); \
- } \
-\
- STC_DEF void \
- CX##_push_back(CX* self, Value value) { \
- _c_clist_insert_after(self, CX, self->last, value); \
- self->last = entry; \
- } \
- STC_DEF void \
- CX##_push_front(CX* self, Value value) { \
- _c_clist_insert_after(self, CX, self->last, value); \
- if (!self->last) self->last = entry; \
- } \
-\
- STC_DEF void \
- CX##_emplace_items(CX *self, const CX##_rawvalue_t arr[], size_t n) { \
- for (size_t i=0; i<n; ++i) CX##_push_back(self, valueFromRaw(arr[i])); \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_insert_after(CX* self, CX##_iter_t pos, Value value) { \
- CX##_node_t* node = pos.ref ? _clist_node(CX, pos.ref) : NULL; \
- _c_clist_insert_after(self, CX, node, value); \
- if (!node || node == self->last && pos._state == 0) self->last = entry; \
- pos.ref = &entry->value, pos._state = 0; return pos; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_erase_after(CX* self, CX##_iter_t pos) { \
- CX##_erase_after_(self, _clist_node(CX, pos.ref)); \
- CX##_next(&pos); return pos; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_erase_range_after(CX* self, CX##_iter_t it1, CX##_iter_t it2) { \
- CX##_node_t* node = _clist_node(CX, it1.ref), *done = it2.ref ? _clist_node(CX, it2.ref) : NULL; \
- while (node && node->next != done) \
- node = CX##_erase_after_(self, node); \
- CX##_next(&it1); return it1; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_find_before_in(CX##_iter_t it1, CX##_iter_t it2, RawValue val) { \
- CX##_iter_t i = it1; \
- for (CX##_next(&i); i.ref != it2.ref; CX##_next(&i)) { \
- RawValue r = valueToRaw(i.ref); \
- if (valueCompareRaw(&r, &val) == 0) return it1; \
- it1 = i; \
- } \
- it1.ref = NULL; return it1; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_find_before(const CX* self, RawValue val) { \
- CX##_iter_t it = CX##_find_before_in(CX##_before_begin(self), CX##_end(self), val); \
- return it; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_find(const CX* self, RawValue val) { \
- CX##_iter_t it = CX##_find_before_in(CX##_before_begin(self), CX##_end(self), val); \
- if (it.ref != CX##_end(self).ref) CX##_next(&it); \
- return it; \
- } \
-\
- STC_DEF CX##_node_t* \
- CX##_erase_after_(CX* self, CX##_node_t* node) { \
- CX##_node_t* del = node->next, *next = del->next; \
- node->next = next; \
- if (del == next) self->last = node = NULL; \
- else if (self->last == del) self->last = node, node = NULL; \
- valueDel(&del->value); c_free(del); \
- return node; \
- } \
-\
- STC_DEF size_t \
- CX##_remove(CX* self, RawValue val) { \
- size_t n = 0; \
- CX##_node_t* prev = self->last, *node; \
- while (prev) { \
- node = prev->next; \
- RawValue r = valueToRaw(&node->value); \
- if (valueCompareRaw(&r, &val) == 0) \
- prev = CX##_erase_after_(self, prev), ++n; \
- else \
- prev = (node == self->last ? NULL : node); \
- } \
- return n; \
- } \
-\
- STC_DEF CX \
- CX##_split_after(CX* self, CX##_iter_t pos1, CX##_iter_t pos2) { \
- CX##_node_t *node1 = _clist_node(CX, pos1.ref), *next1 = node1->next, \
- *node2 = _clist_node(CX, pos2.ref); \
- node1->next = node2->next, node2->next = next1; \
- if (self->last == node2) self->last = node1; \
- CX lst = {node2}; return lst; \
- } \
-\
- STC_DEF void \
- CX##_splice_after(CX* self, CX##_iter_t pos, CX* other) { \
- if (!pos.ref) \
- self->last = other->last; \
- else if (other->last) { \
- CX##_node_t *node = _clist_node(CX, pos.ref), *next = node->next; \
- node->next = other->last->next; \
- other->last->next = next; \
- if (node == self->last && pos._state == 0) self->last = other->last; \
- } \
- other->last = NULL; \
- } \
-\
- STC_DEF void \
- CX##_splice_after_range(CX* self, CX##_iter_t pos, CX* other, CX##_iter_t pos1, CX##_iter_t pos2) { \
- CX tmp = CX##_split_after(other, pos1, pos2); \
- CX##_splice_after(self, pos, &tmp); \
- } \
-\
- STC_DEF int \
- CX##_sort_cmp_(const void* x, const void* y) { \
- RawValue a = valueToRaw(&((CX##_node_t *) x)->value); \
- RawValue b = valueToRaw(&((CX##_node_t *) y)->value); \
- return valueCompareRaw(&a, &b); \
- } \
-\
- STC_DEF void \
- CX##_sort(CX* self) { \
- if (self->last) \
- self->last = (CX##_node_t *) _clist_mergesort((clist_VOID_node_t *) self->last->next, CX##_sort_cmp_); \
- }
-
-
-#define _c_clist_insert_after(self, CX, node, val) \
- CX##_node_t *entry = c_new (CX##_node_t); \
- if (node) entry->next = node->next, node->next = entry; \
- else entry->next = entry; \
- entry->value = val
- /* +: set self->last based on node */
-
-STC_DEF size_t
-_clist_count(const clist_VOID* self) {
- const clist_VOID_node_t *nd = self->last;
- if (!nd) return 0;
- size_t n = 1;
- while ((nd = nd->next) != self->last) ++n;
- return n;
-}
-
-/* Singly linked list Mergesort implementation by Simon Tatham. O(n*log n).
- * https://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
- */
-STC_DEF clist_VOID_node_t *
-_clist_mergesort(clist_VOID_node_t *list, int (*cmp)(const void*, const void*)) {
- clist_VOID_node_t *p, *q, *e, *tail, *oldhead;
- int insize = 1, nmerges, psize, qsize, i;
-
- while (1) {
- p = oldhead = list;
- list = tail = NULL;
- nmerges = 0;
-
- while (p) {
- ++nmerges;
- q = p, psize = 0;
- for (i = 0; i < insize; ++i) {
- ++psize;
- q = (q->next == oldhead ? NULL : q->next);
- if (!q) break;
- }
- qsize = insize;
-
- while (psize > 0 || (qsize > 0 && q)) {
- if (psize == 0) {
- e = q, q = q->next, --qsize;
- if (q == oldhead) q = NULL;
- } else if (qsize == 0 || !q) {
- e = p, p = p->next, --psize;
- if (p == oldhead) p = NULL;
- } else if (cmp(p, q) <= 0) {
- e = p, p = p->next, --psize;
- if (p == oldhead) p = NULL;
- } else {
- e = q, q = q->next, --qsize;
- if (q == oldhead) q = NULL;
- }
- if (tail) tail->next = e; else list = e;
- tail = e;
- }
- p = q;
- }
- tail->next = list;
-
- if (nmerges <= 1)
- return tail;
-
- insize *= 2;
- }
-}
-
-#else
-#define _c_implement_clist(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue)
-#endif
-
-#endif
diff --git a/benchmarks/others/csmap_v1.h b/benchmarks/others/csmap_v1.h
deleted file mode 100644
index 69f3f06d..00000000
--- a/benchmarks/others/csmap_v1.h
+++ /dev/null
@@ -1,510 +0,0 @@
-/* MIT License
- *
- * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * 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 CSMAP_H_INCLUDED
-#define CSMAP_H_INCLUDED
-
-// Sorted/Ordered set and map - implemented as an AA-tree.
-/*
-#include <stdio.h>
-#include <stc/csmap.h>
-using_csmap(mx, int, char); // Sorted map<int, char>
-
-int main(void) {
- c_forvar (csmap_mx m = csmap_mx_init(), csmap_mx_del(&m))
- {
- csmap_mx_insert(&m, 5, 'a');
- csmap_mx_insert(&m, 8, 'b');
- csmap_mx_insert(&m, 12, 'c');
-
- csmap_mx_iter_t it = csmap_mx_find(&m, 10); // none
- char val = csmap_mx_find(&m, 5).ref->second;
- csmap_mx_put(&m, 5, 'd'); // update
- csmap_mx_erase(&m, 8);
-
- c_foreach (i, csmap_mx, m)
- printf("map %d: %c\n", i.ref->first, i.ref->second);
- }
-}
-*/
-#include <stc/ccommon.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define using_csmap(...) c_MACRO_OVERLOAD(using_csmap, __VA_ARGS__)
-
-#define using_csmap_3(X, Key, Mapped) \
- using_csmap_4(X, Key, Mapped, c_default_compare)
-#define using_csmap_4(X, Key, Mapped, keyCompare) \
- using_csmap_6(X, Key, Mapped, keyCompare, c_default_del, c_default_fromraw)
-#define using_csmap_5(X, Key, Mapped, keyCompare, mappedDel) \
- using_csmap_6(X, Key, Mapped, keyCompare, mappedDel, c_no_clone)
-#define using_csmap_6(X, Key, Mapped, keyCompare, mappedDel, mappedClone) \
- using_csmap_8(X, Key, Mapped, keyCompare, mappedDel, mappedClone, c_default_toraw, Mapped)
-#define using_csmap_8(X, Key, Mapped, keyCompare, mappedDel, mappedFromRaw, mappedToRaw, RawMapped) \
- using_csmap_12(X, Key, Mapped, keyCompare, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- c_default_del, c_default_fromraw, c_default_toraw, Key)
-
-#define using_csmap_12(X, Key, Mapped, keyCompareRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey) \
- _c_using_aatree(csmap_##X, csmap_, Key, Mapped, keyCompareRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey)
-
-
-#define using_csmap_keydef(...) c_MACRO_OVERLOAD(using_csmap_keydef, __VA_ARGS__)
-
-#define using_csmap_keydef_6(X, Key, Mapped, keyCompare, keyDel, keyClone) \
- using_csmap_keydef_8(X, Key, Mapped, keyCompare, \
- keyDel, keyClone, c_default_toraw, Key)
-
-#define using_csmap_keydef_8(X, Key, Mapped, keyCompareRaw, \
- keyDel, keyFromRaw, keyToRaw, RawKey) \
- _c_using_aatree(csmap_##X, csmap_, Key, Mapped, keyCompareRaw, \
- c_default_del, c_default_fromraw, c_default_toraw, Mapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey)
-
-#define using_csmap_str() \
- _c_using_aatree(csmap_str, csmap_, cstr, cstr, c_rawstr_compare, \
- cstr_del, cstr_from, cstr_str, const char*, \
- cstr_del, cstr_from, cstr_str, const char*)
-
-
-#define using_csmap_strkey(...) c_MACRO_OVERLOAD(using_csmap_strkey, __VA_ARGS__)
-
-#define using_csmap_strkey_2(X, Mapped) \
- using_csmap_strkey_4(X, Mapped, c_default_del, c_default_fromraw)
-#define using_csmap_strkey_3(X, Mapped, mappedDel) \
- using_csmap_strkey_4(X, Mapped, mappedDel, c_no_clone)
-#define using_csmap_strkey_4(X, Mapped, mappedDel, mappedClone) \
- _c_using_aatree_strkey(X, csmap_, Mapped, mappedDel, mappedClone, c_default_toraw, Mapped)
-#define using_csmap_strkey_6(X, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped) \
- _c_using_aatree_strkey(X, csmap_, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped)
-
-#define _c_using_aatree_strkey(X, C, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped) \
- _c_using_aatree(C##X, C, cstr, Mapped, c_rawstr_compare, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- cstr_del, cstr_from, cstr_str, const char*)
-
-
-#define using_csmap_strval(...) c_MACRO_OVERLOAD(using_csmap_strval, __VA_ARGS__)
-
-#define using_csmap_strval_2(X, Key) \
- using_csmap_strval_3(X, Key, c_default_compare)
-#define using_csmap_strval_3(X, Key, keyCompare) \
- using_csmap_strval_5(X, Key, keyCompare, c_default_del, c_default_fromraw)
-#define using_csmap_strval_4(X, Key, keyCompare, keyDel) \
- using_csmap_strval_5(X, Key, keyCompare, keyDel, c_no_clone)
-#define using_csmap_strval_5(X, Key, keyCompare, keyDel, keyClone) \
- using_csmap_strval_7(X, Key, keyCompare, keyDel, keyClone, c_default_toraw, Key)
-
-#define using_csmap_strval_7(X, Key, keyCompareRaw, keyDel, keyFromRaw, keyToRaw, RawKey) \
- _c_using_aatree(csmap_##X, csmap_, Key, cstr, keyCompareRaw, \
- cstr_del, cstr_from, cstr_str, const char*, \
- keyDel, keyFromRaw, keyToRaw, RawKey)
-
-#define SET_ONLY_csmap_(...)
-#define MAP_ONLY_csmap_(...) __VA_ARGS__
-#define KEY_REF_csmap_(vp) (&(vp)->first)
-
-#define _c_aatree_types(CX, C, Key, Mapped) \
- typedef Key CX##_key_t; \
- typedef Mapped CX##_mapped_t; \
-\
- typedef SET_ONLY_##C( CX##_key_t ) \
- MAP_ONLY_##C( struct CX##_value_t ) \
- CX##_value_t; \
-\
- typedef struct { \
- CX##_value_t *ref; \
- bool inserted; \
- } CX##_result_t; \
-\
- typedef struct CX##_node_t CX##_node_t; \
-\
- typedef struct { \
- CX##_value_t *ref; \
- int _top; \
- CX##_node_t *_tn, *_st[36]; \
- } CX##_iter_t; \
-\
- typedef struct { \
- CX##_node_t* root; \
- size_t size; \
- } CX
-
-#define _c_aatree_complete_types(CX, C) \
- MAP_ONLY_##C( struct CX##_value_t { \
- CX##_key_t first; \
- CX##_mapped_t second; \
- }; ) \
- struct CX##_node_t { \
- struct CX##_node_t *link[2]; \
- uint8_t level; \
- CX##_value_t value; \
- }
-
-#define _c_using_aatree(CX, C, Key, Mapped, keyCompareRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey) \
- _c_aatree_types(CX, C, Key, Mapped); \
- _c_aatree_complete_types(CX, C); \
-\
- typedef RawKey CX##_rawkey_t; \
- typedef RawMapped CX##_rawmapped_t; \
- typedef SET_ONLY_##C( CX##_rawkey_t ) \
- MAP_ONLY_##C( struct { CX##_rawkey_t first; \
- CX##_rawmapped_t second; } ) \
- CX##_rawvalue_t; \
-\
- STC_API CX CX##_init(void); \
- STC_API CX##_value_t* CX##_find_it(const CX* self, RawKey rkey, CX##_iter_t* out); \
- STC_API CX##_iter_t CX##_lower_bound(const CX* self, RawKey rkey); \
- STC_API CX##_value_t* CX##_front(const CX* self); \
- STC_API CX##_value_t* CX##_back(const CX* self); \
- STC_API CX##_iter_t CX##_erase_at(CX* self, CX##_iter_t it); \
- STC_API CX##_iter_t CX##_erase_range(CX* self, CX##_iter_t it1, CX##_iter_t it2); \
- STC_API CX##_node_t* CX##_erase_r_(CX##_node_t *tn, const CX##_rawkey_t* rkey, int *erased); \
- STC_API void CX##_del_r_(CX##_node_t* tn); \
- STC_API CX##_node_t* CX##_clone_r_(CX##_node_t *tn); \
- STC_API CX##_result_t CX##_insert_entry_(CX* self, RawKey rkey); \
- STC_API void CX##_next(CX##_iter_t* it); \
-\
- STC_INLINE bool CX##_empty(CX cx) {return cx.size == 0;} \
- STC_INLINE size_t CX##_size(CX cx) {return cx.size;} \
- STC_INLINE void CX##_del(CX* self) {CX##_del_r_(self->root);} \
- STC_INLINE void CX##_clear(CX* self) {CX##_del(self); *self = CX##_init();} \
- STC_INLINE void CX##_swap(CX* a, CX* b) {c_swap(CX, *a, *b);} \
- STC_INLINE CX CX##_clone(CX cx) {return c_make(CX){CX##_clone_r_(cx.root), cx.size};} \
- STC_INLINE CX##_iter_t CX##_find(const CX* self, RawKey rkey) \
- {CX##_iter_t it; CX##_find_it(self, rkey, &it); return it;} \
- STC_INLINE bool CX##_contains(const CX* self, RawKey rkey) \
- {CX##_iter_t it; return CX##_find_it(self, rkey, &it) != NULL;} \
- STC_INLINE CX##_value_t* CX##_get(const CX* self, RawKey rkey) \
- {CX##_iter_t it; return CX##_find_it(self, rkey, &it);} \
-\
- STC_INLINE void \
- CX##_value_del(CX##_value_t* val) { \
- keyDel(KEY_REF_##C(val)); \
- MAP_ONLY_##C( mappedDel(&val->second); ) \
- } \
-\
- STC_INLINE void \
- CX##_value_clone(CX##_value_t* dst, CX##_value_t* val) { \
- *KEY_REF_##C(dst) = keyFromRaw(keyToRaw(KEY_REF_##C(val))); \
- MAP_ONLY_##C( dst->second = mappedFromRaw(mappedToRaw(&val->second)); ) \
- } \
-\
- STC_INLINE CX##_result_t \
- CX##_emplace(CX* self, RawKey rkey MAP_ONLY_##C(, RawMapped rmapped)) { \
- CX##_result_t res = CX##_insert_entry_(self, rkey); \
- if (res.inserted) { \
- *KEY_REF_##C(res.ref) = keyFromRaw(rkey); \
- MAP_ONLY_##C(res.ref->second = mappedFromRaw(rmapped);) \
- } \
- return res; \
- } \
-\
- STC_INLINE void \
- CX##_emplace_items(CX* self, const CX##_rawvalue_t arr[], size_t n) { \
- for (size_t i=0; i<n; ++i) SET_ONLY_##C( CX##_emplace(self, arr[i]); ) \
- MAP_ONLY_##C( CX##_emplace(self, arr[i].first, arr[i].second); ) \
- } \
-\
- STC_INLINE CX##_result_t \
- CX##_insert(CX* self, Key key MAP_ONLY_##C(, Mapped mapped)) { \
- CX##_result_t res = CX##_insert_entry_(self, keyToRaw(&key)); \
- if (res.inserted) {*KEY_REF_##C(res.ref) = key; MAP_ONLY_##C( res.ref->second = mapped; )} \
- else {keyDel(&key); MAP_ONLY_##C( mappedDel(&mapped); )} \
- return res; \
- } \
-\
- MAP_ONLY_##C( \
- STC_INLINE CX##_result_t \
- CX##_insert_or_assign(CX* self, Key key, Mapped mapped) { \
- CX##_result_t res = CX##_insert_entry_(self, keyToRaw(&key)); \
- if (res.inserted) res.ref->first = key; \
- else {keyDel(&key); mappedDel(&res.ref->second);} \
- res.ref->second = mapped; return res; \
- } \
- \
- STC_INLINE CX##_result_t \
- CX##_put(CX* self, Key key, Mapped mapped) { \
- return CX##_insert_or_assign(self, key, mapped); \
- } \
- \
- STC_INLINE CX##_result_t \
- CX##_emplace_or_assign(CX* self, RawKey rkey, RawMapped rmapped) { \
- CX##_result_t res = CX##_insert_entry_(self, rkey); \
- if (res.inserted) res.ref->first = keyFromRaw(rkey); \
- else mappedDel(&res.ref->second); \
- res.ref->second = mappedFromRaw(rmapped); return res; \
- } \
- \
- STC_INLINE CX##_mapped_t* \
- CX##_at(const CX* self, RawKey rkey) { \
- CX##_iter_t it; \
- return &CX##_find_it(self, rkey, &it)->second; \
- }) \
-\
- STC_INLINE CX##_iter_t \
- CX##_begin(const CX* self) { \
- CX##_iter_t it = {NULL, 0, self->root}; \
- CX##_next(&it); return it; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_end(const CX* self) {\
- CX##_iter_t it = {NULL}; return it; \
- } \
-\
- STC_INLINE size_t \
- CX##_erase(CX* self, RawKey rkey) { \
- int erased = 0; \
- self->root = CX##_erase_r_(self->root, &rkey, &erased); \
- self->size -= erased; return erased; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_fwd(CX##_iter_t it, size_t n) { \
- while (n-- && it.ref) CX##_next(&it); \
- return it; \
- } \
-\
- _c_implement_aatree(CX, C, Key, Mapped, keyCompareRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey) \
- struct stc_trailing_semicolon
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-
-#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
-
-_c_aatree_types(csmap_SENTINEL, csmap_, int, int);
-_c_aatree_complete_types(csmap_SENTINEL, csmap_);
-static csmap_SENTINEL_node_t _aatree_sentinel = {&_aatree_sentinel, &_aatree_sentinel, 0};
-
-#define _c_implement_aatree(CX, C, Key, Mapped, keyCompareRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey) \
- STC_DEF CX \
- CX##_init(void) { \
- CX cx = {(CX##_node_t *) &_aatree_sentinel, 0}; \
- return cx; \
- } \
-\
- STC_DEF CX##_value_t* \
- CX##_front(const CX* self) { \
- CX##_node_t *tn = self->root; \
- while (tn->link[0]->level) tn = tn->link[0]; \
- return &tn->value; \
- } \
-\
- STC_DEF CX##_value_t* \
- CX##_back(const CX* self) { \
- CX##_node_t *tn = self->root; \
- while (tn->link[1]->level) tn = tn->link[1]; \
- return &tn->value; \
- } \
-\
- STC_DEF CX##_value_t* \
- CX##_find_it(const CX* self, CX##_rawkey_t rkey, CX##_iter_t* out) { \
- CX##_node_t *tn = self->root; \
- out->_top = 0; \
- while (tn->level) { \
- int c; CX##_rawkey_t rx = keyToRaw(KEY_REF_##C(&tn->value)); \
- if ((c = keyCompareRaw(&rx, &rkey)) < 0) tn = tn->link[1]; \
- else if (c > 0) {out->_st[out->_top++] = tn; tn = tn->link[0];} \
- else {out->_tn = tn->link[1]; return (out->ref = &tn->value);} \
- } \
- return (out->ref = NULL); \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_lower_bound(const CX* self, RawKey rkey) { \
- CX##_iter_t it; \
- CX##_find_it(self, rkey, &it); \
- if (!it.ref && it._top) { \
- CX##_node_t *tn = it._st[--it._top]; \
- it._tn = tn->link[1]; \
- it.ref = &tn->value; \
- } \
- return it; \
- } \
-\
- STC_DEF void \
- CX##_next(CX##_iter_t *it) { \
- CX##_node_t *tn = it->_tn; \
- if (it->_top || tn->level) { \
- while (tn->level) { \
- it->_st[it->_top++] = tn; \
- tn = tn->link[0]; \
- } \
- tn = it->_st[--it->_top]; \
- it->_tn = tn->link[1]; \
- it->ref = &tn->value; \
- } else \
- it->ref = NULL; \
- } \
-\
- static CX##_node_t * \
- CX##_skew_(CX##_node_t *tn) { \
- if (tn && tn->link[0]->level == tn->level && tn->level) { \
- CX##_node_t *tmp = tn->link[0]; \
- tn->link[0] = tmp->link[1]; \
- tmp->link[1] = tn; \
- tn = tmp; \
- } \
- return tn; \
- } \
-\
- static CX##_node_t * \
- CX##_split_(CX##_node_t *tn) { \
- if (tn->link[1]->link[1]->level == tn->level && tn->level) { \
- CX##_node_t *tmp = tn->link[1]; \
- tn->link[1] = tmp->link[0]; \
- tmp->link[0] = tn; \
- tn = tmp; \
- ++tn->level; \
- } \
- return tn; \
- } \
-\
- static inline CX##_node_t* \
- CX##_insert_entry_i_(CX##_node_t* tn, const CX##_rawkey_t* rkey, CX##_result_t* res) { \
- CX##_node_t *up[64], *tx = tn; \
- int c, top = 0, dir = 0; \
- while (tx->level) { \
- up[top++] = tx; \
- CX##_rawkey_t r = keyToRaw(KEY_REF_##C(&tx->value)); \
- if (!(c = keyCompareRaw(&r, rkey))) {res->ref = &tx->value; return tn;} \
- tx = tx->link[(dir = (c < 0))]; \
- } \
- tn = c_new(CX##_node_t); \
- res->ref = &tn->value, res->inserted = true; \
- tn->link[0] = tn->link[1] = (CX##_node_t*) &_aatree_sentinel, tn->level = 1; \
- if (top == 0) return tn; \
- up[top - 1]->link[dir] = tn; \
- while (top--) { \
- if (top) dir = (up[top - 1]->link[1] == up[top]); \
- up[top] = CX##_skew_(up[top]); \
- up[top] = CX##_split_(up[top]); \
- if (top) up[top - 1]->link[dir] = up[top]; \
- } \
- return up[0]; \
- } \
-\
- STC_DEF CX##_result_t \
- CX##_insert_entry_(CX* self, RawKey rkey) { \
- CX##_result_t res = {NULL, false}; \
- self->root = CX##_insert_entry_i_(self->root, &rkey, &res); \
- self->size += res.inserted; \
- return res; \
- } \
-\
- STC_DEF CX##_node_t* \
- CX##_erase_r_(CX##_node_t *tn, const CX##_rawkey_t* rkey, int *erased) { \
- if (tn->level == 0) \
- return tn; \
- CX##_rawkey_t raw = keyToRaw(KEY_REF_##C(&tn->value)); \
- CX##_node_t *tx; int c = keyCompareRaw(&raw, rkey); \
- if (c != 0) \
- tn->link[c < 0] = CX##_erase_r_(tn->link[c < 0], rkey, erased); \
- else { \
- if (!*erased) {CX##_value_del(&tn->value); *erased = 1;} \
- if (tn->link[0]->level && tn->link[1]->level) { \
- tx = tn->link[0]; \
- while (tx->link[1]->level) \
- tx = tx->link[1]; \
- tn->value = tx->value; \
- raw = keyToRaw(KEY_REF_##C(&tn->value)); \
- tn->link[0] = CX##_erase_r_(tn->link[0], &raw, erased); \
- } else { \
- tx = tn; \
- tn = tn->link[tn->link[0]->level == 0]; \
- c_free(tx); \
- } \
- } \
- if (tn->link[0]->level < tn->level - 1 || tn->link[1]->level < tn->level - 1) { \
- if (tn->link[1]->level > --tn->level) \
- tn->link[1]->level = tn->level; \
- tn = CX##_skew_(tn); \
- tx = tn->link[0] = CX##_skew_(tn->link[0]); \
- tx->link[0] = CX##_skew_(tx->link[0]); \
- tn = CX##_split_(tn); \
- tn->link[0] = CX##_split_(tn->link[0]); \
- } \
- return tn; \
- } \
- STC_DEF CX##_iter_t \
- CX##_erase_at(CX* self, CX##_iter_t it) { \
- CX##_rawkey_t raw = keyToRaw(KEY_REF_##C(it.ref)), nxt; \
- CX##_next(&it); \
- if (it.ref) nxt = keyToRaw(KEY_REF_##C(it.ref)); \
- CX##_erase(self, raw); \
- if (it.ref) CX##_find_it(self, nxt, &it); \
- return it; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_erase_range(CX* self, CX##_iter_t it1, CX##_iter_t it2) { \
- if (!it2.ref) { while (it1.ref) it1 = CX##_erase_at(self, it1); \
- return it1; } \
- CX##_key_t k1 = *KEY_REF_##C(it1.ref), k2 = *KEY_REF_##C(it2.ref); \
- CX##_rawkey_t r1 = keyToRaw(&k1); \
- for (;;) { \
- if (memcmp(&k1, &k2, sizeof k1) == 0) return it1; \
- CX##_next(&it1); k1 = *KEY_REF_##C(it1.ref); \
- CX##_erase(self, r1); \
- CX##_find_it(self, (r1 = keyToRaw(&k1)), &it1); \
- } \
- } \
-\
- STC_DEF CX##_node_t* \
- CX##_clone_r_(CX##_node_t *tn) { \
- if (! tn->level) return tn; \
- CX##_node_t *cn = c_new(CX##_node_t); \
- cn->link[0] = CX##_clone_r_(tn->link[0]); \
- cn->link[1] = CX##_clone_r_(tn->link[1]); \
- cn->level = tn->level; \
- CX##_value_clone(&cn->value, &tn->value); \
- return cn; \
- } \
-\
- STC_DEF void \
- CX##_del_r_(CX##_node_t* tn) { \
- if (tn->level != 0) { \
- CX##_del_r_(tn->link[0]); \
- CX##_del_r_(tn->link[1]); \
- CX##_value_del(&tn->value); \
- c_free(tn); \
- } \
- }
-
-#else
-#define _c_implement_aatree(CX, C, Key, Mapped, keyCompareRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey)
-#endif
-#endif
diff --git a/benchmarks/others/old/clist.h b/benchmarks/others/old/clist.h
new file mode 100644
index 00000000..10d8092e
--- /dev/null
+++ b/benchmarks/others/old/clist.h
@@ -0,0 +1,367 @@
+/* MIT License
+ *
+ * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no
+ *
+ * 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 CLIST_H_INCLUDED
+#define CLIST_H_INCLUDED
+
+/* Circular Singly-linked Lists.
+
+ This implements a std::forward_list-like class in C, but because it is circular,
+ it also support push* and splice* at both ends of the list. This makes it ideal
+ for being used as a queue, unlike std::forward_list. Basic usage is similar to cvec:
+
+ #include <stdio.h>
+ #include <stc/clist.h>
+ #include <stc/crandom.h>
+ using_clist(ix, int64_t);
+
+ int main() {
+ clist_ix list = clist_ix_init();
+ stc64_t rng = stc64_init(12345);
+ int n;
+ for (int i=0; i<1000000; ++i) // one million
+ clist_ix_push_back(&list, stc64_rand(&rng) >> 32);
+ n = 0;
+ c_foreach (i, clist_ix, list)
+ if (++n % 10000 == 0) printf("%8d: %10zd\n", n, i.ref->value);
+ // Sort them...
+ clist_ix_sort(&list); // mergesort O(n*log n)
+ n = 0;
+ puts("sorted");
+ c_foreach (i, clist_ix, list)
+ if (++n % 10000 == 0) printf("%8d: %10zd\n", n, i.ref->value);
+ clist_ix_del(&list);
+ }
+*/
+#include <stc/ccommon.h>
+#include <stdlib.h>
+
+
+
+_c_clist_types(clist_VOID, int);
+STC_API size_t _clist_count(const clist_VOID* self);
+#define _clist_node(Self, vp) c_container_of(vp, cx_node_t, value)
+
+#define _c_using_clist(Self, i_val, i_cmp, i_valdel, i_valfrom, i_valto, i_valraw, defTypes) \
+\
+ defTypes( _c_clist_types(Self, i_val); ) \
+ typedef i_valraw cx_rawvalue_t; \
+\
+ STC_API Self cx_memb(_clone)(Self lst); \
+ STC_API void cx_memb(_del)(Self* self); \
+ STC_API void cx_memb(_push_back)(Self* self, i_val value); \
+ STC_API void cx_memb(_push_front)(Self* self, i_val value); \
+ STC_API void cx_memb(_emplace_items)(Self *self, const cx_rawvalue_t arr[], size_t n); \
+ STC_API Self cx_memb(_split_after)(Self* self, cx_iter_t pos1, cx_iter_t pos2); \
+ STC_API void cx_memb(_splice_after)(Self* self, cx_iter_t pos, Self* other); \
+ STC_DEF void cx_memb(_splice_after_range)(Self* self, cx_iter_t pos, Self* other, cx_iter_t i1, cx_iter_t i2); \
+ STC_API cx_iter_t cx_memb(_find)(const Self* self, i_valraw val); \
+ STC_API cx_iter_t cx_memb(_find_before)(const Self* self, i_valraw val); \
+ STC_API cx_iter_t cx_memb(_find_before_in)(cx_iter_t it1, cx_iter_t it2, i_valraw val); \
+ STC_API void cx_memb(_sort)(Self* self); \
+ STC_API size_t cx_memb(_remove)(Self* self, i_valraw val); \
+ STC_API cx_iter_t cx_memb(_insert_after)(Self* self, cx_iter_t pos, i_val value); \
+ STC_API cx_iter_t cx_memb(_erase_after)(Self* self, cx_iter_t pos); \
+ STC_API cx_iter_t cx_memb(_erase_range_after)(Self* self, cx_iter_t pos, cx_iter_t it2); \
+ STC_API cx_node_t* cx_memb(_erase_after_)(Self* self, cx_node_t* node); \
+\
+ STC_INLINE Self cx_memb(_init)(void) {Self lst = {NULL}; return lst; } \
+ STC_INLINE bool cx_memb(_empty)(Self lst) { return lst.last == NULL; } \
+ STC_INLINE size_t cx_memb(_count)(Self lst) { return _clist_count((const clist_VOID*) &lst); } \
+ STC_INLINE i_val cx_memb(_value_fromraw)(i_valraw raw) { return i_valfrom(raw); } \
+ STC_INLINE i_val cx_memb(_value_clone)(i_val val) { return i_valfrom(i_valto(&val)); } \
+ STC_INLINE void cx_memb(_clear)(Self* self) { cx_memb(_del)(self); } \
+ STC_INLINE void cx_memb(_emplace_back)(Self* self, i_valraw raw) \
+ { cx_memb(_push_back)(self, i_valfrom(raw)); } \
+ STC_INLINE void cx_memb(_emplace_front)(Self* self, i_valraw raw) \
+ { cx_memb(_push_front)(self, i_valfrom(raw)); } \
+ STC_INLINE cx_value_t* \
+ cx_memb(_front)(const Self* self) { return &self->last->next->value; } \
+ STC_INLINE cx_value_t* \
+ cx_memb(_back)(const Self* self) { return &self->last->value; } \
+ STC_INLINE void cx_memb(_pop_front)(Self* self) { cx_memb(_erase_after_)(self, self->last); } \
+ STC_INLINE void cx_memb(_splice_front)(Self* self, Self* other) \
+ { cx_memb(_splice_after)(self, cx_memb(_before_begin)(self), other); } \
+ STC_INLINE void cx_memb(_splice_back)(Self* self, Self* other) \
+ { cx_memb(_splice_after)(self, cx_memb(_last)(self), other); } \
+\
+ STC_INLINE cx_iter_t \
+ cx_memb(_emplace_after)(Self* self, cx_iter_t pos, i_valraw raw) { \
+ return cx_memb(_insert_after)(self, pos, i_valfrom(raw)); \
+ } \
+\
+ STC_INLINE cx_iter_t \
+ cx_memb(_before_begin)(const Self* self) { \
+ cx_value_t *last = self->last ? &self->last->value : NULL; \
+ cx_iter_t it = {&self->last, last, -1}; return it; \
+ } \
+\
+ STC_INLINE cx_iter_t \
+ cx_memb(_begin)(const Self* self) { \
+ cx_value_t* head = self->last ? &self->last->next->value : NULL; \
+ cx_iter_t it = {&self->last, head, 0}; return it; \
+ } \
+\
+ STC_INLINE cx_iter_t \
+ cx_memb(_last)(const Self* self) { \
+ cx_value_t *last = self->last ? &self->last->value : NULL; \
+ cx_iter_t it = {&self->last, last, 0}; return it; \
+ } \
+\
+ STC_INLINE cx_iter_t \
+ cx_memb(_end)(const Self* self) { \
+ cx_iter_t it = {NULL, NULL}; return it; \
+ } \
+\
+ STC_INLINE void \
+ cx_memb(_next)(cx_iter_t* it) { \
+ cx_node_t* node = _clist_node(Self, it->ref); \
+ it->ref = ((it->_state += node == *it->_last) == 1) ? NULL : &node->next->value; \
+ } \
+\
+ STC_INLINE cx_iter_t \
+ cx_memb(_advance)(cx_iter_t it, size_t n) { \
+ while (n-- && it.ref) cx_memb(_next)(&it); return it; \
+ } \
+ \
+ _c_implement_clist(Self, i_val, i_cmp, i_valdel, i_valfrom, i_valto, i_valraw) \
+ struct stc_trailing_semicolon
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+
+#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
+#define _c_implement_clist(Self, i_val, i_cmp, i_valdel, i_valfrom, i_valto, i_valraw) \
+\
+ STC_DEF Self \
+ cx_memb(_clone)(Self lst) { \
+ Self out = cx_memb(_init)(); \
+ c_foreach_3 (i, Self, lst) \
+ cx_memb(_emplace_back)(&out, i_valto(i.ref)); \
+ return out; \
+ } \
+\
+ STC_DEF void \
+ cx_memb(_del)(Self* self) { \
+ while (self->last) cx_memb(_erase_after_)(self, self->last); \
+ } \
+\
+ STC_DEF void \
+ cx_memb(_push_back)(Self* self, i_val value) { \
+ _c_clist_insert_after(self, Self, self->last, value); \
+ self->last = entry; \
+ } \
+ STC_DEF void \
+ cx_memb(_push_front)(Self* self, i_val value) { \
+ _c_clist_insert_after(self, Self, self->last, value); \
+ if (!self->last) self->last = entry; \
+ } \
+\
+ STC_DEF void \
+ cx_memb(_emplace_items)(Self *self, const cx_rawvalue_t arr[], size_t n) { \
+ for (size_t i=0; i<n; ++i) cx_memb(_push_back)(self, i_valfrom(arr[i])); \
+ } \
+\
+ STC_DEF cx_iter_t \
+ cx_memb(_insert_after)(Self* self, cx_iter_t pos, i_val value) { \
+ cx_node_t* node = pos.ref ? _clist_node(Self, pos.ref) : NULL; \
+ _c_clist_insert_after(self, Self, node, value); \
+ if (!node || node == self->last && pos._state == 0) self->last = entry; \
+ pos.ref = &entry->value, pos._state = 0; return pos; \
+ } \
+\
+ STC_DEF cx_iter_t \
+ cx_memb(_erase_after)(Self* self, cx_iter_t pos) { \
+ cx_memb(_erase_after_)(self, _clist_node(Self, pos.ref)); \
+ cx_memb(_next)(&pos); return pos; \
+ } \
+\
+ STC_DEF cx_iter_t \
+ cx_memb(_erase_range_after)(Self* self, cx_iter_t it1, cx_iter_t it2) { \
+ cx_node_t* node = _clist_node(Self, it1.ref), *done = it2.ref ? _clist_node(Self, it2.ref) : NULL; \
+ while (node && node->next != done) \
+ node = cx_memb(_erase_after_)(self, node); \
+ cx_memb(_next)(&it1); return it1; \
+ } \
+\
+ STC_DEF cx_iter_t \
+ cx_memb(_find_before_in)(cx_iter_t it1, cx_iter_t it2, i_valraw val) { \
+ cx_iter_t i = it1; \
+ for (cx_memb(_next)(&i); i.ref != it2.ref; cx_memb(_next)(&i)) { \
+ i_valraw r = i_valto(i.ref); \
+ if (i_cmp(&r, &val) == 0) return it1; \
+ it1 = i; \
+ } \
+ it1.ref = NULL; return it1; \
+ } \
+\
+ STC_DEF cx_iter_t \
+ cx_memb(_find_before)(const Self* self, i_valraw val) { \
+ cx_iter_t it = cx_memb(_find_before_in)(cx_memb(_before_begin)(self), cx_memb(_end)(self), val); \
+ return it; \
+ } \
+\
+ STC_DEF cx_iter_t \
+ cx_memb(_find)(const Self* self, i_valraw val) { \
+ cx_iter_t it = cx_memb(_find_before_in)(cx_memb(_before_begin)(self), cx_memb(_end)(self), val); \
+ if (it.ref != cx_memb(_end)(self).ref) cx_memb(_next)(&it); \
+ return it; \
+ } \
+\
+ STC_DEF cx_node_t* \
+ cx_memb(_erase_after_)(Self* self, cx_node_t* node) { \
+ cx_node_t* del = node->next, *next = del->next; \
+ node->next = next; \
+ if (del == next) self->last = node = NULL; \
+ else if (self->last == del) self->last = node, node = NULL; \
+ i_valdel(&del->value); c_free(del); \
+ return node; \
+ } \
+\
+ STC_DEF size_t \
+ cx_memb(_remove)(Self* self, i_valraw val) { \
+ size_t n = 0; \
+ cx_node_t* prev = self->last, *node; \
+ while (prev) { \
+ node = prev->next; \
+ i_valraw r = i_valto(&node->value); \
+ if (i_cmp(&r, &val) == 0) \
+ prev = cx_memb(_erase_after_)(self, prev), ++n; \
+ else \
+ prev = (node == self->last ? NULL : node); \
+ } \
+ return n; \
+ } \
+\
+ STC_DEF Self \
+ cx_memb(_split_after)(Self* self, cx_iter_t pos1, cx_iter_t pos2) { \
+ cx_node_t *node1 = _clist_node(Self, pos1.ref), *next1 = node1->next, \
+ *node2 = _clist_node(Self, pos2.ref); \
+ node1->next = node2->next, node2->next = next1; \
+ if (self->last == node2) self->last = node1; \
+ Self lst = {node2}; return lst; \
+ } \
+\
+ STC_DEF void \
+ cx_memb(_splice_after)(Self* self, cx_iter_t pos, Self* other) { \
+ if (!pos.ref) \
+ self->last = other->last; \
+ else if (other->last) { \
+ cx_node_t *node = _clist_node(Self, pos.ref), *next = node->next; \
+ node->next = other->last->next; \
+ other->last->next = next; \
+ if (node == self->last && pos._state == 0) self->last = other->last; \
+ } \
+ other->last = NULL; \
+ } \
+\
+ STC_DEF void \
+ cx_memb(_splice_after_range)(Self* self, cx_iter_t pos, Self* other, cx_iter_t pos1, cx_iter_t pos2) { \
+ Self tmp = cx_memb(_split_after)(other, pos1, pos2); \
+ cx_memb(_splice_after)(self, pos, &tmp); \
+ } \
+\
+ STC_DEF int \
+ cx_memb(_sort_cmp_)(const void* x, const void* y) { \
+ i_valraw a = i_valto(&((cx_node_t *) x)->value); \
+ i_valraw b = i_valto(&((cx_node_t *) y)->value); \
+ return i_cmp(&a, &b); \
+ } \
+\
+ STC_DEF void \
+ cx_memb(_sort)(Self* self) { \
+ if (self->last) \
+ self->last = (cx_node_t *) _clist_mergesort((clist_VOID_node_t *) self->last->next, cx_memb(_sort_cmp_)); \
+ }
+
+
+#define _c_clist_insert_after(self, Self, node, val) \
+ cx_node_t *entry = c_new (cx_node_t); \
+ if (node) entry->next = node->next, node->next = entry; \
+ else entry->next = entry; \
+ entry->value = val
+ /* +: set self->last based on node */
+
+STC_DEF size_t
+_clist_count(const clist_VOID* self) {
+ const clist_VOID_node_t *nd = self->last;
+ if (!nd) return 0;
+ size_t n = 1;
+ while ((nd = nd->next) != self->last) ++n;
+ return n;
+}
+
+/* Singly linked list Mergesort implementation by Simon Tatham. O(n*log n).
+ * https://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
+ */
+STC_DEF clist_VOID_node_t *
+_clist_mergesort(clist_VOID_node_t *list, int (*cmp)(const void*, const void*)) {
+ clist_VOID_node_t *p, *q, *e, *tail, *oldhead;
+ int insize = 1, nmerges, psize, qsize, i;
+
+ while (1) {
+ p = oldhead = list;
+ list = tail = NULL;
+ nmerges = 0;
+
+ while (p) {
+ ++nmerges;
+ q = p, psize = 0;
+ for (i = 0; i < insize; ++i) {
+ ++psize;
+ q = (q->next == oldhead ? NULL : q->next);
+ if (!q) break;
+ }
+ qsize = insize;
+
+ while (psize > 0 || (qsize > 0 && q)) {
+ if (psize == 0) {
+ e = q, q = q->next, --qsize;
+ if (q == oldhead) q = NULL;
+ } else if (qsize == 0 || !q) {
+ e = p, p = p->next, --psize;
+ if (p == oldhead) p = NULL;
+ } else if (cmp(p, q) <= 0) {
+ e = p, p = p->next, --psize;
+ if (p == oldhead) p = NULL;
+ } else {
+ e = q, q = q->next, --qsize;
+ if (q == oldhead) q = NULL;
+ }
+ if (tail) tail->next = e; else list = e;
+ tail = e;
+ }
+ p = q;
+ }
+ tail->next = list;
+
+ if (nmerges <= 1)
+ return tail;
+
+ insize *= 2;
+ }
+}
+
+#else
+#define _c_implement_clist(Self, i_val, i_cmp, i_valdel, i_valfrom, i_valto, i_valraw)
+#endif
+
+#endif
diff --git a/benchmarks/others/old/csmap.h b/benchmarks/others/old/csmap.h
new file mode 100644
index 00000000..88c3967a
--- /dev/null
+++ b/benchmarks/others/old/csmap.h
@@ -0,0 +1,404 @@
+/* MIT License
+ *
+ * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no
+ *
+ * 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 CSMAP_H_INCLUDED
+#define CSMAP_H_INCLUDED
+
+// Sorted/Ordered set and map - implemented as an AA-tree.
+/*
+#include <stdio.h>
+#include <stc/csmap.h>
+using_csmap(mx, int, char); // Sorted map<int, char>
+
+int main(void) {
+ c_forvar (csmap_mx m = csmap_mx_init(), csmap_mx_del(&m))
+ {
+ csmap_mx_insert(&m, 5, 'a');
+ csmap_mx_insert(&m, 8, 'b');
+ csmap_mx_insert(&m, 12, 'c');
+
+ csmap_mx_iter_t it = csmap_mx_find(&m, 10); // none
+ char val = csmap_mx_find(&m, 5).ref->second;
+ csmap_mx_put(&m, 5, 'd'); // update
+ csmap_mx_erase(&m, 8);
+
+ c_foreach (i, csmap_mx, m)
+ printf("map %d: %c\n", i.ref->first, i.ref->second);
+ }
+}
+*/
+#include <stc/ccommon.h>
+#include <stc/template.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define KEY_REF_csmap_(vp) (&(vp)->first)
+#define _c_aatree_complete_types(Self, C) \
+ cx_MAP_ONLY( struct cx_value_t { \
+ cx_key_t first; \
+ cx_mapped_t second; \
+ }; ) \
+ struct cx_node_t { \
+ struct cx_node_t *link[2]; \
+ uint8_t level; \
+ cx_value_t value; \
+ }
+
+#ifndef cx_forwarded
+ _c_aatree_types(Self, C, i_key, i_val);
+#endif
+
+ _c_aatree_complete_types(Self, C); \
+\
+ typedef i_keyraw cx_rawkey_t; \
+ typedef i_valraw cx_memb(_rawmapped_t); \
+ typedef cx_SET_ONLY( cx_rawkey_t ) \
+ cx_MAP_ONLY( struct { cx_rawkey_t first; \
+ cx_memb(_rawmapped_t) second; } ) \
+ cx_rawvalue_t; \
+\
+ STC_API Self cx_memb(_init)(void); \
+ STC_API cx_value_t* cx_memb(_find_it)(const Self* self, i_keyraw rkey, cx_iter_t* out); \
+ STC_API cx_iter_t cx_memb(_lower_bound)(const Self* self, i_keyraw rkey); \
+ STC_API cx_value_t* cx_memb(_front)(const Self* self); \
+ STC_API cx_value_t* cx_memb(_back)(const Self* self); \
+ STC_API cx_iter_t cx_memb(_erase_at)(Self* self, cx_iter_t it); \
+ STC_API cx_iter_t cx_memb(_erase_range)(Self* self, cx_iter_t it1, cx_iter_t it2); \
+ STC_API cx_node_t* cx_memb(_erase_r_)(cx_node_t *tn, const cx_rawkey_t* rkey, int *erased); \
+ STC_API void cx_memb(_del_r_)(cx_node_t* tn); \
+ STC_API cx_node_t* cx_memb(_clone_r_)(cx_node_t *tn); \
+ STC_API cx_result_t cx_memb(_insert_entry_)(Self* self, i_keyraw rkey); \
+ STC_API void cx_memb(_next)(cx_iter_t* it); \
+\
+ STC_INLINE bool cx_memb(_empty)(Self cx) { return cx.size == 0; } \
+ STC_INLINE size_t cx_memb(_size)(Self cx) { return cx.size; } \
+ STC_INLINE void cx_memb(_del)(Self* self) { cx_memb(_del_r_)(self->root); } \
+ STC_INLINE void cx_memb(_clear)(Self* self) { cx_memb(_del)(self); *self = cx_memb(_init)(); } \
+ STC_INLINE void cx_memb(_swap)(Self* a, Self* b) {c_swap(Self, *a, *b); } \
+ STC_INLINE Self cx_memb(_clone)(Self cx) { return c_make(Self){ cx_memb(_clone_r_)(cx.root), cx.size}; } \
+ STC_INLINE cx_iter_t cx_memb(_find)(const Self* self, i_keyraw rkey) \
+ {cx_iter_t it; cx_memb(_find_it)(self, rkey, &it); return it; } \
+ STC_INLINE bool cx_memb(_contains)(const Self* self, i_keyraw rkey) \
+ {cx_iter_t it; return cx_memb(_find_it)(self, rkey, &it) != NULL; } \
+ STC_INLINE cx_value_t* cx_memb(_get)(const Self* self, i_keyraw rkey) \
+ {cx_iter_t it; return cx_memb(_find_it)(self, rkey, &it); } \
+\
+ STC_INLINE void \
+ cx_memb(_value_del)(cx_value_t* val) { \
+ i_keydel(cx_keyref(val)); \
+ cx_MAP_ONLY( i_valdel(&val->second); ) \
+ } \
+\
+ STC_INLINE void \
+ cx_memb(_value_clone)(cx_value_t* dst, cx_value_t* val) { \
+ *cx_keyref(dst) = i_keyfrom(i_keyto(cx_keyref(val))); \
+ cx_MAP_ONLY( dst->second = i_valfrom(i_valto(&val->second)); ) \
+ } \
+\
+ STC_INLINE cx_result_t \
+ cx_memb(_emplace)(Self* self, i_keyraw rkey cx_MAP_ONLY(, i_valraw rmapped)) { \
+ cx_result_t res = cx_memb(_insert_entry_)(self, rkey); \
+ if (res.inserted) { \
+ *cx_keyref(res.ref) = i_keyfrom(rkey); \
+ cx_MAP_ONLY(res.ref->second = i_valfrom(rmapped);) \
+ } \
+ return res; \
+ } \
+\
+ STC_INLINE void \
+ cx_memb(_emplace_items)(Self* self, const cx_rawvalue_t arr[], size_t n) { \
+ for (size_t i=0; i<n; ++i) cx_SET_ONLY( cx_memb(_emplace)(self, arr[i]); ) \
+ cx_MAP_ONLY( cx_memb(_emplace)(self, arr[i].first, arr[i].second); ) \
+ } \
+\
+ STC_INLINE cx_result_t \
+ cx_memb(_insert)(Self* self, i_key key cx_MAP_ONLY(, i_val mapped)) { \
+ cx_result_t res = cx_memb(_insert_entry_)(self, i_keyto(&key)); \
+ if (res.inserted) {*cx_keyref(res.ref) = key; cx_MAP_ONLY( res.ref->second = mapped; )} \
+ else {i_keydel(&key); cx_MAP_ONLY( i_valdel(&mapped); )} \
+ return res; \
+ } \
+\
+ cx_MAP_ONLY( \
+ STC_INLINE cx_result_t \
+ cx_memb(_insert_or_assign)(Self* self, i_key key, i_val mapped) { \
+ cx_result_t res = cx_memb(_insert_entry_)(self, i_keyto(&key)); \
+ if (res.inserted) res.ref->first = key; \
+ else {i_keydel(&key); i_valdel(&res.ref->second); } \
+ res.ref->second = mapped; return res; \
+ } \
+ \
+ STC_INLINE cx_result_t \
+ cx_memb(_put)(Self* self, i_key key, i_val mapped) { \
+ return cx_memb(_insert_or_assign)(self, key, mapped); \
+ } \
+ \
+ STC_INLINE cx_result_t \
+ cx_memb(_emplace_or_assign)(Self* self, i_keyraw rkey, i_valraw rmapped) { \
+ cx_result_t res = cx_memb(_insert_entry_)(self, rkey); \
+ if (res.inserted) res.ref->first = i_keyfrom(rkey); \
+ else i_valdel(&res.ref->second); \
+ res.ref->second = i_valfrom(rmapped); return res; \
+ } \
+ \
+ STC_INLINE cx_mapped_t* \
+ cx_memb(_at)(const Self* self, i_keyraw rkey) { \
+ cx_iter_t it; \
+ return &cx_memb(_find_it)(self, rkey, &it)->second; \
+ }) \
+\
+ STC_INLINE cx_iter_t \
+ cx_memb(_begin)(const Self* self) { \
+ cx_iter_t it = {NULL, 0, self->root}; \
+ cx_memb(_next)(&it); return it; \
+ } \
+\
+ STC_INLINE cx_iter_t \
+ cx_memb(_end)(const Self* self) {\
+ cx_iter_t it = {NULL}; return it; \
+ } \
+\
+ STC_INLINE size_t \
+ cx_memb(_erase)(Self* self, i_keyraw rkey) { \
+ int erased = 0; \
+ self->root = cx_memb(_erase_r_)(self->root, &rkey, &erased); \
+ self->size -= erased; return erased; \
+ } \
+\
+ STC_INLINE cx_iter_t \
+ cx_memb(_advance)(cx_iter_t it, size_t n) { \
+ while (n-- && it.ref) cx_memb(_next)(&it); \
+ return it; \
+ } \
+\
+ _c_implement_aatree(Self, C, i_key, i_val, i_cmp, \
+ i_valdel, i_valfrom, i_valto, i_valraw, \
+ i_keydel, i_keyfrom, i_keyto, i_keyraw) \
+ struct stc_trailing_semicolon
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+
+#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
+
+_c_aatree_types(csmap_SENTINEL, csmap_, int, int);
+_c_aatree_complete_types(csmap_SENTINEL, csmap_);
+static csmap_SENTINEL_node_t _aatree_sentinel = {&_aatree_sentinel, &_aatree_sentinel, 0};
+
+#define _c_implement_aatree(Self, C, i_key, i_val, i_cmp, \
+ i_valdel, i_valfrom, i_valto, i_valraw, \
+ i_keydel, i_keyfrom, i_keyto, i_keyraw) \
+ STC_DEF Self \
+ cx_memb(_init)(void) { \
+ Self cx = {(cx_node_t *) &_aatree_sentinel, 0}; \
+ return cx; \
+ } \
+\
+ STC_DEF cx_value_t* \
+ cx_memb(_front)(const Self* self) { \
+ cx_node_t *tn = self->root; \
+ while (tn->link[0]->level) tn = tn->link[0]; \
+ return &tn->value; \
+ } \
+\
+ STC_DEF cx_value_t* \
+ cx_memb(_back)(const Self* self) { \
+ cx_node_t *tn = self->root; \
+ while (tn->link[1]->level) tn = tn->link[1]; \
+ return &tn->value; \
+ } \
+\
+ STC_DEF cx_value_t* \
+ cx_memb(_find_it)(const Self* self, cx_rawkey_t rkey, cx_iter_t* out) { \
+ cx_node_t *tn = self->root; \
+ out->_top = 0; \
+ while (tn->level) { \
+ int c; cx_rawkey_t rx = i_keyto(cx_keyref(&tn->value)); \
+ if ((c = i_cmp(&rx, &rkey)) < 0) tn = tn->link[1]; \
+ else if (c > 0) {out->_st[out->_top++] = tn; tn = tn->link[0]; } \
+ else {out->_tn = tn->link[1]; return (out->ref = &tn->value); } \
+ } \
+ return (out->ref = NULL); \
+ } \
+\
+ STC_DEF cx_iter_t \
+ cx_memb(_lower_bound)(const Self* self, i_keyraw rkey) { \
+ cx_iter_t it; \
+ cx_memb(_find_it)(self, rkey, &it); \
+ if (!it.ref && it._top) { \
+ cx_node_t *tn = it._st[--it._top]; \
+ it._tn = tn->link[1]; \
+ it.ref = &tn->value; \
+ } \
+ return it; \
+ } \
+\
+ STC_DEF void \
+ cx_memb(_next)(cx_iter_t *it) { \
+ cx_node_t *tn = it->_tn; \
+ if (it->_top || tn->level) { \
+ while (tn->level) { \
+ it->_st[it->_top++] = tn; \
+ tn = tn->link[0]; \
+ } \
+ tn = it->_st[--it->_top]; \
+ it->_tn = tn->link[1]; \
+ it->ref = &tn->value; \
+ } else \
+ it->ref = NULL; \
+ } \
+\
+ static cx_node_t * \
+ cx_memb(_skew_)(cx_node_t *tn) { \
+ if (tn && tn->link[0]->level == tn->level && tn->level) { \
+ cx_node_t *tmp = tn->link[0]; \
+ tn->link[0] = tmp->link[1]; \
+ tmp->link[1] = tn; \
+ tn = tmp; \
+ } \
+ return tn; \
+ } \
+\
+ static cx_node_t * \
+ cx_memb(_split_)(cx_node_t *tn) { \
+ if (tn->link[1]->link[1]->level == tn->level && tn->level) { \
+ cx_node_t *tmp = tn->link[1]; \
+ tn->link[1] = tmp->link[0]; \
+ tmp->link[0] = tn; \
+ tn = tmp; \
+ ++tn->level; \
+ } \
+ return tn; \
+ } \
+\
+ static inline cx_node_t* \
+ cx_memb(_insert_entry_i_)(cx_node_t* tn, const cx_rawkey_t* rkey, cx_result_t* res) { \
+ cx_node_t *up[64], *tx = tn; \
+ int c, top = 0, dir = 0; \
+ while (tx->level) { \
+ up[top++] = tx; \
+ cx_rawkey_t r = i_keyto(cx_keyref(&tx->value)); \
+ if (!(c = i_cmp(&r, rkey))) {res->ref = &tx->value; return tn; } \
+ tx = tx->link[(dir = (c < 0))]; \
+ } \
+ tn = c_new(cx_node_t); \
+ res->ref = &tn->value, res->inserted = true; \
+ tn->link[0] = tn->link[1] = (cx_node_t*) &_aatree_sentinel, tn->level = 1; \
+ if (top == 0) return tn; \
+ up[top - 1]->link[dir] = tn; \
+ while (top--) { \
+ if (top) dir = (up[top - 1]->link[1] == up[top]); \
+ up[top] = cx_memb(_skew_)(up[top]); \
+ up[top] = cx_memb(_split_)(up[top]); \
+ if (top) up[top - 1]->link[dir] = up[top]; \
+ } \
+ return up[0]; \
+ } \
+\
+ STC_DEF cx_result_t \
+ cx_memb(_insert_entry_)(Self* self, i_keyraw rkey) { \
+ cx_result_t res = {NULL, false}; \
+ self->root = cx_memb(_insert_entry_i_)(self->root, &rkey, &res); \
+ self->size += res.inserted; \
+ return res; \
+ } \
+\
+ STC_DEF cx_node_t* \
+ cx_memb(_erase_r_)(cx_node_t *tn, const cx_rawkey_t* rkey, int *erased) { \
+ if (tn->level == 0) \
+ return tn; \
+ cx_rawkey_t raw = i_keyto(cx_keyref(&tn->value)); \
+ cx_node_t *tx; int c = i_cmp(&raw, rkey); \
+ if (c != 0) \
+ tn->link[c < 0] = cx_memb(_erase_r_)(tn->link[c < 0], rkey, erased); \
+ else { \
+ if (!*erased) { cx_memb(_value_del)(&tn->value); *erased = 1; } \
+ if (tn->link[0]->level && tn->link[1]->level) { \
+ tx = tn->link[0]; \
+ while (tx->link[1]->level) \
+ tx = tx->link[1]; \
+ tn->value = tx->value; \
+ raw = i_keyto(cx_keyref(&tn->value)); \
+ tn->link[0] = cx_memb(_erase_r_)(tn->link[0], &raw, erased); \
+ } else { \
+ tx = tn; \
+ tn = tn->link[tn->link[0]->level == 0]; \
+ c_free(tx); \
+ } \
+ } \
+ if (tn->link[0]->level < tn->level - 1 || tn->link[1]->level < tn->level - 1) { \
+ if (tn->link[1]->level > --tn->level) \
+ tn->link[1]->level = tn->level; \
+ tn = cx_memb(_skew_)(tn); \
+ tx = tn->link[0] = cx_memb(_skew_)(tn->link[0]); \
+ tx->link[0] = cx_memb(_skew_)(tx->link[0]); \
+ tn = cx_memb(_split_)(tn); \
+ tn->link[0] = cx_memb(_split_)(tn->link[0]); \
+ } \
+ return tn; \
+ } \
+ STC_DEF cx_iter_t \
+ cx_memb(_erase_at)(Self* self, cx_iter_t it) { \
+ cx_rawkey_t raw = i_keyto(cx_keyref(it.ref)), nxt; \
+ cx_memb(_next)(&it); \
+ if (it.ref) nxt = i_keyto(cx_keyref(it.ref)); \
+ cx_memb(_erase)(self, raw); \
+ if (it.ref) cx_memb(_find_it)(self, nxt, &it); \
+ return it; \
+ } \
+\
+ STC_DEF cx_iter_t \
+ cx_memb(_erase_range)(Self* self, cx_iter_t it1, cx_iter_t it2) { \
+ if (!it2.ref) { while (it1.ref) it1 = cx_memb(_erase_at)(self, it1); \
+ return it1; } \
+ cx_key_t k1 = *cx_keyref(it1.ref), k2 = *cx_keyref(it2.ref); \
+ cx_rawkey_t r1 = i_keyto(&k1); \
+ for (;;) { \
+ if (memcmp(&k1, &k2, sizeof k1) == 0) return it1; \
+ cx_memb(_next)(&it1); k1 = *cx_keyref(it1.ref); \
+ cx_memb(_erase)(self, r1); \
+ cx_memb(_find_it)(self, (r1 = i_keyto(&k1)), &it1); \
+ } \
+ } \
+\
+ STC_DEF cx_node_t* \
+ cx_memb(_clone_r_)(cx_node_t *tn) { \
+ if (! tn->level) return tn; \
+ cx_node_t *cn = c_new(cx_node_t); \
+ cn->link[0] = cx_memb(_clone_r_)(tn->link[0]); \
+ cn->link[1] = cx_memb(_clone_r_)(tn->link[1]); \
+ cn->level = tn->level; \
+ cx_memb(_value_clone)(&cn->value, &tn->value); \
+ return cn; \
+ } \
+\
+ STC_DEF void \
+ cx_memb(_del_r_)(cx_node_t* tn) { \
+ if (tn->level != 0) { \
+ cx_memb(_del_r_)(tn->link[0]); \
+ cx_memb(_del_r_)(tn->link[1]); \
+ cx_memb(_value_del)(&tn->value); \
+ c_free(tn); \
+ } \
+ }
+
+#endif
+#endif
diff --git a/benchmarks/shootout1_cmap.cpp b/benchmarks/shootout1_cmap.cpp
index d368afa8..5fd32586 100644
--- a/benchmarks/shootout1_cmap.cpp
+++ b/benchmarks/shootout1_cmap.cpp
@@ -1,6 +1,5 @@
#include <stc/crandom.h>
#include <stc/cstr.h>
-#include <stc/cmap.h>
#include <cmath>
#include <string>
#include <unordered_map>
@@ -39,10 +38,21 @@ DEFMAP(map_i, <int, int>);
DEFMAP(map_x, <uint64_t, uint64_t>);
DEFMAP(map_s, <std::string, std::string>);
-using_cmap(i, int, int, c_default_equals, c_default_hash32);
-using_cmap(x, uint64_t, uint64_t, c_default_equals, c_default_hash64);
-using_cmap_str();
+#define i_tag i
+#define i_key int
+#define i_val int
+#define i_hash c_default_hash32
+#include <stc/cmap.h>
+#define i_tag x
+#define i_key size_t
+#define i_val size_t
+#define i_hash c_default_hash64
+#include <stc/cmap.h>
+
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
PICOBENCH_SUITE("Map1");
diff --git a/benchmarks/shootout2_cmap.cpp b/benchmarks/shootout2_cmap.cpp
index 7c1595f3..669c336c 100644
--- a/benchmarks/shootout2_cmap.cpp
+++ b/benchmarks/shootout2_cmap.cpp
@@ -2,7 +2,6 @@
#include <time.h>
#include <stc/crandom.h>
#include <stc/cstr.h>
-#include <stc/cmap.h>
#include "others/khash.h"
#ifdef __cplusplus
@@ -18,7 +17,12 @@ template<typename C> inline void destroy_me(C& c) { C().swap(c); }
// Visual Studio: compile with -TP to force C++: cl -TP -EHsc -O2 benchmark.c
// cmap and khash template expansion
-using_cmap(ii, int64_t, int64_t, c_default_equals, c_default_hash64); // c_default_hash);
+#define i_tag ii
+#define i_key int64_t
+#define i_val int64_t
+#define i_cmp c_default_hash64
+#include <stc/cmap.h>
+
KHASH_MAP_INIT_INT64(ii, int64_t)
diff --git a/benchmarks/shootout3_csmap.cpp b/benchmarks/shootout3_csmap.cpp
index de14d4ba..6f124cd8 100644
--- a/benchmarks/shootout3_csmap.cpp
+++ b/benchmarks/shootout3_csmap.cpp
@@ -1,7 +1,6 @@
#include <iostream>
#include <stc/crandom.h>
#include <stc/cstr.h>
-#include <stc/csmap.h>
#include <cmath>
#include <string>
#include <map>
@@ -16,9 +15,19 @@ using omap_i = std::map<int, int>;
using omap_x = std::map<uint64_t, uint64_t>;
using omap_s = std::map<std::string, std::string>;
-using_csmap(i, int, int);
-using_csmap(x, uint64_t, uint64_t);
-using_csmap_str();
+#define i_tag i
+#define i_key int
+#define i_val int
+#include <stc/csmap.h>
+
+#define i_tag x
+#define i_key size_t
+#define i_val size_t
+#include <stc/csmap.h>
+
+#define i_key_str
+#define i_val_str
+#include <stc/csmap.h>
PICOBENCH_SUITE("Map1");
diff --git a/docs/carray_api.md b/docs/carray_api.md
index e8ca7ffc..71d27390 100644
--- a/docs/carray_api.md
+++ b/docs/carray_api.md
@@ -1,91 +1,90 @@
-# STC [carray](../include/stc/carray.h): Dynamic Multi-dimensional Array
+# STC [carr2, carr3](../include/stc/carray.h): Dynamic Multi-dimensional Arrays
![Array](pics/array.jpg)
-The **carray** containers provides templates for multidimensional arrays. It supports 2- and
-3-dimensional arrays, which are allocated from the heap as a single contiguous block of memory.
-The carrays can be used almost like regular constant size multi-dimensional arrays in C, and has
-the same property of storing data in one block of memory, which can be passed to any method.
+The **carr2** and **carr3** are templated 2D and 3D dynamic arrays. They are allocated on the heap as a single
+contiguous block of memory. The arrays can be indexed like regular constant size multi-dimensional arrays in C.
See the c++ class [boost::multi_array](https://www.boost.org/doc/libs/release/libs/multi_array) for similar functionality.
## Header file and declaration
```c
-#include <stc/carray.h>
+#define i_tag // defaults to i_val name
+#define i_val // value: REQUIRED
+#define i_valfrom // clone func i_val => i_val - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
-using_carray2(X, Value);
-using_carray2(X, Value, valueDel, valueClone);
-using_carray3(X, Value);
-using_carray3(X, Value, valueDel, valueClone);
+#include <stc/carr2.h> // or <stc/carr3.h>
```
-The macro `using_carray2()` must be instantiated in the global scope. `X` and `N` are type tags and
-will affect the names of all cset types and methods. E.g. declaring `using_carray3(i, int);`, `X` should
-be replaced by `i` in all of the following documentation.
+`X` should be replaced by the value of i_tag in all of the following documentation.
-```c
-#include <stc/carray.h>
-```
## Methods
+carr2_X:
```c
-carray2X carray2X_init(size_t xdim, size_t ydim);
-carray2X carray2X_with_values(size_t xdim, size_t ydim, Value val);
-carray2X carray2X_with_storage(size_t xdim, size_t ydim, Value* array);
-carray2X carray2X_clone(carray2X arr);
-Value* carray2X_release(carray2X* self); // release storage (not freed)
-void carray2X_del(carray2X* self);
-
-size_t carray2X_size(carray2X arr);
-Value* carray2X_data(carray2X* self); // access storage data
-Value* carray2X_at(carray2X* self, size_t x, size_t y);
-
-carray2X_iter_t carray2X_begin(const carray2X* self);
-carray2X_iter_t carray2X_end(const carray2X* self);
-void carray2X_next(carray2X_iter_t* it);
+carr2_X carr2_X_init(size_t xdim, size_t ydim);
+carr2_X carr2_X_with_values(size_t xdim, size_t ydim, Value val);
+carr2_X carr2_X_with_storage(size_t xdim, size_t ydim, Value* array);
+carr2_X carr2_X_clone(carr2_X arr);
+Value* carr2_X_release(carr2_X* self); // release storage (not freed)
+void carr2_X_del(carr2_X* self);
+
+size_t carr2_X_size(carr2_X arr);
+Value* carr2_X_data(carr2_X* self); // access storage data
+Value* carr2_X_at(carr2_X* self, size_t x, size_t y);
+
+carr2_X_iter_t carr2_X_begin(const carr2_X* self);
+carr2_X_iter_t carr2_X_end(const carr2_X* self);
+void carr2_X_next(carr2_X_iter_t* it);
```
+carr3:
```c
-carray3X carray3X_init(size_t xdim, size_t ydim, size_t zdim);
-carray3X carray3X_with_values(size_t xdim, size_t ydim, size_t zdim, Value val);
-carray3X carray3X_with_storage(size_t xdim, size_t ydim, size_t zdim, Value* array);
-carray3X carray3X_clone(carray3X arr);
-Value* carray3X_release(carray3X* self); // release storage (not freed)
-void carray3X_del(carray3X* self);
-
-size_t carray3X_size(carray3X arr);
-Value* carray3X_data(carray3X* self); // access storage data
-Value* carray3X_at(carray3X* self, size_t x, size_t y, size_t z);
-
-carray3X_iter_t carray3X_begin(const carray3X* self);
-carray3X_iter_t carray3X_end(const carray3X* self);
-void carray3X_next(carray3X_iter_t* it);
+carr3_X carr3_X_init(size_t xdim, size_t ydim, size_t zdim);
+carr3_X carr3_X_with_values(size_t xdim, size_t ydim, size_t zdim, Value val);
+carr3_X carr3_X_with_storage(size_t xdim, size_t ydim, size_t zdim, Value* array);
+carr3_X carr3_X_clone(carr3_X arr);
+Value* carr3_X_release(carr3_X* self); // release storage (not freed)
+void carr3_X_del(carr3_X* self);
+
+size_t carr3_X_size(carr3_X arr);
+Value* carr3_X_data(carr3_X* self); // access storage data
+Value* carr3_X_at(carr3_X* self, size_t x, size_t y, size_t z);
+
+carr3_X_iter_t carr3_X_begin(const carr3_X* self);
+carr3_X_iter_t carr3_X_end(const carr3_X* self);
+void carr3_X_next(carr3_X_iter_t* it);
```
## Types
-| Type name | Type definition | Used to represent... |
-|:---------------------|:-----------------------------------------------------|:--------------------------|
-| `carray2X` | `struct { Value **data; size_t xdim, ydim; }` | The carray2 type |
-| `carray2X_value_t` | `Value` | The value type |
-| `carray2X_iter_t` | `struct { Value *ref; }` | Iterator type |
-| `carray3X` | `struct { Value ***data; size_t xdim, ydim, zdim; }` | The carray3 type |
-| `carray3X_value_t` | `Value` | The value type |
-| `carray3X_iter_t` | `struct { Value *ref; }` | Iterator type |
+| Type name | Type definition | Used to represent... |
+|:------------------|:-----------------------------------------------------|:---------------------|
+| `carr2_X` | `struct { Value **data; size_t xdim, ydim; }` | The array 2D type |
+| `carr2_X_value_t` | `Value` | The value type |
+| `carr2_X_iter_t` | `struct { Value *ref; }` | Iterator type |
+| `carr3_X` | `struct { Value ***data; size_t xdim, ydim, zdim; }` | The array 3D type |
+| `carr3_X_value_t` | `Value` | The value type |
+| `carr3_X_iter_t` | `struct { Value *ref; }` | Iterator type |
-The **carray** elements can be accessed like `carray3i arr = ...; int val = arr.data[x][y][z];`, or with `carray3i_at(&arr, x, y, z)`.
+The **carr3** elements can be accessed like `carr3_i arr = ...; int val = arr.data[x][y][z];`, or with `carr3_i_at(&arr, x, y, z)`.
## Example
```c
#include <stdio.h>
-#include <stc/carray.h>
-using_carray3(f, float);
-using_carray2(i, uint32_t);
+#define i_tag i
+#define i_val uint32_t
+#include <stc/carr2.h>
+
+#define i_tag f
+#define i_val float
+#include <stc/carr3.h>
int main()
{
// Ex1
int xd = 30, yd = 20, zd = 10;
// define arr3[30][20][10], initialized with zeros.
- carray3f arr3 = carray3f_with_values(xd, yd, zd, 0.0f);
+ carr3_f arr3 = carr3_f_with_values(xd, yd, zd, 0.0f);
arr3.data[5][4][3] = 3.14f;
float *arr1 = arr3.data[5][4];
@@ -94,20 +93,20 @@ int main()
printf("%f\n", arr1[3]); // 3.14
printf("%f\n", arr2[4][3]); // 3.14
printf("%f\n", arr3.data[5][4][3]); // 3.14
- carray3f_del(&arr3); // free array
+ carr3_f_del(&arr3); // free array
// Ex2
int w = 256, h = 128;
- carray2i image = carray2i_init(w, h);
+ carr2_i image = carr2_i_init(w, h);
int n = 0;
- c_foreach (i, carray2i, image) {
+ c_foreach (i, carr2_i, image) {
uint32_t t = n++ % 256;
*i.ref = t | t << 8 | t << 16 | 255;
}
- for (int y=0; y<image.ydim; ++y)
+ for (int y = 0; y < image.ydim; ++y)
image.data[y][y] = 0xffffffff;
- carray2i_del(&image);
+ carr2_i_del(&image);
}
```
Output:
diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md
index 0eb11f82..dc274869 100644
--- a/docs/ccommon_api.md
+++ b/docs/ccommon_api.md
@@ -38,7 +38,9 @@ c_forauto (cstr, s1, s2)
printf("%s %s\n", s1.str, s2.str);
}
-using_cvec(i32, int32_t);
+#define i_tag i32
+#define i_val int32_t
+#include <stc/cvec.h>
...
cvec_i32 vec;
c_forscope (vec = cvec_i32_init(), cvec_i32_del(&vec))
@@ -59,9 +61,9 @@ c_fordefer (cstr_del(&s1), cstr_del(&s2))
```c
#include <errno.h>
#include <stc/cstr.h>
-#include <stc/cvec.h>
-using_cvec_str();
+#define i_val_str
+#include <stc/cvec.h>
// receiver should check errno variable
cvec_str readFile(const char* name)
@@ -91,9 +93,11 @@ int main()
| `c_foreach (it, ctype, it1, it2)` | Iterate the range [it1, it2) |
```c
-using_csset(x, int);
+#define i_tag x
+#define i_key int
+#include <stc/csset.h>
...
-c_var (csset_x, set, {23, 3, 7, 5, 12});
+c_emplace(csset_x, set, {23, 3, 7, 5, 12});
c_foreach (i, csset_x, set)
printf(" %d", *i.ref);
// 3 5 7 12 23
diff --git a/docs/cdeq_api.md b/docs/cdeq_api.md
index 83c0f19f..1ad754a1 100644
--- a/docs/cdeq_api.md
+++ b/docs/cdeq_api.md
@@ -8,23 +8,16 @@ See the c++ class [std::deque](https://en.cppreference.com/w/cpp/container/deque
## Header file and declaration
```c
+#define i_tag // defaults to i_val name
+#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_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
#include <stc/cdeq.h>
-
-using_cdeq(X, Value);
-using_cdeq(X, Value, valueCompare);
-using_cdeq(X, Value, valueCompare, valueDel, valueClone = c_no_clone);
-using_cdeq(X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue);
-
-using_cdeq_str();
-```
-The macro `using_cdeq()` must be instantiated in the global scope. `X` is a type tag name and
-will affect the names of all cdeq types and methods. E.g. declaring `using_cdeq(i, int);`, `X` should
-be replaced by `i` in all of the following documentation.
-
-`using_cdeq_str()` is a shorthand for:
-```
-using_cdeq(str, cstr, c_rawstr_compare, cstr_del, cstr_from, cstr_str, const char*)
```
+`X` should be replaced by the value of i_tag in all of the following documentation.
## Methods
@@ -100,10 +93,11 @@ cdeq_X_value_t cdeq_X_value_clone(cdeq_X_value_t val);
## Examples
```c
+#define i_tag i
+#define i_val int
#include <stc/cdeq.h>
-#include <stdio.h>
-using_cdeq(i, int);
+#include <stdio.h>
int main() {
cdeq_i q = cdeq_i_init();
diff --git a/docs/clist_api.md b/docs/clist_api.md
index b57662ca..3f866815 100644
--- a/docs/clist_api.md
+++ b/docs/clist_api.md
@@ -13,8 +13,8 @@ and *clist_X_sort()* which is **O**(*n* log(*n*)).
***Iterator invalidation***: Adding, removing and moving the elements within the list, or across several lists
will invalidate other iterators currently refering to these elements and their immediate succesive elements.
However, an iterator to a succesive element can both be dereferenced and advanced. After advancing, it is
-in a fully valid state. This implies that if `clist_X_insert(&L, clist_X_fwd(it,1), x)` and
-`clist_X_erase_at(&L, clist_X_fwd(it,1))` are used consistently, only iterators to erased elements are invalidated.
+in a fully valid state. This implies that if `clist_X_insert(&L, clist_X_advance(it,1), x)` and
+`clist_X_erase_at(&L, clist_X_advance(it,1))` are used consistently, only iterators to erased elements are invalidated.
See the c++ class [std::list](https://en.cppreference.com/w/cpp/container/list) for similar API and
[std::forward_list](https://en.cppreference.com/w/cpp/container/forward_list) for a functional description.
@@ -22,22 +22,18 @@ See the c++ class [std::list](https://en.cppreference.com/w/cpp/container/list)
## Header file and declaration
```c
+#define i_tag // defaults to i_val name
+#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_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
#include <stc/clist.h>
-
-using_clist(X, Value);
-using_clist(X, Value, valueCompare);
-using_clist(X, Value, valueCompare, valueDel, valueClone = c_no_clone);
-using_clist(X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue);
-
-using_clist_str()
-```
-The macro `using_clist()` must be instantiated in the global scope. `X` is a type tag name and
-will affect the names of all clist types and methods. E.g. declaring `using_clist(i, int);`, `X` should
-be replaced by `i` in all of the following documentation. `using_clist_str()` is a shorthand for
-```c
-using_clist(str, cstr, c_rawstr_compare, cstr_del, cstr_from, cstr_str, const char*)
```
+`X` should be replaced by the value of i_tag in all of the following documentation.
+
## Methods
```c
@@ -81,7 +77,7 @@ void clist_X_sort(clist_X* self);
clist_X_iter_t clist_X_begin(const clist_X* self);
clist_X_iter_t clist_X_end(const clist_X* self);
void clist_X_next(clist_X_iter_t* it);
-clist_X_iter_t clist_X_fwd(clist_X_iter it, size_t n); // return it n elements ahead. End allowed.
+clist_X_iter_t clist_X_advance(clist_X_iter it, size_t n); // return it n elements ahead. End allowed.
clist_X_rawvalue_t clist_X_value_toraw(clist_X_value_t* pval);
clist_X_value_t clist_X_value_clone(clist_X_value_t val);
@@ -100,11 +96,11 @@ clist_X_value_t clist_X_value_clone(clist_X_value_t val);
Interleave *push_front()* / *push_back()* then *sort()*:
```c
+#define i_tag d
+#define i_val double
#include <stc/clist.h>
#include <stdio.h>
-using_clist(d, double);
-
int main() {
c_var (clist_d, list, {
10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0
@@ -138,10 +134,11 @@ sorted: 1 2 3 4 5 6 7 8 9 10 20 30 40 50 60 70 80 90
Use of *erase_at()* and *erase_range()*:
```c
// erasing from clist
+#define i_tag i
+#define i_val int
#include <stc/clist.h>
-#include <stdio.h>
-using_clist(i, int);
+#include <stdio.h>
int main ()
{
@@ -171,22 +168,26 @@ mylist contains: 10 30
Splice `[30, 40]` from *L2* into *L1* before `3`:
```c
+#define i_tag i
+#define i_val int
#include <stc/clist.h>
-#include <stdio.h>
-using_clist(i, int);
+#include <stdio.h>
int main() {
- c_var (clist_i, L1, {1, 2, 3, 4, 5});
- c_var (clist_i, L2, {10, 20, 30, 40, 50});
+ c_forauto (clist_i, L1, L2)
+ {
+ c_emplace(clist_i, L1, {1, 2, 3, 4, 5});
+ c_emplace(clist_i, L2, {10, 20, 30, 40, 50});
- clist_i_iter_t i = clist_i_fwd(clist_i_begin(&L1), 2);
- clist_i_iter_t j1 = clist_i_fwd(clist_i_begin(&L2), 2), j2 = clist_i_fwd(j1, 2);
+ clist_i_iter_t i = clist_i_advance(clist_i_begin(&L1), 2);
+ clist_i_iter_t j1 = clist_i_advance(clist_i_begin(&L2), 2), j2 = clist_i_advance(j1, 2);
- clist_i_splice_range(&L1, i, &L2, j1, j2);
+ clist_i_splice_range(&L1, i, &L2, j1, j2);
- c_foreach (i, clist_i, L1) printf(" %d", *i.ref); puts("");
- c_foreach (i, clist_i, L2) printf(" %d", *i.ref); puts("");
+ c_foreach (i, clist_i, L1) printf(" %d", *i.ref); puts("");
+ c_foreach (i, clist_i, L2) printf(" %d", *i.ref); puts("");
+ }
}
```
Output:
diff --git a/docs/cmap_api.md b/docs/cmap_api.md
index 59afa5ab..f72ee280 100644
--- a/docs/cmap_api.md
+++ b/docs/cmap_api.md
@@ -17,31 +17,22 @@ See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/contain
## Header file and declaration
```c
+#define i_tag // defaults to i_key name
+#define i_key // key: REQUIRED
+#define i_val // value: REQUIRED
+#define i_equ // equality comparison two i_keyraw*. REQUIRED IF i_keyraw is non-integral type
+#define i_cmp // three-way compare two i_keyraw* : may be defined instead of i_equ
+#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_keydel // destroy key func - defaults to empty destruct
+#define i_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
#include <stc/cmap.h>
-
-using_cmap(X, Key, Mapped);
-using_cmap(X, Key, Mapped, keyEquals, keyHash);
-using_cmap(X, Key, Mapped, keyEquals, keyHash, mappedDel, mappedClone = c_no_clone);
-using_cmap(X, Key, Mapped, keyEquals, keyHash, mappedDel, mappedFromRaw, mappedToRaw, RawMapped);
-using_cmap(X, Key, Mapped, keyEqualsRaw, keyHashRaw, mappedDel, mappedFromRaw, mappedToRaw, RawMapped,
- keyDel, keyFromRaw, keyToRaw, RawKey);
-using_cmap_keydef(X, Key, Mapped, keyEquals, keyHash, keyDel, keyClone);
-using_cmap_keydef(X, Key, Mapped, keyEqualsRaw, keyHashRaw, keyDel, keyFromRaw, keyToRaw, RawKey);
-
-using_cmap_strkey(X, Mapped); // using_cmap(X, cstr, Mapped, ...)
-using_cmap_strkey(X, Mapped, mappedDel, mappedClone = c_no_clone);
-using_cmap_strkey(X, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped);
-
-using_cmap_strval(X, Key); // using_cmap(X, Key, cstr, ...)
-using_cmap_strval(X, Key, keyEquals, keyHash);
-using_cmap_strval(X, Key, keyEquals, keyHash, keyDel, keyClone = c_no_clone);
-using_cmap_strval(X, Key, keyEqualsRaw, keyHashRaw, keyDel, keyFromRaw, keyToRaw, RawKey);
-
-using_cmap_str() // using_cmap(str, cstr, cstr, ...)
```
-The `using_cmap()` macro family must be instantiated in the global scope. `X` is a type tag name and
-will affect the names of all cmap types and methods. E.g. declaring `using_cmap(ii, int, int);`, `X` should
-be replaced by `ii` in all of the following documentation. Argument `flag` is `c_true` by default.
+`X` should be replaced by the value of i_tag in all of the following documentation.
## Methods
@@ -87,12 +78,16 @@ cmap_X_value_t cmap_X_value_clone(cmap_X_value_t val);
cmap_X_rawvalue_t cmap_X_value_toraw(cmap_X_value_t* pval);
```
```c
+int c_rawstr_compare(const char* const* a, const char* const* b);
+bool c_rawstr_equals(const char* const* a, const char* const* b);
+uint64_t c_rawstr_hash(const char* const* strp, ...);
+
uint64_t c_default_hash(const void *data, size_t len); // key any trivial type
-uint64_t c_string_hash(const char* str); // uses c_default_hash()
-uint64_t c_default_hash32(const void* data, size_t); // key one 32bit int
-uint64_t c_default_hash64(const void* data, size_t); // key one 64bit int
+uint64_t c_default_hash32(const void* data, size_t is4); // key one 32bit int
+uint64_t c_default_hash64(const void* data, size_t is8); // key one 64bit int
int c_default_equals(const RawKey* a, const RawKey* b); // the == operator
int c_memcmp_equals(const RawKey* a, const RawKey* b); // uses memcmp
+
Type c_no_clone(Type val);
Type c_default_fromraw(Type val); // plain copy
Type c_default_toraw(Type* val);
@@ -116,10 +111,11 @@ void c_default_del(Type* val); // doe
## Examples
```c
-#include <stc/cmap.h>
#include <stc/cstr.h>
-using_cmap_str();
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
int main()
{
@@ -157,13 +153,14 @@ The HEX of color BLACK is:[#000000]
```
### Example 2
-This example uses a cmap with cstr as mapped value, by the `using_cmap_strval(id, int)` macro.
+This example uses a cmap with cstr as mapped value.
```c
-#include <stc/cmap.h>
#include <stc/cstr.h>
-/* cmap<int, cstr>: */
-using_cmap_strval(id, int);
+#define i_tag id
+#define i_key int
+#define i_val_str
+#include <stc/cmap.h>
int main()
{
@@ -197,13 +194,14 @@ Output:
### Example 3
Demonstrate cmap with plain-old-data key type Vec3i and int as mapped type: cmap<Vec3i, int>.
```c
-#include <stc/cmap.h>
#include <stdio.h>
-
typedef struct { int x, y, z; } Vec3i;
-using_cmap(vi, Vec3i, int, c_memcmp_equals, // bitwise equals
- c_default_hash); // bytewise hash
+#define i_tag vi
+#define i_key Vec3i
+#define i_val int
+#define i_cmp c_memcmp_equals // bitwise equals, uses c_default_hash
+#include <stc/cmap.h>
int main()
{
@@ -231,11 +229,13 @@ Output:
### Example 4
Inverse: demonstrate cmap with mapped POD type Vec3i: cmap<int, Vec3i>:
```c
-#include <stc/cmap.h>
#include <stdio.h>
-
typedef struct { int x, y, z; } Vec3i;
-using_cmap(iv, int, Vec3i);
+
+#define i_tag iv
+#define i_key int
+#define i_val Vec3i
+#include <stc/cmap.h>
int main()
{
@@ -262,7 +262,6 @@ Output:
### Example 5
Advanced 1: Key type is struct.
```c
-#include <stc/cmap.h>
#include <stc/cstr.h>
typedef struct {
@@ -282,7 +281,13 @@ static void Viking_del(Viking* v) {
c_del(cstr, &v->name, &v->country);
}
-using_cmap_keydef(vk, Viking, int, Viking_equals, Viking_hash, Viking_del, c_no_clone);
+#define i_tag vk
+#define i_key Viking
+#define i_val int
+#define i_equ Viking_equals
+#define i_hash Viking_hash
+#define i_keydel Viking_del
+#include <stc/cmap.h>
int main()
{
@@ -314,10 +319,10 @@ Harald of Iceland has 12 hp
```
### Example 6
-Advanced 2: In example 5 we needed to construct a lookup key which allocated strings, and then had to free it after. 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):
+Advanced 2: In example 5 we needed to construct a lookup key which allocated strings, and then had to free it after.
+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
-#include <stc/cmap.h>
#include <stc/cstr.h>
typedef struct {
@@ -329,47 +334,57 @@ static void Viking_del(Viking* v) {
c_del(cstr, &v->name, &v->country);
}
-// Define a "raw" type with equals, hash, fromraw, toraw functions:
+// Define a "raw" type that need no allocations,
+// and define equals, hash, fromraw, toraw functions:
typedef struct {
const char* name;
const char* country;
} RViking;
-static int RViking_equals(const RViking* r1, const RViking* r2) {
- return !strcmp(r1->name, r2->name) && !strcmp(r1->country, r2->country);
-}
+static int RViking_equals(const RViking* r1, const RViking* r2)
+ { return !strcmp(r1->name, r2->name) && !strcmp(r1->country, r2->country); }
-static uint32_t RViking_hash(const RViking* r, int ignored) {
- return c_string_hash(r->name) ^ (c_string_hash(r->country) >> 15);
-}
+static uint32_t RViking_hash(const RViking* r, int ignored)
+ { return c_rawstr_hash(&r->name) ^ (c_rawstr_hash(&r->country) >> 15); }
-static Viking Viking_fromR(RViking r) {return (Viking){cstr_from(r.name), cstr_from(r.country)};}
-static RViking Viking_toR(const Viking* v) {return (RViking){v->name.str, v->country.str};}
+static Viking Viking_fromR(RViking r)
+ { return (Viking){cstr_from(r.name), cstr_from(r.country)}; }
-using_cmap_keydef(vk, Viking, int, RViking_equals, RViking_hash, Viking_del,
- Viking_fromR, Viking_toR, RViking);
+static RViking Viking_toR(const Viking* v)
+ { return (RViking){v->name.str, v->country.str}; }
+
+#define i_tag vk
+#define i_key Viking
+#define i_val int
+#define i_equ RViking_equals
+#define i_hash RViking_hash
+#define i_keyraw RViking
+#define i_keyfrom Viking_fromR
+#define i_keyto Viking_toR
+#define i_keydel Viking_del
+#include <stc/cmap.h>
int main()
{
- // Use a HashMap to store the vikings' health points.
- cmap_vk vikings = cmap_vk_init();
-
- // insert works as before, takes a constructed Viking object
- cmap_vk_insert(&vikings, (Viking){cstr_from("Einar"), cstr_from("Norway")}, 25);
- cmap_vk_insert(&vikings, (Viking){cstr_from("Olaf"), cstr_from("Denmark")}, 24);
-
- // emplace is simple to use now.
- cmap_vk_emplace(&vikings, (RViking){"Harald", "Iceland"}, 12);
- cmap_vk_emplace(&vikings, (RViking){"Einar", "Denmark"}, 21);
-
- // And lookup uses "raw" key type, so no need construct/destruct key:
- printf("Lookup: Einar of Norway has %d hp\n\n", *cmap_vk_at(&vikings, (RViking){"Einar", "Norway"}));
-
- // Print the status of the vikings.
- c_foreach (i, cmap_vk, vikings) {
- printf("%s of %s has %d hp\n", i.ref->first.name.str, i.ref->first.country.str, i.ref->second);
+ c_forauto (cmap_vk, vikings) // RAII
+ {
+ // Insert works as before, takes a constructed Viking object
+ cmap_vk_insert(&vikings, (Viking){cstr_from("Einar"), cstr_from("Norway")}, 25);
+ cmap_vk_insert(&vikings, (Viking){cstr_from("Olaf"), cstr_from("Denmark")}, 24);
+
+ // But emplace is simpler to use now - takes raw key argument
+ cmap_vk_emplace(&vikings, (RViking){"Harald", "Iceland"}, 12);
+ cmap_vk_emplace(&vikings, (RViking){"Einar", "Denmark"}, 21);
+
+ // Lookup also uses raw key type, so no need construct/destruct key:
+ printf("Lookup: Einar of Norway has %d hp\n\n", *cmap_vk_at(&vikings, (RViking){"Einar", "Norway"}));
+
+ // Print the status of the vikings.
+ c_foreach (i, cmap_vk, vikings) {
+ printf("%s of %s has %d hp\n", i.ref->first.name.str,
+ i.ref->first.country.str, i.ref->second);
+ }
}
- cmap_vk_del(&vikings);
}
```
diff --git a/docs/cpque_api.md b/docs/cpque_api.md
index 441afc0a..343215bf 100644
--- a/docs/cpque_api.md
+++ b/docs/cpque_api.md
@@ -8,18 +8,16 @@ See the c++ class [std::priority_queue](https://en.cppreference.com/w/cpp/contai
## Header file and declaration
```c
+#define i_tag // defaults to i_val name
+#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_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
#include <stc/cpque.h>
-
-using_cpque(X, ctype); // uses valueCompare from ctype
-using_cpque(X, ctype, valueCompare);
```
-The macro `using_cpque()` must be instantiated in the global scope. **cpque** uses normally **cvec_X**
-or **cdeq_X** as underlying implementation, specified as `ctype`. The *valueCompare* can be specified
-to control the order in the priority queue.
-
-By default, the function *`ctype`_value_compare(x, y)* from the underlying vector type is used for
-comparing values (priorities). `X` is a type tag name and will affect the names of all cpque types and methods.
-When declaring `using_cpque(i, cvec_i)`, `X` should be replaced by `i` in the following documentation.
+`X` should be replaced by the value of i_tag in all of the following documentation.
## Methods
@@ -55,12 +53,13 @@ cpque_X_value_t cpque_X_value_clone(cpque_X_value_t val);
## Example
```c
-#include <stc/cpque.h>
#include <stc/crandom.h>
#include <stdio.h>
-using_cvec(i, int64_t);
-using_cpque(i, cvec_i, -c_default_compare); // min-heap
+#define i_tag i
+#define i_val int64_t
+#define i_cmp -c_default_compare // min-heap
+#include <stc/cpque.h>
int main()
{
@@ -69,7 +68,7 @@ int main()
stc64_uniform_t dist = stc64_uniform_init(0, N * 10);
// Declare heap, with defered del()
- c_forvar (cpque_i heap = cpque_i_init(), cpque_i_del(&heap))
+ c_forauto (cpque_i, heap)
{
// Push ten million random numbers to priority queue, plus some negative ones.
c_forrange (N)
diff --git a/docs/cqueue_api.md b/docs/cqueue_api.md
index 8bd9f15e..16e87d47 100644
--- a/docs/cqueue_api.md
+++ b/docs/cqueue_api.md
@@ -1,20 +1,23 @@
# STC [cqueue](../include/stc/cqueue.h): Queue
![Queue](pics/queue.jpg)
-The **cqueue** is container adapter that gives the programmer the functionality of a queue - specifically, a FIFO (first-in, first-out) data structure. The class template acts as a wrapper to the underlying container - only a specific set of functions is provided. The queue pushes the elements on the back of the underlying container and pops them from the front.
+The **cqueue** is container that gives the programmer the functionality of a queue - specifically, a FIFO (first-in, first-out) data structure. The queue pushes the elements on the back of the underlying container and pops them from the front.
See the c++ class [std::queue](https://en.cppreference.com/w/cpp/container/queue) for a functional reference.
## Header file and declaration
```c
-#include <stc/cqueue.h> /* includes default underlying implementation header cdeq.h */
-
-using_cqueue(X, ctype)
+#define i_tag // defaults to i_val name
+#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_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
+#include <stc/cqueue.h>
```
-The macro `using_cqueue()` must be instantiated in the global scope. **cqueue** uses normally
-a **cdeq_X** or **clist_X** type as underlying implementation, given as `ctype`. See example below for usage.
-`X` is a type tag name and will affect the names of all cqueue types and methods. E.g. declaring
-`using_cqueue(i, clist_i)`, `X` should be replaced by `i` in all of the following documentation.
+`X` should be replaced by the value of i_tag in all of the following documentation.
+
## Methods
@@ -54,42 +57,12 @@ cqueue_X_value_t cqueue_X_value_clone(cqueue_X_value_t val);
## Examples
```c
+#define i_tag i
+#define i_val int
#include <stc/cqueue.h>
-#include <stdio.h>
-
-using_cdeq(i, int);
-using_cqueue(i, cdeq_i);
-
-int main() {
- cqueue_i Q = cqueue_i_init();
-
- // push() and pop() a few.
- c_forrange (i, 20)
- cqueue_i_push(&Q, i);
-
- c_forrange (5)
- cqueue_i_pop(&Q);
-
- c_foreach (i, cqueue_i, Q)
- printf(" %d", *i.ref);
- cqueue_i_del(&Q);
-}
-```
-Output:
-```
-5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
-```
-### Example 2
-Use clist as underlying cqueue implementation.
-```c
-#include <stc/cqueue.h>
-#include <stc/clist.h>
#include <stdio.h>
-using_clist(i, int);
-using_cqueue(i, clist_i);
-
int main() {
cqueue_i Q = cqueue_i_init();
diff --git a/docs/crandom_api.md b/docs/crandom_api.md
index 4093204e..6398e197 100644
--- a/docs/crandom_api.md
+++ b/docs/crandom_api.md
@@ -69,15 +69,15 @@ double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist);
## Example
```c
-#include <stdio.h>
#include <time.h>
-
#include <stc/crandom.h>
-#include <stc/csmap.h>
#include <stc/cstr.h>
// Declare int -> int sorted map. Uses typetag 'i' for ints.
-using_csmap(i, int, size_t);
+#define i_tag i
+#define i_key int
+#define i_val size_t
+#include <stc/csmap.h>
int main()
{
@@ -95,7 +95,7 @@ int main()
csmap_i mhist = csmap_i_init();
c_forrange (N) {
int index = (int) round( stc64_normalf(&rng, &dist) );
- ++ csmap_i_emplace(&mhist, index, 0).ref->second;
+ csmap_i_emplace(&mhist, index, 0).ref->second += 1;
}
// Print the gaussian bar chart
diff --git a/docs/cset_api.md b/docs/cset_api.md
index dc628750..8b645d29 100644
--- a/docs/cset_api.md
+++ b/docs/cset_api.md
@@ -7,18 +7,18 @@ A **cset** is an associative container that contains a set of unique objects of
## Header file and declaration
```c
+#define i_tag // defaults to i_key name
+#define i_key // key: REQUIRED
+#define i_hash // hash func: REQUIRED IF i_keyraw is a non-pod type
+#define i_equ // equality comparison two i_keyraw*. REQUIRED IF i_keyraw is a non-integral type
+#define i_cmp // three-way compare two i_keyraw* : alternative to i_equ
+#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_keydel // destroy key func - defaults to empty destruct
#include <stc/cset.h>
-
-using_cset(X, Key);
-using_cset(X, Key, keyEquals, keyHash);
-using_cset(X, Key, keyEquals, keyHash, keyDel, keyClone = c_no_clone);
-using_cset(X, Key, keyEqualsRaw, keyHashRaw, keyDel, keyFromRaw, keyToRaw, RawKey, flag);
-
-using_cset_str(); // using_cset(str, cstr, c_rawstr_equals, c_rawstr_hash, cstr_del, ...)
```
-The macro `using_cset()` must be instantiated in the global scope. `X` is a type tag name and
-will affect the names of all cset types and methods. E.g. declaring `using_cset(i, int);`, `X` should
-be replaced by `i` in all of the following documentation.
+`X` should be replaced by the value of i_tag in all of the following documentation.
## Methods
@@ -72,10 +72,10 @@ cset_X_value_t cset_X_value_clone(cset_X_value_t val);
## Example
```c
-#include <stc/cset.h>
#include <stc/cstr.h>
-using_cset_str();
+#define i_key_str
+#include <stc/cset.h>
int main ()
{
diff --git a/docs/csmap_api.md b/docs/csmap_api.md
index dba4fecd..143da587 100644
--- a/docs/csmap_api.md
+++ b/docs/csmap_api.md
@@ -15,31 +15,21 @@ See the c++ class [std::map](https://en.cppreference.com/w/cpp/container/map) fo
## Header file and declaration
```c
+#define i_tag // defaults to i_key name
+#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_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_keydel // destroy key func - defaults to empty destruct
+#define i_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
#include <stc/csmap.h>
-
-using_csmap(X, Key, Mapped);
-using_csmap(X, Key, Mapped, keyCompare);
-using_csmap(X, Key, Mapped, keyCompare, mappedDel, mappedClone = c_no_clone);
-using_csmap(X, Key, Mapped, keyCompare, mappedDel, mappedFromRaw, mappedToRaw, RawMapped);
-using_csmap(X, Key, Mapped, keyCompareRaw, mappedDel, mappedFromRaw, mappedToRaw, RawMapped,
- keyDel, keyFromRaw, keyToRaw, RawKey, flag);
-using_csmap_keydef(X, Key, Mapped, keyCompare, keyDel, keyClone);
-using_csmap_keydef(X, Key, Mapped, keyCompareRaw, keyDel, keyFromRaw, keyToRaw, RawKey, flag);
-
-using_csmap_strkey(X, Mapped); // using_csmap(X, cstr, Mapped, ...)
-using_csmap_strkey(X, Mapped, mappedDel, mappedClone);
-using_csmap_strkey(X, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped, flag);
-
-using_csmap_strval(X, Key); // using_csmap(X, Key, cstr, ...)
-using_csmap_strval(X, Key, keyCompare);
-using_csmap_strval(X, Key, keyCompare, keyDel, keyClone);
-using_csmap_strval(X, Key, keyCompareRaw, keyDel, keyFromRaw, keyToRaw, RawKey, flag);
-
-using_csmap_str(); // using_csmap(str, cstr, cstr, ...)
```
-The `using_csmap()` macro family must be instantiated in the global scope. `X` is a type tag name and
-will affect the names of all csmap types and methods. E.g. declaring `using_csmap(ii, int, int);`, `X` should
-be replaced by `ii` in all of the following documentation. Argument `flag` is `c_true` by default.
+`X` should be replaced by the value of i_tag in all of the following documentation.
## Methods
@@ -76,7 +66,7 @@ csmap_X_iter_t csmap_X_erase_range(csmap_X* self, csmap_X_iter_t it1, csmap
csmap_X_iter_t csmap_X_begin(const csmap_X* self);
csmap_X_iter_t csmap_X_end(const csmap_X* self);
void csmap_X_next(csmap_X_iter_t* iter);
-csmap_X_iter_t csmap_X_fwd(csmap_X_iter_t it, size_t n);
+csmap_X_iter_t csmap_X_advance(csmap_X_iter_t it, size_t n);
csmap_X_value_t csmap_X_value_clone(csmap_X_value_t val);
csmap_X_rawvalue_t csmap_X_value_toraw(csmap_X_value_t* pval);
@@ -97,10 +87,10 @@ csmap_X_rawvalue_t csmap_X_value_toraw(csmap_X_value_t* pval);
## Examples
```c
-#include <stc/csmap.h>
#include <stc/cstr.h>
-using_csmap_str();
+#define i_key_str
+#include <stc/csmap.h>
int main()
{
@@ -137,13 +127,14 @@ The HEX of color BLACK is:[#000000]
```
### Example 2
-This example uses a csmap with cstr as mapped value, by the `using_csmap_strval(id, int)` macro.
+This example uses a csmap with cstr as mapped value.
```c
-#include <stc/csmap.h>
#include <stc/cstr.h>
-/* csmap<int, cstr>: */
-using_csmap_strval(id, int);
+#define i_tag id
+#define i_key int
+#define i_val_str
+#include <stc/csmap.h>
int main()
{
@@ -176,9 +167,6 @@ Output:
### Example 3
Demonstrate csmap with plain-old-data key type Vec3i and int as mapped type: csmap<Vec3i, int>.
```c
-#include <stc/csmap.h>
-#include <stdio.h>
-
typedef struct { int x, y, z; } Vec3i;
static int Vec3i_compare(const Vec3i* a, const Vec3i* b) {
@@ -188,7 +176,12 @@ static int Vec3i_compare(const Vec3i* a, const Vec3i* b) {
return (a->z > b->z) - (a->z < b->z);
}
-using_csmap(vi, Vec3i, int, Vec3i_compare);
+#define i_tag vi
+#define i_key Vec3i
+#define i_val int
+#define i_cmp Vec3i_compare // uses c_default_hash
+#include <stc/csmap.h>
+#include <stdio.h>
int main()
{
@@ -215,12 +208,14 @@ Output:
### Example 4
Inverse: demonstrate csmap with mapped POD type Vec3i: csmap<int, Vec3i>:
```c
+typedef struct { int x, y, z; } Vec3i;
+
+#define i_tag iv
+#define i_key int
+#define i_val Vec3i
#include <stc/csmap.h>
#include <stdio.h>
-typedef struct { int x, y, z; } Vec3i;
-using_csmap(iv, int, Vec3i);
-
int main()
{
c_forvar (csmap_iv vecs = csmap_iv_init(), csmap_iv_del(&vecs))
diff --git a/docs/csptr_api.md b/docs/csptr_api.md
index 10d3bb77..afef2154 100644
--- a/docs/csptr_api.md
+++ b/docs/csptr_api.md
@@ -21,13 +21,13 @@ See the c++ classes [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/s
## Header file and declaration
```c
+#define i_tag // defaults to i_val name
+#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_valdel // destroy value func - defaults to empty destruct
#include <stc/csptr.h>
-
-using_csptr(X, Value);
-using_csptr(X, Value, valueCompare);
-using_csptr(X, Value, valueCompare, valueDel);
```
-The macro `using_csptr()` must be instantiated in the global scope. `X` is a type tag name and will affect the names of all csptr types and methods. E.g. declaring `using_csptr(v4, Vec4)`, `X` should be replaced by `v4` in all of the following documentation.
+`X` should be replaced by the value of i_tag in all of the following documentation.
## Methods
@@ -66,29 +66,31 @@ bool csptr_X_equals(const csptr_X* x, const csptr_X* y);
## Example
```c
-#include <stc/csptr.h>
#include <stc/cstr.h>
-typedef struct { cstr name, last; } Person;
+typedef struct { cstr name, surname; } Person;
-Person Person_init(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+Person Person_init(const char* name, const char* surname) {
+ return (Person){.name = cstr_from(name), .surname = cstr_from(surname)};
}
void Person_del(Person* p) {
- printf("Destroy: %s %s\n", p->name.str, p->last.str);
- c_del(cstr, &p->name, &p->last);
+ printf("Person_del: %s %s\n", p->name.str, p->surname.str);
+ c_del(cstr, &p->name, &p->surname);
}
-using_csptr(person, Person, c_no_compare, Person_del);
+#define i_val Person
+#define i_cmp c_no_compare
+#define i_valdel Person_del
+#include <stc/csptr.h>
int main() {
csptr_person p = csptr_person_make(Person_init("John", "Smiths"));
csptr_person q = csptr_person_clone(p); // means: share the pointer
- printf("Person: %s %s. uses: %zu\n", p.get->name.str, p.get->last.str, *p.use_count);
+ printf("Person: %s %s. uses: %zu\n", p.get->name.str, p.get->surname.str, *p.use_count);
csptr_person_del(&p);
- printf("Last man standing: %s %s. uses: %zu\n", q.get->name.str, q.get->last.str, *q.use_count);
+ printf("Last man standing: %s %s. uses: %zu\n", q.get->name.str, q.get->surname.str, *q.use_count);
csptr_person_del(&q);
}
```
@@ -96,38 +98,37 @@ Output:
```
Person: John Smiths. uses: 2
Last man standing: John Smiths. uses: 1
-Destroy: John Smiths
+Person_del: John Smiths
```
### Example 2
-Advanced: Two different ways to store Person in vectors: 1) `cvec<Person>`, 2) `cvec< csptr<Person> >`.
+Vector of shared pointers to Person:
```c
-#include <stc/csptr.h>
#include <stc/cstr.h>
-#include <stc/cvec.h>
-typedef struct { cstr name, last; } Person;
+typedef struct { cstr name, surname; } Person;
-Person* Person_make(Person* p, const char* name, const char* last) {
- p->name = cstr_from(name), p->last = cstr_from(last);
- return p;
-}
-int Person_compare(const Person* p, const Person* q) {
- int cmp = strcmp(p->name.str, q->name.str);
- return cmp == 0 ? strcmp(p->last.str, q->last.str) : cmp;
+Person Person_init(const char* name, const char* surname) {
+ return (Person){.name = cstr_from(name), .surname = cstr_from(surname)};
}
void Person_del(Person* p) {
- printf("del: %s\n", p->name.str);
- c_del(cstr, &p->name, &p->last);
+ printf("Person_del: %s %s\n", p->name.str, p->surname.str);
+ c_del(cstr, &p->name, &p->surname);
+}
+int Person_compare(const Person* p, const Person* q) {
+ int cmp = strcmp(p->surname.str, q->surname.str);
+ return cmp == 0 ? strcmp(p->name.str, q->name.str) : cmp;
}
-// 1. cvec of Person struct; emplace and cloning disabled.
-using_cvec(pe, Person, Person_compare, Person_del, c_no_clone);
+#define i_tag pers
+#define i_val Person
+#define i_cmp Person_compare
+#define i_valdel Person_del
+#include <stc/csptr.h>
-// 2. cvec of shared-ptr to Person - with emplace_back() and cloning cvec ENABLED.
-using_csptr(pe, Person, Person_compare, Person_del);
-using_cvec(ps, csptr_pe, csptr_pe_compare, csptr_pe_del, csptr_pe_clone);
+#define i_val_csptr pers // shorthand: derives other i_xxx defines from this. i_tag may be defined.
+#include <stc/cvec.h>
const char* names[] = {
"Joe", "Jordan",
@@ -136,60 +137,43 @@ const char* names[] = {
};
int main() {
- cvec_pe vec1 = cvec_pe_init();
- cvec_ps vec2 = cvec_ps_init();
+ cvec_pers vec = cvec_pers_init();
- for (int i = 0; i < 6; i += 2) {
- Person tmp;
- cvec_pe_push_back(&vec1, *Person_make(&tmp, names[i], names[i+1]));
- cvec_ps_push_back(&vec2, csptr_pe_from(Person_make(c_new(Person), names[i], names[i+1])));
+ for (int i = 0; i < c_arraylen(names); i += 2) {
+ cvec_pers_push_back(&vec, csptr_pers_make(Person_init(names[i], names[i+1])));
}
- puts("1. Sorted vec1 of Person:");
- cvec_pe_sort(&vec1);
- c_foreach (i, cvec_pe, vec1)
- printf(" %s %s\n", i.ref->name.str, i.ref->last.str);
-
- // Append a shared copy of vec2.data[0]. Will only be destructed once!
- cvec_ps_emplace_back(&vec2, vec2.data[0]); // emplace will internally call csptr_ps_clone()!
- puts("\n2. Sorted vec2 of shared-pointer to Person:");
- cvec_ps_sort(&vec2);
- c_foreach (i, cvec_ps, vec2)
- printf(" %s %s\n", i.ref->get->name.str, i.ref->get->last.str);
-
- // Share vec2.data[1] with elem1 variable.
- csptr_pe elem1 = csptr_pe_clone(vec2.data[1]);
-
- puts("\nDestroy vec1:");
- cvec_pe_del(&vec1);
- puts("\nDestroy vec2:");
- cvec_ps_del(&vec2);
+
+ // Append a shared copy of vec.data[0]. Will only be destructed once!
+ cvec_pers_emplace_back(&vec, vec.data[0]); // will internally call csptr_pers_clone()!
+
+ puts("\nSorted vec of shared-pointer to Person:");
+ cvec_pers_sort(&vec);
+
+ c_foreach (i, cvec_pers, vec)
+ printf(" %s, %s\n", i.ref->get->surname.str, i.ref->get->name.str);
+
+ // Share vec.data[1] with elem1 variable.
+ csptr_pers elem1 = csptr_pers_clone(vec.data[1]);
+
+ puts("\nDestroy vec:");
+ cvec_pers_del(&vec);
puts("\nDestroy elem1:");
- csptr_pe_del(&elem1);
+ csptr_pers_del(&elem1);
}
```
Output:
```
-1. Sorted vec1 of Person:
- Annie Aniston
- Jane Jacobs
- Joe Jordan
-
-2. Sorted vec2 of shared-pointer to Person:
- Annie Aniston
- Jane Jacobs
- Joe Jordan
- Joe Jordan
-
-Destroy vec1:
-del: Annie
-del: Jane
-del: Joe
-
-Destroy vec2:
-del: Annie
-del: Joe
+Sorted vec of shared-pointer to Person:
+ Aniston, Annie
+ Jacobs, Jane
+ Jordan, Joe
+ Jordan, Joe
+
+Destroy vec:
+Person_del: Annie Aniston
+Person_del: Joe Jordan
Destroy elem1:
-del: Jane
+Person_del: Jane Jacobs
```
diff --git a/docs/csset_api.md b/docs/csset_api.md
index d308fefd..0fdb8086 100644
--- a/docs/csset_api.md
+++ b/docs/csset_api.md
@@ -8,18 +8,16 @@ See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) fo
## Header file and declaration
```c
+#define i_tag // defaults to i_key name
+#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_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_keydel // destroy key func - defaults to empty destruct
#include <stc/csset.h>
-
-using_csset(X, Key);
-using_csset(X, Key, keyCompare);
-using_csset(X, Key, keyCompare, keyDel, keyClone = c_no_clone);
-using_csset(X, Key, keyCompareRaw, keyDel, keyFromRaw, keyToRaw, RawKey, flag);
-
-using_csset_str(); // using_csset(str, cstr, cstr_del, cstr_from, cstr_str, const char*, c_true)
```
-The macro `using_csset()` must be instantiated in the global scope. `X` is a type tag name and
-will affect the names of all csset types and methods. E.g. declaring `using_csset(i, int);`, `X` should
-be replaced by `i` in all of the following documentation.
+`X` should be replaced by the value of i_tag in all of the following documentation.
## Methods
@@ -69,10 +67,10 @@ csset_X_value_t csset_X_value_clone(csset_X_value_t val);
## Example
```c
-#include <stc/csset.h>
#include <stc/cstr.h>
-using_csset_str();
+#define i_key_str
+#include <stc/csset.h>
int main ()
{
diff --git a/docs/cstack_api.md b/docs/cstack_api.md
index 3d9ecd4f..68f22b57 100644
--- a/docs/cstack_api.md
+++ b/docs/cstack_api.md
@@ -1,21 +1,23 @@
# STC [cstack](../include/stc/cstack.h): Stack
![Stack](pics/stack.jpg)
-The **cstack** is a container adapter that gives the programmer the functionality of a stack - specifically, a LIFO (last-in, first-out) data structure. The class template acts as a wrapper to the underlying container - only a specific set of functions is provided. The stack pushes and pops the element from the back of the underlying container, known as the top of the stack.
+The **cstack** is a container that gives the programmer the functionality of a stack - specifically, a LIFO (last-in, first-out) data structure. The stack pushes and pops the element from the back of the underlying container, known as the top of the stack.
-See the c++ class [std::stack](https://en.cppreference.com/w/cpp/container/stack) for a functional description.
+See the c++ class [std::stack](https://en.cppreference.com/w/cpp/container/stack) for a functional description.
## Header file and declaration
```c
-#include <stc/cstack.h> /* includes default underlying implementation header cvec.h */
-
-using_cstack(X, ctype)
+#define i_tag // defaults to i_val name
+#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_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
+#include <stc/cstack.h>
```
-The macro `using_cstack()` must be instantiated in the global scope. **cstack** uses normally
-a **cvec_X** or **cdeq_X** type as underlying implementation, given as `ctype`. `X` is a type tag name and will
-affect the names of all cstack types and methods. E.g. declaring `using_cstack(i, cvec_i);`,
-`X` should be replaced by `i` in all of the following documentation.
+`X` should be replaced by the value of i_tag in all of the following documentation.
## Methods
@@ -54,12 +56,11 @@ cstack_X_value_t cstack_X_value_clone(cstack_X_value_t val);
## Example
```c
+#define i_tag i
+#define i_val int
#include <stc/cstack.h>
#include <stdio.h>
-using_cvec(i, int);
-using_cstack(i, cvec_i);
-
int main() {
cstack_i S = cstack_i_init();
diff --git a/docs/cstr_api.md b/docs/cstr_api.md
index fd2b241f..b922092d 100644
--- a/docs/cstr_api.md
+++ b/docs/cstr_api.md
@@ -68,12 +68,6 @@ bool cstr_contains(cstr s, const char* needle);
bool cstr_starts_with(cstr s, const char* str);
bool cstr_ends_with(cstr s, const char* str);
-bool cstr_iequalto(cstr s, const char* str); // prefix i = case-insensitive
-size_t cstr_ifind_n(cstr s, const char* needle, size_t pos, size_t nmax);
-bool cstr_icontains(cstr s, const char* needle);
-bool cstr_istarts_with(cstr s, const char* str);
-bool cstr_iends_with(cstr s, const char* str);
-
void cstr_push_back(cstr* self, char ch);
void cstr_pop_back(cstr* self);
char* cstr_front(cstr* self);
@@ -99,9 +93,8 @@ int c_rawstr_compare(const char** x, const char** y);
bool c_rawstr_equals(const char** x, const char** y);
uint64_t c_rawstr_hash(const char* const* x, ...);
-int c_strncasecmp(const char* str1, const char* str2, size_t n);
char* c_strnstrn(const char* str, const char* needle, size_t slen, size_t nlen);
-char* c_strncasestrn(const char* str, const char* needle, size_t slen, size_t nlen);
+int c_strncasecmp(const char* str1, const char* str2, size_t n);
```
## Types
diff --git a/docs/csview_api.md b/docs/csview_api.md
index dfca37c5..905a6489 100644
--- a/docs/csview_api.md
+++ b/docs/csview_api.md
@@ -7,7 +7,7 @@ element of the sequence at position zero. The implementation holds two members:
**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. `using_cmap_strvkey()` may perform better than `using_cmap_strkey()`.
+containers with cstr keys.
Note: a **csview** may ***not be null-terminated***, and must therefore be printed like:
`printf("%.*s", csview_ARG(sv))`.
@@ -98,23 +98,6 @@ uint64_t csview_hash(const csview* x, ...);
| `csview_npos` | same as `cstr_npos` | |
| `csview_ARG(sv)` | printf argument | `printf("%.*s", csview_ARG(sv));` |
-## Associative cstr-containers with csview emplace/lookup API
-```
-using_csmap_strvkey(X, Mapped)
-using_csmap_strvkey(X, Mapped, mappedDel)
-using_csmap_strvkey(X, Mapped, mappedDel, mappedClone)
-using_csmap_strvkey(X, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped)
-using_csmap_strv()
-using_csset_strv()
-
-using_cmap_strvkey(X, Mapped)
-using_cmap_strvkey(X, Mapped, mappedDel)
-using_cmap_strvkey(X, Mapped, mappedDel, mappedClone)
-using_cmap_strvkey(X, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped)
-using_cmap_strv()
-using_cset_strv()
-```
-
## Example
```c
#include <stc/csview.h>
@@ -149,7 +132,6 @@ Splits strings into tokens. *print_split()* makes **no** memory allocations or *
and does not depend on null-terminated strings. *string_split()* function returns a vector of cstr.
```c
#include <stc/csview.h>
-#include <stc/cvec.h>
void print_split(csview str, csview sep)
{
@@ -162,7 +144,8 @@ void print_split(csview str, csview sep)
}
}
-using_cvec_str();
+#define i_val_str
+#include <stc/cvec.h>
cvec_str string_split(csview str, csview sep)
{
@@ -204,36 +187,4 @@ Output:
"string"
"now"
""
-```
-### Example 3
-cmap cstr => int with csview as convertion type
-```c
-#include <stc/csview.h>
-#include <stc/cvec.h>
-#include <stc/cmap.h>
-using_cmap_strvkey(si, int);
-
-int main()
-{
- csview text = c_sv("The length of this literal is evaluated at compile time and stored in csview text.");
- csview suffix = csview_substr(text, -12, cstr_npos); // from pos -12 to end
- printf("%.*s\n", csview_ARG(suffix));
-
- c_forauto (cmap_si, map)
- {
- cmap_si_emplace(&map, c_sv("hello"), 100);
- cmap_si_emplace(&map, c_sv("world"), 200);
- cmap_si_emplace(&map, c_sv("hello"), 300); // already in map, ignored
-
- // Efficient lookup: no string allocation or strlen() takes place:
- cmap_si_value_t* val = cmap_si_get(&map, c_sv("hello"));
- printf("%s: %d\n", val->first.str, val->second);
- }
-}
-```
-Output:
-```
-csview text.
-hello: 100
-```
diff --git a/docs/cvec_api.md b/docs/cvec_api.md
index 5a98b9ca..07164e46 100644
--- a/docs/cvec_api.md
+++ b/docs/cvec_api.md
@@ -12,23 +12,16 @@ See the c++ class [std::vector](https://en.cppreference.com/w/cpp/container/vect
## Header file and declaration
```c
+#define i_tag // defaults to i_val name
+#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_valraw // convertion "raw" type - defaults to i_val
+#define i_valfrom // convertion func i_valraw => i_val - defaults to plain copy
+#define i_valto // convertion func i_val* => i_valraw - defaults to plain copy
+#define i_valdel // destroy value func - defaults to empty destruct
#include <stc/cvec.h>
-
-using_cvec(X, Value);
-using_cvec(X, Value, valueCompare);
-using_cvec(X, Value, valueCompare, valueDel, valueClone = c_no_clone);
-using_cvec(X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue);
-
-using_cvec_str(); // using_cvec(str, cstr, ...)
-```
-The macro `using_cvec()` must be instantiated in the global scope. `X` is a type tag name and
-will affect the names of all cvec types and methods. E.g. declaring `using_cvec(i, int);`, `X` should
-be replaced by `i` in all of the following documentation.
-
-`using_cvec_str()` is a shorthand for:
-```
-using_cvec(str, cstr, c_rawstr_compare, cstr_del, cstr_from, cstr_str, const char*)
```
+`X` should be replaced by the value of i_tag in all of the following documentation.
## Methods
@@ -103,11 +96,11 @@ cvec_X_value_t cvec_X_value_clone(cvec_X_value_t val);
## Examples
```c
+#define i_tag i
+#define i_val int
#include <stc/cvec.h>
#include <stdio.h>
-using_cvec(i, int);
-
int main()
{
// Create a vector containing integers
@@ -143,10 +136,10 @@ sorted: 5 7 8 13 16 25
```
### Example 2
```c
-#include <stc/cvec.h>
#include <stc/cstr.h>
-using_cvec_str();
+#define i_val_str
+#include <stc/cvec.h>
int main() {
cvec_str names = cvec_str_init();
@@ -178,7 +171,6 @@ item: 2 elements so far
Container with elements of structs:
```c
#include <stc/cstr.h>
-#include <stc/cvec.h>
typedef struct {
cstr name; // dynamic string
@@ -198,7 +190,12 @@ User User_clone(User user) {
}
// declare a memory managed, clonable vector of users:
-using_cvec(u, User, User_compare, User_del, User_clone);
+#define i_tag u
+#define i_val User
+#define i_cmp User_compare
+#define i_valdel User_del
+#define i_valfrom User_clone
+#include <stc/cvec.h>
int main(void) {
cvec_u vec = cvec_u_init();
diff --git a/examples/advanced.c b/examples/advanced.c
index 69060242..8044594e 100644
--- a/examples/advanced.c
+++ b/examples/advanced.c
@@ -1,5 +1,4 @@
#include <stdio.h>
-#include <stc/cmap.h>
#include <stc/cstr.h>
typedef struct Viking {
@@ -20,7 +19,7 @@ typedef struct VikingRaw {
} VikingRaw;
uint64_t vikingraw_hash(const VikingRaw* raw, size_t ignore) {
- uint64_t hash = c_string_hash(raw->name) ^ (c_string_hash(raw->country) >> 15);
+ uint64_t hash = c_rawstr_hash(&raw->name) ^ (c_rawstr_hash(&raw->country) >> 15);
return hash;
}
static inline int vikingraw_equals(const VikingRaw* rx, const VikingRaw* ry) {
@@ -34,10 +33,17 @@ static inline VikingRaw viking_toRaw(const Viking* vk) {
return c_make(VikingRaw){vk->name.str, vk->country.str};
}
-// With this in place, we use the using_cmap_keydef() macro to define {Viking -> int} hash map type:
-
-using_cmap_keydef(vk, Viking, int, vikingraw_equals, vikingraw_hash,
- viking_del, viking_fromRaw, viking_toRaw, VikingRaw, c_true);
+// With this in place, we define the Viking => int hash map type:
+#define i_tag vk
+#define i_key Viking
+#define i_val int
+#define i_equ vikingraw_equals
+#define i_hash vikingraw_hash
+#define i_keyraw VikingRaw
+#define i_keyfrom viking_fromRaw
+#define i_keyto viking_toRaw
+#define i_keydel viking_del
+#include <stc/cmap.h>
int main()
{
diff --git a/examples/astar.c b/examples/astar.c
new file mode 100644
index 00000000..5571c306
--- /dev/null
+++ b/examples/astar.c
@@ -0,0 +1,167 @@
+//
+// -- An A* pathfinder inspired by the excellent tutorial at Red Blob Games --
+//
+// 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
+
+#include <stc/cstr.h>
+#include <stdio.h>
+
+typedef struct
+{
+ int x;
+ int y;
+ int priorty;
+ int width;
+}
+point;
+
+point
+point_init(int x, int y, int width)
+{
+ return (point) { x, y, 0, width };
+}
+
+int
+point_compare_priority(const point* a, const point* b)
+{
+ return a->priorty < b->priorty;
+}
+
+int
+point_equal(const point* a, const point* b)
+{
+ return a->x == b->x && a->y == b->y;
+}
+
+point
+point_from(const cstr* maze, const char* c, int width)
+{
+ int index = cstr_find(*maze, c);
+ return point_init(index % width, index / width, width);
+}
+
+int
+point_index(const point* p)
+{
+ return p->x + p->width * p->y;
+}
+
+int
+point_key_compare(const point* a, const point* b)
+{
+ int i = point_index(a);
+ int j = point_index(b);
+ return (i == j) ? 0 : (i < j) ? -1 : 1;
+}
+
+#define i_val point
+#define i_cmp point_compare_priority
+#include <stc/cpque.h>
+
+#define i_val point
+#define i_cmp c_no_compare
+#include <stc/cdeq.h>
+
+#define i_tag pcost
+#define i_key point
+#define i_val int
+#define i_cmp point_key_compare
+#include <stc/csmap.h>
+
+#define i_tag pstep
+#define i_key point
+#define i_val point
+#define i_cmp point_key_compare
+#include <stc/csmap.h>
+
+cdeq_point
+astar(cstr* maze, int width)
+{
+ cdeq_point path = cdeq_point_init();
+
+ c_forauto (cpque_point, front)
+ c_forauto (csmap_pstep, from)
+ c_forauto (csmap_pcost, costs)
+ {
+ point start = point_from(maze, "@", width);
+ point goal = point_from(maze, "!", width);
+ csmap_pcost_insert(&costs, start, 0);
+ cpque_point_push(&front, start);
+ while (!cpque_point_empty(front))
+ {
+ point current = *cpque_point_top(&front);
+ cpque_point_pop(&front);
+ if (point_equal(&current, &goal))
+ break;
+ point deltas[] = {
+ { -1, +1, 0, width }, { 0, +1, 0, width }, { 1, +1, 0, width },
+ { -1, 0, 0, width }, /* ~ ~ ~ ~ ~ ~ ~ */ { 1, 0, 0, width },
+ { -1, -1, 0, width }, { 0, -1, 0, width }, { 1, -1, 0, width },
+ };
+ for (size_t i = 0; i < c_arraylen(deltas); i++)
+ {
+ point delta = deltas[i];
+ point next = point_init(current.x + delta.x, current.y + delta.y, width);
+ int new_cost = *csmap_pcost_at(&costs, current);
+ if (maze->str[point_index(&next)] != '#')
+ {
+ csmap_pcost_value_t *cost = csmap_pcost_get(&costs, next);
+ if (cost == NULL || new_cost < cost->second)
+ {
+ csmap_pcost_insert(&costs, next, new_cost);
+ next.priorty = new_cost + abs(goal.x - next.x) + abs(goal.y - next.y);
+ cpque_point_push(&front, next);
+ csmap_pstep_insert(&from, next, current);
+ }
+ }
+ }
+ }
+ point current = goal;
+ while (!point_equal(&current, &start))
+ {
+ cdeq_point_push_front(&path, current);
+ current = *csmap_pstep_at(&from, current);
+ }
+ cdeq_point_push_front(&path, start);
+ }
+ return path;
+}
+
+int
+main(void)
+{
+ c_forvar (cstr maze = cstr_lit(
+ "#########################################################################\n"
+ "# # # # # # #\n"
+ "# # ######### # ##### ######### ##### ##### ##### # ! #\n"
+ "# # # # # # # # # #\n"
+ "######### # ######### ######### ##### # # # ######### #\n"
+ "# # # # # # # # # # #\n"
+ "# # ############# # # ######### ##### # ######### # #\n"
+ "# # # # # # # # # #\n"
+ "# ############# ##### ##### # ##### ######### # ##### #\n"
+ "# # # # # # # # # #\n"
+ "# ##### ##### # ##### # ######### # # # #############\n"
+ "# # # # # # # # # # # #\n"
+ "############# # # # ######### # ##### # ##### ##### #\n"
+ "# # # # # # # # # #\n"
+ "# ##### # ######### ##### # ##### ##### ############# #\n"
+ "# # # # # # # # # #\n"
+ "# # ######### # ##### ######### # # ############# # #\n"
+ "# # # # # # # # # # #\n"
+ "# ######### # # # ##### ######### ######### # #########\n"
+ "# # # # # # # # # #\n"
+ "# @ # ##### ##### ##### ######### ##### # ######### # #\n"
+ "# # # # # # #\n"
+ "#########################################################################\n"), cstr_del(&maze))
+ {
+ int width = cstr_find(maze, "\n") + 1;
+ c_forvar (cdeq_point path = astar(&maze, width), cdeq_point_del(&path))
+ {
+ c_foreach (it, cdeq_point, path) maze.str[point_index(it.ref)] = 'x';
+ printf("%s", maze.str);
+ }
+ }
+}
diff --git a/examples/birthday.c b/examples/birthday.c
index b3800f70..eca105df 100644
--- a/examples/birthday.c
+++ b/examples/birthday.c
@@ -1,11 +1,13 @@
#include <math.h>
#include <stdio.h>
#include <time.h>
-
#include <stc/crandom.h>
+
+#define i_tag ic
+#define i_key uint64_t
+#define i_val uint8_t
#include <stc/cmap.h>
-using_cmap(ic, uint64_t, uint8_t);
static uint64_t seed = 12345;
static void test_repeats(void)
@@ -16,18 +18,22 @@ static void test_repeats(void)
printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST);
stc64_t rng = stc64_init(seed);
- cmap_ic m = cmap_ic_init();
- cmap_ic_reserve(&m, N);
- c_forrange (i, N) {
- uint64_t k = stc64_rand(&rng) & mask;
- int v = cmap_ic_emplace(&m, k, 0).ref->second += 1;
- if (v > 1) printf("repeated value %llx (%d) at 2^%d\n", k, v, (int) log2(i));
+ c_forauto (cmap_ic, m)
+ {
+ cmap_ic_reserve(&m, N);
+ c_forrange (i, N) {
+ uint64_t k = stc64_rand(&rng) & mask;
+ int v = cmap_ic_emplace(&m, k, 0).ref->second += 1;
+ if (v > 1) printf("repeated value %zu (%d) at 2^%d\n", k, v, (int) log2(i));
+ }
}
cmap_ic_del(&m);
}
-
-using_cmap(x, uint32_t, uint64_t);
+#define i_tag x
+#define i_key uint32_t
+#define i_val uint64_t
+#include <stc/cmap.h>
void test_distribution(void)
{
@@ -36,7 +42,7 @@ void test_distribution(void)
stc64_t rng = stc64_init(seed);
const size_t N = 1ull << BITS ;
- c_forvar (cmap_x map = cmap_x_init(), cmap_x_del(&map)) {
+ c_forauto (cmap_x, map) {
c_forrange (N) {
uint64_t k = stc64_rand(&rng);
cmap_x_emplace(&map, k & 0xf, 0).ref->second += 1;
diff --git a/examples/complex.c b/examples/complex.c
index c6390d52..e7789815 100644
--- a/examples/complex.c
+++ b/examples/complex.c
@@ -1,16 +1,32 @@
#include <stc/cstr.h>
-#include <stc/cmap.h>
-#include <stc/clist.h>
-#include <stc/carray.h>
void check_del(float* v) {printf("destroy %g\n", *v);}
-using_carray2(f, float, check_del, c_default_fromraw);
-using_clist(arr, carray2f, c_no_compare, carray2f_del, c_no_clone);
-using_cmap(lst, int, clist_arr, c_default_equals, c_default_hash, clist_arr_del, c_no_clone);
-using_cmap_strkey(map, cmap_lst, cmap_lst_del, c_no_clone);
+#define i_tag f
+#define i_val float
+#define i_valdel check_del
+#include <stc/cstack.h>
+
+#define i_tag arr
+#define i_val cstack_f
+#define i_cmp c_no_compare
+#define i_valdel cstack_f_del
+#include <stc/clist.h>
+
+#define i_tag lst
+#define i_key int
+#define i_val clist_arr
+#define i_valdel clist_arr_del
+#include <stc/cmap.h>
+
+#define i_tag map
+#define i_key_str
+#define i_val cmap_lst
+#define i_valdel cmap_lst_del
+#include <stc/cmap.h>
+
// c++:
-// using array2f = std::array<std::array<float, 6>, 4>>;
+// using cstack_f = std::stack<float>;
// using map_lst = std::unordered_map<int, std::forward_list<array2f>>;
// using map_map = std::unordered_map<std::string, map_lst>;
@@ -22,23 +38,24 @@ int main() {
cmap_map myMap = cmap_map_init();
cmap_lst listMap = cmap_lst_init();
clist_arr tableList = clist_arr_init();
- carray2f arr2 = carray2f_with_values(xdim, ydim, 1.f);
+ cstack_f stk = cstack_f_with_capacity(xdim * ydim);
+ memset(stk.data, 0, xdim*ydim*sizeof *stk.data);
+ stk.size = stk.capacity;
- printf("arr2 size: %zu x %zu\n", arr2.xdim, arr2.ydim);
+ printf("stk size: %zu\n", cstack_f_size(stk));
- // Put in some data in 2D array
- arr2.data[x][y] = 3.1415927f;
- clist_arr_push_back(&tableList, arr2);
+ // Put in some data in stack array
+ stk.data[x] = 3.1415927f;
+ clist_arr_push_back(&tableList, stk);
cmap_lst_insert(&listMap, tableKey, tableList);
cmap_map_insert(&myMap, cstr_from(strKey), listMap);
// Access the data entry
- cmap_lst* mapl = &cmap_map_find(&myMap, strKey).ref->second;
- clist_arr* lsta = &cmap_lst_find(mapl, tableKey).ref->second;
- carray2f arr = *clist_arr_back(lsta);
-
- printf("value (%d, %d) is: %f\n", x, y, arr.data[x][y]);
+ cmap_lst* mapL = &cmap_map_find(&myMap, strKey).ref->second;
+ clist_arr* lstA = &cmap_lst_find(mapL, tableKey).ref->second;
+ cstack_f arr = *clist_arr_back(lstA);
+ printf("value (%d) is: %f\n", x, arr.data[x]);
- arr2.data[x][y] = 1.41421356f; // change the value in array
+ stk.data[x] = 1.41421356f; // change the value in array
cmap_map_del(&myMap); // free up everything!
}
diff --git a/examples/convert.c b/examples/convert.c
index 25ae9dcd..d42454ee 100644
--- a/examples/convert.c
+++ b/examples/convert.c
@@ -1,14 +1,16 @@
-#include "stc/cmap.h"
-#include "stc/csmap.h"
-#include "stc/cvec.h"
-#include "stc/clist.h"
-#include "stc/cstr.h"
+#include <stc/cstr.h>
#include <stdio.h>
-using_cmap_str();
-using_cvec_str();
-using_clist_str();
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
+
+#define i_val_str
+#include <stc/cvec.h>
+
+#define i_val_str
+#include <stc/clist.h>
int main()
{
diff --git a/examples/cpque.c b/examples/cpque.c
index 3c22fdfd..0e21a5f7 100644
--- a/examples/cpque.c
+++ b/examples/cpque.c
@@ -1,15 +1,20 @@
-#include <stc/cpque.h>
+// Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue
#include <stdio.h>
-// Implements c++ example: https://en.cppreference.com/w/cpp/container/priority_queue
+#define i_tag imax
+#define i_val int
+#include <stc/cpque.h>
-using_cvec(i, int);
-#define imix_less(x, y) ((*(x) ^ 1) < (*(y) ^ 1))
-#define imix_cmp(x, y) c_less_compare(imix_less, x, y)
+#define i_tag imin
+#define i_val int
+#define i_cmp -c_default_compare
+#include <stc/cpque.h>
-using_cpque(imax, cvec_i);
-using_cpque(imin, cvec_i, -c_default_compare);
-using_cpque(imix, cvec_i, imix_cmp);
+#define imix_less(x, y) ((*(x) ^ 1) < (*(y) ^ 1))
+#define i_tag imix
+#define i_val int
+#define i_cmp(x, y) c_less_compare(imix_less, x, y)
+#include <stc/cpque.h>
#define PRINT_Q(Q) \
void print_##Q(Q q) { \
@@ -31,9 +36,9 @@ int main()
{
const int data[] = {1,8,5,6,3,4,0,9,7,2};
- c_forvar (cpque_imax q = cpque_imax_init(), cpque_imax_del(&q)) // init() and defered del()
- c_forvar (cpque_imin q2 = cpque_imin_init(), cpque_imin_del(&q2))
- c_forvar (cpque_imix q3 = cpque_imix_init(), cpque_imix_del(&q3))
+ c_forauto (cpque_imax, q) // init() and defered del()
+ c_forauto (cpque_imin, q2)
+ c_forauto (cpque_imix, q3)
{
c_forrange (n, c_arraylen(data))
cpque_imax_push(&q, n);
diff --git a/examples/csmap_erase.c b/examples/csmap_erase.c
index 6cebffb7..619efb31 100644
--- a/examples/csmap_erase.c
+++ b/examples/csmap_erase.c
@@ -1,10 +1,12 @@
// map_erase.c
// From C++ example: https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-16
-#include <stc/csmap.h>
#include <stc/cstr.h>
#include <stdio.h>
-using_csmap_strval(my, int);
+#define i_tag my
+#define i_key int
+#define i_val_str
+#include <stc/csmap.h>
void printmap(csmap_my map)
{
@@ -27,7 +29,7 @@ int main()
puts("Starting data of map m1 is:");
printmap(m1);
// The 1st member function removes an element at a given position
- csmap_my_erase_at(&m1, csmap_my_fwd(csmap_my_begin(&m1), 1));
+ csmap_my_erase_at(&m1, csmap_my_advance(csmap_my_begin(&m1), 1));
puts("After the 2nd element is deleted, the map m1 is:");
printmap(m1);
}
@@ -45,7 +47,7 @@ int main()
puts("Starting data of map m2 is:");
printmap(m2);
- csmap_my_iter_t it1 = csmap_my_fwd(csmap_my_begin(&m2), 1);
+ csmap_my_iter_t it1 = csmap_my_advance(csmap_my_begin(&m2), 1);
csmap_my_iter_t it2 = csmap_my_find(&m2, csmap_my_back(&m2)->first);
// The 2nd member function removes elements
// in the range [First, Last)
diff --git a/examples/csmap_find.c b/examples/csmap_find.c
index 46ae01fa..66768016 100644
--- a/examples/csmap_find.c
+++ b/examples/csmap_find.c
@@ -1,12 +1,16 @@
// 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
-#include <stc/csmap.h>
-#include <stc/cvec.h>
#include <stc/cstr.h>
-#include <stdio.h>
-using_csmap_strval(istr, int);
-using_cvec(istr, csmap_istr_rawvalue_t, c_no_compare);
+#define i_tag istr
+#define i_key int
+#define i_val_str
+#include <stc/csmap.h>
+
+#define i_tag istr
+#define i_val csmap_istr_rawvalue_t
+#define i_cmp c_no_compare
+#include <stc/cvec.h>
void print_elem(csmap_istr_rawvalue_t p) {
printf("(%d, %s) ", p.first, p.second);
@@ -56,7 +60,7 @@ int main()
puts("Inserting the following vector data into m1:");
print_collection_cvec_istr(v);
-
+
c_foreach (i, cvec_istr, v) csmap_istr_emplace(&m1, i.ref->first, i.ref->second);
puts("The modified map m1 is (key, value):");
diff --git a/examples/csmap_insert.c b/examples/csmap_insert.c
index 684d499a..25f7a23f 100644
--- a/examples/csmap_insert.c
+++ b/examples/csmap_insert.c
@@ -1,21 +1,30 @@
-#include <stc/csmap.h>
-#include <stc/cvec.h>
-#include <stc/csview.h>
+#include <stc/cstr.h>
#include <stdio.h>
// This implements the std::map insert c++ example at:
// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-19
+#define i_tag ii // Map of int => int
+#define i_key int
+#define i_val int
+#include <stc/csmap.h>
-using_csmap(ii, int, int); // Map of int => int
-using_csmap_strval(istr, int); // Map of int => cstr
-using_cvec(ii, csmap_ii_rawvalue_t, c_no_compare);
+#define i_tag istr // Map of int => cstr
+#define i_key int
+#define i_val_str
+#include <stc/csmap.h>
+
+#define i_tag ii
+#define i_val csmap_ii_rawvalue_t
+#define i_cmp c_no_compare
+#include <stc/cvec.h>
void print_ii(csmap_ii map) {
c_foreach (e, csmap_ii, map)
printf("(%d, %d) ", e.ref->first, e.ref->second);
puts("");
}
+
void print_istr(csmap_istr map) {
c_foreach (e, csmap_istr, map)
printf("(%d, %s) ", e.ref->first, e.ref->second.str);
@@ -25,7 +34,7 @@ void print_istr(csmap_istr map) {
int main()
{
// insert single values
- c_forvar (csmap_ii m1 = csmap_ii_init(), csmap_ii_del(&m1)) {
+ c_forauto (csmap_ii, m1) {
csmap_ii_insert(&m1, 1, 10);
csmap_ii_insert(&m1, 2, 20);
@@ -52,13 +61,14 @@ int main()
}
// The templatized version inserting a jumbled range
- c_forvar (csmap_ii m2 = csmap_ii_init(), csmap_ii_del(&m2))
- c_forvar (cvec_ii v = cvec_ii_init(), cvec_ii_del(&v)) {
- cvec_ii_push_back(&v, (cvec_ii_value_t){43, 294});
- cvec_ii_push_back(&v, (cvec_ii_value_t){41, 262});
- cvec_ii_push_back(&v, (cvec_ii_value_t){45, 330});
- cvec_ii_push_back(&v, (cvec_ii_value_t){42, 277});
- cvec_ii_push_back(&v, (cvec_ii_value_t){44, 311});
+ c_forauto (csmap_ii, m2)
+ c_forauto (cvec_ii, v) {
+ typedef cvec_ii_value_t ipair;
+ cvec_ii_push_back(&v, (ipair){43, 294});
+ cvec_ii_push_back(&v, (ipair){41, 262});
+ cvec_ii_push_back(&v, (ipair){45, 330});
+ cvec_ii_push_back(&v, (ipair){42, 277});
+ cvec_ii_push_back(&v, (ipair){44, 311});
puts("Inserting the following vector data into m2:");
c_foreach (e, cvec_ii, v) printf("(%d, %d) ", e.ref->first, e.ref->second);
@@ -72,7 +82,7 @@ int main()
}
// The templatized versions move-constructing elements
- c_forvar (csmap_istr m3 = csmap_istr_init(), csmap_istr_del(&m3)) {
+ c_forauto (csmap_istr, m3) {
csmap_istr_value_t ip1 = {475, cstr_lit("blue")}, ip2 = {510, cstr_lit("green")};
// single element
@@ -87,7 +97,7 @@ int main()
puts("");
}
- c_forvar (csmap_ii m4 = csmap_ii_init(), csmap_ii_del(&m4)) {
+ c_forauto (csmap_ii, m4) {
// Insert the elements from an initializer_list
c_emplace(csmap_ii, m4, { { 4, 44 }, { 2, 22 }, { 3, 33 }, { 1, 11 }, { 5, 55 } });
puts("After initializer_list insertion, m4 contains:");
diff --git a/examples/csset_erase.c b/examples/csset_erase.c
index 53398ff9..a8b2c9d0 100644
--- a/examples/csset_erase.c
+++ b/examples/csset_erase.c
@@ -1,29 +1,36 @@
-#include <stc/csset.h>
#include <stdio.h>
-using_csset(i, int);
+#define i_key int
+#include <stc/csset.h>
int main()
{
- c_var (csset_i, set, {30, 20, 80, 40, 60, 90, 10, 70, 50});
- c_foreach (k, csset_i, set) printf(" %d", *k.ref); puts("");
+ c_forauto (csset_int, set)
+ {
+ c_emplace(csset_int, set, {30, 20, 80, 40, 60, 90, 10, 70, 50});
+ c_foreach (k, csset_int, set)
+ printf(" %d", *k.ref);
+ puts("");
- int val = 64;
- csset_i_iter_t it;
- printf("Show values >= %d:\n", val);
- it = csset_i_lower_bound(&set, val);
- c_foreach (k, csset_i, it, csset_i_end(&set)) printf(" %d", *k.ref); puts("");
+ int val = 64;
+ csset_int_iter_t it;
+ printf("Show values >= %d:\n", val);
+ it = csset_int_lower_bound(&set, val);
+ c_foreach (k, csset_int, it, csset_int_end(&set))
+ printf(" %d", *k.ref); puts("");
- printf("Erase values >= %d:\n", val);
- while (it.ref) it = csset_i_erase_at(&set, it);
- c_foreach (k, csset_i, set) printf(" %d", *k.ref); puts("");
+ printf("Erase values >= %d:\n", val);
+ while (it.ref) it = csset_int_erase_at(&set, it);
+ c_foreach (k, csset_int, set)
+ printf(" %d", *k.ref);
+ puts("");
- val = 40;
- printf("Erase values < %d:\n", val);
- it = csset_i_lower_bound(&set, val);
- csset_i_erase_range(&set, csset_i_begin(&set), it);
- c_foreach (k, csset_i, set) printf(" %d", *k.ref); puts("");
-
- csset_i_del(&set);
+ val = 40;
+ printf("Erase values < %d:\n", val);
+ it = csset_int_lower_bound(&set, val);
+ csset_int_erase_range(&set, csset_int_begin(&set), it);
+ c_foreach (k, csset_int, set)
+ printf(" %d", *k.ref);
+ puts("");
+ }
}
-
diff --git a/examples/cstr_match.c b/examples/cstr_match.c
index a4dbe8d8..bb3a63fe 100644
--- a/examples/cstr_match.c
+++ b/examples/cstr_match.c
@@ -6,10 +6,10 @@ int main()
c_forvar (cstr ss = cstr_lit("The quick brown fox jumps over the lazy dog.JPG"), cstr_del(&ss)) {
size_t pos = cstr_find_n(ss, "brown", 0, 5);
printf("%zu [%s]\n", pos, pos == cstr_npos ? "<NULL>" : &ss.str[pos]);
- printf("iequals: %d\n", cstr_iequalto(ss, "the quick brown fox jumps over the lazy dog.jpg"));
- printf("icontains: %d\n", cstr_icontains(ss, "uMPS Ove"));
- printf("istarts_with: %d\n", cstr_istarts_with(ss, "The Quick Brown"));
- printf("iends_with: %d\n", cstr_iends_with(ss, ".Jpg"));
+ printf("equals: %d\n", cstr_equalto(ss, "The quick brown fox jumps over the lazy dog.JPG"));
+ printf("contains: %d\n", cstr_contains(ss, "umps ove"));
+ printf("starts_with: %d\n", cstr_starts_with(ss, "The quick brown"));
+ printf("ends_with: %d\n", cstr_ends_with(ss, ".jpg"));
printf("ends_with: %d\n", cstr_ends_with(ss, ".JPG"));
}
} \ No newline at end of file
diff --git a/examples/demos.c b/examples/demos.c
index bb4deb22..03bba7a8 100644
--- a/examples/demos.c
+++ b/examples/demos.c
@@ -1,11 +1,5 @@
-#include <stc/cvec.h>
-#include <stc/clist.h>
-#include <stc/carray.h>
-#include <stc/cset.h>
-#include <stc/cmap.h>
#include <stc/cstr.h>
-
void stringdemo1()
{
printf("\nSTRINGDEMO1\n");
@@ -34,8 +28,9 @@ void stringdemo1()
}
}
-
-using_cvec(ix, int64_t); // ix is just an example tag name.
+#define i_tag ix
+#define i_val int64_t
+#include <stc/cvec.h>
void vectordemo1()
{
@@ -58,8 +53,8 @@ void vectordemo1()
}
}
-
-using_cvec_str();
+#define i_val_str
+#include <stc/cvec.h>
void vectordemo2()
{
@@ -77,7 +72,9 @@ void vectordemo2()
}
}
-using_clist(ix, int);
+#define i_tag ix
+#define i_val int
+#include <stc/clist.h>
void listdemo1()
{
@@ -99,7 +96,7 @@ void listdemo1()
*clist_ix_find(&nums, 104).ref += 50;
clist_ix_remove(&nums, 103);
clist_ix_iter_t it = clist_ix_begin(&nums);
- clist_ix_erase_range(&nums, clist_ix_fwd(it, 5), clist_ix_fwd(it, 15));
+ clist_ix_erase_range(&nums, clist_ix_advance(it, 5), clist_ix_advance(it, 15));
clist_ix_pop_front(&nums);
clist_ix_push_back(&nums, -99);
clist_ix_sort(&nums);
@@ -109,7 +106,9 @@ void listdemo1()
}
}
-using_cset(i, int);
+#define i_tag i
+#define i_key int
+#include <stc/cset.h>
void setdemo1()
{
@@ -123,8 +122,10 @@ void setdemo1()
cset_i_del(&nums);
}
-
-using_cmap(ii, int, int);
+#define i_tag ii
+#define i_key int
+#define i_val int
+#include <stc/cmap.h>
void mapdemo1()
{
@@ -136,8 +137,10 @@ void mapdemo1()
cmap_ii_del(&nums);
}
-
-using_cmap_strkey(si, int); // Shorthand macro for the general using_cmap expansion.
+#define i_tag si
+#define i_key_str
+#define i_val int
+#include <stc/cmap.h>
void mapdemo2()
{
@@ -158,8 +161,9 @@ void mapdemo2()
}
}
-
-using_cmap_str();
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
void mapdemo3()
{
@@ -181,33 +185,36 @@ void mapdemo3()
cmap_str_del(&table); // frees key and value cstrs, and hash table.
}
-
-using_carray3(f, float);
+//#define i_prefix carray3 // backward compatible.
+#define i_tag f
+#define i_val float
+#include <stc/carr3.h>
void arraydemo1()
{
printf("\nARRAYDEMO1\n");
- carray3f arr3 = carray3f_with_values(30, 20, 10, 0.0f);
- arr3.data[5][4][3] = 10.2f;
- float **arr2 = arr3.data[5];
- float *arr1 = arr3.data[5][4];
-
- printf("arr3: %zu: (%zu, %zu, %zu) = %zu\n", sizeof(arr3), arr3.xdim, arr3.ydim, arr3.zdim, carray3f_size(arr3));
+ c_forvar (carr3_f arr3 = carr3_f_with_values(30, 20, 10, 0.0f),
+ carr3_f_del(&arr3))
+ {
+ arr3.data[5][4][3] = 10.2f;
+ float **arr2 = arr3.data[5];
+ float *arr1 = arr3.data[5][4];
- printf("%g\n", arr1[3]); // = 10.2
- printf("%g\n", arr2[4][3]); // = 10.2
- printf("%g\n", arr3.data[5][4][3]); // = 10.2
+ printf("arr3: %zu: (%zu, %zu, %zu) = %zu\n", sizeof(arr3),
+ arr3.xdim, arr3.ydim, arr3.zdim, carr3_f_size(arr3));
- float x = 0.0;
- c_foreach (i, carray3f, arr3)
- *i.ref = ++x;
- printf("%g\n", arr3.data[29][19][9]); // = 6000
+ printf("%g\n", arr1[3]); // = 10.2
+ printf("%g\n", arr2[4][3]); // = 10.2
+ printf("%g\n", arr3.data[5][4][3]); // = 10.2
- carray3f_del(&arr3);
+ float x = 0.0;
+ c_foreach (i, carr3_f, arr3)
+ *i.ref = ++x;
+ printf("%g\n", arr3.data[29][19][9]); // = 6000
+ }
}
-
int main()
{
stringdemo1();
diff --git a/examples/ex_gauss1.c b/examples/ex_gauss1.c
index d089de89..e345ddd1 100644
--- a/examples/ex_gauss1.c
+++ b/examples/ex_gauss1.c
@@ -3,19 +3,23 @@
#include <math.h>
#include <stc/crandom.h>
#include <stc/cstr.h>
-#include <stc/cmap.h>
-#include <stc/cvec.h>
// Declare int -> int hashmap. Uses typetag 'ii' for ints.
-using_cmap(ii, int32_t, size_t);
+#define i_tag ii
+#define i_key int32_t
+#define i_val size_t
+#include <stc/cmap.h>
// Declare int vector with map entries that can be sorted by map keys.
-typedef struct {int first; size_t second;} mapval;
+struct {int first; size_t second;} typedef mapval;
static int compare(mapval *a, mapval *b) {
return c_default_compare(&a->first, &b->first);
}
-using_cvec(pair, mapval, compare);
+#define i_tag pair
+#define i_val mapval
+#define i_cmp compare
+#include <stc/cvec.h>
int main()
{
diff --git a/examples/ex_gauss2.c b/examples/ex_gauss2.c
index 553846aa..850cd2de 100644
--- a/examples/ex_gauss2.c
+++ b/examples/ex_gauss2.c
@@ -1,12 +1,12 @@
#include <stdio.h>
#include <time.h>
-
#include <stc/crandom.h>
-#include <stc/csmap.h>
#include <stc/cstr.h>
-// Declare int -> int sorted map. Uses typetag 'i' for ints.
-using_csmap(i, int, size_t);
+// Declare int -> int sorted map.
+#define i_key int
+#define i_val size_t
+#include <stc/csmap.h>
int main()
{
@@ -21,16 +21,16 @@ int main()
stc64_normalf_t dist = stc64_normalf_init(Mean, StdDev);
// Create and init histogram map with defered destruct
- c_forvar (csmap_i mhist = csmap_i_init(), csmap_i_del(&mhist))
- c_forvar (cstr bar = cstr_init(), cstr_del(&bar))
+ c_forauto (csmap_int, mhist)
+ c_forauto (cstr, bar)
{
c_forrange (N) {
int index = (int) round( stc64_normalf(&rng, &dist) );
- csmap_i_emplace(&mhist, index, 0).ref->second += 1;
+ csmap_int_insert(&mhist, index, 0).ref->second += 1;
}
// Print the gaussian bar chart
- c_foreach (i, csmap_i, mhist) {
+ c_foreach (i, csmap_int, mhist) {
size_t n = (size_t) (i.ref->second * StdDev * Scale * 2.5 / (float)N);
if (n > 0) {
cstr_resize(&bar, n, '*');
diff --git a/examples/inits.c b/examples/inits.c
index 40e89139..04860258 100644
--- a/examples/inits.c
+++ b/examples/inits.c
@@ -1,12 +1,15 @@
#include <stdio.h>
#include <stc/cstr.h>
+
+#define i_tag id // Map of int => cstr
+#define i_key int
+#define i_val_str
#include <stc/cmap.h>
-#include <stc/cvec.h>
-#include <stc/cpque.h>
-#include <stc/clist.h>
-using_cmap_strval(id, int); // Map of int => cstr
-using_cmap_strkey(cnt, int); // Map of cstr => int
+#define i_tag cnt // Map of cstr => int
+#define i_key_str
+#define i_val int
+#include <stc/cmap.h>
typedef struct {int x, y;} ipair_t;
inline static int ipair_compare(const ipair_t* a, const ipair_t* b) {
@@ -14,19 +17,31 @@ inline static int ipair_compare(const ipair_t* a, const ipair_t* b) {
return cx == 0 ? c_default_compare(&a->y, &b->y) : cx;
}
-using_cvec(ip, ipair_t, ipair_compare);
-using_clist(ip, ipair_t, ipair_compare);
-using_cvec(f, float);
-using_cpque(f, cvec_f);
+#define i_tag ip
+#define i_val ipair_t
+#define i_cmp ipair_compare
+#include <stc/cvec.h>
+
+#define i_tag ip
+#define i_val ipair_t
+#define i_cmp ipair_compare
+#include <stc/clist.h>
+
+#define i_tag f
+#define i_val float
+#include <stc/cpque.h>
int main(void)
{
// CVEC FLOAT / PRIORITY QUEUE
- c_forvar (cvec_f floats = cvec_f_init(), cvec_f_del(&floats)) {
- c_emplace(cvec_f, floats, {4.0f, 2.0f, 5.0f, 3.0f, 1.0f});
+ c_forauto (cpque_f, floats) {
+ float nums[] = {4.0f, 2.0f, 5.0f, 3.0f, 1.0f};
- c_foreach (i, cvec_f, floats) printf("%.1f ", *i.ref);
+ c_forrange (i, c_arraylen(nums)) {
+ cpque_f_push_back(&floats, nums[i]);
+ printf("%.1f ", floats.data[i]);
+ }
puts("");
// CVEC PRIORITY QUEUE
@@ -45,7 +60,7 @@ int main(void)
// CMAP ID
int year = 2020;
- c_forvar (cmap_id idnames = cmap_id_init(), cmap_id_del(&idnames)) {
+ c_forauto (cmap_id, idnames) {
cmap_id_emplace(&idnames, 100, "Hello");
cmap_id_insert(&idnames, 110, cstr_from("World"));
cmap_id_insert(&idnames, 120, cstr_from_fmt("Howdy, -%d-", year));
@@ -57,7 +72,7 @@ int main(void)
// CMAP CNT
- c_forvar (cmap_cnt countries = cmap_cnt_init(), cmap_cnt_del(&countries)) {
+ c_forauto (cmap_cnt, countries) {
c_emplace(cmap_cnt, countries, {
{"Norway", 100},
{"Denmark", 50},
@@ -80,7 +95,7 @@ int main(void)
// CVEC PAIR
- c_forvar (cvec_ip pairs1 = cvec_ip_init(), cvec_ip_del(&pairs1)) {
+ c_forauto (cvec_ip, pairs1) {
c_emplace (cvec_ip, pairs1, {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
cvec_ip_sort(&pairs1);
@@ -91,7 +106,7 @@ int main(void)
// CLIST PAIR
- c_forvar (clist_ip pairs2 = clist_ip_init(), clist_ip_del(&pairs2)) {
+ c_forauto (clist_ip, pairs2) {
c_emplace(clist_ip, pairs2, {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
clist_ip_sort(&pairs2);
diff --git a/examples/list.c b/examples/list.c
index 327b477c..f08ba34d 100644
--- a/examples/list.c
+++ b/examples/list.c
@@ -1,14 +1,17 @@
#include <stdio.h>
#include <time.h>
-#include <stc/clist.h>
#include <stc/crandom.h>
-using_clist(fx, double);
+
+#define i_tag fx
+#define i_val double
+#include <stc/clist.h>
int main() {
int k;
const int n = 2000000;
- c_forvar (clist_fx list = clist_fx_init(), clist_fx_del(&list)) {
+ c_forauto (clist_fx, list)
+ {
stc64_t rng = stc64_init(1234);
stc64_uniformf_t dist = stc64_uniformf_init(100.0f, n);
int m = 0;
@@ -46,7 +49,7 @@ int main() {
c_foreach (i, clist_fx, list)
printf(" %g", *i.ref);
printf("\nSubs: ");
- c_foreach (i, clist_fx, clist_fx_fwd(it, 4), clist_fx_end(&list))
+ c_foreach (i, clist_fx, clist_fx_advance(it, 4), clist_fx_end(&list))
printf(" %g", *i.ref);
puts("");
}
diff --git a/examples/list_erase.c b/examples/list_erase.c
index 523ee0b8..6d619b9d 100644
--- a/examples/list_erase.c
+++ b/examples/list_erase.c
@@ -1,8 +1,9 @@
// erasing from clist
-#include <stc/clist.h>
#include <stdio.h>
-using_clist(i, int);
+#define i_tag i
+#define i_val int
+#include <stc/clist.h>
int main ()
{
@@ -11,7 +12,7 @@ int main ()
c_emplace(clist_i, L, {10, 20, 30, 40, 50});
// 10 20 30 40 50
clist_i_iter_t it = clist_i_begin(&L); // ^
- clist_i_next(&it);
+ clist_i_next(&it);
it = clist_i_erase_at(&L, it); // 10 30 40 50
// ^
clist_i_iter_t end = clist_i_end(&L); //
diff --git a/examples/list_splice.c b/examples/list_splice.c
index 7724d683..e9139156 100644
--- a/examples/list_splice.c
+++ b/examples/list_splice.c
@@ -1,7 +1,8 @@
-#include <stc/clist.h>
#include <stdio.h>
-using_clist(i, int);
+#define i_tag i
+#define i_val int
+#include <stc/clist.h>
void print_ilist(const char* s, clist_i list)
{
@@ -14,15 +15,14 @@ void print_ilist(const char* s, clist_i list)
int main ()
{
- c_forvar (clist_i list1 = clist_i_init(), clist_i_del(&list1))
- c_forvar (clist_i list2 = clist_i_init(), clist_i_del(&list2))
+ c_forauto (clist_i, list1, list2)
{
c_emplace(clist_i, list1, {1, 2, 3, 4, 5});
c_emplace(clist_i, list2, {10, 20, 30, 40, 50});
print_ilist("list1:", list1);
print_ilist("list2:", list2);
- clist_i_iter_t it = clist_i_fwd(clist_i_begin(&list1), 2);
+ clist_i_iter_t it = clist_i_advance(clist_i_begin(&list1), 2);
it = clist_i_splice(&list1, it, &list2);
puts("After splice");
diff --git a/examples/mapmap.c b/examples/mapmap.c
index e582ab64..b158b96a 100644
--- a/examples/mapmap.c
+++ b/examples/mapmap.c
@@ -1,27 +1,39 @@
#include <stdio.h>
-#include <stc/cmap.h>
#include <stc/cstr.h>
-// unordered_map<string, unordered_map<string, string>>:
+// unordered_map<string, unordered_map<string, string>>:
+
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
+
+#define i_tag cfg
+#define i_key_str
+#define i_val cmap_str
+#define i_valdel cmap_str_del
+#include <stc/cmap.h>
-using_cmap_str();
-using_cmap_strkey(cfg, cmap_str, cmap_str_del, c_no_clone);
+int main(void)
+{
+ c_forauto (cmap_cfg, cfg)
+ {
+ cmap_cfg_insert(&cfg, cstr_from("user"), cmap_str_init());
+ cmap_cfg_insert(&cfg, cstr_from("group"), cmap_str_init());
+ cmap_cfg_insert(&cfg, cstr_from("admin"), cmap_str_init());
-int main(void) {
- c_forvar (cmap_cfg cfg = cmap_cfg_init(), cmap_cfg_del(&cfg)) {
- cmap_str init = cmap_str_init();
- cmap_str_emplace(&cmap_cfg_insert(&cfg, cstr_from("user"), init).ref->second, "name", "Joe");
- cmap_str_emplace(&cmap_cfg_insert(&cfg, cstr_from("user"), init).ref->second, "groups", "proj1,proj3");
- cmap_str_emplace(&cmap_cfg_insert(&cfg, cstr_from("group"), init).ref->second, "proj1", "Energy");
- cmap_str_emplace(&cmap_cfg_insert(&cfg, cstr_from("group"), init).ref->second, "proj2", "Windy");
- cmap_str_emplace(&cmap_cfg_insert(&cfg, cstr_from("group"), init).ref->second, "proj3", "Oil");
- cmap_str_emplace(&cmap_cfg_insert(&cfg, cstr_from("admin"), init).ref->second, "employees", "2302");
+ cmap_str_emplace(cmap_cfg_at(&cfg, "user"), "name", "Joe");
+ cmap_str_emplace(cmap_cfg_at(&cfg, "user"), "groups", "proj1,proj3");
+ cmap_str_emplace(cmap_cfg_at(&cfg, "group"), "proj1", "Energy");
+ cmap_str_emplace(cmap_cfg_at(&cfg, "group"), "proj2", "Windy");
+ cmap_str_emplace(cmap_cfg_at(&cfg, "group"), "proj3", "Oil");
+ cmap_str_emplace(cmap_cfg_at(&cfg, "admin"), "employees", "2302");
- cmap_str_emplace_or_assign(&cmap_cfg_insert(&cfg, cstr_from("group"), init).ref->second, "proj2", "Wind"); // Update
+ cmap_str_emplace_or_assign(cmap_cfg_at(&cfg, "group"), "proj2", "Wind"); // Update
c_foreach (i, cmap_cfg, cfg)
c_foreach (j, cmap_str, i.ref->second)
- printf("%s: %s - %s (%u)\n", i.ref->first.str, j.ref->first.str, j.ref->second.str, i.ref->second.bucket_count);
+ printf("%s: %s - %s (%u)\n", i.ref->first.str, j.ref->first.str, j.ref->second.str,
+ i.ref->second.bucket_count);
}
} \ No newline at end of file
diff --git a/examples/mmap.c b/examples/mmap.c
index 9c92b19b..1cf145d6 100644
--- a/examples/mmap.c
+++ b/examples/mmap.c
@@ -1,13 +1,17 @@
-#include <stc/csmap.h>
-#include <stc/clist.h>
-#include <stc/cstr.h>
-
// This implements the multimap c++ example found at:
// https://en.cppreference.com/w/cpp/container/multimap/insert
+#include <stc/cstr.h>
// Map of int => clist_str. Note the negation of c_default_compare
-using_clist_str();
-using_csmap(mult, int, clist_str, -c_default_compare, clist_str_del);
+#define i_val_str
+#include <stc/clist.h>
+
+#define i_tag mult
+#define i_key int
+#define i_val clist_str
+#define i_valdel clist_str_del
+#define i_cmp -c_default_compare
+#include <stc/csmap.h>
void print(const csmap_mult mmap)
{
@@ -56,7 +60,7 @@ int main()
clist_str_iter_t pos;
c_foreach (e, csmap_mult, mmap)
if ((pos = clist_str_find(&e.ref->second, "bar")).ref != clist_str_end(&e.ref->second).ref) {
- clist_str_erase(&e.ref->second, pos);
+ clist_str_erase_at(&e.ref->second, pos);
break;
}
print(mmap);
diff --git a/examples/multimap.c b/examples/multimap.c
index 03d4712d..0f5ce538 100644
--- a/examples/multimap.c
+++ b/examples/multimap.c
@@ -1,5 +1,3 @@
-#include <stc/csmap.h>
-#include <stc/clist.h>
#include <stc/cstr.h>
#include <stdio.h>
@@ -35,7 +33,6 @@ struct OlympicsData { int year; const char *city, *country, *date; } ol_data[] =
{1924, "Chamonix", "France", "January 25 - February 5"},
};
-
typedef struct { int year; cstr city, date; } OlympicLocation;
int OlympicLocation_compare(OlympicLocation* a, OlympicLocation* b) {
@@ -46,36 +43,44 @@ void OlympicLocation_del(OlympicLocation* self) {
}
// Create a clist<OlympicLocation>, can be sorted by year.
-using_clist(OL, OlympicLocation, OlympicLocation_compare, OlympicLocation_del);
-
-// Create a csmap<cstr, clist_OL> where key is country
-using_csmap_strkey(OL, clist_OL, clist_OL_del, c_no_clone);
+#define i_tag OL
+#define i_val OlympicLocation
+#define i_valdel OlympicLocation_del
+#define i_cmp OlympicLocation_compare
+#include <stc/clist.h>
+// Create a csmap<cstr, clist_OL> where key is country name
+#define i_tag OL
+#define i_key_str
+#define i_val clist_OL
+#define i_valdel clist_OL_del
+#include <stc/csmap.h>
int main()
{
// Define the multimap with destructor defered to when block is completed.
- c_forvar (csmap_OL multimap = csmap_OL_init(), csmap_OL_del(&multimap))
+ c_forauto (csmap_OL, multimap)
{
- clist_OL empty = clist_OL_init();
+ const clist_OL empty = clist_OL_init();
for (int i = 0; i < c_arraylen(ol_data); ++i)
{
- struct OlympicsData* it = &ol_data[i];
- OlympicLocation loc = {.year = it->year,
- .city = cstr_from(it->city),
- .date = cstr_from(it->date)};
+ struct OlympicsData* d = &ol_data[i];
+ OlympicLocation loc = {.year = d->year,
+ .city = cstr_from(d->city),
+ .date = cstr_from(d->date)};
// Insert an empty list for each new country, and append the entry to the list.
- // If list already exist in map, it returns it from the insert function.
- clist_OL_push_back(&csmap_OL_insert(&multimap, cstr_from(it->country), empty).ref->second, loc);
+ // If country already exist in map, its list is returned from the insert function.
+ clist_OL* list = &csmap_OL_insert(&multimap, cstr_from(d->country), empty).ref->second;
+ clist_OL_push_back(list, loc);
}
-
- // Iterate the multimap:
+ // Sort locations by year for each country.
c_foreach (country, csmap_OL, multimap)
- {
- // Sort locations by year for each country.
clist_OL_sort(&country.ref->second);
+ // Print the multimap:
+ c_foreach (country, csmap_OL, multimap)
+ {
// Loop the locations for a country sorted by year
c_foreach (loc, clist_OL, country.ref->second)
printf("%s: %d, %s, %s\n", country.ref->first.str, loc.ref->year,
diff --git a/examples/phonebook.c b/examples/phonebook.c
index a69e701b..a0aee757 100644
--- a/examples/phonebook.c
+++ b/examples/phonebook.c
@@ -22,12 +22,14 @@
// Program to emulates the phone book.
#include <stdio.h>
-#include <stc/cset.h>
-#include <stc/cmap.h>
#include <stc/cstr.h>
-using_cmap_str();
-using_cset_str();
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
+
+#define i_key_str
+#include <stc/cset.h>
void print_phone_book(cmap_str phone_book)
{
@@ -37,16 +39,16 @@ void print_phone_book(cmap_str phone_book)
int main(int argc, char **argv)
{
- c_static_assert(3 == 3, "hello");
+ c_static_assert(sizeof argc == 4);
- c_forvar (cset_str names = cset_str_init(), cset_str_del(&names)) {
+ c_forauto (cset_str, names) {
c_emplace (cset_str, names, {"Hello", "Cool", "True"});
c_foreach (i, cset_str, names) printf("%s ", i.ref->str);
puts("");
}
bool erased;
- c_forvar (cmap_str phone_book = cmap_str_init(), cmap_str_del(&phone_book)) {
+ c_forauto (cmap_str, phone_book) {
c_emplace (cmap_str, phone_book, {
{"Lilia Friedman", "(892) 670-4739"},
{"Tariq Beltran", "(489) 600-7575"},
@@ -63,7 +65,7 @@ int main(int argc, char **argv)
printf("\nPhone book after adding Zak Byers:\n");
print_phone_book(phone_book);
- if (cmap_str_find(&phone_book, "Tariq Beltran").ref != NULL)
+ if (cmap_str_contains(&phone_book, "Tariq Beltran"))
printf("\nTariq Beltran is in phone book\n");
erased = cmap_str_erase(&phone_book, "Tariq Beltran");
diff --git a/examples/priority.c b/examples/priority.c
index 4824a294..09ede43c 100644
--- a/examples/priority.c
+++ b/examples/priority.c
@@ -1,13 +1,12 @@
#include <stdio.h>
#include <time.h>
-#include <stc/cvec.h>
-#include <stc/cpque.h>
-#include <stc/cmap.h>
#include <stc/crandom.h>
-using_cvec(i, int64_t);
-using_cpque(i, cvec_i, -c_default_compare); // min-heap (increasing values)
+#define i_tag i
+#define i_val int64_t
+#define i_cmp -c_default_compare // min-heap (increasing values)
+#include <stc/cpque.h>
int main() {
size_t N = 10000000;
@@ -16,6 +15,7 @@ int main() {
c_forauto (cpque_i, heap)
{
// Push ten million random numbers to priority queue
+ printf("Push %zu numbers\n", N);
c_forrange (N)
cpque_i_push(&heap, stc64_uniform(&rng, &dist));
@@ -25,7 +25,7 @@ int main() {
c_forrange (N)
cpque_i_push(&heap, stc64_uniform(&rng, &dist));
- // Extract the hundred smallest.
+ puts("Extract the hundred smallest.");
c_forrange (100) {
printf("%zd ", *cpque_i_top(&heap));
cpque_i_pop(&heap);
diff --git a/examples/queue.c b/examples/queue.c
index 1e96b53a..dabb0a08 100644
--- a/examples/queue.c
+++ b/examples/queue.c
@@ -1,15 +1,9 @@
#include <stc/crandom.h>
-#include <stc/cqueue.h>
#include <stdio.h>
-#if 1
-using_cdeq(i, int);
-using_cqueue(i, cdeq_i);
-#else
-#include <stc/clist.h>
-using_clist(i, int);
-using_cqueue(i, clist_i);
-#endif
+#define i_tag i
+#define i_val int
+#include <stc/cqueue.h>
int main() {
int n = 100000000;
@@ -17,7 +11,7 @@ int main() {
stc64_t rng = stc64_init(1234);
dist = stc64_uniform_init(0, n);
- c_forvar (cqueue_i queue = cqueue_i_init(), cqueue_i_del(&queue))
+ c_forauto (cqueue_i, queue)
{
// Push ten million random numbers onto the queue.
c_forrange (n)
@@ -25,7 +19,7 @@ int main() {
// Push or pop on the queue ten million times
printf("%d\n", n);
- c_forrange (n) { // range uses initial n only.
+ c_forrange (n) { // forrange uses initial n only.
int r = stc64_uniform(&rng, &dist);
if (r & 1)
++n, cqueue_i_push(&queue, r);
diff --git a/examples/read.c b/examples/read.c
index 2324d1df..2e8320eb 100644
--- a/examples/read.c
+++ b/examples/read.c
@@ -1,27 +1,26 @@
-#include <errno.h>
#include <stc/cstr.h>
-#include <stc/cvec.h>
+#include <errno.h>
-using_cvec_str();
+#define i_val_str
+#include <stc/cvec.h>
-cvec_str read_file(const char* name) {
+cvec_str read_file(const char* name)
+{
cvec_str vec = cvec_str_init();
- for (FILE* f = fopen(name, "r"); f; fclose(f), f=NULL) {
- cstr line = cstr_init();
- while (cstr_getline(&line, f))
- cvec_str_emplace_back(&vec, line.str);
- cstr_del(&line);
- }
+ c_forvar (FILE* f = fopen(name, "r"), fclose(f))
+ c_forauto (cstr, line)
+ while (cstr_getline(&line, f))
+ cvec_str_emplace_back(&vec, line.str);
return vec;
}
-int main() {
- cvec_str vec = read_file("read.c");
- if (errno) printf("errno: %d\n", errno);
-
+int main()
+{
int n = 0;
- c_foreach (i, cvec_str, vec)
- printf("%5d: %s\n", ++n, i.ref->str);
+ c_forvar (cvec_str vec = read_file(__FILE__), cvec_str_del(&vec))
+ c_foreach (i, cvec_str, vec)
+ printf("%5d: %s\n", ++n, i.ref->str);
- cvec_str_del(&vec);
+ if (errno)
+ printf("error: read_file(" __FILE__ "). errno: %d\n", errno);
} \ No newline at end of file
diff --git a/examples/runall.sh b/examples/runall.sh
new file mode 100644
index 00000000..c476c6e1
--- /dev/null
+++ b/examples/runall.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+cc=gcc
+#cc=clang
+#cc='clang -c -DSTC_HEADER'
+#cc='cl -nologo'
+#cc='cl -nologo -TP'
+#cc='cl -nologo -std:c11'
+run=0
+if [ "$1" == '-h' -o "$1" == '--help' ]; then
+ echo usage: runall.sh [-run] [compiler + options]
+ exit
+fi
+if [ "$1" == '-run' ]; then
+ run=1
+ shift
+fi
+if [ ! -z "$1" ] ; then
+ cc=$@
+fi
+if [ $run = 0 ] ; then
+ for i in *.c ; do
+ echo $cc -I../include $i
+ $cc -I../include $i
+ done
+else
+ for i in *.c ; do
+ echo $cc -I../include $i
+ $cc -I../include $i
+ 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
+ done
+fi
+
+rm -f a.out *.o *.obj *.exe
diff --git a/examples/sharedptr.c b/examples/sharedptr.c
new file mode 100644
index 00000000..40e1be6f
--- /dev/null
+++ b/examples/sharedptr.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+
+void int_del(int* x) {
+ printf("del: %d\n", *x);
+}
+
+#define i_val int
+#define i_valdel int_del // optional func to show elements destroyed
+#include <stc/csptr.h> // define csptr_int shared pointers
+
+#define i_key_csptr int // refer to csptr_int definition above
+#include <stc/csset.h> // define a sorted set of csptr_int
+
+#define i_val_csptr int
+#include <stc/cvec.h>
+
+int main()
+{
+ c_forauto (cvec_int, vec) // declare and init vec, call del at scope exit
+ c_forauto (csset_int, set) // declare and init set, call del at scope exit
+ {
+ cvec_int_push_back(&vec, csptr_int_make(2021));
+ cvec_int_push_back(&vec, csptr_int_make(2012));
+ cvec_int_push_back(&vec, csptr_int_make(2022));
+ cvec_int_push_back(&vec, csptr_int_make(2015));
+
+ printf("vec:");
+ c_foreach (i, cvec_int, vec) printf(" %d", *i.ref->get);
+ puts("");
+
+ // add odd numbers from vec to set
+ c_foreach (i, cvec_int, vec)
+ if (*i.ref->get & 1)
+ csset_int_emplace(&set, *i.ref); // copy shared pointer => increments counter.
+
+ // erase the two last elements in vec
+ cvec_int_pop_back(&vec);
+ cvec_int_pop_back(&vec);
+
+ printf("vec:");
+ c_foreach (i, cvec_int, vec) printf(" %d", *i.ref->get);
+
+ printf("\nset:");
+ c_foreach (i, csset_int, set) printf(" %d", *i.ref->get);
+
+ puts("\nDone");
+ }
+}
+
+/* output:
+vec: 2021 2012 2022 2015
+del: 2022
+vec: 2021 2012
+set: 2015 2021
+Done
+del: 2015
+del: 2021
+del: 2012
+*/
diff --git a/examples/splitstr.c b/examples/splitstr.c
index 54bbe92d..42dd4dbd 100644
--- a/examples/splitstr.c
+++ b/examples/splitstr.c
@@ -1,5 +1,4 @@
#include <stc/csview.h>
-#include <stc/cvec.h>
void print_split(csview str, csview sep)
{
@@ -12,7 +11,8 @@ void print_split(csview str, csview sep)
}
}
-using_cvec_str();
+#define i_val_str
+#include <stc/cvec.h>
cvec_str string_split(csview str, csview sep)
{
diff --git a/examples/stack.c b/examples/stack.c
index 7ae53e0f..89987b7b 100644
--- a/examples/stack.c
+++ b/examples/stack.c
@@ -1,12 +1,14 @@
#include <stdio.h>
#include <stc/cstr.h>
+
+#define i_tag i
+#define i_val int
#include <stc/cstack.h>
-using_cvec(i, int);
-using_cvec(c, char);
-using_cstack(i, cvec_i);
-using_cstack(c, cvec_c);
+#define i_tag c
+#define i_val char
+#include <stc/cstack.h>
int main() {
cstack_i stack = cstack_i_init();
diff --git a/examples/stc_astar.c b/examples/stc_astar.c
deleted file mode 100644
index 6122aad4..00000000
--- a/examples/stc_astar.c
+++ /dev/null
@@ -1,172 +0,0 @@
-//
-// -- An A* pathfinder inspired by the excellent tutorial at Red Blob Games --
-//
-// See:
-// https://www.redblobgames.com/pathfinding/a-star/introduction.html
-
-#include <stc/cstr.h>
-#include <stc/cpque.h>
-#include <stc/cdeq.h>
-#include <stc/csmap.h>
-
-#include <stdio.h>
-
-typedef struct {
- int x, y;
- int priorty, width;
-} MazePoint;
-
-MazePoint
-mpnt_init(int x, int y, int width)
-{
- return c_make(MazePoint){ x, y, 0, width };
-}
-
-int
-mpnt_compare_priority(const MazePoint* a, const MazePoint* b)
-{
- //return 0; // NB! gives 14 steps shorter path!? hmm..
- return c_default_compare(&b->priorty, &a->priorty); // note: high priority is low cost
-}
-
-int
-mpnt_equal(MazePoint* a, MazePoint* b)
-{
- return a->x == b->x && a->y == b->y;
-}
-
-MazePoint
-mpnt_from(cstr maze, const char* c, int width)
-{
- int index = cstr_find(maze, c);
- return mpnt_init(index % width, index / width, width);
-}
-
-int
-mpnt_index(const MazePoint* p)
-{
- return p->x + p->width * p->y;
-}
-
-int
-mpnt_key_compare(const MazePoint* a, const MazePoint* b)
-{
- int i = mpnt_index(a);
- int j = mpnt_index(b);
- return (i > j) - (i < j);
-}
-
-typedef struct {
- MazePoint point;
- int value;
-} MazeCost;
-
-typedef struct {
- MazePoint a;
- MazePoint b;
-} MazeStep;
-
-using_cdeq(pnt, MazePoint, c_no_compare);
-using_cpque(pnt, cdeq_pnt, mpnt_compare_priority);
-using_csmap(step, MazePoint, MazePoint, mpnt_key_compare);
-using_csmap(cost, MazePoint, int, mpnt_key_compare);
-
-
-cdeq_pnt
-astar(cstr maze, int width)
-{
- MazePoint start = mpnt_from(maze, "@", width);
- MazePoint goal = mpnt_from(maze, "!", width);
-
- cdeq_pnt path = cdeq_pnt_init(); // returned
-
- cpque_pnt frontier = cpque_pnt_init();
- csmap_step came_from = csmap_step_init();
- csmap_cost cost_so_far = csmap_cost_init();
- c_fordefer (cpque_pnt_del(&frontier),
- csmap_step_del(&came_from),
- csmap_cost_del(&cost_so_far))
- {
- cpque_pnt_push(&frontier, start);
- csmap_cost_insert(&cost_so_far, start, 0);
-
- while (!cpque_pnt_empty(frontier))
- {
- MazePoint current = *cpque_pnt_top(&frontier);
- cpque_pnt_pop(&frontier);
- if (mpnt_equal(&current, &goal))
- break;
- MazePoint deltas[] = {
- { -1, +1, 0, width }, { 0, +1, 0, width }, { 1, +1, 0, width },
- { -1, 0, 0, width }, /* ~ ~ ~ ~ ~ ~ ~ */ { 1, 0, 0, width },
- { -1, -1, 0, width }, { 0, -1, 0, width }, { 1, -1, 0, width },
- };
-
- c_forrange (i, c_arraylen(deltas))
- {
- MazePoint delta = deltas[i];
- MazePoint next = mpnt_init(current.x + delta.x, current.y + delta.y, width);
- int new_cost = *csmap_cost_at(&cost_so_far, current);
- if (maze.str[mpnt_index(&next)] != '#')
- {
- csmap_cost_value_t* cost = csmap_cost_find(&cost_so_far, next).ref;
- if (!cost || new_cost < cost->second)
- {
- csmap_cost_put(&cost_so_far, next, new_cost); // update
- next.priorty = new_cost + abs(goal.x - next.x) + abs(goal.y - next.y);
- cpque_pnt_push(&frontier, next);
- csmap_step_put(&came_from, next, current);
- }
- }
- }
- }
- MazePoint current = goal;
- while(!mpnt_equal(&current, &start))
- {
- cdeq_pnt_push_front(&path, current);
- current = *csmap_step_at(&came_from, current);
- }
- cdeq_pnt_push_front(&path, start);
- }
- return path;
-}
-
-int
-main(void)
-{
- cstr maze = cstr_from(
- "#########################################################################\n"
- "# # # # # # #\n"
- "# # ######### # ##### ######### ##### ##### ##### # ! #\n"
- "# # # # # # # # # #\n"
- "######### # ######### ######### ##### # # # ######### #\n"
- "# # # # # # # # # # #\n"
- "# # ############# # # ######### ##### # ######### # #\n"
- "# # # # # # # # # #\n"
- "# ############# ##### ##### # ##### ######### # ##### #\n"
- "# # # # # # # # # #\n"
- "# ##### ##### # ##### # ######### # # # #############\n"
- "# # # # # # # # # # # #\n"
- "############# # # # ######### # ##### # ##### ##### #\n"
- "# # # # # # # # # #\n"
- "# ##### # ######### ##### # ##### ##### ############# #\n"
- "# # # # # # # # # #\n"
- "# # ######### # ##### ######### # # ############# # #\n"
- "# # # # # # # # # # #\n"
- "# ######### # # # ##### ######### ######### # #########\n"
- "# # # # # # # # # #\n"
- "# @ # ##### ##### ##### ######### ##### # ######### # #\n"
- "# # # # # # #\n"
- "#########################################################################\n");
- int width = cstr_find(maze, "\n") + 1;
- cdeq_pnt path = astar(maze, width);
-
- printf("length: %zu\n", cdeq_pnt_size(path));
-
- c_foreach (it, cdeq_pnt, path)
- maze.str[mpnt_index(it.ref)] = 'x';
-
- printf("%s", maze.str);
- cstr_del(&maze);
- cdeq_pnt_del(&path);
-} \ No newline at end of file
diff --git a/examples/words.c b/examples/words.c
index afc1f989..442f04f0 100644
--- a/examples/words.c
+++ b/examples/words.c
@@ -1,40 +1,31 @@
#include <math.h>
#include <stc/cstr.h>
-#include <stc/cmap.h>
-#include <stc/clist.h>
-#include <stc/cvec.h>
-using_cvec_str();
-using_clist_str();
-using_cmap_strkey(si, int);
+#define i_val_str
+#include <stc/cvec.h>
+#define i_tag strn
+#define i_key_str
+#define i_val int
+#include <stc/cmap.h>
int main1()
{
- c_var (clist_str, lwords, {
- "this", "sentence", "is", "not", "a", "sentence",
- "this", "sentence", "is", "a", "hoax"
- });
- c_fordefer (clist_str_del(&lwords))
+ c_forauto (cvec_str, words)
+ c_forauto (cmap_strn, word_map)
{
- clist_str_push_back(&lwords, cstr_from_fmt("%.15f", sqrt(2)));
- c_foreach (w, clist_str, lwords)
- printf("%s\n", w.ref->str);
- puts("");
-
- c_var (cvec_str, words, {
+ c_emplace (cvec_str, words, {
"this", "sentence", "is", "not", "a", "sentence",
"this", "sentence", "is", "a", "hoax"
});
- c_fordefer (cvec_str_del(&words))
- {
- cmap_si word_map = cmap_si_init();
- c_foreach (w, cvec_str, words)
- cmap_si_emplace(&word_map, w.ref->str, 0).ref->second += 1;
- c_foreach (i, cmap_si, word_map) {
- printf("%d occurrences of word '%s'\n", i.ref->second, i.ref->first.str);
- }
+ c_foreach (w, cvec_str, words) {
+ cmap_strn_emplace(&word_map, w.ref->str, 0).ref->second += 1;
+ }
+
+ c_foreach (i, cmap_strn, word_map) {
+ printf("%d occurrences of word '%s'\n",
+ i.ref->second, i.ref->first.str);
}
}
return 0;
diff --git a/include/stc/alt/cstr.h b/include/stc/alt/cstr.h
new file mode 100644
index 00000000..e5dc65ec
--- /dev/null
+++ b/include/stc/alt/cstr.h
@@ -0,0 +1,406 @@
+/* MIT License
+ *
+ * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no
+ *
+ * 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.
+ */
+
+/* A string type with short string optimization in C99 with optimal short string
+ * utilization (23 characters with 24 bytes string representation).
+ */
+#ifndef CSTR_INCLUDED
+#define CSTR_INCLUDED
+
+#include <stc/ccommon.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef cstr_size_t
+typedef size_t cstr_size_t;
+#endif
+typedef struct { char* data; cstr_size_t size, cap; } cstr_rep_t;
+typedef const char cstr_literal_t[];
+
+typedef union {
+ struct { char* data; cstr_size_t size, ncap; } lon;
+ struct { char data[sizeof(cstr_rep_t)]; } sso;
+} cstr;
+
+/**************************** PRIVATE API **********************************/
+
+enum { SSO_CAP = offsetof(cstr, lon.ncap) + sizeof((cstr){{0}}.lon.ncap) - 1 };
+#define cstr_is_long(s) (bool)((s)->sso.data[SSO_CAP] & 128)
+#define cstr_select_(s, memb) (cstr_is_long(s) ? cstr_l_##memb : cstr_s_##memb)
+
+#define cstr_s_cap(s) SSO_CAP
+#define cstr_s_size(s) ((cstr_size_t)(SSO_CAP - (s)->sso.data[SSO_CAP]))
+#define cstr_s_set_size(s, len) ((s)->sso.data[SSO_CAP] = SSO_CAP - (len), (s)->sso.data[len] = 0)
+#define cstr_s_data(s) (s)->sso.data
+#define cstr_s_end(s) ((s)->sso.data + cstr_s_size(s))
+
+#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define byte_rotl_(x, b) ((x) << (b)*8 | (x) >> (sizeof(x) - (b))*8)
+#define cstr_l_cap(s) (~byte_rotl_((s)->lon.ncap, sizeof((s)->lon.ncap) - 1))
+#define cstr_l_set_cap(s, cap) ((s)->lon.ncap = ~byte_rotl_(cap, 1))
+#else
+#define cstr_l_cap(s) (~(s)->lon.ncap)
+#define cstr_l_set_cap(s, cap) ((s)->lon.ncap = ~(cap))
+#endif
+#define cstr_l_size(s) ((s)->lon.size)
+#define cstr_l_set_size(s, len) ((s)->lon.data[(s)->lon.size = (len)] = 0)
+#define cstr_l_data(s) (s)->lon.data
+#define cstr_l_end(s) ((s)->lon.data + cstr_l_size(s))
+#define cstr_l_del(s) free((s)->lon.data)
+
+STC_API char* cstr_init_(cstr* self, cstr_size_t len, cstr_size_t cap);
+STC_API void cstr_internal_move_(cstr* self, size_t pos1, size_t pos2);
+
+STC_INLINE void cstr_set_size_(cstr* self, cstr_size_t len) {
+ cstr_select_(self, set_size(self, len));
+}
+
+STC_INLINE cstr_rep_t cstr_rep_(cstr* self) {
+ return cstr_is_long(self)
+ ? c_make(cstr_rep_t){self->lon.data, cstr_l_size(self), cstr_l_cap(self)}
+ : c_make(cstr_rep_t){self->sso.data, cstr_s_size(self), cstr_s_cap(self)};
+}
+
+/**************************** PUBLIC API **********************************/
+
+#define cstr_lit(lit) cstr_from_n(lit, sizeof((cstr_literal_t){lit}) - 1)
+#define cstr_npos (~(cstr_size_t)0 >> 1)
+
+STC_API char* cstr_reserve(cstr* self, cstr_size_t cap);
+STC_API void cstr_shrink_to_fit(cstr* self);
+STC_API void cstr_resize(cstr* self, cstr_size_t size, char value);
+STC_API char* strnstrn(const char *s, const char *needle, size_t slen, size_t nlen);
+STC_API cstr_size_t cstr_find_n(cstr s, const char* needle, cstr_size_t pos, cstr_size_t nmax);
+STC_API void cstr_assign_n(cstr* self, const char* str, cstr_size_t n);
+STC_API void cstr_append_n(cstr* self, const char* str, cstr_size_t n);
+STC_API bool cstr_getdelim(cstr *self, int delim, FILE *fp);
+STC_API void cstr_erase_n(cstr* self, size_t pos, size_t n);
+
+
+STC_INLINE cstr cstr_init(void) {
+ cstr s;
+ cstr_s_set_size(&s, 0);
+ return s;
+}
+
+STC_INLINE cstr cstr_from_n(const char* str, cstr_size_t n) {
+ cstr s;
+ memcpy(cstr_init_(&s, n, n), str, n);
+ return s;
+}
+
+STC_INLINE cstr cstr_from(const char* str) {
+ return cstr_from_n(str, strlen(str));
+}
+
+STC_INLINE cstr cstr_with_size(cstr_size_t size, char value) {
+ cstr s;
+ memset(cstr_init_(&s, size, size), value, size);
+ return s;
+}
+
+STC_INLINE cstr cstr_with_capacity(cstr_size_t cap) {
+ cstr s;
+ cstr_init_(&s, 0, cap);
+ return s;
+}
+
+STC_INLINE cstr cstr_clone(cstr s) {
+ cstr_rep_t rep = cstr_rep_(&s);
+ return cstr_from_n(rep.data, rep.size);
+}
+
+STC_INLINE void cstr_del(cstr* self) {
+ if (cstr_is_long(self)) cstr_l_del(self);
+}
+
+STC_INLINE void cstr_clear(cstr* self) {
+ cstr_set_size_(self, 0);
+}
+
+STC_INLINE char* cstr_data(cstr* self) {
+ return cstr_select_(self, data(self));
+}
+
+STC_INLINE const char* cstr_str(const cstr* self) {
+ return cstr_select_(self, data(self));
+}
+
+STC_INLINE bool cstr_empty(cstr s) {
+ return cstr_select_(&s, size(&s)) == 0;
+}
+
+STC_INLINE cstr_size_t cstr_size(cstr s) {
+ return cstr_select_(&s, size(&s));
+}
+
+STC_INLINE cstr_size_t cstr_length(cstr s) {
+ return cstr_select_(&s, size(&s));
+}
+
+STC_INLINE cstr_size_t cstr_capacity(cstr s) {
+ return cstr_select_(&s, cap(&s));
+}
+
+STC_INLINE bool cstr_equalto(cstr s1, const char* str) {
+ return strcmp(cstr_str(&s1), str) == 0;
+}
+
+STC_INLINE bool cstr_equalto_s(cstr s1, cstr s2) {
+ return strcmp(cstr_str(&s1), cstr_str(&s2)) == 0;
+}
+
+STC_INLINE int cstr_equals(const cstr* s1, const cstr* s2) {
+ return strcmp(cstr_str(s1), cstr_str(s2)) == 0;
+}
+
+STC_INLINE int cstr_compare(const cstr* s1, const cstr* s2) {
+ return strcmp(cstr_str(s1), cstr_str(s2));
+}
+
+STC_INLINE cstr_size_t cstr_find(cstr s, const char* needle) {
+ const char *str = cstr_str(&s), *res = strstr(str, needle);
+ return res ? res - str : cstr_npos;
+}
+
+STC_INLINE bool cstr_find_s(cstr s, cstr needle) {
+ return cstr_find(s, cstr_str(&needle));
+}
+
+STC_INLINE bool cstr_contains(cstr s, const char* needle) {
+ return strstr(cstr_str(&s), needle) != NULL;
+}
+
+STC_INLINE bool cstr_contains_s(cstr s, cstr needle) {
+ return strstr(cstr_str(&s), cstr_str(&needle)) != NULL;
+}
+
+STC_INLINE bool cstr_starts_with(cstr s, const char* sub) {
+ const char* str = cstr_str(&s);
+ while (*sub && *str == *sub) ++str, ++sub;
+ return *sub == 0;
+}
+
+STC_INLINE bool cstr_starts_with_s(cstr s, cstr sub) {
+ return cstr_starts_with(s, cstr_str(&sub));
+}
+
+STC_INLINE bool cstr_ends_with(cstr s, const char* sub) {
+ cstr_rep_t rep = cstr_rep_(&s); cstr_size_t n = strlen(sub);
+ return n <= rep.size && memcmp(rep.data + rep.size - n, sub, n) == 0;
+}
+
+STC_INLINE bool cstr_ends_with_s(cstr s, cstr sub) {
+ return cstr_ends_with(s, cstr_str(&sub));
+}
+
+STC_INLINE void cstr_assign(cstr* self, const char* str) {
+ cstr_assign_n(self, str, strlen(str));
+}
+
+STC_INLINE void cstr_copy(cstr* self, cstr s) {
+ cstr_rep_t rep = cstr_rep_(&s);
+ cstr_assign_n(self, rep.data, rep.size);
+}
+
+STC_INLINE void cstr_append(cstr* self, const char* str) {
+ cstr_append_n(self, str, strlen(str));
+}
+
+STC_INLINE void cstr_append_s(cstr* self, cstr s) {
+ cstr_rep_t rep = cstr_rep_(&s);
+ cstr_append_n(self, rep.data, rep.size);
+}
+
+STC_INLINE void cstr_replace_n(cstr* self, size_t pos, size_t len, const char* str, size_t n) {
+ cstr_internal_move_(self, pos + len, pos + n);
+ memcpy(&cstr_data(self)[pos], str, n);
+}
+
+STC_INLINE void cstr_replace(cstr* self, size_t pos, size_t len, const char* str) {
+ cstr_replace_n(self, pos, len, str, strlen(str));
+}
+
+STC_INLINE void cstr_replace_s(cstr* self, size_t pos, size_t len, cstr s) {
+ cstr_rep_t rep = cstr_rep_(&s);
+ cstr_replace_n(self, pos, len, rep.data, rep.size);
+}
+
+STC_INLINE void cstr_insert_n(cstr* self, size_t pos, const char* str, size_t n) {
+ cstr_replace_n(self, pos, 0, str, n);
+}
+
+STC_INLINE void cstr_insert(cstr* self, size_t pos, const char* str) {
+ cstr_replace_n(self, pos, 0, str, strlen(str));
+}
+
+STC_INLINE void cstr_insert_s(cstr* self, size_t pos, cstr s) {
+ cstr_rep_t rep = cstr_rep_(&s);
+ cstr_replace_n(self, pos, 0, rep.data, rep.size);
+}
+
+STC_INLINE bool cstr_getline(cstr *self, FILE *fp) {
+ return cstr_getdelim(self, '\n', fp);
+}
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+
+#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
+
+STC_DEF void cstr_internal_move_(cstr* self, size_t pos1, size_t pos2) {
+ if (pos1 == pos2)
+ return;
+ cstr_rep_t rep = cstr_rep_(self);
+ cstr_size_t newlen = rep.size + pos2 - pos1;
+ if (newlen > rep.cap)
+ rep.data = cstr_reserve(self, (rep.size*13 >> 3) + pos2 - pos1);
+ memmove(&rep.data[pos2], &rep.data[pos1], rep.size - pos1);
+ cstr_set_size_(self, newlen);
+}
+
+STC_DEF char* cstr_init_(cstr* self, cstr_size_t len, cstr_size_t cap) {
+ if (cap > SSO_CAP) {
+ self->lon.data = (char *)malloc(cap + 1);
+ cstr_l_set_size(self, len);
+ cstr_l_set_cap(self, cap);
+ return self->lon.data;
+ }
+ cstr_s_set_size(self, len);
+ return self->sso.data;
+}
+
+STC_DEF void cstr_shrink_to_fit(cstr* self) {
+ cstr_rep_t rep = cstr_rep_(self);
+ if (rep.size == rep.cap)
+ return;
+ if (rep.size > SSO_CAP) {
+ self->lon.data = (char *)realloc(self->lon.data, cstr_l_size(self) + 1);
+ cstr_l_set_cap(self, cstr_l_size(self));
+ } else if (rep.cap > SSO_CAP) {
+ memcpy(self->sso.data, rep.data, rep.size + 1);
+ cstr_s_set_size(self, rep.size);
+ free(rep.data);
+ }
+}
+
+STC_DEF char* cstr_reserve(cstr* self, cstr_size_t cap) {
+ if (cstr_is_long(self)) {
+ if (cap > cstr_l_cap(self)) {
+ self->lon.data = (char *)realloc(self->lon.data, cap + 1);
+ cstr_l_set_cap(self, cap);
+ }
+ return self->lon.data;
+ }
+ /* from short to long: */
+ if (cap > cstr_s_cap(self)) {
+ char* data = (char *)malloc(cap + 1);
+ cstr_size_t len = cstr_s_size(self);
+ memcpy(data, self->sso.data, len);
+ self->lon.data = data;
+ cstr_l_set_size(self, len);
+ cstr_l_set_cap(self, cap);
+ return data;
+ }
+ return self->sso.data;
+}
+
+STC_DEF void cstr_resize(cstr* self, cstr_size_t size, char value) {
+ cstr_rep_t rep = cstr_rep_(self);
+ if (size > rep.size) {
+ if (size > rep.cap) rep.data = cstr_reserve(self, size);
+ memset(rep.data + rep.size, value, size - rep.size);
+ }
+ cstr_set_size_(self, size);
+}
+
+STC_DEF char* strnstrn(const char *s, const char *needle, size_t slen, size_t nlen) {
+ if (!nlen) return (char *)s;
+ if (nlen > slen) return NULL;
+ slen -= nlen;
+ do {
+ if (*s == *needle && !memcmp(s, needle, nlen)) return (char *)s;
+ ++s;
+ } while (slen--);
+ return NULL;
+}
+
+STC_DEF cstr_size_t
+cstr_find_n(cstr s, const char* needle, cstr_size_t pos, cstr_size_t nmax) {
+ cstr_rep_t rep = cstr_rep_(&s);
+ cstr_size_t nlen = (cstr_size_t) strlen(needle);
+ if (pos > rep.size) return cstr_npos;
+ char* res = strnstrn(rep.data + pos, needle, rep.size, nmax < nlen ? nmax : nlen);
+ return res ? res - rep.data : cstr_npos;
+}
+
+STC_DEF void cstr_assign_n(cstr* self, const char* str, cstr_size_t n) {
+ cstr_rep_t rep = cstr_rep_(self);
+ if (n > rep.cap) {
+ rep.data = (char *)realloc(cstr_is_long(self) ? rep.data : NULL, n + 1);
+ cstr_l_set_cap(self, n);
+ }
+ memmove(rep.data, str, n);
+ cstr_set_size_(self, n);
+}
+
+STC_DEF void cstr_append_n(cstr* self, const char* str, cstr_size_t n) {
+ cstr_rep_t rep = cstr_rep_(self);
+ if (rep.size + n > rep.cap) {
+ cstr_size_t off = (cstr_size_t)(str - rep.data); /* handle self append */
+ rep.data = cstr_reserve(self, (rep.size*13 >> 3) + n);
+ if (off <= rep.size) str = rep.data + off;
+ }
+ memcpy(rep.data + rep.size, str, n);
+ cstr_set_size_(self, rep.size + n);
+}
+
+STC_DEF bool cstr_getdelim(cstr *self, int delim, FILE *fp) {
+ int c = fgetc(fp);
+ if (c == EOF)
+ return false;
+ cstr_size_t pos = 0;
+ cstr_rep_t rep = cstr_rep_(self);
+ for (;;) {
+ if (c == delim || c == EOF) {
+ cstr_set_size_(self, pos);
+ return true;
+ }
+ if (pos == rep.cap) {
+ cstr_set_size_(self, pos);
+ rep.data = cstr_reserve(self, (rep.cap = (rep.cap*13 >> 3) + 16));
+ }
+ rep.data[pos++] = (char) c;
+ c = fgetc(fp);
+ }
+}
+
+STC_DEF void cstr_erase_n(cstr* self, size_t pos, size_t n) {
+ cstr_rep_t rep = cstr_rep_(self);
+ if (n > rep.size - pos) n = rep.size - pos;
+ memmove(&rep.data[pos], &rep.data[pos + n], rep.size - (pos + n));
+ cstr_set_size_(self, rep.size - n);
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/include/stc/carr2.h b/include/stc/carr2.h
new file mode 100644
index 00000000..e390469e
--- /dev/null
+++ b/include/stc/carr2.h
@@ -0,0 +1,131 @@
+/* MIT License
+ *
+ * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no
+ *
+ * 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 CARR2_H_INCLUDED
+#define CARR2_H_INCLUDED
+#include "ccommon.h"
+#include "forward.h"
+#include <stdlib.h>
+#endif
+/*
+// carr2- 2D dynamic array in one memory block with easy indexing.
+#define i_val int
+#include <stc/carr2.h>
+#include <stdio.h>
+
+int main() {
+ int w = 7, h = 5;
+ c_forvar (carr2_int image = carr2_int_init(w, h), carr2_int_del(&image))
+ {
+ int *dat = carr2_int_data(&image);
+ for (int i = 0; i < carr2_int_size(image); ++i)
+ dat[i] = i;
+
+ for (int x = 0; x < image.xdim; ++x)
+ for (int y = 0; y < image.ydim; ++y)
+ printf(" %d", image.data[x][y]);
+ puts("\n");
+
+ c_foreach (i, carr2_int, image)
+ printf(" %d", *i.ref);
+ puts("");
+ }
+}
+*/
+
+#ifndef i_prefix
+#define i_prefix carr2_
+#endif
+#include "template.h"
+
+#ifndef i_fwd
+cx_deftypes(_c_carr2_types, Self, i_val);
+#endif
+
+STC_API Self cx_memb(_with_values)(size_t xdim, size_t ydim, i_val value);
+STC_API Self cx_memb(_with_storage)(size_t xdim, size_t ydim, cx_value_t* storage);
+STC_API Self cx_memb(_clone)(Self src);
+STC_API cx_value_t* cx_memb(_release)(Self* self);
+STC_API void cx_memb(_del)(Self* self);
+
+STC_INLINE Self cx_memb(_init)(size_t xdim, size_t ydim) {
+ return cx_memb(_with_storage)(xdim, ydim, c_new_n(cx_value_t, xdim*ydim));
+}
+STC_INLINE size_t cx_memb(_size)(Self arr)
+ { return arr.xdim*arr.ydim; }
+
+STC_INLINE cx_value_t *cx_memb(_data)(Self* self)
+ { return *self->data; }
+
+STC_INLINE cx_value_t *cx_memb(_at)(Self* self, size_t x, size_t y)
+ { return *self->data + self->ydim*x + y; }
+
+STC_INLINE cx_iter_t cx_memb(_begin)(const Self* self)
+ { return c_make(cx_iter_t){*self->data}; }
+
+STC_INLINE cx_iter_t cx_memb(_end)(const Self* self)
+ { return c_make(cx_iter_t){*self->data + self->xdim*self->ydim}; }
+
+STC_INLINE void cx_memb(_next)(cx_iter_t* it)
+ { ++it->ref; }
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) || defined(i_imp)
+
+STC_DEF Self cx_memb(_with_storage)(size_t xdim, size_t ydim, cx_value_t* block) {
+ Self _arr = {c_new_n(cx_value_t*, xdim), xdim, ydim};
+ for (size_t x = 0; x < xdim; ++x, block += ydim)
+ _arr.data[x] = block;
+ return _arr;
+}
+
+STC_DEF Self cx_memb(_with_values)(size_t xdim, size_t ydim, i_val value) {
+ Self _arr = cx_memb(_init)(xdim, ydim);
+ for (cx_value_t* p = _arr.data[0], *e = p + xdim*ydim; p != e; ++p)
+ *p = value;
+ return _arr;
+}
+
+STC_DEF Self cx_memb(_clone)(Self src) {
+ Self _arr = cx_memb(_init)(src.xdim, src.ydim);
+ for (cx_value_t* p = _arr.data[0], *q = src.data[0], *e = p + cx_memb(_size)(src); p != e; ++p, ++q)
+ *p = i_valfrom(*q);
+ return _arr;
+}
+
+STC_DEF cx_value_t *cx_memb(_release)(Self* self) {
+ cx_value_t *values = self->data[0];
+ c_free(self->data);
+ self->data = NULL;
+ return values;
+}
+
+STC_DEF void cx_memb(_del)(Self* self) {
+ if (!self->data) return;
+ for (cx_value_t* p = self->data[0], *e = p + cx_memb(_size)(*self); p != e; ++p)
+ i_valdel(p);
+ c_free(self->data[0]); /* values */
+ c_free(self->data); /* pointers */
+}
+
+#endif
+#include "template.h"
diff --git a/include/stc/carr3.h b/include/stc/carr3.h
new file mode 100644
index 00000000..8467739d
--- /dev/null
+++ b/include/stc/carr3.h
@@ -0,0 +1,135 @@
+/* MIT License
+ *
+ * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no
+ *
+ * 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 CARR3_H_INCLUDED
+#define CARR3_H_INCLUDED
+#include "ccommon.h"
+#include "forward.h"
+#include <stdlib.h>
+#endif
+/*
+// carr3 - 3D dynamic array in one memory block with easy indexing.
+#define i_val int
+#include <stc/carr3.h>
+#include <stdio.h>
+
+int main() {
+ int w = 7, h = 5, d = 3;
+ c_forvar (carr3_int image = carr3_int_init(w, h, d), carr3_int_del(&image))
+ {
+ int *dat = carr3_int_data(&image);
+ for (int i = 0; i < carr3_int_size(image); ++i)
+ dat[i] = i;
+
+ for (int x = 0; x < image.xdim; ++x)
+ for (int y = 0; y < image.ydim; ++y)
+ for (int z = 0; z < image.zdim; ++z)
+ printf(" %d", image.data[x][y][z]);
+ puts("\n");
+
+ c_foreach (i, carr3_int, image)
+ printf(" %d", *i.ref);
+ puts("");
+ }
+}
+*/
+
+#ifndef i_prefix
+#define i_prefix carr3_
+#endif
+#include "template.h"
+
+#ifndef i_fwd
+cx_deftypes(_c_carr3_types, Self, i_val);
+#endif
+
+STC_API Self cx_memb(_with_values)(size_t xdim, size_t ydim, size_t zdim, i_val value);
+STC_API Self cx_memb(_with_storage)(size_t xdim, size_t ydim, size_t zdim, cx_value_t* storage);
+STC_API Self cx_memb(_clone)(Self src);
+STC_API cx_value_t* cx_memb(_release)(Self* self);
+STC_API void cx_memb(_del)(Self* self);
+
+STC_INLINE Self cx_memb(_init)(size_t xdim, size_t ydim, size_t zdim) {
+ return cx_memb(_with_storage)(xdim, ydim, zdim, c_new_n(cx_value_t, xdim*ydim*zdim));
+}
+
+STC_INLINE size_t cx_memb(_size)(Self arr)
+ { return arr.xdim*arr.ydim*arr.zdim; }
+
+STC_INLINE cx_value_t* cx_memb(_data)(Self* self)
+ { return **self->data; }
+
+STC_INLINE cx_value_t* cx_memb(_at)(Self* self, size_t x, size_t y, size_t z)
+ { return **self->data + self->zdim*(self->ydim*x + y) + z; }
+
+STC_INLINE cx_iter_t cx_memb(_begin)(const Self* self)
+ { return c_make(cx_iter_t){**self->data}; }
+
+STC_INLINE cx_iter_t cx_memb(_end)(const Self* self)
+ { return c_make(cx_iter_t){**self->data + cx_memb(_size)(*self)}; }
+
+STC_INLINE void cx_memb(_next)(cx_iter_t* it)
+ { ++it->ref; }
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) || defined(i_imp)
+
+STC_DEF Self cx_memb(_with_storage)(size_t xdim, size_t ydim, size_t zdim, cx_value_t* block) {
+ Self _arr = {c_new_n(cx_value_t**, xdim*(ydim + 1)), xdim, ydim, zdim};
+ cx_value_t** p = (cx_value_t**) &_arr.data[xdim];
+ for (size_t x = 0, y; x < xdim; ++x, p += ydim)
+ for (_arr.data[x] = p, y = 0; y < ydim; ++y, block += zdim)
+ _arr.data[x][y] = block;
+ return _arr;
+}
+
+STC_DEF Self cx_memb(_with_values)(size_t xdim, size_t ydim, size_t zdim, i_val value) {
+ Self _arr = cx_memb(_init)(xdim, ydim, zdim);
+ for (cx_value_t* p = **_arr.data, *e = p + xdim*ydim*zdim; p != e; ++p)
+ *p = value;
+ return _arr;
+}
+
+STC_DEF Self cx_memb(_clone)(Self src) {
+ Self _arr = cx_memb(_init)(src.xdim, src.ydim, src.zdim);
+ for (cx_value_t* p = **_arr.data, *q = **src.data, *e = p + cx_memb(_size)(src); p != e; ++p, ++q)
+ *p = i_valfrom(*q);
+ return _arr;
+}
+
+STC_DEF cx_value_t* cx_memb(_release)(Self* self) {
+ cx_value_t *values = self->data[0][0];
+ c_free(self->data);
+ self->data = NULL;
+ return values;
+}
+
+STC_DEF void cx_memb(_del)(Self* self) {
+ if (!self->data) return;
+ for (cx_value_t* p = **self->data, *e = p + cx_memb(_size)(*self); p != e; ++p)
+ i_valdel(p);
+ c_free(self->data[0][0]); /* data */
+ c_free(self->data); /* pointers */
+}
+
+#endif
+#include "template.h"
diff --git a/include/stc/carray.h b/include/stc/carray.h
deleted file mode 100644
index d67c1410..00000000
--- a/include/stc/carray.h
+++ /dev/null
@@ -1,218 +0,0 @@
-/* MIT License
- *
- * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * 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 CARRAY_H_INCLUDED
-#define CARRAY_H_INCLUDED
-
-#include "ccommon.h"
-#include <stdlib.h>
-/*
-// carray2 and carray3 - 2D and 3D dynamic arrays in one memory block with easy indexing.
-#include <stc/carray.h>
-#include <stdio.h>
-using_carray2(i, int);
-
-int main() {
- int w = 7, h = 5;
- c_forvar (carray2i image = carray2i_init(w, h), carray2i_del(&image))
- {
- int *dat = carray2i_data(&image);
- for (int i = 0; i < carray2i_size(image); ++i)
- dat[i] = i;
-
- for (int x = 0; x < image.xdim; ++x)
- for (int y = 0; y < image.ydim; ++y)
- printf(" %d", image.data[x][y]);
- puts("\n");
-
- c_foreach (i, carray2i, image)
- printf(" %d", *i.ref);
- puts("");
- }
-}
-*/
-
-#define using_carray2(...) c_MACRO_OVERLOAD(using_carray2, __VA_ARGS__)
-
-#define using_carray2_2(X, Value) \
- _c_using_carray2(carray2##X, Value, c_default_del, c_default_fromraw)
-#define using_carray2_3(X, Value, valueDel) \
- _c_using_carray2(carray2##X, Value, valueDel, c_no_clone)
-#define using_carray2_4(X, Value, valueDel, valueClone) \
- _c_using_carray2(carray2##X, Value, valueDel, valueClone)
-
-#define _c_using_carray2(CX, Value, valueDel, valueClone) \
-\
- typedef Value CX##_value_t; \
- typedef struct { CX##_value_t **data; size_t xdim, ydim; } CX; \
- typedef struct { CX##_value_t *ref; } CX##_iter_t; \
-\
- STC_API CX CX##_with_values(size_t xdim, size_t ydim, Value value); \
- STC_API CX CX##_with_storage(size_t xdim, size_t ydim, CX##_value_t* storage); \
- STC_API CX CX##_clone(CX src); \
-\
- STC_INLINE CX CX##_init(size_t xdim, size_t ydim) { \
- return CX##_with_storage(xdim, ydim, c_new_n(CX##_value_t, xdim*ydim)); \
- } \
- STC_INLINE size_t CX##_size(CX arr) { return arr.xdim*arr.ydim; } \
- STC_INLINE CX##_value_t *CX##_data(CX* self) { return *self->data; } \
- STC_INLINE CX##_value_t *CX##_at(CX* self, size_t x, size_t y) { \
- return *self->data + self->ydim*x + y; \
- } \
- STC_INLINE CX##_value_t *CX##_release(CX* self) { \
- CX##_value_t *t = *self->data; c_free(self->data); self->data = NULL; return t; \
- } \
-\
- STC_INLINE CX##_iter_t CX##_begin(const CX* self) { \
- return c_make(CX##_iter_t){*self->data}; \
- } \
- STC_INLINE CX##_iter_t CX##_end(const CX* self) { \
- return c_make(CX##_iter_t){*self->data + self->xdim*self->ydim}; \
- } \
- STC_INLINE void CX##_next(CX##_iter_t* it) { ++it->ref; } \
-\
- _c_implement_carray2(CX, Value, valueDel, valueClone) \
- STC_API void CX##_del(CX* self)
-
-// carray3:
-
-#define using_carray3(...) c_MACRO_OVERLOAD(using_carray3, __VA_ARGS__)
-
-#define using_carray3_2(X, Value) \
- _c_using_carray3(carray3##X, Value, c_default_del, c_default_fromraw)
-#define using_carray3_3(X, Value, valueDel) \
- _c_using_carray3(carray3##X, Value, valueDel, c_no_clone)
-#define using_carray3_4(X, Value, valueDel, valueClone) \
- _c_using_carray3(carray3##X, Value, valueDel, valueClone)
-
-#define _c_using_carray3(CX, Value, valueDel, valueClone) \
-\
- typedef Value CX##_value_t; \
- typedef struct { CX##_value_t ***data; size_t xdim, ydim, zdim; } CX; \
- typedef struct { CX##_value_t *ref; } CX##_iter_t; \
-\
- STC_API CX CX##_with_values(size_t xdim, size_t ydim, size_t zdim, Value value); \
- STC_API CX CX##_with_storage(size_t xdim, size_t ydim, size_t zdim, CX##_value_t* storage); \
- STC_API CX CX##_clone(CX src); \
-\
- STC_INLINE CX CX##_init(size_t xdim, size_t ydim, size_t zdim) { \
- return CX##_with_storage(xdim, ydim, zdim, c_new_n(CX##_value_t, xdim*ydim*zdim)); \
- } \
- STC_INLINE size_t CX##_size(CX arr) { return arr.xdim*arr.ydim*arr.zdim; } \
- STC_INLINE CX##_value_t* CX##_data(CX* self) { return **self->data; } \
- STC_INLINE CX##_value_t* CX##_at(CX* self, size_t x, size_t y, size_t z) { \
- return **self->data + self->zdim*(self->ydim*x + y) + z; \
- } \
-\
- STC_INLINE CX##_value_t* CX##_release(CX* self) { \
- CX##_value_t *values = **self->data; \
- c_free(self->data); self->data = NULL; \
- return values; \
- } \
-\
- STC_INLINE CX##_iter_t CX##_begin(const CX* self) { \
- return c_make(CX##_iter_t){**self->data}; \
- } \
- STC_INLINE CX##_iter_t CX##_end(const CX* self) { \
- return c_make(CX##_iter_t){**self->data + CX##_size(*self)}; \
- } \
- STC_INLINE void CX##_next(CX##_iter_t* it) { ++it->ref; } \
-\
- _c_implement_carray3(CX, Value, valueDel, valueClone) \
- STC_API void CX##_del(CX* self)
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-
-#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
-
-#define _c_implement_carray2(CX, Value, valueDel, valueClone) \
-\
- STC_DEF CX CX##_with_storage(size_t xdim, size_t ydim, CX##_value_t* block) { \
- CX _arr = {c_new_n(CX##_value_t*, xdim), xdim, ydim}; \
- for (size_t x = 0; x < xdim; ++x, block += ydim) \
- _arr.data[x] = block; \
- return _arr; \
- } \
-\
- STC_DEF CX CX##_with_values(size_t xdim, size_t ydim, Value value) { \
- CX _arr = CX##_init(xdim, ydim); \
- for (CX##_value_t* p = _arr.data[0], *e = p + xdim*ydim; p != e; ++p) \
- *p = value; \
- return _arr; \
- } \
-\
- STC_DEF CX CX##_clone(CX src) { \
- CX _arr = CX##_init(src.xdim, src.ydim); \
- for (CX##_value_t* p = _arr.data[0], *q = src.data[0], *e = p + CX##_size(src); p != e; ++p, ++q) \
- *p = valueClone(*q); \
- return _arr; \
- } \
-\
- STC_DEF void CX##_del(CX* self) { \
- if (!self->data) return; \
- for (CX##_value_t* p = self->data[0], *e = p + CX##_size(*self); p != e; ++p) \
- valueDel(p); \
- c_free(self->data[0]); /* data */ \
- c_free(self->data); /* pointers */ \
- }
-
-// carray3 impl.
-
-#define _c_implement_carray3(CX, Value, valueDel, valueClone) \
-\
- STC_DEF CX CX##_with_storage(size_t xdim, size_t ydim, size_t zdim, CX##_value_t* block) { \
- CX _arr = {c_new_n(CX##_value_t**, xdim*(ydim + 1)), xdim, ydim, zdim}; \
- CX##_value_t** p = (CX##_value_t**) &_arr.data[xdim]; \
- for (size_t x = 0, y; x < xdim; ++x, p += ydim) \
- for (_arr.data[x] = p, y = 0; y < ydim; ++y, block += zdim) \
- _arr.data[x][y] = block; \
- return _arr; \
- } \
-\
- STC_DEF CX CX##_with_values(size_t xdim, size_t ydim, size_t zdim, Value value) { \
- CX _arr = CX##_init(xdim, ydim, zdim); \
- for (CX##_value_t* p = **_arr.data, *e = p + xdim*ydim*zdim; p != e; ++p) \
- *p = value; \
- return _arr; \
- } \
-\
- STC_DEF CX CX##_clone(CX src) { \
- CX _arr = CX##_init(src.xdim, src.ydim, src.zdim); \
- for (CX##_value_t* p = **_arr.data, *q = **src.data, *e = p + CX##_size(src); p != e; ++p, ++q) \
- *p = valueClone(*q); \
- return _arr; \
- } \
-\
- STC_DEF void CX##_del(CX* self) { \
- if (!self->data) return; \
- for (CX##_value_t* p = **self->data, *e = p + CX##_size(*self); p != e; ++p) \
- valueDel(p); \
- c_free(self->data[0][0]); /* data */ \
- c_free(self->data); /* pointers */ \
- }
-
-#else
-#define _c_implement_carray2(CX, Value, valueDel, valueClone)
-#define _c_implement_carray3(CX, Value, valueDel, valueClone)
-#endif
-
-#endif
diff --git a/include/stc/cbits.h b/include/stc/cbits.h
index 2424f70f..af767207 100644
--- a/include/stc/cbits.h
+++ b/include/stc/cbits.h
@@ -56,10 +56,10 @@ int main() {
#include <string.h>
#include "ccommon.h"
-typedef struct {
- uint64_t *data64;
- size_t size;
-} cbits;
+struct cbits {
+ uint64_t *data64;
+ size_t size;
+} typedef cbits;
STC_API cbits cbits_with_size(size_t size, bool value);
STC_API cbits cbits_with_values(size_t size, uint64_t pattern);
diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h
index e901f499..a64bff40 100644
--- a/include/stc/ccommon.h
+++ b/include/stc/ccommon.h
@@ -39,7 +39,7 @@
#endif
#define STC_INLINE static inline
-#if defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
+#if defined(STC_HEADER) || defined(STC_IMPLEMENTATION) || defined(i_imp)
# define STC_API extern
# define STC_DEF
# define STC_LIBRARY_ONLY(...) __VA_ARGS__
@@ -55,8 +55,8 @@
#define c_MACRO_OVERLOAD(name, ...) \
c_PASTE3(name, _, c_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
#define c_CONCAT(a, b) a ## b
-#define c_CONCAT3(a, b, c) a ## b ## c
#define c_PASTE(a, b) c_CONCAT(a, b)
+#define c_CONCAT3(a, b, c) a ## b ## c
#define c_PASTE3(a, b, c) c_CONCAT3(a, b, c)
#define c_EXPAND(...) __VA_ARGS__
#define c_NUM_ARGS(...) _c_APPLY_ARG_N((__VA_ARGS__, _c_RSEQ_N))
@@ -68,9 +68,10 @@
_13, _14, _15, _16, _17, _18, _19, _20, _21, _22, \
_23, _24, _25, _26, _27, _28, _29, _30, N, ...) N
-#define c_static_assert(cond, ...) typedef char _static_assert_[(cond) ? 1 : -1]
+#define c_static_assert(cond) \
+ typedef char c_PASTE(_static_assert_line_, __LINE__)[(cond) ? 1 : -1]
#define c_container_of(ptr, type, member) \
- ((type *)((char *)(ptr) - offsetof(type, member)))
+ ((type *)((char *)(ptr) - offsetof(type, member)))
#if __cplusplus
#define c_new(T) static_cast<T*>(c_malloc(sizeof(T)))
@@ -109,8 +110,11 @@
#define c_default_del(ptr) ((void) (ptr))
-#define c_true(...) __VA_ARGS__
-#define c_false(...)
+STC_API uint64_t c_default_hash(const void *key, size_t len);
+#define c_default_hash32(data, len_is_4) \
+ ((*(const uint32_t*)data * 0xc6a4a7935bd1e99d) >> 15)
+#define c_default_hash64(data, len_is_8) \
+ (*(const uint64_t *)data * 0xc6a4a7935bd1e99d)
/* Generic algorithms */
diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h
index d052e9eb..8fe81845 100644
--- a/include/stc/cdeq.h
+++ b/include/stc/cdeq.h
@@ -20,347 +20,350 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#ifndef CDEQ_H_INCLUDED
-#define CDEQ_H_INCLUDED
+#ifndef CDEQ_H_INCLUDED
#include "ccommon.h"
+#include "forward.h"
#include <stdlib.h>
#include <string.h>
-#define forward_cdeq(X, Value) _c_cdeq_types(cdeq_##X, Value)
+struct cdeq_rep { size_t size, cap; void* base[]; };
+#define cdeq_rep_(self) c_container_of((self)->_base, struct cdeq_rep, base)
+#endif // CDEQ_H_INCLUDED
-#define using_cdeq(...) c_MACRO_OVERLOAD(using_cdeq, __VA_ARGS__)
+#ifndef i_prefix
+#define i_prefix cdeq_
+#endif
+#include "template.h"
-#define using_cdeq_2(X, Value) \
- using_cdeq_3(X, Value, c_default_compare)
-#define using_cdeq_3(X, Value, valueCompare) \
- using_cdeq_5(X, Value, valueCompare, c_default_del, c_default_fromraw)
-#define using_cdeq_4(X, Value, valueCompare, valueDel) \
- using_cdeq_5(X, Value, valueCompare, valueDel, c_no_clone)
-#define using_cdeq_5(X, Value, valueCompare, valueDel, valueClone) \
- using_cdeq_7(X, Value, valueCompare, valueDel, valueClone, c_default_toraw, Value)
-#define using_cdeq_7(X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue) \
- _c_using_cdeq(cdeq_##X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue, c_true)
-#define using_cdeq_8(X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue, defTypes) \
- _c_using_cdeq(cdeq_##X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue, defTypes)
+#if !defined i_fwd
+cx_deftypes(_c_cdeq_types, Self, i_val);
+#endif
+typedef i_valraw cx_rawvalue_t;
-#define using_cdeq_str() \
- using_cdeq_7(str, cstr, c_rawstr_compare, cstr_del, cstr_from, cstr_str, const char*)
+STC_API Self cx_memb(_init)(void);
+STC_API Self cx_memb(_clone)(Self cx);
+STC_API void cx_memb(_clear)(Self* self);
+STC_API void cx_memb(_del)(Self* self);
+STC_API cx_value_t* cx_memb(_push_back)(Self* self, i_val value);
+STC_API void cx_memb(_expand_right_half_)(Self* self, size_t idx, size_t n);
+#ifndef i_queue
+STC_API cx_iter_t cx_memb(_find_in)(cx_iter_t p1, cx_iter_t p2, i_valraw raw);
+STC_API int cx_memb(_value_compare)(const cx_value_t* x, const cx_value_t* y);
+STC_API cx_value_t* cx_memb(_push_front)(Self* self, i_val value);
+STC_API cx_iter_t cx_memb(_erase_range_p)(Self* self, cx_value_t* p1, cx_value_t* p2);
+STC_API cx_iter_t cx_memb(_insert_range_p)(Self* self, cx_value_t* pos,
+ const cx_value_t* p1, const cx_value_t* p2, bool clone);
+STC_API cx_iter_t cx_memb(_emplace_range_p)(Self* self, cx_value_t* pos,
+ const cx_rawvalue_t* p1, const cx_rawvalue_t* p2);
+#endif // i_queue
-struct cdeq_rep { size_t size, cap; void* base[]; };
-#define _cdeq_rep(self) c_container_of((self)->_base, struct cdeq_rep, base)
-
-#define _c_cdeq_types(CX, Value) \
- typedef Value CX##_value_t; \
- typedef struct {CX##_value_t *ref; } CX##_iter_t; \
- typedef struct {CX##_value_t *_base, *data;} CX
-
-#define _c_using_cdeq(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue, defTypes) \
-\
- defTypes( _c_cdeq_types(CX, Value); ) \
- typedef RawValue CX##_rawvalue_t; \
-\
- STC_API CX CX##_init(void); \
- STC_API CX CX##_clone(CX cx); \
- STC_API void CX##_clear(CX* self); \
- STC_API void CX##_del(CX* self); \
- STC_API CX##_iter_t CX##_find_in(CX##_iter_t p1, CX##_iter_t p2, RawValue raw); \
- STC_API int CX##_value_compare(const CX##_value_t* x, const CX##_value_t* y); \
- STC_API void CX##_push_back(CX* self, Value value); \
- STC_API void CX##_push_front(CX* self, Value value); \
- STC_API CX##_iter_t CX##_erase_range_p(CX* self, CX##_value_t* p1, CX##_value_t* p2); \
- STC_API CX##_iter_t CX##_insert_range_p(CX* self, CX##_value_t* pos, \
- const CX##_value_t* p1, const CX##_value_t* p2, bool clone); \
- STC_API CX##_iter_t CX##_emplace_range_p(CX* self, CX##_value_t* pos, \
- const CX##_rawvalue_t* p1, const CX##_rawvalue_t* p2); \
- STC_API void CX##_expand_right_(CX* self, size_t idx, size_t n); \
-\
- STC_INLINE bool CX##_empty(CX cx) {return !_cdeq_rep(&cx)->size;} \
- STC_INLINE size_t CX##_size(CX cx) {return _cdeq_rep(&cx)->size;} \
- STC_INLINE size_t CX##_capacity(CX cx) {return _cdeq_rep(&cx)->cap;} \
- STC_INLINE void CX##_swap(CX* a, CX* b) {c_swap(CX, *a, *b);} \
- STC_INLINE Value CX##_value_fromraw(RawValue raw) {return valueFromRaw(raw);} \
- STC_INLINE RawValue CX##_value_toraw(CX##_value_t* pval) {return valueToRaw(pval);} \
- STC_INLINE Value CX##_value_clone(Value val) \
- {return valueFromRaw(valueToRaw(&val));} \
- STC_INLINE void CX##_emplace_back(CX* self, RawValue raw) \
- {CX##_push_back(self, valueFromRaw(raw));} \
- STC_INLINE void CX##_emplace_front(CX* self, RawValue raw) \
- {CX##_push_front(self, valueFromRaw(raw));} \
- STC_INLINE void CX##_pop_back(CX* self) \
- {valueDel(&self->data[--_cdeq_rep(self)->size]);} \
- STC_INLINE void CX##_pop_front(CX* self) \
- {valueDel(self->data++); --_cdeq_rep(self)->size;} \
- STC_INLINE CX##_value_t* CX##_front(const CX* self) {return self->data;} \
- STC_INLINE CX##_value_t* CX##_back(const CX* self) \
- {return self->data + _cdeq_rep(self)->size - 1;} \
- STC_INLINE CX##_value_t* CX##_at(const CX* self, size_t idx) \
- {assert(idx < _cdeq_rep(self)->size); return self->data + idx;} \
- STC_INLINE CX##_iter_t CX##_begin(const CX* self) \
- {return c_make(CX##_iter_t){self->data};} \
- STC_INLINE CX##_iter_t CX##_end(const CX* self) \
- {return c_make(CX##_iter_t){self->data + _cdeq_rep(self)->size};} \
- STC_INLINE void CX##_next(CX##_iter_t* it) {++it->ref;} \
- STC_INLINE CX##_iter_t CX##_adv(CX##_iter_t it, intptr_t offs) {it.ref += offs; return it;} \
- STC_INLINE size_t CX##_idx(CX cx, CX##_iter_t it) {return it.ref - cx.data;} \
-\
- STC_INLINE CX \
- CX##_with_capacity(size_t n) { \
- CX cx = CX##_init(); \
- CX##_expand_right_(&cx, 0, n); \
- return cx; \
- } \
-\
- STC_INLINE void \
- CX##_reserve(CX* self, size_t n) { \
- size_t sz = _cdeq_rep(self)->size; \
- if (n > sz) CX##_expand_right_(self, sz, n - sz); \
- } \
-\
- STC_INLINE void \
- CX##_shrink_to_fit(CX *self) { \
- CX cx = CX##_clone(*self); \
- CX##_del(self); *self = cx; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_insert(CX* self, size_t idx, Value value) { \
- return CX##_insert_range_p(self, self->data + idx, &value, &value + 1, false); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_insert_n(CX* self, size_t idx, const CX##_value_t arr[], size_t n) { \
- return CX##_insert_range_p(self, self->data + idx, arr, arr + n, false); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_insert_at(CX* self, CX##_iter_t it, Value value) { \
- return CX##_insert_range_p(self, it.ref, &value, &value + 1, false); \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_emplace(CX* self, size_t idx, RawValue raw) { \
- return CX##_emplace_range_p(self, self->data + idx, &raw, &raw + 1); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_emplace_n(CX* self, size_t idx, const CX##_rawvalue_t arr[], size_t n) { \
- return CX##_emplace_range_p(self, self->data + idx, arr, arr + n); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_emplace_at(CX* self, CX##_iter_t it, RawValue raw) { \
- return CX##_emplace_range_p(self, it.ref, &raw, &raw + 1); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_emplace_range(CX* self, CX##_iter_t it, CX##_iter_t it1, CX##_iter_t it2) { \
- return CX##_insert_range_p(self, it.ref, it1.ref, it2.ref, true); \
- } \
- STC_INLINE void \
- CX##_emplace_items(CX *self, const CX##_rawvalue_t arr[], size_t n) { \
- CX##_emplace_range_p(self, self->data + _cdeq_rep(self)->size, arr, arr + n); \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_erase(CX* self, size_t idx) { \
- return CX##_erase_range_p(self, self->data + idx, self->data + idx + 1); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_erase_n(CX* self, size_t idx, size_t n) { \
- return CX##_erase_range_p(self, self->data + idx, self->data + idx + n); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_erase_at(CX* self, CX##_iter_t it) { \
- return CX##_erase_range_p(self, it.ref, it.ref + 1); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_erase_range(CX* self, CX##_iter_t it1, CX##_iter_t it2) { \
- return CX##_erase_range_p(self, it1.ref, it2.ref); \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_find(const CX* self, RawValue raw) { \
- return CX##_find_in(CX##_begin(self), CX##_end(self), raw); \
- } \
-\
- STC_INLINE CX##_value_t* \
- CX##_get(const CX* self, RawValue raw) { \
- CX##_iter_t end = CX##_end(self); \
- CX##_value_t* val = CX##_find_in(CX##_begin(self), end, raw).ref; \
- return val == end.ref ? NULL : val; \
- } \
-\
- STC_INLINE void \
- CX##_sort_range(CX##_iter_t i1, CX##_iter_t i2, \
- int(*_cmp_)(const CX##_value_t*, const CX##_value_t*)) { \
- qsort(i1.ref, i2.ref - i1.ref, sizeof *i1.ref, (int(*)(const void*, const void*)) _cmp_); \
- } \
-\
- STC_INLINE void \
- CX##_sort(CX* self) { \
- CX##_sort_range(CX##_begin(self), CX##_end(self), CX##_value_compare); \
- } \
-\
- _c_implement_cdeq(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue) \
- struct stc_trailing_semicolon
+STC_INLINE bool cx_memb(_empty)(Self cx) { return !cdeq_rep_(&cx)->size; }
+STC_INLINE size_t cx_memb(_size)(Self cx) { return cdeq_rep_(&cx)->size; }
+STC_INLINE size_t cx_memb(_capacity)(Self cx) { return cdeq_rep_(&cx)->cap; }
+STC_INLINE void cx_memb(_swap)(Self* a, Self* b) {c_swap(Self, *a, *b); }
+STC_INLINE i_val cx_memb(_value_fromraw)(i_valraw raw) { return i_valfrom(raw); }
+STC_INLINE i_valraw cx_memb(_value_toraw)(cx_value_t* pval) { return i_valto(pval); }
+STC_INLINE i_val cx_memb(_value_clone)(i_val val)
+ { return i_valfrom(i_valto(&val)); }
+STC_INLINE cx_value_t* cx_memb(_emplace_back)(Self* self, i_valraw raw)
+ { return cx_memb(_push_back)(self, i_valfrom(raw)); }
+STC_INLINE void cx_memb(_pop_front)(Self* self)
+ { i_valdel(self->data++); --cdeq_rep_(self)->size; }
+STC_INLINE cx_value_t* cx_memb(_back)(const Self* self)
+ { return self->data + cdeq_rep_(self)->size - 1; }
+STC_INLINE cx_value_t* cx_memb(_front)(const Self* self) { return self->data; }
+STC_INLINE cx_iter_t cx_memb(_begin)(const Self* self)
+ { return c_make(cx_iter_t){self->data}; }
+STC_INLINE cx_iter_t cx_memb(_end)(const Self* self)
+ { return c_make(cx_iter_t){self->data + cdeq_rep_(self)->size}; }
+STC_INLINE void cx_memb(_next)(cx_iter_t* it) { ++it->ref; }
+STC_INLINE cx_iter_t cx_memb(_advance)(cx_iter_t it, intptr_t offs)
+ { it.ref += offs; return it; }
-/* -------------------------- IMPLEMENTATION ------------------------- */
+STC_INLINE Self
+cx_memb(_with_capacity)(size_t n) {
+ Self cx = cx_memb(_init)();
+ cx_memb(_expand_right_half_)(&cx, 0, n);
+ return cx;
+}
+
+STC_INLINE void
+cx_memb(_shrink_to_fit)(Self *self) {
+ Self cx = cx_memb(_clone)(*self);
+ cx_memb(_del)(self); *self = cx;
+}
+
+STC_INLINE void
+cx_memb(_emplace_items)(Self *self, const cx_rawvalue_t arr[], size_t n) {
+ for (size_t i = 0; i < n; ++i)
+ cx_memb(_push_back)(self, i_valfrom(arr[i]));
+}
+
+#ifndef i_queue
+
+STC_INLINE cx_value_t* cx_memb(_emplace_front)(Self* self, i_valraw raw) {
+ return cx_memb(_push_front)(self, i_valfrom(raw));
+}
+
+STC_INLINE void cx_memb(_pop_back)(Self* self) {
+ i_valdel(&self->data[--cdeq_rep_(self)->size]);
+}
+
+STC_INLINE cx_value_t* cx_memb(_at)(const Self* self, size_t idx) {
+ assert(idx < cdeq_rep_(self)->size); return self->data + idx;
+}
+
+STC_INLINE size_t cx_memb(_index)(Self cx, cx_iter_t it) {
+ return it.ref - cx.data;
+}
+
+STC_INLINE void
+cx_memb(_reserve)(Self* self, size_t n) {
+ size_t sz = cdeq_rep_(self)->size;
+ if (n > sz) cx_memb(_expand_right_half_)(self, sz, n - sz);
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_insert)(Self* self, size_t idx, i_val value) {
+ return cx_memb(_insert_range_p)(self, self->data + idx, &value, &value + 1, false);
+}
+STC_INLINE cx_iter_t
+cx_memb(_insert_n)(Self* self, size_t idx, const cx_value_t arr[], size_t n) {
+ return cx_memb(_insert_range_p)(self, self->data + idx, arr, arr + n, false);
+}
+STC_INLINE cx_iter_t
+cx_memb(_insert_at)(Self* self, cx_iter_t it, i_val value) {
+ return cx_memb(_insert_range_p)(self, it.ref, &value, &value + 1, false);
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_emplace)(Self* self, size_t idx, i_valraw raw) {
+ return cx_memb(_emplace_range_p)(self, self->data + idx, &raw, &raw + 1);
+}
+STC_INLINE cx_iter_t
+cx_memb(_emplace_n)(Self* self, size_t idx, const cx_rawvalue_t arr[], size_t n) {
+ return cx_memb(_emplace_range_p)(self, self->data + idx, arr, arr + n);
+}
+STC_INLINE cx_iter_t
+cx_memb(_emplace_at)(Self* self, cx_iter_t it, i_valraw raw) {
+ return cx_memb(_emplace_range_p)(self, it.ref, &raw, &raw + 1);
+}
+STC_INLINE cx_iter_t
+cx_memb(_emplace_range)(Self* self, cx_iter_t it, cx_iter_t it1, cx_iter_t it2) {
+ return cx_memb(_insert_range_p)(self, it.ref, it1.ref, it2.ref, true);
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_erase)(Self* self, size_t idx) {
+ return cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + 1);
+}
+STC_INLINE cx_iter_t
+cx_memb(_erase_n)(Self* self, size_t idx, size_t n) {
+ return cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n);
+}
+STC_INLINE cx_iter_t
+cx_memb(_erase_at)(Self* self, cx_iter_t it) {
+ return cx_memb(_erase_range_p)(self, it.ref, it.ref + 1);
+}
+STC_INLINE cx_iter_t
+cx_memb(_erase_range)(Self* self, cx_iter_t it1, cx_iter_t it2) {
+ return cx_memb(_erase_range_p)(self, it1.ref, it2.ref);
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_find)(const Self* self, i_valraw raw) {
+ return cx_memb(_find_in)(cx_memb(_begin)(self), cx_memb(_end)(self), raw);
+}
+
+STC_INLINE cx_value_t*
+cx_memb(_get)(const Self* self, i_valraw raw) {
+ cx_iter_t end = cx_memb(_end)(self);
+ cx_value_t* val = cx_memb(_find_in)(cx_memb(_begin)(self), end, raw).ref;
+ return val == end.ref ? NULL : val;
+}
+
+STC_INLINE void
+cx_memb(_sort_range)(cx_iter_t i1, cx_iter_t i2,
+ int(*_cmp_)(const cx_value_t*, const cx_value_t*)) {
+ qsort(i1.ref, i2.ref - i1.ref, sizeof *i1.ref, (int(*)(const void*, const void*)) _cmp_);
+}
+
+STC_INLINE void
+cx_memb(_sort)(Self* self) {
+ cx_memb(_sort_range)(cx_memb(_begin)(self), cx_memb(_end)(self), cx_memb(_value_compare));
+}
+#endif // i_queue
-#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) || defined(i_imp)
+#ifndef CDEQ_H_INCLUDED
static struct cdeq_rep _cdeq_sentinel = {0, 0};
#define _cdeq_nfront(self) ((self)->data - (self)->_base)
+#endif
-#define _c_implement_cdeq(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue) \
-\
- STC_DEF CX \
- CX##_init(void) { \
- CX##_value_t *b = (CX##_value_t *) _cdeq_sentinel.base; \
- return c_make(CX){b, b}; \
- } \
-\
- STC_DEF void \
- CX##_clear(CX* self) { \
- struct cdeq_rep* rep = _cdeq_rep(self); if (rep->cap) { \
- for (CX##_value_t *p = self->data, *q = p + rep->size; p != q; ++p) \
- valueDel(p); \
- rep->size = 0; \
- } \
- } \
-\
- STC_DEF void \
- CX##_del(CX* self) { \
- CX##_clear(self); \
- if (_cdeq_rep(self)->cap) \
- c_free(_cdeq_rep(self)); \
- } \
-\
- STC_DEF size_t \
- CX##_realloc_(CX* self, size_t n) { \
- struct cdeq_rep* rep = _cdeq_rep(self); \
- size_t sz = rep->size, cap = (size_t) (sz*1.7) + n + 7; \
- size_t nfront = _cdeq_nfront(self); \
- rep = (struct cdeq_rep*) c_realloc(rep->cap ? rep : NULL, \
- offsetof(struct cdeq_rep, base) + cap*sizeof(Value)); \
- rep->size = sz, rep->cap = cap; \
- self->_base = (CX##_value_t *) rep->base; \
- self->data = self->_base + nfront; \
- return cap; \
- } \
-\
- STC_DEF void \
- CX##_expand_left_(CX* self, size_t idx, size_t n) { \
- struct cdeq_rep* rep = _cdeq_rep(self); \
- size_t sz = rep->size, cap = rep->cap; \
- size_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront; \
- if (nfront >= n) { \
- self->data = (CX##_value_t *) memmove(self->data - n, self->data, idx*sizeof(Value)); \
- } else { \
- if (sz*1.3 + n > cap) cap = CX##_realloc_(self, n); \
- size_t unused = cap - (sz + n); \
- size_t pos = (nback*2 < unused) ? unused - nback : unused/2; \
- memmove(self->_base + pos + idx + n, self->data + idx, (sz - idx)*sizeof(Value)); \
- self->data = (CX##_value_t *) memmove(self->_base + pos, self->data, idx*sizeof(Value)); \
- } \
- } \
-\
- STC_DEF void \
- CX##_expand_right_(CX* self, size_t idx, size_t n) { \
- struct cdeq_rep* rep = _cdeq_rep(self); \
- size_t sz = rep->size, cap = rep->cap; \
- size_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront; \
- if (nback >= n || sz*1.3 + n > cap && CX##_realloc_(self, n)) { \
- memmove(self->data + idx + n, self->data + idx, (sz - idx)*sizeof(Value)); \
- } else { \
- size_t unused = cap - (sz + n); \
- size_t pos = (nfront*2 < unused) ? nfront : unused/2; \
- memmove(self->_base + pos, self->data, idx*sizeof(Value)); \
- memmove(self->data + pos + idx + n, self->data + idx, (sz - idx)*sizeof(Value)); \
- self->data = ((CX##_value_t *) self->_base) + pos; \
- } \
- } \
-\
- STC_DEF CX##_value_t* \
- CX##_insert_space_(CX* self, CX##_value_t* pos, size_t n) { \
- size_t idx = pos - self->data; \
- if (idx*2 < _cdeq_rep(self)->size) CX##_expand_left_(self, idx, n); \
- else CX##_expand_right_(self, idx, n); \
- if (n) _cdeq_rep(self)->size += n; /* do only if size > 0 */ \
- return self->data + idx; \
- } \
-\
- STC_DEF void \
- CX##_push_front(CX* self, Value value) { \
- if (self->data == self->_base) \
- CX##_expand_left_(self, 0, 1); \
- else \
- --self->data; \
- *self->data = value; \
- ++_cdeq_rep(self)->size; \
- } \
-\
- STC_DEF void \
- CX##_push_back(CX* self, Value value) { \
- struct cdeq_rep* rep = _cdeq_rep(self); \
- if (_cdeq_nfront(self) + rep->size == rep->cap) \
- CX##_expand_right_(self, rep->size, 1); \
- self->data[_cdeq_rep(self)->size++] = value; \
- } \
-\
- STC_DEF CX \
- CX##_clone(CX cx) { \
- size_t sz = _cdeq_rep(&cx)->size; \
- CX out = CX##_with_capacity(sz); \
- CX##_insert_range_p(&out, out.data, cx.data, cx.data + sz, true); \
- return out; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_insert_range_p(CX* self, CX##_value_t* pos, const CX##_value_t* p1, \
- const CX##_value_t* p2, bool clone) { \
- pos = CX##_insert_space_(self, pos, p2 - p1); \
- CX##_iter_t it = {pos}; \
- if (clone) while (p1 != p2) *pos++ = valueFromRaw(valueToRaw(p1++)); \
- else memcpy(pos, p1, (p2 - p1)*sizeof *p1); \
- return it; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_emplace_range_p(CX* self, CX##_value_t* pos, const CX##_rawvalue_t* p1, const CX##_rawvalue_t* p2) { \
- pos = CX##_insert_space_(self, pos, p2 - p1); \
- CX##_iter_t it = {pos}; \
- while (p1 != p2) *pos++ = valueFromRaw(*p1++); \
- return it; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_erase_range_p(CX* self, CX##_value_t* p1, CX##_value_t* p2) { \
- size_t n = p2 - p1; \
- if (n > 0) { \
- CX##_value_t* p = p1, *end = self->data + _cdeq_rep(self)->size; \
- while (p != p2) valueDel(p++); \
- if (p1 == self->data) self->data += n; \
- else memmove(p1, p2, (end - p2) * sizeof(Value)); \
- _cdeq_rep(self)->size -= n; \
- } \
- return c_make(CX##_iter_t){p1}; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_find_in(CX##_iter_t i1, CX##_iter_t i2, RawValue raw) { \
- for (; i1.ref != i2.ref; ++i1.ref) { \
- RawValue r = valueToRaw(i1.ref); \
- if (valueCompareRaw(&raw, &r) == 0) return i1; \
- } \
- return i2; \
- } \
-\
- STC_DEF int \
- CX##_value_compare(const CX##_value_t* x, const CX##_value_t* y) { \
- RawValue rx = valueToRaw(x); \
- RawValue ry = valueToRaw(y); \
- return valueCompareRaw(&rx, &ry); \
+STC_DEF Self
+cx_memb(_init)(void) {
+ cx_value_t *b = (cx_value_t *) _cdeq_sentinel.base;
+ return c_make(Self){b, b};
+}
+
+STC_DEF void
+cx_memb(_clear)(Self* self) {
+ struct cdeq_rep* rep = cdeq_rep_(self);
+ if (rep->cap) {
+ for (cx_value_t *p = self->data, *q = p + rep->size; p != q; ++p)
+ i_valdel(p);
+ rep->size = 0;
}
+}
+
+STC_DEF void
+cx_memb(_del)(Self* self) {
+ cx_memb(_clear)(self);
+ if (cdeq_rep_(self)->cap)
+ c_free(cdeq_rep_(self));
+}
+
+STC_DEF size_t
+cx_memb(_realloc_)(Self* self, size_t n) {
+ struct cdeq_rep* rep = cdeq_rep_(self);
+ size_t sz = rep->size, cap = (size_t) (sz*1.7) + n + 7;
+ size_t nfront = _cdeq_nfront(self);
+ rep = (struct cdeq_rep*) c_realloc(rep->cap ? rep : NULL,
+ offsetof(struct cdeq_rep, base) + cap*sizeof(i_val));
+ rep->size = sz, rep->cap = cap;
+ self->_base = (cx_value_t *) rep->base;
+ self->data = self->_base + nfront;
+ return cap;
+}
+STC_DEF void
+cx_memb(_expand_right_half_)(Self* self, size_t idx, size_t n) {
+ struct cdeq_rep* rep = cdeq_rep_(self);
+ size_t sz = rep->size, cap = rep->cap;
+ size_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront;
+ if (nback >= n || sz*1.3 + n > cap && cx_memb(_realloc_)(self, n)) {
+ memmove(self->data + idx + n, self->data + idx, (sz - idx)*sizeof(i_val));
+ } else {
+#ifdef i_queue
+ size_t pos = 0;
#else
-#define _c_implement_cdeq(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue)
+ size_t unused = cap - (sz + n);
+ size_t pos = (nfront*2 < unused) ? nfront : unused/2;
#endif
+ memmove(self->_base + pos, self->data, idx*sizeof(i_val));
+ memmove(self->data + pos + idx + n, self->data + idx, (sz - idx)*sizeof(i_val));
+ self->data = self->_base + pos;
+ }
+}
-#endif
+STC_DEF cx_value_t*
+cx_memb(_push_back)(Self* self, i_val value) {
+ struct cdeq_rep* rep = cdeq_rep_(self);
+ if (_cdeq_nfront(self) + rep->size == rep->cap)
+ cx_memb(_expand_right_half_)(self, rep->size, 1);
+ cx_value_t *v = self->data + cdeq_rep_(self)->size++;
+ *v = value; return v;
+}
+
+STC_DEF Self
+cx_memb(_clone)(Self cx) {
+ size_t sz = cdeq_rep_(&cx)->size;
+ Self out = cx_memb(_with_capacity)(sz);
+ cdeq_rep_(&out)->size = sz;
+ for (size_t i = 0; i < sz; ++i) out.data[i] = i_valfrom(i_valto(&cx.data[i]));
+ return out;
+}
+
+#ifndef i_queue
+
+STC_DEF void
+cx_memb(_expand_left_half_)(Self* self, size_t idx, size_t n) {
+ struct cdeq_rep* rep = cdeq_rep_(self);
+ size_t sz = rep->size, cap = rep->cap;
+ size_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront;
+ if (nfront >= n) {
+ self->data = (cx_value_t *) memmove(self->data - n, self->data, idx*sizeof(i_val));
+ } else {
+ if (sz*1.3 + n > cap) cap = cx_memb(_realloc_)(self, n);
+ size_t unused = cap - (sz + n);
+ size_t pos = (nback*2 < unused) ? unused - nback : unused/2;
+ memmove(self->_base + pos + idx + n, self->data + idx, (sz - idx)*sizeof(i_val));
+ self->data = (cx_value_t *) memmove(self->_base + pos, self->data, idx*sizeof(i_val));
+ }
+}
+
+STC_DEF cx_value_t*
+cx_memb(_insert_space_)(Self* self, cx_value_t* pos, size_t n) {
+ size_t idx = pos - self->data;
+ if (idx*2 < cdeq_rep_(self)->size) cx_memb(_expand_left_half_)(self, idx, n);
+ else cx_memb(_expand_right_half_)(self, idx, n);
+ if (n) cdeq_rep_(self)->size += n; /* do only if size > 0 */
+ return self->data + idx;
+}
+
+STC_DEF cx_value_t*
+cx_memb(_push_front)(Self* self, i_val value) {
+ if (self->data == self->_base)
+ cx_memb(_expand_left_half_)(self, 0, 1);
+ else
+ --self->data;
+ ++cdeq_rep_(self)->size;
+ *self->data = value;
+ return self->data;
+}
+
+STC_DEF cx_iter_t
+cx_memb(_insert_range_p)(Self* self, cx_value_t* pos, const cx_value_t* p1,
+ const cx_value_t* p2, bool clone) {
+ pos = cx_memb(_insert_space_)(self, pos, p2 - p1);
+ cx_iter_t it = {pos};
+ if (clone) while (p1 != p2) *pos++ = i_valfrom(i_valto(p1++));
+ else memcpy(pos, p1, (p2 - p1)*sizeof *p1);
+ return it;
+}
+
+STC_DEF cx_iter_t
+cx_memb(_emplace_range_p)(Self* self, cx_value_t* pos, const cx_rawvalue_t* p1, const cx_rawvalue_t* p2) {
+ pos = cx_memb(_insert_space_)(self, pos, p2 - p1);
+ cx_iter_t it = {pos};
+ while (p1 != p2) *pos++ = i_valfrom(*p1++);
+ return it;
+}
+
+STC_DEF cx_iter_t
+cx_memb(_erase_range_p)(Self* self, cx_value_t* p1, cx_value_t* p2) {
+ size_t n = p2 - p1;
+ if (n > 0) {
+ cx_value_t* p = p1, *end = self->data + cdeq_rep_(self)->size;
+ while (p != p2) i_valdel(p++);
+ if (p1 == self->data) self->data += n;
+ else memmove(p1, p2, (end - p2) * sizeof(i_val));
+ cdeq_rep_(self)->size -= n;
+ }
+ return c_make(cx_iter_t){p1};
+}
+
+STC_DEF cx_iter_t
+cx_memb(_find_in)(cx_iter_t i1, cx_iter_t i2, i_valraw raw) {
+ for (; i1.ref != i2.ref; ++i1.ref) {
+ i_valraw r = i_valto(i1.ref);
+ if (i_cmp(&raw, &r) == 0) return i1;
+ }
+ return i2;
+}
+
+STC_DEF int
+cx_memb(_value_compare)(const cx_value_t* x, const cx_value_t* y) {
+ i_valraw rx = i_valto(x);
+ i_valraw ry = i_valto(y);
+ return i_cmp(&rx, &ry);
+}
+
+#endif // i_queue
+#endif // IMPLEMENTATION
+#include "template.h"
+#define CDEQ_H_INCLUDED \ No newline at end of file
diff --git a/include/stc/clist.h b/include/stc/clist.h
index 75364a4f..83e08c24 100644
--- a/include/stc/clist.h
+++ b/include/stc/clist.h
@@ -20,8 +20,6 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#ifndef CLIST_H_INCLUDED
-#define CLIST_H_INCLUDED
/* Circular Singly-linked Lists.
@@ -30,9 +28,11 @@
for being used as a queue, unlike std::forward_list. Basic usage is similar to cvec:
#include <stdio.h>
- #include <stc/clist.h>
#include <stc/crandom.h>
- using_clist(ix, int64_t);
+
+ #define i_tag ix
+ #define i_val int64_t
+ #include <stc/clist.h>
int main() {
c_forvar (clist_ix list = clist_ix_init(), clist_ix_del(&list))
@@ -53,288 +53,269 @@
}
}
*/
+
+#ifndef CLIST_H_INCLUDED
#include "ccommon.h"
+#include "forward.h"
#include <stdlib.h>
+#include <string.h>
-#define forward_clist(X, Value) _c_clist_types(clist_##X, Value)
-
-#define using_clist(...) c_MACRO_OVERLOAD(using_clist, __VA_ARGS__)
-
-#define using_clist_2(X, Value) \
- using_clist_3(X, Value, c_default_compare)
-#define using_clist_3(X, Value, valueCompare) \
- using_clist_5(X, Value, valueCompare, c_default_del, c_default_fromraw)
-#define using_clist_4(X, Value, valueCompare, valueDel) \
- using_clist_5(X, Value, valueCompare, valueDel, c_no_clone)
-#define using_clist_5(X, Value, valueCompare, valueDel, valueClone) \
- using_clist_7(X, Value, valueCompare, valueDel, valueClone, c_default_toraw, Value)
-#define using_clist_7(X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue) \
- _c_using_clist(clist_##X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue, c_true)
-#define using_clist_8(X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue, defTypes) \
- _c_using_clist(clist_##X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue, defTypes)
-
-#define using_clist_str() \
- using_clist_7(str, cstr, c_rawstr_compare, cstr_del, cstr_from, cstr_str, const char*)
-
-
-#define _c_clist_types(CX, Value) \
- typedef Value CX##_value_t; \
- typedef struct CX##_node_t CX##_node_t; \
-\
- typedef struct { \
- CX##_node_t *const *_last, *prev; \
- CX##_value_t *ref; \
- } CX##_iter_t; \
-\
- typedef struct { \
- CX##_node_t *last; \
- } CX
-
-#define _c_clist_complete_types(CX) \
- struct CX##_node_t { \
- struct CX##_node_t *next; \
- CX##_value_t value; \
+#define _c_clist_complete_types(SELF, dummy) \
+ struct SELF##_node_t { \
+ struct SELF##_node_t *next; \
+ SELF##_value_t value; \
}
+#define clist_node_(vp) c_container_of(vp, cx_node_t, value)
+
_c_clist_types(clist_VOID, int);
-_c_clist_complete_types(clist_VOID);
-STC_API size_t _clist_count(const clist_VOID* self);
-#define _clist_node(CX, vp) c_container_of(vp, CX##_node_t, value)
-
-
-#define _c_using_clist(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue, defTypes) \
-\
- defTypes( _c_clist_types(CX, Value); ) \
- _c_clist_complete_types(CX); \
- typedef RawValue CX##_rawvalue_t; \
-\
- STC_API CX CX##_clone(CX cx); \
- STC_API void CX##_del(CX* self); \
- STC_API void CX##_push_back(CX* self, Value value); \
- STC_API void CX##_push_front(CX* self, Value value); \
- STC_API CX##_iter_t CX##_insert(CX* self, CX##_iter_t it, Value value); \
- STC_API void CX##_emplace_items(CX *self, const CX##_rawvalue_t arr[], size_t n); \
- STC_API CX##_iter_t CX##_erase_at(CX* self, CX##_iter_t it); \
- STC_API CX##_iter_t CX##_erase_range(CX* self, CX##_iter_t it1, CX##_iter_t it2); \
- STC_API size_t CX##_remove(CX* self, RawValue val); \
- STC_API CX##_iter_t CX##_splice(CX* self, CX##_iter_t it, CX* other); \
- STC_API CX CX##_split_off(CX* self, CX##_iter_t it1, CX##_iter_t it2); \
- STC_API void CX##_sort(CX* self); \
- STC_API CX##_iter_t CX##_find_in(CX##_iter_t it1, CX##_iter_t it2, RawValue val); \
- STC_API CX##_node_t* CX##_erase_after_(CX* self, CX##_node_t* node); \
-\
- STC_INLINE CX CX##_init(void) {return c_make(CX){NULL};} \
- STC_INLINE bool CX##_empty(CX cx) {return cx.last == NULL;} \
- STC_INLINE size_t CX##_count(CX cx) \
- {return _clist_count((const clist_VOID*) &cx);} \
- STC_INLINE void CX##_clear(CX* self) {CX##_del(self);} \
- STC_INLINE Value CX##_value_fromraw(RawValue raw) {return valueFromRaw(raw);} \
- STC_INLINE RawValue CX##_value_toraw(CX##_value_t* pval) {return valueToRaw(pval);} \
- STC_INLINE Value CX##_value_clone(Value val) \
- {return valueFromRaw(valueToRaw(&val));} \
- STC_INLINE void CX##_pop_front(CX* self) \
- {CX##_erase_after_(self, self->last);} \
- STC_INLINE CX##_iter_t CX##_erase(CX* self, CX##_iter_t it) \
- {return CX##_erase_at(self, it);} \
- STC_INLINE void CX##_emplace_back(CX* self, RawValue raw) \
- {CX##_push_back(self, valueFromRaw(raw));} \
- STC_INLINE void CX##_emplace_front(CX* self, RawValue raw) \
- {CX##_push_front(self, valueFromRaw(raw));} \
- STC_INLINE CX##_iter_t CX##_emplace(CX* self, CX##_iter_t it, RawValue raw) \
- {return CX##_insert(self, it, valueFromRaw(raw));} \
- STC_INLINE CX##_value_t* CX##_front(const CX* self) {return &self->last->next->value;} \
- STC_INLINE CX##_value_t* CX##_back(const CX* self) {return &self->last->value;} \
-\
- STC_INLINE CX##_iter_t \
- CX##_iter(const CX* self, CX##_node_t* prev) { \
- return c_make(CX##_iter_t){&self->last, prev, &prev->next->value}; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_begin(const CX* self) { \
- CX##_value_t* head = self->last ? &self->last->next->value : NULL; \
- return c_make(CX##_iter_t){&self->last, self->last, head}; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_end(const CX* self) { \
- return c_make(CX##_iter_t){NULL}; \
- } \
-\
- STC_INLINE void \
- CX##_next(CX##_iter_t* it) { \
- CX##_node_t* node = it->prev = _clist_node(CX, it->ref); \
- it->ref = (node == *it->_last ? NULL : &node->next->value); \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_fwd(CX##_iter_t it, size_t n) { \
- while (n-- && it.ref) CX##_next(&it); \
- return it; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_splice_range(CX* self, CX##_iter_t it, \
- CX* other, CX##_iter_t it1, CX##_iter_t it2) { \
- CX tmp = CX##_split_off(other, it1, it2); \
- return CX##_splice(self, it, &tmp); \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_find(const CX* self, RawValue val) { \
- return CX##_find_in(CX##_begin(self), CX##_end(self), val); \
- } \
-\
- STC_INLINE CX##_value_t* \
- CX##_get(const CX* self, RawValue val) { \
- return CX##_find_in(CX##_begin(self), CX##_end(self), val).ref; \
- } \
-\
- _c_implement_clist(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue) \
- struct stc_trailing_semicolon
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-
-#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
-#define _c_implement_clist(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue) \
-\
- STC_DEF CX \
- CX##_clone(CX cx) { \
- CX out = CX##_init(); \
- c_foreach_3 (it, CX, cx) CX##_emplace_back(&out, valueToRaw(it.ref)); \
- return out; \
- } \
-\
- STC_DEF void \
- CX##_del(CX* self) { \
- while (self->last) CX##_erase_after_(self, self->last); \
- } \
-\
- STC_DEF void \
- CX##_push_back(CX* self, Value value) { \
- _c_clist_insert_after(self, CX, self->last, value); \
- self->last = entry; \
- } \
-\
- STC_DEF void \
- CX##_push_front(CX* self, Value value) { \
- _c_clist_insert_after(self, CX, self->last, value); \
- if (!self->last) self->last = entry; \
- } \
-\
- STC_DEF void \
- CX##_emplace_items(CX *self, const CX##_rawvalue_t arr[], size_t n) { \
- for (size_t i=0; i<n; ++i) CX##_push_back(self, valueFromRaw(arr[i])); \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_insert(CX* self, CX##_iter_t it, Value value) { \
- CX##_node_t* node = it.ref ? it.prev : self->last; \
- _c_clist_insert_after(self, CX, node, value); \
- if (!self->last || !it.ref) { \
- it.prev = self->last ? self->last : entry; \
- self->last = entry; \
- } \
- it.ref = &entry->value; \
- return it; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_erase_at(CX* self, CX##_iter_t it) { \
- CX##_node_t *node = _clist_node(CX, it.ref); \
- it.ref = (node == self->last) ? NULL : &node->next->value; \
- CX##_erase_after_(self, it.prev); \
- return it; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_erase_range(CX* self, CX##_iter_t it1, CX##_iter_t it2) { \
- CX##_node_t *node = it1.ref ? it1.prev : NULL, \
- *done = it2.ref ? _clist_node(CX, it2.ref) : NULL; \
- while (node && node->next != done) \
- node = CX##_erase_after_(self, node); \
- return it2; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_find_in(CX##_iter_t it1, CX##_iter_t it2, RawValue val) { \
- c_foreach_4 (it, CX, it1, it2) { \
- RawValue r = valueToRaw(it.ref); \
- if (valueCompareRaw(&r, &val) == 0) return it; \
- } \
- it2.ref = NULL; return it2; \
- } \
-\
- STC_DEF CX##_node_t* \
- CX##_erase_after_(CX* self, CX##_node_t* node) { \
- CX##_node_t* del = node->next, *next = del->next; \
- node->next = next; \
- if (del == next) self->last = node = NULL; \
- else if (self->last == del) self->last = node, node = NULL; \
- valueDel(&del->value); c_free(del); \
- return node; \
- } \
-\
- STC_DEF size_t \
- CX##_remove(CX* self, RawValue val) { \
- size_t n = 0; \
- CX##_node_t* prev = self->last, *node; \
- while (prev) { \
- node = prev->next; \
- RawValue r = valueToRaw(&node->value); \
- if (valueCompareRaw(&r, &val) == 0) \
- prev = CX##_erase_after_(self, prev), ++n; \
- else \
- prev = (node == self->last ? NULL : node); \
- } \
- return n; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_splice(CX* self, CX##_iter_t it, CX* other) { \
- if (!self->last) \
- self->last = other->last; \
- else if (other->last) { \
- CX##_node_t *p = it.ref ? it.prev : self->last, *next = p->next; \
- it.prev = other->last; \
- p->next = it.prev->next; \
- it.prev->next = next; \
- if (!it.ref) self->last = it.prev; \
- } \
- other->last = NULL; return it; \
- } \
-\
- STC_DEF CX \
- CX##_split_off(CX* self, CX##_iter_t it1, CX##_iter_t it2) { \
- CX cx = {NULL}; \
- if (it1.ref == it2.ref) return cx; \
- CX##_node_t *p1 = it1.prev, \
- *p2 = it2.ref ? it2.prev : self->last; \
- p1->next = p2->next, p2->next = _clist_node(CX, it1.ref); \
- if (self->last == p2) self->last = (p1 == p2) ? NULL : p1; \
- cx.last = p2; \
- return cx; \
- } \
-\
- STC_DEF int \
- CX##_sort_cmp_(const clist_VOID_node_t* x, const clist_VOID_node_t* y) { \
- RawValue a = valueToRaw(&((const CX##_node_t *) x)->value); \
- RawValue b = valueToRaw(&((const CX##_node_t *) y)->value); \
- return valueCompareRaw(&a, &b); \
- } \
- STC_DEF void \
- CX##_sort(CX* self) { \
- if (self->last) \
- self->last = (CX##_node_t *) _clist_mergesort((clist_VOID_node_t *) self->last->next, CX##_sort_cmp_); \
- }
+_c_clist_complete_types(clist_VOID, dummy);
-
-#define _c_clist_insert_after(self, CX, node, val) \
- CX##_node_t *entry = c_new (CX##_node_t); \
+#define _c_clist_insert_after(self, Self, node, val) \
+ cx_node_t *entry = c_new (cx_node_t); \
if (node) entry->next = node->next, node->next = entry; \
else entry->next = entry; \
entry->value = val
- /* +: set self->last based on node */
+ // +: set self->last based on node
+
+#endif // CLIST_H_INCLUDED
+
+#ifndef i_prefix
+#define i_prefix clist_
+#endif
+#include "template.h"
+
+#if !defined i_fwd
+ cx_deftypes(_c_clist_types, Self, i_val);
+#endif
+cx_deftypes(_c_clist_complete_types, Self, dummy);
+typedef i_valraw cx_rawvalue_t;
+
+STC_API size_t _clist_count(const clist_VOID* self);
+
+STC_API Self cx_memb(_clone)(Self cx);
+STC_API void cx_memb(_del)(Self* self);
+STC_API cx_value_t* cx_memb(_push_back)(Self* self, i_val value);
+STC_API cx_value_t* cx_memb(_push_front)(Self* self, i_val value);
+STC_API cx_iter_t cx_memb(_insert)(Self* self, cx_iter_t it, i_val value);
+STC_API void cx_memb(_emplace_items)(Self *self, const cx_rawvalue_t arr[], size_t n);
+STC_API cx_iter_t cx_memb(_erase_at)(Self* self, cx_iter_t it);
+STC_API cx_iter_t cx_memb(_erase_range)(Self* self, cx_iter_t it1, cx_iter_t it2);
+STC_API size_t cx_memb(_remove)(Self* self, i_valraw val);
+STC_API cx_iter_t cx_memb(_splice)(Self* self, cx_iter_t it, Self* other);
+STC_API Self cx_memb(_split_off)(Self* self, cx_iter_t it1, cx_iter_t it2);
+STC_API void cx_memb(_sort)(Self* self);
+STC_API cx_iter_t cx_memb(_find_in)(cx_iter_t it1, cx_iter_t it2, i_valraw val);
+STC_API cx_node_t* cx_memb(_erase_after_)(Self* self, cx_node_t* node);
+
+STC_INLINE Self cx_memb(_init)(void) { return c_make(Self){NULL}; }
+STC_INLINE bool cx_memb(_empty)(Self cx) { return cx.last == NULL; }
+STC_INLINE size_t cx_memb(_count)(Self cx)
+ { return _clist_count((const clist_VOID*) &cx); }
+STC_INLINE void cx_memb(_clear)(Self* self) { cx_memb(_del)(self); }
+STC_INLINE i_val cx_memb(_value_fromraw)(i_valraw raw) { return i_valfrom(raw); }
+STC_INLINE i_valraw cx_memb(_value_toraw)(cx_value_t* pval) { return i_valto(pval); }
+STC_INLINE i_val cx_memb(_value_clone)(i_val val)
+ { return i_valfrom(i_valto(&val)); }
+STC_INLINE void cx_memb(_pop_front)(Self* self)
+ { cx_memb(_erase_after_)(self, self->last); }
+STC_INLINE cx_value_t* cx_memb(_emplace_back)(Self* self, i_valraw raw)
+ { return cx_memb(_push_back)(self, i_valfrom(raw)); }
+STC_INLINE cx_value_t* cx_memb(_emplace_front)(Self* self, i_valraw raw)
+ { return cx_memb(_push_front)(self, i_valfrom(raw)); }
+STC_INLINE cx_iter_t cx_memb(_emplace)(Self* self, cx_iter_t it, i_valraw raw)
+ { return cx_memb(_insert)(self, it, i_valfrom(raw)); }
+STC_INLINE cx_value_t* cx_memb(_front)(const Self* self) { return &self->last->next->value; }
+STC_INLINE cx_value_t* cx_memb(_back)(const Self* self) { return &self->last->value; }
+
+STC_INLINE cx_iter_t
+cx_memb(_iter)(const Self* self, cx_node_t* prev) {
+ return c_make(cx_iter_t){&self->last, prev, &prev->next->value};
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_begin)(const Self* self) {
+ cx_value_t* head = self->last ? &self->last->next->value : NULL;
+ return c_make(cx_iter_t){&self->last, self->last, head};
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_end)(const Self* self) {
+ return c_make(cx_iter_t){NULL};
+}
+
+STC_INLINE void
+cx_memb(_next)(cx_iter_t* it) {
+ cx_node_t* node = it->prev = clist_node_(it->ref);
+ it->ref = (node == *it->_last ? NULL : &node->next->value);
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_advance)(cx_iter_t it, size_t n) {
+ while (n-- && it.ref) cx_memb(_next)(&it);
+ return it;
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_splice_range)(Self* self, cx_iter_t it,
+ Self* other, cx_iter_t it1, cx_iter_t it2) {
+ Self tmp = cx_memb(_split_off)(other, it1, it2);
+ return cx_memb(_splice)(self, it, &tmp);
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_find)(const Self* self, i_valraw val) {
+ return cx_memb(_find_in)(cx_memb(_begin)(self), cx_memb(_end)(self), val);
+}
+
+STC_INLINE cx_value_t*
+cx_memb(_get)(const Self* self, i_valraw val) {
+ return cx_memb(_find_in)(cx_memb(_begin)(self), cx_memb(_end)(self), val).ref;
+}
+
+// -------------------------- IMPLEMENTATION -------------------------
+
+#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) || defined(i_imp)
+
+STC_DEF Self
+cx_memb(_clone)(Self cx) {
+ Self out = cx_memb(_init)();
+ c_foreach (it, Self, cx) cx_memb(_emplace_back)(&out, i_valto(it.ref));
+ return out;
+}
+
+STC_DEF void
+cx_memb(_del)(Self* self) {
+ while (self->last) cx_memb(_erase_after_)(self, self->last);
+}
+
+STC_DEF cx_value_t*
+cx_memb(_push_back)(Self* self, i_val value) {
+ _c_clist_insert_after(self, Self, self->last, value);
+ self->last = entry;
+ return &entry->value;
+}
+
+STC_DEF cx_value_t*
+cx_memb(_push_front)(Self* self, i_val value) {
+ _c_clist_insert_after(self, Self, self->last, value);
+ if (!self->last) self->last = entry;
+ return &entry->value;
+}
+
+STC_DEF void
+cx_memb(_emplace_items)(Self *self, const cx_rawvalue_t arr[], size_t n) {
+ for (size_t i=0; i<n; ++i) cx_memb(_push_back)(self, i_valfrom(arr[i]));
+}
+
+STC_DEF cx_iter_t
+cx_memb(_insert)(Self* self, cx_iter_t it, i_val value) {
+ cx_node_t* node = it.ref ? it.prev : self->last;
+ _c_clist_insert_after(self, Self, node, value);
+ if (!self->last || !it.ref) {
+ it.prev = self->last ? self->last : entry;
+ self->last = entry;
+ }
+ it.ref = &entry->value;
+ return it;
+}
+
+STC_DEF cx_iter_t
+cx_memb(_erase_at)(Self* self, cx_iter_t it) {
+ cx_node_t *node = clist_node_(it.ref);
+ it.ref = (node == self->last) ? NULL : &node->next->value;
+ cx_memb(_erase_after_)(self, it.prev);
+ return it;
+}
+
+STC_DEF cx_iter_t
+cx_memb(_erase_range)(Self* self, cx_iter_t it1, cx_iter_t it2) {
+ cx_node_t *node = it1.ref ? it1.prev : NULL,
+ *done = it2.ref ? clist_node_(it2.ref) : NULL;
+ while (node && node->next != done)
+ node = cx_memb(_erase_after_)(self, node);
+ return it2;
+}
+
+STC_DEF cx_iter_t
+cx_memb(_find_in)(cx_iter_t it1, cx_iter_t it2, i_valraw val) {
+ c_foreach (it, Self, it1, it2) {
+ i_valraw r = i_valto(it.ref);
+ if (i_cmp(&r, &val) == 0) return it;
+ }
+ it2.ref = NULL; return it2;
+}
+
+STC_DEF cx_node_t*
+cx_memb(_erase_after_)(Self* self, cx_node_t* node) {
+ cx_node_t* del = node->next, *next = del->next;
+ node->next = next;
+ if (del == next) self->last = node = NULL;
+ else if (self->last == del) self->last = node, node = NULL;
+ i_valdel(&del->value); c_free(del);
+ return node;
+}
+
+STC_DEF size_t
+cx_memb(_remove)(Self* self, i_valraw val) {
+ size_t n = 0;
+ cx_node_t* prev = self->last, *node;
+ while (prev) {
+ node = prev->next;
+ i_valraw r = i_valto(&node->value);
+ if (i_cmp(&r, &val) == 0)
+ prev = cx_memb(_erase_after_)(self, prev), ++n;
+ else
+ prev = (node == self->last ? NULL : node);
+ }
+ return n;
+}
+
+STC_DEF cx_iter_t
+cx_memb(_splice)(Self* self, cx_iter_t it, Self* other) {
+ if (!self->last)
+ self->last = other->last;
+ else if (other->last) {
+ cx_node_t *p = it.ref ? it.prev : self->last, *next = p->next;
+ it.prev = other->last;
+ p->next = it.prev->next;
+ it.prev->next = next;
+ if (!it.ref) self->last = it.prev;
+ }
+ other->last = NULL; return it;
+}
+
+STC_DEF Self
+cx_memb(_split_off)(Self* self, cx_iter_t it1, cx_iter_t it2) {
+ Self cx = {NULL};
+ if (it1.ref == it2.ref) return cx;
+ cx_node_t *p1 = it1.prev,
+ *p2 = it2.ref ? it2.prev : self->last;
+ p1->next = p2->next, p2->next = clist_node_(it1.ref);
+ if (self->last == p2) self->last = (p1 == p2) ? NULL : p1;
+ cx.last = p2;
+ return cx;
+}
+
+STC_DEF int
+cx_memb(_sort_cmp_)(const clist_VOID_node_t* x, const clist_VOID_node_t* y) {
+ i_valraw a = i_valto(&((const cx_node_t *) x)->value);
+ i_valraw b = i_valto(&((const cx_node_t *) y)->value);
+ return i_cmp(&a, &b);
+}
+
+STC_API clist_VOID_node_t*
+_clist_mergesort(clist_VOID_node_t *list, int (*cmp)(const clist_VOID_node_t*, const clist_VOID_node_t*));
+
+STC_DEF void
+cx_memb(_sort)(Self* self) {
+ if (self->last)
+ self->last = (cx_node_t *) _clist_mergesort((clist_VOID_node_t *) self->last->next, cx_memb(_sort_cmp_));
+}
+
+#endif // TEMPLATE IMPLEMENTATION
+
+#if !defined(STC_HEADER) && !defined(CLIST_H_INCLUDED) || defined(i_imp) && i_imp == 2
STC_DEF size_t
_clist_count(const clist_VOID* self) {
@@ -345,9 +326,8 @@ _clist_count(const clist_VOID* self) {
return n;
}
-/* Singly linked list Mergesort implementation by Simon Tatham. O(n*log n).
- * https://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
- */
+// Singly linked list Mergesort implementation by Simon Tatham. O(n*log n).
+// https://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
STC_DEF clist_VOID_node_t *
_clist_mergesort(clist_VOID_node_t *list, int (*cmp)(const clist_VOID_node_t*, const clist_VOID_node_t*)) {
clist_VOID_node_t *p, *q, *e, *tail, *oldhead;
@@ -395,9 +375,6 @@ _clist_mergesort(clist_VOID_node_t *list, int (*cmp)(const clist_VOID_node_t*, c
insize *= 2;
}
}
-
-#else
-#define _c_implement_clist(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue)
-#endif
-
-#endif
+#endif // NON-TEMPLATE IMPLEMENTATION
+#include "template.h"
+#define CLIST_H_INCLUDED \ No newline at end of file
diff --git a/include/stc/cmap.h b/include/stc/cmap.h
index 476558c7..989335c1 100644
--- a/include/stc/cmap.h
+++ b/include/stc/cmap.h
@@ -20,444 +20,210 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#ifndef CMAP_H_INCLUDED
-#define CMAP_H_INCLUDED
// Unordered set/map - implemented as closed hashing with linear probing and no tombstones.
/*
-#include <stc/cmap.h>
#include <stdio.h>
-using_cmap(mx, int, char); // Map of int -> char
+#define i_tag ichar // Map int => char
+#define i_key int
+#define i_val char
+#include <stc/cmap.h>
int main(void) {
- c_forvar (cmap_mx m = cmap_mx_init(), cmap_mx_del(&m))
+ c_forvar (cmap_ichar m = cmap_ichar_init(), cmap_ichar_del(&m))
{
- cmap_mx_emplace(&m, 5, 'a');
- cmap_mx_emplace(&m, 8, 'b');
- cmap_mx_emplace(&m, 12, 'c');
+ cmap_ichar_emplace(&m, 5, 'a');
+ cmap_ichar_emplace(&m, 8, 'b');
+ cmap_ichar_emplace(&m, 12, 'c');
- cmap_mx_iter_t it = cmap_mx_find(&m, 10); // none
- char val = cmap_mx_find(&m, 5).ref->second;
- cmap_mx_emplace_or_assign(&m, 5, 'd'); // update
- cmap_mx_erase(&m, 8);
+ cmap_ichar_value_t* v = cmap_ichar_get(&m, 10); // NULL
+ char val = *cmap_ichar_at(&m, 5); // 'a'
+ cmap_ichar_emplace_or_assign(&m, 5, 'd'); // update
+ cmap_ichar_erase(&m, 8);
- c_foreach (i, cmap_mx, m)
+ c_foreach (i, cmap_ichar, m)
printf("map %d: %c\n", i.ref->first, i.ref->second);
}
}
*/
+
+#ifndef CMAP_H_INCLUDED
#include "ccommon.h"
+#include "forward.h"
#include <stdlib.h>
#include <string.h>
-#define using_cmap(...) c_MACRO_OVERLOAD(using_cmap, __VA_ARGS__)
-
-#define using_cmap_3(X, Key, Mapped) \
- using_cmap_5(X, Key, Mapped, c_default_equals, c_default_hash)
-#define using_cmap_5(X, Key, Mapped, keyEquals, keyHash) \
- using_cmap_7(X, Key, Mapped, keyEquals, keyHash, \
- c_default_del, c_default_fromraw)
-#define using_cmap_6(X, Key, Mapped, keyEquals, keyHash, mappedDel) \
- using_cmap_7(X, Key, Mapped, keyEquals, keyHash, \
- mappedDel, c_no_clone)
-#define using_cmap_7(X, Key, Mapped, keyEquals, keyHash, mappedDel, mappedClone) \
- using_cmap_10(X, Key, Mapped, keyEquals, keyHash, \
- mappedDel, mappedClone, c_default_toraw, Mapped, c_true)
-#define using_cmap_10(X, Key, Mapped, keyEquals, keyHash, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, defTypes) \
- using_cmap_14(X, Key, Mapped, keyEquals, keyHash, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- c_default_del, c_default_fromraw, c_default_toraw, Key, defTypes)
-#define using_cmap_14(X, Key, Mapped, keyEqualsRaw, keyHashRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey, defTypes) \
- _c_using_chash(cmap_##X, cmap_, Key, Mapped, keyEqualsRaw, keyHashRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey, defTypes)
-
-
-#define using_cmap_keydef(...) c_MACRO_OVERLOAD(using_cmap_keydef, __VA_ARGS__)
-
-#define using_cmap_keydef_7(X, Key, Mapped, keyEquals, keyHash, keyDel, keyClone) \
- using_cmap_keydef_10(X, Key, Mapped, keyEquals, keyHash, \
- keyDel, keyClone, c_default_toraw, Key, c_true)
-#define using_cmap_keydef_10(X, Key, Mapped, keyEqualsRaw, keyHashRaw, \
- keyDel, keyFromRaw, keyToRaw, RawKey, defTypes) \
- _c_using_chash(cmap_##X, cmap_, Key, Mapped, keyEqualsRaw, keyHashRaw, \
- c_default_del, c_default_fromraw, c_default_toraw, Mapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey, defTypes)
-
-#define using_cmap_str() \
- _c_using_chash(cmap_str, cmap_, cstr, cstr, c_rawstr_equals, c_rawstr_hash, \
- cstr_del, cstr_from, cstr_str, const char*, \
- cstr_del, cstr_from, cstr_str, const char*, c_true)
-
-
-#define using_cmap_strkey(...) c_MACRO_OVERLOAD(using_cmap_strkey, __VA_ARGS__)
-
-#define using_cmap_strkey_2(X, Mapped) \
- using_cmap_strkey_4(X, Mapped, c_default_del, c_default_fromraw)
-#define using_cmap_strkey_3(X, Mapped, mappedDel) \
- using_cmap_strkey_4(X, Mapped, mappedDel, c_no_clone)
-#define using_cmap_strkey_4(X, Mapped, mappedDel, mappedClone) \
- using_cmap_strkey_7(X, Mapped, mappedDel, mappedClone, c_default_toraw, Mapped, c_true)
-#define using_cmap_strkey_7(X, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped, defTypes) \
- _c_using_chash_strkey(X, cmap_, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped, defTypes)
-#define _c_using_chash_strkey(X, C, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped, defTypes) \
- _c_using_chash(C##X, C, cstr, Mapped, c_rawstr_equals, c_rawstr_hash, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- cstr_del, cstr_from, cstr_str, const char*, defTypes)
-
-
-#define using_cmap_strval(...) c_MACRO_OVERLOAD(using_cmap_strval, __VA_ARGS__)
-
-#define using_cmap_strval_2(X, Key) \
- using_cmap_strval_4(X, Key, c_default_equals, c_default_hash)
-#define using_cmap_strval_4(X, Key, keyEquals, keyHash) \
- using_cmap_strval_6(X, Key, keyEquals, keyHash, c_default_del, c_default_fromraw)
-#define using_cmap_strval_5(X, Key, keyEquals, keyHash, keyDel) \
- using_cmap_strval_6(X, Key, keyEquals, keyHash, keyDel, c_no_clone)
-#define using_cmap_strval_6(X, Key, keyEquals, keyHash, keyDel, keyClone) \
- using_cmap_strval_9(X, Key, keyEquals, keyHash, keyDel, keyClone, c_default_toraw, Key, c_true)
-#define using_cmap_strval_9(X, Key, keyEqualsRaw, keyHashRaw, keyDel, keyFromRaw, keyToRaw, RawKey, defTypes) \
- _c_using_chash(cmap_##X, cmap_, Key, cstr, keyEqualsRaw, keyHashRaw, \
- cstr_del, cstr_from, cstr_str, const char*, \
- keyDel, keyFromRaw, keyToRaw, RawKey, defTypes)
-
-#define SET_ONLY_cmap_(...)
-#define MAP_ONLY_cmap_(...) __VA_ARGS__
-#define KEY_REF_cmap_(vp) (&(vp)->first)
-#ifndef CMAP_SIZE_T
-#define CMAP_SIZE_T uint32_t
-#endif
#define _cmap_inits {NULL, NULL, 0, 0, 0.85f}
-typedef struct {size_t idx; uint_fast8_t hx;} chash_bucket_t; \
-
-STC_API uint64_t c_default_hash(const void *data, size_t len);
-STC_INLINE uint64_t c_string_hash(const char *s)
- {return c_default_hash(s, strlen(s));}
-STC_INLINE uint64_t c_default_hash32(const void* data, size_t ignored)
- {return *(const uint32_t *)data * 0xc6a4a7935bd1e99d;}
-STC_INLINE uint64_t c_default_hash64(const void* data, size_t ignored)
- {return *(const uint64_t *)data * 0xc6a4a7935bd1e99d;}
-
-#define _c_chash_types(CX, C, Key, Mapped) \
- typedef Key CX##_key_t; \
- typedef Mapped CX##_mapped_t; \
- typedef CMAP_SIZE_T CX##_size_t; \
-\
- typedef SET_ONLY_##C( CX##_key_t ) \
- MAP_ONLY_##C( struct CX##_value_t ) \
- CX##_value_t; \
-\
- typedef struct { \
- CX##_value_t *ref; \
- bool inserted; \
- } CX##_result_t; \
-\
- typedef struct { \
- CX##_value_t *ref; \
- uint8_t* _hx; \
- } CX##_iter_t; \
-\
- typedef struct { \
- CX##_value_t* table; \
- uint8_t* _hashx; \
- CX##_size_t size, bucket_count; \
- float max_load_factor; \
- } CX
-
-#define _c_using_chash(CX, C, Key, Mapped, keyEqualsRaw, keyHashRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey, defTypes) \
- defTypes( _c_chash_types(CX, C, Key, Mapped); ) \
-\
- MAP_ONLY_##C( struct CX##_value_t { \
- CX##_key_t first; \
- CX##_mapped_t second; \
- }; ) \
-\
- typedef RawKey CX##_rawkey_t; \
- typedef RawMapped CX##_rawmapped_t; \
- typedef SET_ONLY_##C( RawKey ) \
- MAP_ONLY_##C( struct { RawKey first; \
- RawMapped second; } ) \
- CX##_rawvalue_t; \
-\
- STC_API CX CX##_with_capacity(size_t cap); \
- STC_API CX CX##_clone(CX map); \
- STC_API void CX##_del(CX* self); \
- STC_API void CX##_clear(CX* self); \
- STC_API void CX##_reserve(CX* self, size_t capacity); \
- STC_API chash_bucket_t CX##_bucket_(const CX* self, const CX##_rawkey_t* rkeyptr); \
- STC_API CX##_result_t CX##_insert_entry_(CX* self, RawKey rkey); \
- STC_API void CX##_erase_entry(CX* self, CX##_value_t* val); \
-\
- STC_INLINE CX CX##_init(void) {return c_make(CX)_cmap_inits;} \
- STC_INLINE void CX##_shrink_to_fit(CX* self) {CX##_reserve(self, self->size);} \
- STC_INLINE void CX##_max_load_factor(CX* self, float ml) {self->max_load_factor = ml;} \
- STC_INLINE bool CX##_empty(CX m) {return m.size == 0;} \
- STC_INLINE size_t CX##_size(CX m) {return m.size;} \
- STC_INLINE size_t CX##_bucket_count(CX map) {return map.bucket_count;} \
- STC_INLINE size_t CX##_capacity(CX map) \
- {return (size_t) (map.bucket_count * map.max_load_factor);} \
- STC_INLINE void CX##_swap(CX *map1, CX *map2) {c_swap(CX, *map1, *map2);} \
- STC_INLINE bool CX##_contains(const CX* self, RawKey rkey) \
- {return self->size && self->_hashx[CX##_bucket_(self, &rkey).idx];} \
-\
- STC_INLINE void \
- CX##_value_clone(CX##_value_t* _dst, CX##_value_t* _val) { \
- *KEY_REF_##C(_dst) = keyFromRaw(keyToRaw(KEY_REF_##C(_val))); \
- MAP_ONLY_##C( _dst->second = mappedFromRaw(mappedToRaw(&_val->second)); ) \
- } \
-\
- STC_INLINE CX##_rawvalue_t \
- CX##_value_toraw(CX##_value_t* val) { \
- return SET_ONLY_##C( keyToRaw(val) ) \
- MAP_ONLY_##C( c_make(CX##_rawvalue_t){keyToRaw(&val->first), mappedToRaw(&val->second)} ); \
- } \
-\
- STC_INLINE void \
- CX##_value_del(CX##_value_t* _val) { \
- keyDel(KEY_REF_##C(_val)); \
- MAP_ONLY_##C( mappedDel(&_val->second); ) \
- } \
-\
- STC_INLINE CX##_result_t \
- CX##_emplace(CX* self, RawKey rkey MAP_ONLY_##C(, RawMapped rmapped)) { \
- CX##_result_t _res = CX##_insert_entry_(self, rkey); \
- if (_res.inserted) { \
- *KEY_REF_##C(_res.ref) = keyFromRaw(rkey); \
- MAP_ONLY_##C(_res.ref->second = mappedFromRaw(rmapped);) \
- } \
- return _res; \
- } \
-\
- STC_INLINE void \
- CX##_emplace_items(CX* self, const CX##_rawvalue_t arr[], size_t n) { \
- for (size_t i=0; i<n; ++i) SET_ONLY_##C( CX##_emplace(self, arr[i]); ) \
- MAP_ONLY_##C( CX##_emplace(self, arr[i].first, arr[i].second); ) \
- } \
-\
- STC_INLINE CX##_result_t \
- CX##_insert(CX* self, Key _key MAP_ONLY_##C(, Mapped _mapped)) { \
- CX##_result_t _res = CX##_insert_entry_(self, keyToRaw(&_key)); \
- if (_res.inserted) {*KEY_REF_##C(_res.ref) = _key; MAP_ONLY_##C( _res.ref->second = _mapped; )} \
- else {keyDel(&_key); MAP_ONLY_##C( mappedDel(&_mapped); )} \
- return _res; \
- } \
-\
- MAP_ONLY_##C( \
- STC_INLINE CX##_result_t \
- CX##_insert_or_assign(CX* self, Key _key, Mapped _mapped) { \
- CX##_result_t _res = CX##_insert_entry_(self, keyToRaw(&_key)); \
- if (_res.inserted) _res.ref->first = _key; \
- else {keyDel(&_key); mappedDel(&_res.ref->second);} \
- _res.ref->second = _mapped; return _res; \
- } \
- \
- STC_INLINE CX##_result_t \
- CX##_put(CX* self, Key k, Mapped m) { /* shorter, like operator[] */ \
- return CX##_insert_or_assign(self, k, m); \
- } \
- \
- STC_INLINE CX##_result_t \
- CX##_emplace_or_assign(CX* self, RawKey rkey, RawMapped rmapped) { \
- CX##_result_t _res = CX##_insert_entry_(self, rkey); \
- if (_res.inserted) _res.ref->first = keyFromRaw(rkey); \
- else mappedDel(&_res.ref->second); \
- _res.ref->second = mappedFromRaw(rmapped); return _res; \
- } \
- \
- STC_INLINE CX##_mapped_t* \
- CX##_at(const CX* self, RawKey rkey) { \
- chash_bucket_t b = CX##_bucket_(self, &rkey); \
- return &self->table[b.idx].second; \
- }) \
-\
- STC_INLINE CX##_iter_t \
- CX##_find(const CX* self, RawKey rkey) { \
- CX##_iter_t it = {NULL}; \
- if (self->size == 0) return it; \
- chash_bucket_t b = CX##_bucket_(self, &rkey); \
- if (*(it._hx = self->_hashx+b.idx)) it.ref = self->table+b.idx; \
- return it; \
- } \
-\
- STC_INLINE CX##_value_t* \
- CX##_get(const CX* self, RawKey rkey) \
- {return CX##_find(self, rkey).ref;} \
-\
- STC_INLINE CX##_iter_t \
- CX##_begin(const CX* self) { \
- CX##_iter_t it = {self->table, self->_hashx}; \
- if (it._hx) while (*it._hx == 0) ++it.ref, ++it._hx; \
- return it; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_end(const CX* self) \
- {return c_make(CX##_iter_t){self->table + self->bucket_count};} \
-\
- STC_INLINE void \
- CX##_next(CX##_iter_t* it) \
- {while ((++it->ref, *++it->_hx == 0)) ;} \
-\
- STC_INLINE size_t \
- CX##_erase(CX* self, RawKey rkey) { \
- if (self->size == 0) return 0; \
- chash_bucket_t b = CX##_bucket_(self, &rkey); \
- return self->_hashx[b.idx] ? CX##_erase_entry(self, self->table + b.idx), 1 : 0; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_erase_at(CX* self, CX##_iter_t it) { \
- CX##_erase_entry(self, it.ref); \
- if (*it._hx == 0) CX##_next(&it); \
- return it; \
- } \
-\
- _c_implement_chash(CX, C, Key, Mapped, keyEqualsRaw, keyHashRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey) \
- struct stc_trailing_semicolon
+typedef struct { size_t idx; uint_fast8_t hx; } chash_bucket_t;
+#endif // CMAP_H_INCLUDED
-/* -------------------------- IMPLEMENTATION ------------------------- */
+#ifndef i_prefix
+#define i_prefix cmap_
+#endif
+#ifdef i_isset
+ #define cx_MAP_ONLY c_false
+ #define cx_SET_ONLY c_true
+ #define cx_keyref(vp) (vp)
+#else
+ #define cx_MAP_ONLY c_true
+ #define cx_SET_ONLY c_false
+ #define cx_keyref(vp) (&(vp)->first)
+#endif
+#include "template.h"
+#ifndef i_fwd
+cx_deftypes(_c_chash_types, Self, i_key, i_val, cx_MAP_ONLY, cx_SET_ONLY);
+#endif
-#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
+cx_MAP_ONLY( struct cx_value_t {
+ cx_key_t first;
+ cx_mapped_t second;
+}; )
-#ifdef c_umul128
-STC_INLINE size_t fastrange_uint64_t(uint64_t x, uint64_t n) \
- {uint64_t l, h; c_umul128(x, n, &l, &h); return h;}
-#endif
-#define fastrange_uint32_t(x, n) ((size_t) (((uint32_t)(x)*(uint64_t)(n)) >> 32))
-#define chash_index_(h, entryPtr) ((entryPtr) - (h).table)
+typedef i_keyraw cx_rawkey_t;
+typedef i_valraw cx_memb(_rawmapped_t);
+typedef cx_SET_ONLY( i_keyraw )
+ cx_MAP_ONLY( struct { i_keyraw first;
+ i_valraw second; } )
+cx_rawvalue_t;
+
+STC_API Self cx_memb(_with_capacity)(size_t cap);
+STC_API Self cx_memb(_clone)(Self map);
+STC_API void cx_memb(_del)(Self* self);
+STC_API void cx_memb(_clear)(Self* self);
+STC_API void cx_memb(_reserve)(Self* self, size_t capacity);
+STC_API chash_bucket_t cx_memb(_bucket_)(const Self* self, const cx_rawkey_t* rkeyptr);
+STC_API cx_result_t cx_memb(_insert_entry_)(Self* self, i_keyraw rkey);
+STC_API void cx_memb(_erase_entry)(Self* self, cx_value_t* val);
+
+STC_INLINE Self cx_memb(_init)(void) { return c_make(Self)_cmap_inits; }
+STC_INLINE void cx_memb(_shrink_to_fit)(Self* self) { cx_memb(_reserve)(self, self->size); }
+STC_INLINE void cx_memb(_max_load_factor)(Self* self, float ml) {self->max_load_factor = ml; }
+STC_INLINE bool cx_memb(_empty)(Self m) { return m.size == 0; }
+STC_INLINE size_t cx_memb(_size)(Self m) { return m.size; }
+STC_INLINE size_t cx_memb(_bucket_count)(Self map) { return map.bucket_count; }
+STC_INLINE size_t cx_memb(_capacity)(Self map)
+ { return (size_t) (map.bucket_count * map.max_load_factor); }
+STC_INLINE void cx_memb(_swap)(Self *map1, Self *map2) {c_swap(Self, *map1, *map2); }
+STC_INLINE bool cx_memb(_contains)(const Self* self, i_keyraw rkey)
+ { return self->size && self->_hashx[cx_memb(_bucket_)(self, &rkey).idx]; }
+
+cx_MAP_ONLY(
+ STC_API cx_result_t cx_memb(_insert_or_assign)(Self* self, i_key _key, i_val _mapped);
+ STC_API cx_result_t cx_memb(_emplace_or_assign)(Self* self, i_keyraw rkey, i_valraw rmapped);
+
+ STC_INLINE cx_result_t /* short-form, like operator[]: */
+ cx_memb(_put)(Self* self, i_key key, i_val mapped) {
+ return cx_memb(_insert_or_assign)(self, key, mapped);
+ }
+ STC_INLINE cx_mapped_t*
+ cx_memb(_at)(const Self* self, i_keyraw rkey) {
+ chash_bucket_t b = cx_memb(_bucket_)(self, &rkey);
+ return &self->table[b.idx].second;
+ }
+)
+
+STC_INLINE void
+cx_memb(_value_clone)(cx_value_t* _dst, cx_value_t* _val) {
+ *cx_keyref(_dst) = i_keyfrom(i_keyto(cx_keyref(_val)));
+ cx_MAP_ONLY( _dst->second = i_valfrom(i_valto(&_val->second)); )
+}
+
+STC_INLINE cx_rawvalue_t
+cx_memb(_value_toraw)(cx_value_t* val) {
+ return cx_SET_ONLY( i_keyto(val) )
+ cx_MAP_ONLY( c_make(cx_rawvalue_t){i_keyto(&val->first), i_valto(&val->second)} );
+}
-#define _c_implement_chash(CX, C, Key, Mapped, keyEqualsRaw, keyHashRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey) \
- STC_DEF CX \
- CX##_with_capacity(size_t cap) { \
- CX h = _cmap_inits; \
- CX##_reserve(&h, cap); \
- return h; \
- } \
-\
- STC_INLINE void CX##_wipe_(CX* self) { \
- if (self->size == 0) return; \
- CX##_value_t* e = self->table, *end = e + self->bucket_count; \
- uint8_t *hx = self->_hashx; \
- for (; e != end; ++e) if (*hx++) CX##_value_del(e); \
- } \
-\
- STC_DEF void CX##_del(CX* self) { \
- CX##_wipe_(self); \
- c_free(self->_hashx); \
- c_free((void *) self->table); \
- } \
-\
- STC_DEF void CX##_clear(CX* self) { \
- CX##_wipe_(self); \
- self->size = 0; \
- memset(self->_hashx, 0, self->bucket_count); \
- } \
-\
- STC_DEF chash_bucket_t \
- CX##_bucket_(const CX* self, const CX##_rawkey_t* rkeyptr) { \
- const uint64_t _hash = keyHashRaw(rkeyptr, sizeof *rkeyptr); \
- uint_fast8_t _hx; size_t _cap = self->bucket_count; \
- chash_bucket_t b = {c_PASTE(fastrange_,CMAP_SIZE_T)(_hash, _cap), (uint_fast8_t)(_hash | 0x80)}; \
- const uint8_t* _hashx = self->_hashx; \
- while ((_hx = _hashx[b.idx])) { \
- if (_hx == b.hx) { \
- CX##_rawkey_t _raw = keyToRaw(KEY_REF_##C(self->table + b.idx)); \
- if (keyEqualsRaw(&_raw, rkeyptr)) break; \
- } \
- if (++b.idx == _cap) b.idx = 0; \
- } \
- return b; \
- } \
-\
- STC_DEF CX##_result_t \
- CX##_insert_entry_(CX* self, RawKey rkey) { \
- if (self->size + 1 >= (CX##_size_t) (self->bucket_count * self->max_load_factor)) \
- CX##_reserve(self, 8 + (self->size*13ull >> 3)); \
- chash_bucket_t b = CX##_bucket_(self, &rkey); \
- CX##_result_t res = {&self->table[b.idx], !self->_hashx[b.idx]}; \
- if (res.inserted) { \
- self->_hashx[b.idx] = b.hx; \
- ++self->size; \
- } \
- return res; \
- } \
-\
- STC_DEF CX \
- CX##_clone(CX m) { \
- CX clone = { \
- c_new_n(CX##_value_t, m.bucket_count), \
- (uint8_t *) memcpy(c_malloc(m.bucket_count + 1), m._hashx, m.bucket_count + 1), \
- m.size, m.bucket_count, \
- m.max_load_factor \
- }; \
- CX##_value_t *e = m.table, *end = e + m.bucket_count, *dst = clone.table; \
- for (uint8_t *hx = m._hashx; e != end; ++hx, ++e, ++dst) \
- if (*hx) CX##_value_clone(dst, e); \
- return clone; \
- } \
-\
- STC_DEF void \
- CX##_reserve(CX* self, size_t _newcap) { \
- if (_newcap < self->size) return; \
- size_t _oldcap = self->bucket_count; \
- _newcap = (size_t) (2 + _newcap / self->max_load_factor) | 1; \
- CX _tmp = { \
- c_new_n(CX##_value_t, _newcap), \
- (uint8_t *) c_calloc(_newcap + 1, sizeof(uint8_t)), \
- self->size, (CX##_size_t) _newcap, \
- self->max_load_factor \
- }; \
- /* Rehash: */ \
- _tmp._hashx[_newcap] = 0xff; c_swap(CX, *self, _tmp); \
- CX##_value_t* e = _tmp.table, *_slot = self->table; \
- uint8_t* _hashx = self->_hashx; \
- for (size_t i = 0; i < _oldcap; ++i, ++e) \
- if (_tmp._hashx[i]) { \
- CX##_rawkey_t _raw = keyToRaw(KEY_REF_##C(e)); \
- chash_bucket_t b = CX##_bucket_(self, &_raw); \
- memcpy((void *) &_slot[b.idx], e, sizeof *e); \
- _hashx[b.idx] = (uint8_t) b.hx; \
- } \
- c_free(_tmp._hashx); \
- c_free((void *) _tmp.table); \
- } \
-\
- STC_DEF void \
- CX##_erase_entry(CX* self, CX##_value_t* _val) { \
- size_t i = chash_index_(*self, _val), j = i, k, _cap = self->bucket_count; \
- CX##_value_t* _slot = self->table; \
- uint8_t* _hashx = self->_hashx; \
- CX##_value_del(&_slot[i]); \
- for (;;) { /* delete without leaving tombstone */ \
- if (++j == _cap) j = 0; \
- if (! _hashx[j]) \
- break; \
- CX##_rawkey_t _raw = keyToRaw(KEY_REF_##C(_slot+j)); \
- k = c_PASTE(fastrange_,CMAP_SIZE_T)(keyHashRaw(&_raw, sizeof _raw), _cap); \
- if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */ \
- memcpy((void *) &_slot[i], &_slot[j], sizeof *_slot), _hashx[i] = _hashx[j], i = j; \
- } \
- _hashx[i] = 0; \
- --self->size; \
+STC_INLINE void
+cx_memb(_value_del)(cx_value_t* _val) {
+ i_keydel(cx_keyref(_val));
+ cx_MAP_ONLY( i_valdel(&_val->second); )
+}
+
+STC_INLINE cx_result_t
+cx_memb(_emplace)(Self* self, i_keyraw rkey cx_MAP_ONLY(, i_valraw rmapped)) {
+ cx_result_t _res = cx_memb(_insert_entry_)(self, rkey);
+ if (_res.inserted) {
+ *cx_keyref(_res.ref) = i_keyfrom(rkey);
+ cx_MAP_ONLY( _res.ref->second = i_valfrom(rmapped); )
}
+ return _res;
+}
+
+STC_INLINE void
+cx_memb(_emplace_items)(Self* self, const cx_rawvalue_t arr[], size_t n) {
+ for (size_t i=0; i<n; ++i) cx_SET_ONLY( cx_memb(_emplace)(self, arr[i]); )
+ cx_MAP_ONLY( cx_memb(_emplace)(self, arr[i].first, arr[i].second); )
+}
+STC_INLINE cx_result_t
+cx_memb(_insert)(Self* self, i_key _key cx_MAP_ONLY(, i_val _mapped)) {
+ cx_result_t _res = cx_memb(_insert_entry_)(self, i_keyto(&_key));
+ if (_res.inserted) { *cx_keyref(_res.ref) = _key; cx_MAP_ONLY( _res.ref->second = _mapped; )}
+ else { i_keydel(&_key); cx_MAP_ONLY( i_valdel(&_mapped); )}
+ return _res;
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_find)(const Self* self, i_keyraw rkey) {
+ cx_iter_t it = {NULL};
+ if (self->size == 0) return it;
+ chash_bucket_t b = cx_memb(_bucket_)(self, &rkey);
+ if (*(it._hx = self->_hashx+b.idx)) it.ref = self->table+b.idx;
+ return it;
+}
+
+STC_INLINE cx_value_t*
+cx_memb(_get)(const Self* self, i_keyraw rkey)
+ { return cx_memb(_find)(self, rkey).ref; }
+
+STC_INLINE cx_iter_t
+cx_memb(_begin)(const Self* self) {
+ cx_iter_t it = {self->table, self->_hashx};
+ if (it._hx) while (*it._hx == 0) ++it.ref, ++it._hx;
+ return it;
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_end)(const Self* self)
+ { return c_make(cx_iter_t){self->table + self->bucket_count}; }
+
+STC_INLINE void
+cx_memb(_next)(cx_iter_t* it)
+ { while ((++it->ref, *++it->_hx == 0)) ; }
+
+STC_INLINE cx_iter_t
+cx_memb(_advance)(cx_iter_t it, size_t n) {
+ // UB if n > elements left
+ while (n--) cx_memb(_next)(&it);
+ return it;
+}
+
+STC_INLINE size_t
+cx_memb(_erase)(Self* self, i_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;
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_erase_at)(Self* self, cx_iter_t it) {
+ cx_memb(_erase_entry)(self, it.ref);
+ if (*it._hx == 0) cx_memb(_next)(&it);
+ return it;
+}
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+
+#if !defined(STC_HEADER) && !defined(CMAP_H_INCLUDED) || defined(i_imp) && i_imp == 2
STC_DEF uint64_t c_default_hash(const void *key, size_t len) {
const uint64_t m = 0xb5ad4eceda1ce2a9;
uint64_t k, h = m + len;
const uint8_t *p = (const uint8_t *)key, *end = p + (len & ~7ull);
- for (; p != end; p += 8) {memcpy(&k, p, 8); h ^= m*k;}
+ for (; p != end; p += 8) { memcpy(&k, p, 8); h ^= m*k; }
switch (len & 7) {
case 7: h ^= (uint64_t) p[6] << 48;
case 6: h ^= (uint64_t) p[5] << 40;
@@ -469,11 +235,153 @@ STC_DEF uint64_t c_default_hash(const void *key, size_t len) {
}
return h ^ (h >> 15);
}
+#endif // NON-TEMPLATED
-#else
-#define _c_implement_chash(CX, C, Key, Mapped, keyEqualsRaw, keyHashRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey)
-#endif
+#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) || defined(i_imp)
+#ifndef CMAP_H_INCLUDED
+//STC_INLINE size_t fastrange_uint64_t(uint64_t x, uint64_t n)
+// { uint64_t lo, hi; c_umul128(x, n, &lo, &hi); return hi; }
+#define fastrange_uint32_t(x, n) ((size_t) (((uint32_t)(x)*(uint64_t)(n)) >> 32))
+#define chash_index_(h, entryPtr) ((entryPtr) - (h).table)
#endif
+
+STC_DEF Self
+cx_memb(_with_capacity)(size_t cap) {
+ Self h = _cmap_inits;
+ cx_memb(_reserve)(&h, cap);
+ return h;
+}
+
+STC_INLINE void cx_memb(_wipe_)(Self* self) {
+ if (self->size == 0) return;
+ cx_value_t* e = self->table, *end = e + self->bucket_count;
+ uint8_t *hx = self->_hashx;
+ for (; e != end; ++e) if (*hx++) cx_memb(_value_del)(e);
+}
+
+STC_DEF void cx_memb(_del)(Self* self) {
+ cx_memb(_wipe_)(self);
+ c_free(self->_hashx);
+ c_free((void *) self->table);
+}
+
+STC_DEF void cx_memb(_clear)(Self* self) {
+ cx_memb(_wipe_)(self);
+ self->size = 0;
+ memset(self->_hashx, 0, self->bucket_count);
+}
+
+cx_MAP_ONLY(
+ STC_DEF cx_result_t
+ cx_memb(_insert_or_assign)(Self* self, i_key _key, i_val _mapped) {
+ cx_result_t _res = cx_memb(_insert_entry_)(self, i_keyto(&_key));
+ if (_res.inserted) _res.ref->first = _key;
+ else { i_keydel(&_key); i_valdel(&_res.ref->second); }
+ _res.ref->second = _mapped; return _res;
+ }
+
+ STC_DEF cx_result_t
+ cx_memb(_emplace_or_assign)(Self* self, i_keyraw rkey, i_valraw rmapped) {
+ cx_result_t _res = cx_memb(_insert_entry_)(self, rkey);
+ if (_res.inserted) _res.ref->first = i_keyfrom(rkey);
+ else i_valdel(&_res.ref->second);
+ _res.ref->second = i_valfrom(rmapped); return _res;
+ }
+)
+
+STC_DEF chash_bucket_t
+cx_memb(_bucket_)(const Self* self, const cx_rawkey_t* rkeyptr) {
+ const uint64_t _hash = i_hash(rkeyptr, sizeof *rkeyptr);
+ uint_fast8_t _hx; size_t _cap = self->bucket_count;
+ chash_bucket_t b = {c_PASTE(fastrange_,MAP_SIZE_T)(_hash, _cap), (uint_fast8_t)(_hash | 0x80)};
+ const uint8_t* _hashx = self->_hashx;
+ while ((_hx = _hashx[b.idx])) {
+ if (_hx == b.hx) {
+ cx_rawkey_t _raw = i_keyto(cx_keyref(self->table + b.idx));
+ if (i_equ(&_raw, rkeyptr)) break;
+ }
+ if (++b.idx == _cap) b.idx = 0;
+ }
+ return b;
+}
+
+STC_DEF cx_result_t
+cx_memb(_insert_entry_)(Self* self, i_keyraw rkey) {
+ if (self->size + 1 >= (cx_size_t) (self->bucket_count * self->max_load_factor))
+ cx_memb(_reserve)(self, 8 + (self->size*13ull >> 3));
+ chash_bucket_t b = cx_memb(_bucket_)(self, &rkey);
+ cx_result_t res = {&self->table[b.idx], !self->_hashx[b.idx]};
+ if (res.inserted) {
+ self->_hashx[b.idx] = b.hx;
+ ++self->size;
+ }
+ return res;
+}
+
+STC_DEF Self
+cx_memb(_clone)(Self m) {
+ Self clone = {
+ c_new_n(cx_value_t, m.bucket_count),
+ (uint8_t *) memcpy(c_malloc(m.bucket_count + 1), m._hashx, m.bucket_count + 1),
+ m.size, m.bucket_count,
+ m.max_load_factor
+ };
+ cx_value_t *e = m.table, *end = e + m.bucket_count, *dst = clone.table;
+ for (uint8_t *hx = m._hashx; e != end; ++hx, ++e, ++dst)
+ if (*hx) cx_memb(_value_clone)(dst, e);
+ return clone;
+}
+
+STC_DEF void
+cx_memb(_reserve)(Self* self, size_t _newcap) {
+ if (_newcap < self->size) return;
+ size_t _oldcap = self->bucket_count;
+ _newcap = (size_t) (2 + _newcap / self->max_load_factor) | 1;
+ Self _tmp = {
+ c_new_n(cx_value_t, _newcap),
+ (uint8_t *) c_calloc(_newcap + 1, sizeof(uint8_t)),
+ self->size, (cx_size_t) _newcap,
+ self->max_load_factor
+ };
+ /* Rehash: */
+ _tmp._hashx[_newcap] = 0xff; c_swap(Self, *self, _tmp);
+ cx_value_t* e = _tmp.table, *_slot = self->table;
+ uint8_t* _hashx = self->_hashx;
+ for (size_t i = 0; i < _oldcap; ++i, ++e)
+ if (_tmp._hashx[i]) {
+ cx_rawkey_t _raw = i_keyto(cx_keyref(e));
+ chash_bucket_t b = cx_memb(_bucket_)(self, &_raw);
+ _slot[b.idx] = *e;
+ _hashx[b.idx] = (uint8_t) b.hx;
+ }
+ c_free(_tmp._hashx);
+ c_free((void *) _tmp.table);
+}
+
+STC_DEF void
+cx_memb(_erase_entry)(Self* self, cx_value_t* _val) {
+ size_t i = chash_index_(*self, _val), j = i, k, _cap = self->bucket_count;
+ cx_value_t* _slot = self->table;
+ uint8_t* _hashx = self->_hashx;
+ cx_memb(_value_del)(&_slot[i]);
+ for (;;) { /* delete without leaving tombstone */
+ if (++j == _cap) j = 0;
+ if (! _hashx[j])
+ break;
+ cx_rawkey_t _raw = i_keyto(cx_keyref(_slot + j));
+ k = c_PASTE(fastrange_,MAP_SIZE_T)(i_hash(&_raw, sizeof _raw), _cap);
+ if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */
+ _slot[i] = _slot[j], _hashx[i] = _hashx[j], i = j;
+ }
+ _hashx[i] = 0;
+ --self->size;
+}
+
+#endif // TEMPLATED IMPLEMENTATION
+#undef i_isset
+#undef cx_keyref
+#undef cx_MAP_ONLY
+#undef cx_SET_ONLY
+#include "template.h"
+#define CMAP_H_INCLUDED
diff --git a/include/stc/cpque.h b/include/stc/cpque.h
index c6e0ed61..de509710 100644
--- a/include/stc/cpque.h
+++ b/include/stc/cpque.h
@@ -21,126 +21,138 @@
* SOFTWARE.
*/
-/* Priority-Queue adapter (implemented as heap), default uses cvec.
-
- #include <stc/crandom.h>
- #include <stc/cpque.h>
- using_cvec(f, float);
- using_cpque(f, cvec_f, -c_default_compare); // min-heap (increasing values)
-
- int main() {
- stc64_t rng = stc64_init(1234);
- stc64_uniformf_t dist = stc64_uniformf_init(10.0f, 100.0f);
-
- c_forvar (cpque_f queue = cpque_f_init(), cpque_f_del(&queue))
- {
- // Push ten million random numbers onto the queue.
- for (int i=0; i<10000000; ++i)
- cpque_f_push(&queue, stc64_uniformf(&rng, dist));
-
- // Extract the 100 smallest.
- for (int i=0; i<100; ++i) {
- printf("%f ", *cpque_f_top(queue));
- cpque_f_pop(&queue);
- }
- }
+#ifndef CPQUE_H_INCLUDED
+#include <stdlib.h>
+#include "ccommon.h"
+#include "forward.h"
+#endif
+
+#ifndef i_prefix
+#define i_prefix cpque_
+#endif
+
+#include "template.h"
+
+#if !defined i_fwd
+ cx_deftypes(_c_cpque_types, Self, i_val);
+#endif
+typedef i_valraw cx_rawvalue_t;
+
+STC_API void cx_memb(_make_heap)(Self* self);
+STC_API void cx_memb(_erase_at)(Self* self, size_t idx);
+STC_API void cx_memb(_push)(Self* self, cx_value_t value);
+STC_API void cx_memb(_emplace_items)(Self *self, const cx_rawvalue_t arr[], size_t n);
+STC_API Self cx_memb(_clone)(Self q);
+
+STC_INLINE Self cx_memb(_init)(void)
+ { return c_make(Self){0, 0, 0}; }
+
+STC_INLINE Self cx_memb(_with_capacity)(size_t cap) {
+ Self out = {(cx_value_t *) c_malloc(cap*sizeof(cx_value_t)), 0, cap};
+ return out;
+}
+
+STC_INLINE void cx_memb(_clear)(Self* self) {
+ size_t i = self->size; self->size = 0;
+ while (i--) i_valdel(&self->data[i]);
+}
+
+STC_INLINE void cx_memb(_del)(Self* self)
+ { cx_memb(_clear)(self); c_free(self->data); }
+
+STC_INLINE size_t cx_memb(_size)(Self q)
+ { return q.size; }
+
+STC_INLINE bool cx_memb(_empty)(Self q)
+ { return !q.size; }
+
+STC_INLINE size_t cx_memb(_capacity)(Self q)
+ { return q.capacity; }
+
+STC_INLINE cx_value_t* cx_memb(_top)(const Self* self)
+ { return &self->data[0]; }
+
+STC_INLINE void cx_memb(_pop)(Self* self)
+ { cx_memb(_erase_at)(self, 0); }
+
+STC_INLINE void cx_memb(_emplace)(Self* self, cx_rawvalue_t raw)
+ { cx_memb(_push)(self, i_valfrom(raw)); }
+
+STC_INLINE i_val cx_memb(_value_clone)(cx_value_t val)
+ { return i_valfrom(i_valto(&val)); }
+
+STC_INLINE int cx_memb(_value_compare)(const cx_value_t* x, const cx_value_t* y) {
+ cx_rawvalue_t rx = i_valto(x), ry = i_valto(y);
+ return i_cmp(&rx, &ry);
+}
+
+STC_INLINE void
+cx_memb(_push_back)(Self* self, cx_value_t value) {
+ if (self->size == self->capacity) {
+ self->capacity = self->size*3/2 + 4;
+ self->data = (cx_value_t *)c_realloc(self->data, self->capacity*sizeof value);
}
-*/
-#ifndef CPQUEUE_H_INCLUDED
-#define CPQUEUE_H_INCLUDED
-
-#include "cvec.h"
-
-#define using_cpque(...) c_MACRO_OVERLOAD(using_cpque, __VA_ARGS__)
-
-#define using_cpque_2(X, ctype) \
- _c_using_cpque(cpque_##X, ctype, ctype##_value_compare)
-#define using_cpque_3(X, ctype, valueCompare) \
- _c_using_cpque(cpque_##X, ctype, valueCompare)
-
-#define _c_using_cpque(CX, ctype, valueCompare) \
- typedef ctype CX; \
- typedef ctype##_value_t CX##_value_t; \
- typedef ctype##_rawvalue_t CX##_rawvalue_t; \
-\
- STC_INLINE CX CX##_init(void) {return ctype##_init();} \
- STC_INLINE CX CX##_clone(CX pq) {return ctype##_clone(pq);} \
- STC_INLINE CX##_value_t CX##_value_clone(CX##_value_t val) \
- {return ctype##_value_clone(val);} \
- STC_INLINE void CX##_clear(CX* self) {ctype##_clear(self);} \
- STC_INLINE void CX##_del(CX* self) {ctype##_del(self);} \
-\
- STC_INLINE size_t CX##_size(CX pq) {return ctype##_size(pq);} \
- STC_INLINE bool CX##_empty(CX pq) {return ctype##_empty(pq);} \
- \
- STC_API void CX##_make_heap(CX* self); \
- STC_API void CX##_erase_at(CX* self, size_t idx); \
- STC_INLINE \
- const CX##_value_t* CX##_top(const CX* self) {return &self->data[0];} \
- STC_INLINE void CX##_pop(CX* self) {CX##_erase_at(self, 0);} \
- \
- STC_API void CX##_push(CX* self, CX##_value_t value); \
- STC_INLINE void CX##_emplace(CX* self, CX##_rawvalue_t raw) \
- {CX##_push(self, ctype##_value_fromraw(raw));} \
- STC_API void CX##_emplace_items(CX *self, const CX##_rawvalue_t arr[], size_t n); \
-\
- _c_implement_cpque(CX, ctype, valueCompare) \
- struct stc_trailing_semicolon
+ self->data[ self->size++ ] = value;
+}
+STC_INLINE void
+cx_memb(_pop_back)(Self* self)
+ { --self->size; i_valdel(&self->data[self->size]); }
/* -------------------------- IMPLEMENTATION ------------------------- */
+#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) || defined(i_imp)
-#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
-
-#define _c_implement_cpque(CX, ctype, valueCompare) \
-\
- STC_INLINE void \
- CX##_sift_down_(CX##_value_t* arr, size_t i, size_t n) { \
- size_t r = i, c = i << 1; \
- while (c <= n) { \
- c += (c < n && valueCompare(&arr[c], &arr[c + 1]) < 0); \
- if (valueCompare(&arr[r], &arr[c]) < 0) { \
- CX##_value_t tmp = arr[r]; arr[r] = arr[c]; arr[r = c] = tmp; \
- } else \
- return; \
- c <<= 1; \
- } \
- } \
-\
- STC_API void \
- CX##_make_heap(CX* self) { \
- size_t n = CX##_size(*self); \
- CX##_value_t *arr = self->data - 1; \
- for (size_t k = n >> 1; k != 0; --k) \
- CX##_sift_down_(arr, k, n); \
- } \
-\
- STC_API void \
- CX##_erase_at(CX* self, size_t idx) { \
- size_t n = CX##_size(*self) - 1; \
- self->data[idx] = self->data[n]; \
- ctype##_pop_back(self); \
- CX##_sift_down_(self->data - 1, idx + 1, n); \
- } \
-\
- STC_API void \
- CX##_push(CX* self, CX##_value_t value) { \
- ctype##_push_back(self, value); /* sift-up the value */ \
- size_t n = CX##_size(*self), c = n; \
- CX##_value_t *arr = self->data - 1; \
- for (; c > 1 && valueCompare(&arr[c >> 1], &value) < 0; c >>= 1) \
- arr[c] = arr[c >> 1]; \
- if (c != n) arr[c] = value; \
- } \
-\
- STC_API void \
- CX##_emplace_items(CX *self, const CX##_rawvalue_t arr[], size_t n) { \
- for (size_t i = 0; i < n; ++i) \
- CX##_push(self, ctype##_value_fromraw(arr[i])); \
- } \
-
-#else
-#define _c_implement_cpque(CX, ctype, valueCompare)
-#endif
+STC_DEF void
+cx_memb(_sift_down_)(cx_value_t* arr, size_t i, size_t n) {
+ size_t r = i, c = i << 1;
+ while (c <= n) {
+ c += (c < n && i_cmp(&arr[c], &arr[c + 1]) < 0);
+ if (i_cmp(&arr[r], &arr[c]) < 0) {
+ cx_value_t tmp = arr[r]; arr[r] = arr[c]; arr[r = c] = tmp;
+ } else
+ return;
+ c <<= 1;
+ }
+}
+
+STC_DEF void
+cx_memb(_make_heap)(Self* self) {
+ size_t n = cx_memb(_size)(*self);
+ cx_value_t *arr = self->data - 1;
+ for (size_t k = n >> 1; k != 0; --k)
+ cx_memb(_sift_down_)(arr, k, n);
+}
+
+STC_DEF Self cx_memb(_clone)(Self q) {
+ Self out = {(cx_value_t *) c_malloc(q.size*sizeof(cx_value_t)), q.size, q.size};
+ for (size_t i = 0; i < q.size; ++i, ++q.data) out.data[i] = i_valfrom(i_valto(q.data));
+ return out;
+}
+
+STC_DEF void
+cx_memb(_erase_at)(Self* self, size_t idx) {
+ size_t n = cx_memb(_size)(*self) - 1;
+ self->data[idx] = self->data[n];
+ cx_memb(_pop_back)(self);
+ cx_memb(_sift_down_)(self->data - 1, idx + 1, n);
+}
+
+STC_DEF void
+cx_memb(_push)(Self* self, cx_value_t value) {
+ cx_memb(_push_back)(self, value); /* sift-up the value */
+ size_t n = cx_memb(_size)(*self), c = n;
+ cx_value_t *arr = self->data - 1;
+ for (; c > 1 && i_cmp(&arr[c >> 1], &value) < 0; c >>= 1)
+ arr[c] = arr[c >> 1];
+ if (c != n) arr[c] = value;
+}
+
+STC_DEF void
+cx_memb(_emplace_items)(Self *self, const cx_rawvalue_t arr[], size_t n) {
+ for (size_t i = 0; i < n; ++i)
+ cx_memb(_push)(self, i_valfrom(arr[i]));
+}
#endif
+#include "template.h"
+#define CPQUE_H_INCLUDED \ No newline at end of file
diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h
index b89291c8..f1d173e2 100644
--- a/include/stc/cqueue.h
+++ b/include/stc/cqueue.h
@@ -20,74 +20,48 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#ifndef CQUEUE_H_INCLUDED
-#define CQUEUE_H_INCLUDED
+// STC queue
+/*
+#include <stc/crandom.h>
+#include <stdio.h>
-/* Queue adapter, default uses clist.
+#define i_val int
+#include <stc/cqueue.h>
- #include <stc/crandom.h>
- #include <stc/cqueue.h>
- using_cdeq(i, int);
- using_cqueue(i, cdeq_i);
+int main() {
+ int n = 10000000;
+ stc64_t rng = stc64_init(1234);
+ stc64_uniform_t dist = stc64_uniform_init(0, n);
- int main() {
- int n = 10000000;
- stc64_t rng = stc64_init(1234);
- stc64_uniform_t dist = stc64_uniform_init(rng, 0, n);
+ c_forauto (cqueue_int, Q)
+ {
+ // Push ten million random numbers onto the queue.
+ for (int i=0; i<n; ++i)
+ cqueue_int_push(&Q, stc64_uniform(&rng, &dist));
- c_forvar (cqueue_i queue = cqueue_i_init(), cqueue_i_del(&queue))
- {
- // Push ten million random numbers onto the queue.
- for (int i=0; i<n; ++i)
- cqueue_i_push(&queue, stc64_uniform(&dist));
-
- // Push or pop on the queue ten million times
- printf("%d\n", n);
- for (int i=n; i>0; --i) {
- int r = stc64_uniform(&dist);
- if (r & 1)
- ++n, cqueue_i_push(&queue, r);
- else
- --n, cqueue_i_pop(&queue);
- }
+ // 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 = stc64_uniform(&rng, &dist);
+ if (r & 1)
+ ++n, cqueue_int_push(&Q, r);
+ else
+ --n, cqueue_int_pop(&Q);
}
- printf("%d\n", n);
+ printf("after: size, capacity: %d, %d\n", n, cqueue_int_size(Q), cqueue_int_capacity(Q));
}
+}
*/
-#include "cdeq.h"
-#define using_cqueue(X, ctype) \
- _c_using_cqueue(cqueue_##X, ctype)
+#ifndef i_prefix
+#define i_prefix cqueue_
+#endif
+#define i_queue
+#define _push_back _push
+#define _pop_front _pop
-#define _c_using_cqueue(CX, ctype) \
- typedef struct { ctype rep; size_t size; } CX; \
- typedef ctype##_value_t CX##_value_t; \
- typedef ctype##_rawvalue_t CX##_rawvalue_t; \
- typedef ctype##_iter_t CX##_iter_t; \
-\
- STC_INLINE CX CX##_init(void) {return c_make(CX){ctype##_init(), 0};} \
- STC_INLINE CX CX##_clone(CX q) {return c_make(CX){ctype##_clone(q.rep), q.size};} \
- STC_INLINE CX##_value_t CX##_value_clone(CX##_value_t val) \
- {return ctype##_value_clone(val);} \
- STC_INLINE void CX##_clear(CX* self) {ctype##_clear(&self->rep); self->size = 0;} \
- STC_INLINE void CX##_del(CX* self) {ctype##_del(&self->rep);} \
-\
- STC_INLINE size_t CX##_size(CX q) {return q.size;} \
- STC_INLINE bool CX##_empty(CX q) {return q.size == 0;} \
- STC_INLINE CX##_value_t* CX##_front(const CX* self) {return ctype##_front(&self->rep);} \
- STC_INLINE CX##_value_t* CX##_back(const CX* self) {return ctype##_back(&self->rep);} \
-\
- STC_INLINE void CX##_pop(CX* self) {ctype##_pop_front(&self->rep); --self->size;} \
- STC_INLINE void CX##_push(CX* self, ctype##_value_t value) \
- {ctype##_push_back(&self->rep, value); ++self->size;} \
- STC_INLINE void CX##_emplace(CX* self, CX##_rawvalue_t raw) \
- {ctype##_emplace_back(&self->rep, raw); ++self->size;} \
- STC_INLINE void CX##_emplace_items(CX *self, const CX##_rawvalue_t arr[], size_t n) \
- {ctype##_emplace_items(&self->rep, arr, n); self->size += n;} \
-\
- STC_INLINE CX##_iter_t CX##_begin(const CX* self) {return ctype##_begin(&self->rep);} \
- STC_INLINE CX##_iter_t CX##_end(const CX* self) {return ctype##_end(&self->rep);} \
- STC_INLINE void CX##_next(CX##_iter_t* it) {ctype##_next(it);} \
- struct stc_trailing_semicolon
+#include "cdeq.h"
-#endif
+#undef _push_back
+#undef _pop_front
+#undef i_queue
diff --git a/include/stc/crandom.h b/include/stc/crandom.h
index 7be7ea6c..978e8740 100644
--- a/include/stc/crandom.h
+++ b/include/stc/crandom.h
@@ -43,20 +43,20 @@ int main() {
#include <string.h>
#include <math.h>
-typedef struct { uint64_t state[5]; } stc64_t;
-typedef struct { uint32_t state[5]; } stc32_t;
-typedef struct { int64_t lower; uint64_t range, threshold; } stc64_uniform_t;
-typedef struct { double lower, range; } stc64_uniformf_t;
-typedef struct { double mean, stddev, next; unsigned has_next; } stc64_normalf_t;
+typedef struct stc64 { uint64_t state[5]; } stc64_t;
+typedef struct stc32 { uint32_t state[5]; } stc32_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; unsigned 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
+ * 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
+ * streams with one-bit diff state. Even the 16-bit version (LR=6, RS=5, LS=3) passes
* PractRand to multiple TB input.
*/
@@ -137,15 +137,15 @@ static stc64_t stc64_global = {{
0x6a09e667a754166b
}};
-STC_DEF void stc64_srandom(uint64_t seed) {
- stc64_global = stc64_init(seed);
+STC_DEF void stc64_srandom(uint64_t seed) {
+ stc64_global = stc64_init(seed);
}
STC_DEF uint64_t stc64_random(void) {
return stc64_rand(&stc64_global);
}
-/* rng.state[4] must be odd */
+/* rng.state[4] must be odd */
STC_DEF stc64_t stc64_with_seq(uint64_t seed, uint64_t seq) {
stc64_t rng = {{seed, seed+0x26aa069ea2fb1a4d, seed+0x70c72c95cd592d04,
seed+0x504f333d3aa0b359, (seq << 1) | 1}};
diff --git a/include/stc/cset.h b/include/stc/cset.h
index 6979311a..aa2ba022 100644
--- a/include/stc/cset.h
+++ b/include/stc/cset.h
@@ -20,16 +20,14 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#ifndef CSET_H_INCLUDED
-#define CSET_H_INCLUDED
// Unordered set - implemented as closed hashing with linear probing and no tombstones.
/*
+#define i_tag sx
+#define i_key int
#include <stc/cset.h>
#include <stdio.h>
-using_cset(sx, int); // Set of int
-
int main(void) {
cset_sx s = cset_sx_init();
cset_sx_insert(&s, 5);
@@ -41,30 +39,8 @@ int main(void) {
}
*/
-#include "cmap.h"
-
-#define forward_cset(X, Key) _c_chash_types(cset_##X, cset_, Key, Key)
-
-#define using_cset(...) c_MACRO_OVERLOAD(using_cset, __VA_ARGS__)
-
-#define using_cset_2(X, Key) \
- using_cset_4(X, Key, c_default_equals, c_default_hash)
-#define using_cset_4(X, Key, keyEquals, keyHash) \
- using_cset_6(X, Key, keyEquals, keyHash, c_default_del, c_default_fromraw)
-#define using_cset_5(X, Key, keyEquals, keyHash, keyDel) \
- using_cset_6(X, Key, keyEquals, keyHash, keyDel, c_no_clone)
-#define using_cset_6(X, Key, keyEquals, keyHash, keyDel, keyClone) \
- using_cset_9(X, Key, keyEquals, keyHash, keyDel, keyClone, c_default_toraw, Key, c_true)
-#define using_cset_9(X, Key, keyEqualsRaw, keyHashRaw, keyDel, keyFromRaw, keyToRaw, RawKey, defTypes) \
- _c_using_chash(cset_##X, cset_, Key, Key, keyEqualsRaw, keyHashRaw, \
- @@, @@, @@, void, keyDel, keyFromRaw, keyToRaw, RawKey, defTypes)
-
-#define using_cset_str() \
- using_cset_9(str, cstr, c_rawstr_equals, c_rawstr_hash, cstr_del, \
- cstr_from, cstr_str, const char*, c_true)
-
-#define SET_ONLY_cset_(...) __VA_ARGS__
-#define MAP_ONLY_cset_(...)
-#define KEY_REF_cset_(vp) (vp)
-
+#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 bf7fd6ab..d52f70c4 100644
--- a/include/stc/csmap.h
+++ b/include/stc/csmap.h
@@ -20,564 +20,479 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#ifndef CSMAP_H_INCLUDED
-#define CSMAP_H_INCLUDED
// Sorted/Ordered set and map - implemented as an AA-tree.
/*
#include <stdio.h>
+#include <stc/cstr.h>
+
+#define i_tag sx // Sorted map<cstr, double>
+#define i_key_str
+#define i_val double
#include <stc/csmap.h>
-using_csmap(mx, int, char); // Sorted map<int, char>
int main(void) {
- c_forvar (csmap_mx m = csmap_mx_init(), csmap_mx_del(&m))
+ c_forvar (csmap_sx m = csmap_sx_init(), csmap_sx_del(&m))
{
- csmap_mx_insert(&m, 5, 'a');
- csmap_mx_insert(&m, 8, 'b');
- csmap_mx_insert(&m, 12, 'c');
+ csmap_sx_emplace(&m, "Testing one", 1.234);
+ csmap_sx_emplace(&m, "Testing two", 12.34);
+ csmap_sx_emplace(&m, "Testing three", 123.4);
- csmap_mx_iter_t it = csmap_mx_find(&m, 10); // none
- char val = csmap_mx_find(&m, 5).ref->second;
- csmap_mx_put(&m, 5, 'd'); // update
- csmap_mx_erase(&m, 8);
+ csmap_sx_value_t *v = csmap_sx_get(&m, "Testing five"); // NULL
+ double num = *csmap_sx_at(&m, "Testing one");
+ csmap_sx_emplace_or_assign(&m, "Testing three", 1000.0); // update
+ csmap_sx_erase(&m, "Testing two");
- c_foreach (i, csmap_mx, m)
- printf("map %d: %c\n", i.ref->first, i.ref->second);
+ c_foreach (i, csmap_sx, m)
+ printf("map %s: %g\n", i.ref->first.str, i.ref->second);
}
}
*/
+
+#ifndef CSMAP_H_INCLUDED
#include "ccommon.h"
+#include "forward.h"
#include <stdlib.h>
#include <string.h>
-#define forward_csmap(X, Key, Mapped) _c_aatree_types(csmap_##X, csmap_, Key, Mapped)
-
-
-#define using_csmap(...) c_MACRO_OVERLOAD(using_csmap, __VA_ARGS__)
-
-#define using_csmap_3(X, Key, Mapped) \
- using_csmap_4(X, Key, Mapped, c_default_compare)
-#define using_csmap_4(X, Key, Mapped, keyCompare) \
- using_csmap_6(X, Key, Mapped, keyCompare, c_default_del, c_default_fromraw)
-#define using_csmap_5(X, Key, Mapped, keyCompare, mappedDel) \
- using_csmap_6(X, Key, Mapped, keyCompare, mappedDel, c_no_clone)
-#define using_csmap_6(X, Key, Mapped, keyCompare, mappedDel, mappedClone) \
- using_csmap_9(X, Key, Mapped, keyCompare, mappedDel, mappedClone, c_default_toraw, Mapped, c_true)
-#define using_csmap_9(X, Key, Mapped, keyCompare, mappedDel, mappedFromRaw, mappedToRaw, RawMapped, defTypes) \
- using_csmap_13(X, Key, Mapped, keyCompare, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- c_default_del, c_default_fromraw, c_default_toraw, Key, defTypes)
-#define using_csmap_13(X, Key, Mapped, keyCompareRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey, defTypes) \
- _c_using_aatree(csmap_##X, csmap_, Key, Mapped, keyCompareRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey, defTypes)
-
-
-#define using_csmap_keydef(...) c_MACRO_OVERLOAD(using_csmap_keydef, __VA_ARGS__)
-
-#define using_csmap_keydef_6(X, Key, Mapped, keyCompare, keyDel, keyClone) \
- using_csmap_keydef_9(X, Key, Mapped, keyCompare, \
- keyDel, keyClone, c_default_toraw, Key, c_true)
-#define using_csmap_keydef_9(X, Key, Mapped, keyCompareRaw, \
- keyDel, keyFromRaw, keyToRaw, RawKey, defTypes) \
- _c_using_aatree(csmap_##X, csmap_, Key, Mapped, keyCompareRaw, \
- c_default_del, c_default_fromraw, c_default_toraw, Mapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey, defTypes)
-
-#define using_csmap_str() \
- _c_using_aatree(csmap_str, csmap_, cstr, cstr, c_rawstr_compare, \
- cstr_del, cstr_from, cstr_str, const char*, \
- cstr_del, cstr_from, cstr_str, const char*, c_true)
-
-
-#define using_csmap_strkey(...) c_MACRO_OVERLOAD(using_csmap_strkey, __VA_ARGS__)
-
-#define using_csmap_strkey_2(X, Mapped) \
- using_csmap_strkey_4(X, Mapped, c_default_del, c_default_fromraw)
-#define using_csmap_strkey_3(X, Mapped, mappedDel) \
- using_csmap_strkey_4(X, Mapped, mappedDel, c_no_clone)
-#define using_csmap_strkey_4(X, Mapped, mappedDel, mappedClone) \
- using_csmap_strkey_7(X, Mapped, mappedDel, mappedClone, c_default_toraw, Mapped, c_true)
-#define using_csmap_strkey_7(X, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped, defTypes) \
- _c_using_aatree_strkey(X, csmap_, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped, defTypes)
-#define _c_using_aatree_strkey(X, C, Mapped, mappedDel, mappedFromRaw, mappedToRaw, RawMapped, defTypes) \
- _c_using_aatree(C##X, C, cstr, Mapped, c_rawstr_compare, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- cstr_del, cstr_from, cstr_str, const char*, defTypes)
-
-
-#define using_csmap_strval(...) c_MACRO_OVERLOAD(using_csmap_strval, __VA_ARGS__)
-
-#define using_csmap_strval_2(X, Key) \
- using_csmap_strval_3(X, Key, c_default_compare)
-#define using_csmap_strval_3(X, Key, keyCompare) \
- using_csmap_strval_5(X, Key, keyCompare, c_default_del, c_default_fromraw)
-#define using_csmap_strval_4(X, Key, keyCompare, keyDel) \
- using_csmap_strval_5(X, Key, keyCompare, keyDel, c_no_clone)
-#define using_csmap_strval_5(X, Key, keyCompare, keyDel, keyClone) \
- using_csmap_strval_8(X, Key, keyCompare, keyDel, keyClone, c_default_toraw, Key, c_true)
-#define using_csmap_strval_8(X, Key, keyCompareRaw, keyDel, keyFromRaw, keyToRaw, RawKey, defTypes) \
- _c_using_aatree(csmap_##X, csmap_, Key, cstr, keyCompareRaw, \
- cstr_del, cstr_from, cstr_str, const char*, \
- keyDel, keyFromRaw, keyToRaw, RawKey, defTypes)
-
-#define SET_ONLY_csmap_(...)
-#define MAP_ONLY_csmap_(...) __VA_ARGS__
-#define KEY_REF_csmap_(vp) (&(vp)->first)
-#ifndef CSMAP_SIZE_T
-#define CSMAP_SIZE_T uint32_t
-#endif
struct csmap_rep { size_t root, disp, head, size, cap; void* nodes[]; };
#define _csmap_rep(self) c_container_of((self)->nodes, struct csmap_rep, nodes)
+#endif // CSMAP_H_INCLUDED
+
+#ifndef i_prefix
+#define i_prefix csmap_
+#endif
+#ifdef i_isset
+ #define cx_MAP_ONLY c_false
+ #define cx_SET_ONLY c_true
+ #define cx_keyref(vp) (vp)
+#else
+ #define cx_MAP_ONLY c_true
+ #define cx_SET_ONLY c_false
+ #define cx_keyref(vp) (&(vp)->first)
+#endif
+#include "template.h"
+
+#ifndef i_fwd
+cx_deftypes(_c_aatree_types, Self, i_key, i_val, cx_MAP_ONLY, cx_SET_ONLY);
+#endif
+
+cx_MAP_ONLY( struct cx_value_t {
+ cx_key_t first;
+ cx_mapped_t second;
+}; )
+struct cx_node_t {
+ cx_size_t link[2];
+ int8_t level;
+ cx_value_t value;
+};
+
+typedef i_keyraw cx_rawkey_t;
+typedef i_valraw cx_memb(_rawmapped_t);
+typedef cx_SET_ONLY( i_keyraw )
+ cx_MAP_ONLY( struct { i_keyraw first; i_valraw second; } )
+ cx_rawvalue_t;
+
+STC_API Self cx_memb(_init)(void);
+STC_API Self cx_memb(_clone)(Self tree);
+STC_API void cx_memb(_del)(Self* self);
+STC_API void cx_memb(_reserve)(Self* self, size_t cap);
+STC_API cx_value_t* cx_memb(_find_it)(const Self* self, i_keyraw rkey, cx_iter_t* out);
+STC_API cx_iter_t cx_memb(_lower_bound)(const Self* self, i_keyraw rkey);
+STC_API cx_value_t* cx_memb(_front)(const Self* self);
+STC_API cx_value_t* cx_memb(_back)(const Self* self);
+STC_API int cx_memb(_erase)(Self* self, i_keyraw rkey);
+STC_API cx_iter_t cx_memb(_erase_at)(Self* self, cx_iter_t it);
+STC_API cx_iter_t cx_memb(_erase_range)(Self* self, cx_iter_t it1, cx_iter_t it2);
+STC_API cx_result_t cx_memb(_insert_entry_)(Self* self, i_keyraw rkey);
+STC_API void cx_memb(_next)(cx_iter_t* it);
+
+STC_INLINE bool cx_memb(_empty)(Self tree) { return _csmap_rep(&tree)->size == 0; }
+STC_INLINE size_t cx_memb(_size)(Self tree) { return _csmap_rep(&tree)->size; }
+STC_INLINE size_t cx_memb(_capacity)(Self tree) { return _csmap_rep(&tree)->cap; }
+STC_INLINE void cx_memb(_clear)(Self* self) { cx_memb(_del)(self); *self = cx_memb(_init)(); }
+STC_INLINE void cx_memb(_swap)(Self* a, Self* b) { c_swap(Self, *a, *b); }
+STC_INLINE bool cx_memb(_contains)(const Self* self, i_keyraw rkey)
+ { cx_iter_t it; return cx_memb(_find_it)(self, rkey, &it) != NULL; }
+STC_INLINE cx_value_t* cx_memb(_get)(const Self* self, i_keyraw rkey)
+ { cx_iter_t it; return cx_memb(_find_it)(self, rkey, &it); }
+
+STC_INLINE Self
+cx_memb(_with_capacity)(size_t size) {
+ Self tree = cx_memb(_init)();
+ cx_memb(_reserve)(&tree, size);
+ return tree;
+}
+
+STC_INLINE cx_rawvalue_t
+cx_memb(_value_toraw)(cx_value_t* val) {
+ return cx_SET_ONLY( i_keyto(val) )
+ cx_MAP_ONLY( c_make(cx_rawvalue_t){i_keyto(&val->first), i_valto(&val->second)} );
+}
+
+STC_INLINE void
+cx_memb(_value_del)(cx_value_t* val) {
+ i_keydel(cx_keyref(val));
+ cx_MAP_ONLY( i_valdel(&val->second); )
+}
+
+STC_INLINE void
+cx_memb(_value_clone)(cx_value_t* dst, cx_value_t* val) {
+ *cx_keyref(dst) = i_keyfrom(i_keyto(cx_keyref(val)));
+ cx_MAP_ONLY( dst->second = i_valfrom(i_valto(&val->second)); )
+}
+
+cx_MAP_ONLY(
+ STC_API cx_result_t cx_memb(_insert_or_assign)(Self* self, i_key key, i_val mapped);
+ STC_API cx_result_t cx_memb(_emplace_or_assign)(Self* self, i_keyraw rkey, i_valraw rmapped);
-#define _c_aatree_types(CX, C, Key, Mapped) \
- typedef Key CX##_key_t; \
- typedef Mapped CX##_mapped_t; \
- typedef CSMAP_SIZE_T CX##_size_t; \
-\
- typedef SET_ONLY_##C( CX##_key_t ) \
- MAP_ONLY_##C( struct CX##_value_t ) \
- CX##_value_t; \
-\
- typedef struct { \
- CX##_value_t *ref; \
- bool inserted; \
- } CX##_result_t; \
-\
- typedef struct CX##_node_t CX##_node_t; \
-\
- typedef struct { \
- CX##_value_t *ref; \
- CX##_node_t *_d; \
- int _top; \
- CX##_size_t _tn, _st[36]; \
- } CX##_iter_t; \
-\
- typedef struct { \
- CX##_node_t *nodes; \
- } CX
-
-#define _c_using_aatree(CX, C, Key, Mapped, keyCompareRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey, defTypes) \
- defTypes( _c_aatree_types(CX, C, Key, Mapped); ) \
-\
- MAP_ONLY_##C( struct CX##_value_t { \
- CX##_key_t first; \
- CX##_mapped_t second; \
- }; ) \
-\
- struct CX##_node_t { \
- CX##_size_t link[2]; \
- int8_t level; \
- CX##_value_t value; \
- }; \
-\
- typedef RawKey CX##_rawkey_t; \
- typedef RawMapped CX##_rawmapped_t; \
- typedef SET_ONLY_##C( RawKey ) \
- MAP_ONLY_##C( struct { RawKey first; \
- RawMapped second; } ) \
- CX##_rawvalue_t; \
-\
- STC_API CX CX##_init(void); \
- STC_API CX CX##_clone(CX tree); \
- STC_API void CX##_del(CX* self); \
- STC_API void CX##_reserve(CX* self, size_t cap); \
- STC_API CX##_value_t* CX##_find_it(const CX* self, RawKey rkey, CX##_iter_t* out); \
- STC_API CX##_iter_t CX##_lower_bound(const CX* self, RawKey rkey); \
- STC_API CX##_value_t* CX##_front(const CX* self); \
- STC_API CX##_value_t* CX##_back(const CX* self); \
- STC_API int CX##_erase(CX* self, RawKey rkey); \
- STC_API CX##_iter_t CX##_erase_at(CX* self, CX##_iter_t it); \
- STC_API CX##_iter_t CX##_erase_range(CX* self, CX##_iter_t it1, CX##_iter_t it2); \
- STC_API CX##_result_t CX##_insert_entry_(CX* self, RawKey rkey); \
- STC_API void CX##_next(CX##_iter_t* it); \
-\
- STC_INLINE bool CX##_empty(CX tree) {return _csmap_rep(&tree)->size == 0;} \
- STC_INLINE size_t CX##_size(CX tree) {return _csmap_rep(&tree)->size;} \
- STC_INLINE size_t CX##_capacity(CX tree) {return _csmap_rep(&tree)->cap;} \
- STC_INLINE void CX##_clear(CX* self) {CX##_del(self); *self = CX##_init();} \
- STC_INLINE void CX##_swap(CX* a, CX* b) {c_swap(CX, *a, *b);} \
- STC_INLINE bool CX##_contains(const CX* self, RawKey rkey) \
- {CX##_iter_t it; return CX##_find_it(self, rkey, &it) != NULL;} \
- STC_INLINE CX##_value_t* CX##_get(const CX* self, RawKey rkey) \
- {CX##_iter_t it; return CX##_find_it(self, rkey, &it);} \
-\
- STC_INLINE CX \
- CX##_with_capacity(size_t size) { \
- CX tree = CX##_init(); \
- CX##_reserve(&tree, size); \
- return tree; \
- } \
-\
- STC_INLINE CX##_rawvalue_t \
- CX##_value_toraw(CX##_value_t* val) { \
- return SET_ONLY_##C( keyToRaw(val) ) \
- MAP_ONLY_##C( c_make(CX##_rawvalue_t){keyToRaw(&val->first), mappedToRaw(&val->second)} ); \
- } \
- STC_INLINE void \
- CX##_value_del(CX##_value_t* val) { \
- keyDel(KEY_REF_##C(val)); \
- MAP_ONLY_##C( mappedDel(&val->second); ) \
- } \
- STC_INLINE void \
- CX##_value_clone(CX##_value_t* dst, CX##_value_t* val) { \
- *KEY_REF_##C(dst) = keyFromRaw(keyToRaw(KEY_REF_##C(val))); \
- MAP_ONLY_##C( dst->second = mappedFromRaw(mappedToRaw(&val->second)); ) \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_find(const CX* self, RawKey rkey) { \
- CX##_iter_t it; \
- CX##_find_it(self, rkey, &it); \
- return it; \
- } \
-\
- STC_INLINE CX##_result_t \
- CX##_emplace(CX* self, RawKey rkey MAP_ONLY_##C(, RawMapped rmapped)) { \
- CX##_result_t res = CX##_insert_entry_(self, rkey); \
- if (res.inserted) { \
- *KEY_REF_##C(res.ref) = keyFromRaw(rkey); \
- MAP_ONLY_##C(res.ref->second = mappedFromRaw(rmapped);) \
- } \
- return res; \
- } \
-\
- STC_INLINE void \
- CX##_emplace_items(CX* self, const CX##_rawvalue_t arr[], size_t n) { \
- for (size_t i=0; i<n; ++i) SET_ONLY_##C( CX##_emplace(self, arr[i]); ) \
- MAP_ONLY_##C( CX##_emplace(self, arr[i].first, arr[i].second); ) \
- } \
-\
- STC_INLINE CX##_result_t \
- CX##_insert(CX* self, Key key MAP_ONLY_##C(, Mapped mapped)) { \
- CX##_result_t res = CX##_insert_entry_(self, keyToRaw(&key)); \
- if (res.inserted) {*KEY_REF_##C(res.ref) = key; MAP_ONLY_##C( res.ref->second = mapped; )} \
- else {keyDel(&key); MAP_ONLY_##C( mappedDel(&mapped); )} \
- return res; \
- } \
-\
- MAP_ONLY_##C( \
- STC_INLINE CX##_result_t \
- CX##_insert_or_assign(CX* self, Key key, Mapped mapped) { \
- CX##_result_t res = CX##_insert_entry_(self, keyToRaw(&key)); \
- if (res.inserted) res.ref->first = key; \
- else {keyDel(&key); mappedDel(&res.ref->second);} \
- res.ref->second = mapped; return res; \
- } \
- \
- STC_INLINE CX##_result_t \
- CX##_put(CX* self, Key key, Mapped mapped) { \
- return CX##_insert_or_assign(self, key, mapped); \
- } \
- \
- STC_INLINE CX##_result_t \
- CX##_emplace_or_assign(CX* self, RawKey rkey, RawMapped rmapped) { \
- CX##_result_t res = CX##_insert_entry_(self, rkey); \
- if (res.inserted) res.ref->first = keyFromRaw(rkey); \
- else mappedDel(&res.ref->second); \
- res.ref->second = mappedFromRaw(rmapped); return res; \
- } \
- \
- STC_INLINE CX##_mapped_t* \
- CX##_at(const CX* self, RawKey rkey) { \
- CX##_iter_t it; \
- return &CX##_find_it(self, rkey, &it)->second; \
- }) \
-\
- STC_INLINE CX##_iter_t \
- CX##_begin(const CX* self) { \
- CX##_iter_t it; it._d = self->nodes, it._top = 0; \
- it._tn = (CX##_size_t) _csmap_rep(self)->root; \
- if (it._tn) CX##_next(&it); \
- return it; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_end(const CX* self) {\
- return c_make(CX##_iter_t){.ref = NULL}; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_fwd(CX##_iter_t it, size_t n) { \
- while (n-- && it.ref) CX##_next(&it); \
- return it; \
- } \
-\
- _c_implement_aatree(CX, C, Key, Mapped, keyCompareRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey) \
- struct stc_trailing_semicolon
+ STC_INLINE cx_result_t
+ cx_memb(_put)(Self* self, i_key key, i_val mapped)
+ { return cx_memb(_insert_or_assign)(self, key, mapped); }
+
+ STC_INLINE cx_mapped_t*
+ cx_memb(_at)(const Self* self, i_keyraw rkey)
+ { cx_iter_t it; return &cx_memb(_find_it)(self, rkey, &it)->second; }
+)
+
+STC_INLINE cx_iter_t
+cx_memb(_find)(const Self* self, i_keyraw rkey) {
+ cx_iter_t it;
+ cx_memb(_find_it)(self, rkey, &it);
+ return it;
+}
+
+STC_INLINE cx_result_t
+cx_memb(_emplace)(Self* self, i_keyraw rkey cx_MAP_ONLY(, i_valraw rmapped)) {
+ cx_result_t res = cx_memb(_insert_entry_)(self, rkey);
+ if (res.inserted) {
+ *cx_keyref(res.ref) = i_keyfrom(rkey);
+ cx_MAP_ONLY(res.ref->second = i_valfrom(rmapped);)
+ }
+ return res;
+}
+
+STC_INLINE void
+cx_memb(_emplace_items)(Self* self, const cx_rawvalue_t arr[], size_t n) {
+ for (size_t i=0; i<n; ++i) cx_SET_ONLY( cx_memb(_emplace)(self, arr[i]); )
+ cx_MAP_ONLY( cx_memb(_emplace)(self, arr[i].first, arr[i].second); )
+}
+
+STC_INLINE cx_result_t
+cx_memb(_insert)(Self* self, i_key key cx_MAP_ONLY(, i_val mapped)) {
+ cx_result_t res = cx_memb(_insert_entry_)(self, i_keyto(&key));
+ if (res.inserted) { *cx_keyref(res.ref) = key; cx_MAP_ONLY( res.ref->second = mapped; )}
+ else { i_keydel(&key); cx_MAP_ONLY( i_valdel(&mapped); )}
+ return res;
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_begin)(const Self* self) {
+ cx_iter_t it; it._d = self->nodes, it._top = 0;
+ it._tn = (cx_size_t) _csmap_rep(self)->root;
+ if (it._tn) cx_memb(_next)(&it);
+ return it;
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_end)(const Self* self) {
+ return c_make(cx_iter_t){.ref = NULL};
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_advance)(cx_iter_t it, size_t n) {
+ while (n-- && it.ref) cx_memb(_next)(&it);
+ return it;
+}
/* -------------------------- IMPLEMENTATION ------------------------- */
+#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) || defined(i_imp)
-#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
+#ifndef CSMAP_H_INCLUDED
static struct csmap_rep _csmap_sentinel = {0, 0, 0, 0, 0};
+#endif // CSMAP_H_INCLUDED
+
+STC_DEF Self
+cx_memb(_init)(void) {
+ Self tree = {(cx_node_t *) _csmap_sentinel.nodes};
+ return tree;
+}
-#define _c_implement_aatree(CX, C, Key, Mapped, keyCompareRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey) \
- STC_DEF CX \
- CX##_init(void) { \
- CX tree = {(CX##_node_t *) _csmap_sentinel.nodes}; \
- return tree; \
- } \
-\
- STC_DEF CX##_value_t* \
- CX##_front(const CX* self) { \
- CX##_node_t *d = self->nodes; \
- CX##_size_t tn = (CX##_size_t) _csmap_rep(self)->root; \
- while (d[tn].link[0]) tn = d[tn].link[0]; \
- return &d[tn].value; \
- } \
-\
- STC_DEF CX##_value_t* \
- CX##_back(const CX* self) { \
- CX##_node_t *d = self->nodes; \
- CX##_size_t tn = (CX##_size_t) _csmap_rep(self)->root; \
- while (d[tn].link[1]) tn = d[tn].link[1]; \
- return &d[tn].value; \
- } \
-\
- STC_DEF void \
- CX##_reserve(CX* self, size_t cap) { \
- struct csmap_rep* rep = _csmap_rep(self); \
- CX##_size_t oldcap = rep->cap; \
- if (cap > oldcap) { \
- rep = (struct csmap_rep*) c_realloc(oldcap ? rep : NULL, \
- sizeof(struct csmap_rep) + (cap + 1)*sizeof(CX##_node_t)); \
- if (oldcap == 0) \
- memset(rep, 0, sizeof(struct csmap_rep) + sizeof(CX##_node_t)); \
- rep->cap = cap; \
- self->nodes = (CX##_node_t *) rep->nodes; \
- } \
- } \
-\
- STC_DEF CX##_size_t \
- CX##_node_new_(CX* self, int level) { \
- size_t tn; struct csmap_rep *rep = _csmap_rep(self); \
- if (rep->disp) { \
- tn = rep->disp; \
- rep->disp = self->nodes[tn].link[1]; \
- } else { \
- if ((tn = rep->head + 1) > rep->cap) CX##_reserve(self, 4 + (tn*13 >> 3)); \
- ++_csmap_rep(self)->head; /* do after reserve */ \
- } \
- CX##_node_t* dn = &self->nodes[tn]; \
- dn->link[0] = dn->link[1] = 0; dn->level = level; \
- return (CX##_size_t) tn; \
- } \
-\
- STC_DEF CX##_value_t* \
- CX##_find_it(const CX* self, RawKey rkey, CX##_iter_t* out) { \
- CX##_size_t tn = _csmap_rep(self)->root; \
- CX##_node_t *d = out->_d = self->nodes; \
- out->_top = 0; \
- while (tn) { \
- int c; CX##_rawkey_t raw = keyToRaw(KEY_REF_##C(&d[tn].value)); \
- if ((c = keyCompareRaw(&raw, &rkey)) < 0) \
- tn = d[tn].link[1]; \
- else if (c > 0) \
- { out->_st[out->_top++] = tn; tn = d[tn].link[0]; } \
- else \
- { out->_tn = d[tn].link[1]; return (out->ref = &d[tn].value); } \
- } \
- return (out->ref = NULL); \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_lower_bound(const CX* self, RawKey rkey) { \
- CX##_iter_t it; \
- CX##_find_it(self, rkey, &it); \
- if (!it.ref && it._top) { \
- CX##_size_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##_next(CX##_iter_t *it) { \
- CX##_size_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; \
- } \
-\
- static CX##_size_t \
- CX##_skew_(CX##_node_t *d, CX##_size_t tn) { \
- if (tn && d[d[tn].link[0]].level == d[tn].level) { \
- CX##_size_t tmp = d[tn].link[0]; \
- d[tn].link[0] = d[tmp].link[1]; \
- d[tmp].link[1] = tn; \
- tn = tmp; \
- } \
- return tn; \
- } \
- static CX##_size_t \
- CX##_split_(CX##_node_t *d, CX##_size_t tn) { \
- if (d[d[d[tn].link[1]].link[1]].level == d[tn].level) { \
- CX##_size_t tmp = d[tn].link[1]; \
- d[tn].link[1] = d[tmp].link[0]; \
- d[tmp].link[0] = tn; \
- tn = tmp; \
- ++d[tn].level; \
- } \
- return tn; \
- } \
-\
- STC_DEF CX##_size_t \
- CX##_insert_entry_i_(CX* self, CX##_size_t tn, const CX##_rawkey_t* rkey, CX##_result_t* res) { \
- CX##_size_t up[64], tx = tn; \
- CX##_node_t* d = self->nodes; \
- int c, top = 0, dir = 0; \
- while (tx) { \
- up[top++] = tx; \
- RawKey raw = keyToRaw(KEY_REF_##C(&d[tx].value)); \
- if ((c = keyCompareRaw(&raw, rkey)) == 0) {res->ref = &d[tx].value; return tn;} \
- dir = (c < 0); \
- tx = d[tx].link[dir]; \
- } \
- tx = CX##_node_new_(self, 1); d = self->nodes; \
- res->ref = &d[tx].value, res->inserted = true; \
- if (top == 0) return tx; \
- d[up[top - 1]].link[dir] = tx; \
- while (top--) { \
- if (top) dir = (d[up[top - 1]].link[1] == up[top]); \
- up[top] = CX##_skew_(d, up[top]); \
- up[top] = CX##_split_(d, up[top]); \
- if (top) d[up[top - 1]].link[dir] = up[top]; \
- } \
- return up[0]; \
- } \
-\
- STC_DEF CX##_result_t \
- CX##_insert_entry_(CX* self, RawKey rkey) { \
- CX##_result_t res = {NULL, false}; \
- CX##_size_t tn = CX##_insert_entry_i_(self, (CX##_size_t) _csmap_rep(self)->root, &rkey, &res); \
- _csmap_rep(self)->root = tn; \
- _csmap_rep(self)->size += res.inserted; \
- return res; \
- } \
-\
- STC_DEF CX##_size_t \
- CX##_erase_r_(CX##_node_t *d, CX##_size_t tn, const CX##_rawkey_t* rkey, int *erased) { \
- if (tn == 0) return 0; \
- RawKey raw = keyToRaw(KEY_REF_##C(&d[tn].value)); \
- CX##_size_t tx; int c = keyCompareRaw(&raw, rkey); \
- if (c != 0) \
- d[tn].link[c < 0] = CX##_erase_r_(d, d[tn].link[c < 0], rkey, erased); \
- else { \
- if (!(*erased)++) CX##_value_del(&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]; \
- memcpy((void *) &d[tn].value, &d[tx].value, sizeof d[0].value); /* move */ \
- raw = keyToRaw(KEY_REF_##C(&d[tn].value)); \
- d[tn].link[0] = CX##_erase_r_(d, d[tn].link[0], &raw, erased); \
- } else { /* unlink node */ \
- tx = tn; \
- tn = d[tn].link[ d[tn].link[0] == 0 ]; \
- /* move it to disposed nodes list */ \
- struct csmap_rep *rep = c_container_of(d, struct csmap_rep, nodes); \
- d[tx].link[1] = (CX##_size_t) rep->disp; \
- rep->disp = tx; \
- } \
- } \
- tx = d[tn].link[1]; \
- 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##_skew_(d, tn); \
- tx = d[tn].link[1] = CX##_skew_(d, d[tn].link[1]); \
- d[tx].link[1] = CX##_skew_(d, d[tx].link[1]); \
- tn = CX##_split_(d, tn); \
- d[tn].link[1] = CX##_split_(d, d[tn].link[1]); \
- } \
- return tn; \
- } \
-\
- STC_DEF int \
- CX##_erase(CX* self, RawKey rkey) { \
- int erased = 0; \
- CX##_size_t root = CX##_erase_r_(self->nodes, (CX##_size_t) _csmap_rep(self)->root, &rkey, &erased); \
- return erased ? (_csmap_rep(self)->root = root, --_csmap_rep(self)->size, 1) : 0; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_erase_at(CX* self, CX##_iter_t it) { \
- CX##_rawkey_t raw = keyToRaw(KEY_REF_##C(it.ref)), nxt; \
- CX##_next(&it); \
- if (it.ref) nxt = keyToRaw(KEY_REF_##C(it.ref)); \
- CX##_erase(self, raw); \
- if (it.ref) CX##_find_it(self, nxt, &it); \
- return it; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_erase_range(CX* self, CX##_iter_t it1, CX##_iter_t it2) { \
- if (!it2.ref) { while (it1.ref) it1 = CX##_erase_at(self, it1); \
- return it1; } \
- CX##_key_t k1 = *KEY_REF_##C(it1.ref), k2 = *KEY_REF_##C(it2.ref); \
- CX##_rawkey_t r1 = keyToRaw(&k1); \
- for (;;) { \
- if (memcmp(&k1, &k2, sizeof k1) == 0) return it1; \
- CX##_next(&it1); k1 = *KEY_REF_##C(it1.ref); \
- CX##_erase(self, r1); \
- CX##_find_it(self, (r1 = keyToRaw(&k1)), &it1); \
- } \
- } \
-\
- static CX##_size_t \
- CX##_clone_r_(CX* self, CX##_node_t* src, CX##_size_t sn) { \
- if (sn == 0) return 0; \
- CX##_size_t tx, tn = CX##_node_new_(self, src[sn].level); \
- CX##_value_clone(&self->nodes[tn].value, &src[sn].value); \
- tx = CX##_clone_r_(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx; \
- tx = CX##_clone_r_(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx; \
- return tn; \
- } \
- STC_DEF CX \
- CX##_clone(CX tree) { \
- CX clone = CX##_with_capacity(_csmap_rep(&tree)->size); \
- CX##_size_t root = CX##_clone_r_(&clone, tree.nodes, (CX##_size_t) _csmap_rep(&tree)->root); \
- _csmap_rep(&clone)->root = root; \
- _csmap_rep(&clone)->size = _csmap_rep(&tree)->size; \
- return clone; \
- } \
-\
- STC_DEF void \
- CX##_del_r_(CX##_node_t* d, CX##_size_t tn) { \
- if (tn) { \
- CX##_del_r_(d, d[tn].link[0]); \
- CX##_del_r_(d, d[tn].link[1]); \
- CX##_value_del(&d[tn].value); \
- } \
- } \
- STC_DEF void \
- CX##_del(CX* self) { \
- if (_csmap_rep(self)->root) { \
- CX##_del_r_(self->nodes, (CX##_size_t) _csmap_rep(self)->root); \
- c_free(_csmap_rep(self)); \
- } \
+STC_DEF cx_value_t*
+cx_memb(_front)(const Self* self) {
+ cx_node_t *d = self->nodes;
+ cx_size_t tn = (cx_size_t) _csmap_rep(self)->root;
+ while (d[tn].link[0]) tn = d[tn].link[0];
+ return &d[tn].value;
+}
+
+STC_DEF cx_value_t*
+cx_memb(_back)(const Self* self) {
+ cx_node_t *d = self->nodes;
+ cx_size_t tn = (cx_size_t) _csmap_rep(self)->root;
+ while (d[tn].link[1]) tn = d[tn].link[1];
+ return &d[tn].value;
+}
+
+STC_DEF void
+cx_memb(_reserve)(Self* self, size_t cap) {
+ struct csmap_rep* rep = _csmap_rep(self);
+ cx_size_t oldcap = rep->cap;
+ if (cap > oldcap) {
+ rep = (struct csmap_rep*) c_realloc(oldcap ? rep : NULL,
+ sizeof(struct csmap_rep) + (cap + 1)*sizeof(cx_node_t));
+ if (oldcap == 0)
+ memset(rep, 0, sizeof(struct csmap_rep) + sizeof(cx_node_t));
+ rep->cap = cap;
+ self->nodes = (cx_node_t *) rep->nodes;
}
+}
-#else
-#define _c_implement_aatree(CX, C, Key, Mapped, keyCompareRaw, \
- mappedDel, mappedFromRaw, mappedToRaw, RawMapped, \
- keyDel, keyFromRaw, keyToRaw, RawKey)
-#endif
+STC_DEF cx_size_t
+cx_memb(_node_new_)(Self* self, int level) {
+ size_t tn; struct csmap_rep *rep = _csmap_rep(self);
+ if (rep->disp) {
+ tn = rep->disp;
+ rep->disp = self->nodes[tn].link[1];
+ } else {
+ if ((tn = rep->head + 1) > rep->cap) cx_memb(_reserve)(self, 4 + (tn*13 >> 3));
+ ++_csmap_rep(self)->head; /* do after reserve */
+ }
+ cx_node_t* dn = &self->nodes[tn];
+ dn->link[0] = dn->link[1] = 0; dn->level = level;
+ return (cx_size_t) tn;
+}
-#endif
+cx_MAP_ONLY(
+ STC_DEF cx_result_t
+ cx_memb(_insert_or_assign)(Self* self, i_key key, i_val mapped) {
+ cx_result_t res = cx_memb(_insert_entry_)(self, i_keyto(&key));
+ if (res.inserted) res.ref->first = key;
+ else {i_keydel(&key); i_valdel(&res.ref->second); }
+ res.ref->second = mapped; return res;
+ }
+
+ STC_DEF cx_result_t
+ cx_memb(_emplace_or_assign)(Self* self, i_keyraw rkey, i_valraw rmapped) {
+ cx_result_t res = cx_memb(_insert_entry_)(self, rkey);
+ if (res.inserted) res.ref->first = i_keyfrom(rkey);
+ else i_valdel(&res.ref->second);
+ res.ref->second = i_valfrom(rmapped); return res;
+ }
+)
+
+STC_DEF cx_value_t*
+cx_memb(_find_it)(const Self* self, i_keyraw rkey, cx_iter_t* out) {
+ cx_size_t tn = _csmap_rep(self)->root;
+ cx_node_t *d = out->_d = self->nodes;
+ out->_top = 0;
+ while (tn) {
+ int c; cx_rawkey_t raw = i_keyto(cx_keyref(&d[tn].value));
+ if ((c = i_cmp(&raw, &rkey)) < 0)
+ tn = d[tn].link[1];
+ else if (c > 0)
+ { out->_st[out->_top++] = tn; tn = d[tn].link[0]; }
+ else
+ { out->_tn = d[tn].link[1]; return (out->ref = &d[tn].value); }
+ }
+ return (out->ref = NULL);
+}
+
+STC_DEF cx_iter_t
+cx_memb(_lower_bound)(const Self* self, i_keyraw rkey) {
+ cx_iter_t it;
+ cx_memb(_find_it)(self, rkey, &it);
+ if (!it.ref && it._top) {
+ cx_size_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_t *it) {
+ cx_size_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_size_t
+cx_memb(_skew_)(cx_node_t *d, cx_size_t tn) {
+ if (tn && d[d[tn].link[0]].level == d[tn].level) {
+ cx_size_t tmp = d[tn].link[0];
+ d[tn].link[0] = d[tmp].link[1];
+ d[tmp].link[1] = tn;
+ tn = tmp;
+ }
+ return tn;
+}
+
+STC_DEF cx_size_t
+cx_memb(_split_)(cx_node_t *d, cx_size_t tn) {
+ if (d[d[d[tn].link[1]].link[1]].level == d[tn].level) {
+ cx_size_t tmp = d[tn].link[1];
+ d[tn].link[1] = d[tmp].link[0];
+ d[tmp].link[0] = tn;
+ tn = tmp;
+ ++d[tn].level;
+ }
+ return tn;
+}
+
+STC_DEF cx_size_t
+cx_memb(_insert_entry_i_)(Self* self, cx_size_t tn, const cx_rawkey_t* rkey, cx_result_t* res) {
+ cx_size_t up[64], tx = tn;
+ cx_node_t* d = self->nodes;
+ int c, top = 0, dir = 0;
+ while (tx) {
+ up[top++] = tx;
+ i_keyraw raw = i_keyto(cx_keyref(&d[tx].value));
+ if ((c = i_cmp(&raw, rkey)) == 0) {res->ref = &d[tx].value; return tn; }
+ dir = (c < 0);
+ tx = d[tx].link[dir];
+ }
+ tx = cx_memb(_node_new_)(self, 1); d = self->nodes;
+ res->ref = &d[tx].value, res->inserted = true;
+ if (top == 0) return tx;
+ d[up[top - 1]].link[dir] = tx;
+ 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]);
+ if (top) d[up[top - 1]].link[dir] = up[top];
+ }
+ return up[0];
+}
+
+STC_DEF cx_result_t
+cx_memb(_insert_entry_)(Self* self, i_keyraw rkey) {
+ cx_result_t res = {NULL, false};
+ cx_size_t tn = cx_memb(_insert_entry_i_)(self, (cx_size_t) _csmap_rep(self)->root, &rkey, &res);
+ _csmap_rep(self)->root = tn;
+ _csmap_rep(self)->size += res.inserted;
+ return res;
+}
+
+STC_DEF cx_size_t
+cx_memb(_erase_r_)(cx_node_t *d, cx_size_t tn, const cx_rawkey_t* rkey, int *erased) {
+ if (tn == 0)
+ return 0;
+ i_keyraw raw = i_keyto(cx_keyref(&d[tn].value));
+ cx_size_t tx; int c = i_cmp(&raw, rkey);
+ if (c != 0)
+ d[tn].link[c < 0] = cx_memb(_erase_r_)(d, d[tn].link[c < 0], rkey, erased);
+ else {
+ if (!(*erased)++)
+ cx_memb(_value_del)(&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(cx_keyref(&d[tn].value));
+ d[tn].link[0] = cx_memb(_erase_r_)(d, d[tn].link[0], &raw, erased);
+ } else { /* unlink node */
+ tx = tn;
+ tn = d[tn].link[ d[tn].link[0] == 0 ];
+ /* move it to disposed nodes list */
+ struct csmap_rep *rep = c_container_of(d, struct csmap_rep, nodes);
+ d[tx].link[1] = (cx_size_t) rep->disp;
+ rep->disp = tx;
+ }
+ }
+ tx = d[tn].link[1];
+ 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]);
+ }
+ return tn;
+}
+
+STC_DEF int
+cx_memb(_erase)(Self* self, i_keyraw rkey) {
+ int erased = 0;
+ cx_size_t root = cx_memb(_erase_r_)(self->nodes, (cx_size_t) _csmap_rep(self)->root, &rkey, &erased);
+ return erased ? (_csmap_rep(self)->root = root, --_csmap_rep(self)->size, 1) : 0;
+}
+
+STC_DEF cx_iter_t
+cx_memb(_erase_at)(Self* self, cx_iter_t it) {
+ cx_rawkey_t raw = i_keyto(cx_keyref(it.ref)), nxt;
+ cx_memb(_next)(&it);
+ if (it.ref) nxt = i_keyto(cx_keyref(it.ref));
+ cx_memb(_erase)(self, raw);
+ if (it.ref) cx_memb(_find_it)(self, nxt, &it);
+ return it;
+}
+
+STC_DEF cx_iter_t
+cx_memb(_erase_range)(Self* self, cx_iter_t it1, cx_iter_t it2) {
+ if (!it2.ref) { while (it1.ref) it1 = cx_memb(_erase_at)(self, it1);
+ return it1; }
+ cx_key_t k1 = *cx_keyref(it1.ref), k2 = *cx_keyref(it2.ref);
+ cx_rawkey_t r1 = i_keyto(&k1);
+ for (;;) {
+ if (memcmp(&k1, &k2, sizeof k1) == 0) return it1;
+ cx_memb(_next)(&it1); k1 = *cx_keyref(it1.ref);
+ cx_memb(_erase)(self, r1);
+ cx_memb(_find_it)(self, (r1 = i_keyto(&k1)), &it1);
+ }
+}
+
+STC_DEF cx_size_t
+cx_memb(_clone_r_)(Self* self, cx_node_t* src, cx_size_t sn) {
+ if (sn == 0) return 0;
+ cx_size_t tx, tn = cx_memb(_node_new_)(self, src[sn].level);
+ cx_memb(_value_clone)(&self->nodes[tn].value, &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 Self
+cx_memb(_clone)(Self tree) {
+ Self clone = cx_memb(_with_capacity)(_csmap_rep(&tree)->size);
+ cx_size_t root = cx_memb(_clone_r_)(&clone, tree.nodes, (cx_size_t) _csmap_rep(&tree)->root);
+ _csmap_rep(&clone)->root = root;
+ _csmap_rep(&clone)->size = _csmap_rep(&tree)->size;
+ return clone;
+}
+
+STC_DEF void
+cx_memb(_del_r_)(cx_node_t* d, cx_size_t tn) {
+ if (tn) {
+ cx_memb(_del_r_)(d, d[tn].link[0]);
+ cx_memb(_del_r_)(d, d[tn].link[1]);
+ cx_memb(_value_del)(&d[tn].value);
+ }
+}
+
+STC_DEF void
+cx_memb(_del)(Self* self) {
+ if (_csmap_rep(self)->root) {
+ cx_memb(_del_r_)(self->nodes, (cx_size_t) _csmap_rep(self)->root);
+ c_free(_csmap_rep(self));
+ }
+}
+
+#endif // IMPLEMENTATION
+#undef i_isset
+#undef cx_keyref
+#undef cx_MAP_ONLY
+#undef cx_SET_ONLY
+#include "template.h"
+#define CSMAP_H_INCLUDED
diff --git a/include/stc/csptr.h b/include/stc/csptr.h
index 4f183498..d1a0cfe6 100644
--- a/include/stc/csptr.h
+++ b/include/stc/csptr.h
@@ -20,14 +20,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#ifndef CSPTR_H_INCLUDED
-#define CSPTR_H_INCLUDED
-
-#include "ccommon.h"
/* csptr: shared_ptr type
-
-#include <stc/csptr.h>
#include <stc/cstr.h>
typedef struct { cstr name, last; } Person;
@@ -40,7 +34,10 @@ void Person_del(Person* p) {
c_del(cstr, &p->name, &p->last);
}
-using_csptr(person, Person, c_no_compare, Person_del);
+#define i_tag person
+#define i_val Person
+#define i_valdel Person_del
+#include <stc/csptr.h>
int main() {
csptr_person p = csptr_person_make(Person_init("John", "Smiths"));
@@ -50,6 +47,13 @@ int main() {
c_del(csptr_person, &p, &q);
}
*/
+
+#ifndef CSPTR_H_INCLUDED
+#define CSPTR_H_INCLUDED
+#include "ccommon.h"
+#include "forward.h"
+#include <stdlib.h>
+
typedef long atomic_count_t;
#if defined(__GNUC__) || defined(__clang__)
#define c_atomic_increment(v) (void)__atomic_add_fetch(v, 1, __ATOMIC_SEQ_CST)
@@ -68,113 +72,96 @@ typedef long atomic_count_t;
}
#endif
-#define forward_csptr(X, Value) _csptr_types(csptr_##X, Value)
#define csptr_null {NULL, NULL}
+#endif // CSPTR_H_INCLUDED
+#ifndef i_prefix
+#define i_prefix csptr_
+#endif
+#include "template.h"
-#define using_csptr(...) c_MACRO_OVERLOAD(using_csptr, __VA_ARGS__)
-
-#define using_csptr_2(X, Value) \
- using_csptr_3(X, Value, c_default_compare)
-#define using_csptr_3(X, Value, valueCompare) \
- using_csptr_4(X, Value, valueCompare, c_default_del)
-#define using_csptr_4(X, Value, valueCompare, valueDel) \
- _c_using_csptr(csptr_##X, Value, valueCompare, valueDel, c_true)
-#define using_csptr_5(X, Value, valueCompare, valueDel, defTypes) \
- _c_using_csptr(csptr_##X, Value, valueCompare, valueDel, defTypes)
-
-#define _csptr_types(CX, Value) \
- typedef Value CX##_value_t; \
-\
- typedef struct { \
- CX##_value_t* get; \
- atomic_count_t* use_count; \
- } CX
-
-#define _c_using_csptr(CX, Value, valueCompare, valueDel, defTypes) \
- defTypes( _csptr_types(CX, Value); ) \
- struct CX##_rep_ {atomic_count_t cnt; CX##_value_t val;}; \
-\
- STC_INLINE CX \
- CX##_init() { return c_make(CX){NULL, NULL}; } \
-\
- STC_INLINE atomic_count_t \
- CX##_use_count(CX ptr) { return ptr.use_count ? *ptr.use_count : 0; } \
-\
- STC_INLINE CX \
- CX##_from(CX##_value_t* p) { \
- CX ptr = {p}; \
- if (p) *(ptr.use_count = c_new(atomic_count_t)) = 1; \
- return ptr; \
- } \
-\
- STC_INLINE CX \
- CX##_make(CX##_value_t val) { \
- CX ptr; struct CX##_rep_ *rep = c_new(struct CX##_rep_); \
- *(ptr.use_count = &rep->cnt) = 1; \
- *(ptr.get = &rep->val) = val; \
- return ptr; \
- } \
-\
- STC_INLINE CX \
- CX##_clone(CX ptr) { \
- if (ptr.use_count) c_atomic_increment(ptr.use_count); \
- return ptr; \
- } \
-\
- STC_INLINE CX \
- CX##_move(CX* self) { \
- CX ptr = *self; \
- self->get = NULL, self->use_count = NULL; \
- return ptr; \
- } \
-\
- STC_INLINE void \
- CX##_del(CX* self) { \
- if (self->use_count && c_atomic_decrement(self->use_count) == 0) { \
- valueDel(self->get); \
- if (self->get != &((struct CX##_rep_*)self->use_count)->val) c_free(self->get); \
- c_free(self->use_count); \
- } \
- } \
-\
- STC_INLINE void \
- CX##_reset(CX* self) { \
- CX##_del(self); \
- self->use_count = NULL, self->get = NULL; \
- } \
-\
- STC_INLINE CX##_value_t* \
- CX##_reset_with(CX* self, CX##_value_t* p) { \
- CX##_del(self); \
- *self = CX##_from(p); \
- return self->get; \
- } \
-\
- STC_INLINE CX##_value_t* \
- CX##_reset_make(CX* self, CX##_value_t val) { \
- CX##_del(self); \
- *self = CX##_make(val); \
- return self->get; \
- } \
-\
- STC_INLINE CX##_value_t* \
- CX##_copy(CX* self, CX ptr) { \
- CX##_del(self); \
- *self = ptr; \
- if (self->use_count) c_atomic_increment(self->use_count); \
- return self->get; \
- } \
-\
- STC_INLINE int \
- CX##_compare(const CX* x, const CX* y) { \
- return valueCompare(x->get, y->get); \
- } \
-\
- STC_INLINE bool \
- CX##_equals(const CX* x, const CX* y) { \
- return valueCompare(x->get, y->get) == 0; \
- } \
- struct stc_trailing_semicolon
-
+#ifndef i_fwd
+cx_deftypes(_c_csptr_types, Self, i_val);
#endif
+#define cx_csptr_rep struct cx_memb(_rep_)
+cx_csptr_rep { atomic_count_t cnt; cx_value_t val; };
+
+STC_INLINE Self
+cx_memb(_init)(void) { return c_make(Self){NULL, NULL}; }
+
+STC_INLINE atomic_count_t
+cx_memb(_use_count)(Self ptr) { return ptr.use_count ? *ptr.use_count : 0; }
+
+STC_INLINE Self
+cx_memb(_from)(cx_value_t* p) {
+ Self ptr = {p};
+ if (p) *(ptr.use_count = c_new(atomic_count_t)) = 1;
+ return ptr;
+}
+
+STC_INLINE Self
+cx_memb(_make)(cx_value_t val) {
+ Self ptr; cx_csptr_rep *rep = c_new(cx_csptr_rep);
+ *(ptr.use_count = &rep->cnt) = 1;
+ *(ptr.get = &rep->val) = val;
+ return ptr;
+}
+
+STC_INLINE Self
+cx_memb(_clone)(Self ptr) {
+ if (ptr.use_count) c_atomic_increment(ptr.use_count);
+ return ptr;
+}
+
+STC_INLINE Self
+cx_memb(_move)(Self* self) {
+ Self ptr = *self;
+ self->get = NULL, self->use_count = NULL;
+ return ptr;
+}
+
+STC_INLINE void
+cx_memb(_del)(Self* self) {
+ if (self->use_count && c_atomic_decrement(self->use_count) == 0) {
+ i_valdel(self->get);
+ if (self->get != &((cx_csptr_rep*)self->use_count)->val)
+ c_free(self->get);
+ c_free(self->use_count);
+ }
+}
+
+STC_INLINE void
+cx_memb(_reset)(Self* self) {
+ cx_memb(_del)(self);
+ self->use_count = NULL, self->get = NULL;
+}
+
+STC_INLINE cx_value_t*
+cx_memb(_reset_with)(Self* self, cx_value_t* p) {
+ cx_memb(_del)(self);
+ *self = cx_memb(_from)(p);
+ return self->get;
+}
+
+STC_INLINE cx_value_t*
+cx_memb(_reset_make)(Self* self, cx_value_t val) {
+ cx_memb(_del)(self);
+ *self = cx_memb(_make)(val);
+ return self->get;
+}
+
+STC_INLINE cx_value_t*
+cx_memb(_copy)(Self* self, Self ptr) {
+ cx_memb(_del)(self);
+ *self = ptr;
+ if (self->use_count) c_atomic_increment(self->use_count);
+ return self->get;
+}
+
+STC_INLINE int
+cx_memb(_compare)(const Self* x, const Self* y) {
+ return i_cmp(x->get, y->get);
+}
+
+#undef cx_csptr_rep
+#include "template.h" \ No newline at end of file
diff --git a/include/stc/csset.h b/include/stc/csset.h
index 747307e4..ee06ec7f 100644
--- a/include/stc/csset.h
+++ b/include/stc/csset.h
@@ -20,15 +20,14 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#ifndef CSSET_H_INCLUDED
-#define CSSET_H_INCLUDED
// Sorted set - implemented as an AA-tree (balanced binary tree).
/*
-#include <stc/csset.h>
#include <stdio.h>
-using_csset(i, int); // sorted set of int
+#define i_tag i
+#define i_key int
+#include <stc/csset.h> // sorted set of int
int main(void) {
csset_i s = csset_i_init();
@@ -43,30 +42,8 @@ int main(void) {
}
*/
-#include "csmap.h"
-
-#define forward_csset(X, Key) _c_aatree_types(csset_##X, csset_, Key, Key)
-
-#define using_csset(...) c_MACRO_OVERLOAD(using_csset, __VA_ARGS__)
-
-#define using_csset_2(X, Key) \
- using_csset_3(X, Key, c_default_compare)
-#define using_csset_3(X, Key, keyCompare) \
- using_csset_5(X, Key, keyCompare, c_default_del, c_default_fromraw)
-#define using_csset_4(X, Key, keyCompare, keyDel) \
- using_csset_5(X, Key, keyCompare, keyDel, c_no_clone)
-#define using_csset_5(X, Key, keyCompare, keyDel, keyClone) \
- using_csset_8(X, Key, keyCompare, keyDel, keyClone, c_default_toraw, Key, c_true)
-#define using_csset_8(X, Key, keyCompareRaw, keyDel, keyFromRaw, keyToRaw, RawKey, defTypes) \
- _c_using_aatree(csset_##X, csset_, Key, Key, keyCompareRaw, \
- @@, @@, @@, void, keyDel, keyFromRaw, keyToRaw, RawKey, defTypes)
-
-#define using_csset_str() \
- using_csset_8(str, cstr, c_rawstr_compare, cstr_del, \
- cstr_from, cstr_str, const char*, c_true)
-
-#define SET_ONLY_csset_(...) __VA_ARGS__
-#define MAP_ONLY_csset_(...)
-#define KEY_REF_csset_(vp) (vp)
-
+#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 d6b1b3ad..f7c16421 100644
--- a/include/stc/cstack.h
+++ b/include/stc/cstack.h
@@ -20,63 +20,84 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#ifndef CSTACK_H_INCLUDED
#define CSTACK_H_INCLUDED
+#include <stdlib.h>
+#include "ccommon.h"
+#include "forward.h"
+#endif // CSTACK_H_INCLUDED
+
+#ifndef i_prefix
+#define i_prefix cstack_
+#endif
+#include "template.h"
+
+#if !defined i_fwd
+cx_deftypes(_c_cstack_types, Self, i_val);
+#endif
+typedef i_valraw cx_rawvalue_t;
+
+STC_INLINE Self cx_memb(_init)(void)
+ { return c_make(Self){0, 0, 0}; }
+
+STC_INLINE Self cx_memb(_with_capacity)(size_t cap) {
+ Self out = {(cx_value_t *) c_malloc(cap*sizeof(cx_value_t)), 0, cap};
+ return out;
+}
+
+STC_INLINE void cx_memb(_clear)(Self* self) {
+ size_t i = self->size; self->size = 0;
+ while (i--) i_valdel(&self->data[i]);
+}
-/* Stack adapter, default uses cvec.
+STC_INLINE void cx_memb(_del)(Self* self)
+ { cx_memb(_clear)(self); c_free(self->data); }
- #include <stc/cstack.h>
- #include <stdio.h>
+STC_INLINE size_t cx_memb(_size)(Self v)
+ { return v.size; }
- using_cvec(i, int);
- using_cstack(i, cvec_i);
+STC_INLINE bool cx_memb(_empty)(Self v)
+ { return !v.size; }
- int main() {
- c_forvar (cstack_i stack = cstack_i_init(), cstack_i_del(&stack))
- {
- for (int i=0; i<100; ++i)
- cstack_i_push(&stack, i*i);
+STC_INLINE size_t cx_memb(_capacity)(Self v)
+ { return v.capacity; }
- for (int i=0; i<90; ++i)
- cstack_i_pop(&stack);
+STC_INLINE cx_value_t* cx_memb(_top)(const Self* self)
+ { return &self->data[self->size - 1]; }
- printf("top: %d\n", *cstack_i_top(&stack));
- }
+STC_INLINE void cx_memb(_pop)(Self* self)
+ { --self->size; i_valdel(&self->data[self->size]); }
+
+STC_INLINE void cx_memb(_push)(Self* self, cx_value_t value) {
+ if (self->size == self->capacity) {
+ self->capacity = self->size*3/2 + 4;
+ self->data = (cx_value_t *)c_realloc(self->data, self->capacity*sizeof value);
}
-*/
-#include "cvec.h"
-
-#define using_cstack(X, ctype) \
- _c_using_cstack(cstack_##X, ctype)
-
-#define _c_using_cstack(CX, ctype) \
- typedef ctype CX; \
- typedef ctype##_value_t CX##_value_t; \
- typedef ctype##_rawvalue_t CX##_rawvalue_t; \
- typedef ctype##_iter_t CX##_iter_t; \
-\
- STC_INLINE CX CX##_init(void) {return ctype##_init();} \
- STC_INLINE CX CX##_clone(CX st) {return ctype##_clone(st);} \
- STC_INLINE CX##_value_t CX##_value_clone(CX##_value_t val) \
- {return ctype##_value_clone(val);} \
- STC_INLINE void CX##_clear(CX* self) {ctype##_clear(self);} \
- STC_INLINE void CX##_del(CX* self) {ctype##_del(self);} \
-\
- STC_INLINE size_t CX##_size(CX st) {return ctype##_size(st);} \
- STC_INLINE bool CX##_empty(CX st) {return ctype##_empty(st);} \
- STC_INLINE CX##_value_t* CX##_top(const CX* self) {return ctype##_back(self);} \
-\
- STC_INLINE void CX##_pop(CX* self) {ctype##_pop_back(self);} \
- STC_INLINE void CX##_push(CX* self, ctype##_value_t value) \
- {ctype##_push_back(self, value);} \
- STC_INLINE void CX##_emplace(CX* self, CX##_rawvalue_t raw) \
- {ctype##_emplace_back(self, raw);} \
- STC_INLINE void CX##_emplace_items(CX *self, const CX##_rawvalue_t arr[], size_t n) \
- {ctype##_emplace_items(self, arr, n);} \
-\
- STC_INLINE CX##_iter_t CX##_begin(const CX* self) {return ctype##_begin(self);} \
- STC_INLINE CX##_iter_t CX##_end(const CX* self) {return ctype##_end(self);} \
- STC_INLINE void CX##_next(CX##_iter_t* it) {ctype##_next(it);} \
- struct stc_trailing_semicolon
+ self->data[ self->size++ ] = value;
+}
-#endif
+STC_INLINE void cx_memb(_emplace)(Self* self, cx_rawvalue_t raw)
+ { cx_memb(_push)(self, i_valfrom(raw)); }
+
+STC_INLINE Self cx_memb(_clone)(Self v) {
+ Self out = {(cx_value_t *) c_malloc(v.size*sizeof(cx_value_t)), v.size, v.size};
+ for (size_t i = 0; i < v.size; ++i, ++v.data) out.data[i] = i_valfrom(i_valto(v.data));
+ return out;
+}
+
+STC_INLINE void cx_memb(_emplace_items)(Self *self, const cx_rawvalue_t arr[], size_t n)
+ { for (size_t i = 0; i < n; ++i) cx_memb(_push)(self, i_valfrom(arr[i])); }
+
+STC_INLINE i_val cx_memb(_value_clone)(cx_value_t val)
+ { return i_valfrom(i_valto(&val)); }
+
+STC_INLINE cx_iter_t cx_memb(_begin)(const Self* self)
+ { return c_make(cx_iter_t){self->data}; }
+STC_INLINE cx_iter_t cx_memb(_end)(const Self* self)
+ { return c_make(cx_iter_t){self->data + self->size}; }
+STC_INLINE void cx_memb(_next)(cx_iter_t* it) { ++it->ref; }
+STC_INLINE cx_iter_t cx_memb(_advance)(cx_iter_t it, intptr_t offs)
+ { it.ref += offs; return it; }
+
+#include "template.h"
diff --git a/include/stc/cstr.h b/include/stc/cstr.h
index 67f1a0a5..681f38b1 100644
--- a/include/stc/cstr.h
+++ b/include/stc/cstr.h
@@ -30,9 +30,9 @@
#include <stdio.h> /* vsnprintf */
#include <ctype.h>
-typedef struct { char* str; } cstr;
-typedef struct { char *ref; } cstr_iter_t;
-typedef char cstr_value_t;
+typedef struct cstr { char* str; } cstr;
+typedef struct cstr_iter { char *ref; } cstr_iter_t;
+typedef char cstr_value_t;
#define cstr_npos (SIZE_MAX >> 1)
STC_LIBRARY_ONLY( extern const cstr cstr_null; )
@@ -62,12 +62,10 @@ STC_API void cstr_replace_all(cstr* self, const char* find, const cha
STC_API void cstr_erase_n(cstr* self, size_t pos, size_t n);
STC_API size_t cstr_find(cstr s, const char* needle);
STC_API size_t cstr_find_n(cstr s, const char* needle, size_t pos, size_t nmax);
-STC_API size_t cstr_ifind_n(cstr s, const char* needle, size_t pos, size_t nmax);
STC_API bool cstr_getdelim(cstr *self, int delim, FILE *stream);
-STC_API int c_strncasecmp(const char* s1, const char* s2, size_t nmax);
STC_API char* c_strnstrn(const char* s, const char* needle, size_t slen, size_t nlen);
-STC_API char* c_strncasestrn(const char* s, const char* needle, size_t slen, size_t nlen);
+STC_API int c_strncasecmp(const char* s1, const char* s2, size_t nmax);
STC_INLINE cstr cstr_init() { return cstr_null; }
#define cstr_lit(literal) \
@@ -122,12 +120,8 @@ STC_INLINE bool cstr_equalto(cstr s, const char* str)
{ return strcmp(s.str, str) == 0; }
STC_INLINE bool cstr_equalto_s(cstr s1, cstr s2)
{ return strcmp(s1.str, s2.str) == 0; }
-STC_INLINE bool cstr_iequalto(cstr s, const char* str)
- { return c_strncasecmp(s.str, str, cstr_npos) == 0; }
STC_INLINE bool cstr_contains(cstr s, const char* needle)
{ return strstr(s.str, needle) != NULL; }
-STC_INLINE bool cstr_icontains(cstr s, const char* needle)
- { return c_strncasestrn(s.str, needle, cstr_size(s), strlen(needle)) != NULL; }
STC_INLINE bool cstr_getline(cstr *self, FILE *stream)
{ return cstr_getdelim(self, '\n', stream); }
@@ -172,18 +166,6 @@ cstr_ends_with(cstr s, const char* sub) {
return n <= sz && !memcmp(s.str + sz - n, sub, n);
}
-STC_INLINE bool
-cstr_istarts_with(cstr s, const char* sub) {
- while (*sub && tolower(*s.str) == tolower(*sub)) ++s.str, ++sub;
- return *sub == 0;
-}
-
-STC_INLINE bool
-cstr_iends_with(cstr s, const char* sub) {
- size_t n = strlen(sub), sz = _cstr_rep(&s)->size;
- return n <= sz && !c_strncasecmp(s.str + sz - n, sub, n);
-}
-
/* container adaptor functions: */
#define cstr_toraw(xp) ((xp)->str) // deprecated
#define cstr_compare(xp, yp) strcmp((xp)->str, (yp)->str)
@@ -382,14 +364,6 @@ cstr_find_n(cstr s, const char* needle, size_t pos, size_t nmax) {
return res ? res - s.str : cstr_npos;
}
-STC_DEF size_t
-cstr_ifind_n(cstr s, const char* needle, size_t pos, size_t nmax) {
- if (pos > _cstr_rep(&s)->size) return cstr_npos;
- size_t nlen = strlen(needle);
- char* res = c_strncasestrn(s.str + pos, needle, _cstr_rep(&s)->size - pos, nmax < nlen ? nmax : nlen);
- return res ? res - s.str : cstr_npos;
-}
-
STC_DEF int
c_strncasecmp(const char* s1, const char* s2, size_t nmax) {
int ret = 0;
@@ -409,17 +383,5 @@ c_strnstrn(const char *s, const char *needle, size_t slen, size_t nlen) {
return NULL;
}
-STC_DEF char*
-c_strncasestrn(const char *s, const char *needle, size_t slen, size_t nlen) {
- if (!nlen) return (char *)s;
- if (nlen > slen) return NULL;
- int c = tolower(*needle); slen -= nlen;
- do {
- if (tolower(*s) == c && !c_strncasecmp(s, needle, nlen)) return (char *)s;
- ++s;
- } while (slen--);
- return NULL;
-}
-
#endif
#endif \ No newline at end of file
diff --git a/include/stc/csview.h b/include/stc/csview.h
index d5d6d246..6733912d 100644
--- a/include/stc/csview.h
+++ b/include/stc/csview.h
@@ -25,8 +25,8 @@
#include "cstr.h"
-typedef struct { const char* str; size_t size; } csview;
-typedef struct { const char *ref; } csview_iter_t;
+typedef struct csview { const char* str; size_t size; } csview;
+typedef struct csview_iter { const char *ref; } csview_iter_t;
typedef char csview_value_t;
#define csview_null c_make(csview){"", 0}
@@ -81,12 +81,12 @@ STC_INLINE void csview_next(csview_iter_t* it) { ++it->ref; }
STC_INLINE cstr cstr_from_v(csview sv)
{ return cstr_from_n(sv.str, sv.size); }
-STC_INLINE cstr cstr_from_replace_all_v(csview sv, csview find, csview repl)
+STC_INLINE cstr cstr_from_replace_all_v(csview sv, csview find, csview repl)
{ return cstr_from_replace_all(sv.str, sv.size, find.str, find.size,
repl.str, repl.size); }
STC_INLINE csview cstr_to_v(const cstr* self)
{ return c_make(csview){self->str, _cstr_rep(self)->size}; }
-STC_INLINE csview cstr_substr(cstr s, intptr_t pos, size_t n)
+STC_INLINE csview cstr_substr(cstr s, intptr_t pos, size_t n)
{ return csview_substr(csview_from_s(s), pos, n); }
STC_INLINE csview cstr_slice(cstr s, intptr_t p1, intptr_t p2)
{ return csview_slice(csview_from_s(s), p1, p2); }
@@ -133,12 +133,12 @@ STC_DEF csview
csview_slice(csview sv, intptr_t p1, intptr_t p2) {
if (p1 < 0) { p1 += sv.size; if (p1 < 0) p1 = 0; }
if (p2 < 0) p2 += sv.size; if (p2 > sv.size) p2 = sv.size;
- sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0; return sv;
+ sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0; return sv;
}
STC_DEF csview
csview_first_token(csview sv, csview sep) {
- const char* res = c_strnstrn(sv.str, sep.str, sv.size, sep.size);
+ const char* res = c_strnstrn(sv.str, sep.str, sv.size, sep.size);
return c_make(csview){sv.str, (res ? res - sv.str : sv.size)};
}
diff --git a/include/stc/cvec.h b/include/stc/cvec.h
index 567c22ae..03e04290 100644
--- a/include/stc/cvec.h
+++ b/include/stc/cvec.h
@@ -20,332 +20,347 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#ifndef CVEC_H_INCLUDED
-#define CVEC_H_INCLUDED
+
+/*
+#include <stc/cstr.h>
+#include <stc/forward.h>
+
+forward_cvec(i32, int);
+
+struct MyStruct {
+ cvec_i32 int_vec;
+ cstr name;
+} typedef MyStruct;
+
+#define i_val float
+#include <stc/cvec.h>
+
+#define i_val_str // special for cstr
+#include <stc/cvec.h>
+
+#define F_tag i32 // forward declared above; shorthand for i_fwd
+#define i_val int
+#include <stc/cvec.h>
+int main() {
+ cvec_i32 vec = cvec_i32_init();
+ cvec_i32_push_back(&vec, 123);
+ cvec_i32_del(&vec);
+
+ cvec_float fvec = cvec_float_init();
+ cvec_float_push_back(&fvec, 123.3);
+ cvec_float_del(&fvec);
+
+ cvec_str svec = cvec_str_init();
+ cvec_str_emplace_back(&svec, "Hello, friend");
+ cvec_str_del(&svec);
+}
+*/
+
+#ifndef CVEC_H_INCLUDED
#include "ccommon.h"
+#include "forward.h"
#include <stdlib.h>
#include <string.h>
-#define forward_cvec(X, Value) _c_cvec_types(cvec_##X, Value)
+struct cvec_rep { size_t size, cap; void* data[]; };
+#define cvec_rep_(self) c_container_of((self)->data, struct cvec_rep, data)
+#endif // CVEC_H_INCLUDED
+
+#ifndef i_prefix
+#define i_prefix cvec_
+#endif
+#include "template.h"
+
+#if !defined i_fwd
+ cx_deftypes(_c_cvec_types, Self, i_val);
+#endif
+typedef i_valraw cx_rawvalue_t;
-#define using_cvec(...) c_MACRO_OVERLOAD(using_cvec, __VA_ARGS__)
+STC_API Self cx_memb(_init)(void);
+STC_API Self cx_memb(_clone)(Self cx);
+STC_API void cx_memb(_del)(Self* self);
+STC_API void cx_memb(_clear)(Self* self);
+STC_API void cx_memb(_reserve)(Self* self, size_t cap);
+STC_API void cx_memb(_resize)(Self* self, size_t size, i_val fill_val);
+STC_API int cx_memb(_value_compare)(const cx_value_t* x, const cx_value_t* y);
+STC_API cx_iter_t cx_memb(_find_in)(cx_iter_t it1, cx_iter_t it2, i_valraw raw);
+STC_API cx_iter_t cx_memb(_bsearch_in)(cx_iter_t it1, cx_iter_t it2, i_valraw raw);
+STC_API cx_value_t* cx_memb(_push_back)(Self* self, i_val value);
+STC_API cx_iter_t cx_memb(_erase_range_p)(Self* self, cx_value_t* p1, cx_value_t* p2);
+STC_API cx_iter_t cx_memb(_insert_range_p)(Self* self, cx_value_t* pos,
+ const cx_value_t* p1, const cx_value_t* p2, bool clone);
+STC_API cx_iter_t cx_memb(_emplace_range_p)(Self* self, cx_value_t* pos,
+ const cx_rawvalue_t* p1, const cx_rawvalue_t* p2);
-#define using_cvec_2(X, Value) \
- using_cvec_3(X, Value, c_default_compare)
-#define using_cvec_3(X, Value, valueCompare) \
- using_cvec_5(X, Value, valueCompare, c_default_del, c_default_fromraw)
-#define using_cvec_4(X, Value, valueCompare, valueDel) \
- using_cvec_5(X, Value, valueCompare, valueDel, c_no_clone)
-#define using_cvec_5(X, Value, valueCompare, valueDel, valueClone) \
- using_cvec_7(X, Value, valueCompare, valueDel, valueClone, c_default_toraw, Value)
-#define using_cvec_7(X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue) \
- _c_using_cvec(cvec_##X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue, c_true)
-#define using_cvec_8(X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue, defTypes) \
- _c_using_cvec(cvec_##X, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue, defTypes)
+STC_INLINE size_t cx_memb(_size)(Self cx) { return cvec_rep_(&cx)->size; }
+STC_INLINE size_t cx_memb(_capacity)(Self cx) { return cvec_rep_(&cx)->cap; }
+STC_INLINE bool cx_memb(_empty)(Self cx) { return !cvec_rep_(&cx)->size; }
+STC_INLINE i_val cx_memb(_value_fromraw)(i_valraw raw) { return i_valfrom(raw); }
+STC_INLINE i_valraw cx_memb(_value_toraw)(cx_value_t* val) { return i_valto(val); }
+STC_INLINE i_val cx_memb(_value_clone)(cx_value_t val)
+ { return i_valfrom(i_valto(&val)); }
+STC_INLINE void cx_memb(_swap)(Self* a, Self* b) { c_swap(Self, *a, *b); }
+STC_INLINE cx_value_t* cx_memb(_front)(const Self* self) { return self->data; }
+STC_INLINE cx_value_t* cx_memb(_back)(const Self* self)
+ { return self->data + cvec_rep_(self)->size - 1; }
+STC_INLINE cx_value_t* cx_memb(_emplace_back)(Self* self, i_valraw raw)
+ { return cx_memb(_push_back)(self, i_valfrom(raw)); }
+STC_INLINE void cx_memb(_pop_back)(Self* self)
+ { i_valdel(&self->data[--cvec_rep_(self)->size]); }
+STC_INLINE cx_iter_t cx_memb(_begin)(const Self* self)
+ { return c_make(cx_iter_t){self->data}; }
+STC_INLINE cx_iter_t cx_memb(_end)(const Self* self)
+ { return c_make(cx_iter_t){self->data + cvec_rep_(self)->size}; }
+STC_INLINE void cx_memb(_next)(cx_iter_t* it) { ++it->ref; }
+STC_INLINE cx_iter_t cx_memb(_advance)(cx_iter_t it, intptr_t offs)
+ { it.ref += offs; return it; }
+STC_INLINE size_t cx_memb(_index)(Self cx, cx_iter_t it) { return it.ref - cx.data; }
-#define using_cvec_str() \
- using_cvec_7(str, cstr, c_rawstr_compare, cstr_del, cstr_from, cstr_str, const char*)
+STC_INLINE Self
+cx_memb(_with_size)(size_t size, i_val null_val) {
+ Self cx = cx_memb(_init)();
+ cx_memb(_resize)(&cx, size, null_val);
+ return cx;
+}
-struct cvec_rep { size_t size, cap; void* data[]; };
-#define _cvec_rep(self) c_container_of((self)->data, struct cvec_rep, data)
-
-#define _c_cvec_types(CX, Value) \
- typedef Value CX##_value_t; \
- typedef struct { CX##_value_t *ref; } CX##_iter_t; \
- typedef struct { CX##_value_t *data; } CX
-
-#define _c_using_cvec(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue, defTypes) \
-\
- defTypes( _c_cvec_types(CX, Value); ) \
- typedef RawValue CX##_rawvalue_t; \
-\
- STC_API CX CX##_init(void); \
- STC_API CX CX##_clone(CX cx); \
- STC_API void CX##_del(CX* self); \
- STC_API void CX##_clear(CX* self); \
- STC_API void CX##_reserve(CX* self, size_t cap); \
- STC_API void CX##_resize(CX* self, size_t size, Value fill_val); \
- STC_API int CX##_value_compare(const CX##_value_t* x, const CX##_value_t* y); \
- STC_API CX##_iter_t CX##_find_in(CX##_iter_t it1, CX##_iter_t it2, RawValue raw); \
- STC_API CX##_iter_t CX##_bsearch_in(CX##_iter_t it1, CX##_iter_t it2, RawValue raw); \
- STC_API void CX##_push_back(CX* self, Value value); \
- STC_API CX##_iter_t CX##_erase_range_p(CX* self, CX##_value_t* p1, CX##_value_t* p2); \
- STC_API CX##_iter_t CX##_insert_range_p(CX* self, CX##_value_t* pos, \
- const CX##_value_t* p1, const CX##_value_t* p2, bool clone); \
- STC_API CX##_iter_t CX##_emplace_range_p(CX* self, CX##_value_t* pos, \
- const CX##_rawvalue_t* p1, const CX##_rawvalue_t* p2); \
-\
- STC_INLINE size_t CX##_size(CX cx) { return _cvec_rep(&cx)->size; } \
- STC_INLINE size_t CX##_capacity(CX cx) { return _cvec_rep(&cx)->cap; } \
- STC_INLINE bool CX##_empty(CX cx) {return !_cvec_rep(&cx)->size;} \
- STC_INLINE Value CX##_value_fromraw(RawValue raw) {return valueFromRaw(raw);} \
- STC_INLINE RawValue CX##_value_toraw(CX##_value_t* val) {return valueToRaw(val);} \
- STC_INLINE Value CX##_value_clone(CX##_value_t val) \
- {return valueFromRaw(valueToRaw(&val));} \
- STC_INLINE void CX##_swap(CX* a, CX* b) {c_swap(CX, *a, *b);} \
- STC_INLINE CX##_value_t*CX##_front(const CX* self) {return self->data;} \
- STC_INLINE CX##_value_t*CX##_back(const CX* self) \
- {return self->data + _cvec_rep(self)->size - 1;} \
- STC_INLINE void CX##_emplace_back(CX* self, RawValue raw) \
- {CX##_push_back(self, valueFromRaw(raw));} \
- STC_INLINE void CX##_pop_back(CX* self) \
- {valueDel(&self->data[--_cvec_rep(self)->size]);} \
- STC_INLINE CX##_iter_t CX##_begin(const CX* self) \
- {return c_make(CX##_iter_t){self->data};} \
- STC_INLINE CX##_iter_t CX##_end(const CX* self) \
- {return c_make(CX##_iter_t){self->data + _cvec_rep(self)->size};} \
- STC_INLINE void CX##_next(CX##_iter_t* it) {++it->ref;} \
- STC_INLINE CX##_iter_t CX##_adv(CX##_iter_t it, intptr_t offs) {it.ref += offs; return it;} \
- STC_INLINE size_t CX##_idx(CX cx, CX##_iter_t it) {return it.ref - cx.data;} \
-\
- STC_INLINE CX \
- CX##_with_size(size_t size, Value null_val) { \
- CX cx = CX##_init(); \
- CX##_resize(&cx, size, null_val); \
- return cx; \
- } \
-\
- STC_INLINE CX \
- CX##_with_capacity(size_t size) { \
- CX cx = CX##_init(); \
- CX##_reserve(&cx, size); \
- return cx; \
- } \
-\
- STC_INLINE void \
- CX##_shrink_to_fit(CX *self) { \
- CX cx = CX##_clone(*self); \
- CX##_del(self); *self = cx; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_insert(CX* self, size_t idx, Value value) { \
- return CX##_insert_range_p(self, self->data + idx, &value, &value + 1, false); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_insert_n(CX* self, size_t idx, const CX##_value_t arr[], size_t n) { \
- return CX##_insert_range_p(self, self->data + idx, arr, arr + n, false); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_insert_at(CX* self, CX##_iter_t it, Value value) { \
- return CX##_insert_range_p(self, it.ref, &value, &value + 1, false); \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_emplace(CX* self, size_t idx, RawValue raw) { \
- return CX##_emplace_range_p(self, self->data + idx, &raw, &raw + 1); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_emplace_n(CX* self, size_t idx, const CX##_rawvalue_t arr[], size_t n) { \
- return CX##_emplace_range_p(self, self->data + idx, arr, arr + n); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_emplace_at(CX* self, CX##_iter_t it, RawValue raw) { \
- return CX##_emplace_range_p(self, it.ref, &raw, &raw + 1); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_emplace_range(CX* self, CX##_iter_t it, CX##_iter_t it1, CX##_iter_t it2) { \
- return CX##_insert_range_p(self, it.ref, it1.ref, it2.ref, true); \
- } \
- STC_INLINE void \
- CX##_emplace_items(CX *self, const CX##_rawvalue_t arr[], size_t n) { \
- CX##_emplace_range_p(self, self->data + _cvec_rep(self)->size, arr, arr + n); \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_erase(CX* self, size_t idx) { \
- return CX##_erase_range_p(self, self->data + idx, self->data + idx + 1); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_erase_n(CX* self, size_t idx, size_t n) { \
- return CX##_erase_range_p(self, self->data + idx, self->data + idx + n); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_erase_at(CX* self, CX##_iter_t it) { \
- return CX##_erase_range_p(self, it.ref, it.ref + 1); \
- } \
- STC_INLINE CX##_iter_t \
- CX##_erase_range(CX* self, CX##_iter_t it1, CX##_iter_t it2) { \
- return CX##_erase_range_p(self, it1.ref, it2.ref); \
- } \
-\
- STC_INLINE CX##_value_t* \
- CX##_at(const CX* self, size_t idx) { \
- assert(idx < _cvec_rep(self)->size); \
- return self->data + idx; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_find(const CX* self, RawValue raw) { \
- return CX##_find_in(CX##_begin(self), CX##_end(self), raw); \
- } \
-\
- STC_INLINE CX##_value_t* \
- CX##_get(const CX* self, RawValue raw) { \
- CX##_iter_t end = CX##_end(self); \
- CX##_value_t* val = CX##_find_in(CX##_begin(self), end, raw).ref; \
- return val == end.ref ? NULL : val; \
- } \
-\
- STC_INLINE CX##_iter_t \
- CX##_bsearch(const CX* self, RawValue raw) { \
- return CX##_bsearch_in(CX##_begin(self), CX##_end(self), raw); \
- } \
- STC_INLINE void \
- CX##_sort_range(CX##_iter_t i1, CX##_iter_t i2, \
- int(*_cmp_)(const CX##_value_t*, const CX##_value_t*)) { \
- qsort(i1.ref, i2.ref - i1.ref, sizeof(CX##_value_t), (int(*)(const void*, const void*)) _cmp_); \
- } \
- STC_INLINE void \
- CX##_sort(CX* self) { \
- CX##_sort_range(CX##_begin(self), CX##_end(self), CX##_value_compare); \
- } \
-\
- _c_implement_cvec(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue) \
- struct stc_trailing_semicolon
+STC_INLINE Self
+cx_memb(_with_capacity)(size_t size) {
+ Self cx = cx_memb(_init)();
+ cx_memb(_reserve)(&cx, size);
+ return cx;
+}
+
+STC_INLINE void
+cx_memb(_shrink_to_fit)(Self *self) {
+ Self cx = cx_memb(_clone)(*self);
+ cx_memb(_del)(self); *self = cx;
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_insert)(Self* self, size_t idx, i_val value) {
+ return cx_memb(_insert_range_p)(self, self->data + idx, &value, &value + 1, false);
+}
+STC_INLINE cx_iter_t
+cx_memb(_insert_n)(Self* self, size_t idx, const cx_value_t arr[], size_t n) {
+ return cx_memb(_insert_range_p)(self, self->data + idx, arr, arr + n, false);
+}
+STC_INLINE cx_iter_t
+cx_memb(_insert_at)(Self* self, cx_iter_t it, i_val value) {
+ return cx_memb(_insert_range_p)(self, it.ref, &value, &value + 1, false);
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_emplace)(Self* self, size_t idx, i_valraw raw) {
+ return cx_memb(_emplace_range_p)(self, self->data + idx, &raw, &raw + 1);
+}
+STC_INLINE cx_iter_t
+cx_memb(_emplace_n)(Self* self, size_t idx, const cx_rawvalue_t arr[], size_t n) {
+ return cx_memb(_emplace_range_p)(self, self->data + idx, arr, arr + n);
+}
+STC_INLINE cx_iter_t
+cx_memb(_emplace_at)(Self* self, cx_iter_t it, i_valraw raw) {
+ return cx_memb(_emplace_range_p)(self, it.ref, &raw, &raw + 1);
+}
+STC_INLINE cx_iter_t
+cx_memb(_emplace_range)(Self* self, cx_iter_t it, cx_iter_t it1, cx_iter_t it2) {
+ return cx_memb(_insert_range_p)(self, it.ref, it1.ref, it2.ref, true);
+}
+STC_INLINE void
+cx_memb(_emplace_items)(Self *self, const cx_rawvalue_t arr[], size_t n) {
+ cx_memb(_emplace_range_p)(self, self->data + cvec_rep_(self)->size, arr, arr + n);
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_erase)(Self* self, size_t idx) {
+ return cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + 1);
+}
+STC_INLINE cx_iter_t
+cx_memb(_erase_n)(Self* self, size_t idx, size_t n) {
+ return cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n);
+}
+STC_INLINE cx_iter_t
+cx_memb(_erase_at)(Self* self, cx_iter_t it) {
+ return cx_memb(_erase_range_p)(self, it.ref, it.ref + 1);
+}
+STC_INLINE cx_iter_t
+cx_memb(_erase_range)(Self* self, cx_iter_t it1, cx_iter_t it2) {
+ return cx_memb(_erase_range_p)(self, it1.ref, it2.ref);
+}
+
+STC_INLINE cx_value_t*
+cx_memb(_at)(const Self* self, size_t idx) {
+ assert(idx < cvec_rep_(self)->size);
+ return self->data + idx;
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_find)(const Self* self, i_valraw raw) {
+ return cx_memb(_find_in)(cx_memb(_begin)(self), cx_memb(_end)(self), raw);
+}
+
+STC_INLINE cx_value_t*
+cx_memb(_get)(const Self* self, i_valraw raw) {
+ cx_iter_t end = cx_memb(_end)(self);
+ cx_value_t* val = cx_memb(_find_in)(cx_memb(_begin)(self), end, raw).ref;
+ return val == end.ref ? NULL : val;
+}
+
+STC_INLINE cx_iter_t
+cx_memb(_bsearch)(const Self* self, i_valraw raw) {
+ return cx_memb(_bsearch_in)(cx_memb(_begin)(self), cx_memb(_end)(self), raw);
+}
+STC_INLINE void
+cx_memb(_sort_range)(cx_iter_t i1, cx_iter_t i2,
+ int(*_cmp_)(const cx_value_t*, const cx_value_t*)) {
+ qsort(i1.ref, i2.ref - i1.ref, sizeof(cx_value_t), (int(*)(const void*, const void*)) _cmp_);
+}
+STC_INLINE void
+cx_memb(_sort)(Self* self) {
+ cx_memb(_sort_range)(cx_memb(_begin)(self), cx_memb(_end)(self), cx_memb(_value_compare));
+}
/* -------------------------- IMPLEMENTATION ------------------------- */
+#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) || defined(i_imp)
-#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION)
+#ifndef CVEC_H_INCLUDED
static struct cvec_rep _cvec_sentinel = {0, 0};
+#endif
+
+STC_DEF Self
+cx_memb(_init)(void) {
+ Self cx = {(cx_value_t *) _cvec_sentinel.data};
+ return cx;
+}
-#define _c_implement_cvec(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue) \
-\
- STC_DEF CX \
- CX##_init(void) { \
- CX cx = {(CX##_value_t *) _cvec_sentinel.data}; \
- return cx; \
- } \
-\
- STC_DEF void \
- CX##_clear(CX* self) { \
- struct cvec_rep* rep = _cvec_rep(self); if (rep->cap) { \
- for (CX##_value_t *p = self->data, *q = p + rep->size; p != q; ++p) \
- valueDel(p); \
- rep->size = 0; \
- } \
- } \
-\
- STC_DEF void \
- CX##_del(CX* self) { \
- CX##_clear(self); \
- if (_cvec_rep(self)->cap) \
- c_free(_cvec_rep(self)); \
- } \
-\
- STC_DEF void \
- CX##_reserve(CX* self, size_t cap) { \
- struct cvec_rep* rep = _cvec_rep(self); \
- size_t len = rep->size, oldcap = rep->cap; \
- if (cap > oldcap) { \
- rep = (struct cvec_rep*) c_realloc(oldcap ? rep : NULL, \
- offsetof(struct cvec_rep, data) + cap*sizeof(Value)); \
- self->data = (CX##_value_t*) rep->data; \
- rep->size = len; \
- rep->cap = cap; \
- } \
- } \
-\
- STC_DEF void \
- CX##_resize(CX* self, size_t len, Value null_val) { \
- CX##_reserve(self, len); \
- struct cvec_rep* rep = _cvec_rep(self); \
- size_t i, n = rep->size; \
- for (i = len; i < n; ++i) valueDel(self->data + i); \
- for (i = n; i < len; ++i) self->data[i] = null_val; \
- if (rep->cap) rep->size = len; \
- } \
-\
- STC_DEF void \
- CX##_push_back(CX* self, Value value) { \
- size_t len = _cvec_rep(self)->size; \
- if (len == CX##_capacity(*self)) \
- CX##_reserve(self, (len*13 >> 3) + 4); \
- self->data[_cvec_rep(self)->size++] = value; \
- } \
-\
- STC_DEF CX \
- CX##_clone(CX cx) { \
- size_t len = _cvec_rep(&cx)->size; \
- CX out = CX##_with_capacity(len); \
- CX##_insert_range_p(&out, out.data, cx.data, cx.data + len, true); \
- return out; \
- } \
-\
- STC_DEF CX##_value_t* \
- CX##_insert_space_(CX* self, CX##_value_t* pos, size_t len) { \
- size_t idx = pos - self->data, size = _cvec_rep(self)->size; \
- if (len == 0) return pos; \
- if (size + len > CX##_capacity(*self)) \
- CX##_reserve(self, (size*13 >> 3) + len), \
- pos = self->data + idx; \
- _cvec_rep(self)->size += len; \
- memmove(pos + len, pos, (size - idx) * sizeof(Value)); \
- return pos; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_insert_range_p(CX* self, CX##_value_t* pos, const CX##_value_t* p1, \
- const CX##_value_t* p2, bool clone) { \
- pos = CX##_insert_space_(self, pos, p2 - p1); \
- CX##_iter_t it = {pos}; \
- if (clone) while (p1 != p2) *pos++ = valueFromRaw(valueToRaw(p1++)); \
- else memcpy(pos, p1, (p2 - p1)*sizeof *p1); \
- return it; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_emplace_range_p(CX* self, CX##_value_t* pos, const CX##_rawvalue_t* p1, const CX##_rawvalue_t* p2) { \
- pos = CX##_insert_space_(self, pos, p2 - p1); \
- CX##_iter_t it = {pos}; \
- while (p1 != p2) *pos++ = valueFromRaw(*p1++); \
- return it; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_erase_range_p(CX* self, CX##_value_t* p1, CX##_value_t* p2) { \
- intptr_t len = p2 - p1; \
- if (len > 0) { \
- CX##_value_t* p = p1, *end = self->data + _cvec_rep(self)->size; \
- while (p != p2) valueDel(p++); \
- memmove(p1, p2, (end - p2) * sizeof(Value)); \
- _cvec_rep(self)->size -= len; \
- } \
- return c_make(CX##_iter_t){.ref = p1}; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_find_in(CX##_iter_t i1, CX##_iter_t i2, RawValue raw) { \
- for (; i1.ref != i2.ref; ++i1.ref) { \
- RawValue r = valueToRaw(i1.ref); \
- if (valueCompareRaw(&raw, &r) == 0) return i1; \
- } \
- return i2; \
- } \
-\
- STC_DEF CX##_iter_t \
- CX##_bsearch_in(CX##_iter_t i1, CX##_iter_t i2, RawValue raw) { \
- CX##_iter_t mid, last = i2; \
- while (i1.ref != i2.ref) { \
- mid.ref = i1.ref + ((i2.ref - i1.ref)>>1); \
- int c; RawValue m = valueToRaw(mid.ref); \
- if ((c = valueCompareRaw(&raw, &m)) == 0) return mid; \
- else if (c < 0) i2.ref = mid.ref; \
- else i1.ref = mid.ref + 1; \
- } \
- return last; \
- } \
-\
- STC_DEF int \
- CX##_value_compare(const CX##_value_t* x, const CX##_value_t* y) { \
- RawValue rx = valueToRaw(x); \
- RawValue ry = valueToRaw(y); \
- return valueCompareRaw(&rx, &ry); \
+STC_DEF void
+cx_memb(_clear)(Self* self) {
+ struct cvec_rep* rep = cvec_rep_(self); if (rep->cap) {
+ for (cx_value_t *p = self->data, *q = p + rep->size; p != q; ++p)
+ i_valdel(p);
+ rep->size = 0;
}
+}
-#else
-#define _c_implement_cvec(CX, Value, valueCompareRaw, valueDel, valueFromRaw, valueToRaw, RawValue)
-#endif
+STC_DEF void
+cx_memb(_del)(Self* self) {
+ cx_memb(_clear)(self);
+ if (cvec_rep_(self)->cap)
+ c_free(cvec_rep_(self));
+}
+
+STC_DEF void
+cx_memb(_reserve)(Self* self, size_t cap) {
+ struct cvec_rep* rep = cvec_rep_(self);
+ size_t len = rep->size, oldcap = rep->cap;
+ if (cap > oldcap) {
+ rep = (struct cvec_rep*) c_realloc(oldcap ? rep : NULL,
+ offsetof(struct cvec_rep, data) + cap*sizeof(i_val));
+ self->data = (cx_value_t*) rep->data;
+ rep->size = len;
+ rep->cap = cap;
+ }
+}
+
+STC_DEF void
+cx_memb(_resize)(Self* self, size_t len, i_val null_val) {
+ cx_memb(_reserve)(self, len);
+ struct cvec_rep* rep = cvec_rep_(self);
+ size_t i, n = rep->size;
+ for (i = len; i < n; ++i) i_valdel(self->data + i);
+ for (i = n; i < len; ++i) self->data[i] = null_val;
+ if (rep->cap) rep->size = len;
+}
+
+STC_DEF cx_value_t*
+cx_memb(_push_back)(Self* self, i_val value) {
+ size_t len = cvec_rep_(self)->size;
+ if (len == cx_memb(_capacity)(*self))
+ cx_memb(_reserve)(self, (len*13 >> 3) + 4);
+ cx_value_t *v = self->data + cvec_rep_(self)->size++;
+ *v = value; return v;
+}
+
+STC_DEF Self
+cx_memb(_clone)(Self cx) {
+ size_t len = cvec_rep_(&cx)->size;
+ Self out = cx_memb(_with_capacity)(len);
+ cx_memb(_insert_range_p)(&out, out.data, cx.data, cx.data + len, true);
+ return out;
+}
-#endif \ No newline at end of file
+STC_DEF cx_value_t*
+cx_memb(_insert_space_)(Self* self, cx_value_t* pos, size_t len) {
+ size_t idx = pos - self->data, size = cvec_rep_(self)->size;
+ if (len == 0) return pos;
+ if (size + len > cx_memb(_capacity)(*self))
+ cx_memb(_reserve)(self, (size*13 >> 3) + len),
+ pos = self->data + idx;
+ cvec_rep_(self)->size += len;
+ memmove(pos + len, pos, (size - idx) * sizeof(i_val));
+ return pos;
+}
+
+STC_DEF cx_iter_t
+cx_memb(_insert_range_p)(Self* self, cx_value_t* pos, const cx_value_t* p1,
+ const cx_value_t* p2, bool clone) {
+ pos = cx_memb(_insert_space_)(self, pos, p2 - p1);
+ cx_iter_t it = {pos};
+ if (clone) while (p1 != p2) *pos++ = i_valfrom(i_valto(p1++));
+ else memcpy(pos, p1, (p2 - p1)*sizeof *p1);
+ return it;
+}
+
+STC_DEF cx_iter_t
+cx_memb(_emplace_range_p)(Self* self, cx_value_t* pos, const cx_rawvalue_t* p1,
+ const cx_rawvalue_t* p2) {
+ pos = cx_memb(_insert_space_)(self, pos, p2 - p1);
+ cx_iter_t it = {pos};
+ while (p1 != p2) *pos++ = i_valfrom(*p1++);
+ return it;
+}
+
+STC_DEF cx_iter_t
+cx_memb(_erase_range_p)(Self* self, cx_value_t* p1, cx_value_t* p2) {
+ intptr_t len = p2 - p1;
+ if (len > 0) {
+ cx_value_t* p = p1, *end = self->data + cvec_rep_(self)->size;
+ while (p != p2) i_valdel(p++);
+ memmove(p1, p2, (end - p2) * sizeof(i_val));
+ cvec_rep_(self)->size -= len;
+ }
+ return c_make(cx_iter_t){.ref = p1};
+}
+
+STC_DEF cx_iter_t
+cx_memb(_find_in)(cx_iter_t i1, cx_iter_t i2, i_valraw raw) {
+ for (; i1.ref != i2.ref; ++i1.ref) {
+ i_valraw r = i_valto(i1.ref);
+ if (i_cmp(&raw, &r) == 0) return i1;
+ }
+ return i2;
+}
+
+STC_DEF cx_iter_t
+cx_memb(_bsearch_in)(cx_iter_t i1, cx_iter_t i2, i_valraw raw) {
+ cx_iter_t mid, last = i2;
+ while (i1.ref != i2.ref) {
+ mid.ref = i1.ref + ((i2.ref - i1.ref)>>1);
+ int c; i_valraw m = i_valto(mid.ref);
+ if ((c = i_cmp(&raw, &m)) == 0) return mid;
+ else if (c < 0) i2.ref = mid.ref;
+ else i1.ref = mid.ref + 1;
+ }
+ return last;
+}
+
+STC_DEF int
+cx_memb(_value_compare)(const cx_value_t* x, const cx_value_t* y) {
+ i_valraw rx = i_valto(x);
+ i_valraw ry = i_valto(y);
+ return i_cmp(&rx, &ry);
+}
+
+#endif
+#include "template.h"
+#define CVEC_H_INCLUDED \ No newline at end of file
diff --git a/include/stc/forward.h b/include/stc/forward.h
new file mode 100644
index 00000000..70c21440
--- /dev/null
+++ b/include/stc/forward.h
@@ -0,0 +1,156 @@
+/* MIT License
+ *
+ * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no
+ *
+ * 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_FORWARD_H_INCLUDED
+#define STC_FORWARD_H_INCLUDED
+
+#include <stddef.h>
+
+#define forward_carr2(TAG, VAL) _c_carr2_types(carr2_##TAG, VAL)
+#define forward_carr3(TAG, VAL) _c_carr3_types(carr3_##TAG, VAL)
+#define forward_cdeq(TAG, VAL) _c_cdeq_types(cdeq_##TAG, VAL)
+#define forward_clist(TAG, VAL) _c_clist_types(clist_##TAG, VAL)
+#define forward_cmap(TAG, KEY, VAL) _c_chash_types(cmap_##TAG, KEY, VAL, c_true, c_false)
+#define forward_csmap(TAG, KEY, VAL) _c_aatree_types(csmap_##TAG, KEY, VAL, c_true, c_false)
+#define forward_cset(TAG, KEY) _c_chash_types(cset_##TAG, cset, KEY, KEY, c_false, c_true)
+#define forward_csset(TAG, KEY) _c_aatree_types(csset_##TAG, KEY, KEY, c_false, c_true)
+#define forward_csptr(TAG, VAL) _c_csptr_types(csptr_##TAG, VAL)
+#define forward_cpque(TAG, VAL) _c_cpque_types(cpque_##TAG, VAL)
+#define forward_cstack(TAG, VAL) _c_cstack_types(cstack_##TAG, VAL)
+#define forward_cqueue(TAG, VAL) _c_cdeq_types(cqueue_##TAG, VAL)
+#define forward_cvec(TAG, VAL) _c_cvec_types(cvec_##TAG, VAL)
+
+#ifndef MAP_SIZE_T
+#define MAP_SIZE_T uint32_t
+#endif
+#define c_true(...) __VA_ARGS__
+#define c_false(...)
+
+#define _c_carr2_types(SELF, VAL) \
+ typedef VAL SELF##_value_t; \
+ typedef struct { SELF##_value_t *ref; } SELF##_iter_t; \
+ typedef struct { SELF##_value_t **data; size_t xdim, ydim; } SELF
+
+#define _c_carr3_types(SELF, VAL) \
+ typedef VAL SELF##_value_t; \
+ typedef struct { SELF##_value_t *ref; } SELF##_iter_t; \
+ typedef struct { SELF##_value_t ***data; size_t xdim, ydim, zdim; } SELF
+
+#define _c_cdeq_types(SELF, VAL) \
+ typedef VAL SELF##_value_t; \
+ typedef struct {SELF##_value_t *ref; } SELF##_iter_t; \
+ typedef struct {SELF##_value_t *_base, *data;} SELF
+
+#define _c_clist_types(SELF, VAL) \
+ typedef VAL SELF##_value_t; \
+ typedef struct SELF##_node_t SELF##_node_t; \
+\
+ typedef struct { \
+ SELF##_node_t *const *_last, *prev; \
+ SELF##_value_t *ref; \
+ } SELF##_iter_t; \
+\
+ typedef struct { \
+ SELF##_node_t *last; \
+ } SELF
+
+#define _c_chash_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \
+ typedef KEY SELF##_key_t; \
+ typedef VAL SELF##_mapped_t; \
+ typedef MAP_SIZE_T SELF##_size_t; \
+\
+ typedef SET_ONLY( SELF##_key_t ) \
+ MAP_ONLY( struct SELF##_value_t ) \
+ SELF##_value_t; \
+\
+ typedef struct { \
+ SELF##_value_t *ref; \
+ bool inserted; \
+ } SELF##_result_t; \
+\
+ typedef struct { \
+ SELF##_value_t *ref; \
+ uint8_t* _hx; \
+ } SELF##_iter_t; \
+\
+ typedef struct { \
+ SELF##_value_t* table; \
+ uint8_t* _hashx; \
+ SELF##_size_t size, bucket_count; \
+ float max_load_factor; \
+ } SELF
+
+#define _c_aatree_types(SELF, KEY, VAL, MAP_ONLY, SET_ONLY) \
+ typedef KEY SELF##_key_t; \
+ typedef VAL SELF##_mapped_t; \
+ typedef MAP_SIZE_T SELF##_size_t; \
+ typedef struct SELF##_node_t SELF##_node_t; \
+\
+ typedef SET_ONLY( SELF##_key_t ) \
+ MAP_ONLY( struct SELF##_value_t ) \
+ SELF##_value_t; \
+\
+ typedef struct { \
+ SELF##_value_t *ref; \
+ bool inserted; \
+ } SELF##_result_t; \
+\
+ typedef struct { \
+ SELF##_value_t *ref; \
+ SELF##_node_t *_d; \
+ int _top; \
+ SELF##_size_t _tn, _st[36]; \
+ } SELF##_iter_t; \
+\
+ typedef struct { \
+ SELF##_node_t *nodes; \
+ } SELF
+
+#define _c_csptr_types(SELF, VAL) \
+ typedef VAL SELF##_value_t; \
+\
+ typedef struct { \
+ SELF##_value_t* get; \
+ long* use_count; \
+ } SELF
+
+#define _c_cstack_types(SELF, VAL) \
+ typedef VAL SELF##_value_t; \
+ typedef struct { SELF##_value_t *ref; } SELF##_iter_t; \
+ typedef struct SELF { \
+ SELF##_value_t* data; \
+ size_t size, capacity; \
+ } SELF
+
+#define _c_cpque_types(SELF, VAL) \
+ typedef VAL SELF##_value_t; \
+ typedef struct SELF { \
+ SELF##_value_t* data; \
+ size_t size, capacity; \
+ } SELF
+
+#define _c_cvec_types(SELF, VAL) \
+ typedef VAL SELF##_value_t; \
+ typedef struct { SELF##_value_t *ref; } SELF##_iter_t; \
+ typedef struct { SELF##_value_t *data; } SELF
+
+#endif // STC_FORWARD_H_INCLUDED
diff --git a/include/stc/template.h b/include/stc/template.h
new file mode 100644
index 00000000..b255d647
--- /dev/null
+++ b/include/stc/template.h
@@ -0,0 +1,182 @@
+/* MIT License
+ *
+ * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no
+ *
+ * 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 i_template
+#define i_template
+
+#ifndef STC_TEMPLATE_H_INCLUDED
+#define STC_TEMPLATE_H_INCLUDED
+ #define cx_memb(name) c_PASTE(Self, name)
+ #define Self c_PASTE(i_prefix, i_tag)
+ // typedef container types defined in forward.h. VC requires c_EXPAND.
+ #define cx_deftypes(macro, SELF, ...) c_EXPAND(macro(SELF, __VA_ARGS__))
+
+ #define cx_value_t cx_memb(_value_t)
+ #define cx_key_t cx_memb(_key_t)
+ #define cx_mapped_t cx_memb(_mapped_t)
+ #define cx_rawvalue_t cx_memb(_rawvalue_t)
+ #define cx_rawkey_t cx_memb(_rawkey_t)
+ #define cx_rawmapped_t cx_memb(_rawmapped_t)
+ #define cx_iter_t cx_memb(_iter_t)
+ #define cx_result_t cx_memb(_result_t)
+ #define cx_node_t cx_memb(_node_t)
+ #define cx_size_t cx_memb(_size_t)
+#endif
+
+#ifdef F_tag
+ #define i_tag F_tag
+ #define i_fwd
+#endif
+
+#ifndef i_prefix_csptr
+#define i_prefix_csptr csptr_
+#endif
+#ifdef i_key_csptr
+ #ifndef i_tag
+ #define i_tag i_key_csptr
+ #endif
+ #define i_key c_PASTE(i_prefix_csptr, i_key_csptr)
+ #define i_cmp c_PASTE3(i_prefix_csptr, i_key_csptr, _compare)
+ #define i_keydel c_PASTE3(i_prefix_csptr, i_key_csptr, _del)
+ #define i_keyfrom c_PASTE3(i_prefix_csptr, i_key_csptr, _clone)
+#endif
+#ifdef i_val_csptr
+ #if !defined i_tag && !defined i_key
+ #define i_tag i_val_csptr
+ #endif
+ #define i_val c_PASTE(i_prefix_csptr, i_val_csptr)
+ #ifndef i_key
+ #define i_cmp c_PASTE3(i_prefix_csptr, i_val_csptr, _compare)
+ #endif
+ #define i_valdel c_PASTE3(i_prefix_csptr, i_val_csptr, _del)
+ #define i_valfrom c_PASTE3(i_prefix_csptr, i_val_csptr, _clone)
+#endif
+
+#ifdef i_key_str
+ #define i_key cstr
+ #ifndef i_tag
+ #define i_tag str
+ #endif
+ #define i_cmp c_rawstr_compare
+ #define i_hash c_rawstr_hash
+ #define i_keydel cstr_del
+ #define i_keyfrom cstr_from
+ #define i_keyto cstr_str
+ #define i_keyraw const char*
+#endif
+#ifdef i_val_str
+ #define i_val cstr
+ #if !defined i_tag && !defined i_key
+ #define i_tag str
+ #endif
+ #ifndef i_key
+ #define i_cmp c_rawstr_compare
+ #endif
+ #define i_valdel cstr_del
+ #define i_valfrom cstr_from
+ #define i_valto cstr_str
+ #define i_valraw const char*
+#endif
+
+#if defined i_key && !defined i_val
+ #define i_val i_key
+#endif
+#if !defined i_tag && defined i_key
+ #define i_tag i_key
+#elif !defined i_tag
+ #define i_tag i_val
+#endif
+
+#if (defined i_valto ^ defined i_valraw) || (defined i_valraw && !defined i_valfrom)
+ #error if i_valraw defined, both i_valfrom and i_valto must be defined
+#endif
+#if (defined i_keyto ^ defined i_keyraw) || (defined i_keyraw && !defined i_keyfrom)
+ #error if i_keyraw defined, both i_keyfrom and i_keyto must be defined
+#endif
+
+#ifdef i_key
+ #if !defined i_keyfrom && defined i_keydel
+ #define i_keyfrom c_no_clone
+ #elif !defined i_keyfrom
+ #define i_keyfrom c_default_fromraw
+ #endif
+ #ifndef i_keyraw
+ #define i_keyraw i_key
+ #define i_keyto c_default_toraw
+ #endif
+ #if !defined i_equ && defined i_cmp
+ #define i_equ !i_cmp
+ #elif !defined i_equ
+ #define i_equ c_default_equals
+ #endif
+ #ifndef i_hash
+ #define i_hash c_default_hash
+ #endif
+#endif
+
+#if !defined i_valfrom && defined i_valdel
+ #define i_valfrom c_no_clone
+#elif !defined i_valfrom
+ #define i_valfrom c_default_fromraw
+#endif
+#ifndef i_valraw
+ #define i_valraw i_val
+ #define i_valto c_default_toraw
+#endif
+#ifndef i_keydel
+ #define i_keydel c_default_del
+#endif
+#ifndef i_valdel
+ #define i_valdel c_default_del
+#endif
+#ifndef i_cmp
+ #define i_cmp c_default_compare
+#endif
+
+#else // -------------------------------------------------------
+
+#undef i_prefix
+#undef i_tag
+#undef F_tag
+#undef i_imp
+#undef i_fwd
+#undef i_cmp
+#undef i_equ
+#undef i_hash
+#undef i_val
+#undef i_val_str
+#undef i_valdel
+#undef i_valfrom
+#undef i_valto
+#undef i_valraw
+#undef i_key
+#undef i_key_str
+#undef i_keydel
+#undef i_keyfrom
+#undef i_keyto
+#undef i_keyraw
+#undef i_key_csptr
+#undef i_val_csptr
+#undef i_prefix_csptr
+
+#undef i_template
+#endif
diff --git a/tests/test_new_arr.c b/tests/test_new_arr.c
new file mode 100644
index 00000000..54423349
--- /dev/null
+++ b/tests/test_new_arr.c
@@ -0,0 +1,45 @@
+#include <stdio.h>
+
+#define i_val int
+#include <stc/carr2.h>
+
+#define i_val int
+#include <stc/carr3.h>
+
+int main()
+{
+ int w = 7, h = 5, d = 3;
+
+ c_forvar (carr2_int image = carr2_int_init(w, h), carr2_int_del(&image))
+ {
+ int *dat = carr2_int_data(&image);
+ for (size_t i = 0; i < carr2_int_size(image); ++i)
+ dat[i] = i;
+
+ for (size_t x = 0; x < image.xdim; ++x)
+ for (size_t y = 0; y < image.ydim; ++y)
+ printf(" %d", image.data[x][y]);
+ puts("");
+
+ c_foreach (i, carr2_int, image)
+ printf(" %d", *i.ref);
+ }
+ puts("\n");
+
+ c_forvar (carr3_int image = carr3_int_init(w, h, d), carr3_int_del(&image))
+ {
+ int *dat = carr3_int_data(&image);
+ for (size_t i = 0; i < carr3_int_size(image); ++i)
+ dat[i] = i;
+
+ for (size_t x = 0; x < image.xdim; ++x)
+ for (size_t y = 0; y < image.ydim; ++y)
+ for (size_t z = 0; z < image.zdim; ++z)
+ printf(" %d", image.data[x][y][z]);
+ puts("");
+
+ c_foreach (i, carr3_int, image)
+ printf(" %d", *i.ref);
+ }
+ puts("");
+}
diff --git a/tests/test_new_deq.c b/tests/test_new_deq.c
new file mode 100644
index 00000000..d1a5c2a6
--- /dev/null
+++ b/tests/test_new_deq.c
@@ -0,0 +1,57 @@
+#include <stc/cstr.h>
+#include <stc/forward.h>
+
+forward_cdeq(i32, int);
+forward_cdeq(pnt, struct Point);
+
+struct MyStruct {
+ cdeq_i32 intvec;
+ cdeq_pnt pntvec;
+} typedef MyStruct;
+
+
+#define F_tag i32
+#define i_val int
+#include <stc/cdeq.h>
+
+struct Point { int x, y; } typedef Point;
+int point_compare(const Point* a, const Point* b) {
+ int c = c_default_compare(&a->x, &b->x);
+ return c ? c : c_default_compare(&a->y, &b->y);
+}
+#define F_tag pnt
+#define i_val Point
+#define i_cmp point_compare
+#include <stc/cdeq.h>
+
+#define i_val float
+#include <stc/cdeq.h>
+
+#define i_val_str
+#include <stc/cdeq.h>
+
+
+int main()
+{
+ cdeq_i32 vec = cdeq_i32_init();
+ cdeq_i32_push_back(&vec, 123);
+ cdeq_i32_del(&vec);
+
+ cdeq_float fvec = cdeq_float_init();
+ cdeq_float_push_back(&fvec, 123.3);
+ cdeq_float_del(&fvec);
+
+ cdeq_pnt pvec = cdeq_pnt_init();
+ cdeq_pnt_push_back(&pvec, (Point){42, 14});
+ cdeq_pnt_push_back(&pvec, (Point){32, 94});
+ cdeq_pnt_push_front(&pvec, (Point){62, 81});
+ cdeq_pnt_sort(&pvec);
+ c_foreach (i, cdeq_pnt, pvec)
+ printf(" (%d %d)", i.ref->x, i.ref->y);
+ puts("");
+ cdeq_pnt_del(&pvec);
+
+ cdeq_str svec = cdeq_str_init();
+ cdeq_str_emplace_back(&svec, "Hello, friend");
+ cdeq_str_del(&svec);
+} \ No newline at end of file
diff --git a/tests/test_new_list.c b/tests/test_new_list.c
new file mode 100644
index 00000000..f0983b76
--- /dev/null
+++ b/tests/test_new_list.c
@@ -0,0 +1,57 @@
+#include "cstr.h"
+#include "forward.h"
+
+forward_clist(i32, int);
+forward_clist(pnt, struct Point);
+
+struct MyStruct {
+ clist_i32 intlst;
+ clist_pnt pntlst;
+} typedef MyStruct;
+
+
+#define F_tag i32
+#define i_val int
+#include "clist.h"
+
+struct Point { int x, y; } typedef Point;
+int point_compare(const Point* a, const Point* b) {
+ int c = c_default_compare(&a->x, &b->x);
+ return c ? c : c_default_compare(&a->y, &b->y);
+}
+#define F_tag pnt
+#define i_val Point
+#define i_cmp point_compare
+#include "clist.h"
+
+#define i_val float
+#include "clist.h"
+
+#define i_val_str
+#include "clist.h"
+
+
+int main()
+{
+ clist_i32 lst = clist_i32_init();
+ clist_i32_push_back(&lst, 123);
+ clist_i32_del(&lst);
+
+ clist_float flst = clist_float_init();
+ clist_float_push_back(&flst, 123.3);
+ clist_float_del(&flst);
+
+ clist_pnt plst = clist_pnt_init();
+ clist_pnt_push_back(&plst, (Point){42, 14});
+ clist_pnt_push_back(&plst, (Point){32, 94});
+ clist_pnt_push_back(&plst, (Point){62, 81});
+ clist_pnt_sort(&plst);
+ c_foreach (i, clist_pnt, plst)
+ printf(" (%d %d)", i.ref->x, i.ref->y);
+ puts("");
+ clist_pnt_del(&plst);
+
+ clist_str slst = clist_str_init();
+ clist_str_emplace_back(&slst, "Hello, friend");
+ clist_str_del(&slst);
+} \ No newline at end of file
diff --git a/tests/test_new_map.c b/tests/test_new_map.c
new file mode 100644
index 00000000..2c4ee3bb
--- /dev/null
+++ b/tests/test_new_map.c
@@ -0,0 +1,60 @@
+#include <stc/cstr.h>
+#include <stc/forward.h>
+
+forward_cmap(pnt, struct Point, int);
+
+struct MyStruct {
+ cmap_pnt pntmap;
+ cstr name;
+} typedef MyStruct;
+
+// int => int map
+#define i_key int
+#define i_val int
+#include <stc/cmap.h>
+
+// Point => int map
+struct Point { int x, y; } typedef Point;
+int point_compare(const Point* a, const Point* b) {
+ int c = c_default_compare(&a->x, &b->x);
+ return c ? c : c_default_compare(&a->y, &b->y);
+}
+#define F_tag pnt // F=forward declared
+#define i_key Point
+#define i_val int
+#define i_cmp point_compare
+#include <stc/cmap.h>
+
+// int => int map
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
+
+// string set
+#define i_key_str
+#include <stc/cset.h>
+
+
+int main()
+{
+ cmap_int map = cmap_int_init();
+ cmap_int_insert(&map, 123, 321);
+ cmap_int_del(&map);
+
+ cmap_pnt pmap = cmap_pnt_init();
+ cmap_pnt_insert(&pmap, (Point){42, 14}, 1);
+ cmap_pnt_insert(&pmap, (Point){32, 94}, 2);
+ cmap_pnt_insert(&pmap, (Point){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_pnt_del(&pmap);
+
+ cmap_str smap = cmap_str_init();
+ cmap_str_emplace(&smap, "Hello, friend", "this is the mapped value");
+ cmap_str_del(&smap);
+
+ cset_str sset = cset_str_init();
+ cset_str_emplace(&sset, "Hello, friend");
+ cset_str_del(&sset);
+} \ No newline at end of file
diff --git a/tests/test_new_pque.c b/tests/test_new_pque.c
new file mode 100644
index 00000000..b9750c44
--- /dev/null
+++ b/tests/test_new_pque.c
@@ -0,0 +1,63 @@
+#include <stc/forward.h>
+
+forward_cpque(pnt, struct Point);
+
+struct MyStruct {
+ cpque_pnt priority_queue;
+ int id;
+};
+
+#define i_val int
+#include "cstack.h"
+
+#define i_val int
+#include "cpque.h"
+
+struct Point { int x, y; } typedef Point;
+
+int Point_cmp(const Point* a, const Point* b) {
+ int c = c_default_compare(&a->x, &b->x);
+ return c ? c : c_default_compare(&a->y, &b->y);
+}
+#define F_tag pnt // F: was forward declared.
+#define i_val Point
+#define i_cmp Point_cmp
+#include "cpque.h"
+
+#include <stdio.h>
+
+int main()
+{
+ cstack_int istk = cstack_int_init();
+ cstack_int_push(&istk, 123);
+ cstack_int_push(&istk, 321);
+ // print
+ c_foreach (i, cstack_int, istk)
+ printf(" %d", *i.ref);
+ cstack_int_del(&istk);
+ puts("");
+
+ cpque_pnt pque = cpque_pnt_init();
+ cpque_pnt_push(&pque, (Point){23, 80});
+ cpque_pnt_push(&pque, (Point){12, 32});
+ cpque_pnt_push(&pque, (Point){54, 74});
+ cpque_pnt_push(&pque, (Point){12, 62});
+ // print
+ while (!cpque_pnt_empty(pque)) {
+ cpque_pnt_value_t *v = cpque_pnt_top(&pque);
+ printf(" (%d,%d)", v->x, v->y);
+ cpque_pnt_pop(&pque);
+ }
+ // free
+ cpque_pnt_del(&pque);
+ puts("");
+
+ cpque_int ique = cpque_int_init();
+ cpque_int_push(&ique, 123);
+ cpque_int_push(&ique, 321);
+ // print
+ for (int i=0; i<cpque_int_size(ique); ++i)
+ printf(" %d", ique.data[i]);
+ cpque_int_del(&ique);
+ puts("");
+}
diff --git a/tests/test_new_queue.c b/tests/test_new_queue.c
new file mode 100644
index 00000000..a76f4fde
--- /dev/null
+++ b/tests/test_new_queue.c
@@ -0,0 +1,43 @@
+#include <stc/crandom.h>
+#include <stc/forward.h>
+#include <stdio.h>
+
+forward_cqueue(pnt, struct Point);
+
+struct Point { int x, y; } typedef Point;
+int point_compare(const Point* a, const Point* b) {
+ int c = c_default_compare(&a->x, &b->x);
+ return c ? c : c_default_compare(&a->y, &b->y);
+}
+#define F_tag pnt
+#define i_val Point
+#define i_cmp point_compare
+#include <stc/cqueue.h>
+
+#define i_val int
+#include <stc/cqueue.h>
+#include <time.h>
+
+int main() {
+ int n = 60000000;
+ stc64_t rng = stc64_init(time(NULL));
+ stc64_uniform_t dist = stc64_uniform_init(0, n);
+
+ c_forauto (cqueue_int, Q)
+ {
+ // Push eight million random numbers onto the queue.
+ for (int i=0; i<n; ++i)
+ cqueue_int_push(&Q, stc64_uniform(&rng, &dist));
+
+ // Push or pop on the queue ten million times
+ printf("befor: size %zu, capacity %zu\n", cqueue_int_size(Q), cqueue_int_capacity(Q));
+ for (int i=n; i>0; --i) {
+ int r = stc64_uniform(&rng, &dist);
+ if (r & 1)
+ cqueue_int_push(&Q, r);
+ else
+ cqueue_int_pop(&Q);
+ }
+ printf("after: size %zu, capacity %zu\n", cqueue_int_size(Q), cqueue_int_capacity(Q));
+ }
+} \ No newline at end of file
diff --git a/tests/test_new_smap.c b/tests/test_new_smap.c
new file mode 100644
index 00000000..033749ce
--- /dev/null
+++ b/tests/test_new_smap.c
@@ -0,0 +1,67 @@
+#include <stc/cstr.h>
+#include <stc/forward.h>
+
+forward_csmap(pnt, struct Point, int);
+
+struct MyStruct {
+ csmap_pnt pntmap;
+ cstr name;
+} typedef MyStruct;
+
+// int => int map
+#define i_key int
+#define i_val int
+#include <stc/csmap.h>
+
+// Point => int map
+struct Point { int x, y; } typedef Point;
+int point_compare(const Point* a, const Point* b) {
+ int c = c_default_compare(&a->x, &b->x);
+ return c ? c : c_default_compare(&a->y, &b->y);
+}
+
+#define i_fwd
+#define i_tag pnt
+#define i_key Point
+#define i_val int
+#define i_cmp point_compare
+#include <stc/csmap.h>
+
+// int => int map
+#define i_key_str
+#define i_val_str
+#include <stc/csmap.h>
+
+// string set
+#define i_key_str
+#include <stc/csset.h>
+
+
+int main()
+{
+ c_forauto (csmap_int, map)
+ csmap_int_insert(&map, 123, 321);
+
+ c_forauto (csmap_pnt, pmap) {
+ csmap_pnt_insert(&pmap, (Point){42, 14}, 1);
+ csmap_pnt_insert(&pmap, (Point){32, 94}, 2);
+ csmap_pnt_insert(&pmap, (Point){62, 81}, 3);
+ c_foreach (i, csmap_pnt, pmap)
+ printf(" (%d,%d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second);
+ puts("");
+ }
+
+ c_forauto (csmap_str, smap) {
+ csmap_str_emplace(&smap, "Hello, friend", "this is the mapped value");
+ csmap_str_emplace(&smap, "The brown fox", "jumped");
+ csmap_str_emplace(&smap, "This is the time", "for all good things");
+ c_foreach (i, csmap_str, smap)
+ printf(" (%s: %s)\n", i.ref->first.str, i.ref->second.str);
+ }
+
+ c_forauto (csset_str, sset) {
+ csset_str_emplace(&sset, "Hello, friend");
+ csset_str_emplace(&sset, "Goodbye, foe");
+ printf("Found? %s\n", csset_str_contains(&sset, "Hello, friend") ? "true" : "false");
+ }
+} \ No newline at end of file
diff --git a/tests/test_new_sptr.c b/tests/test_new_sptr.c
new file mode 100644
index 00000000..2ef31790
--- /dev/null
+++ b/tests/test_new_sptr.c
@@ -0,0 +1,45 @@
+#include <stc/cstr.h>
+
+#include <stc/forward.h>
+forward_csptr(person, struct Person);
+
+struct Person { cstr name, last; } typedef Person;
+
+Person Person_init(const char* name, const char* last) {
+ return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+}
+void Person_del(Person* p) {
+ printf("del: %s %s\n", p->name.str, p->last.str);
+ c_del(cstr, &p->name, &p->last);
+}
+
+#define F_tag person
+#define i_val Person
+#define i_valdel Person_del
+#define i_cmp c_no_compare
+#include <stc/csptr.h>
+
+#define i_val int
+#include <stc/csptr.h>
+
+#define i_tag iptr
+#define i_key csptr_int
+#define i_cmp csptr_int_compare
+#include <stc/csset.h>
+
+int main(void) {
+ c_forvar (csptr_person p = csptr_person_make(Person_init("John", "Smiths")), csptr_person_del(&p))
+ c_forvar (csptr_person q = csptr_person_clone(p), csptr_person_del(&q)) // share the pointer
+ {
+ printf("%s %s. uses: %zu\n", q.get->name.str, q.get->last.str, *q.use_count);
+
+ c_forauto (csset_iptr, map) {
+ csset_iptr_insert(&map, csptr_int_make(2021));
+ csset_iptr_insert(&map, csptr_int_make(2033));
+
+ c_foreach (i, csset_iptr, map)
+ printf(" %d", *i.ref->get);
+ puts("");
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/test_new_vec.c b/tests/test_new_vec.c
new file mode 100644
index 00000000..ae1fd155
--- /dev/null
+++ b/tests/test_new_vec.c
@@ -0,0 +1,57 @@
+#include <stc/cstr.h>
+#include <stc/forward.h>
+
+forward_cvec(i32, int);
+forward_cvec(pnt, struct Point);
+
+struct MyStruct {
+ cvec_i32 intvec;
+ cvec_pnt pntvec;
+} typedef MyStruct;
+
+
+#define F_tag i32
+#define i_val int
+#include <stc/cvec.h>
+
+struct Point { int x, y; } typedef Point;
+int point_compare(const Point* a, const Point* b) {
+ int c = c_default_compare(&a->x, &b->x);
+ return c ? c : c_default_compare(&a->y, &b->y);
+}
+#define F_tag pnt
+#define i_val Point
+#define i_cmp point_compare
+#include <stc/cvec.h>
+
+#define i_val float
+#include <stc/cvec.h>
+
+#define i_val_str
+#include <stc/cvec.h>
+
+
+int main()
+{
+ cvec_i32 vec = cvec_i32_init();
+ cvec_i32_push_back(&vec, 123);
+ cvec_i32_del(&vec);
+
+ cvec_float fvec = cvec_float_init();
+ cvec_float_push_back(&fvec, 123.3);
+ cvec_float_del(&fvec);
+
+ cvec_pnt pvec = cvec_pnt_init();
+ cvec_pnt_push_back(&pvec, (Point){42, 14});
+ cvec_pnt_push_back(&pvec, (Point){32, 94});
+ cvec_pnt_push_back(&pvec, (Point){62, 81});
+ cvec_pnt_sort(&pvec);
+ c_foreach (i, cvec_pnt, pvec)
+ printf(" (%d %d)", i.ref->x, i.ref->y);
+ puts("");
+ cvec_pnt_del(&pvec);
+
+ cvec_str svec = cvec_str_init();
+ cvec_str_emplace_back(&svec, "Hello, friend");
+ cvec_str_del(&svec);
+} \ No newline at end of file