summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--benchmarks/misc/prng_bench.cpp412
-rw-r--r--benchmarks/misc/rust_cmap.c120
-rw-r--r--benchmarks/picobench/picobench_cmap.cpp604
-rw-r--r--benchmarks/picobench/picobench_csmap.cpp644
-rw-r--r--benchmarks/plotbench/cdeq_benchmark.cpp260
-rw-r--r--benchmarks/plotbench/clist_benchmark.cpp252
-rw-r--r--benchmarks/plotbench/cmap_benchmark.cpp266
-rw-r--r--benchmarks/plotbench/cpque_benchmark.cpp142
-rw-r--r--benchmarks/plotbench/csmap_benchmark.cpp270
-rw-r--r--benchmarks/plotbench/cvec_benchmark.cpp252
-rw-r--r--docs/cset_api.md246
-rw-r--r--docs/csset_api.md246
-rw-r--r--examples/README.md8
-rw-r--r--examples/arc_containers.c154
-rw-r--r--examples/arc_demo.c112
-rw-r--r--examples/arcvec_erase.c106
-rw-r--r--examples/astar.c334
-rw-r--r--examples/birthday.c132
-rw-r--r--examples/bits.c126
-rw-r--r--examples/bits2.c86
-rw-r--r--examples/books.c122
-rw-r--r--examples/box.c150
-rw-r--r--examples/box2.c176
-rw-r--r--examples/city.c166
-rw-r--r--examples/complex.c126
-rw-r--r--examples/csmap_insert.c224
-rw-r--r--examples/csset_erase.c84
-rw-r--r--examples/cstr_match.c46
-rw-r--r--examples/demos.c458
-rw-r--r--examples/gauss1.c114
-rw-r--r--examples/gauss2.c86
-rw-r--r--examples/hashmap.c98
-rw-r--r--examples/inits.c228
-rw-r--r--examples/list.c122
-rw-r--r--examples/list_erase.c58
-rw-r--r--examples/lower_bound.c128
-rw-r--r--examples/mapmap.c146
-rw-r--r--examples/mmap.c152
-rw-r--r--examples/multimap.c200
-rw-r--r--examples/music_arc.c118
-rw-r--r--examples/new_deq.c124
-rw-r--r--examples/new_map.c146
-rw-r--r--examples/new_pque.c130
-rw-r--r--examples/new_queue.c90
-rw-r--r--examples/new_smap.c152
-rw-r--r--examples/new_sptr.c112
-rw-r--r--examples/new_vec.c114
-rw-r--r--examples/person_arc.c144
-rw-r--r--examples/phonebook.c162
-rw-r--r--examples/prime.c84
-rw-r--r--examples/priority.c70
-rw-r--r--examples/queue.c64
-rw-r--r--examples/random.c86
-rw-r--r--examples/rawptr_elements.c136
-rw-r--r--examples/read.c52
-rw-r--r--examples/replace.c62
-rw-r--r--examples/shape.c322
-rw-r--r--examples/shape.cpp244
-rw-r--r--examples/sidebyside.cpp108
-rw-r--r--examples/splitstr.c78
-rw-r--r--examples/sso_map.c36
-rw-r--r--examples/stack.c58
-rw-r--r--examples/sview_split.c42
-rw-r--r--examples/unordered_map.c128
-rw-r--r--examples/unordered_set.c86
-rw-r--r--include/stc/alt/csmap.h1024
-rw-r--r--include/stc/alt/cstr.h778
-rw-r--r--include/stc/carc.h398
-rw-r--r--include/stc/cbits.h656
-rw-r--r--include/stc/cbox.h364
-rw-r--r--include/stc/ccommon.h538
-rw-r--r--include/stc/cdeq.h874
-rw-r--r--include/stc/clist.h848
-rw-r--r--include/stc/cmap.h846
-rw-r--r--include/stc/cpque.h314
-rw-r--r--include/stc/cqueue.h130
-rw-r--r--include/stc/crandom.h388
-rw-r--r--include/stc/cregex.h180
-rw-r--r--include/stc/cset.h92
-rw-r--r--include/stc/csmap.h1188
-rw-r--r--include/stc/csset.h98
-rw-r--r--include/stc/cstack.h300
-rw-r--r--include/stc/cstr.h1110
-rw-r--r--include/stc/csview.h438
-rw-r--r--include/stc/cvec.h872
-rw-r--r--include/stc/forward.h414
-rw-r--r--include/stc/template.h592
-rw-r--r--include/stc/utf8.h190
-rw-r--r--src/cregex.c2372
89 files changed, 12804 insertions, 12804 deletions
diff --git a/benchmarks/misc/prng_bench.cpp b/benchmarks/misc/prng_bench.cpp
index 9d840316..2bb25429 100644
--- a/benchmarks/misc/prng_bench.cpp
+++ b/benchmarks/misc/prng_bench.cpp
@@ -1,206 +1,206 @@
-#include <cstdint>
-#include <iostream>
-#include <ctime>
-#include <random>
-#include <stc/crandom.h>
-
-static inline uint64_t rotl64(const uint64_t x, const int k)
- { return (x << k) | (x >> (64 - k)); }
-
-static uint64_t splitmix64_x = 87213627321ull; /* The state can be seeded with any value. */
-
-uint64_t splitmix64(void) {
- uint64_t z = (splitmix64_x += 0x9e3779b97f4a7c15);
- z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
- z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
- return z ^ (z >> 31);
-}
-
-static void init_state(uint64_t *rng, uint64_t seed) {
- splitmix64_x = seed;
- for (int i=0; i<4; ++i) rng[i] = splitmix64();
-}
-
-/* romu_trio */
-
-uint64_t romu_trio(uint64_t s[3]) {
- uint64_t xp = s[0], yp = s[1], zp = s[2];
- s[0] = 15241094284759029579u * zp;
- s[1] = yp - xp; s[1] = rotl64(s[1], 12);
- s[2] = zp - yp; s[2] = rotl64(s[2], 44);
- return xp;
-}
-
-/* sfc64 */
-
-static inline uint64_t sfc64(uint64_t s[4]) {
- uint64_t result = s[0] + s[1] + s[3]++;
- s[0] = s[1] ^ (s[1] >> 11);
- s[1] = s[2] + (s[2] << 3);
- s[2] = rotl64(s[2], 24) + result;
- return result;
-}
-
-uint32_t sfc32(uint32_t s[4]) {
- uint32_t t = s[0] + s[1] + s[3]++;
- s[0] = s[1] ^ (s[1] >> 9);
- s[1] = s[2] + (s[2] << 3);
- s[2] = (s[2] << 21) | (s[2] >> 11) + t;
- return t;
-}
-
-uint32_t stc32(uint32_t s[5]) {
- uint32_t t = (s[0] ^ (s[3] += s[4])) + s[1];
- s[0] = s[1] ^ (s[1] >> 9);
- s[1] = s[2] + (s[2] << 3);
- s[2] = (s[2] << 21) | (s[2] >> 11) + t;
- return t;
-}
-
-/* xoshiro128+ */
-
-uint64_t xoroshiro128plus(uint64_t s[2]) {
- const uint64_t s0 = s[0];
- uint64_t s1 = s[1];
- const uint64_t result = s0 + s1;
-
- s1 ^= s0;
- s[0] = rotl64(s0, 24) ^ s1 ^ (s1 << 16); // a, b
- s[1] = rotl64(s1, 37); // c
-
- return result;
-}
-
-
-/* xoshiro256** */
-
-static inline uint64_t xoshiro256starstar(uint64_t s[4]) {
- const uint64_t result = rotl64(s[1] * 5, 7) * 9;
- const uint64_t t = s[1] << 17;
- s[2] ^= s[0];
- s[3] ^= s[1];
- s[1] ^= s[2];
- s[0] ^= s[3];
- s[2] ^= t;
- s[3] = rotl64(s[3], 45);
- return result;
-}
-
-// wyrand - 2020-12-07
-static inline void _wymum(uint64_t *A, uint64_t *B){
-#if defined(__SIZEOF_INT128__)
- __uint128_t r = *A; r *= *B;
- *A = (uint64_t) r; *B = (uint64_t ) (r >> 64);
-#elif defined(_MSC_VER) && defined(_M_X64)
- *A = _umul128(*A, *B, B);
-#else
- uint64_t ha=*A>>32, hb=*B>>32, la=(uint32_t)*A, lb=(uint32_t)*B, hi, lo;
- uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t<rl;
- lo=t+(rm1<<32); c+=lo<t; hi=rh+(rm0>>32)+(rm1>>32)+c;
- *A=lo; *B=hi;
-#endif
-}
-static inline uint64_t _wymix(uint64_t A, uint64_t B){
- _wymum(&A,&B); return A^B;
-}
-static inline uint64_t wyrand64(uint64_t *seed){
- static const uint64_t _wyp[] = {0xa0761d6478bd642full, 0xe7037ed1a0b428dbull};
- *seed+=_wyp[0]; return _wymix(*seed,*seed^_wyp[1]);
-}
-
-
-using namespace std;
-
-int main(void)
-{
- enum {N = 2000000000};
- uint16_t* recipient = new uint16_t[N];
- static stc64_t rng;
- init_state(rng.state, 12345123);
- std::mt19937 mt(12345123);
-
- cout << "WARMUP" << endl;
- for (size_t i = 0; i < N; i++)
- recipient[i] = wyrand64(rng.state);
-
- clock_t beg, end;
- for (size_t ti = 0; ti < 2; ti++) {
- init_state(rng.state, 12345123);
- cout << endl << "ROUND " << ti+1 << " ---------" << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = romu_trio(rng.state);
- end = clock();
- cout << "romu_trio:\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = wyrand64(rng.state);
- end = clock();
- cout << "wyrand64:\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = sfc32((uint32_t *)rng.state);
- end = clock();
- cout << "sfc32:\t\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = stc32((uint32_t *)rng.state);
- end = clock();
- cout << "stc32:\t\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = sfc64(rng.state);
- end = clock();
- cout << "sfc64:\t\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = stc64_rand(&rng);
- end = clock();
- cout << "stc64:\t\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = xoroshiro128plus(rng.state);
- end = clock();
- cout << "xoroshiro128+:\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = xoshiro256starstar(rng.state);
- end = clock();
- cout << "xoshiro256**:\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = mt();
- end = clock();
- cout << "std::mt19937:\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
- }
- delete[] recipient;
- return 0;
-}
+#include <cstdint>
+#include <iostream>
+#include <ctime>
+#include <random>
+#include <stc/crandom.h>
+
+static inline uint64_t rotl64(const uint64_t x, const int k)
+ { return (x << k) | (x >> (64 - k)); }
+
+static uint64_t splitmix64_x = 87213627321ull; /* The state can be seeded with any value. */
+
+uint64_t splitmix64(void) {
+ uint64_t z = (splitmix64_x += 0x9e3779b97f4a7c15);
+ z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
+ z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
+ return z ^ (z >> 31);
+}
+
+static void init_state(uint64_t *rng, uint64_t seed) {
+ splitmix64_x = seed;
+ for (int i=0; i<4; ++i) rng[i] = splitmix64();
+}
+
+/* romu_trio */
+
+uint64_t romu_trio(uint64_t s[3]) {
+ uint64_t xp = s[0], yp = s[1], zp = s[2];
+ s[0] = 15241094284759029579u * zp;
+ s[1] = yp - xp; s[1] = rotl64(s[1], 12);
+ s[2] = zp - yp; s[2] = rotl64(s[2], 44);
+ return xp;
+}
+
+/* sfc64 */
+
+static inline uint64_t sfc64(uint64_t s[4]) {
+ uint64_t result = s[0] + s[1] + s[3]++;
+ s[0] = s[1] ^ (s[1] >> 11);
+ s[1] = s[2] + (s[2] << 3);
+ s[2] = rotl64(s[2], 24) + result;
+ return result;
+}
+
+uint32_t sfc32(uint32_t s[4]) {
+ uint32_t t = s[0] + s[1] + s[3]++;
+ s[0] = s[1] ^ (s[1] >> 9);
+ s[1] = s[2] + (s[2] << 3);
+ s[2] = (s[2] << 21) | (s[2] >> 11) + t;
+ return t;
+}
+
+uint32_t stc32(uint32_t s[5]) {
+ uint32_t t = (s[0] ^ (s[3] += s[4])) + s[1];
+ s[0] = s[1] ^ (s[1] >> 9);
+ s[1] = s[2] + (s[2] << 3);
+ s[2] = (s[2] << 21) | (s[2] >> 11) + t;
+ return t;
+}
+
+/* xoshiro128+ */
+
+uint64_t xoroshiro128plus(uint64_t s[2]) {
+ const uint64_t s0 = s[0];
+ uint64_t s1 = s[1];
+ const uint64_t result = s0 + s1;
+
+ s1 ^= s0;
+ s[0] = rotl64(s0, 24) ^ s1 ^ (s1 << 16); // a, b
+ s[1] = rotl64(s1, 37); // c
+
+ return result;
+}
+
+
+/* xoshiro256** */
+
+static inline uint64_t xoshiro256starstar(uint64_t s[4]) {
+ const uint64_t result = rotl64(s[1] * 5, 7) * 9;
+ const uint64_t t = s[1] << 17;
+ s[2] ^= s[0];
+ s[3] ^= s[1];
+ s[1] ^= s[2];
+ s[0] ^= s[3];
+ s[2] ^= t;
+ s[3] = rotl64(s[3], 45);
+ return result;
+}
+
+// wyrand - 2020-12-07
+static inline void _wymum(uint64_t *A, uint64_t *B){
+#if defined(__SIZEOF_INT128__)
+ __uint128_t r = *A; r *= *B;
+ *A = (uint64_t) r; *B = (uint64_t ) (r >> 64);
+#elif defined(_MSC_VER) && defined(_M_X64)
+ *A = _umul128(*A, *B, B);
+#else
+ uint64_t ha=*A>>32, hb=*B>>32, la=(uint32_t)*A, lb=(uint32_t)*B, hi, lo;
+ uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t<rl;
+ lo=t+(rm1<<32); c+=lo<t; hi=rh+(rm0>>32)+(rm1>>32)+c;
+ *A=lo; *B=hi;
+#endif
+}
+static inline uint64_t _wymix(uint64_t A, uint64_t B){
+ _wymum(&A,&B); return A^B;
+}
+static inline uint64_t wyrand64(uint64_t *seed){
+ static const uint64_t _wyp[] = {0xa0761d6478bd642full, 0xe7037ed1a0b428dbull};
+ *seed+=_wyp[0]; return _wymix(*seed,*seed^_wyp[1]);
+}
+
+
+using namespace std;
+
+int main(void)
+{
+ enum {N = 2000000000};
+ uint16_t* recipient = new uint16_t[N];
+ static stc64_t rng;
+ init_state(rng.state, 12345123);
+ std::mt19937 mt(12345123);
+
+ cout << "WARMUP" << endl;
+ for (size_t i = 0; i < N; i++)
+ recipient[i] = wyrand64(rng.state);
+
+ clock_t beg, end;
+ for (size_t ti = 0; ti < 2; ti++) {
+ init_state(rng.state, 12345123);
+ cout << endl << "ROUND " << ti+1 << " ---------" << endl;
+
+ beg = clock();
+ for (size_t i = 0; i < N; i++)
+ recipient[i] = romu_trio(rng.state);
+ end = clock();
+ cout << "romu_trio:\t"
+ << (float(end - beg) / CLOCKS_PER_SEC)
+ << "s: " << recipient[312] << endl;
+
+ beg = clock();
+ for (size_t i = 0; i < N; i++)
+ recipient[i] = wyrand64(rng.state);
+ end = clock();
+ cout << "wyrand64:\t"
+ << (float(end - beg) / CLOCKS_PER_SEC)
+ << "s: " << recipient[312] << endl;
+
+ beg = clock();
+ for (size_t i = 0; i < N; i++)
+ recipient[i] = sfc32((uint32_t *)rng.state);
+ end = clock();
+ cout << "sfc32:\t\t"
+ << (float(end - beg) / CLOCKS_PER_SEC)
+ << "s: " << recipient[312] << endl;
+
+ beg = clock();
+ for (size_t i = 0; i < N; i++)
+ recipient[i] = stc32((uint32_t *)rng.state);
+ end = clock();
+ cout << "stc32:\t\t"
+ << (float(end - beg) / CLOCKS_PER_SEC)
+ << "s: " << recipient[312] << endl;
+
+ beg = clock();
+ for (size_t i = 0; i < N; i++)
+ recipient[i] = sfc64(rng.state);
+ end = clock();
+ cout << "sfc64:\t\t"
+ << (float(end - beg) / CLOCKS_PER_SEC)
+ << "s: " << recipient[312] << endl;
+
+ beg = clock();
+ for (size_t i = 0; i < N; i++)
+ recipient[i] = stc64_rand(&rng);
+ end = clock();
+ cout << "stc64:\t\t"
+ << (float(end - beg) / CLOCKS_PER_SEC)
+ << "s: " << recipient[312] << endl;
+
+
+ beg = clock();
+ for (size_t i = 0; i < N; i++)
+ recipient[i] = xoroshiro128plus(rng.state);
+ end = clock();
+ cout << "xoroshiro128+:\t"
+ << (float(end - beg) / CLOCKS_PER_SEC)
+ << "s: " << recipient[312] << endl;
+
+ beg = clock();
+ for (size_t i = 0; i < N; i++)
+ recipient[i] = xoshiro256starstar(rng.state);
+ end = clock();
+ cout << "xoshiro256**:\t"
+ << (float(end - beg) / CLOCKS_PER_SEC)
+ << "s: " << recipient[312] << endl;
+
+ beg = clock();
+ for (size_t i = 0; i < N; i++)
+ recipient[i] = mt();
+ end = clock();
+ cout << "std::mt19937:\t"
+ << (float(end - beg) / CLOCKS_PER_SEC)
+ << "s: " << recipient[312] << endl;
+ }
+ delete[] recipient;
+ return 0;
+}
diff --git a/benchmarks/misc/rust_cmap.c b/benchmarks/misc/rust_cmap.c
index 5a052915..1e763bde 100644
--- a/benchmarks/misc/rust_cmap.c
+++ b/benchmarks/misc/rust_cmap.c
@@ -1,61 +1,61 @@
-#include <time.h>
-#include <stdio.h>
-#define i_key uint64_t
-#define i_val uint64_t
-#define i_tag u64
-#include <stc/cmap.h>
-
-uint64_t romu_rotl(uint64_t val, uint32_t r) {
- return (val << r) | (val >> (64 - r));
-}
-
-uint64_t romu_trio(uint64_t s[3]) {
- const uint64_t xp = s[0],
- yp = s[1],
- zp = s[2];
- s[0] = 15241094284759029579u * zp;
- s[1] = yp - xp;
- s[1] = romu_rotl(s[1], 12);
- s[2] = zp - yp;
- s[2] = romu_rotl(s[2], 44);
- return xp;
-}
-
-int main()
-{
- c_auto (cmap_u64, m) {
- const size_t n = 50000000,
- mask = (1 << 25) - 1,
- ms = CLOCKS_PER_SEC/1000;
- cmap_u64_max_load_factor(&m, 0.8);
- cmap_u64_reserve(&m, n);
- printf("STC cmap n = %" PRIuMAX ", mask = 0x%" PRIxMAX "\n", n, mask);
-
- uint64_t rng[3] = {1872361123, 123879177, 87739234}, sum;
- clock_t now = clock();
- c_forrange (n) {
- uint64_t key = romu_trio(rng) & mask;
- cmap_u64_insert(&m, key, 0).ref->second += 1;
- }
- printf("insert : %zums \tsize : %" PRIuMAX "\n", (clock() - now)/ms, cmap_u64_size(m));
-
- now = clock();
- sum = 0;
- c_forrange (key, mask + 1) { sum += cmap_u64_contains(&m, key); }
- printf("lookup : %zums \tsum : %" PRIuMAX "\n", (clock() - now)/ms, sum);
-
- now = clock();
- sum = 0;
- c_foreach (i, cmap_u64, m) { sum += i.ref->second; }
- printf("iterate : %zums \tsum : %" PRIuMAX "\n", (clock() - now)/ms, sum);
-
- uint64_t rng2[3] = {1872361123, 123879177, 87739234};
- now = clock();
- c_forrange (n) {
- uint64_t key = romu_trio(rng2) & mask;
- cmap_u64_erase(&m, key);
- }
- printf("remove : %zums \tsize : %" PRIuMAX "\n", (clock() - now)/ms, cmap_u64_size(m));
- printf("press a key:\n"); getchar();
- }
+#include <time.h>
+#include <stdio.h>
+#define i_key uint64_t
+#define i_val uint64_t
+#define i_tag u64
+#include <stc/cmap.h>
+
+uint64_t romu_rotl(uint64_t val, uint32_t r) {
+ return (val << r) | (val >> (64 - r));
+}
+
+uint64_t romu_trio(uint64_t s[3]) {
+ const uint64_t xp = s[0],
+ yp = s[1],
+ zp = s[2];
+ s[0] = 15241094284759029579u * zp;
+ s[1] = yp - xp;
+ s[1] = romu_rotl(s[1], 12);
+ s[2] = zp - yp;
+ s[2] = romu_rotl(s[2], 44);
+ return xp;
+}
+
+int main()
+{
+ c_auto (cmap_u64, m) {
+ const size_t n = 50000000,
+ mask = (1 << 25) - 1,
+ ms = CLOCKS_PER_SEC/1000;
+ cmap_u64_max_load_factor(&m, 0.8);
+ cmap_u64_reserve(&m, n);
+ printf("STC cmap n = %" PRIuMAX ", mask = 0x%" PRIxMAX "\n", n, mask);
+
+ uint64_t rng[3] = {1872361123, 123879177, 87739234}, sum;
+ clock_t now = clock();
+ c_forrange (n) {
+ uint64_t key = romu_trio(rng) & mask;
+ cmap_u64_insert(&m, key, 0).ref->second += 1;
+ }
+ printf("insert : %zums \tsize : %" PRIuMAX "\n", (clock() - now)/ms, cmap_u64_size(m));
+
+ now = clock();
+ sum = 0;
+ c_forrange (key, mask + 1) { sum += cmap_u64_contains(&m, key); }
+ printf("lookup : %zums \tsum : %" PRIuMAX "\n", (clock() - now)/ms, sum);
+
+ now = clock();
+ sum = 0;
+ c_foreach (i, cmap_u64, m) { sum += i.ref->second; }
+ printf("iterate : %zums \tsum : %" PRIuMAX "\n", (clock() - now)/ms, sum);
+
+ uint64_t rng2[3] = {1872361123, 123879177, 87739234};
+ now = clock();
+ c_forrange (n) {
+ uint64_t key = romu_trio(rng2) & mask;
+ cmap_u64_erase(&m, key);
+ }
+ printf("remove : %zums \tsize : %" PRIuMAX "\n", (clock() - now)/ms, cmap_u64_size(m));
+ printf("press a key:\n"); getchar();
+ }
} \ No newline at end of file
diff --git a/benchmarks/picobench/picobench_cmap.cpp b/benchmarks/picobench/picobench_cmap.cpp
index 30170061..4a330019 100644
--- a/benchmarks/picobench/picobench_cmap.cpp
+++ b/benchmarks/picobench/picobench_cmap.cpp
@@ -1,302 +1,302 @@
-#define i_static
-#include <stc/crandom.h>
-#define i_static
-#include <stc/cstr.h>
-#include <cmath>
-#include <string>
-#include <unordered_map>
-#include <stdexcept>
-#include "../external/robin_hood.h"
-#include "../external/skarupke/bytell_hash_map.hpp"
-#include "../external/tsl/hopscotch_map.h"
-#include "../external/parallel_hashmap/phmap.h"
-
-#define PICOBENCH_IMPLEMENT_WITH_MAIN
-#include "picobench.hpp"
-
-enum {N1 = 4000000, S1 = 1, MaxLoadFactor100 = 80};
-uint64_t seed = time(NULL);
-
-template <class K, class V> using umap = std::unordered_map<K, V>;
-template <class K, class V> using bmap = ska::bytell_hash_map<K, V>;
-template <class K, class V> using fmap = ska::flat_hash_map<K, V>;
-template <class K, class V> using hmap = tsl::hopscotch_map<K, V>;
-template <class K, class V> using pmap = phmap::flat_hash_map<K, V>;
-template <class K, class V> using rmap = robin_hood::unordered_flat_map<K, V,
- robin_hood::hash<K>, std::equal_to<K>, MaxLoadFactor100>;
-#define DEFMAP(map, ...) \
- using u##map = umap __VA_ARGS__; \
- using b##map = bmap __VA_ARGS__; \
- using f##map = fmap __VA_ARGS__; \
- using h##map = hmap __VA_ARGS__; \
- using p##map = pmap __VA_ARGS__; \
- using r##map = rmap __VA_ARGS__
-
-
-DEFMAP(map_i, <int32_t, int32_t>);
-DEFMAP(map_x, <uint64_t, uint64_t>);
-DEFMAP(map_s, <std::string, std::string>);
-
-#define i_key int32_t
-#define i_val int32_t
-#define i_tag i
-#include <stc/cmap.h>
-
-#define i_key uint64_t
-#define i_val uint64_t
-#define i_tag x
-#include <stc/cmap.h>
-
-#define i_key_str
-#define i_val_str
-#include <stc/cmap.h>
-
-PICOBENCH_SUITE("Map1");
-
-template <class MapInt>
-static void ins_and_erase_i(picobench::state& s)
-{
- size_t result = 0;
- MapInt map;
- map.max_load_factor((int)MaxLoadFactor100 / 100.0);
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (s.iterations())
- map[crandom()];
- map.clear();
- csrandom(seed);
- c_forrange (s.iterations())
- map[crandom()];
- csrandom(seed);
- c_forrange (s.iterations())
- map.erase(crandom());
- s.set_result(map.size());
-}
-
-static void ins_and_erase_cmap_i(picobench::state& s)
-{
- cmap_i map = cmap_i_init();
- cmap_i_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (s.iterations())
- cmap_i_insert(&map, crandom(), 0);
- cmap_i_clear(&map);
- csrandom(seed);
- c_forrange (s.iterations())
- cmap_i_insert(&map, crandom(), 0);
- csrandom(seed);
- c_forrange (s.iterations())
- cmap_i_erase(&map, crandom());
- s.set_result(cmap_i_size(map));
- cmap_i_drop(&map);
-}
-
-static void ins_and_erase_cmap_x(picobench::state& s)
-{
- cmap_x map = cmap_x_init();
- cmap_x_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (s.iterations())
- cmap_x_insert(&map, crandom(), 0);
- cmap_x_clear(&map);
- csrandom(seed);
- c_forrange (s.iterations())
- cmap_x_insert(&map, crandom(), 0);
- csrandom(seed);
- c_forrange (s.iterations())
- cmap_x_erase(&map, crandom());
- s.set_result(cmap_x_size(map));
- cmap_x_drop(&map);
-}
-
-#define P samples(S1).iterations({N1/4})
-PICOBENCH(ins_and_erase_i<umap_x>).P;
-PICOBENCH(ins_and_erase_i<bmap_x>).P;
-PICOBENCH(ins_and_erase_i<fmap_x>).P;
-PICOBENCH(ins_and_erase_i<hmap_x>).P;
-PICOBENCH(ins_and_erase_i<pmap_x>).P;
-PICOBENCH(ins_and_erase_i<rmap_x>).P;
-PICOBENCH(ins_and_erase_cmap_x).P;
-#undef P
-
-PICOBENCH_SUITE("Map2");
-
-template <class MapInt>
-static void ins_and_access_i(picobench::state& s)
-{
- uint64_t mask = (1ull << s.arg()) - 1;
- size_t result = 0;
- MapInt map;
- map.max_load_factor((int)MaxLoadFactor100 / 100.0);
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (N1)
- result += ++map[crandom() & mask];
- s.set_result(result);
-}
-
-static void ins_and_access_cmap_i(picobench::state& s)
-{
- uint64_t mask = (1ull << s.arg()) - 1;
- size_t result = 0;
- cmap_i map = cmap_i_init();
- cmap_i_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (N1)
- result += ++cmap_i_insert(&map, crandom() & mask, 0).ref->second;
- s.set_result(result);
- cmap_i_drop(&map);
-}
-
-#define P samples(S1).iterations({N1, N1, N1, N1}).args({18, 23, 25, 31})
-PICOBENCH(ins_and_access_i<umap_i>).P;
-PICOBENCH(ins_and_access_i<bmap_i>).P;
-PICOBENCH(ins_and_access_i<fmap_i>).P;
-PICOBENCH(ins_and_access_i<hmap_i>).P;
-PICOBENCH(ins_and_access_i<pmap_i>).P;
-PICOBENCH(ins_and_access_i<rmap_i>).P;
-PICOBENCH(ins_and_access_cmap_i).P;
-#undef P
-
-PICOBENCH_SUITE("Map3");
-
-static void randomize(char* str, size_t len) {
- for (int k=0; k < len; ++k) {
- union {uint64_t i; char c[8];} r = {.i = crandom()};
- for (int i=0; i<8 && k<len; ++k, ++i)
- str[k] = (r.c[i] & 63) + 48;
- }
-}
-
-template <class MapStr>
-static void ins_and_access_s(picobench::state& s)
-{
- std::string str(s.arg(), 'x');
- size_t result = 0;
- MapStr map;
- map.max_load_factor((int)MaxLoadFactor100 / 100.0);
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (s.iterations()) {
- randomize(&str[0], str.size());
- map.emplace(str, str);
- randomize(&str[0], str.size());
- result += map.erase(str);
- }
- s.set_result(result + map.size());
-}
-
-static void ins_and_access_cmap_s(picobench::state& s)
-{
- cstr str = cstr_with_size(s.arg(), 'x');
- char* buf = cstr_data(&str);
- size_t result = 0;
- cmap_str map = cmap_str_init();
- cmap_str_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (s.iterations()) {
- randomize(buf, s.arg());
- //if (s.arg() > 30) { printf("%s\n", buf); exit(0); }
- cmap_str_emplace(&map, buf, buf);
-
- randomize(buf, s.arg());
- result += cmap_str_erase(&map, buf);
- }
- s.set_result(result + cmap_str_size(map));
- cstr_drop(&str);
- cmap_str_drop(&map);
-}
-
-#define P samples(S1).iterations({N1/5, N1/5, N1/5, N1/10, N1/40}).args({13, 7, 8, 100, 1000})
-PICOBENCH(ins_and_access_s<umap_s>).P;
-PICOBENCH(ins_and_access_s<bmap_s>).P;
-PICOBENCH(ins_and_access_s<fmap_s>).P;
-PICOBENCH(ins_and_access_s<hmap_s>).P;
-PICOBENCH(ins_and_access_s<pmap_s>).P;
-PICOBENCH(ins_and_access_s<rmap_s>).P;
-PICOBENCH(ins_and_access_cmap_s).P;
-#undef P
-
-PICOBENCH_SUITE("Map4");
-
-template <class MapX>
-static void iterate_x(picobench::state& s)
-{
- MapX map;
- map.max_load_factor((int)MaxLoadFactor100 / 100.0);
- uint64_t K = (1ull << s.arg()) - 1;
-
- picobench::scope scope(s);
- csrandom(seed);
- size_t result = 0;
-
- // measure insert then iterate whole map
- c_forrange (n, s.iterations()) {
- map[crandom()] = n;
- if (!(n & K)) for (auto const& keyVal : map)
- result += keyVal.second;
- }
-
- // reset rng back to inital state
- csrandom(seed);
-
- // measure erase then iterate whole map
- c_forrange (n, s.iterations()) {
- map.erase(crandom());
- if (!(n & K)) for (auto const& keyVal : map)
- result += keyVal.second;
- }
- s.set_result(result);
-}
-
-static void iterate_cmap_x(picobench::state& s)
-{
- cmap_x map = cmap_x_init();
- cmap_x_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
- uint64_t K = (1ull << s.arg()) - 1;
-
- picobench::scope scope(s);
- csrandom(seed);
- size_t result = 0;
-
- // measure insert then iterate whole map
- c_forrange (n, s.iterations()) {
- cmap_x_insert_or_assign(&map, crandom(), n);
- if (!(n & K)) c_foreach (i, cmap_x, map)
- result += i.ref->second;
- }
-
- // reset rng back to inital state
- csrandom(seed);
-
- // measure erase then iterate whole map
- c_forrange (n, s.iterations()) {
- cmap_x_erase(&map, crandom());
- if (!(n & K)) c_foreach (i, cmap_x, map)
- result += i.ref->second;
- }
- s.set_result(result);
- cmap_x_drop(&map);
-}
-
-
-#define P samples(S1).iterations({N1/20}).args({12})
-PICOBENCH(iterate_x<umap_x>).P;
-PICOBENCH(iterate_x<bmap_x>).P;
-PICOBENCH(iterate_x<fmap_x>).P;
-PICOBENCH(iterate_x<hmap_x>).P;
-PICOBENCH(iterate_x<pmap_x>).P;
-PICOBENCH(iterate_x<rmap_x>).P;
-PICOBENCH(iterate_cmap_x).P;
-#undef P
+#define i_static
+#include <stc/crandom.h>
+#define i_static
+#include <stc/cstr.h>
+#include <cmath>
+#include <string>
+#include <unordered_map>
+#include <stdexcept>
+#include "../external/robin_hood.h"
+#include "../external/skarupke/bytell_hash_map.hpp"
+#include "../external/tsl/hopscotch_map.h"
+#include "../external/parallel_hashmap/phmap.h"
+
+#define PICOBENCH_IMPLEMENT_WITH_MAIN
+#include "picobench.hpp"
+
+enum {N1 = 4000000, S1 = 1, MaxLoadFactor100 = 80};
+uint64_t seed = time(NULL);
+
+template <class K, class V> using umap = std::unordered_map<K, V>;
+template <class K, class V> using bmap = ska::bytell_hash_map<K, V>;
+template <class K, class V> using fmap = ska::flat_hash_map<K, V>;
+template <class K, class V> using hmap = tsl::hopscotch_map<K, V>;
+template <class K, class V> using pmap = phmap::flat_hash_map<K, V>;
+template <class K, class V> using rmap = robin_hood::unordered_flat_map<K, V,
+ robin_hood::hash<K>, std::equal_to<K>, MaxLoadFactor100>;
+#define DEFMAP(map, ...) \
+ using u##map = umap __VA_ARGS__; \
+ using b##map = bmap __VA_ARGS__; \
+ using f##map = fmap __VA_ARGS__; \
+ using h##map = hmap __VA_ARGS__; \
+ using p##map = pmap __VA_ARGS__; \
+ using r##map = rmap __VA_ARGS__
+
+
+DEFMAP(map_i, <int32_t, int32_t>);
+DEFMAP(map_x, <uint64_t, uint64_t>);
+DEFMAP(map_s, <std::string, std::string>);
+
+#define i_key int32_t
+#define i_val int32_t
+#define i_tag i
+#include <stc/cmap.h>
+
+#define i_key uint64_t
+#define i_val uint64_t
+#define i_tag x
+#include <stc/cmap.h>
+
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
+
+PICOBENCH_SUITE("Map1");
+
+template <class MapInt>
+static void ins_and_erase_i(picobench::state& s)
+{
+ size_t result = 0;
+ MapInt map;
+ map.max_load_factor((int)MaxLoadFactor100 / 100.0);
+ csrandom(seed);
+
+ picobench::scope scope(s);
+ c_forrange (s.iterations())
+ map[crandom()];
+ map.clear();
+ csrandom(seed);
+ c_forrange (s.iterations())
+ map[crandom()];
+ csrandom(seed);
+ c_forrange (s.iterations())
+ map.erase(crandom());
+ s.set_result(map.size());
+}
+
+static void ins_and_erase_cmap_i(picobench::state& s)
+{
+ cmap_i map = cmap_i_init();
+ cmap_i_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
+ csrandom(seed);
+
+ picobench::scope scope(s);
+ c_forrange (s.iterations())
+ cmap_i_insert(&map, crandom(), 0);
+ cmap_i_clear(&map);
+ csrandom(seed);
+ c_forrange (s.iterations())
+ cmap_i_insert(&map, crandom(), 0);
+ csrandom(seed);
+ c_forrange (s.iterations())
+ cmap_i_erase(&map, crandom());
+ s.set_result(cmap_i_size(map));
+ cmap_i_drop(&map);
+}
+
+static void ins_and_erase_cmap_x(picobench::state& s)
+{
+ cmap_x map = cmap_x_init();
+ cmap_x_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
+ csrandom(seed);
+
+ picobench::scope scope(s);
+ c_forrange (s.iterations())
+ cmap_x_insert(&map, crandom(), 0);
+ cmap_x_clear(&map);
+ csrandom(seed);
+ c_forrange (s.iterations())
+ cmap_x_insert(&map, crandom(), 0);
+ csrandom(seed);
+ c_forrange (s.iterations())
+ cmap_x_erase(&map, crandom());
+ s.set_result(cmap_x_size(map));
+ cmap_x_drop(&map);
+}
+
+#define P samples(S1).iterations({N1/4})
+PICOBENCH(ins_and_erase_i<umap_x>).P;
+PICOBENCH(ins_and_erase_i<bmap_x>).P;
+PICOBENCH(ins_and_erase_i<fmap_x>).P;
+PICOBENCH(ins_and_erase_i<hmap_x>).P;
+PICOBENCH(ins_and_erase_i<pmap_x>).P;
+PICOBENCH(ins_and_erase_i<rmap_x>).P;
+PICOBENCH(ins_and_erase_cmap_x).P;
+#undef P
+
+PICOBENCH_SUITE("Map2");
+
+template <class MapInt>
+static void ins_and_access_i(picobench::state& s)
+{
+ uint64_t mask = (1ull << s.arg()) - 1;
+ size_t result = 0;
+ MapInt map;
+ map.max_load_factor((int)MaxLoadFactor100 / 100.0);
+ csrandom(seed);
+
+ picobench::scope scope(s);
+ c_forrange (N1)
+ result += ++map[crandom() & mask];
+ s.set_result(result);
+}
+
+static void ins_and_access_cmap_i(picobench::state& s)
+{
+ uint64_t mask = (1ull << s.arg()) - 1;
+ size_t result = 0;
+ cmap_i map = cmap_i_init();
+ cmap_i_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
+ csrandom(seed);
+
+ picobench::scope scope(s);
+ c_forrange (N1)
+ result += ++cmap_i_insert(&map, crandom() & mask, 0).ref->second;
+ s.set_result(result);
+ cmap_i_drop(&map);
+}
+
+#define P samples(S1).iterations({N1, N1, N1, N1}).args({18, 23, 25, 31})
+PICOBENCH(ins_and_access_i<umap_i>).P;
+PICOBENCH(ins_and_access_i<bmap_i>).P;
+PICOBENCH(ins_and_access_i<fmap_i>).P;
+PICOBENCH(ins_and_access_i<hmap_i>).P;
+PICOBENCH(ins_and_access_i<pmap_i>).P;
+PICOBENCH(ins_and_access_i<rmap_i>).P;
+PICOBENCH(ins_and_access_cmap_i).P;
+#undef P
+
+PICOBENCH_SUITE("Map3");
+
+static void randomize(char* str, size_t len) {
+ for (int k=0; k < len; ++k) {
+ union {uint64_t i; char c[8];} r = {.i = crandom()};
+ for (int i=0; i<8 && k<len; ++k, ++i)
+ str[k] = (r.c[i] & 63) + 48;
+ }
+}
+
+template <class MapStr>
+static void ins_and_access_s(picobench::state& s)
+{
+ std::string str(s.arg(), 'x');
+ size_t result = 0;
+ MapStr map;
+ map.max_load_factor((int)MaxLoadFactor100 / 100.0);
+ csrandom(seed);
+
+ picobench::scope scope(s);
+ c_forrange (s.iterations()) {
+ randomize(&str[0], str.size());
+ map.emplace(str, str);
+ randomize(&str[0], str.size());
+ result += map.erase(str);
+ }
+ s.set_result(result + map.size());
+}
+
+static void ins_and_access_cmap_s(picobench::state& s)
+{
+ cstr str = cstr_with_size(s.arg(), 'x');
+ char* buf = cstr_data(&str);
+ size_t result = 0;
+ cmap_str map = cmap_str_init();
+ cmap_str_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
+ csrandom(seed);
+
+ picobench::scope scope(s);
+ c_forrange (s.iterations()) {
+ randomize(buf, s.arg());
+ //if (s.arg() > 30) { printf("%s\n", buf); exit(0); }
+ cmap_str_emplace(&map, buf, buf);
+
+ randomize(buf, s.arg());
+ result += cmap_str_erase(&map, buf);
+ }
+ s.set_result(result + cmap_str_size(map));
+ cstr_drop(&str);
+ cmap_str_drop(&map);
+}
+
+#define P samples(S1).iterations({N1/5, N1/5, N1/5, N1/10, N1/40}).args({13, 7, 8, 100, 1000})
+PICOBENCH(ins_and_access_s<umap_s>).P;
+PICOBENCH(ins_and_access_s<bmap_s>).P;
+PICOBENCH(ins_and_access_s<fmap_s>).P;
+PICOBENCH(ins_and_access_s<hmap_s>).P;
+PICOBENCH(ins_and_access_s<pmap_s>).P;
+PICOBENCH(ins_and_access_s<rmap_s>).P;
+PICOBENCH(ins_and_access_cmap_s).P;
+#undef P
+
+PICOBENCH_SUITE("Map4");
+
+template <class MapX>
+static void iterate_x(picobench::state& s)
+{
+ MapX map;
+ map.max_load_factor((int)MaxLoadFactor100 / 100.0);
+ uint64_t K = (1ull << s.arg()) - 1;
+
+ picobench::scope scope(s);
+ csrandom(seed);
+ size_t result = 0;
+
+ // measure insert then iterate whole map
+ c_forrange (n, s.iterations()) {
+ map[crandom()] = n;
+ if (!(n & K)) for (auto const& keyVal : map)
+ result += keyVal.second;
+ }
+
+ // reset rng back to inital state
+ csrandom(seed);
+
+ // measure erase then iterate whole map
+ c_forrange (n, s.iterations()) {
+ map.erase(crandom());
+ if (!(n & K)) for (auto const& keyVal : map)
+ result += keyVal.second;
+ }
+ s.set_result(result);
+}
+
+static void iterate_cmap_x(picobench::state& s)
+{
+ cmap_x map = cmap_x_init();
+ cmap_x_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
+ uint64_t K = (1ull << s.arg()) - 1;
+
+ picobench::scope scope(s);
+ csrandom(seed);
+ size_t result = 0;
+
+ // measure insert then iterate whole map
+ c_forrange (n, s.iterations()) {
+ cmap_x_insert_or_assign(&map, crandom(), n);
+ if (!(n & K)) c_foreach (i, cmap_x, map)
+ result += i.ref->second;
+ }
+
+ // reset rng back to inital state
+ csrandom(seed);
+
+ // measure erase then iterate whole map
+ c_forrange (n, s.iterations()) {
+ cmap_x_erase(&map, crandom());
+ if (!(n & K)) c_foreach (i, cmap_x, map)
+ result += i.ref->second;
+ }
+ s.set_result(result);
+ cmap_x_drop(&map);
+}
+
+
+#define P samples(S1).iterations({N1/20}).args({12})
+PICOBENCH(iterate_x<umap_x>).P;
+PICOBENCH(iterate_x<bmap_x>).P;
+PICOBENCH(iterate_x<fmap_x>).P;
+PICOBENCH(iterate_x<hmap_x>).P;
+PICOBENCH(iterate_x<pmap_x>).P;
+PICOBENCH(iterate_x<rmap_x>).P;
+PICOBENCH(iterate_cmap_x).P;
+#undef P
diff --git a/benchmarks/picobench/picobench_csmap.cpp b/benchmarks/picobench/picobench_csmap.cpp
index 3f203cc8..ea2174fa 100644
--- a/benchmarks/picobench/picobench_csmap.cpp
+++ b/benchmarks/picobench/picobench_csmap.cpp
@@ -1,322 +1,322 @@
-#include <iostream>
-#define i_static
-#include <stc/crandom.h>
-#define i_static
-#include <stc/cstr.h>
-#include <cmath>
-#include <string>
-#include <map>
-
-#define PICOBENCH_IMPLEMENT_WITH_MAIN
-#include "picobench.hpp"
-
-enum {N1 = 1000000, S1 = 1};
-uint64_t seed = time(NULL); // 18237129837891;
-
-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>;
-
-#define i_key int
-#define i_val int
-#define i_tag i
-#include <stc/csmap.h>
-
-#define i_key size_t
-#define i_val size_t
-#define i_tag x
-#include <stc/csmap.h>
-
-#define i_key_str
-#define i_val_str
-#include <stc/csmap.h>
-
-PICOBENCH_SUITE("Map1");
-
-template <class MapInt>
-static void ctor_and_ins_one_i(picobench::state& s)
-{
- size_t result = 0;
- picobench::scope scope(s);
- c_forrange (n, s.iterations()) {
- MapInt map;
- map[n];
- result += map.size();
- }
- s.set_result(result);
-}
-
-static void ctor_and_ins_one_csmap_i(picobench::state& s)
-{
- size_t result = 0;
- picobench::scope scope(s);
- c_forrange (n, s.iterations()) {
- csmap_i map = csmap_i_init();
- csmap_i_insert(&map, n, 0);
- result += csmap_i_size(map);
- csmap_i_drop(&map);
- }
- s.set_result(result);
-}
-
-#define P samples(S1).iterations({N1})
-//PICOBENCH(ctor_and_ins_one_i<omap_i>).P;
-//PICOBENCH(ctor_and_ins_one_csmap_i).P;
-#undef P
-
-
-PICOBENCH_SUITE("Map_insert_only");
-
-template <class MapInt>
-static void insert_i(picobench::state& s)
-{
- size_t result = 0;
- MapInt map;
- csrandom(seed);
- picobench::scope scope(s);
- c_forrange (n, s.iterations())
- map.emplace(crandom() & 0xfffffff, n);
- s.set_result(map.size());
-}
-
-static void insert_csmap_i(picobench::state& s)
-{
- size_t result = 0;
- csmap_i map = csmap_i_init();
- csrandom(seed);
- picobench::scope scope(s);
- c_forrange (n, s.iterations())
- csmap_i_insert(&map, crandom() & 0xfffffff, n);
- s.set_result(csmap_i_size(map));
- csmap_i_drop(&map);
-}
-
-#define P samples(S1).iterations({N1})
-PICOBENCH(insert_i<omap_i>).P;
-PICOBENCH(insert_csmap_i).P;
-#undef P
-
-
-PICOBENCH_SUITE("Map2");
-
-template <class MapInt>
-static void ins_and_erase_i(picobench::state& s)
-{
- size_t result = 0;
- uint64_t mask = (1ull << s.arg()) - 1;
- MapInt map;
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (i, s.iterations())
- map.emplace(crandom() & mask, i);
- result = map.size();
-
- map.clear();
- csrandom(seed);
- c_forrange (i, s.iterations())
- map[crandom() & mask] = i;
-
- csrandom(seed);
- c_forrange (s.iterations())
- map.erase(crandom() & mask);
- s.set_result(result);
-}
-
-static void ins_and_erase_csmap_i(picobench::state& s)
-{
- size_t result = 0;
- uint64_t mask = (1ull << s.arg()) - 1;
- csmap_i map = csmap_i_init();
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (i, s.iterations())
- csmap_i_insert(&map, crandom() & mask, i);
- result = csmap_i_size(map);
-
- csmap_i_clear(&map);
- csrandom(seed);
- c_forrange (i, s.iterations())
- csmap_i_insert_or_assign(&map, crandom() & mask, i);
-
- csrandom(seed);
- c_forrange (s.iterations())
- csmap_i_erase(&map, crandom() & mask);
- s.set_result(result);
- csmap_i_drop(&map);
-}
-
-#define P samples(S1).iterations({N1/2, N1/2, N1/2, N1/2}).args({18, 23, 25, 31})
-PICOBENCH(ins_and_erase_i<omap_i>).P;
-PICOBENCH(ins_and_erase_csmap_i).P;
-#undef P
-
-PICOBENCH_SUITE("Map3");
-
-template <class MapInt>
-static void ins_and_access_i(picobench::state& s)
-{
- uint64_t mask = (1ull << s.arg()) - 1;
- size_t result = 0;
- MapInt map;
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (s.iterations()) {
- result += ++map[crandom() & mask];
- auto it = map.find(crandom() & mask);
- if (it != map.end()) map.erase(it->first);
- }
- s.set_result(result + map.size());
-}
-
-static void ins_and_access_csmap_i(picobench::state& s)
-{
- uint64_t mask = (1ull << s.arg()) - 1;
- size_t result = 0;
- csmap_i map = csmap_i_init();
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (s.iterations()) {
- result += ++csmap_i_insert(&map, crandom() & mask, 0).ref->second;
- const csmap_i_value* val = csmap_i_get(&map, crandom() & mask);
- if (val) csmap_i_erase(&map, val->first);
- }
- s.set_result(result + csmap_i_size(map));
- csmap_i_drop(&map);
-}
-
-#define P samples(S1).iterations({N1, N1, N1, N1}).args({18, 23, 25, 31})
-PICOBENCH(ins_and_access_i<omap_i>).P;
-PICOBENCH(ins_and_access_csmap_i).P;
-#undef P
-
-PICOBENCH_SUITE("Map4");
-
-static void randomize(char* str, size_t len) {
- union {uint64_t i; char c[8];} r = {.i = crandom()};
- for (int i = len - 7, j = 0; i < len; ++j, ++i)
- str[i] = (r.c[j] & 63) + 48;
-}
-
-template <class MapStr>
-static void ins_and_access_s(picobench::state& s)
-{
- std::string str(s.arg(), 'x');
- size_t result = 0;
- MapStr map;
-
- picobench::scope scope(s);
- csrandom(seed);
- c_forrange (s.iterations()) {
- randomize(&str[0], str.size());
- map.emplace(str, str);
- }
- csrandom(seed);
- c_forrange (s.iterations()) {
- randomize(&str[0], str.size());
- result += map.erase(str);
- }
- s.set_result(result + map.size());
-}
-
-static void ins_and_access_csmap_s(picobench::state& s)
-{
- cstr str = cstr_with_size(s.arg(), 'x');
- char* buf = cstr_data(&str);
- size_t result = 0;
- csmap_str map = csmap_str_init();
-
- picobench::scope scope(s);
- csrandom(seed);
- c_forrange (s.iterations()) {
- randomize(buf, s.arg());
- csmap_str_emplace(&map, buf, buf);
- }
- csrandom(seed);
- c_forrange (s.iterations()) {
- randomize(buf, s.arg());
- result += csmap_str_erase(&map, buf);
- /*csmap_str_iter it = csmap_str_find(&map, buf);
- if (it.ref) {
- ++result;
- csmap_str_erase(&map, cstr_str(&it.ref->first));
- }*/
- }
- s.set_result(result + csmap_str_size(map));
- cstr_drop(&str);
- csmap_str_drop(&map);
-}
-
-#define P samples(S1).iterations({N1/5, N1/5, N1/5, N1/10, N1/40}).args({13, 7, 8, 100, 1000})
-PICOBENCH(ins_and_access_s<omap_s>).P;
-PICOBENCH(ins_and_access_csmap_s).P;
-#undef P
-
-PICOBENCH_SUITE("Map5");
-
-template <class MapX>
-static void iterate_x(picobench::state& s)
-{
- MapX map;
- uint64_t K = (1ull << s.arg()) - 1;
-
- picobench::scope scope(s);
- csrandom(seed);
- size_t result = 0;
-
- // measure insert then iterate whole map
- c_forrange (n, s.iterations()) {
- map[crandom()] = n;
- if (!(n & K)) for (auto const& keyVal : map)
- result += keyVal.second;
- }
-
- // reset rng back to inital state
- csrandom(seed);
-
- // measure erase then iterate whole map
- c_forrange (n, s.iterations()) {
- map.erase(crandom());
- if (!(n & K)) for (auto const& keyVal : map)
- result += keyVal.second;
- }
- s.set_result(result);
-}
-
-static void iterate_csmap_x(picobench::state& s)
-{
- csmap_x map = csmap_x_init();
- uint64_t K = (1ull << s.arg()) - 1;
-
- picobench::scope scope(s);
- csrandom(seed);
- size_t result = 0;
-
- // measure insert then iterate whole map
- c_forrange (n, s.iterations()) {
- csmap_x_insert_or_assign(&map, crandom(), n);
- if (!(n & K)) c_foreach (i, csmap_x, map)
- result += i.ref->second;
- }
-
- // reset rng back to inital state
- csrandom(seed);
-
- // measure erase then iterate whole map
- c_forrange (n, s.iterations()) {
- csmap_x_erase(&map, crandom());
- if (!(n & K)) c_foreach (i, csmap_x, map)
- result += i.ref->second;
- }
- s.set_result(result);
- csmap_x_drop(&map);
-}
-
-
-#define P samples(S1).iterations({N1/20}).args({12})
-//PICOBENCH(iterate_x<omap_x>).P;
-//PICOBENCH(iterate_csmap_x).P;
-#undef P
+#include <iostream>
+#define i_static
+#include <stc/crandom.h>
+#define i_static
+#include <stc/cstr.h>
+#include <cmath>
+#include <string>
+#include <map>
+
+#define PICOBENCH_IMPLEMENT_WITH_MAIN
+#include "picobench.hpp"
+
+enum {N1 = 1000000, S1 = 1};
+uint64_t seed = time(NULL); // 18237129837891;
+
+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>;
+
+#define i_key int
+#define i_val int
+#define i_tag i
+#include <stc/csmap.h>
+
+#define i_key size_t
+#define i_val size_t
+#define i_tag x
+#include <stc/csmap.h>
+
+#define i_key_str
+#define i_val_str
+#include <stc/csmap.h>
+
+PICOBENCH_SUITE("Map1");
+
+template <class MapInt>
+static void ctor_and_ins_one_i(picobench::state& s)
+{
+ size_t result = 0;
+ picobench::scope scope(s);
+ c_forrange (n, s.iterations()) {
+ MapInt map;
+ map[n];
+ result += map.size();
+ }
+ s.set_result(result);
+}
+
+static void ctor_and_ins_one_csmap_i(picobench::state& s)
+{
+ size_t result = 0;
+ picobench::scope scope(s);
+ c_forrange (n, s.iterations()) {
+ csmap_i map = csmap_i_init();
+ csmap_i_insert(&map, n, 0);
+ result += csmap_i_size(map);
+ csmap_i_drop(&map);
+ }
+ s.set_result(result);
+}
+
+#define P samples(S1).iterations({N1})
+//PICOBENCH(ctor_and_ins_one_i<omap_i>).P;
+//PICOBENCH(ctor_and_ins_one_csmap_i).P;
+#undef P
+
+
+PICOBENCH_SUITE("Map_insert_only");
+
+template <class MapInt>
+static void insert_i(picobench::state& s)
+{
+ size_t result = 0;
+ MapInt map;
+ csrandom(seed);
+ picobench::scope scope(s);
+ c_forrange (n, s.iterations())
+ map.emplace(crandom() & 0xfffffff, n);
+ s.set_result(map.size());
+}
+
+static void insert_csmap_i(picobench::state& s)
+{
+ size_t result = 0;
+ csmap_i map = csmap_i_init();
+ csrandom(seed);
+ picobench::scope scope(s);
+ c_forrange (n, s.iterations())
+ csmap_i_insert(&map, crandom() & 0xfffffff, n);
+ s.set_result(csmap_i_size(map));
+ csmap_i_drop(&map);
+}
+
+#define P samples(S1).iterations({N1})
+PICOBENCH(insert_i<omap_i>).P;
+PICOBENCH(insert_csmap_i).P;
+#undef P
+
+
+PICOBENCH_SUITE("Map2");
+
+template <class MapInt>
+static void ins_and_erase_i(picobench::state& s)
+{
+ size_t result = 0;
+ uint64_t mask = (1ull << s.arg()) - 1;
+ MapInt map;
+ csrandom(seed);
+
+ picobench::scope scope(s);
+ c_forrange (i, s.iterations())
+ map.emplace(crandom() & mask, i);
+ result = map.size();
+
+ map.clear();
+ csrandom(seed);
+ c_forrange (i, s.iterations())
+ map[crandom() & mask] = i;
+
+ csrandom(seed);
+ c_forrange (s.iterations())
+ map.erase(crandom() & mask);
+ s.set_result(result);
+}
+
+static void ins_and_erase_csmap_i(picobench::state& s)
+{
+ size_t result = 0;
+ uint64_t mask = (1ull << s.arg()) - 1;
+ csmap_i map = csmap_i_init();
+ csrandom(seed);
+
+ picobench::scope scope(s);
+ c_forrange (i, s.iterations())
+ csmap_i_insert(&map, crandom() & mask, i);
+ result = csmap_i_size(map);
+
+ csmap_i_clear(&map);
+ csrandom(seed);
+ c_forrange (i, s.iterations())
+ csmap_i_insert_or_assign(&map, crandom() & mask, i);
+
+ csrandom(seed);
+ c_forrange (s.iterations())
+ csmap_i_erase(&map, crandom() & mask);
+ s.set_result(result);
+ csmap_i_drop(&map);
+}
+
+#define P samples(S1).iterations({N1/2, N1/2, N1/2, N1/2}).args({18, 23, 25, 31})
+PICOBENCH(ins_and_erase_i<omap_i>).P;
+PICOBENCH(ins_and_erase_csmap_i).P;
+#undef P
+
+PICOBENCH_SUITE("Map3");
+
+template <class MapInt>
+static void ins_and_access_i(picobench::state& s)
+{
+ uint64_t mask = (1ull << s.arg()) - 1;
+ size_t result = 0;
+ MapInt map;
+ csrandom(seed);
+
+ picobench::scope scope(s);
+ c_forrange (s.iterations()) {
+ result += ++map[crandom() & mask];
+ auto it = map.find(crandom() & mask);
+ if (it != map.end()) map.erase(it->first);
+ }
+ s.set_result(result + map.size());
+}
+
+static void ins_and_access_csmap_i(picobench::state& s)
+{
+ uint64_t mask = (1ull << s.arg()) - 1;
+ size_t result = 0;
+ csmap_i map = csmap_i_init();
+ csrandom(seed);
+
+ picobench::scope scope(s);
+ c_forrange (s.iterations()) {
+ result += ++csmap_i_insert(&map, crandom() & mask, 0).ref->second;
+ const csmap_i_value* val = csmap_i_get(&map, crandom() & mask);
+ if (val) csmap_i_erase(&map, val->first);
+ }
+ s.set_result(result + csmap_i_size(map));
+ csmap_i_drop(&map);
+}
+
+#define P samples(S1).iterations({N1, N1, N1, N1}).args({18, 23, 25, 31})
+PICOBENCH(ins_and_access_i<omap_i>).P;
+PICOBENCH(ins_and_access_csmap_i).P;
+#undef P
+
+PICOBENCH_SUITE("Map4");
+
+static void randomize(char* str, size_t len) {
+ union {uint64_t i; char c[8];} r = {.i = crandom()};
+ for (int i = len - 7, j = 0; i < len; ++j, ++i)
+ str[i] = (r.c[j] & 63) + 48;
+}
+
+template <class MapStr>
+static void ins_and_access_s(picobench::state& s)
+{
+ std::string str(s.arg(), 'x');
+ size_t result = 0;
+ MapStr map;
+
+ picobench::scope scope(s);
+ csrandom(seed);
+ c_forrange (s.iterations()) {
+ randomize(&str[0], str.size());
+ map.emplace(str, str);
+ }
+ csrandom(seed);
+ c_forrange (s.iterations()) {
+ randomize(&str[0], str.size());
+ result += map.erase(str);
+ }
+ s.set_result(result + map.size());
+}
+
+static void ins_and_access_csmap_s(picobench::state& s)
+{
+ cstr str = cstr_with_size(s.arg(), 'x');
+ char* buf = cstr_data(&str);
+ size_t result = 0;
+ csmap_str map = csmap_str_init();
+
+ picobench::scope scope(s);
+ csrandom(seed);
+ c_forrange (s.iterations()) {
+ randomize(buf, s.arg());
+ csmap_str_emplace(&map, buf, buf);
+ }
+ csrandom(seed);
+ c_forrange (s.iterations()) {
+ randomize(buf, s.arg());
+ result += csmap_str_erase(&map, buf);
+ /*csmap_str_iter it = csmap_str_find(&map, buf);
+ if (it.ref) {
+ ++result;
+ csmap_str_erase(&map, cstr_str(&it.ref->first));
+ }*/
+ }
+ s.set_result(result + csmap_str_size(map));
+ cstr_drop(&str);
+ csmap_str_drop(&map);
+}
+
+#define P samples(S1).iterations({N1/5, N1/5, N1/5, N1/10, N1/40}).args({13, 7, 8, 100, 1000})
+PICOBENCH(ins_and_access_s<omap_s>).P;
+PICOBENCH(ins_and_access_csmap_s).P;
+#undef P
+
+PICOBENCH_SUITE("Map5");
+
+template <class MapX>
+static void iterate_x(picobench::state& s)
+{
+ MapX map;
+ uint64_t K = (1ull << s.arg()) - 1;
+
+ picobench::scope scope(s);
+ csrandom(seed);
+ size_t result = 0;
+
+ // measure insert then iterate whole map
+ c_forrange (n, s.iterations()) {
+ map[crandom()] = n;
+ if (!(n & K)) for (auto const& keyVal : map)
+ result += keyVal.second;
+ }
+
+ // reset rng back to inital state
+ csrandom(seed);
+
+ // measure erase then iterate whole map
+ c_forrange (n, s.iterations()) {
+ map.erase(crandom());
+ if (!(n & K)) for (auto const& keyVal : map)
+ result += keyVal.second;
+ }
+ s.set_result(result);
+}
+
+static void iterate_csmap_x(picobench::state& s)
+{
+ csmap_x map = csmap_x_init();
+ uint64_t K = (1ull << s.arg()) - 1;
+
+ picobench::scope scope(s);
+ csrandom(seed);
+ size_t result = 0;
+
+ // measure insert then iterate whole map
+ c_forrange (n, s.iterations()) {
+ csmap_x_insert_or_assign(&map, crandom(), n);
+ if (!(n & K)) c_foreach (i, csmap_x, map)
+ result += i.ref->second;
+ }
+
+ // reset rng back to inital state
+ csrandom(seed);
+
+ // measure erase then iterate whole map
+ c_forrange (n, s.iterations()) {
+ csmap_x_erase(&map, crandom());
+ if (!(n & K)) c_foreach (i, csmap_x, map)
+ result += i.ref->second;
+ }
+ s.set_result(result);
+ csmap_x_drop(&map);
+}
+
+
+#define P samples(S1).iterations({N1/20}).args({12})
+//PICOBENCH(iterate_x<omap_x>).P;
+//PICOBENCH(iterate_csmap_x).P;
+#undef P
diff --git a/benchmarks/plotbench/cdeq_benchmark.cpp b/benchmarks/plotbench/cdeq_benchmark.cpp
index 057a50b8..d938450a 100644
--- a/benchmarks/plotbench/cdeq_benchmark.cpp
+++ b/benchmarks/plotbench/cdeq_benchmark.cpp
@@ -1,130 +1,130 @@
-#include <stdio.h>
-#include <time.h>
-#define i_static
-#include <stc/crandom.h>
-
-#ifdef __cplusplus
-#include <deque>
-#include <algorithm>
-#endif
-
-enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
-typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
-typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 100000000, S = 0x3ffc, R = 4};
-uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
-
-static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-
-#define i_tag x
-#define i_val size_t
-#include <stc/cdeq.h>
-
-#ifdef __cplusplus
-Sample test_std_deque() {
- typedef std::deque<size_t> container;
- Sample s = {"std,deque"};
- {
- s.test[INSERT].t1 = clock();
- container con;
- csrandom(seed);
- c_forrange (N/3) con.push_front(crandom() & mask1);
- c_forrange (N/3) {con.push_back(crandom() & mask1); con.pop_front();}
- c_forrange (N/3) con.push_back(crandom() & mask1);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = con.size();
- s.test[ERASE].t1 = clock();
- c_forrange (con.size()/2) { con.pop_front(); con.pop_back(); }
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = con.size();
- }{
- container con;
- csrandom(seed);
- c_forrange (N) con.push_back(crandom() & mask2);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- // Iteration - not inherent find - skipping
- //container::iterator it;
- //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con[i];
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-#else
-Sample test_std_deque() { Sample s = {"std-deque"}; return s;}
-#endif
-
-
-Sample test_stc_deque() {
- typedef cdeq_x container;
- Sample s = {"STC,deque"};
- {
- s.test[INSERT].t1 = clock();
- container con = cdeq_x_init();
- //cdeq_x_reserve(&con, N);
- csrandom(seed);
- c_forrange (N/3) cdeq_x_push_front(&con, crandom() & mask1);
- c_forrange (N/3) {cdeq_x_push_back(&con, crandom() & mask1); cdeq_x_pop_front(&con);}
- c_forrange (N/3) cdeq_x_push_back(&con, crandom() & mask1);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = cdeq_x_size(con);
- s.test[ERASE].t1 = clock();
- c_forrange (cdeq_x_size(con)/2) { cdeq_x_pop_front(&con); cdeq_x_pop_back(&con); }
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = cdeq_x_size(con);
- cdeq_x_drop(&con);
- }{
- csrandom(seed);
- container con = cdeq_x_init();
- c_forrange (N) cdeq_x_push_back(&con, crandom() & mask2);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- //cdeq_x_iter it, end = cdeq_x_end(&con);
- //c_forrange (S) if ((it = cdeq_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con.data[i];
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- cdeq_x_drop(&con);
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-
-int main(int argc, char* argv[])
-{
- Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1];
- c_forrange (i, int, SAMPLES) {
- std_s[i] = test_std_deque();
- stc_s[i] = test_stc_deque();
- if (i > 0) c_forrange (j, int, N_TESTS) {
- if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
- if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
- if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
- }
- }
- const char* comp = argc > 1 ? argv[1] : "test";
- bool header = (argc > 2 && argv[2][0] == '1');
- float std_sum = 0, stc_sum = 0;
- c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
- if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
-}
+#include <stdio.h>
+#include <time.h>
+#define i_static
+#include <stc/crandom.h>
+
+#ifdef __cplusplus
+#include <deque>
+#include <algorithm>
+#endif
+
+enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
+const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
+typedef struct { const char* name; Range test[N_TESTS]; } Sample;
+enum {SAMPLES = 2, N = 100000000, S = 0x3ffc, R = 4};
+uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
+
+static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
+
+#define i_tag x
+#define i_val size_t
+#include <stc/cdeq.h>
+
+#ifdef __cplusplus
+Sample test_std_deque() {
+ typedef std::deque<size_t> container;
+ Sample s = {"std,deque"};
+ {
+ s.test[INSERT].t1 = clock();
+ container con;
+ csrandom(seed);
+ c_forrange (N/3) con.push_front(crandom() & mask1);
+ c_forrange (N/3) {con.push_back(crandom() & mask1); con.pop_front();}
+ c_forrange (N/3) con.push_back(crandom() & mask1);
+ s.test[INSERT].t2 = clock();
+ s.test[INSERT].sum = con.size();
+ s.test[ERASE].t1 = clock();
+ c_forrange (con.size()/2) { con.pop_front(); con.pop_back(); }
+ s.test[ERASE].t2 = clock();
+ s.test[ERASE].sum = con.size();
+ }{
+ container con;
+ csrandom(seed);
+ c_forrange (N) con.push_back(crandom() & mask2);
+ s.test[FIND].t1 = clock();
+ size_t sum = 0;
+ // Iteration - not inherent find - skipping
+ //container::iterator it;
+ //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it;
+ s.test[FIND].t2 = clock();
+ s.test[FIND].sum = sum;
+ s.test[ITER].t1 = clock();
+ sum = 0;
+ c_forrange (R) c_forrange (i, N) sum += con[i];
+ s.test[ITER].t2 = clock();
+ s.test[ITER].sum = sum;
+ s.test[DESTRUCT].t1 = clock();
+ }
+ s.test[DESTRUCT].t2 = clock();
+ s.test[DESTRUCT].sum = 0;
+ return s;
+}
+#else
+Sample test_std_deque() { Sample s = {"std-deque"}; return s;}
+#endif
+
+
+Sample test_stc_deque() {
+ typedef cdeq_x container;
+ Sample s = {"STC,deque"};
+ {
+ s.test[INSERT].t1 = clock();
+ container con = cdeq_x_init();
+ //cdeq_x_reserve(&con, N);
+ csrandom(seed);
+ c_forrange (N/3) cdeq_x_push_front(&con, crandom() & mask1);
+ c_forrange (N/3) {cdeq_x_push_back(&con, crandom() & mask1); cdeq_x_pop_front(&con);}
+ c_forrange (N/3) cdeq_x_push_back(&con, crandom() & mask1);
+ s.test[INSERT].t2 = clock();
+ s.test[INSERT].sum = cdeq_x_size(con);
+ s.test[ERASE].t1 = clock();
+ c_forrange (cdeq_x_size(con)/2) { cdeq_x_pop_front(&con); cdeq_x_pop_back(&con); }
+ s.test[ERASE].t2 = clock();
+ s.test[ERASE].sum = cdeq_x_size(con);
+ cdeq_x_drop(&con);
+ }{
+ csrandom(seed);
+ container con = cdeq_x_init();
+ c_forrange (N) cdeq_x_push_back(&con, crandom() & mask2);
+ s.test[FIND].t1 = clock();
+ size_t sum = 0;
+ //cdeq_x_iter it, end = cdeq_x_end(&con);
+ //c_forrange (S) if ((it = cdeq_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref;
+ s.test[FIND].t2 = clock();
+ s.test[FIND].sum = sum;
+ s.test[ITER].t1 = clock();
+ sum = 0;
+ c_forrange (R) c_forrange (i, N) sum += con.data[i];
+ s.test[ITER].t2 = clock();
+ s.test[ITER].sum = sum;
+ s.test[DESTRUCT].t1 = clock();
+ cdeq_x_drop(&con);
+ }
+ s.test[DESTRUCT].t2 = clock();
+ s.test[DESTRUCT].sum = 0;
+ return s;
+}
+
+int main(int argc, char* argv[])
+{
+ Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1];
+ c_forrange (i, int, SAMPLES) {
+ std_s[i] = test_std_deque();
+ stc_s[i] = test_stc_deque();
+ if (i > 0) c_forrange (j, int, N_TESTS) {
+ if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
+ if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
+ if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
+ }
+ }
+ const char* comp = argc > 1 ? argv[1] : "test";
+ bool header = (argc > 2 && argv[2][0] == '1');
+ float std_sum = 0, stc_sum = 0;
+ c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
+ if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
+ c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
+ printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
+ c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
+ printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
+}
diff --git a/benchmarks/plotbench/clist_benchmark.cpp b/benchmarks/plotbench/clist_benchmark.cpp
index dfa043f0..0f5a3f8f 100644
--- a/benchmarks/plotbench/clist_benchmark.cpp
+++ b/benchmarks/plotbench/clist_benchmark.cpp
@@ -1,127 +1,127 @@
-#include <stdio.h>
-#include <time.h>
-#define i_static
-#include <stc/crandom.h>
-
-#ifdef __cplusplus
-#include <forward_list>
-#include <algorithm>
-#endif
-
-enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
-typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
-typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 50000000, S = 0x3ffc, R = 4};
-uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
-
-static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-
-#define i_val size_t
-#define i_tag x
-#include <stc/clist.h>
-
-#ifdef __cplusplus
-Sample test_std_forward_list() {
- typedef std::forward_list<size_t> container;
- Sample s = {"std,forward_list"};
- {
- s.test[INSERT].t1 = clock();
- container con;
- csrandom(seed);
- c_forrange (N/2) con.push_front(crandom() & mask1);
- c_forrange (N/2) con.push_front(crandom() & mask1);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = 0;
- s.test[ERASE].t1 = clock();
- c_forrange (N) con.pop_front();
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = 0;
- }{
- container con;
- csrandom(seed);
- c_forrange (N) con.push_front(crandom() & mask2);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- container::iterator it;
- // Iteration - not inherent find - skipping
- //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) for (auto i: con) sum += i;
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-#else
-Sample test_std_forward_list() { Sample s = {"std-forward_list"}; return s;}
-#endif
-
-
-Sample test_stc_forward_list() {
- typedef clist_x container;
- Sample s = {"STC,forward_list"};
- {
- s.test[INSERT].t1 = clock();
- container con = clist_x_init();
- csrandom(seed);
- c_forrange (N/2) clist_x_push_front(&con, crandom() & mask1);
- c_forrange (N/2) clist_x_push_back(&con, crandom() & mask1);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = 0;
- s.test[ERASE].t1 = clock();
- c_forrange (N) clist_x_pop_front(&con);
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = 0;
- clist_x_drop(&con);
- }{
- csrandom(seed);
- container con = clist_x_init();
- c_forrange (N) clist_x_push_front(&con, crandom() & mask2);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- //clist_x_iter it, end = clist_x_end(&con);
- //c_forrange (S) if ((it = clist_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) c_foreach (i, clist_x, con) sum += *i.ref;
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- clist_x_drop(&con);
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-
-int main(int argc, char* argv[])
-{
- Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1];
- c_forrange (i, int, SAMPLES) {
- std_s[i] = test_std_forward_list();
- stc_s[i] = test_stc_forward_list();
- if (i > 0) c_forrange (j, int, N_TESTS) {
- if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
- if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
- if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
- }
- }
- const char* comp = argc > 1 ? argv[1] : "test";
- bool header = (argc > 2 && argv[2][0] == '1');
- float std_sum = 0, stc_sum = 0;
- c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
- if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
+#include <stdio.h>
+#include <time.h>
+#define i_static
+#include <stc/crandom.h>
+
+#ifdef __cplusplus
+#include <forward_list>
+#include <algorithm>
+#endif
+
+enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
+const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
+typedef struct { const char* name; Range test[N_TESTS]; } Sample;
+enum {SAMPLES = 2, N = 50000000, S = 0x3ffc, R = 4};
+uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
+
+static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
+
+#define i_val size_t
+#define i_tag x
+#include <stc/clist.h>
+
+#ifdef __cplusplus
+Sample test_std_forward_list() {
+ typedef std::forward_list<size_t> container;
+ Sample s = {"std,forward_list"};
+ {
+ s.test[INSERT].t1 = clock();
+ container con;
+ csrandom(seed);
+ c_forrange (N/2) con.push_front(crandom() & mask1);
+ c_forrange (N/2) con.push_front(crandom() & mask1);
+ s.test[INSERT].t2 = clock();
+ s.test[INSERT].sum = 0;
+ s.test[ERASE].t1 = clock();
+ c_forrange (N) con.pop_front();
+ s.test[ERASE].t2 = clock();
+ s.test[ERASE].sum = 0;
+ }{
+ container con;
+ csrandom(seed);
+ c_forrange (N) con.push_front(crandom() & mask2);
+ s.test[FIND].t1 = clock();
+ size_t sum = 0;
+ container::iterator it;
+ // Iteration - not inherent find - skipping
+ //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it;
+ s.test[FIND].t2 = clock();
+ s.test[FIND].sum = sum;
+ s.test[ITER].t1 = clock();
+ sum = 0;
+ c_forrange (R) for (auto i: con) sum += i;
+ s.test[ITER].t2 = clock();
+ s.test[ITER].sum = sum;
+ s.test[DESTRUCT].t1 = clock();
+ }
+ s.test[DESTRUCT].t2 = clock();
+ s.test[DESTRUCT].sum = 0;
+ return s;
+}
+#else
+Sample test_std_forward_list() { Sample s = {"std-forward_list"}; return s;}
+#endif
+
+
+Sample test_stc_forward_list() {
+ typedef clist_x container;
+ Sample s = {"STC,forward_list"};
+ {
+ s.test[INSERT].t1 = clock();
+ container con = clist_x_init();
+ csrandom(seed);
+ c_forrange (N/2) clist_x_push_front(&con, crandom() & mask1);
+ c_forrange (N/2) clist_x_push_back(&con, crandom() & mask1);
+ s.test[INSERT].t2 = clock();
+ s.test[INSERT].sum = 0;
+ s.test[ERASE].t1 = clock();
+ c_forrange (N) clist_x_pop_front(&con);
+ s.test[ERASE].t2 = clock();
+ s.test[ERASE].sum = 0;
+ clist_x_drop(&con);
+ }{
+ csrandom(seed);
+ container con = clist_x_init();
+ c_forrange (N) clist_x_push_front(&con, crandom() & mask2);
+ s.test[FIND].t1 = clock();
+ size_t sum = 0;
+ //clist_x_iter it, end = clist_x_end(&con);
+ //c_forrange (S) if ((it = clist_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref;
+ s.test[FIND].t2 = clock();
+ s.test[FIND].sum = sum;
+ s.test[ITER].t1 = clock();
+ sum = 0;
+ c_forrange (R) c_foreach (i, clist_x, con) sum += *i.ref;
+ s.test[ITER].t2 = clock();
+ s.test[ITER].sum = sum;
+ s.test[DESTRUCT].t1 = clock();
+ clist_x_drop(&con);
+ }
+ s.test[DESTRUCT].t2 = clock();
+ s.test[DESTRUCT].sum = 0;
+ return s;
+}
+
+int main(int argc, char* argv[])
+{
+ Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1];
+ c_forrange (i, int, SAMPLES) {
+ std_s[i] = test_std_forward_list();
+ stc_s[i] = test_stc_forward_list();
+ if (i > 0) c_forrange (j, int, N_TESTS) {
+ if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
+ if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
+ if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
+ }
+ }
+ const char* comp = argc > 1 ? argv[1] : "test";
+ bool header = (argc > 2 && argv[2][0] == '1');
+ float std_sum = 0, stc_sum = 0;
+ c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
+ if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
+ c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
+ printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
+ c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
+ printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
} \ No newline at end of file
diff --git a/benchmarks/plotbench/cmap_benchmark.cpp b/benchmarks/plotbench/cmap_benchmark.cpp
index 1021ab1c..781ad720 100644
--- a/benchmarks/plotbench/cmap_benchmark.cpp
+++ b/benchmarks/plotbench/cmap_benchmark.cpp
@@ -1,134 +1,134 @@
-#include <stdio.h>
-#include <time.h>
-#define i_static
-#include <stc/crandom.h>
-
-#ifdef __cplusplus
-#include <unordered_map>
-#endif
-
-enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
-typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
-typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 8000000, R = 4};
-uint64_t seed = 1, mask1 = 0xffffffff;
-
-static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-
-#define i_key uint64_t
-#define i_val uint64_t
-#define i_tag x
-#include <stc/cmap.h>
-
-#ifdef __cplusplus
-Sample test_std_unordered_map() {
- typedef std::unordered_map<uint64_t, uint64_t> container;
- Sample s = {"std,unordered_map"};
- {
- csrandom(seed);
- s.test[INSERT].t1 = clock();
- container con;
- c_forrange (i, N/2) con.emplace(crandom() & mask1, i);
- c_forrange (i, N/2) con.emplace(i, i);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = con.size();
- csrandom(seed);
- s.test[ERASE].t1 = clock();
- c_forrange (N) con.erase(crandom() & mask1);
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = con.size();
- }{
- container con;
- csrandom(seed);
- c_forrange (i, N/2) con.emplace(crandom() & mask1, i);
- c_forrange (i, N/2) con.emplace(i, i);
- csrandom(seed);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- container::iterator it;
- c_forrange (N) if ((it = con.find(crandom() & mask1)) != con.end()) sum += it->second;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) for (auto i: con) sum += i.second;
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-#else
-Sample test_std_unordered_map() { Sample s = {"std-unordered_map"}; return s;}
-#endif
-
-
-Sample test_stc_unordered_map() {
- typedef cmap_x container;
- Sample s = {"STC,unordered_map"};
- {
- csrandom(seed);
- s.test[INSERT].t1 = clock();
- container con = cmap_x_init();
- c_forrange (i, N/2) cmap_x_insert(&con, crandom() & mask1, i);
- c_forrange (i, N/2) cmap_x_insert(&con, i, i);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = cmap_x_size(con);
- csrandom(seed);
- s.test[ERASE].t1 = clock();
- c_forrange (N) cmap_x_erase(&con, crandom() & mask1);
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = cmap_x_size(con);
- cmap_x_drop(&con);
- }{
- container con = cmap_x_init();
- csrandom(seed);
- c_forrange (i, N/2) cmap_x_insert(&con, crandom() & mask1, i);
- c_forrange (i, N/2) cmap_x_insert(&con, i, i);
- csrandom(seed);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- const cmap_x_value* val;
- c_forrange (N)
- if ((val = cmap_x_get(&con, crandom() & mask1)))
- sum += val->second;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) c_foreach (i, cmap_x, con) sum += i.ref->second;
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- cmap_x_drop(&con);
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-
-int main(int argc, char* argv[])
-{
- Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1];
- c_forrange (i, int, SAMPLES) {
- std_s[i] = test_std_unordered_map();
- stc_s[i] = test_stc_unordered_map();
- if (i > 0) c_forrange (j, int, N_TESTS) {
- if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
- if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
- if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
- }
- }
- const char* comp = argc > 1 ? argv[1] : "test";
- bool header = (argc > 2 && argv[2][0] == '1');
- float std_sum = 0, stc_sum = 0;
- c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
- if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
+#include <stdio.h>
+#include <time.h>
+#define i_static
+#include <stc/crandom.h>
+
+#ifdef __cplusplus
+#include <unordered_map>
+#endif
+
+enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
+const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
+typedef struct { const char* name; Range test[N_TESTS]; } Sample;
+enum {SAMPLES = 2, N = 8000000, R = 4};
+uint64_t seed = 1, mask1 = 0xffffffff;
+
+static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
+
+#define i_key uint64_t
+#define i_val uint64_t
+#define i_tag x
+#include <stc/cmap.h>
+
+#ifdef __cplusplus
+Sample test_std_unordered_map() {
+ typedef std::unordered_map<uint64_t, uint64_t> container;
+ Sample s = {"std,unordered_map"};
+ {
+ csrandom(seed);
+ s.test[INSERT].t1 = clock();
+ container con;
+ c_forrange (i, N/2) con.emplace(crandom() & mask1, i);
+ c_forrange (i, N/2) con.emplace(i, i);
+ s.test[INSERT].t2 = clock();
+ s.test[INSERT].sum = con.size();
+ csrandom(seed);
+ s.test[ERASE].t1 = clock();
+ c_forrange (N) con.erase(crandom() & mask1);
+ s.test[ERASE].t2 = clock();
+ s.test[ERASE].sum = con.size();
+ }{
+ container con;
+ csrandom(seed);
+ c_forrange (i, N/2) con.emplace(crandom() & mask1, i);
+ c_forrange (i, N/2) con.emplace(i, i);
+ csrandom(seed);
+ s.test[FIND].t1 = clock();
+ size_t sum = 0;
+ container::iterator it;
+ c_forrange (N) if ((it = con.find(crandom() & mask1)) != con.end()) sum += it->second;
+ s.test[FIND].t2 = clock();
+ s.test[FIND].sum = sum;
+ s.test[ITER].t1 = clock();
+ sum = 0;
+ c_forrange (R) for (auto i: con) sum += i.second;
+ s.test[ITER].t2 = clock();
+ s.test[ITER].sum = sum;
+ s.test[DESTRUCT].t1 = clock();
+ }
+ s.test[DESTRUCT].t2 = clock();
+ s.test[DESTRUCT].sum = 0;
+ return s;
+}
+#else
+Sample test_std_unordered_map() { Sample s = {"std-unordered_map"}; return s;}
+#endif
+
+
+Sample test_stc_unordered_map() {
+ typedef cmap_x container;
+ Sample s = {"STC,unordered_map"};
+ {
+ csrandom(seed);
+ s.test[INSERT].t1 = clock();
+ container con = cmap_x_init();
+ c_forrange (i, N/2) cmap_x_insert(&con, crandom() & mask1, i);
+ c_forrange (i, N/2) cmap_x_insert(&con, i, i);
+ s.test[INSERT].t2 = clock();
+ s.test[INSERT].sum = cmap_x_size(con);
+ csrandom(seed);
+ s.test[ERASE].t1 = clock();
+ c_forrange (N) cmap_x_erase(&con, crandom() & mask1);
+ s.test[ERASE].t2 = clock();
+ s.test[ERASE].sum = cmap_x_size(con);
+ cmap_x_drop(&con);
+ }{
+ container con = cmap_x_init();
+ csrandom(seed);
+ c_forrange (i, N/2) cmap_x_insert(&con, crandom() & mask1, i);
+ c_forrange (i, N/2) cmap_x_insert(&con, i, i);
+ csrandom(seed);
+ s.test[FIND].t1 = clock();
+ size_t sum = 0;
+ const cmap_x_value* val;
+ c_forrange (N)
+ if ((val = cmap_x_get(&con, crandom() & mask1)))
+ sum += val->second;
+ s.test[FIND].t2 = clock();
+ s.test[FIND].sum = sum;
+ s.test[ITER].t1 = clock();
+ sum = 0;
+ c_forrange (R) c_foreach (i, cmap_x, con) sum += i.ref->second;
+ s.test[ITER].t2 = clock();
+ s.test[ITER].sum = sum;
+ s.test[DESTRUCT].t1 = clock();
+ cmap_x_drop(&con);
+ }
+ s.test[DESTRUCT].t2 = clock();
+ s.test[DESTRUCT].sum = 0;
+ return s;
+}
+
+int main(int argc, char* argv[])
+{
+ Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1];
+ c_forrange (i, int, SAMPLES) {
+ std_s[i] = test_std_unordered_map();
+ stc_s[i] = test_stc_unordered_map();
+ if (i > 0) c_forrange (j, int, N_TESTS) {
+ if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
+ if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
+ if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
+ }
+ }
+ const char* comp = argc > 1 ? argv[1] : "test";
+ bool header = (argc > 2 && argv[2][0] == '1');
+ float std_sum = 0, stc_sum = 0;
+ c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
+ if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
+ c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
+ printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
+ c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
+ printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
} \ No newline at end of file
diff --git a/benchmarks/plotbench/cpque_benchmark.cpp b/benchmarks/plotbench/cpque_benchmark.cpp
index b38bed1a..afa9c07e 100644
--- a/benchmarks/plotbench/cpque_benchmark.cpp
+++ b/benchmarks/plotbench/cpque_benchmark.cpp
@@ -1,71 +1,71 @@
-#include <stdio.h>
-#include <time.h>
-#define i_static
-#include <stc/crandom.h>
-
-#define i_val float
-#define i_cmp -c_default_cmp
-#define i_tag f
-#include <stc/cpque.h>
-
-#include <queue>
-
-static const uint32_t seed = 1234;
-
-void std_test()
-{
- stc64_t rng;
- int N = 10000000, M = 10;
-
- std::priority_queue<float, std::vector<float>, std::greater<float>> pq;
- rng = stc64_new(seed);
- clock_t start = clock();
- c_forrange (i, N)
- pq.push((float) stc64_randf(&rng)*100000);
-
- printf("Built priority queue: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC);
- printf("%g ", pq.top());
-
- start = clock();
- c_forrange (i, N) {
- pq.pop();
- }
-
- printf("\npopped PQ: %f secs\n\n", (clock() - start) / (float) CLOCKS_PER_SEC);
-}
-
-
-void stc_test()
-{
- stc64_t rng;
- int N = 10000000, M = 10;
-
- c_auto (cpque_f, pq)
- {
- rng = stc64_new(seed);
- clock_t start = clock();
- c_forrange (i, N)
- cpque_f_push(&pq, (float) stc64_randf(&rng)*100000);
-
- printf("Built priority queue: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC);
- printf("%g ", *cpque_f_top(&pq));
-
- c_forrange (i, int, M) {
- cpque_f_pop(&pq);
- }
-
- start = clock();
- c_forrange (i, int, M, N)
- cpque_f_pop(&pq);
- printf("\npopped PQ: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC);
- }
-}
-
-
-int main()
-{
- puts("STD P.QUEUE:");
- std_test();
- puts("\nSTC P.QUEUE:");
- stc_test();
-}
+#include <stdio.h>
+#include <time.h>
+#define i_static
+#include <stc/crandom.h>
+
+#define i_val float
+#define i_cmp -c_default_cmp
+#define i_tag f
+#include <stc/cpque.h>
+
+#include <queue>
+
+static const uint32_t seed = 1234;
+
+void std_test()
+{
+ stc64_t rng;
+ int N = 10000000, M = 10;
+
+ std::priority_queue<float, std::vector<float>, std::greater<float>> pq;
+ rng = stc64_new(seed);
+ clock_t start = clock();
+ c_forrange (i, N)
+ pq.push((float) stc64_randf(&rng)*100000);
+
+ printf("Built priority queue: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC);
+ printf("%g ", pq.top());
+
+ start = clock();
+ c_forrange (i, N) {
+ pq.pop();
+ }
+
+ printf("\npopped PQ: %f secs\n\n", (clock() - start) / (float) CLOCKS_PER_SEC);
+}
+
+
+void stc_test()
+{
+ stc64_t rng;
+ int N = 10000000, M = 10;
+
+ c_auto (cpque_f, pq)
+ {
+ rng = stc64_new(seed);
+ clock_t start = clock();
+ c_forrange (i, N)
+ cpque_f_push(&pq, (float) stc64_randf(&rng)*100000);
+
+ printf("Built priority queue: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC);
+ printf("%g ", *cpque_f_top(&pq));
+
+ c_forrange (i, int, M) {
+ cpque_f_pop(&pq);
+ }
+
+ start = clock();
+ c_forrange (i, int, M, N)
+ cpque_f_pop(&pq);
+ printf("\npopped PQ: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC);
+ }
+}
+
+
+int main()
+{
+ puts("STD P.QUEUE:");
+ std_test();
+ puts("\nSTC P.QUEUE:");
+ stc_test();
+}
diff --git a/benchmarks/plotbench/csmap_benchmark.cpp b/benchmarks/plotbench/csmap_benchmark.cpp
index 778d6894..3fb8a0a4 100644
--- a/benchmarks/plotbench/csmap_benchmark.cpp
+++ b/benchmarks/plotbench/csmap_benchmark.cpp
@@ -1,135 +1,135 @@
-#include <stdio.h>
-#include <time.h>
-#define i_static
-#include <stc/crandom.h>
-
-#ifdef __cplusplus
-#include <map>
-#endif
-
-enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
-typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
-typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 4000000, R = 4};
-uint64_t seed = 1, mask1 = 0xfffffff;
-
-static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-
-#define i_key size_t
-#define i_val size_t
-#define i_tag x
-#include <stc/csmap.h>
-
-#ifdef __cplusplus
-Sample test_std_map() {
- typedef std::map<size_t, size_t> container;
- Sample s = {"std,map"};
- {
- csrandom(seed);
- s.test[INSERT].t1 = clock();
- container con;
- c_forrange (i, N/2) con.emplace(crandom() & mask1, i);
- c_forrange (i, N/2) con.emplace(i, i);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = con.size();
- csrandom(seed);
- s.test[ERASE].t1 = clock();
- c_forrange (N) con.erase(crandom() & mask1);
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = con.size();
- }{
- container con;
- csrandom(seed);
- c_forrange (i, N/2) con.emplace(crandom() & mask1, i);
- c_forrange (i, N/2) con.emplace(i, i);
- csrandom(seed);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- container::iterator it;
- c_forrange (N) if ((it = con.find(crandom() & mask1)) != con.end()) sum += it->second;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) for (auto i: con) sum += i.second;
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-#else
-Sample test_std_map() { Sample s = {"std-map"}; return s;}
-#endif
-
-
-
-Sample test_stc_map() {
- typedef csmap_x container;
- Sample s = {"STC,map"};
- {
- csrandom(seed);
- s.test[INSERT].t1 = clock();
- container con = csmap_x_init();
- c_forrange (i, N/2) csmap_x_insert(&con, crandom() & mask1, i);
- c_forrange (i, N/2) csmap_x_insert(&con, i, i);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = csmap_x_size(con);
- csrandom(seed);
- s.test[ERASE].t1 = clock();
- c_forrange (N) csmap_x_erase(&con, crandom() & mask1);
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = csmap_x_size(con);
- csmap_x_drop(&con);
- }{
- container con = csmap_x_init();
- csrandom(seed);
- c_forrange (i, N/2) csmap_x_insert(&con, crandom() & mask1, i);
- c_forrange (i, N/2) csmap_x_insert(&con, i, i);
- csrandom(seed);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- const csmap_x_value* val;
- c_forrange (N)
- if ((val = csmap_x_get(&con, crandom() & mask1)))
- sum += val->second;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) c_foreach (i, csmap_x, con) sum += i.ref->second;
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- csmap_x_drop(&con);
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-
-int main(int argc, char* argv[])
-{
- Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1];
- c_forrange (i, int, SAMPLES) {
- std_s[i] = test_std_map();
- stc_s[i] = test_stc_map();
- if (i > 0) c_forrange (j, int, N_TESTS) {
- if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
- if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
- if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
- }
- }
- const char* comp = argc > 1 ? argv[1] : "test";
- bool header = (argc > 2 && argv[2][0] == '1');
- float std_sum = 0, stc_sum = 0;
- c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
- if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
-}
+#include <stdio.h>
+#include <time.h>
+#define i_static
+#include <stc/crandom.h>
+
+#ifdef __cplusplus
+#include <map>
+#endif
+
+enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
+const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
+typedef struct { const char* name; Range test[N_TESTS]; } Sample;
+enum {SAMPLES = 2, N = 4000000, R = 4};
+uint64_t seed = 1, mask1 = 0xfffffff;
+
+static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
+
+#define i_key size_t
+#define i_val size_t
+#define i_tag x
+#include <stc/csmap.h>
+
+#ifdef __cplusplus
+Sample test_std_map() {
+ typedef std::map<size_t, size_t> container;
+ Sample s = {"std,map"};
+ {
+ csrandom(seed);
+ s.test[INSERT].t1 = clock();
+ container con;
+ c_forrange (i, N/2) con.emplace(crandom() & mask1, i);
+ c_forrange (i, N/2) con.emplace(i, i);
+ s.test[INSERT].t2 = clock();
+ s.test[INSERT].sum = con.size();
+ csrandom(seed);
+ s.test[ERASE].t1 = clock();
+ c_forrange (N) con.erase(crandom() & mask1);
+ s.test[ERASE].t2 = clock();
+ s.test[ERASE].sum = con.size();
+ }{
+ container con;
+ csrandom(seed);
+ c_forrange (i, N/2) con.emplace(crandom() & mask1, i);
+ c_forrange (i, N/2) con.emplace(i, i);
+ csrandom(seed);
+ s.test[FIND].t1 = clock();
+ size_t sum = 0;
+ container::iterator it;
+ c_forrange (N) if ((it = con.find(crandom() & mask1)) != con.end()) sum += it->second;
+ s.test[FIND].t2 = clock();
+ s.test[FIND].sum = sum;
+ s.test[ITER].t1 = clock();
+ sum = 0;
+ c_forrange (R) for (auto i: con) sum += i.second;
+ s.test[ITER].t2 = clock();
+ s.test[ITER].sum = sum;
+ s.test[DESTRUCT].t1 = clock();
+ }
+ s.test[DESTRUCT].t2 = clock();
+ s.test[DESTRUCT].sum = 0;
+ return s;
+}
+#else
+Sample test_std_map() { Sample s = {"std-map"}; return s;}
+#endif
+
+
+
+Sample test_stc_map() {
+ typedef csmap_x container;
+ Sample s = {"STC,map"};
+ {
+ csrandom(seed);
+ s.test[INSERT].t1 = clock();
+ container con = csmap_x_init();
+ c_forrange (i, N/2) csmap_x_insert(&con, crandom() & mask1, i);
+ c_forrange (i, N/2) csmap_x_insert(&con, i, i);
+ s.test[INSERT].t2 = clock();
+ s.test[INSERT].sum = csmap_x_size(con);
+ csrandom(seed);
+ s.test[ERASE].t1 = clock();
+ c_forrange (N) csmap_x_erase(&con, crandom() & mask1);
+ s.test[ERASE].t2 = clock();
+ s.test[ERASE].sum = csmap_x_size(con);
+ csmap_x_drop(&con);
+ }{
+ container con = csmap_x_init();
+ csrandom(seed);
+ c_forrange (i, N/2) csmap_x_insert(&con, crandom() & mask1, i);
+ c_forrange (i, N/2) csmap_x_insert(&con, i, i);
+ csrandom(seed);
+ s.test[FIND].t1 = clock();
+ size_t sum = 0;
+ const csmap_x_value* val;
+ c_forrange (N)
+ if ((val = csmap_x_get(&con, crandom() & mask1)))
+ sum += val->second;
+ s.test[FIND].t2 = clock();
+ s.test[FIND].sum = sum;
+ s.test[ITER].t1 = clock();
+ sum = 0;
+ c_forrange (R) c_foreach (i, csmap_x, con) sum += i.ref->second;
+ s.test[ITER].t2 = clock();
+ s.test[ITER].sum = sum;
+ s.test[DESTRUCT].t1 = clock();
+ csmap_x_drop(&con);
+ }
+ s.test[DESTRUCT].t2 = clock();
+ s.test[DESTRUCT].sum = 0;
+ return s;
+}
+
+int main(int argc, char* argv[])
+{
+ Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1];
+ c_forrange (i, int, SAMPLES) {
+ std_s[i] = test_std_map();
+ stc_s[i] = test_stc_map();
+ if (i > 0) c_forrange (j, int, N_TESTS) {
+ if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
+ if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
+ if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
+ }
+ }
+ const char* comp = argc > 1 ? argv[1] : "test";
+ bool header = (argc > 2 && argv[2][0] == '1');
+ float std_sum = 0, stc_sum = 0;
+ c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
+ if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
+ c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
+ printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
+ c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
+ printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
+}
diff --git a/benchmarks/plotbench/cvec_benchmark.cpp b/benchmarks/plotbench/cvec_benchmark.cpp
index c23b689a..9ba95f31 100644
--- a/benchmarks/plotbench/cvec_benchmark.cpp
+++ b/benchmarks/plotbench/cvec_benchmark.cpp
@@ -1,126 +1,126 @@
-#include <stdio.h>
-#include <time.h>
-#define i_static
-#include <stc/crandom.h>
-
-#ifdef __cplusplus
-#include <vector>
-#include <algorithm>
-#endif
-
-enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
-typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
-typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 150000000, S = 0x3ffc, R = 4};
-uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
-
-static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-
-#define i_val size_t
-#define i_tag x
-#include <stc/cvec.h>
-
-#ifdef __cplusplus
-Sample test_std_vector() {
- typedef std::vector<size_t> container;
- Sample s = {"std,vector"};
- {
- s.test[INSERT].t1 = clock();
- container con;
- csrandom(seed);
- c_forrange (N) con.push_back(crandom() & mask1);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = con.size();
- s.test[ERASE].t1 = clock();
- c_forrange (N) con.pop_back();
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = con.size();
- }{
- container con;
- csrandom(seed);
- c_forrange (N) con.push_back(crandom() & mask2);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- container::iterator it;
- // Iteration - not inherent find - skipping
- //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con[i];
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-#else
-Sample test_std_vector() { Sample s = {"std-vector"}; return s;}
-#endif
-
-
-
-Sample test_stc_vector() {
- typedef cvec_x container;
- Sample s = {"STC,vector"};
- {
- s.test[INSERT].t1 = clock();
- container con = cvec_x_init();
- csrandom(seed);
- c_forrange (N) cvec_x_push_back(&con, crandom() & mask1);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = cvec_x_size(con);
- s.test[ERASE].t1 = clock();
- c_forrange (N) { cvec_x_pop_back(&con); }
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = cvec_x_size(con);
- cvec_x_drop(&con);
- }{
- csrandom(seed);
- container con = cvec_x_init();
- c_forrange (N) cvec_x_push_back(&con, crandom() & mask2);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- //cvec_x_iter it, end = cvec_x_end(&con);
- //c_forrange (S) if ((it = cvec_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con.data[i];
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- cvec_x_drop(&con);
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-
-int main(int argc, char* argv[])
-{
- Sample std_s[SAMPLES + 1] = {0}, stc_s[SAMPLES + 1] = {0};
- c_forrange (i, int, SAMPLES) {
- std_s[i] = test_std_vector();
- stc_s[i] = test_stc_vector();
- if (i > 0) c_forrange (j, int, N_TESTS) {
- if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
- if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
- if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
- }
- }
- const char* comp = argc > 1 ? argv[1] : "test";
- bool header = (argc > 2 && argv[2][0] == '1');
- float std_sum = 0, stc_sum = 0;
- c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
- if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
-}
+#include <stdio.h>
+#include <time.h>
+#define i_static
+#include <stc/crandom.h>
+
+#ifdef __cplusplus
+#include <vector>
+#include <algorithm>
+#endif
+
+enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
+const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
+typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
+typedef struct { const char* name; Range test[N_TESTS]; } Sample;
+enum {SAMPLES = 2, N = 150000000, S = 0x3ffc, R = 4};
+uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
+
+static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
+
+#define i_val size_t
+#define i_tag x
+#include <stc/cvec.h>
+
+#ifdef __cplusplus
+Sample test_std_vector() {
+ typedef std::vector<size_t> container;
+ Sample s = {"std,vector"};
+ {
+ s.test[INSERT].t1 = clock();
+ container con;
+ csrandom(seed);
+ c_forrange (N) con.push_back(crandom() & mask1);
+ s.test[INSERT].t2 = clock();
+ s.test[INSERT].sum = con.size();
+ s.test[ERASE].t1 = clock();
+ c_forrange (N) con.pop_back();
+ s.test[ERASE].t2 = clock();
+ s.test[ERASE].sum = con.size();
+ }{
+ container con;
+ csrandom(seed);
+ c_forrange (N) con.push_back(crandom() & mask2);
+ s.test[FIND].t1 = clock();
+ size_t sum = 0;
+ container::iterator it;
+ // Iteration - not inherent find - skipping
+ //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it;
+ s.test[FIND].t2 = clock();
+ s.test[FIND].sum = sum;
+ s.test[ITER].t1 = clock();
+ sum = 0;
+ c_forrange (R) c_forrange (i, N) sum += con[i];
+ s.test[ITER].t2 = clock();
+ s.test[ITER].sum = sum;
+ s.test[DESTRUCT].t1 = clock();
+ }
+ s.test[DESTRUCT].t2 = clock();
+ s.test[DESTRUCT].sum = 0;
+ return s;
+}
+#else
+Sample test_std_vector() { Sample s = {"std-vector"}; return s;}
+#endif
+
+
+
+Sample test_stc_vector() {
+ typedef cvec_x container;
+ Sample s = {"STC,vector"};
+ {
+ s.test[INSERT].t1 = clock();
+ container con = cvec_x_init();
+ csrandom(seed);
+ c_forrange (N) cvec_x_push_back(&con, crandom() & mask1);
+ s.test[INSERT].t2 = clock();
+ s.test[INSERT].sum = cvec_x_size(con);
+ s.test[ERASE].t1 = clock();
+ c_forrange (N) { cvec_x_pop_back(&con); }
+ s.test[ERASE].t2 = clock();
+ s.test[ERASE].sum = cvec_x_size(con);
+ cvec_x_drop(&con);
+ }{
+ csrandom(seed);
+ container con = cvec_x_init();
+ c_forrange (N) cvec_x_push_back(&con, crandom() & mask2);
+ s.test[FIND].t1 = clock();
+ size_t sum = 0;
+ //cvec_x_iter it, end = cvec_x_end(&con);
+ //c_forrange (S) if ((it = cvec_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref;
+ s.test[FIND].t2 = clock();
+ s.test[FIND].sum = sum;
+ s.test[ITER].t1 = clock();
+ sum = 0;
+ c_forrange (R) c_forrange (i, N) sum += con.data[i];
+ s.test[ITER].t2 = clock();
+ s.test[ITER].sum = sum;
+ s.test[DESTRUCT].t1 = clock();
+ cvec_x_drop(&con);
+ }
+ s.test[DESTRUCT].t2 = clock();
+ s.test[DESTRUCT].sum = 0;
+ return s;
+}
+
+int main(int argc, char* argv[])
+{
+ Sample std_s[SAMPLES + 1] = {0}, stc_s[SAMPLES + 1] = {0};
+ c_forrange (i, int, SAMPLES) {
+ std_s[i] = test_std_vector();
+ stc_s[i] = test_stc_vector();
+ if (i > 0) c_forrange (j, int, N_TESTS) {
+ if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
+ if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
+ if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
+ }
+ }
+ const char* comp = argc > 1 ? argv[1] : "test";
+ bool header = (argc > 2 && argv[2][0] == '1');
+ float std_sum = 0, stc_sum = 0;
+ c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
+ if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
+ c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
+ printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
+ c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
+ printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
+}
diff --git a/docs/cset_api.md b/docs/cset_api.md
index 2d20c303..b325eaca 100644
--- a/docs/cset_api.md
+++ b/docs/cset_api.md
@@ -1,123 +1,123 @@
-# STC [cset](../include/stc/cset.h): Unordered Set
-![Set](pics/set.jpg)
-
-A **cset** is an associative container that contains a set of unique objects of type i_key. Search, insertion, and removal have average constant-time complexity. See the c++ class
-[std::unordered_set](https://en.cppreference.com/w/cpp/container/unordered_set) for a functional description.
-
-## Header file and declaration
-
-```c
-#define i_key // hash key: REQUIRED.
-#define i_hash // hash func: REQUIRED IF i_keyraw is a non-pod type.
-#define i_eq // equality comparison two i_keyraw*: !i_cmp will be used if not defined.
-#define i_keydrop // destroy key func - defaults to empty destruct
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy
-#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
-#define i_tag // typename tag. defaults to i_key
-#define i_type // full typename of the container
-#include <stc/cset.h>
-```
-`X` should be replaced by the value of `i_tag` in all of the following documentation.
-
-## Methods
-
-```c
-cset_X cset_X_init(void);
-cset_X cset_X_with_capacity(size_t cap);
-cset_X cset_X_clone(cset_x set);
-
-void cset_X_clear(cset_X* self);
-void cset_X_copy(cset_X* self, cset_X other);
-void cset_X_max_load_factor(cset_X* self, float max_load); // default: 0.85
-bool cset_X_reserve(cset_X* self, size_t size);
-void cset_X_shrink_to_fit(cset_X* self);
-void cset_X_swap(cset_X* a, cset_X* b);
-void cset_X_drop(cset_X* self); // destructor
-
-size_t cset_X_size(cset_X set); // num. of allocated buckets
-size_t cset_X_capacity(cset_X set); // buckets * max_load_factor
-bool cset_X_empty(cset_X set);
-size_t cset_X_bucket_count(cset_X set);
-
-bool cset_X_contains(const cset_X* self, i_keyraw rkey);
-const cset_X_value* cset_X_get(const cset_X* self, i_keyraw rkey); // return NULL if not found
-cset_X_value* cset_X_get_mut(cset_X* self, i_keyraw rkey); // mutable get
-cset_X_iter cset_X_find(const cset_X* self, i_keyraw rkey);
-
-cset_X_result cset_X_insert(cset_X* self, i_key key);
-cset_X_result cset_X_push(cset_X* self, i_key key); // alias for insert.
-cset_X_result cset_X_emplace(cset_X* self, i_keyraw rkey);
-
-size_t cset_X_erase(cset_X* self, i_keyraw rkey); // return 0 or 1
-cset_X_iter cset_X_erase_at(cset_X* self, cset_X_iter it); // return iter after it
-void cset_X_erase_entry(cset_X* self, cset_X_value* entry);
-
-cset_X_iter cset_X_begin(const cset_X* self);
-cset_X_iter cset_X_end(const cset_X* self);
-void cset_X_next(cset_X_iter* it);
-
-cset_X_value cset_X_value_clone(cset_X_value val);
-```
-
-## Types
-
-| Type name | Type definition | Used to represent... |
-|:-------------------|:-------------------------------------------------|:----------------------------|
-| `cset_X` | `struct { ... }` | The cset type |
-| `cset_X_rawkey` | `i_keyraw` | The raw key type |
-| `cset_X_raw` | `i_keyraw` | The raw value type |
-| `cset_X_key` | `i_key` | The key type |
-| `cset_X_value` | `i_key` | The value |
-| `cset_X_result` | `struct { cset_X_value* ref; bool inserted; }` | Result of insert/emplace |
-| `cset_X_iter` | `struct { cset_X_value *ref; ... }` | Iterator type |
-
-## Example
-```c
-#include <stc/cstr.h>
-
-#define i_key_str
-#include <stc/cset.h>
-
-int main ()
-{
- c_auto (cset_str, fifth)
- {
- c_auto (cset_str, first, second)
- c_auto (cset_str, third, fourth)
- {
- c_apply(v, cset_str_emplace(&second, *v), const char*,
- {"red", "green", "blue"});
- c_apply(v, cset_str_emplace(&third, *v), const char*,
- {"orange", "pink", "yellow"});
-
- cset_str_emplace(&fourth, "potatoes");
- cset_str_emplace(&fourth, "milk");
- cset_str_emplace(&fourth, "flour");
-
- fifth = cset_str_clone(second);
- c_foreach (i, cset_str, third)
- cset_str_emplace(&fifth, cstr_str(i.ref));
- c_foreach (i, cset_str, fourth)
- cset_str_emplace(&fifth, cstr_str(i.ref));
- }
- printf("fifth contains:\n\n");
- c_foreach (i, cset_str, fifth)
- printf("%s\n", cstr_str(i.ref));
- }
-}
-```
-Output:
-```
-fifth contains:
-
-red
-green
-flour
-orange
-blue
-pink
-yellow
-milk
-potatoes
-```
+# STC [cset](../include/stc/cset.h): Unordered Set
+![Set](pics/set.jpg)
+
+A **cset** is an associative container that contains a set of unique objects of type i_key. Search, insertion, and removal have average constant-time complexity. See the c++ class
+[std::unordered_set](https://en.cppreference.com/w/cpp/container/unordered_set) for a functional description.
+
+## Header file and declaration
+
+```c
+#define i_key // hash key: REQUIRED.
+#define i_hash // hash func: REQUIRED IF i_keyraw is a non-pod type.
+#define i_eq // equality comparison two i_keyraw*: !i_cmp will be used if not defined.
+#define i_keydrop // destroy key func - defaults to empty destruct
+#define i_keyraw // convertion "raw" type - defaults to i_key
+#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy
+#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
+#define i_tag // typename tag. defaults to i_key
+#define i_type // full typename of the container
+#include <stc/cset.h>
+```
+`X` should be replaced by the value of `i_tag` in all of the following documentation.
+
+## Methods
+
+```c
+cset_X cset_X_init(void);
+cset_X cset_X_with_capacity(size_t cap);
+cset_X cset_X_clone(cset_x set);
+
+void cset_X_clear(cset_X* self);
+void cset_X_copy(cset_X* self, cset_X other);
+void cset_X_max_load_factor(cset_X* self, float max_load); // default: 0.85
+bool cset_X_reserve(cset_X* self, size_t size);
+void cset_X_shrink_to_fit(cset_X* self);
+void cset_X_swap(cset_X* a, cset_X* b);
+void cset_X_drop(cset_X* self); // destructor
+
+size_t cset_X_size(cset_X set); // num. of allocated buckets
+size_t cset_X_capacity(cset_X set); // buckets * max_load_factor
+bool cset_X_empty(cset_X set);
+size_t cset_X_bucket_count(cset_X set);
+
+bool cset_X_contains(const cset_X* self, i_keyraw rkey);
+const cset_X_value* cset_X_get(const cset_X* self, i_keyraw rkey); // return NULL if not found
+cset_X_value* cset_X_get_mut(cset_X* self, i_keyraw rkey); // mutable get
+cset_X_iter cset_X_find(const cset_X* self, i_keyraw rkey);
+
+cset_X_result cset_X_insert(cset_X* self, i_key key);
+cset_X_result cset_X_push(cset_X* self, i_key key); // alias for insert.
+cset_X_result cset_X_emplace(cset_X* self, i_keyraw rkey);
+
+size_t cset_X_erase(cset_X* self, i_keyraw rkey); // return 0 or 1
+cset_X_iter cset_X_erase_at(cset_X* self, cset_X_iter it); // return iter after it
+void cset_X_erase_entry(cset_X* self, cset_X_value* entry);
+
+cset_X_iter cset_X_begin(const cset_X* self);
+cset_X_iter cset_X_end(const cset_X* self);
+void cset_X_next(cset_X_iter* it);
+
+cset_X_value cset_X_value_clone(cset_X_value val);
+```
+
+## Types
+
+| Type name | Type definition | Used to represent... |
+|:-------------------|:-------------------------------------------------|:----------------------------|
+| `cset_X` | `struct { ... }` | The cset type |
+| `cset_X_rawkey` | `i_keyraw` | The raw key type |
+| `cset_X_raw` | `i_keyraw` | The raw value type |
+| `cset_X_key` | `i_key` | The key type |
+| `cset_X_value` | `i_key` | The value |
+| `cset_X_result` | `struct { cset_X_value* ref; bool inserted; }` | Result of insert/emplace |
+| `cset_X_iter` | `struct { cset_X_value *ref; ... }` | Iterator type |
+
+## Example
+```c
+#include <stc/cstr.h>
+
+#define i_key_str
+#include <stc/cset.h>
+
+int main ()
+{
+ c_auto (cset_str, fifth)
+ {
+ c_auto (cset_str, first, second)
+ c_auto (cset_str, third, fourth)
+ {
+ c_apply(v, cset_str_emplace(&second, *v), const char*,
+ {"red", "green", "blue"});
+ c_apply(v, cset_str_emplace(&third, *v), const char*,
+ {"orange", "pink", "yellow"});
+
+ cset_str_emplace(&fourth, "potatoes");
+ cset_str_emplace(&fourth, "milk");
+ cset_str_emplace(&fourth, "flour");
+
+ fifth = cset_str_clone(second);
+ c_foreach (i, cset_str, third)
+ cset_str_emplace(&fifth, cstr_str(i.ref));
+ c_foreach (i, cset_str, fourth)
+ cset_str_emplace(&fifth, cstr_str(i.ref));
+ }
+ printf("fifth contains:\n\n");
+ c_foreach (i, cset_str, fifth)
+ printf("%s\n", cstr_str(i.ref));
+ }
+}
+```
+Output:
+```
+fifth contains:
+
+red
+green
+flour
+orange
+blue
+pink
+yellow
+milk
+potatoes
+```
diff --git a/docs/csset_api.md b/docs/csset_api.md
index 83b7e11b..e7a7b044 100644
--- a/docs/csset_api.md
+++ b/docs/csset_api.md
@@ -1,123 +1,123 @@
-# STC [csset](../include/stc/csset.h): Sorted Set
-![Set](pics/sset.jpg)
-
-A **csset** is an associative container that contains a sorted set of unique objects of type *i_key*. Sorting is done using the key comparison function *keyCompare*. Search, removal, and insertion operations have logarithmic complexity. **csset** is implemented as an AA-tree.
-
-See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) for a functional description.
-
-## Header file and declaration
-
-```c
-#define i_key // key: REQUIRED
-#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
-#define i_keydrop // destroy key func - defaults to empty destruct
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy
-#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
-#define i_tag // typename tag. defaults to i_key
-#define i_type // full typename of the container
-#include <stc/csset.h>
-```
-`X` should be replaced by the value of `i_tag` in all of the following documentation.
-
-## Methods
-
-```c
-csset_X csset_X_init(void);
-csset_X csset_X_with_capacity(size_t cap);
-bool csset_X_reserve(csset_X* self, size_t cap);
-void csset_X_shrink_to_fit(csset_X* self);
-csset_X csset_X_clone(csset_x set);
-
-void csset_X_clear(csset_X* self);
-void csset_X_copy(csset_X* self, csset_X other);
-void csset_X_swap(csset_X* a, csset_X* b);
-void csset_X_drop(csset_X* self); // destructor
-
-size_t csset_X_size(csset_X set);
-bool csset_X_empty(csset_X set);
-
-const csset_X_value* csset_X_get(const csset_X* self, i_keyraw rkey); // const get
-csset_X_value* csset_X_get_mut(csset_X* self, i_keyraw rkey); // return NULL if not found
-bool csset_X_contains(const csset_X* self, i_keyraw rkey);
-csset_X_iter csset_X_find(const csset_X* self, i_keyraw rkey);
-csset_X_value* csset_X_find_it(const csset_X* self, i_keyraw rkey, csset_X_iter* out); // return NULL if not found
-csset_X_iter csset_X_lower_bound(const csset_X* self, i_keyraw rkey); // find closest entry >= rkey
-
-csset_X_result csset_X_insert(csset_X* self, i_key key);
-csset_X_result csset_X_push(csset_X* self, i_key key); // alias for insert()
-csset_X_result csset_X_emplace(csset_X* self, i_keyraw rkey);
-
-size_t csset_X_erase(csset_X* self, i_keyraw rkey);
-csset_X_iter csset_X_erase_at(csset_X* self, csset_X_iter it); // return iter after it
-csset_X_iter csset_X_erase_range(csset_X* self, csset_X_iter it1, csset_X_iter it2); // return updated it2
-
-csset_X_iter csset_X_begin(const csset_X* self);
-csset_X_iter csset_X_end(const csset_X* self);
-void csset_X_next(csset_X_iter* it);
-
-csset_X_value csset_X_value_clone(csset_X_value val);
-```
-
-## Types
-
-| Type name | Type definition | Used to represent... |
-|:-------------------|:--------------------------------------------------|:----------------------------|
-| `csset_X` | `struct { ... }` | The csset type |
-| `csset_X_rawkey` | `i_keyraw` | The raw key type |
-| `csset_X_raw` | `i_keyraw` | The raw key type |
-| `csset_X_key` | `i_key` | The key type |
-| `csset_X_value` | `i_key ` | The value: key is immutable |
-| `csset_X_result` | `struct { csset_X_value* ref; bool inserted; }` | Result of insert/emplace |
-| `csset_X_iter` | `struct { csset_X_value *ref; ... }` | Iterator type |
-
-## Example
-```c
-#define i_implement
-#include <stc/cstr.h>
-
-#define i_key_str
-#include <stc/csset.h>
-
-int main ()
-{
-c_auto (csset_str, fifth)
- {
- c_auto (csset_str, first, second)
- c_auto (csset_str, third, fourth)
- {
- c_apply(v, csset_str_emplace(&second, *v), const char*,
- {"red", "green", "blue"});
- c_apply(v, csset_str_emplace(&third, *v), const char*,
- {"orange", "pink", "yellow"});
-
- csset_str_emplace(&fourth, "potatoes");
- csset_str_emplace(&fourth, "milk");
- csset_str_emplace(&fourth, "flour");
-
- fifth = csset_str_clone(second);
- c_foreach (i, csset_str, third)
- csset_str_emplace(&fifth, cstr_str(i.ref));
- c_foreach (i, csset_str, fourth)
- csset_str_emplace(&fifth, cstr_str(i.ref));
- }
- printf("fifth contains:\n\n");
- c_foreach (i, csset_str, fifth)
- printf("%s\n", cstr_str(i.ref));
- }
-}
-```
-Output:
-```
-fifth contains:
-
-blue
-flour
-green
-milk
-orange
-pink
-potatoes
-red
-yellow
-```
+# STC [csset](../include/stc/csset.h): Sorted Set
+![Set](pics/sset.jpg)
+
+A **csset** is an associative container that contains a sorted set of unique objects of type *i_key*. Sorting is done using the key comparison function *keyCompare*. Search, removal, and insertion operations have logarithmic complexity. **csset** is implemented as an AA-tree.
+
+See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) for a functional description.
+
+## Header file and declaration
+
+```c
+#define i_key // key: REQUIRED
+#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
+#define i_keydrop // destroy key func - defaults to empty destruct
+#define i_keyraw // convertion "raw" type - defaults to i_key
+#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy
+#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
+#define i_tag // typename tag. defaults to i_key
+#define i_type // full typename of the container
+#include <stc/csset.h>
+```
+`X` should be replaced by the value of `i_tag` in all of the following documentation.
+
+## Methods
+
+```c
+csset_X csset_X_init(void);
+csset_X csset_X_with_capacity(size_t cap);
+bool csset_X_reserve(csset_X* self, size_t cap);
+void csset_X_shrink_to_fit(csset_X* self);
+csset_X csset_X_clone(csset_x set);
+
+void csset_X_clear(csset_X* self);
+void csset_X_copy(csset_X* self, csset_X other);
+void csset_X_swap(csset_X* a, csset_X* b);
+void csset_X_drop(csset_X* self); // destructor
+
+size_t csset_X_size(csset_X set);
+bool csset_X_empty(csset_X set);
+
+const csset_X_value* csset_X_get(const csset_X* self, i_keyraw rkey); // const get
+csset_X_value* csset_X_get_mut(csset_X* self, i_keyraw rkey); // return NULL if not found
+bool csset_X_contains(const csset_X* self, i_keyraw rkey);
+csset_X_iter csset_X_find(const csset_X* self, i_keyraw rkey);
+csset_X_value* csset_X_find_it(const csset_X* self, i_keyraw rkey, csset_X_iter* out); // return NULL if not found
+csset_X_iter csset_X_lower_bound(const csset_X* self, i_keyraw rkey); // find closest entry >= rkey
+
+csset_X_result csset_X_insert(csset_X* self, i_key key);
+csset_X_result csset_X_push(csset_X* self, i_key key); // alias for insert()
+csset_X_result csset_X_emplace(csset_X* self, i_keyraw rkey);
+
+size_t csset_X_erase(csset_X* self, i_keyraw rkey);
+csset_X_iter csset_X_erase_at(csset_X* self, csset_X_iter it); // return iter after it
+csset_X_iter csset_X_erase_range(csset_X* self, csset_X_iter it1, csset_X_iter it2); // return updated it2
+
+csset_X_iter csset_X_begin(const csset_X* self);
+csset_X_iter csset_X_end(const csset_X* self);
+void csset_X_next(csset_X_iter* it);
+
+csset_X_value csset_X_value_clone(csset_X_value val);
+```
+
+## Types
+
+| Type name | Type definition | Used to represent... |
+|:-------------------|:--------------------------------------------------|:----------------------------|
+| `csset_X` | `struct { ... }` | The csset type |
+| `csset_X_rawkey` | `i_keyraw` | The raw key type |
+| `csset_X_raw` | `i_keyraw` | The raw key type |
+| `csset_X_key` | `i_key` | The key type |
+| `csset_X_value` | `i_key ` | The value: key is immutable |
+| `csset_X_result` | `struct { csset_X_value* ref; bool inserted; }` | Result of insert/emplace |
+| `csset_X_iter` | `struct { csset_X_value *ref; ... }` | Iterator type |
+
+## Example
+```c
+#define i_implement
+#include <stc/cstr.h>
+
+#define i_key_str
+#include <stc/csset.h>
+
+int main ()
+{
+c_auto (csset_str, fifth)
+ {
+ c_auto (csset_str, first, second)
+ c_auto (csset_str, third, fourth)
+ {
+ c_apply(v, csset_str_emplace(&second, *v), const char*,
+ {"red", "green", "blue"});
+ c_apply(v, csset_str_emplace(&third, *v), const char*,
+ {"orange", "pink", "yellow"});
+
+ csset_str_emplace(&fourth, "potatoes");
+ csset_str_emplace(&fourth, "milk");
+ csset_str_emplace(&fourth, "flour");
+
+ fifth = csset_str_clone(second);
+ c_foreach (i, csset_str, third)
+ csset_str_emplace(&fifth, cstr_str(i.ref));
+ c_foreach (i, csset_str, fourth)
+ csset_str_emplace(&fifth, cstr_str(i.ref));
+ }
+ printf("fifth contains:\n\n");
+ c_foreach (i, csset_str, fifth)
+ printf("%s\n", cstr_str(i.ref));
+ }
+}
+```
+Output:
+```
+fifth contains:
+
+blue
+flour
+green
+milk
+orange
+pink
+potatoes
+red
+yellow
+```
diff --git a/examples/README.md b/examples/README.md
index ad7726d4..4c0aa763 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -1,4 +1,4 @@
-Examples
-========
-This folder contains various examples of STC container usage.
-
+Examples
+========
+This folder contains various examples of STC container usage.
+
diff --git a/examples/arc_containers.c b/examples/arc_containers.c
index 1fe227f7..969825eb 100644
--- a/examples/arc_containers.c
+++ b/examples/arc_containers.c
@@ -1,77 +1,77 @@
-// Create a stack and a list of shared pointers to maps,
-// and demonstrate sharing and cloning of maps.
-#define i_static
-#include <stc/cstr.h>
-#define i_type Map
-#define i_key_str // strings
-#define i_val int
-#define i_keydrop(p) (printf("drop name: %s\n", cstr_str(p)), cstr_drop(p))
-#include <stc/csmap.h>
-
-#define i_type Arc // (atomic) ref. counted type
-#define i_val Map
-#define i_valdrop(p) (printf("drop Arc:\n"), Map_drop(p))
-// no need for atomic ref. count in single thread:
-// no compare function available for csmap:
-#define i_opt c_no_atomic|c_no_cmp
-#include <stc/carc.h>
-
-#define i_type Stack
-#define i_val_arcbox Arc // define i_val_bind for carc/cbox value (not i_val)
-#include <stc/cstack.h>
-
-#define i_type List
-#define i_val_arcbox Arc // as above
-#include <stc/clist.h>
-
-int main()
-{
- c_auto (Stack, stack)
- c_auto (List, list)
- {
- // POPULATE stack with shared pointers to Maps:
- Map *map;
- map = Stack_push(&stack, Arc_make(Map_init()))->get;
- c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, {
- {"Joey", 1990}, {"Mary", 1995}, {"Joanna", 1992}
- });
- map = Stack_push(&stack, Arc_make(Map_init()))->get;
- c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, {
- {"Rosanna", 2001}, {"Brad", 1999}, {"Jack", 1980}
- });
-
- // POPULATE list:
- map = List_push_back(&list, Arc_make(Map_init()))->get;
- c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, {
- {"Steve", 1979}, {"Rick", 1974}, {"Tracy", 2003}
- });
-
- // Share two Maps from the stack with the list using emplace (clone the carc):
- List_push_back(&list, Arc_clone(stack.data[0]));
- List_push_back(&list, Arc_clone(stack.data[1]));
-
- // Clone (deep copy) a Map from the stack to the list
- // List will contain two shared and two unshared maps.
- map = List_push_back(&list, Arc_make(Map_clone(*stack.data[1].get)))->get;
-
- // Add one more element to the cloned map:
- Map_emplace_or_assign(map, "CLONED", 2021);
-
- // Add one more element to the shared map:
- Map_emplace_or_assign(stack.data[1].get, "SHARED", 2021);
-
-
- puts("STACKS");
- c_foreach (i, Stack, stack) {
- c_forpair (name, year, Map, *i.ref->get)
- printf(" %s:%d", cstr_str(_.name), *_.year);
- puts("");
- }
- puts("LIST");
- c_foreach (i, List, list) {
- c_forpair (name, year, Map, *i.ref->get)
- printf(" %s:%d", cstr_str(_.name), *_.year);
- puts("");
- }
- }
-}
+// Create a stack and a list of shared pointers to maps,
+// and demonstrate sharing and cloning of maps.
+#define i_static
+#include <stc/cstr.h>
+#define i_type Map
+#define i_key_str // strings
+#define i_val int
+#define i_keydrop(p) (printf("drop name: %s\n", cstr_str(p)), cstr_drop(p))
+#include <stc/csmap.h>
+
+#define i_type Arc // (atomic) ref. counted type
+#define i_val Map
+#define i_valdrop(p) (printf("drop Arc:\n"), Map_drop(p))
+// no need for atomic ref. count in single thread:
+// no compare function available for csmap:
+#define i_opt c_no_atomic|c_no_cmp
+#include <stc/carc.h>
+
+#define i_type Stack
+#define i_val_arcbox Arc // define i_val_bind for carc/cbox value (not i_val)
+#include <stc/cstack.h>
+
+#define i_type List
+#define i_val_arcbox Arc // as above
+#include <stc/clist.h>
+
+int main()
+{
+ c_auto (Stack, stack)
+ c_auto (List, list)
+ {
+ // POPULATE stack with shared pointers to Maps:
+ Map *map;
+ map = Stack_push(&stack, Arc_make(Map_init()))->get;
+ c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, {
+ {"Joey", 1990}, {"Mary", 1995}, {"Joanna", 1992}
+ });
+ map = Stack_push(&stack, Arc_make(Map_init()))->get;
+ c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, {
+ {"Rosanna", 2001}, {"Brad", 1999}, {"Jack", 1980}
+ });
+
+ // POPULATE list:
+ map = List_push_back(&list, Arc_make(Map_init()))->get;
+ c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, {
+ {"Steve", 1979}, {"Rick", 1974}, {"Tracy", 2003}
+ });
+
+ // Share two Maps from the stack with the list using emplace (clone the carc):
+ List_push_back(&list, Arc_clone(stack.data[0]));
+ List_push_back(&list, Arc_clone(stack.data[1]));
+
+ // Clone (deep copy) a Map from the stack to the list
+ // List will contain two shared and two unshared maps.
+ map = List_push_back(&list, Arc_make(Map_clone(*stack.data[1].get)))->get;
+
+ // Add one more element to the cloned map:
+ Map_emplace_or_assign(map, "CLONED", 2021);
+
+ // Add one more element to the shared map:
+ Map_emplace_or_assign(stack.data[1].get, "SHARED", 2021);
+
+
+ puts("STACKS");
+ c_foreach (i, Stack, stack) {
+ c_forpair (name, year, Map, *i.ref->get)
+ printf(" %s:%d", cstr_str(_.name), *_.year);
+ puts("");
+ }
+ puts("LIST");
+ c_foreach (i, List, list) {
+ c_forpair (name, year, Map, *i.ref->get)
+ printf(" %s:%d", cstr_str(_.name), *_.year);
+ puts("");
+ }
+ }
+}
diff --git a/examples/arc_demo.c b/examples/arc_demo.c
index daeb5a68..85e3886f 100644
--- a/examples/arc_demo.c
+++ b/examples/arc_demo.c
@@ -1,56 +1,56 @@
-#include <stdio.h>
-#include <string.h>
-
-void int_drop(int* x) {
- printf("drop: %d\n", *x);
-}
-
-// carc implements its own clone method using reference counting,
-// so 'i_valclone' is not required to be defined (ignored).
-
-#define i_type Arc // set type name to be defined (instead of 'carc_int')
-#define i_val int
-#define i_valdrop int_drop // optional, just to display the elements destroyed
-#include <stc/carc.h> // Arc
-
-#define i_key_arcbox Arc // note: use i_key_bind instead of i_key for carc/cbox elements
-#include <stc/csset.h> // csset_Arc (like: std::set<std::shared_ptr<int>>)
-
-#define i_val_arcbox Arc // note: as above.
-#include <stc/cvec.h> // cvec_Arc (like: std::vector<std::shared_ptr<int>>)
-
-int main()
-{
- c_auto (cvec_Arc, vec) // declare and init vec, call cvec_Arc_drop() at scope exit
- c_auto (csset_Arc, set) // declare and init set, call csset_Arc_drop() at scope exit
- {
- const int years[] = {2021, 2012, 2022, 2015};
- c_forrange (i, c_arraylen(years))
- cvec_Arc_push_back(&vec, Arc_make(years[i]));
-
- printf("vec:");
- c_foreach (i, cvec_Arc, vec) printf(" %d", *i.ref->get);
- puts("");
-
- // add odd numbers from vec to set
- c_foreach (i, cvec_Arc, vec)
- if (*i.ref->get & 1)
- csset_Arc_insert(&set, Arc_clone(*i.ref)); // copy shared pointer => increments counter.
-
- // erase the two last elements in vec
- cvec_Arc_pop_back(&vec);
- cvec_Arc_pop_back(&vec);
-
- printf("vec:");
- c_foreach (i, cvec_Arc, vec) printf(" %d", *i.ref->get);
-
- printf("\nset:");
- c_foreach (i, csset_Arc, set) printf(" %d", *i.ref->get);
-
- c_autovar (Arc p = Arc_clone(vec.data[0]), Arc_drop(&p)) {
- printf("\n%d is now owned by %ld objects\n", *p.get, *p.use_count);
- }
-
- puts("\nDone");
- }
-}
+#include <stdio.h>
+#include <string.h>
+
+void int_drop(int* x) {
+ printf("drop: %d\n", *x);
+}
+
+// carc implements its own clone method using reference counting,
+// so 'i_valclone' is not required to be defined (ignored).
+
+#define i_type Arc // set type name to be defined (instead of 'carc_int')
+#define i_val int
+#define i_valdrop int_drop // optional, just to display the elements destroyed
+#include <stc/carc.h> // Arc
+
+#define i_key_arcbox Arc // note: use i_key_bind instead of i_key for carc/cbox elements
+#include <stc/csset.h> // csset_Arc (like: std::set<std::shared_ptr<int>>)
+
+#define i_val_arcbox Arc // note: as above.
+#include <stc/cvec.h> // cvec_Arc (like: std::vector<std::shared_ptr<int>>)
+
+int main()
+{
+ c_auto (cvec_Arc, vec) // declare and init vec, call cvec_Arc_drop() at scope exit
+ c_auto (csset_Arc, set) // declare and init set, call csset_Arc_drop() at scope exit
+ {
+ const int years[] = {2021, 2012, 2022, 2015};
+ c_forrange (i, c_arraylen(years))
+ cvec_Arc_push_back(&vec, Arc_make(years[i]));
+
+ printf("vec:");
+ c_foreach (i, cvec_Arc, vec) printf(" %d", *i.ref->get);
+ puts("");
+
+ // add odd numbers from vec to set
+ c_foreach (i, cvec_Arc, vec)
+ if (*i.ref->get & 1)
+ csset_Arc_insert(&set, Arc_clone(*i.ref)); // copy shared pointer => increments counter.
+
+ // erase the two last elements in vec
+ cvec_Arc_pop_back(&vec);
+ cvec_Arc_pop_back(&vec);
+
+ printf("vec:");
+ c_foreach (i, cvec_Arc, vec) printf(" %d", *i.ref->get);
+
+ printf("\nset:");
+ c_foreach (i, csset_Arc, set) printf(" %d", *i.ref->get);
+
+ c_autovar (Arc p = Arc_clone(vec.data[0]), Arc_drop(&p)) {
+ printf("\n%d is now owned by %ld objects\n", *p.get, *p.use_count);
+ }
+
+ puts("\nDone");
+ }
+}
diff --git a/examples/arcvec_erase.c b/examples/arcvec_erase.c
index e4497486..eba77f51 100644
--- a/examples/arcvec_erase.c
+++ b/examples/arcvec_erase.c
@@ -1,53 +1,53 @@
-#include <stdio.h>
-
-void show_drop(int* x) { printf("drop: %d\n", *x); }
-
-#define i_type Arc
-#define i_val int
-#define i_valdrop show_drop
-// carc/cbox will use pointer address comparison of i_val
-// if 'i_opt c_no_cmp' is defined, otherwise i_cmp is used
-// to compare object values. See the two differences by
-// commenting out the next line.
-#include <stc/carc.h> // Shared pointer to int
-
-#define i_type Vec
-#define i_val_arcbox Arc
-#include <stc/cvec.h> // Vec: cvec<Arc>
-
-
-int main()
-{
- c_auto (Vec, vec)
- {
- const int v[] = {2012, 1990, 2012, 2019, 2015};
- c_forrange (i, c_arraylen(v))
- Vec_push_back(&vec, Arc_make(v[i]));
-
- // clone the second 2012 and push it back.
- // note: cloning make sure that vec.data[2] has ref count 2.
- Vec_push_back(&vec, Arc_clone(vec.data[2]));
-
- printf("vec before erase :");
- c_foreach (i, Vec, vec)
- printf(" %d", *i.ref->get);
- puts("");
-
- printf("erase vec.data[2]; or first matching value depending on compare.\n");
- Vec_iter it;
- it = Vec_find(&vec, *vec.data[2].get);
- if (it.ref != Vec_end(&vec).ref)
- Vec_erase_at(&vec, it);
-
- int year = 2015;
- it = Vec_find(&vec, year); // Ok as tmp only.
- if (it.ref != Vec_end(&vec).ref)
- Vec_erase_at(&vec, it);
-
- printf("vec after erase :");
- c_foreach (i, Vec, vec)
- printf(" %d", *i.ref->get);
-
- puts("\nDone");
- }
-}
+#include <stdio.h>
+
+void show_drop(int* x) { printf("drop: %d\n", *x); }
+
+#define i_type Arc
+#define i_val int
+#define i_valdrop show_drop
+// carc/cbox will use pointer address comparison of i_val
+// if 'i_opt c_no_cmp' is defined, otherwise i_cmp is used
+// to compare object values. See the two differences by
+// commenting out the next line.
+#include <stc/carc.h> // Shared pointer to int
+
+#define i_type Vec
+#define i_val_arcbox Arc
+#include <stc/cvec.h> // Vec: cvec<Arc>
+
+
+int main()
+{
+ c_auto (Vec, vec)
+ {
+ const int v[] = {2012, 1990, 2012, 2019, 2015};
+ c_forrange (i, c_arraylen(v))
+ Vec_push_back(&vec, Arc_make(v[i]));
+
+ // clone the second 2012 and push it back.
+ // note: cloning make sure that vec.data[2] has ref count 2.
+ Vec_push_back(&vec, Arc_clone(vec.data[2]));
+
+ printf("vec before erase :");
+ c_foreach (i, Vec, vec)
+ printf(" %d", *i.ref->get);
+ puts("");
+
+ printf("erase vec.data[2]; or first matching value depending on compare.\n");
+ Vec_iter it;
+ it = Vec_find(&vec, *vec.data[2].get);
+ if (it.ref != Vec_end(&vec).ref)
+ Vec_erase_at(&vec, it);
+
+ int year = 2015;
+ it = Vec_find(&vec, year); // Ok as tmp only.
+ if (it.ref != Vec_end(&vec).ref)
+ Vec_erase_at(&vec, it);
+
+ printf("vec after erase :");
+ c_foreach (i, Vec, vec)
+ printf(" %d", *i.ref->get);
+
+ puts("\nDone");
+ }
+}
diff --git a/examples/astar.c b/examples/astar.c
index 5bcbe7e9..db2d128c 100644
--- a/examples/astar.c
+++ b/examples/astar.c
@@ -1,167 +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
-#define i_implement
-#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_cmp_priority(const point* a, const point* b)
-{
- return c_default_cmp(&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_cmp(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_cmp_priority
-#include <stc/cpque.h>
-
-#define i_val point
-#define i_opt c_no_cmp
-#include <stc/cdeq.h>
-
-#define i_key point
-#define i_val int
-#define i_cmp point_key_cmp
-#define i_tag pcost
-#include <stc/csmap.h>
-
-#define i_key point
-#define i_val point
-#define i_cmp point_key_cmp
-#define i_tag pstep
-#include <stc/csmap.h>
-
-cdeq_point
-astar(cstr* maze, int width)
-{
- cdeq_point path = cdeq_point_init();
-
- c_auto (cpque_point, front)
- c_auto (csmap_pstep, from)
- c_auto (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 (cstr_str(maze)[point_index(&next)] != '#')
- {
- const csmap_pcost_value *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_autovar (cstr maze = cstr_new(
- "#########################################################################\n"
- "# # # # # # #\n"
- "# # ######### # ##### ######### ##### ##### ##### # ! #\n"
- "# # # # # # # # # #\n"
- "######### # ######### ######### ##### # # # ######### #\n"
- "# # # # # # # # # # #\n"
- "# # ############# # # ######### ##### # ######### # #\n"
- "# # # # # # # # # #\n"
- "# ############# ##### ##### # ##### ######### # ##### #\n"
- "# # # # # # # # # #\n"
- "# ##### ##### # ##### # ######### # # # #############\n"
- "# # # # # # # # # # # #\n"
- "############# # # # ######### # ##### # ##### ##### #\n"
- "# # # # # # # # # #\n"
- "# ##### # ######### ##### # ##### ##### ############# #\n"
- "# # # # # # # # # #\n"
- "# # ######### # ##### ######### # # ############# # #\n"
- "# # # # # # # # # # #\n"
- "# ######### # # # ##### ######### ######### # #########\n"
- "# # # # # # # # # #\n"
- "# @ # ##### ##### ##### ######### ##### # ######### # #\n"
- "# # # # # # #\n"
- "#########################################################################\n"), cstr_drop(&maze))
- {
- int width = cstr_find(maze, "\n") + 1;
- c_autovar (cdeq_point path = astar(&maze, width), cdeq_point_drop(&path))
- {
- c_foreach (it, cdeq_point, path) cstr_data(&maze)[point_index(it.ref)] = 'x';
- printf("%s", cstr_str(&maze));
- }
- }
-}
+//
+// -- 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
+#define i_implement
+#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_cmp_priority(const point* a, const point* b)
+{
+ return c_default_cmp(&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_cmp(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_cmp_priority
+#include <stc/cpque.h>
+
+#define i_val point
+#define i_opt c_no_cmp
+#include <stc/cdeq.h>
+
+#define i_key point
+#define i_val int
+#define i_cmp point_key_cmp
+#define i_tag pcost
+#include <stc/csmap.h>
+
+#define i_key point
+#define i_val point
+#define i_cmp point_key_cmp
+#define i_tag pstep
+#include <stc/csmap.h>
+
+cdeq_point
+astar(cstr* maze, int width)
+{
+ cdeq_point path = cdeq_point_init();
+
+ c_auto (cpque_point, front)
+ c_auto (csmap_pstep, from)
+ c_auto (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 (cstr_str(maze)[point_index(&next)] != '#')
+ {
+ const csmap_pcost_value *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_autovar (cstr maze = cstr_new(
+ "#########################################################################\n"
+ "# # # # # # #\n"
+ "# # ######### # ##### ######### ##### ##### ##### # ! #\n"
+ "# # # # # # # # # #\n"
+ "######### # ######### ######### ##### # # # ######### #\n"
+ "# # # # # # # # # # #\n"
+ "# # ############# # # ######### ##### # ######### # #\n"
+ "# # # # # # # # # #\n"
+ "# ############# ##### ##### # ##### ######### # ##### #\n"
+ "# # # # # # # # # #\n"
+ "# ##### ##### # ##### # ######### # # # #############\n"
+ "# # # # # # # # # # # #\n"
+ "############# # # # ######### # ##### # ##### ##### #\n"
+ "# # # # # # # # # #\n"
+ "# ##### # ######### ##### # ##### ##### ############# #\n"
+ "# # # # # # # # # #\n"
+ "# # ######### # ##### ######### # # ############# # #\n"
+ "# # # # # # # # # # #\n"
+ "# ######### # # # ##### ######### ######### # #########\n"
+ "# # # # # # # # # #\n"
+ "# @ # ##### ##### ##### ######### ##### # ######### # #\n"
+ "# # # # # # #\n"
+ "#########################################################################\n"), cstr_drop(&maze))
+ {
+ int width = cstr_find(maze, "\n") + 1;
+ c_autovar (cdeq_point path = astar(&maze, width), cdeq_point_drop(&path))
+ {
+ c_foreach (it, cdeq_point, path) cstr_data(&maze)[point_index(it.ref)] = 'x';
+ printf("%s", cstr_str(&maze));
+ }
+ }
+}
diff --git a/examples/birthday.c b/examples/birthday.c
index 15d85e0c..50cd60dc 100644
--- a/examples/birthday.c
+++ b/examples/birthday.c
@@ -1,66 +1,66 @@
-#include <math.h>
-#include <stdio.h>
-#include <time.h>
-#define i_implement
-#include <stc/crandom.h>
-
-#define i_tag ic
-#define i_key uint64_t
-#define i_val uint8_t
-#include <stc/cmap.h>
-
-static uint64_t seed = 12345;
-
-static void test_repeats(void)
-{
- enum {BITS = 46, BITS_TEST = BITS/2 + 2};
- const static uint64_t N = 1ull << BITS_TEST;
- const static uint64_t mask = (1ull << BITS) - 1;
-
- printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST);
- stc64_t rng = stc64_new(seed);
- c_auto (cmap_ic, m)
- {
- cmap_ic_reserve(&m, N);
- c_forrange (i, N) {
- uint64_t k = stc64_rand(&rng) & mask;
- int v = cmap_ic_insert(&m, k, 0).ref->second += 1;
- if (v > 1) printf("repeated value %" PRIuMAX " (%d) at 2^%d\n", k, v, (int) log2((double) i));
- }
- }
-}
-
-#define i_key uint32_t
-#define i_val uint64_t
-#define i_tag x
-#include <stc/cmap.h>
-
-void test_distribution(void)
-{
- enum {BITS = 26};
- printf("distribution test: 2^%d values\n", BITS);
- stc64_t rng = stc64_new(seed);
- const size_t N = 1ull << BITS ;
-
- c_auto (cmap_x, map) {
- c_forrange (N) {
- uint64_t k = stc64_rand(&rng);
- cmap_x_insert(&map, k & 0xf, 0).ref->second += 1;
- }
-
- uint64_t sum = 0;
- c_foreach (i, cmap_x, map) sum += i.ref->second;
- sum /= map.size;
-
- c_foreach (i, cmap_x, map) {
- printf("%4u: %" PRIuMAX " - %" PRIuMAX ": %11.8f\n", i.ref->first, i.ref->second, sum, (1 - (double) i.ref->second / sum));
- }
- }
-}
-
-int main()
-{
- seed = time(NULL);
- test_distribution();
- test_repeats();
-}
+#include <math.h>
+#include <stdio.h>
+#include <time.h>
+#define i_implement
+#include <stc/crandom.h>
+
+#define i_tag ic
+#define i_key uint64_t
+#define i_val uint8_t
+#include <stc/cmap.h>
+
+static uint64_t seed = 12345;
+
+static void test_repeats(void)
+{
+ enum {BITS = 46, BITS_TEST = BITS/2 + 2};
+ const static uint64_t N = 1ull << BITS_TEST;
+ const static uint64_t mask = (1ull << BITS) - 1;
+
+ printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST);
+ stc64_t rng = stc64_new(seed);
+ c_auto (cmap_ic, m)
+ {
+ cmap_ic_reserve(&m, N);
+ c_forrange (i, N) {
+ uint64_t k = stc64_rand(&rng) & mask;
+ int v = cmap_ic_insert(&m, k, 0).ref->second += 1;
+ if (v > 1) printf("repeated value %" PRIuMAX " (%d) at 2^%d\n", k, v, (int) log2((double) i));
+ }
+ }
+}
+
+#define i_key uint32_t
+#define i_val uint64_t
+#define i_tag x
+#include <stc/cmap.h>
+
+void test_distribution(void)
+{
+ enum {BITS = 26};
+ printf("distribution test: 2^%d values\n", BITS);
+ stc64_t rng = stc64_new(seed);
+ const size_t N = 1ull << BITS ;
+
+ c_auto (cmap_x, map) {
+ c_forrange (N) {
+ uint64_t k = stc64_rand(&rng);
+ cmap_x_insert(&map, k & 0xf, 0).ref->second += 1;
+ }
+
+ uint64_t sum = 0;
+ c_foreach (i, cmap_x, map) sum += i.ref->second;
+ sum /= map.size;
+
+ c_foreach (i, cmap_x, map) {
+ printf("%4u: %" PRIuMAX " - %" PRIuMAX ": %11.8f\n", i.ref->first, i.ref->second, sum, (1 - (double) i.ref->second / sum));
+ }
+ }
+}
+
+int main()
+{
+ seed = time(NULL);
+ test_distribution();
+ test_repeats();
+}
diff --git a/examples/bits.c b/examples/bits.c
index 051beb02..71fe1ee0 100644
--- a/examples/bits.c
+++ b/examples/bits.c
@@ -1,63 +1,63 @@
-#include <stdio.h>
-#define i_implement
-#include <stc/cbits.h>
-
-int main()
-{
- c_autovar (cbits set = cbits_with_size(23, true), cbits_drop(&set)) {
- printf("count %" PRIuMAX ", %" PRIuMAX "\n", cbits_count(&set), cbits_size(&set));
- cbits s1 = cbits_from("1110100110111");
- char buf[256];
- cbits_to_str(&s1, buf, 0, -1);
- printf("buf: %s: %" PRIuMAX "\n", buf, cbits_count(&s1));
- cbits_drop(&s1);
-
- cbits_reset(&set, 9);
- cbits_resize(&set, 43, false);
- c_autobuf (str, char, cbits_size(&set) + 1)
- printf(" str: %s\n", cbits_to_str(&set, str, 0, -1));
-
- printf("%4" PRIuMAX ": ", cbits_size(&set));
- c_forrange (i, cbits_size(&set))
- printf("%d", cbits_test(&set, i));
- puts("");
-
- cbits_set(&set, 28);
- cbits_resize(&set, 77, true);
- cbits_resize(&set, 93, false);
- cbits_resize(&set, 102, true);
- cbits_set_value(&set, 99, false);
- printf("%4" PRIuMAX ": ", cbits_size(&set));
- c_forrange (i, cbits_size(&set))
- printf("%d", cbits_test(&set, i));
-
- puts("\nIterate:");
- printf("%4" PRIuMAX ": ", cbits_size(&set));
- c_forrange (i, cbits_size(&set))
- printf("%d", cbits_test(&set, i));
- puts("");
-
- c_autovar (cbits s2 = cbits_clone(set), cbits_drop(&s2)) {
- cbits_flip_all(&s2);
- cbits_set(&s2, 16);
- cbits_set(&s2, 17);
- cbits_set(&s2, 18);
- printf(" new: ");
- c_forrange (i, cbits_size(&s2))
- printf("%d", cbits_test(&s2, i));
- puts("");
-
- printf(" xor: ");
- cbits_xor(&set, &s2);
- c_forrange (i, cbits_size(&set))
- printf("%d", cbits_test(&set, i));
- puts("");
-
- cbits_set_all(&set, false);
- printf("%4" PRIuMAX ": ", cbits_size(&set));
- c_forrange (i, cbits_size(&set))
- printf("%d", cbits_test(&set, i));
- puts("");
- }
- }
-}
+#include <stdio.h>
+#define i_implement
+#include <stc/cbits.h>
+
+int main()
+{
+ c_autovar (cbits set = cbits_with_size(23, true), cbits_drop(&set)) {
+ printf("count %" PRIuMAX ", %" PRIuMAX "\n", cbits_count(&set), cbits_size(&set));
+ cbits s1 = cbits_from("1110100110111");
+ char buf[256];
+ cbits_to_str(&s1, buf, 0, -1);
+ printf("buf: %s: %" PRIuMAX "\n", buf, cbits_count(&s1));
+ cbits_drop(&s1);
+
+ cbits_reset(&set, 9);
+ cbits_resize(&set, 43, false);
+ c_autobuf (str, char, cbits_size(&set) + 1)
+ printf(" str: %s\n", cbits_to_str(&set, str, 0, -1));
+
+ printf("%4" PRIuMAX ": ", cbits_size(&set));
+ c_forrange (i, cbits_size(&set))
+ printf("%d", cbits_test(&set, i));
+ puts("");
+
+ cbits_set(&set, 28);
+ cbits_resize(&set, 77, true);
+ cbits_resize(&set, 93, false);
+ cbits_resize(&set, 102, true);
+ cbits_set_value(&set, 99, false);
+ printf("%4" PRIuMAX ": ", cbits_size(&set));
+ c_forrange (i, cbits_size(&set))
+ printf("%d", cbits_test(&set, i));
+
+ puts("\nIterate:");
+ printf("%4" PRIuMAX ": ", cbits_size(&set));
+ c_forrange (i, cbits_size(&set))
+ printf("%d", cbits_test(&set, i));
+ puts("");
+
+ c_autovar (cbits s2 = cbits_clone(set), cbits_drop(&s2)) {
+ cbits_flip_all(&s2);
+ cbits_set(&s2, 16);
+ cbits_set(&s2, 17);
+ cbits_set(&s2, 18);
+ printf(" new: ");
+ c_forrange (i, cbits_size(&s2))
+ printf("%d", cbits_test(&s2, i));
+ puts("");
+
+ printf(" xor: ");
+ cbits_xor(&set, &s2);
+ c_forrange (i, cbits_size(&set))
+ printf("%d", cbits_test(&set, i));
+ puts("");
+
+ cbits_set_all(&set, false);
+ printf("%4" PRIuMAX ": ", cbits_size(&set));
+ c_forrange (i, cbits_size(&set))
+ printf("%d", cbits_test(&set, i));
+ puts("");
+ }
+ }
+}
diff --git a/examples/bits2.c b/examples/bits2.c
index af87df42..4b16ad76 100644
--- a/examples/bits2.c
+++ b/examples/bits2.c
@@ -1,43 +1,43 @@
-#include <stdio.h>
-// Example of static sized (stack allocated) bitsets
-
-#define i_type Bits
-#define i_len 80 // enable fixed bitset on the stack
-#define i_implement
-#include <stc/cbits.h>
-
-int main()
-{
- Bits s1 = Bits_from("1110100110111");
-
- printf("size %" PRIuMAX "\n", Bits_size(&s1));
- char buf[256];
- Bits_to_str(&s1, buf, 0, -1);
- printf("buf: %s: count=%" PRIuMAX "\n", buf, Bits_count(&s1));
-
- Bits_reset(&s1, 8);
- c_autobuf (str, char, Bits_size(&s1) + 1)
- printf(" s1: %s\n", Bits_to_str(&s1, str, 0, -1));
-
- Bits s2 = Bits_clone(s1);
-
- Bits_flip_all(&s2);
- Bits_reset(&s2, 66);
- Bits_reset(&s2, 67);
- printf(" s2: ");
- c_forrange (i, Bits_size(&s2))
- printf("%d", Bits_test(&s2, i));
- puts("");
-
- printf("xor: ");
- Bits_xor(&s1, &s2);
- c_forrange (i, Bits_size(&s1))
- printf("%d", Bits_test(&s1, i));
- puts("");
-
- printf("all: ");
- Bits_set_pattern(&s1, 0x3333333333333333);
- c_forrange (i, Bits_size(&s1))
- printf("%d", Bits_test(&s1, i));
- puts("");
-}
+#include <stdio.h>
+// Example of static sized (stack allocated) bitsets
+
+#define i_type Bits
+#define i_len 80 // enable fixed bitset on the stack
+#define i_implement
+#include <stc/cbits.h>
+
+int main()
+{
+ Bits s1 = Bits_from("1110100110111");
+
+ printf("size %" PRIuMAX "\n", Bits_size(&s1));
+ char buf[256];
+ Bits_to_str(&s1, buf, 0, -1);
+ printf("buf: %s: count=%" PRIuMAX "\n", buf, Bits_count(&s1));
+
+ Bits_reset(&s1, 8);
+ c_autobuf (str, char, Bits_size(&s1) + 1)
+ printf(" s1: %s\n", Bits_to_str(&s1, str, 0, -1));
+
+ Bits s2 = Bits_clone(s1);
+
+ Bits_flip_all(&s2);
+ Bits_reset(&s2, 66);
+ Bits_reset(&s2, 67);
+ printf(" s2: ");
+ c_forrange (i, Bits_size(&s2))
+ printf("%d", Bits_test(&s2, i));
+ puts("");
+
+ printf("xor: ");
+ Bits_xor(&s1, &s2);
+ c_forrange (i, Bits_size(&s1))
+ printf("%d", Bits_test(&s1, i));
+ puts("");
+
+ printf("all: ");
+ Bits_set_pattern(&s1, 0x3333333333333333);
+ c_forrange (i, Bits_size(&s1))
+ printf("%d", Bits_test(&s1, i));
+ puts("");
+}
diff --git a/examples/books.c b/examples/books.c
index de724a19..5677ff3a 100644
--- a/examples/books.c
+++ b/examples/books.c
@@ -1,61 +1,61 @@
-// https://doc.rust-lang.org/std/collections/struct.HashMap.html
-#define i_implement
-#include <stc/cstr.h>
-#define i_key_str
-#define i_val_str
-#include <stc/cmap.h>
-
-// Type inference lets us omit an explicit type signature (which
-// would be `HashMap<String, String>` in this example).
-int main()
-{
- c_auto (cmap_str, book_reviews)
- {
- // Review some books.
- cmap_str_emplace(&book_reviews,
- "Adventures of Huckleberry Finn",
- "My favorite book."
- );
- cmap_str_emplace(&book_reviews,
- "Grimms' Fairy Tales",
- "Masterpiece."
- );
- cmap_str_emplace(&book_reviews,
- "Pride and Prejudice",
- "Very enjoyable"
- );
- cmap_str_insert(&book_reviews,
- cstr_new("The Adventures of Sherlock Holmes"),
- cstr_new("Eye lyked it alot.")
- );
-
- // Check for a specific one.
- // When collections store owned values (String), they can still be
- // queried using references (&str).
- if (cmap_str_contains(&book_reviews, "Les Misérables")) {
- printf("We've got %" PRIuMAX " reviews, but Les Misérables ain't one.",
- cmap_str_size(book_reviews));
- }
-
- // oops, this review has a lot of spelling mistakes, let's delete it.
- cmap_str_erase(&book_reviews, "The Adventures of Sherlock Holmes");
-
- // Look up the values associated with some keys.
- const char* to_find[] = {"Pride and Prejudice", "Alice's Adventure in Wonderland"};
- c_forrange (i, c_arraylen(to_find)) {
- const cmap_str_value* b;
- if ((b = cmap_str_get(&book_reviews, to_find[i])))
- printf("%s: %s\n", cstr_str(&b->first), cstr_str(&b->second));
- else
- printf("%s is unreviewed.\n", to_find[i]);
- }
-
- // Look up the value for a key (will panic if the key is not found).
- printf("Review for Jane: %s\n", cstr_str(cmap_str_at(&book_reviews, "Pride and Prejudice")));
-
- // Iterate over everything.
- c_forpair (book, review, cmap_str, book_reviews) {
- printf("%s: \"%s\"\n", cstr_str(_.book), cstr_str(_.review));
- }
- }
-}
+// https://doc.rust-lang.org/std/collections/struct.HashMap.html
+#define i_implement
+#include <stc/cstr.h>
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
+
+// Type inference lets us omit an explicit type signature (which
+// would be `HashMap<String, String>` in this example).
+int main()
+{
+ c_auto (cmap_str, book_reviews)
+ {
+ // Review some books.
+ cmap_str_emplace(&book_reviews,
+ "Adventures of Huckleberry Finn",
+ "My favorite book."
+ );
+ cmap_str_emplace(&book_reviews,
+ "Grimms' Fairy Tales",
+ "Masterpiece."
+ );
+ cmap_str_emplace(&book_reviews,
+ "Pride and Prejudice",
+ "Very enjoyable"
+ );
+ cmap_str_insert(&book_reviews,
+ cstr_new("The Adventures of Sherlock Holmes"),
+ cstr_new("Eye lyked it alot.")
+ );
+
+ // Check for a specific one.
+ // When collections store owned values (String), they can still be
+ // queried using references (&str).
+ if (cmap_str_contains(&book_reviews, "Les Misérables")) {
+ printf("We've got %" PRIuMAX " reviews, but Les Misérables ain't one.",
+ cmap_str_size(book_reviews));
+ }
+
+ // oops, this review has a lot of spelling mistakes, let's delete it.
+ cmap_str_erase(&book_reviews, "The Adventures of Sherlock Holmes");
+
+ // Look up the values associated with some keys.
+ const char* to_find[] = {"Pride and Prejudice", "Alice's Adventure in Wonderland"};
+ c_forrange (i, c_arraylen(to_find)) {
+ const cmap_str_value* b;
+ if ((b = cmap_str_get(&book_reviews, to_find[i])))
+ printf("%s: %s\n", cstr_str(&b->first), cstr_str(&b->second));
+ else
+ printf("%s is unreviewed.\n", to_find[i]);
+ }
+
+ // Look up the value for a key (will panic if the key is not found).
+ printf("Review for Jane: %s\n", cstr_str(cmap_str_at(&book_reviews, "Pride and Prejudice")));
+
+ // Iterate over everything.
+ c_forpair (book, review, cmap_str, book_reviews) {
+ printf("%s: \"%s\"\n", cstr_str(_.book), cstr_str(_.review));
+ }
+ }
+}
diff --git a/examples/box.c b/examples/box.c
index 4502f479..7a984a21 100644
--- a/examples/box.c
+++ b/examples/box.c
@@ -1,75 +1,75 @@
-/* cbox: heap allocated boxed type */
-#define i_implement
-#include <stc/cstr.h>
-
-typedef struct { cstr name, last; } Person;
-
-Person Person_new(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
-}
-
-uint64_t Person_hash(const Person* a) {
- return cstr_hash(&a->name) ^ cstr_hash(&a->last);
-}
-
-int Person_cmp(const Person* a, const Person* b) {
- int c = cstr_cmp(&a->name, &b->name);
- return c ? c : cstr_cmp(&a->last, &b->last);
-}
-
-Person Person_clone(Person p) {
- p.name = cstr_clone(p.name);
- p.last = cstr_clone(p.last);
- return p;
-}
-
-void Person_drop(Person* p) {
- printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
- c_drop(cstr, &p->name, &p->last);
-}
-
-#define i_type PBox
-#define i_val_bind Person // binds Person_cmp, ...
-#include <stc/cbox.h>
-
-#define i_type Persons
-#define i_val_arcbox PBox // informs that PBox is a smart pointer.
-#include <stc/cvec.h>
-
-int main()
-{
- c_auto (Persons, vec)
- c_auto (PBox, p, q)
- {
- p = PBox_make(Person_new("Laura", "Palmer"));
-
- q = PBox_clone(p);
- cstr_assign(&q.get->name, "Leland");
-
- printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last));
- printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last));
-
- Persons_push_back(&vec, PBox_make(Person_new("Dale", "Cooper")));
- Persons_push_back(&vec, PBox_make(Person_new("Audrey", "Home")));
-
- // NB! Clone p and q to the vector using emplace_back()
- c_apply(v, Persons_push_back(&vec, PBox_clone(*v)), PBox, {p, q});
-
- c_foreach (i, Persons, vec)
- printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last));
- puts("");
-
- // Look-up Audrey! Use a (fake) temporary PBox for lookup.
- c_autovar (Person a = Person_new("Audrey", "Home"), Person_drop(&a)) {
- const PBox *v = Persons_get(&vec, a);
- if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last));
- }
- puts("");
-
- // Alternative to use cbox (when not placed in container).
- Person *she = c_new(Person, Person_new("Shelly", "Johnson"));
- printf("%s %s\n", cstr_str(&she->name), cstr_str(&she->last));
- c_delete(Person, she); // drop and free
- puts("");
- }
-}
+/* cbox: heap allocated boxed type */
+#define i_implement
+#include <stc/cstr.h>
+
+typedef struct { cstr name, last; } Person;
+
+Person Person_new(const char* name, const char* last) {
+ return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+}
+
+uint64_t Person_hash(const Person* a) {
+ return cstr_hash(&a->name) ^ cstr_hash(&a->last);
+}
+
+int Person_cmp(const Person* a, const Person* b) {
+ int c = cstr_cmp(&a->name, &b->name);
+ return c ? c : cstr_cmp(&a->last, &b->last);
+}
+
+Person Person_clone(Person p) {
+ p.name = cstr_clone(p.name);
+ p.last = cstr_clone(p.last);
+ return p;
+}
+
+void Person_drop(Person* p) {
+ printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
+ c_drop(cstr, &p->name, &p->last);
+}
+
+#define i_type PBox
+#define i_val_bind Person // binds Person_cmp, ...
+#include <stc/cbox.h>
+
+#define i_type Persons
+#define i_val_arcbox PBox // informs that PBox is a smart pointer.
+#include <stc/cvec.h>
+
+int main()
+{
+ c_auto (Persons, vec)
+ c_auto (PBox, p, q)
+ {
+ p = PBox_make(Person_new("Laura", "Palmer"));
+
+ q = PBox_clone(p);
+ cstr_assign(&q.get->name, "Leland");
+
+ printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last));
+ printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last));
+
+ Persons_push_back(&vec, PBox_make(Person_new("Dale", "Cooper")));
+ Persons_push_back(&vec, PBox_make(Person_new("Audrey", "Home")));
+
+ // NB! Clone p and q to the vector using emplace_back()
+ c_apply(v, Persons_push_back(&vec, PBox_clone(*v)), PBox, {p, q});
+
+ c_foreach (i, Persons, vec)
+ printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last));
+ puts("");
+
+ // Look-up Audrey! Use a (fake) temporary PBox for lookup.
+ c_autovar (Person a = Person_new("Audrey", "Home"), Person_drop(&a)) {
+ const PBox *v = Persons_get(&vec, a);
+ if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last));
+ }
+ puts("");
+
+ // Alternative to use cbox (when not placed in container).
+ Person *she = c_new(Person, Person_new("Shelly", "Johnson"));
+ printf("%s %s\n", cstr_str(&she->name), cstr_str(&she->last));
+ c_delete(Person, she); // drop and free
+ puts("");
+ }
+}
diff --git a/examples/box2.c b/examples/box2.c
index 2d1b82fc..c44802d3 100644
--- a/examples/box2.c
+++ b/examples/box2.c
@@ -1,88 +1,88 @@
-// https://doc.rust-lang.org/rust-by-example/std/box.html
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stc/ccommon.h>
-
-struct {
- double x;
- double y;
-} typedef Point;
-
-// A Rectangle can be specified by where its top left and bottom right
-// corners are in space
-struct {
- Point top_left;
- Point bottom_right;
-} typedef Rectangle;
-
-#define i_val Point
-#define i_opt c_no_cmp
-#include <stc/cbox.h> // cbox_Point
-
-#define i_val Rectangle
-#define i_opt c_no_cmp
-#include <stc/cbox.h> // cbox_Rectangle
-
-// Box in box:
-#define i_val_arcbox cbox_Point // NB: use i_val_arcbox when value is a cbox or carc!
- // it will auto-set i_valdrop, i_valfrom, i_cmp for you.
-#define i_opt c_no_cmp
-#define i_tag BoxPoint
-#include <stc/cbox.h> // cbox_BoxPoint
-
-Point origin(void) {
- return (Point){ .x=0.0, .y=0.0 };
-}
-
-cbox_Point boxed_origin(void) {
- // Allocate this point on the heap, and return a pointer to it
- return cbox_Point_make((Point){ .x=0.0, .y=0.0 });
-}
-
-
-int main(void) {
- // (all the type annotations are superfluous)
- // Stack allocated variables
- Point point = origin();
- Rectangle rectangle = (Rectangle){
- .top_left = origin(),
- .bottom_right = (Point){ .x=3.0, .y=-4.0 }
- };
-
- // Heap allocated rectangle
- c_auto (cbox_Rectangle, boxed_rectangle)
- c_auto (cbox_Point, boxed_point)
- c_auto (cbox_BoxPoint, box_in_a_box)
- {
- boxed_rectangle = cbox_Rectangle_make((Rectangle){
- .top_left = origin(),
- .bottom_right = (Point){ .x=3.0, .y=-4.0 }
- });
-
- // The output of functions can be boxed
- boxed_point = cbox_Point_make(origin());
-
- // Double indirection
- box_in_a_box = cbox_BoxPoint_make(boxed_origin());
-
- printf("Point occupies %" PRIuMAX " bytes on the stack\n",
- sizeof(point));
- printf("Rectangle occupies %" PRIuMAX " bytes on the stack\n",
- sizeof(rectangle));
-
- // box size == pointer size
- printf("Boxed point occupies %" PRIuMAX " bytes on the stack\n",
- sizeof(boxed_point));
- printf("Boxed rectangle occupies %" PRIuMAX " bytes on the stack\n",
- sizeof(boxed_rectangle));
- printf("Boxed box occupies %" PRIuMAX " bytes on the stack\n",
- sizeof(box_in_a_box));
-
- // Copy the data contained in `boxed_point` into `unboxed_point`
- Point unboxed_point = *boxed_point.get;
- printf("Unboxed point occupies %" PRIuMAX " bytes on the stack\n",
- sizeof(unboxed_point));
- }
-}
+// https://doc.rust-lang.org/rust-by-example/std/box.html
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stc/ccommon.h>
+
+struct {
+ double x;
+ double y;
+} typedef Point;
+
+// A Rectangle can be specified by where its top left and bottom right
+// corners are in space
+struct {
+ Point top_left;
+ Point bottom_right;
+} typedef Rectangle;
+
+#define i_val Point
+#define i_opt c_no_cmp
+#include <stc/cbox.h> // cbox_Point
+
+#define i_val Rectangle
+#define i_opt c_no_cmp
+#include <stc/cbox.h> // cbox_Rectangle
+
+// Box in box:
+#define i_val_arcbox cbox_Point // NB: use i_val_arcbox when value is a cbox or carc!
+ // it will auto-set i_valdrop, i_valfrom, i_cmp for you.
+#define i_opt c_no_cmp
+#define i_tag BoxPoint
+#include <stc/cbox.h> // cbox_BoxPoint
+
+Point origin(void) {
+ return (Point){ .x=0.0, .y=0.0 };
+}
+
+cbox_Point boxed_origin(void) {
+ // Allocate this point on the heap, and return a pointer to it
+ return cbox_Point_make((Point){ .x=0.0, .y=0.0 });
+}
+
+
+int main(void) {
+ // (all the type annotations are superfluous)
+ // Stack allocated variables
+ Point point = origin();
+ Rectangle rectangle = (Rectangle){
+ .top_left = origin(),
+ .bottom_right = (Point){ .x=3.0, .y=-4.0 }
+ };
+
+ // Heap allocated rectangle
+ c_auto (cbox_Rectangle, boxed_rectangle)
+ c_auto (cbox_Point, boxed_point)
+ c_auto (cbox_BoxPoint, box_in_a_box)
+ {
+ boxed_rectangle = cbox_Rectangle_make((Rectangle){
+ .top_left = origin(),
+ .bottom_right = (Point){ .x=3.0, .y=-4.0 }
+ });
+
+ // The output of functions can be boxed
+ boxed_point = cbox_Point_make(origin());
+
+ // Double indirection
+ box_in_a_box = cbox_BoxPoint_make(boxed_origin());
+
+ printf("Point occupies %" PRIuMAX " bytes on the stack\n",
+ sizeof(point));
+ printf("Rectangle occupies %" PRIuMAX " bytes on the stack\n",
+ sizeof(rectangle));
+
+ // box size == pointer size
+ printf("Boxed point occupies %" PRIuMAX " bytes on the stack\n",
+ sizeof(boxed_point));
+ printf("Boxed rectangle occupies %" PRIuMAX " bytes on the stack\n",
+ sizeof(boxed_rectangle));
+ printf("Boxed box occupies %" PRIuMAX " bytes on the stack\n",
+ sizeof(box_in_a_box));
+
+ // Copy the data contained in `boxed_point` into `unboxed_point`
+ Point unboxed_point = *boxed_point.get;
+ printf("Unboxed point occupies %" PRIuMAX " bytes on the stack\n",
+ sizeof(unboxed_point));
+ }
+}
diff --git a/examples/city.c b/examples/city.c
index 8ee1576f..c359ebdf 100644
--- a/examples/city.c
+++ b/examples/city.c
@@ -1,83 +1,83 @@
-#define i_implement
-#include <stc/cstr.h>
-
-typedef struct {
- cstr name;
- cstr country;
- float lat, lon;
- int population;
-} City;
-
-static inline int City_cmp(const City* a, const City* b) {
- int c = cstr_cmp(&a->name, &b->name);
- return c ? c : cstr_cmp(&a->country, &b->country);
-}
-
-static inline uint64_t City_hash(const City* a) {
- printf("hash %s\n", cstr_str(&a->name));
- return cstr_hash(&a->name) ^ cstr_hash(&a->country);
-}
-
-static inline City City_clone(City c) {
- printf("clone %s\n", cstr_str(&c.name));
- c.name = cstr_clone(c.name);
- c.country = cstr_clone(c.country);
- return c;
-}
-
-static inline void City_drop(City* c) {
- printf("drop %s\n", cstr_str(&c->name));
- c_drop(cstr, &c->name, &c->country);
-}
-
-
-#define i_type CityArc
-#define i_key_bind City
-#include <stc/cbox.h>
-//#include <stc/carc.h> // try instead of cbox.h
-
-#define i_type Cities
-#define i_key_arcbox CityArc
-#include <stc/cvec.h>
-
-#define i_type CityMap
-#define i_key int
-#define i_val_arcbox CityArc
-#include <stc/csmap.h>
-
-
-int main(void)
-{
- c_auto (Cities, cities, copy)
- c_auto (CityMap, map)
- {
- struct City_s { const char *name, *country; float lat, lon; int pop; };
-
- c_apply(c, Cities_push(&cities, CityArc_make((City){cstr_from(c->name), cstr_from(c->country),
- c->lat, c->lon, c->pop})), struct City_s, {
- {"New York", "US", 4.3, 23.2, 9000000},
- {"Paris", "France", 4.3, 23.2, 9000000},
- {"Berlin", "Germany", 4.3, 23.2, 9000000},
- {"London", "UK", 4.3, 23.2, 9000000},
- });
-
- copy = Cities_clone(cities); // share each element!
-
- int k = 0, id[] = {8, 4, 3, 9, 2, 5};
- c_foreach (i, Cities, cities)
- CityMap_insert(&map, id[k++], CityArc_clone(*i.ref));
-
- Cities_pop(&cities);
- Cities_pop(&cities);
-
- printf("Vec:\n");
- c_foreach (c, Cities, cities)
- printf("city:%s, %d, use:%ld\n", cstr_str(&c.ref->get->name), c.ref->get->population, CityArc_use_count(*c.ref));
-
- printf("\nMap:\n");
- c_forpair (id, city, CityMap, map)
- printf("id:%d, city:%s, %d, use:%ld\n", *_.id, cstr_str(&_.city->get->name),
- _.city->get->population, CityArc_use_count(*_.city));
- puts("");
- }
-}
+#define i_implement
+#include <stc/cstr.h>
+
+typedef struct {
+ cstr name;
+ cstr country;
+ float lat, lon;
+ int population;
+} City;
+
+static inline int City_cmp(const City* a, const City* b) {
+ int c = cstr_cmp(&a->name, &b->name);
+ return c ? c : cstr_cmp(&a->country, &b->country);
+}
+
+static inline uint64_t City_hash(const City* a) {
+ printf("hash %s\n", cstr_str(&a->name));
+ return cstr_hash(&a->name) ^ cstr_hash(&a->country);
+}
+
+static inline City City_clone(City c) {
+ printf("clone %s\n", cstr_str(&c.name));
+ c.name = cstr_clone(c.name);
+ c.country = cstr_clone(c.country);
+ return c;
+}
+
+static inline void City_drop(City* c) {
+ printf("drop %s\n", cstr_str(&c->name));
+ c_drop(cstr, &c->name, &c->country);
+}
+
+
+#define i_type CityArc
+#define i_key_bind City
+#include <stc/cbox.h>
+//#include <stc/carc.h> // try instead of cbox.h
+
+#define i_type Cities
+#define i_key_arcbox CityArc
+#include <stc/cvec.h>
+
+#define i_type CityMap
+#define i_key int
+#define i_val_arcbox CityArc
+#include <stc/csmap.h>
+
+
+int main(void)
+{
+ c_auto (Cities, cities, copy)
+ c_auto (CityMap, map)
+ {
+ struct City_s { const char *name, *country; float lat, lon; int pop; };
+
+ c_apply(c, Cities_push(&cities, CityArc_make((City){cstr_from(c->name), cstr_from(c->country),
+ c->lat, c->lon, c->pop})), struct City_s, {
+ {"New York", "US", 4.3, 23.2, 9000000},
+ {"Paris", "France", 4.3, 23.2, 9000000},
+ {"Berlin", "Germany", 4.3, 23.2, 9000000},
+ {"London", "UK", 4.3, 23.2, 9000000},
+ });
+
+ copy = Cities_clone(cities); // share each element!
+
+ int k = 0, id[] = {8, 4, 3, 9, 2, 5};
+ c_foreach (i, Cities, cities)
+ CityMap_insert(&map, id[k++], CityArc_clone(*i.ref));
+
+ Cities_pop(&cities);
+ Cities_pop(&cities);
+
+ printf("Vec:\n");
+ c_foreach (c, Cities, cities)
+ printf("city:%s, %d, use:%ld\n", cstr_str(&c.ref->get->name), c.ref->get->population, CityArc_use_count(*c.ref));
+
+ printf("\nMap:\n");
+ c_forpair (id, city, CityMap, map)
+ printf("id:%d, city:%s, %d, use:%ld\n", *_.id, cstr_str(&_.city->get->name),
+ _.city->get->population, CityArc_use_count(*_.city));
+ puts("");
+ }
+}
diff --git a/examples/complex.c b/examples/complex.c
index c5ac9882..8db85bbd 100644
--- a/examples/complex.c
+++ b/examples/complex.c
@@ -1,63 +1,63 @@
-#define i_implement
-#include <stc/cstr.h>
-
-void check_drop(float* v) {printf("destroy %g\n", *v);}
-
-#define i_type FloatStack
-#define i_val float
-#define i_valdrop check_drop
-#define i_valclone(x) x // required to allow cloning when i_valdrop is defined
- // (not for carc as it does not use i_valclone to clone).
-#include <stc/cstack.h>
-
-#define i_type StackList
-#define i_val_bind FloatStack
-#define i_opt c_no_cmp
-#include <stc/clist.h>
-
-#define i_type ListMap
-#define i_key int
-#define i_val_bind StackList
-#include <stc/cmap.h>
-
-#define i_type MapMap
-#define i_key_str
-#define i_val_bind ListMap
-#include <stc/cmap.h>
-
-// c++:
-// using FloatStack = std::stack<float>;
-// using map_lst = std::unordered_map<int, std::forward_list<array2f>>;
-// using map_map = std::unordered_map<std::string, map_lst>;
-
-int main() {
- int xdim = 4, ydim = 6;
- int x = 1, tableKey = 42;
- const char* strKey = "first";
-
- c_auto (MapMap, mmap)
- {
- FloatStack stack = FloatStack_with_capacity(xdim * ydim);
- memset(stack.data, 0, xdim*ydim*sizeof *stack.data);
- stack.size = stack.capacity;
-
- // Put in some data in stack array
- stack.data[x] = 3.1415927f;
- printf("stack size: %" PRIuMAX "\n", FloatStack_size(stack));
-
- StackList list = StackList_init();
- StackList_push_back(&list, stack);
-
- ListMap lmap = ListMap_init();
- ListMap_insert(&lmap, tableKey, list);
- MapMap_insert(&mmap, cstr_from(strKey), lmap);
-
- // Access the data entry
- const ListMap* lmap_p = MapMap_at(&mmap, strKey);
- const StackList* list_p = ListMap_at(lmap_p, tableKey);
- const FloatStack* stack_p = StackList_back(list_p);
- printf("value (%d) is: %f\n", x, *FloatStack_at(stack_p, x));
-
- stack.data[x] = 1.41421356f; // change the value in array
- }
-}
+#define i_implement
+#include <stc/cstr.h>
+
+void check_drop(float* v) {printf("destroy %g\n", *v);}
+
+#define i_type FloatStack
+#define i_val float
+#define i_valdrop check_drop
+#define i_valclone(x) x // required to allow cloning when i_valdrop is defined
+ // (not for carc as it does not use i_valclone to clone).
+#include <stc/cstack.h>
+
+#define i_type StackList
+#define i_val_bind FloatStack
+#define i_opt c_no_cmp
+#include <stc/clist.h>
+
+#define i_type ListMap
+#define i_key int
+#define i_val_bind StackList
+#include <stc/cmap.h>
+
+#define i_type MapMap
+#define i_key_str
+#define i_val_bind ListMap
+#include <stc/cmap.h>
+
+// c++:
+// using FloatStack = std::stack<float>;
+// using map_lst = std::unordered_map<int, std::forward_list<array2f>>;
+// using map_map = std::unordered_map<std::string, map_lst>;
+
+int main() {
+ int xdim = 4, ydim = 6;
+ int x = 1, tableKey = 42;
+ const char* strKey = "first";
+
+ c_auto (MapMap, mmap)
+ {
+ FloatStack stack = FloatStack_with_capacity(xdim * ydim);
+ memset(stack.data, 0, xdim*ydim*sizeof *stack.data);
+ stack.size = stack.capacity;
+
+ // Put in some data in stack array
+ stack.data[x] = 3.1415927f;
+ printf("stack size: %" PRIuMAX "\n", FloatStack_size(stack));
+
+ StackList list = StackList_init();
+ StackList_push_back(&list, stack);
+
+ ListMap lmap = ListMap_init();
+ ListMap_insert(&lmap, tableKey, list);
+ MapMap_insert(&mmap, cstr_from(strKey), lmap);
+
+ // Access the data entry
+ const ListMap* lmap_p = MapMap_at(&mmap, strKey);
+ const StackList* list_p = ListMap_at(lmap_p, tableKey);
+ const FloatStack* stack_p = StackList_back(list_p);
+ printf("value (%d) is: %f\n", x, *FloatStack_at(stack_p, x));
+
+ stack.data[x] = 1.41421356f; // change the value in array
+ }
+}
diff --git a/examples/csmap_insert.c b/examples/csmap_insert.c
index 24f536e9..3d235877 100644
--- a/examples/csmap_insert.c
+++ b/examples/csmap_insert.c
@@ -1,112 +1,112 @@
-#define i_implement
-#include <stc/cstr.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_key int
-#define i_val int
-#define i_tag ii // Map of int => int
-#include <stc/csmap.h>
-
-#define i_key int
-#define i_val_str
-#define i_tag istr // Map of int => cstr
-#include <stc/csmap.h>
-
-#define i_val csmap_ii_raw
-#define i_opt c_no_cmp
-#define i_tag ii
-#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, cstr_str(&e.ref->second));
- puts("");
-}
-
-int main()
-{
- // insert single values
- c_auto (csmap_ii, m1) {
- csmap_ii_insert(&m1, 1, 10);
- csmap_ii_insert(&m1, 2, 20);
-
- puts("The original key and mapped values of m1 are:");
- print_ii(m1);
-
- // intentionally attempt a duplicate, single element
- csmap_ii_result ret = csmap_ii_insert(&m1, 1, 111);
- if (!ret.inserted) {
- csmap_ii_value pr = *ret.ref;
- puts("Insert failed, element with key value 1 already exists.");
- printf(" The existing element is (%d, %d)\n", pr.first, pr.second);
- }
- else {
- puts("The modified key and mapped values of m1 are:");
- print_ii(m1);
- }
- puts("");
-
- csmap_ii_insert(&m1, 3, 30);
- puts("The modified key and mapped values of m1 are:");
- print_ii(m1);
- puts("");
- }
-
- // The templatized version inserting a jumbled range
- c_auto (csmap_ii, m2)
- c_auto (cvec_ii, v) {
- typedef cvec_ii_value 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);
- puts("");
-
- c_foreach (e, cvec_ii, v)
- csmap_ii_insert_or_assign(&m2, e.ref->first, e.ref->second);
-
- puts("The modified key and mapped values of m2 are:");
- c_foreach (e, csmap_ii, m2)
- printf("(%d, %d) ", e.ref->first, e.ref->second);
- puts("\n");
- }
-
- // The templatized versions move-constructing elements
- c_auto (csmap_istr, m3) {
- csmap_istr_value ip1 = {475, cstr_new("blue")}, ip2 = {510, cstr_new("green")};
-
- // single element
- csmap_istr_insert(&m3, ip1.first, cstr_move(&ip1.second));
- puts("After the first move insertion, m3 contains:");
- print_istr(m3);
-
- // single element
- csmap_istr_insert(&m3, ip2.first, cstr_move(&ip2.second));
- puts("After the second move insertion, m3 contains:");
- print_istr(m3);
- puts("");
- }
-
- c_auto (csmap_ii, m4) {
- // Insert the elements from an initializer_list
- c_apply(v, csmap_ii_insert(&m4, c_pair(v)), csmap_ii_raw, {
- { 4, 44 }, { 2, 22 }, { 3, 33 }, { 1, 11 }, { 5, 55 }
- });
- puts("After initializer_list insertion, m4 contains:");
- print_ii(m4);
- puts("");
- }
-}
+#define i_implement
+#include <stc/cstr.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_key int
+#define i_val int
+#define i_tag ii // Map of int => int
+#include <stc/csmap.h>
+
+#define i_key int
+#define i_val_str
+#define i_tag istr // Map of int => cstr
+#include <stc/csmap.h>
+
+#define i_val csmap_ii_raw
+#define i_opt c_no_cmp
+#define i_tag ii
+#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, cstr_str(&e.ref->second));
+ puts("");
+}
+
+int main()
+{
+ // insert single values
+ c_auto (csmap_ii, m1) {
+ csmap_ii_insert(&m1, 1, 10);
+ csmap_ii_insert(&m1, 2, 20);
+
+ puts("The original key and mapped values of m1 are:");
+ print_ii(m1);
+
+ // intentionally attempt a duplicate, single element
+ csmap_ii_result ret = csmap_ii_insert(&m1, 1, 111);
+ if (!ret.inserted) {
+ csmap_ii_value pr = *ret.ref;
+ puts("Insert failed, element with key value 1 already exists.");
+ printf(" The existing element is (%d, %d)\n", pr.first, pr.second);
+ }
+ else {
+ puts("The modified key and mapped values of m1 are:");
+ print_ii(m1);
+ }
+ puts("");
+
+ csmap_ii_insert(&m1, 3, 30);
+ puts("The modified key and mapped values of m1 are:");
+ print_ii(m1);
+ puts("");
+ }
+
+ // The templatized version inserting a jumbled range
+ c_auto (csmap_ii, m2)
+ c_auto (cvec_ii, v) {
+ typedef cvec_ii_value 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);
+ puts("");
+
+ c_foreach (e, cvec_ii, v)
+ csmap_ii_insert_or_assign(&m2, e.ref->first, e.ref->second);
+
+ puts("The modified key and mapped values of m2 are:");
+ c_foreach (e, csmap_ii, m2)
+ printf("(%d, %d) ", e.ref->first, e.ref->second);
+ puts("\n");
+ }
+
+ // The templatized versions move-constructing elements
+ c_auto (csmap_istr, m3) {
+ csmap_istr_value ip1 = {475, cstr_new("blue")}, ip2 = {510, cstr_new("green")};
+
+ // single element
+ csmap_istr_insert(&m3, ip1.first, cstr_move(&ip1.second));
+ puts("After the first move insertion, m3 contains:");
+ print_istr(m3);
+
+ // single element
+ csmap_istr_insert(&m3, ip2.first, cstr_move(&ip2.second));
+ puts("After the second move insertion, m3 contains:");
+ print_istr(m3);
+ puts("");
+ }
+
+ c_auto (csmap_ii, m4) {
+ // Insert the elements from an initializer_list
+ c_apply(v, csmap_ii_insert(&m4, c_pair(v)), csmap_ii_raw, {
+ { 4, 44 }, { 2, 22 }, { 3, 33 }, { 1, 11 }, { 5, 55 }
+ });
+ puts("After initializer_list insertion, m4 contains:");
+ print_ii(m4);
+ puts("");
+ }
+}
diff --git a/examples/csset_erase.c b/examples/csset_erase.c
index 3cfaa7f1..7c8c1d97 100644
--- a/examples/csset_erase.c
+++ b/examples/csset_erase.c
@@ -1,42 +1,42 @@
-#include <stdio.h>
-
-#define i_key int
-#include <stc/csset.h>
-
-int main()
-{
- c_auto (csset_int, set)
- {
- c_apply(v, csset_int_insert(&set, *v),
- int, {30, 20, 80, 40, 60, 90, 10, 70, 50});
- c_foreach (k, csset_int, set)
- printf(" %d", *k.ref);
- puts("");
-
- int val = 64;
- csset_int_iter 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 != csset_int_end(&set).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_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("");
- }
-}
+#include <stdio.h>
+
+#define i_key int
+#include <stc/csset.h>
+
+int main()
+{
+ c_auto (csset_int, set)
+ {
+ c_apply(v, csset_int_insert(&set, *v),
+ int, {30, 20, 80, 40, 60, 90, 10, 70, 50});
+ c_foreach (k, csset_int, set)
+ printf(" %d", *k.ref);
+ puts("");
+
+ int val = 64;
+ csset_int_iter 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 != csset_int_end(&set).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_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 a110e49a..69c12ef2 100644
--- a/examples/cstr_match.c
+++ b/examples/cstr_match.c
@@ -1,23 +1,23 @@
-#define i_implement
-#include <stc/cstr.h>
-#include <stc/csview.h>
-#include <stdio.h>
-
-int main()
-{
- c_autovar (cstr ss = cstr_new("The quick brown fox jumps over the lazy dog.JPG"), cstr_drop(&ss)) {
- size_t pos = cstr_find_from(ss, 0, "brown");
- printf("%" PRIuMAX " [%s]\n", pos, pos == cstr_npos ? "<NULL>" : cstr_str(&ss) + pos);
- printf("equals: %d\n", cstr_equals(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"));
-
- cstr s1 = cstr_new("hell😀 w😀rl🐨");
- csview ch1 = cstr_at(&s1, 10);
- csview ch2 = cstr_at_u8(&s1, 10);
- printf("ch1: %" c_PRIsv "\n", c_ARGsv(ch1));
- printf("ch2: %" c_PRIsv "\n", c_ARGsv(ch2));
- }
-}
+#define i_implement
+#include <stc/cstr.h>
+#include <stc/csview.h>
+#include <stdio.h>
+
+int main()
+{
+ c_autovar (cstr ss = cstr_new("The quick brown fox jumps over the lazy dog.JPG"), cstr_drop(&ss)) {
+ size_t pos = cstr_find_from(ss, 0, "brown");
+ printf("%" PRIuMAX " [%s]\n", pos, pos == cstr_npos ? "<NULL>" : cstr_str(&ss) + pos);
+ printf("equals: %d\n", cstr_equals(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"));
+
+ cstr s1 = cstr_new("hell😀 w😀rl🐨");
+ csview ch1 = cstr_at(&s1, 10);
+ csview ch2 = cstr_at_u8(&s1, 10);
+ printf("ch1: %" c_PRIsv "\n", c_ARGsv(ch1));
+ printf("ch2: %" c_PRIsv "\n", c_ARGsv(ch2));
+ }
+}
diff --git a/examples/demos.c b/examples/demos.c
index 62df82a4..780a4bff 100644
--- a/examples/demos.c
+++ b/examples/demos.c
@@ -1,229 +1,229 @@
-#define i_implement
-#include <stc/cstr.h>
-
-void stringdemo1()
-{
- printf("\nSTRINGDEMO1\n");
- c_autovar (cstr cs = cstr_new("one-nine-three-seven-five"), cstr_drop(&cs))
- {
- printf("%s.\n", cstr_str(&cs));
-
- cstr_insert(&cs, 3, "-two");
- printf("%s.\n", cstr_str(&cs));
-
- cstr_erase_n(&cs, 7, 5); // -nine
- printf("%s.\n", cstr_str(&cs));
-
- cstr_replace_one(&cs, 0, "seven", "four");
- printf("%s.\n", cstr_str(&cs));
-
- cstr_take(&cs, cstr_from_fmt("%s *** %s", cstr_str(&cs), cstr_str(&cs)));
- printf("%s.\n", cstr_str(&cs));
-
- printf("find \"four\": %s\n", cstr_str(&cs) + cstr_find(cs, "four"));
-
- // reassign:
- cstr_assign(&cs, "one two three four five six seven");
- cstr_append(&cs, " eight");
- printf("append: %s\n", cstr_str(&cs));
- }
-}
-
-#define i_val int64_t
-#define i_tag ix
-#include <stc/cvec.h>
-
-void vectordemo1()
-{
- printf("\nVECTORDEMO1\n");
- c_autovar (cvec_ix bignums = cvec_ix_with_capacity(100), cvec_ix_drop(&bignums))
- {
- cvec_ix_reserve(&bignums, 100);
- for (size_t i = 10; i <= 100; i += 10)
- cvec_ix_push_back(&bignums, i * i);
-
- printf("erase - %d: %" PRIuMAX "\n", 3, bignums.data[3]);
- cvec_ix_erase_n(&bignums, 3, 1); // erase index 3
-
- cvec_ix_pop_back(&bignums); // erase the last
- cvec_ix_erase_n(&bignums, 0, 1); // erase the first
-
- for (size_t i = 0; i < cvec_ix_size(bignums); ++i) {
- printf("%" PRIuMAX ": %" PRIuMAX "\n", i, bignums.data[i]);
- }
- }
-}
-
-#define i_val_str
-#include <stc/cvec.h>
-
-void vectordemo2()
-{
- printf("\nVECTORDEMO2\n");
- c_auto (cvec_str, names) {
- cvec_str_emplace_back(&names, "Mary");
- cvec_str_emplace_back(&names, "Joe");
- cvec_str_emplace_back(&names, "Chris");
- cstr_assign(&names.data[1], "Jane"); // replace Joe
- printf("names[1]: %s\n", cstr_str(&names.data[1]));
-
- cvec_str_sort(&names); // Sort the array
- c_foreach (i, cvec_str, names)
- printf("sorted: %s\n", cstr_str(i.ref));
- }
-}
-
-#define i_val int
-#define i_tag ix
-#define i_extern // define _clist_mergesort() once
-#include <stc/clist.h>
-
-void listdemo1()
-{
- printf("\nLISTDEMO1\n");
- c_auto (clist_ix, nums, nums2)
- {
- for (int i = 0; i < 10; ++i)
- clist_ix_push_back(&nums, i);
- for (int i = 100; i < 110; ++i)
- clist_ix_push_back(&nums2, i);
-
- /* splice nums2 to front of nums */
- clist_ix_splice(&nums, clist_ix_begin(&nums), &nums2);
- c_foreach (i, clist_ix, nums)
- printf("spliced: %d\n", *i.ref);
- puts("");
-
- *clist_ix_find(&nums, 104).ref += 50;
- clist_ix_remove(&nums, 103);
- clist_ix_iter it = clist_ix_begin(&nums);
- 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);
-
- c_foreach (i, clist_ix, nums)
- printf("sorted: %d\n", *i.ref);
- }
-}
-
-#define i_key int
-#define i_tag i
-#include <stc/cset.h>
-
-void setdemo1()
-{
- printf("\nSETDEMO1\n");
- cset_i nums = cset_i_init();
- cset_i_insert(&nums, 8);
- cset_i_insert(&nums, 11);
-
- c_foreach (i, cset_i, nums)
- printf("set: %d\n", *i.ref);
- cset_i_drop(&nums);
-}
-
-#define i_key int
-#define i_val int
-#define i_tag ii
-#include <stc/cmap.h>
-
-void mapdemo1()
-{
- printf("\nMAPDEMO1\n");
- cmap_ii nums = cmap_ii_init();
- cmap_ii_insert(&nums, 8, 64);
- cmap_ii_insert(&nums, 11, 121);
- printf("val 8: %d\n", *cmap_ii_at(&nums, 8));
- cmap_ii_drop(&nums);
-}
-
-#define i_key_str
-#define i_val int
-#define i_tag si
-#include <stc/cmap.h>
-
-void mapdemo2()
-{
- printf("\nMAPDEMO2\n");
- c_auto (cmap_si, nums)
- {
- cmap_si_emplace_or_assign(&nums, "Hello", 64);
- cmap_si_emplace_or_assign(&nums, "Groovy", 121);
- cmap_si_emplace_or_assign(&nums, "Groovy", 200); // overwrite previous
-
- // iterate the map:
- for (cmap_si_iter i = cmap_si_begin(&nums); i.ref != cmap_si_end(&nums).ref; cmap_si_next(&i))
- printf("long: %s: %d\n", cstr_str(&i.ref->first), i.ref->second);
-
- // or rather use the short form:
- c_foreach (i, cmap_si, nums)
- printf("short: %s: %d\n", cstr_str(&i.ref->first), i.ref->second);
- }
-}
-
-#define i_key_str
-#define i_val_str
-#include <stc/cmap.h>
-
-void mapdemo3()
-{
- printf("\nMAPDEMO3\n");
- cmap_str table = cmap_str_init();
- cmap_str_emplace(&table, "Map", "test");
- cmap_str_emplace(&table, "Make", "my");
- cmap_str_emplace(&table, "Sunny", "day");
- cmap_str_iter it = cmap_str_find(&table, "Make");
- c_foreach (i, cmap_str, table)
- printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
- printf("size %" PRIuMAX ": remove: Make: %s\n", cmap_str_size(table), cstr_str(&it.ref->second));
- //cmap_str_erase(&table, "Make");
- cmap_str_erase_at(&table, it);
-
- printf("size %" PRIuMAX "\n", cmap_str_size(table));
- c_foreach (i, cmap_str, table)
- printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
- cmap_str_drop(&table); // frees key and value cstrs, and hash table.
-}
-
-#define i_val float
-#define i_tag f
-#include <stc/carr3.h>
-
-void arraydemo1()
-{
- printf("\nARRAYDEMO1\n");
- c_autovar (carr3_f arr3 = carr3_f_with_size(30, 20, 10, 0.0f),
- carr3_f_drop(&arr3))
- {
- arr3.data[5][4][3] = 10.2f;
- float **arr2 = arr3.data[5];
- float *arr1 = arr3.data[5][4];
-
- printf("arr3: %" PRIuMAX ": (%" PRIuMAX ", %" PRIuMAX ", %" PRIuMAX ") = %" PRIuMAX "\n", sizeof(arr3),
- arr3.xdim, arr3.ydim, arr3.zdim, carr3_f_size(arr3));
-
- 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
-
- 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();
- vectordemo1();
- vectordemo2();
- listdemo1();
- setdemo1();
- mapdemo1();
- mapdemo2();
- mapdemo3();
- arraydemo1();
-}
+#define i_implement
+#include <stc/cstr.h>
+
+void stringdemo1()
+{
+ printf("\nSTRINGDEMO1\n");
+ c_autovar (cstr cs = cstr_new("one-nine-three-seven-five"), cstr_drop(&cs))
+ {
+ printf("%s.\n", cstr_str(&cs));
+
+ cstr_insert(&cs, 3, "-two");
+ printf("%s.\n", cstr_str(&cs));
+
+ cstr_erase_n(&cs, 7, 5); // -nine
+ printf("%s.\n", cstr_str(&cs));
+
+ cstr_replace_one(&cs, 0, "seven", "four");
+ printf("%s.\n", cstr_str(&cs));
+
+ cstr_take(&cs, cstr_from_fmt("%s *** %s", cstr_str(&cs), cstr_str(&cs)));
+ printf("%s.\n", cstr_str(&cs));
+
+ printf("find \"four\": %s\n", cstr_str(&cs) + cstr_find(cs, "four"));
+
+ // reassign:
+ cstr_assign(&cs, "one two three four five six seven");
+ cstr_append(&cs, " eight");
+ printf("append: %s\n", cstr_str(&cs));
+ }
+}
+
+#define i_val int64_t
+#define i_tag ix
+#include <stc/cvec.h>
+
+void vectordemo1()
+{
+ printf("\nVECTORDEMO1\n");
+ c_autovar (cvec_ix bignums = cvec_ix_with_capacity(100), cvec_ix_drop(&bignums))
+ {
+ cvec_ix_reserve(&bignums, 100);
+ for (size_t i = 10; i <= 100; i += 10)
+ cvec_ix_push_back(&bignums, i * i);
+
+ printf("erase - %d: %" PRIuMAX "\n", 3, bignums.data[3]);
+ cvec_ix_erase_n(&bignums, 3, 1); // erase index 3
+
+ cvec_ix_pop_back(&bignums); // erase the last
+ cvec_ix_erase_n(&bignums, 0, 1); // erase the first
+
+ for (size_t i = 0; i < cvec_ix_size(bignums); ++i) {
+ printf("%" PRIuMAX ": %" PRIuMAX "\n", i, bignums.data[i]);
+ }
+ }
+}
+
+#define i_val_str
+#include <stc/cvec.h>
+
+void vectordemo2()
+{
+ printf("\nVECTORDEMO2\n");
+ c_auto (cvec_str, names) {
+ cvec_str_emplace_back(&names, "Mary");
+ cvec_str_emplace_back(&names, "Joe");
+ cvec_str_emplace_back(&names, "Chris");
+ cstr_assign(&names.data[1], "Jane"); // replace Joe
+ printf("names[1]: %s\n", cstr_str(&names.data[1]));
+
+ cvec_str_sort(&names); // Sort the array
+ c_foreach (i, cvec_str, names)
+ printf("sorted: %s\n", cstr_str(i.ref));
+ }
+}
+
+#define i_val int
+#define i_tag ix
+#define i_extern // define _clist_mergesort() once
+#include <stc/clist.h>
+
+void listdemo1()
+{
+ printf("\nLISTDEMO1\n");
+ c_auto (clist_ix, nums, nums2)
+ {
+ for (int i = 0; i < 10; ++i)
+ clist_ix_push_back(&nums, i);
+ for (int i = 100; i < 110; ++i)
+ clist_ix_push_back(&nums2, i);
+
+ /* splice nums2 to front of nums */
+ clist_ix_splice(&nums, clist_ix_begin(&nums), &nums2);
+ c_foreach (i, clist_ix, nums)
+ printf("spliced: %d\n", *i.ref);
+ puts("");
+
+ *clist_ix_find(&nums, 104).ref += 50;
+ clist_ix_remove(&nums, 103);
+ clist_ix_iter it = clist_ix_begin(&nums);
+ 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);
+
+ c_foreach (i, clist_ix, nums)
+ printf("sorted: %d\n", *i.ref);
+ }
+}
+
+#define i_key int
+#define i_tag i
+#include <stc/cset.h>
+
+void setdemo1()
+{
+ printf("\nSETDEMO1\n");
+ cset_i nums = cset_i_init();
+ cset_i_insert(&nums, 8);
+ cset_i_insert(&nums, 11);
+
+ c_foreach (i, cset_i, nums)
+ printf("set: %d\n", *i.ref);
+ cset_i_drop(&nums);
+}
+
+#define i_key int
+#define i_val int
+#define i_tag ii
+#include <stc/cmap.h>
+
+void mapdemo1()
+{
+ printf("\nMAPDEMO1\n");
+ cmap_ii nums = cmap_ii_init();
+ cmap_ii_insert(&nums, 8, 64);
+ cmap_ii_insert(&nums, 11, 121);
+ printf("val 8: %d\n", *cmap_ii_at(&nums, 8));
+ cmap_ii_drop(&nums);
+}
+
+#define i_key_str
+#define i_val int
+#define i_tag si
+#include <stc/cmap.h>
+
+void mapdemo2()
+{
+ printf("\nMAPDEMO2\n");
+ c_auto (cmap_si, nums)
+ {
+ cmap_si_emplace_or_assign(&nums, "Hello", 64);
+ cmap_si_emplace_or_assign(&nums, "Groovy", 121);
+ cmap_si_emplace_or_assign(&nums, "Groovy", 200); // overwrite previous
+
+ // iterate the map:
+ for (cmap_si_iter i = cmap_si_begin(&nums); i.ref != cmap_si_end(&nums).ref; cmap_si_next(&i))
+ printf("long: %s: %d\n", cstr_str(&i.ref->first), i.ref->second);
+
+ // or rather use the short form:
+ c_foreach (i, cmap_si, nums)
+ printf("short: %s: %d\n", cstr_str(&i.ref->first), i.ref->second);
+ }
+}
+
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
+
+void mapdemo3()
+{
+ printf("\nMAPDEMO3\n");
+ cmap_str table = cmap_str_init();
+ cmap_str_emplace(&table, "Map", "test");
+ cmap_str_emplace(&table, "Make", "my");
+ cmap_str_emplace(&table, "Sunny", "day");
+ cmap_str_iter it = cmap_str_find(&table, "Make");
+ c_foreach (i, cmap_str, table)
+ printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
+ printf("size %" PRIuMAX ": remove: Make: %s\n", cmap_str_size(table), cstr_str(&it.ref->second));
+ //cmap_str_erase(&table, "Make");
+ cmap_str_erase_at(&table, it);
+
+ printf("size %" PRIuMAX "\n", cmap_str_size(table));
+ c_foreach (i, cmap_str, table)
+ printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
+ cmap_str_drop(&table); // frees key and value cstrs, and hash table.
+}
+
+#define i_val float
+#define i_tag f
+#include <stc/carr3.h>
+
+void arraydemo1()
+{
+ printf("\nARRAYDEMO1\n");
+ c_autovar (carr3_f arr3 = carr3_f_with_size(30, 20, 10, 0.0f),
+ carr3_f_drop(&arr3))
+ {
+ arr3.data[5][4][3] = 10.2f;
+ float **arr2 = arr3.data[5];
+ float *arr1 = arr3.data[5][4];
+
+ printf("arr3: %" PRIuMAX ": (%" PRIuMAX ", %" PRIuMAX ", %" PRIuMAX ") = %" PRIuMAX "\n", sizeof(arr3),
+ arr3.xdim, arr3.ydim, arr3.zdim, carr3_f_size(arr3));
+
+ 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
+
+ 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();
+ vectordemo1();
+ vectordemo2();
+ listdemo1();
+ setdemo1();
+ mapdemo1();
+ mapdemo2();
+ mapdemo3();
+ arraydemo1();
+}
diff --git a/examples/gauss1.c b/examples/gauss1.c
index cca38953..75d5567e 100644
--- a/examples/gauss1.c
+++ b/examples/gauss1.c
@@ -1,57 +1,57 @@
-#include <time.h>
-#include <math.h>
-
-#define STC_IMPLEMENT
-#include <stc/crandom.h>
-#include <stc/cstr.h>
-
-// Declare int -> int hashmap. Uses typetag 'ii' for ints.
-#define i_key int
-#define i_val int
-#define i_tag ii
-#include <stc/cmap.h>
-
-// Declare int vector with entries from the cmap.
-#define i_val cmap_ii_raw
-#define i_less(x, y) x->first < y->first
-#define i_tag ii
-#include <stc/cvec.h>
-
-int main()
-{
- enum {N = 10000000};
- const double Mean = -12.0, StdDev = 6.0, Scale = 74;
-
- printf("Demo of gaussian / normal distribution of %d random samples\n", N);
-
- // Setup random engine with normal distribution.
- uint64_t seed = time(NULL);
- stc64_t rng = stc64_new(seed);
- stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev);
-
- // Create and init histogram vec and map with defered destructors:
- c_auto (cvec_ii, histvec)
- c_auto (cmap_ii, histmap)
- {
- c_forrange (N) {
- int index = (int) round( stc64_normalf(&rng, &dist) );
- cmap_ii_insert(&histmap, index, 0).ref->second += 1;
- }
-
- // Transfer map to vec and sort it by map keys.
- c_foreach (i, cmap_ii, histmap)
- cvec_ii_push_back(&histvec, (cmap_ii_raw){i.ref->first, i.ref->second});
-
- cvec_ii_sort(&histvec);
-
- // Print the gaussian bar chart
- c_auto (cstr, bar)
- c_foreach (i, cvec_ii, histvec) {
- size_t n = (size_t) (i.ref->second * StdDev * Scale * 2.5 / (float)N);
- if (n > 0) {
- cstr_resize(&bar, n, '*');
- printf("%4d %s\n", i.ref->first, cstr_str(&bar));
- }
- }
- }
-}
+#include <time.h>
+#include <math.h>
+
+#define STC_IMPLEMENT
+#include <stc/crandom.h>
+#include <stc/cstr.h>
+
+// Declare int -> int hashmap. Uses typetag 'ii' for ints.
+#define i_key int
+#define i_val int
+#define i_tag ii
+#include <stc/cmap.h>
+
+// Declare int vector with entries from the cmap.
+#define i_val cmap_ii_raw
+#define i_less(x, y) x->first < y->first
+#define i_tag ii
+#include <stc/cvec.h>
+
+int main()
+{
+ enum {N = 10000000};
+ const double Mean = -12.0, StdDev = 6.0, Scale = 74;
+
+ printf("Demo of gaussian / normal distribution of %d random samples\n", N);
+
+ // Setup random engine with normal distribution.
+ uint64_t seed = time(NULL);
+ stc64_t rng = stc64_new(seed);
+ stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev);
+
+ // Create and init histogram vec and map with defered destructors:
+ c_auto (cvec_ii, histvec)
+ c_auto (cmap_ii, histmap)
+ {
+ c_forrange (N) {
+ int index = (int) round( stc64_normalf(&rng, &dist) );
+ cmap_ii_insert(&histmap, index, 0).ref->second += 1;
+ }
+
+ // Transfer map to vec and sort it by map keys.
+ c_foreach (i, cmap_ii, histmap)
+ cvec_ii_push_back(&histvec, (cmap_ii_raw){i.ref->first, i.ref->second});
+
+ cvec_ii_sort(&histvec);
+
+ // Print the gaussian bar chart
+ c_auto (cstr, bar)
+ c_foreach (i, cvec_ii, histvec) {
+ size_t n = (size_t) (i.ref->second * StdDev * Scale * 2.5 / (float)N);
+ if (n > 0) {
+ cstr_resize(&bar, n, '*');
+ printf("%4d %s\n", i.ref->first, cstr_str(&bar));
+ }
+ }
+ }
+}
diff --git a/examples/gauss2.c b/examples/gauss2.c
index 297b8616..2e07c5a5 100644
--- a/examples/gauss2.c
+++ b/examples/gauss2.c
@@ -1,43 +1,43 @@
-#include <stdio.h>
-#include <time.h>
-
-#define STC_IMPLEMENT
-#include <stc/crandom.h>
-#include <stc/cstr.h>
-
-// Declare int -> int sorted map.
-#define i_key int
-#define i_val size_t
-#include <stc/csmap.h>
-
-int main()
-{
- enum {N = 10000000};
- const double Mean = -12.0, StdDev = 6.0, Scale = 74;
-
- printf("Demo of gaussian / normal distribution of %d random samples\n", N);
-
- // Setup random engine with normal distribution.
- uint64_t seed = time(NULL);
- stc64_t rng = stc64_new(seed);
- stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev);
-
- // Create and init histogram map with defered destruct
- c_auto (csmap_int, mhist)
- {
- c_forrange (N) {
- int index = (int) round( stc64_normalf(&rng, &dist) );
- csmap_int_insert(&mhist, index, 0).ref->second += 1;
- }
-
- // Print the gaussian bar chart
- c_auto (cstr, bar)
- c_forpair (index, count, csmap_int, mhist) {
- size_t n = (size_t) (*_.count * StdDev * Scale * 2.5 / (float)N);
- if (n > 0) {
- cstr_resize(&bar, n, '*');
- printf("%4d %s\n", *_.index, cstr_str(&bar));
- }
- }
- }
-}
+#include <stdio.h>
+#include <time.h>
+
+#define STC_IMPLEMENT
+#include <stc/crandom.h>
+#include <stc/cstr.h>
+
+// Declare int -> int sorted map.
+#define i_key int
+#define i_val size_t
+#include <stc/csmap.h>
+
+int main()
+{
+ enum {N = 10000000};
+ const double Mean = -12.0, StdDev = 6.0, Scale = 74;
+
+ printf("Demo of gaussian / normal distribution of %d random samples\n", N);
+
+ // Setup random engine with normal distribution.
+ uint64_t seed = time(NULL);
+ stc64_t rng = stc64_new(seed);
+ stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev);
+
+ // Create and init histogram map with defered destruct
+ c_auto (csmap_int, mhist)
+ {
+ c_forrange (N) {
+ int index = (int) round( stc64_normalf(&rng, &dist) );
+ csmap_int_insert(&mhist, index, 0).ref->second += 1;
+ }
+
+ // Print the gaussian bar chart
+ c_auto (cstr, bar)
+ c_forpair (index, count, csmap_int, mhist) {
+ size_t n = (size_t) (*_.count * StdDev * Scale * 2.5 / (float)N);
+ if (n > 0) {
+ cstr_resize(&bar, n, '*');
+ printf("%4d %s\n", *_.index, cstr_str(&bar));
+ }
+ }
+ }
+}
diff --git a/examples/hashmap.c b/examples/hashmap.c
index 62f20079..ab980045 100644
--- a/examples/hashmap.c
+++ b/examples/hashmap.c
@@ -1,49 +1,49 @@
-// https://doc.rust-lang.org/rust-by-example/std/hash.html
-#define i_implement
-#include <stc/cstr.h>
-#define i_key_str
-#define i_val_str
-#include <stdio.h>
-#include <stc/cmap.h>
-
-const char* call(const char* number) {
- if (!strcmp(number, "798-1364"))
- return "We're sorry, the call cannot be completed as dialed."
- " Please hang up and try again.";
- else if (!strcmp(number, "645-7689"))
- return "Hello, this is Mr. Awesome's Pizza. My name is Fred."
- " What can I get for you today?";
- else
- return "Hi! Who is this again?";
-}
-
-int main(void) {
- c_auto (cmap_str, contacts)
- {
- cmap_str_emplace(&contacts, "Daniel", "798-1364");
- cmap_str_emplace(&contacts, "Ashley", "645-7689");
- cmap_str_emplace(&contacts, "Katie", "435-8291");
- cmap_str_emplace(&contacts, "Robert", "956-1745");
-
- const cmap_str_value* v;
- if ((v = cmap_str_get(&contacts, "Daniel")))
- printf("Calling Daniel: %s\n", call(cstr_str(&v->second)));
- else
- printf("Don't have Daniel's number.");
-
- cmap_str_emplace(&contacts, "Daniel", "164-6743");
-
- if ((v = cmap_str_get(&contacts, "Ashley")))
- printf("Calling Ashley: %s\n", call(cstr_str(&v->second)));
- else
- printf("Don't have Ashley's number.");
-
- cmap_str_erase(&contacts, "Ashley");
-
- puts("");
- c_forpair (contact, number, cmap_str, contacts) {
- printf("Calling %s: %s\n", cstr_str(_.contact), call(cstr_str(_.number)));
- }
- puts("");
- }
-}
+// https://doc.rust-lang.org/rust-by-example/std/hash.html
+#define i_implement
+#include <stc/cstr.h>
+#define i_key_str
+#define i_val_str
+#include <stdio.h>
+#include <stc/cmap.h>
+
+const char* call(const char* number) {
+ if (!strcmp(number, "798-1364"))
+ return "We're sorry, the call cannot be completed as dialed."
+ " Please hang up and try again.";
+ else if (!strcmp(number, "645-7689"))
+ return "Hello, this is Mr. Awesome's Pizza. My name is Fred."
+ " What can I get for you today?";
+ else
+ return "Hi! Who is this again?";
+}
+
+int main(void) {
+ c_auto (cmap_str, contacts)
+ {
+ cmap_str_emplace(&contacts, "Daniel", "798-1364");
+ cmap_str_emplace(&contacts, "Ashley", "645-7689");
+ cmap_str_emplace(&contacts, "Katie", "435-8291");
+ cmap_str_emplace(&contacts, "Robert", "956-1745");
+
+ const cmap_str_value* v;
+ if ((v = cmap_str_get(&contacts, "Daniel")))
+ printf("Calling Daniel: %s\n", call(cstr_str(&v->second)));
+ else
+ printf("Don't have Daniel's number.");
+
+ cmap_str_emplace(&contacts, "Daniel", "164-6743");
+
+ if ((v = cmap_str_get(&contacts, "Ashley")))
+ printf("Calling Ashley: %s\n", call(cstr_str(&v->second)));
+ else
+ printf("Don't have Ashley's number.");
+
+ cmap_str_erase(&contacts, "Ashley");
+
+ puts("");
+ c_forpair (contact, number, cmap_str, contacts) {
+ printf("Calling %s: %s\n", cstr_str(_.contact), call(cstr_str(_.number)));
+ }
+ puts("");
+ }
+}
diff --git a/examples/inits.c b/examples/inits.c
index 26f4b286..1013da36 100644
--- a/examples/inits.c
+++ b/examples/inits.c
@@ -1,114 +1,114 @@
-#define i_implement
-#include <stc/cstr.h>
-
-#define i_key int
-#define i_val_str
-#define i_tag id // Map of int => cstr
-#include <stc/cmap.h>
-
-#define i_key_str
-#define i_val int
-#define i_tag cnt // Map of cstr => int
-#include <stc/cmap.h>
-
-typedef struct {int x, y;} ipair_t;
-inline static int ipair_cmp(const ipair_t* a, const ipair_t* b) {
- int c = c_default_cmp(&a->x, &b->x);
- return c ? c : c_default_cmp(&a->y, &b->y);
-}
-
-
-#define i_val ipair_t
-#define i_cmp ipair_cmp
-#define i_tag ip
-#include <stc/cvec.h>
-
-#define i_val ipair_t
-#define i_cmp ipair_cmp
-#define i_tag ip
-#define i_extern // define _clist_mergesort() once
-#include <stc/clist.h>
-
-#define i_val float
-#define i_tag f
-#include <stc/cpque.h>
-
-int main(void)
-{
- // CVEC FLOAT / PRIORITY QUEUE
-
- c_auto (cpque_f, floats) {
- const float nums[] = {4.0f, 2.0f, 5.0f, 3.0f, 1.0f};
-
- // PRIORITY QUEUE
-
- c_apply_arr(v, cpque_f_push(&floats, *v), const float, nums, c_arraylen(nums));
-
- puts("\npop and show high priorites first:");
- while (! cpque_f_empty(floats)) {
- printf("%.1f ", *cpque_f_top(&floats));
- cpque_f_pop(&floats);
- }
- puts("\n");
- }
-
- // CMAP ID
-
- int year = 2020;
- c_auto (cmap_id, idnames) {
- cmap_id_emplace(&idnames, 100, "Hello");
- cmap_id_insert(&idnames, 110, cstr_new("World"));
- cmap_id_insert(&idnames, 120, cstr_from_fmt("Howdy, -%d-", year));
-
- c_foreach (i, cmap_id, idnames)
- printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second));
- puts("");
- }
-
- // CMAP CNT
-
- c_auto (cmap_cnt, countries) {
- c_apply(v, cmap_cnt_emplace(&countries, c_pair(v)), cmap_cnt_raw, {
- {"Norway", 100},
- {"Denmark", 50},
- {"Iceland", 10},
- {"Belgium", 10},
- {"Italy", 10},
- {"Germany", 10},
- {"Spain", 10},
- {"France", 10},
- });
- cmap_cnt_emplace(&countries, "Greenland", 0).ref->second += 20;
- cmap_cnt_emplace(&countries, "Sweden", 0).ref->second += 20;
- cmap_cnt_emplace(&countries, "Norway", 0).ref->second += 20;
- cmap_cnt_emplace(&countries, "Finland", 0).ref->second += 20;
-
- c_forpair (country, health, cmap_cnt, countries)
- printf("%s: %d\n", cstr_str(_.country), *_.health);
- puts("");
- }
-
- // CVEC PAIR
-
- c_auto (cvec_ip, pairs1) {
- c_apply(p, cvec_ip_push_back(&pairs1, *p), ipair_t,
- {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
- cvec_ip_sort(&pairs1);
-
- c_foreach (i, cvec_ip, pairs1)
- printf("(%d %d) ", i.ref->x, i.ref->y);
- puts("");
- }
-
- // CLIST PAIR
-
- c_auto (clist_ip, pairs2) {
- c_apply(p, clist_ip_push_back(&pairs2, *p), ipair_t,
- {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
- clist_ip_sort(&pairs2);
-
- c_foreach (i, clist_ip, pairs2)
- printf("(%d %d) ", i.ref->x, i.ref->y);
- puts("");
- }
-}
+#define i_implement
+#include <stc/cstr.h>
+
+#define i_key int
+#define i_val_str
+#define i_tag id // Map of int => cstr
+#include <stc/cmap.h>
+
+#define i_key_str
+#define i_val int
+#define i_tag cnt // Map of cstr => int
+#include <stc/cmap.h>
+
+typedef struct {int x, y;} ipair_t;
+inline static int ipair_cmp(const ipair_t* a, const ipair_t* b) {
+ int c = c_default_cmp(&a->x, &b->x);
+ return c ? c : c_default_cmp(&a->y, &b->y);
+}
+
+
+#define i_val ipair_t
+#define i_cmp ipair_cmp
+#define i_tag ip
+#include <stc/cvec.h>
+
+#define i_val ipair_t
+#define i_cmp ipair_cmp
+#define i_tag ip
+#define i_extern // define _clist_mergesort() once
+#include <stc/clist.h>
+
+#define i_val float
+#define i_tag f
+#include <stc/cpque.h>
+
+int main(void)
+{
+ // CVEC FLOAT / PRIORITY QUEUE
+
+ c_auto (cpque_f, floats) {
+ const float nums[] = {4.0f, 2.0f, 5.0f, 3.0f, 1.0f};
+
+ // PRIORITY QUEUE
+
+ c_apply_arr(v, cpque_f_push(&floats, *v), const float, nums, c_arraylen(nums));
+
+ puts("\npop and show high priorites first:");
+ while (! cpque_f_empty(floats)) {
+ printf("%.1f ", *cpque_f_top(&floats));
+ cpque_f_pop(&floats);
+ }
+ puts("\n");
+ }
+
+ // CMAP ID
+
+ int year = 2020;
+ c_auto (cmap_id, idnames) {
+ cmap_id_emplace(&idnames, 100, "Hello");
+ cmap_id_insert(&idnames, 110, cstr_new("World"));
+ cmap_id_insert(&idnames, 120, cstr_from_fmt("Howdy, -%d-", year));
+
+ c_foreach (i, cmap_id, idnames)
+ printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second));
+ puts("");
+ }
+
+ // CMAP CNT
+
+ c_auto (cmap_cnt, countries) {
+ c_apply(v, cmap_cnt_emplace(&countries, c_pair(v)), cmap_cnt_raw, {
+ {"Norway", 100},
+ {"Denmark", 50},
+ {"Iceland", 10},
+ {"Belgium", 10},
+ {"Italy", 10},
+ {"Germany", 10},
+ {"Spain", 10},
+ {"France", 10},
+ });
+ cmap_cnt_emplace(&countries, "Greenland", 0).ref->second += 20;
+ cmap_cnt_emplace(&countries, "Sweden", 0).ref->second += 20;
+ cmap_cnt_emplace(&countries, "Norway", 0).ref->second += 20;
+ cmap_cnt_emplace(&countries, "Finland", 0).ref->second += 20;
+
+ c_forpair (country, health, cmap_cnt, countries)
+ printf("%s: %d\n", cstr_str(_.country), *_.health);
+ puts("");
+ }
+
+ // CVEC PAIR
+
+ c_auto (cvec_ip, pairs1) {
+ c_apply(p, cvec_ip_push_back(&pairs1, *p), ipair_t,
+ {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
+ cvec_ip_sort(&pairs1);
+
+ c_foreach (i, cvec_ip, pairs1)
+ printf("(%d %d) ", i.ref->x, i.ref->y);
+ puts("");
+ }
+
+ // CLIST PAIR
+
+ c_auto (clist_ip, pairs2) {
+ c_apply(p, clist_ip_push_back(&pairs2, *p), ipair_t,
+ {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
+ clist_ip_sort(&pairs2);
+
+ c_foreach (i, clist_ip, pairs2)
+ printf("(%d %d) ", i.ref->x, i.ref->y);
+ puts("");
+ }
+}
diff --git a/examples/list.c b/examples/list.c
index 7d6d1a50..17ed048d 100644
--- a/examples/list.c
+++ b/examples/list.c
@@ -1,61 +1,61 @@
-#include <stdio.h>
-#include <time.h>
-
-#define STC_IMPLEMENT
-#define STC_EXTERN
-
-#define i_val double
-#define i_tag fx
-#include <stc/clist.h>
-#include <stc/crandom.h>
-
-int main() {
- int k;
- const int n = 2000000;
-
- c_auto (clist_fx, list)
- {
- stc64_t rng = stc64_new(1234);
- stc64_uniformf_t dist = stc64_uniformf_new(100.0f, n);
- int m = 0;
- c_forrange (i, int, n)
- clist_fx_push_back(&list, stc64_uniformf(&rng, &dist)), ++m;
- double sum = 0.0;
- printf("sumarize %d:\n", m);
- c_foreach (i, clist_fx, list)
- sum += *i.ref;
- printf("sum %f\n\n", sum);
-
- k = 0;
- c_foreach (i, clist_fx, list)
- if (++k <= 10) printf("%8d: %10f\n", k, *i.ref); else break;
- puts("sort");
- clist_fx_sort(&list); // mergesort O(n*log n)
- puts("sorted");
-
- k = 0;
- c_foreach (i, clist_fx, list)
- if (++k <= 10) printf("%8d: %10f\n", k, *i.ref); else break;
- puts("");
-
- clist_fx_clear(&list);
- c_apply(v, clist_fx_push_back(&list, *v), int, {10, 20, 30, 40, 30, 50});
- const double* v = clist_fx_get(&list, 30);
- printf("found: %f\n", *v);
- c_foreach (i, clist_fx, list) printf(" %g", *i.ref);
- puts("");
-
- clist_fx_remove(&list, 30);
- clist_fx_insert_at(&list, clist_fx_begin(&list), 5); // same as push_front()
- clist_fx_push_back(&list, 500);
- clist_fx_push_front(&list, 1964);
- clist_fx_iter it = clist_fx_begin(&list);
- printf("Full: ");
- c_foreach (i, clist_fx, list)
- printf(" %g", *i.ref);
- printf("\nSubs: ");
- c_foreach (i, clist_fx, clist_fx_advance(it, 4), clist_fx_end(&list))
- printf(" %g", *i.ref);
- puts("");
- }
-}
+#include <stdio.h>
+#include <time.h>
+
+#define STC_IMPLEMENT
+#define STC_EXTERN
+
+#define i_val double
+#define i_tag fx
+#include <stc/clist.h>
+#include <stc/crandom.h>
+
+int main() {
+ int k;
+ const int n = 2000000;
+
+ c_auto (clist_fx, list)
+ {
+ stc64_t rng = stc64_new(1234);
+ stc64_uniformf_t dist = stc64_uniformf_new(100.0f, n);
+ int m = 0;
+ c_forrange (i, int, n)
+ clist_fx_push_back(&list, stc64_uniformf(&rng, &dist)), ++m;
+ double sum = 0.0;
+ printf("sumarize %d:\n", m);
+ c_foreach (i, clist_fx, list)
+ sum += *i.ref;
+ printf("sum %f\n\n", sum);
+
+ k = 0;
+ c_foreach (i, clist_fx, list)
+ if (++k <= 10) printf("%8d: %10f\n", k, *i.ref); else break;
+ puts("sort");
+ clist_fx_sort(&list); // mergesort O(n*log n)
+ puts("sorted");
+
+ k = 0;
+ c_foreach (i, clist_fx, list)
+ if (++k <= 10) printf("%8d: %10f\n", k, *i.ref); else break;
+ puts("");
+
+ clist_fx_clear(&list);
+ c_apply(v, clist_fx_push_back(&list, *v), int, {10, 20, 30, 40, 30, 50});
+ const double* v = clist_fx_get(&list, 30);
+ printf("found: %f\n", *v);
+ c_foreach (i, clist_fx, list) printf(" %g", *i.ref);
+ puts("");
+
+ clist_fx_remove(&list, 30);
+ clist_fx_insert_at(&list, clist_fx_begin(&list), 5); // same as push_front()
+ clist_fx_push_back(&list, 500);
+ clist_fx_push_front(&list, 1964);
+ clist_fx_iter it = clist_fx_begin(&list);
+ printf("Full: ");
+ c_foreach (i, clist_fx, list)
+ printf(" %g", *i.ref);
+ printf("\nSubs: ");
+ 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 19a00299..ad062131 100644
--- a/examples/list_erase.c
+++ b/examples/list_erase.c
@@ -1,29 +1,29 @@
-// erasing from clist
-#include <stdio.h>
-
-#define i_val int
-#include <stc/clist.h>
-
-int main ()
-{
- c_auto (clist_int, L)
- {
- c_apply(i, clist_int_push_back(&L, *i), int, {10, 20, 30, 40, 50});
- c_foreach (x, clist_int, L)
- printf("%d ", *x.ref);
- puts("");
- // 10 20 30 40 50
- clist_int_iter it = clist_int_begin(&L); // ^
- clist_int_next(&it);
- it = clist_int_erase_at(&L, it); // 10 30 40 50
- // ^
- clist_int_iter end = clist_int_end(&L); //
- clist_int_next(&it);
- it = clist_int_erase_range(&L, it, end); // 10 30
- // ^
- printf("list contains:");
- c_foreach (x, clist_int, L)
- printf(" %d", *x.ref);
- puts("");
- }
-}
+// erasing from clist
+#include <stdio.h>
+
+#define i_val int
+#include <stc/clist.h>
+
+int main ()
+{
+ c_auto (clist_int, L)
+ {
+ c_apply(i, clist_int_push_back(&L, *i), int, {10, 20, 30, 40, 50});
+ c_foreach (x, clist_int, L)
+ printf("%d ", *x.ref);
+ puts("");
+ // 10 20 30 40 50
+ clist_int_iter it = clist_int_begin(&L); // ^
+ clist_int_next(&it);
+ it = clist_int_erase_at(&L, it); // 10 30 40 50
+ // ^
+ clist_int_iter end = clist_int_end(&L); //
+ clist_int_next(&it);
+ it = clist_int_erase_range(&L, it, end); // 10 30
+ // ^
+ printf("list contains:");
+ c_foreach (x, clist_int, L)
+ printf(" %d", *x.ref);
+ puts("");
+ }
+}
diff --git a/examples/lower_bound.c b/examples/lower_bound.c
index 6039dd48..a1de1cfd 100644
--- a/examples/lower_bound.c
+++ b/examples/lower_bound.c
@@ -1,64 +1,64 @@
-#include <stdio.h>
-
-#define i_val int
-#include <stc/cvec.h>
-
-#define i_val int
-#include <stc/csset.h>
-
-int main()
-{
- // TEST SORTED VECTOR
- c_auto (cvec_int, vec)
- {
- int key, *res;
-
- c_apply(t, cvec_int_push(&vec, *t), int, {
- 40, 600, 1, 7000, 2, 500, 30,
- });
-
- cvec_int_sort(&vec);
-
- key = 500;
- res = cvec_int_lower_bound(&vec, key).ref;
- if (res != cvec_int_end(&vec).ref)
- printf("Sorted Vec %d: lower bound: %d\n", key, *res); // 600
-
- key = 550;
- res = cvec_int_lower_bound(&vec, key).ref;
- if (res != cvec_int_end(&vec).ref)
- printf("Sorted Vec %d: lower_bound: %d\n", key, *res); // 500
-
- key = 500;
- res = cvec_int_binary_search(&vec, key).ref;
- if (res != cvec_int_end(&vec).ref)
- printf("Sorted Vec %d: bin. search: %d\n", key, *res); // 500
- puts("");
- }
-
- // TEST SORTED SET
- c_auto (csset_int, set)
- {
- int key, *res;
-
- c_apply(t, csset_int_push(&set, *t), int, {
- 40, 600, 1, 7000, 2, 500, 30,
- });
-
- key = 500;
- res = csset_int_lower_bound(&set, key).ref;
- if (res != csset_int_end(&set).ref)
- printf("Sorted Set %d: lower bound: %d\n", key, *res); // 600
-
- key = 550;
- res = csset_int_lower_bound(&set, key).ref;
- if (res != csset_int_end(&set).ref)
- printf("Sorted Set %d: lower bound: %d\n", key, *res); // 600
-
- key = 500;
- res = csset_int_find(&set, key).ref;
- if (res != csset_int_end(&set).ref)
- printf("Sorted Set %d: find : %d\n", key, *res); // 600
- }
- return 0;
-}
+#include <stdio.h>
+
+#define i_val int
+#include <stc/cvec.h>
+
+#define i_val int
+#include <stc/csset.h>
+
+int main()
+{
+ // TEST SORTED VECTOR
+ c_auto (cvec_int, vec)
+ {
+ int key, *res;
+
+ c_apply(t, cvec_int_push(&vec, *t), int, {
+ 40, 600, 1, 7000, 2, 500, 30,
+ });
+
+ cvec_int_sort(&vec);
+
+ key = 500;
+ res = cvec_int_lower_bound(&vec, key).ref;
+ if (res != cvec_int_end(&vec).ref)
+ printf("Sorted Vec %d: lower bound: %d\n", key, *res); // 600
+
+ key = 550;
+ res = cvec_int_lower_bound(&vec, key).ref;
+ if (res != cvec_int_end(&vec).ref)
+ printf("Sorted Vec %d: lower_bound: %d\n", key, *res); // 500
+
+ key = 500;
+ res = cvec_int_binary_search(&vec, key).ref;
+ if (res != cvec_int_end(&vec).ref)
+ printf("Sorted Vec %d: bin. search: %d\n", key, *res); // 500
+ puts("");
+ }
+
+ // TEST SORTED SET
+ c_auto (csset_int, set)
+ {
+ int key, *res;
+
+ c_apply(t, csset_int_push(&set, *t), int, {
+ 40, 600, 1, 7000, 2, 500, 30,
+ });
+
+ key = 500;
+ res = csset_int_lower_bound(&set, key).ref;
+ if (res != csset_int_end(&set).ref)
+ printf("Sorted Set %d: lower bound: %d\n", key, *res); // 600
+
+ key = 550;
+ res = csset_int_lower_bound(&set, key).ref;
+ if (res != csset_int_end(&set).ref)
+ printf("Sorted Set %d: lower bound: %d\n", key, *res); // 600
+
+ key = 500;
+ res = csset_int_find(&set, key).ref;
+ if (res != csset_int_end(&set).ref)
+ printf("Sorted Set %d: find : %d\n", key, *res); // 600
+ }
+ return 0;
+}
diff --git a/examples/mapmap.c b/examples/mapmap.c
index 9ac22371..ab48ecc6 100644
--- a/examples/mapmap.c
+++ b/examples/mapmap.c
@@ -1,73 +1,73 @@
-// unordered_map<string, unordered_map<string, string>>:
-#define i_implement
-#include <stc/cstr.h>
-#define i_type People
-#define i_key_str
-#define i_val_str
-#define i_keydrop(p) (printf("kdrop: %s\n", cstr_str(p)), cstr_drop(p)) // override
-#include <stc/csmap.h>
-
-#define i_type Departments
-#define i_key_str
-#define i_val_bind People
-// Shorthand for:
-// #define i_val People
-// #define i_cmp People_cmp
-// #define i_valclone People_clone
-// #define i_valdrop People_drop
-#include <stc/csmap.h>
-
-#define i_type Stack
-#define i_val_bind People_value
-// Shorthand for:
-// #define i_val People_value (pair of cstr)
-// #define i_cmp People_value_cmp
-// #define i_valclone People_value_clone
-// #define i_valdrop People_value_drop
-#include <stc/cvec.h>
-
-void add(Departments* deps, const char* name, const char* email, const char* dep)
-{
- People *people = &Departments_insert(deps, cstr_from(dep), People_init()).ref->second;
- People_emplace_or_assign(people, name, email);
-}
-
-int contains(Departments* map, const char* name)
-{
- int count = 0;
- c_foreach (i, Departments, *map)
- if (People_contains(&i.ref->second, name))
- ++count;
- return count;
-}
-
-int main(void)
-{
- c_auto (Departments, map)
- {
- add(&map, "Anna Kendro", "[email protected]", "Support");
- add(&map, "Terry Dane", "[email protected]", "Development");
- add(&map, "Kik Winston", "[email protected]", "Finance");
- add(&map, "Nancy Drew", "[email protected]", "Development");
- add(&map, "Nick Denton", "[email protected]", "Finance");
- add(&map, "Stan Whiteword", "[email protected]", "Marketing");
- add(&map, "Serena Bath", "[email protected]", "Support");
- add(&map, "Patrick Dust", "[email protected]", "Finance");
- add(&map, "Red Winger", "[email protected]", "Marketing");
- add(&map, "Nick Denton", "[email protected]", "Support");
- add(&map, "Colin Turth", "[email protected]", "Support");
- add(&map, "Dennis Kay", "[email protected]", "Marketing");
- add(&map, "Anne Dickens", "[email protected]", "Development");
-
- c_foreach (i, Departments, map)
- c_forpair (name, email, People, i.ref->second)
- printf("%s: %s - %s\n", cstr_str(&i.ref->first), cstr_str(_.name), cstr_str(_.email));
- puts("");
-
- printf("found: %d\n", contains(&map, "Nick Denton"));
- printf("found: %d\n", contains(&map, "Patrick Dust"));
- printf("found: %d\n", contains(&map, "Dennis Kay"));
- printf("found: %d\n", contains(&map, "Serena Bath"));
- puts("Done");
- }
-}
+// unordered_map<string, unordered_map<string, string>>:
+#define i_implement
+#include <stc/cstr.h>
+#define i_type People
+#define i_key_str
+#define i_val_str
+#define i_keydrop(p) (printf("kdrop: %s\n", cstr_str(p)), cstr_drop(p)) // override
+#include <stc/csmap.h>
+
+#define i_type Departments
+#define i_key_str
+#define i_val_bind People
+// Shorthand for:
+// #define i_val People
+// #define i_cmp People_cmp
+// #define i_valclone People_clone
+// #define i_valdrop People_drop
+#include <stc/csmap.h>
+
+#define i_type Stack
+#define i_val_bind People_value
+// Shorthand for:
+// #define i_val People_value (pair of cstr)
+// #define i_cmp People_value_cmp
+// #define i_valclone People_value_clone
+// #define i_valdrop People_value_drop
+#include <stc/cvec.h>
+
+void add(Departments* deps, const char* name, const char* email, const char* dep)
+{
+ People *people = &Departments_insert(deps, cstr_from(dep), People_init()).ref->second;
+ People_emplace_or_assign(people, name, email);
+}
+
+int contains(Departments* map, const char* name)
+{
+ int count = 0;
+ c_foreach (i, Departments, *map)
+ if (People_contains(&i.ref->second, name))
+ ++count;
+ return count;
+}
+
+int main(void)
+{
+ c_auto (Departments, map)
+ {
+ add(&map, "Anna Kendro", "[email protected]", "Support");
+ add(&map, "Terry Dane", "[email protected]", "Development");
+ add(&map, "Kik Winston", "[email protected]", "Finance");
+ add(&map, "Nancy Drew", "[email protected]", "Development");
+ add(&map, "Nick Denton", "[email protected]", "Finance");
+ add(&map, "Stan Whiteword", "[email protected]", "Marketing");
+ add(&map, "Serena Bath", "[email protected]", "Support");
+ add(&map, "Patrick Dust", "[email protected]", "Finance");
+ add(&map, "Red Winger", "[email protected]", "Marketing");
+ add(&map, "Nick Denton", "[email protected]", "Support");
+ add(&map, "Colin Turth", "[email protected]", "Support");
+ add(&map, "Dennis Kay", "[email protected]", "Marketing");
+ add(&map, "Anne Dickens", "[email protected]", "Development");
+
+ c_foreach (i, Departments, map)
+ c_forpair (name, email, People, i.ref->second)
+ printf("%s: %s - %s\n", cstr_str(&i.ref->first), cstr_str(_.name), cstr_str(_.email));
+ puts("");
+
+ printf("found: %d\n", contains(&map, "Nick Denton"));
+ printf("found: %d\n", contains(&map, "Patrick Dust"));
+ printf("found: %d\n", contains(&map, "Dennis Kay"));
+ printf("found: %d\n", contains(&map, "Serena Bath"));
+ puts("Done");
+ }
+}
diff --git a/examples/mmap.c b/examples/mmap.c
index cfb7470e..5e3eda00 100644
--- a/examples/mmap.c
+++ b/examples/mmap.c
@@ -1,76 +1,76 @@
-// This implements the multimap c++ example found at:
-// https://en.cppreference.com/w/cpp/container/multimap/insert
-
-// Multimap entries
-#define i_implement
-#include <stc/cstr.h>
-#define i_val_str
-#define i_extern // define _clist_mergesort() once
-#include <stc/clist.h>
-
-// Map of int => clist_str.
-#define i_type Multimap
-#define i_key int
-#define i_val_bind clist_str // uses clist_str as i_val and binds clist_str_clone, clist_str_drop
-#define i_cmp -c_default_cmp // like std::greater<int>
-#include <stc/csmap.h>
-
-void print(const char* lbl, const Multimap mmap)
-{
- printf("%s ", lbl);
- c_foreach (e, Multimap, mmap) {
- c_foreach (s, clist_str, e.ref->second)
- printf("{%d,%s} ", e.ref->first, cstr_str(s.ref));
- }
- puts("");
-}
-
-void insert(Multimap* mmap, int key, const char* str)
-{
- clist_str *list = &Multimap_insert(mmap, key, clist_str_init()).ref->second;
- clist_str_emplace_back(list, str);
-}
-
-int main()
-{
- c_auto (Multimap, mmap)
- {
- // list-initialize
- struct { int first; const char* second; } vals[] =
- {{2, "foo"}, {2, "bar"}, {3, "baz"}, {1, "abc"}, {5, "def"}};
- c_forrange (i, c_arraylen(vals)) insert(&mmap, c_pair(&vals[i]));
- print("#1", mmap);
-
- // insert using value_type
- insert(&mmap, 5, "pqr");
- print("#2", mmap);
-
- // insert using make_pair
- insert(&mmap, 6, "uvw");
- print("#3", mmap);
-
- insert(&mmap, 7, "xyz");
- print("#4", mmap);
-
- // insert using initialization_list
- insert(&mmap, 5, "one");
- insert(&mmap, 5, "two");
- print("#5", mmap);
-
- // FOLLOWING NOT IN ORIGINAL EXAMPLE:
-
- // erase all entries with key 5
- Multimap_erase(&mmap, 5);
- print("+6", mmap);
-
- // find and erase first entry containing "bar"
- clist_str_iter pos;
- c_foreach (e, Multimap, mmap) {
- if ((pos = clist_str_find(&e.ref->second, "bar")).ref != clist_str_end(&e.ref->second).ref) {
- clist_str_erase_at(&e.ref->second, pos);
- break;
- }
- }
- print("+7", mmap);
- }
-}
+// This implements the multimap c++ example found at:
+// https://en.cppreference.com/w/cpp/container/multimap/insert
+
+// Multimap entries
+#define i_implement
+#include <stc/cstr.h>
+#define i_val_str
+#define i_extern // define _clist_mergesort() once
+#include <stc/clist.h>
+
+// Map of int => clist_str.
+#define i_type Multimap
+#define i_key int
+#define i_val_bind clist_str // uses clist_str as i_val and binds clist_str_clone, clist_str_drop
+#define i_cmp -c_default_cmp // like std::greater<int>
+#include <stc/csmap.h>
+
+void print(const char* lbl, const Multimap mmap)
+{
+ printf("%s ", lbl);
+ c_foreach (e, Multimap, mmap) {
+ c_foreach (s, clist_str, e.ref->second)
+ printf("{%d,%s} ", e.ref->first, cstr_str(s.ref));
+ }
+ puts("");
+}
+
+void insert(Multimap* mmap, int key, const char* str)
+{
+ clist_str *list = &Multimap_insert(mmap, key, clist_str_init()).ref->second;
+ clist_str_emplace_back(list, str);
+}
+
+int main()
+{
+ c_auto (Multimap, mmap)
+ {
+ // list-initialize
+ struct { int first; const char* second; } vals[] =
+ {{2, "foo"}, {2, "bar"}, {3, "baz"}, {1, "abc"}, {5, "def"}};
+ c_forrange (i, c_arraylen(vals)) insert(&mmap, c_pair(&vals[i]));
+ print("#1", mmap);
+
+ // insert using value_type
+ insert(&mmap, 5, "pqr");
+ print("#2", mmap);
+
+ // insert using make_pair
+ insert(&mmap, 6, "uvw");
+ print("#3", mmap);
+
+ insert(&mmap, 7, "xyz");
+ print("#4", mmap);
+
+ // insert using initialization_list
+ insert(&mmap, 5, "one");
+ insert(&mmap, 5, "two");
+ print("#5", mmap);
+
+ // FOLLOWING NOT IN ORIGINAL EXAMPLE:
+
+ // erase all entries with key 5
+ Multimap_erase(&mmap, 5);
+ print("+6", mmap);
+
+ // find and erase first entry containing "bar"
+ clist_str_iter pos;
+ c_foreach (e, Multimap, mmap) {
+ if ((pos = clist_str_find(&e.ref->second, "bar")).ref != clist_str_end(&e.ref->second).ref) {
+ clist_str_erase_at(&e.ref->second, pos);
+ break;
+ }
+ }
+ print("+7", mmap);
+ }
+}
diff --git a/examples/multimap.c b/examples/multimap.c
index c2920ef4..a2d06a06 100644
--- a/examples/multimap.c
+++ b/examples/multimap.c
@@ -1,100 +1,100 @@
-#define i_implement
-#include <stc/cstr.h>
-
-// Olympics multimap example
-
-struct OlympicsData { int year; const char *city, *country, *date; } ol_data[] = {
- {2026, "Milan and Cortina d'Ampezzo", "Italy", "February 6-22"},
- {2022, "Beijing", "China", "February 4-20"},
- {2018, "PyeongChang", "South Korea", "February 9-25"},
- {2014, "Sochi", "Russia", "February 7-23"},
- {2010, "Vancouver", "Canada", "February 12-28"},
- {2006, "Torino", "Italy", "February 10-26"},
- {2002, "Salt Lake City", "United States", "February 8-24"},
- {1998, "Nagano", "Japan", "February 7-22"},
- {1994, "Lillehammer", "Norway", "February 12-27"},
- {1992, "Albertville", "France", "February 8-23"},
- {1988, "Calgary", "Canada", "February 13-28"},
- {1984, "Sarajevo", "Yugoslavia", "February 8-19"},
- {1980, "Lake Placid", "United States", "February 13-24"},
- {1976, "Innsbruck", "Austria", "February 4-15"},
- {1972, "Sapporo", "Japan", "February 3-13"},
- {1968, "Grenoble", "France", "February 6-18"},
- {1964, "Innsbruck", "Austria", "January 29-February 9"},
- {1960, "Squaw Valley", "United States", "February 18-28"},
- {1956, "Cortina d'Ampezzo", "Italy", "January 26 - February 5"},
- {1952, "Oslo", "Norway", "February 14 - 25"},
- {1948, "St. Moritz", "Switzerland", "January 30 - February 8"},
- {1944, "canceled", "canceled", "canceled"},
- {1940, "canceled", "canceled", "canceled"},
- {1936, "Garmisch-Partenkirchen", "Germany", "February 6 - 16"},
- {1932, "Lake Placid", "United States", "February 4 - 15"},
- {1928, "St. Moritz", "Switzerland", "February 11 - 19"},
- {1924, "Chamonix", "France", "January 25 - February 5"},
-};
-
-typedef struct { int year; cstr city, date; } OlympicLocation;
-
-int OlympicLocation_cmp(const OlympicLocation* a, const OlympicLocation* b);
-OlympicLocation OlympicLocation_clone(OlympicLocation loc);
-void OlympicLocation_drop(OlympicLocation* self);
-
-// Create a clist<OlympicLocation>, can be sorted by year.
-#define i_val_bind OlympicLocation // binds _cmp, _clone and _drop.
-#define i_tag OL
-#define i_extern // define _clist_mergesort()
-#include <stc/clist.h>
-
-// Create a csmap<cstr, clist_OL> where key is country name
-#define i_key_str // binds cstr_equ, cstr_hash, cstr_clone, ++
-#define i_val_bind clist_OL // binds clist_OL_clone, clist_OL_drop
-#define i_tag OL
-#include <stc/csmap.h>
-
-int OlympicLocation_cmp(const OlympicLocation* a, const OlympicLocation* b) {
- return a->year - b->year;
-}
-
-OlympicLocation OlympicLocation_clone(OlympicLocation loc) {
- loc.city = cstr_clone(loc.city);
- loc.date = cstr_clone(loc.date);
- return loc;
-}
-void OlympicLocation_drop(OlympicLocation* self) {
- c_drop(cstr, &self->city, &self->date);
-}
-
-int main()
-{
- // Define the multimap with destructor defered to when block is completed.
- c_auto (csmap_OL, multimap)
- {
- const clist_OL empty = clist_OL_init();
-
- for (size_t i = 0; i < c_arraylen(ol_data); ++i)
- {
- 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 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);
- }
- // Sort locations by year for each country.
- c_foreach (country, csmap_OL, multimap)
- 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", cstr_str(&country.ref->first),
- loc.ref->year,
- cstr_str(&loc.ref->city),
- cstr_str(&loc.ref->date));
- }
- }
-}
+#define i_implement
+#include <stc/cstr.h>
+
+// Olympics multimap example
+
+struct OlympicsData { int year; const char *city, *country, *date; } ol_data[] = {
+ {2026, "Milan and Cortina d'Ampezzo", "Italy", "February 6-22"},
+ {2022, "Beijing", "China", "February 4-20"},
+ {2018, "PyeongChang", "South Korea", "February 9-25"},
+ {2014, "Sochi", "Russia", "February 7-23"},
+ {2010, "Vancouver", "Canada", "February 12-28"},
+ {2006, "Torino", "Italy", "February 10-26"},
+ {2002, "Salt Lake City", "United States", "February 8-24"},
+ {1998, "Nagano", "Japan", "February 7-22"},
+ {1994, "Lillehammer", "Norway", "February 12-27"},
+ {1992, "Albertville", "France", "February 8-23"},
+ {1988, "Calgary", "Canada", "February 13-28"},
+ {1984, "Sarajevo", "Yugoslavia", "February 8-19"},
+ {1980, "Lake Placid", "United States", "February 13-24"},
+ {1976, "Innsbruck", "Austria", "February 4-15"},
+ {1972, "Sapporo", "Japan", "February 3-13"},
+ {1968, "Grenoble", "France", "February 6-18"},
+ {1964, "Innsbruck", "Austria", "January 29-February 9"},
+ {1960, "Squaw Valley", "United States", "February 18-28"},
+ {1956, "Cortina d'Ampezzo", "Italy", "January 26 - February 5"},
+ {1952, "Oslo", "Norway", "February 14 - 25"},
+ {1948, "St. Moritz", "Switzerland", "January 30 - February 8"},
+ {1944, "canceled", "canceled", "canceled"},
+ {1940, "canceled", "canceled", "canceled"},
+ {1936, "Garmisch-Partenkirchen", "Germany", "February 6 - 16"},
+ {1932, "Lake Placid", "United States", "February 4 - 15"},
+ {1928, "St. Moritz", "Switzerland", "February 11 - 19"},
+ {1924, "Chamonix", "France", "January 25 - February 5"},
+};
+
+typedef struct { int year; cstr city, date; } OlympicLocation;
+
+int OlympicLocation_cmp(const OlympicLocation* a, const OlympicLocation* b);
+OlympicLocation OlympicLocation_clone(OlympicLocation loc);
+void OlympicLocation_drop(OlympicLocation* self);
+
+// Create a clist<OlympicLocation>, can be sorted by year.
+#define i_val_bind OlympicLocation // binds _cmp, _clone and _drop.
+#define i_tag OL
+#define i_extern // define _clist_mergesort()
+#include <stc/clist.h>
+
+// Create a csmap<cstr, clist_OL> where key is country name
+#define i_key_str // binds cstr_equ, cstr_hash, cstr_clone, ++
+#define i_val_bind clist_OL // binds clist_OL_clone, clist_OL_drop
+#define i_tag OL
+#include <stc/csmap.h>
+
+int OlympicLocation_cmp(const OlympicLocation* a, const OlympicLocation* b) {
+ return a->year - b->year;
+}
+
+OlympicLocation OlympicLocation_clone(OlympicLocation loc) {
+ loc.city = cstr_clone(loc.city);
+ loc.date = cstr_clone(loc.date);
+ return loc;
+}
+void OlympicLocation_drop(OlympicLocation* self) {
+ c_drop(cstr, &self->city, &self->date);
+}
+
+int main()
+{
+ // Define the multimap with destructor defered to when block is completed.
+ c_auto (csmap_OL, multimap)
+ {
+ const clist_OL empty = clist_OL_init();
+
+ for (size_t i = 0; i < c_arraylen(ol_data); ++i)
+ {
+ 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 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);
+ }
+ // Sort locations by year for each country.
+ c_foreach (country, csmap_OL, multimap)
+ 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", cstr_str(&country.ref->first),
+ loc.ref->year,
+ cstr_str(&loc.ref->city),
+ cstr_str(&loc.ref->date));
+ }
+ }
+}
diff --git a/examples/music_arc.c b/examples/music_arc.c
index b6b59489..13075741 100644
--- a/examples/music_arc.c
+++ b/examples/music_arc.c
@@ -1,59 +1,59 @@
-// shared_ptr-examples.cpp
-// based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160
-#define i_implement
-#include <stc/cstr.h>
-
-struct Song
-{
- cstr artist;
- cstr title;
-} typedef Song;
-
-Song Song_new(const char* artist, const char* title)
- { return (Song){cstr_from(artist), cstr_from(title)}; }
-
-void Song_drop(Song* s) {
- printf("drop: %s\n", cstr_str(&s->title));
- c_drop(cstr, &s->artist, &s->title);
-}
-
-#define i_type SongPtr
-#define i_val Song
-#define i_valdrop Song_drop
-#define i_opt c_no_cmp
-#include <stc/carc.h>
-
-#define i_type SongVec
-#define i_val_arcbox SongPtr
-#include <stc/cvec.h>
-
-void example3()
-{
- c_auto (SongVec, vec, vec2)
- {
- c_apply(v, SongVec_push_back(&vec, *v), SongPtr, {
- SongPtr_make(Song_new("Bob Dylan", "The Times They Are A Changing")),
- SongPtr_make(Song_new("Aretha Franklin", "Bridge Over Troubled Water")),
- SongPtr_make(Song_new("Thalia", "Entre El Mar y Una Estrella"))
- });
-
- c_foreach (s, SongVec, vec)
- if (!cstr_equals(s.ref->get->artist, "Bob Dylan"))
- SongVec_push_back(&vec2, SongPtr_clone(*s.ref));
-
- c_apply(v, SongVec_push_back(&vec2, *v), SongPtr, {
- SongPtr_make(Song_new("Michael Jackson", "Billie Jean")),
- SongPtr_make(Song_new("Rihanna", "Stay")),
- });
-
- c_foreach (s, SongVec, vec2)
- printf("%s - %s: refs %lu\n", cstr_str(&s.ref->get->artist),
- cstr_str(&s.ref->get->title),
- *s.ref->use_count);
- }
-}
-
-int main()
-{
- example3();
-}
+// shared_ptr-examples.cpp
+// based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160
+#define i_implement
+#include <stc/cstr.h>
+
+struct Song
+{
+ cstr artist;
+ cstr title;
+} typedef Song;
+
+Song Song_new(const char* artist, const char* title)
+ { return (Song){cstr_from(artist), cstr_from(title)}; }
+
+void Song_drop(Song* s) {
+ printf("drop: %s\n", cstr_str(&s->title));
+ c_drop(cstr, &s->artist, &s->title);
+}
+
+#define i_type SongPtr
+#define i_val Song
+#define i_valdrop Song_drop
+#define i_opt c_no_cmp
+#include <stc/carc.h>
+
+#define i_type SongVec
+#define i_val_arcbox SongPtr
+#include <stc/cvec.h>
+
+void example3()
+{
+ c_auto (SongVec, vec, vec2)
+ {
+ c_apply(v, SongVec_push_back(&vec, *v), SongPtr, {
+ SongPtr_make(Song_new("Bob Dylan", "The Times They Are A Changing")),
+ SongPtr_make(Song_new("Aretha Franklin", "Bridge Over Troubled Water")),
+ SongPtr_make(Song_new("Thalia", "Entre El Mar y Una Estrella"))
+ });
+
+ c_foreach (s, SongVec, vec)
+ if (!cstr_equals(s.ref->get->artist, "Bob Dylan"))
+ SongVec_push_back(&vec2, SongPtr_clone(*s.ref));
+
+ c_apply(v, SongVec_push_back(&vec2, *v), SongPtr, {
+ SongPtr_make(Song_new("Michael Jackson", "Billie Jean")),
+ SongPtr_make(Song_new("Rihanna", "Stay")),
+ });
+
+ c_foreach (s, SongVec, vec2)
+ printf("%s - %s: refs %lu\n", cstr_str(&s.ref->get->artist),
+ cstr_str(&s.ref->get->title),
+ *s.ref->use_count);
+ }
+}
+
+int main()
+{
+ example3();
+}
diff --git a/examples/new_deq.c b/examples/new_deq.c
index f1e872f0..5fe2403a 100644
--- a/examples/new_deq.c
+++ b/examples/new_deq.c
@@ -1,62 +1,62 @@
-#define i_implement
-#include <stc/cstr.h>
-#include <stc/forward.h>
-
-forward_cdeq(cdeq_i32, int);
-forward_cdeq(cdeq_pnt, struct Point);
-
-struct MyStruct {
- cdeq_i32 intvec;
- cdeq_pnt pntvec;
-} typedef MyStruct;
-
-
-#define i_val int
-#define i_opt c_is_fwd
-#define i_tag i32
-#include <stc/cdeq.h>
-
-struct Point { int x, y; } typedef Point;
-int point_cmp(const Point* a, const Point* b) {
- int c = a->x - b->x;
- return c ? c : a->y - b->y;
-}
-
-#define i_val Point
-#define i_cmp point_cmp
-#define i_opt c_is_fwd
-#define i_tag pnt
-#include <stc/cdeq.h>
-
-#define i_val float
-#include <stc/cdeq.h>
-
-#define i_val_str
-#include <stc/cdeq.h>
-
-
-int main()
-{
- c_auto (cdeq_i32, vec)
- {
- cdeq_i32_push_back(&vec, 123);
- }
- c_auto (cdeq_float, fvec)
- {
- cdeq_float_push_back(&fvec, 123.3);
- }
- c_auto (cdeq_pnt, pvec)
- {
- 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("");
- }
- c_auto (cdeq_str, svec)
- {
- cdeq_str_emplace_back(&svec, "Hello, friend");
- }
-}
+#define i_implement
+#include <stc/cstr.h>
+#include <stc/forward.h>
+
+forward_cdeq(cdeq_i32, int);
+forward_cdeq(cdeq_pnt, struct Point);
+
+struct MyStruct {
+ cdeq_i32 intvec;
+ cdeq_pnt pntvec;
+} typedef MyStruct;
+
+
+#define i_val int
+#define i_opt c_is_fwd
+#define i_tag i32
+#include <stc/cdeq.h>
+
+struct Point { int x, y; } typedef Point;
+int point_cmp(const Point* a, const Point* b) {
+ int c = a->x - b->x;
+ return c ? c : a->y - b->y;
+}
+
+#define i_val Point
+#define i_cmp point_cmp
+#define i_opt c_is_fwd
+#define i_tag pnt
+#include <stc/cdeq.h>
+
+#define i_val float
+#include <stc/cdeq.h>
+
+#define i_val_str
+#include <stc/cdeq.h>
+
+
+int main()
+{
+ c_auto (cdeq_i32, vec)
+ {
+ cdeq_i32_push_back(&vec, 123);
+ }
+ c_auto (cdeq_float, fvec)
+ {
+ cdeq_float_push_back(&fvec, 123.3);
+ }
+ c_auto (cdeq_pnt, pvec)
+ {
+ 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("");
+ }
+ c_auto (cdeq_str, svec)
+ {
+ cdeq_str_emplace_back(&svec, "Hello, friend");
+ }
+}
diff --git a/examples/new_map.c b/examples/new_map.c
index 0882d02f..78c1a44d 100644
--- a/examples/new_map.c
+++ b/examples/new_map.c
@@ -1,73 +1,73 @@
-#define i_implement
-#include <stc/cstr.h>
-#include <stc/forward.h>
-
-forward_cmap(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_cmp(const Point* a, const Point* b) {
- int c = a->x - b->x;
- return c ? c : a->y - b->y;
-}
-
-// Point => int map
-#define i_key Point
-#define i_val int
-#define i_cmp point_cmp
-#define i_hash c_default_hash
-#define i_opt c_is_fwd
-#define i_tag pnt
-#include <stc/cmap.h>
-
-// cstr => cstr 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()
-{
- c_auto (cmap_int, map)
- c_auto (cmap_pnt, pmap)
- c_auto (cmap_str, smap)
- c_auto (cset_str, sset)
- {
- cmap_int_insert(&map, 123, 321);
-
- c_apply(v, cmap_pnt_insert(&pmap, c_pair(v)), cmap_pnt_raw, {
- {{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}
- });
- c_foreach (i, cmap_pnt, pmap)
- printf(" (%d, %d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second);
- puts("");
-
- c_apply(v, cmap_str_emplace(&smap, c_pair(v)), cmap_str_raw, {
- {"Hello, friend", "long time no see"},
- {"So long, friend", "see you around"},
- });
-
- c_apply(v, cset_str_emplace(&sset, *v), const char*, {
- "Hello, friend",
- "Nice to see you again",
- "So long, friend",
- });
- c_foreach (i, cset_str, sset)
- printf(" %s\n", cstr_str(i.ref));
- }
-}
+#define i_implement
+#include <stc/cstr.h>
+#include <stc/forward.h>
+
+forward_cmap(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_cmp(const Point* a, const Point* b) {
+ int c = a->x - b->x;
+ return c ? c : a->y - b->y;
+}
+
+// Point => int map
+#define i_key Point
+#define i_val int
+#define i_cmp point_cmp
+#define i_hash c_default_hash
+#define i_opt c_is_fwd
+#define i_tag pnt
+#include <stc/cmap.h>
+
+// cstr => cstr 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()
+{
+ c_auto (cmap_int, map)
+ c_auto (cmap_pnt, pmap)
+ c_auto (cmap_str, smap)
+ c_auto (cset_str, sset)
+ {
+ cmap_int_insert(&map, 123, 321);
+
+ c_apply(v, cmap_pnt_insert(&pmap, c_pair(v)), cmap_pnt_raw, {
+ {{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}
+ });
+ c_foreach (i, cmap_pnt, pmap)
+ printf(" (%d, %d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second);
+ puts("");
+
+ c_apply(v, cmap_str_emplace(&smap, c_pair(v)), cmap_str_raw, {
+ {"Hello, friend", "long time no see"},
+ {"So long, friend", "see you around"},
+ });
+
+ c_apply(v, cset_str_emplace(&sset, *v), const char*, {
+ "Hello, friend",
+ "Nice to see you again",
+ "So long, friend",
+ });
+ c_foreach (i, cset_str, sset)
+ printf(" %s\n", cstr_str(i.ref));
+ }
+}
diff --git a/examples/new_pque.c b/examples/new_pque.c
index 79e895d8..2e5cf9ca 100644
--- a/examples/new_pque.c
+++ b/examples/new_pque.c
@@ -1,65 +1,65 @@
-#include <stc/forward.h>
-
-forward_cpque(cpque_pnt, struct Point);
-
-struct MyStruct {
- cpque_pnt priority_queue;
- int id;
-};
-
-#define i_val int
-#include <stc/cstack.h>
-
-#define i_val int
-#include <stc/cpque.h>
-
-struct Point { int x, y; } typedef Point;
-
-int Point_cmp(const Point* a, const Point* b) {
- int c = a->x - b->x;
- return c ? c : a->y - b->y;
-}
-
-#define i_val Point
-#define i_cmp Point_cmp
-#define i_opt c_is_fwd
-#define i_tag pnt
-#include <stc/cpque.h>
-
-#include <stdio.h>
-
-int main()
-{
- c_auto (cstack_int, istk)
- {
- cstack_int_push(&istk, 123);
- cstack_int_push(&istk, 321);
- // print
- c_foreach (i, cstack_int, istk)
- printf(" %d", *i.ref);
- puts("");
- }
- c_auto (cpque_pnt, pque)
- {
- 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 *v = cpque_pnt_top(&pque);
- printf(" (%d,%d)", v->x, v->y);
- cpque_pnt_pop(&pque);
- }
- puts("");
- }
- c_auto (cpque_int, ique)
- {
- cpque_int_push(&ique, 123);
- cpque_int_push(&ique, 321);
- // print
- for (size_t i=0; i<cpque_int_size(ique); ++i)
- printf(" %d", ique.data[i]);
- puts("");
- }
-}
+#include <stc/forward.h>
+
+forward_cpque(cpque_pnt, struct Point);
+
+struct MyStruct {
+ cpque_pnt priority_queue;
+ int id;
+};
+
+#define i_val int
+#include <stc/cstack.h>
+
+#define i_val int
+#include <stc/cpque.h>
+
+struct Point { int x, y; } typedef Point;
+
+int Point_cmp(const Point* a, const Point* b) {
+ int c = a->x - b->x;
+ return c ? c : a->y - b->y;
+}
+
+#define i_val Point
+#define i_cmp Point_cmp
+#define i_opt c_is_fwd
+#define i_tag pnt
+#include <stc/cpque.h>
+
+#include <stdio.h>
+
+int main()
+{
+ c_auto (cstack_int, istk)
+ {
+ cstack_int_push(&istk, 123);
+ cstack_int_push(&istk, 321);
+ // print
+ c_foreach (i, cstack_int, istk)
+ printf(" %d", *i.ref);
+ puts("");
+ }
+ c_auto (cpque_pnt, pque)
+ {
+ 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 *v = cpque_pnt_top(&pque);
+ printf(" (%d,%d)", v->x, v->y);
+ cpque_pnt_pop(&pque);
+ }
+ puts("");
+ }
+ c_auto (cpque_int, ique)
+ {
+ cpque_int_push(&ique, 123);
+ cpque_int_push(&ique, 321);
+ // print
+ for (size_t i=0; i<cpque_int_size(ique); ++i)
+ printf(" %d", ique.data[i]);
+ puts("");
+ }
+}
diff --git a/examples/new_queue.c b/examples/new_queue.c
index 86f4227c..f0d8120f 100644
--- a/examples/new_queue.c
+++ b/examples/new_queue.c
@@ -1,45 +1,45 @@
-#define i_implement
-#include <stc/crandom.h>
-#include <stc/forward.h>
-#include <stdio.h>
-#include <time.h>
-
-forward_cqueue(cqueue_pnt, struct Point);
-
-struct Point { int x, y; } typedef Point;
-int point_cmp(const Point* a, const Point* b) {
- int c = c_default_cmp(&a->x, &b->x);
- return c ? c : c_default_cmp(&a->y, &b->y);
-}
-#define i_val Point
-#define i_cmp point_cmp
-#define i_opt c_is_fwd
-#define i_tag pnt
-#include <stc/cqueue.h>
-
-#define i_val int
-#include <stc/cqueue.h>
-
-int main() {
- int n = 60000000;
- stc64_t rng = stc64_new(time(NULL));
- stc64_uniform_t dist = stc64_uniform_new(0, n);
-
- c_auto (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 %" PRIuMAX ", capacity %" PRIuMAX "\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 %" PRIuMAX ", capacity %" PRIuMAX "\n", cqueue_int_size(Q), cqueue_int_capacity(Q));
- }
-}
+#define i_implement
+#include <stc/crandom.h>
+#include <stc/forward.h>
+#include <stdio.h>
+#include <time.h>
+
+forward_cqueue(cqueue_pnt, struct Point);
+
+struct Point { int x, y; } typedef Point;
+int point_cmp(const Point* a, const Point* b) {
+ int c = c_default_cmp(&a->x, &b->x);
+ return c ? c : c_default_cmp(&a->y, &b->y);
+}
+#define i_val Point
+#define i_cmp point_cmp
+#define i_opt c_is_fwd
+#define i_tag pnt
+#include <stc/cqueue.h>
+
+#define i_val int
+#include <stc/cqueue.h>
+
+int main() {
+ int n = 60000000;
+ stc64_t rng = stc64_new(time(NULL));
+ stc64_uniform_t dist = stc64_uniform_new(0, n);
+
+ c_auto (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 %" PRIuMAX ", capacity %" PRIuMAX "\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 %" PRIuMAX ", capacity %" PRIuMAX "\n", cqueue_int_size(Q), cqueue_int_capacity(Q));
+ }
+}
diff --git a/examples/new_smap.c b/examples/new_smap.c
index 2a885d03..141934d3 100644
--- a/examples/new_smap.c
+++ b/examples/new_smap.c
@@ -1,76 +1,76 @@
-#define i_implement
-#include <stc/cstr.h>
-#include <stc/forward.h>
-
-forward_csmap(PMap, struct Point, int);
-
-// Use forward declared PMap in struct
-struct MyStruct {
- PMap 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_cmp(const Point* a, const Point* b) {
- int c = a->x - b->x;
- return c ? c : a->y - b->y;
-}
-
-#define i_type PMap
-#define i_key Point
-#define i_val int
-#define i_cmp point_cmp
-#define i_opt c_is_fwd
-#include <stc/csmap.h>
-
-// cstr => cstr map
-#define i_type SMap
-#define i_key_str
-#define i_val_str
-#include <stc/csmap.h>
-
-// cstr set
-#define i_type SSet
-#define i_key_str
-#include <stc/csset.h>
-
-
-int main()
-{
- c_auto (csmap_int, imap) {
- csmap_int_insert(&imap, 123, 321);
- }
-
- c_auto (PMap, pmap) {
- c_apply(v, PMap_insert(&pmap, c_pair(v)), PMap_value, {
- {{42, 14}, 1},
- {{32, 94}, 2},
- {{62, 81}, 3},
- });
- c_forpair (p, i, PMap, pmap)
- printf(" (%d,%d: %d)", _.p->x, _.p->y, *_.i);
- puts("");
- }
-
- c_auto (SMap, smap) {
- c_apply(v, SMap_emplace(&smap, c_pair(v)), SMap_raw, {
- {"Hello, friend", "this is the mapped value"},
- {"The brown fox", "jumped"},
- {"This is the time", "for all good things"},
- });
- c_forpair (i, j, SMap, smap)
- printf(" (%s: %s)\n", cstr_str(_.i), cstr_str(_.j));
- }
-
- c_auto (SSet, sset) {
- SSet_emplace(&sset, "Hello, friend");
- SSet_emplace(&sset, "Goodbye, foe");
- printf("Found? %s\n", SSet_contains(&sset, "Hello, friend") ? "true" : "false");
- }
-}
+#define i_implement
+#include <stc/cstr.h>
+#include <stc/forward.h>
+
+forward_csmap(PMap, struct Point, int);
+
+// Use forward declared PMap in struct
+struct MyStruct {
+ PMap 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_cmp(const Point* a, const Point* b) {
+ int c = a->x - b->x;
+ return c ? c : a->y - b->y;
+}
+
+#define i_type PMap
+#define i_key Point
+#define i_val int
+#define i_cmp point_cmp
+#define i_opt c_is_fwd
+#include <stc/csmap.h>
+
+// cstr => cstr map
+#define i_type SMap
+#define i_key_str
+#define i_val_str
+#include <stc/csmap.h>
+
+// cstr set
+#define i_type SSet
+#define i_key_str
+#include <stc/csset.h>
+
+
+int main()
+{
+ c_auto (csmap_int, imap) {
+ csmap_int_insert(&imap, 123, 321);
+ }
+
+ c_auto (PMap, pmap) {
+ c_apply(v, PMap_insert(&pmap, c_pair(v)), PMap_value, {
+ {{42, 14}, 1},
+ {{32, 94}, 2},
+ {{62, 81}, 3},
+ });
+ c_forpair (p, i, PMap, pmap)
+ printf(" (%d,%d: %d)", _.p->x, _.p->y, *_.i);
+ puts("");
+ }
+
+ c_auto (SMap, smap) {
+ c_apply(v, SMap_emplace(&smap, c_pair(v)), SMap_raw, {
+ {"Hello, friend", "this is the mapped value"},
+ {"The brown fox", "jumped"},
+ {"This is the time", "for all good things"},
+ });
+ c_forpair (i, j, SMap, smap)
+ printf(" (%s: %s)\n", cstr_str(_.i), cstr_str(_.j));
+ }
+
+ c_auto (SSet, sset) {
+ SSet_emplace(&sset, "Hello, friend");
+ SSet_emplace(&sset, "Goodbye, foe");
+ printf("Found? %s\n", SSet_contains(&sset, "Hello, friend") ? "true" : "false");
+ }
+}
diff --git a/examples/new_sptr.c b/examples/new_sptr.c
index 58f68dae..e2d4da85 100644
--- a/examples/new_sptr.c
+++ b/examples/new_sptr.c
@@ -1,56 +1,56 @@
-#define i_implement
-#include <stc/cstr.h>
-
-struct Person { cstr name, last; } typedef Person;
-
-Person Person_new(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
-}
-Person Person_clone(Person p) {
- p.name = cstr_clone(p.name), p.last = cstr_clone(p.last);
- return p;
-}
-void Person_drop(Person* p) {
- printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
- c_drop(cstr, &p->name, &p->last);
-}
-
-#define i_val_bind Person
-#define i_opt c_no_cmp // makes cmp and hash not required when using _bind
-#define i_tag person
-#include <stc/carc.h>
-
-// ...
-#define i_type SPtr
-#define i_val int
-#define i_valdrop(x) printf("drop: %d\n", *x)
-#include <stc/carc.h>
-
-#define i_val_arcbox SPtr
-#define i_tag iptr
-#include <stc/cstack.h>
-
-int main(void) {
- c_auto (carc_person, p, q, r, s)
- {
- puts("Ex1");
- p = carc_person_make(Person_new("John", "Smiths"));
- q = carc_person_clone(p);
- r = carc_person_clone(p);
- s = carc_person_make(Person_clone(*p.get)); // deep copy
- printf("%s %s. uses: %lu\n", cstr_str(&r.get->name), cstr_str(&s.get->last), *p.use_count);
- }
-
- c_auto (cstack_iptr, stk) {
- puts("Ex2");
- cstack_iptr_push(&stk, SPtr_make(10));
- cstack_iptr_push(&stk, SPtr_make(20));
- cstack_iptr_push(&stk, SPtr_make(30));
- cstack_iptr_push(&stk, SPtr_clone(*cstack_iptr_top(&stk)));
- cstack_iptr_push(&stk, SPtr_clone(*cstack_iptr_begin(&stk).ref));
-
- c_foreach (i, cstack_iptr, stk)
- printf(" (%d, uses %ld)", *i.ref->get, *i.ref->use_count);
- puts("");
- }
-}
+#define i_implement
+#include <stc/cstr.h>
+
+struct Person { cstr name, last; } typedef Person;
+
+Person Person_new(const char* name, const char* last) {
+ return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+}
+Person Person_clone(Person p) {
+ p.name = cstr_clone(p.name), p.last = cstr_clone(p.last);
+ return p;
+}
+void Person_drop(Person* p) {
+ printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
+ c_drop(cstr, &p->name, &p->last);
+}
+
+#define i_val_bind Person
+#define i_opt c_no_cmp // makes cmp and hash not required when using _bind
+#define i_tag person
+#include <stc/carc.h>
+
+// ...
+#define i_type SPtr
+#define i_val int
+#define i_valdrop(x) printf("drop: %d\n", *x)
+#include <stc/carc.h>
+
+#define i_val_arcbox SPtr
+#define i_tag iptr
+#include <stc/cstack.h>
+
+int main(void) {
+ c_auto (carc_person, p, q, r, s)
+ {
+ puts("Ex1");
+ p = carc_person_make(Person_new("John", "Smiths"));
+ q = carc_person_clone(p);
+ r = carc_person_clone(p);
+ s = carc_person_make(Person_clone(*p.get)); // deep copy
+ printf("%s %s. uses: %lu\n", cstr_str(&r.get->name), cstr_str(&s.get->last), *p.use_count);
+ }
+
+ c_auto (cstack_iptr, stk) {
+ puts("Ex2");
+ cstack_iptr_push(&stk, SPtr_make(10));
+ cstack_iptr_push(&stk, SPtr_make(20));
+ cstack_iptr_push(&stk, SPtr_make(30));
+ cstack_iptr_push(&stk, SPtr_clone(*cstack_iptr_top(&stk)));
+ cstack_iptr_push(&stk, SPtr_clone(*cstack_iptr_begin(&stk).ref));
+
+ c_foreach (i, cstack_iptr, stk)
+ printf(" (%d, uses %ld)", *i.ref->get, *i.ref->use_count);
+ puts("");
+ }
+}
diff --git a/examples/new_vec.c b/examples/new_vec.c
index 3f3d5de8..73e4987f 100644
--- a/examples/new_vec.c
+++ b/examples/new_vec.c
@@ -1,57 +1,57 @@
-#define i_implement
-#include <stc/cstr.h>
-#include <stc/forward.h>
-
-forward_cvec(cvec_i32, int);
-forward_cvec(cvec_pnt, struct Point);
-
-struct MyStruct {
- cvec_i32 intvec;
- cvec_pnt pntvec;
-} typedef MyStruct;
-
-#define i_val int
-#define i_opt c_is_fwd
-#define i_tag i32
-#include <stc/cvec.h>
-
-struct Point { int x, y; } typedef Point;
-int point_cmp(const Point* a, const Point* b) {
- int c = c_default_cmp(&a->x, &b->x);
- return c ? c : c_default_cmp(&a->y, &b->y);
-}
-
-#define i_val Point
-#define i_cmp point_cmp
-#define i_opt c_is_fwd
-#define i_tag pnt
-#include <stc/cvec.h>
-
-#define i_val float
-#include <stc/cvec.h>
-
-#define i_val_str
-#include <stc/cvec.h>
-
-
-int main()
-{
- c_auto (cvec_i32, vec)
- c_auto (cvec_float, fvec)
- c_auto (cvec_pnt, pvec)
- c_auto (cvec_str, svec)
- {
- cvec_i32_push_back(&vec, 123);
- cvec_float_push_back(&fvec, 123.3);
-
- 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_str_emplace_back(&svec, "Hello, friend");
- }
-}
+#define i_implement
+#include <stc/cstr.h>
+#include <stc/forward.h>
+
+forward_cvec(cvec_i32, int);
+forward_cvec(cvec_pnt, struct Point);
+
+struct MyStruct {
+ cvec_i32 intvec;
+ cvec_pnt pntvec;
+} typedef MyStruct;
+
+#define i_val int
+#define i_opt c_is_fwd
+#define i_tag i32
+#include <stc/cvec.h>
+
+struct Point { int x, y; } typedef Point;
+int point_cmp(const Point* a, const Point* b) {
+ int c = c_default_cmp(&a->x, &b->x);
+ return c ? c : c_default_cmp(&a->y, &b->y);
+}
+
+#define i_val Point
+#define i_cmp point_cmp
+#define i_opt c_is_fwd
+#define i_tag pnt
+#include <stc/cvec.h>
+
+#define i_val float
+#include <stc/cvec.h>
+
+#define i_val_str
+#include <stc/cvec.h>
+
+
+int main()
+{
+ c_auto (cvec_i32, vec)
+ c_auto (cvec_float, fvec)
+ c_auto (cvec_pnt, pvec)
+ c_auto (cvec_str, svec)
+ {
+ cvec_i32_push_back(&vec, 123);
+ cvec_float_push_back(&fvec, 123.3);
+
+ 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_str_emplace_back(&svec, "Hello, friend");
+ }
+}
diff --git a/examples/person_arc.c b/examples/person_arc.c
index 5ac1e9c2..685d1b3c 100644
--- a/examples/person_arc.c
+++ b/examples/person_arc.c
@@ -1,72 +1,72 @@
-/* cbox: heap allocated boxed type */
-#define i_implement
-#include <stc/cstr.h>
-
-typedef struct { cstr name, last; } Person;
-
-Person Person_new(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
-}
-
-int Person_cmp(const Person* a, const Person* b) {
- int c = cstr_cmp(&a->name, &b->name);
- return c ? c : cstr_cmp(&a->last, &b->last);
-}
-
-uint64_t Person_hash(const Person* a) {
- return cstr_hash(&a->name) ^ cstr_hash(&a->last);
-}
-
-Person Person_clone(Person p) {
- p.name = cstr_clone(p.name);
- p.last = cstr_clone(p.last);
- return p;
-}
-
-void Person_drop(Person* p) {
- printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
- c_drop(cstr, &p->name, &p->last);
-}
-
-#define i_type PSPtr
-#define i_val_bind Person // binds Person_cmp, ...
-#include <stc/carc.h>
-
-#define i_type Persons
-#define i_val_arcbox PSPtr // binds PSPtr_cmp, ...
-#include <stc/cvec.h>
-
-
-int main()
-{
- c_auto (Persons, vec)
- c_auto (PSPtr, p, q)
- {
- p = PSPtr_make(Person_new("Laura", "Palmer"));
-
- // We want a deep copy -- PSPtr_clone(p) only shares!
- q = PSPtr_make(Person_clone(*p.get));
- cstr_assign(&q.get->name, "Leland");
-
- printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last));
- printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last));
-
- Persons_push_back(&vec, PSPtr_make(Person_new("Dale", "Cooper")));
- Persons_push_back(&vec, PSPtr_make(Person_new("Audrey", "Home")));
-
- // Clone/share p and q to the vector
- c_apply(v, Persons_push_back(&vec, PSPtr_clone(*v)), PSPtr, {p, q});
-
- c_foreach (i, Persons, vec)
- printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last));
- puts("");
-
- // Look-up Audrey!
- c_autovar (Person a = Person_new("Audrey", "Home"), Person_drop(&a)) {
- const PSPtr *v = Persons_get(&vec, a);
- if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last));
- }
-
- puts("");
- }
-}
+/* cbox: heap allocated boxed type */
+#define i_implement
+#include <stc/cstr.h>
+
+typedef struct { cstr name, last; } Person;
+
+Person Person_new(const char* name, const char* last) {
+ return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+}
+
+int Person_cmp(const Person* a, const Person* b) {
+ int c = cstr_cmp(&a->name, &b->name);
+ return c ? c : cstr_cmp(&a->last, &b->last);
+}
+
+uint64_t Person_hash(const Person* a) {
+ return cstr_hash(&a->name) ^ cstr_hash(&a->last);
+}
+
+Person Person_clone(Person p) {
+ p.name = cstr_clone(p.name);
+ p.last = cstr_clone(p.last);
+ return p;
+}
+
+void Person_drop(Person* p) {
+ printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
+ c_drop(cstr, &p->name, &p->last);
+}
+
+#define i_type PSPtr
+#define i_val_bind Person // binds Person_cmp, ...
+#include <stc/carc.h>
+
+#define i_type Persons
+#define i_val_arcbox PSPtr // binds PSPtr_cmp, ...
+#include <stc/cvec.h>
+
+
+int main()
+{
+ c_auto (Persons, vec)
+ c_auto (PSPtr, p, q)
+ {
+ p = PSPtr_make(Person_new("Laura", "Palmer"));
+
+ // We want a deep copy -- PSPtr_clone(p) only shares!
+ q = PSPtr_make(Person_clone(*p.get));
+ cstr_assign(&q.get->name, "Leland");
+
+ printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last));
+ printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last));
+
+ Persons_push_back(&vec, PSPtr_make(Person_new("Dale", "Cooper")));
+ Persons_push_back(&vec, PSPtr_make(Person_new("Audrey", "Home")));
+
+ // Clone/share p and q to the vector
+ c_apply(v, Persons_push_back(&vec, PSPtr_clone(*v)), PSPtr, {p, q});
+
+ c_foreach (i, Persons, vec)
+ printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last));
+ puts("");
+
+ // Look-up Audrey!
+ c_autovar (Person a = Person_new("Audrey", "Home"), Person_drop(&a)) {
+ const PSPtr *v = Persons_get(&vec, a);
+ if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last));
+ }
+
+ puts("");
+ }
+}
diff --git a/examples/phonebook.c b/examples/phonebook.c
index ab782653..2368480c 100644
--- a/examples/phonebook.c
+++ b/examples/phonebook.c
@@ -1,81 +1,81 @@
-// The MIT License (MIT)
-// Copyright (c) 2018 Maksim Andrianov
-//
-// 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.
-
-// Program to emulates the phone book.
-
-#define i_implement
-#include <stc/cstr.h>
-
-#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)
-{
- c_foreach (i, cmap_str, phone_book)
- printf("%s\t- %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
-}
-
-int main(int argc, char **argv)
-{
- c_auto (cset_str, names) {
- c_apply(v, cset_str_emplace(&names, *v), const char*,
- {"Hello", "Cool", "True"});
- c_foreach (i, cset_str, names) printf("%s ", cstr_str(i.ref));
- puts("");
- }
-
- c_auto (cmap_str, phone_book) {
- c_apply(v, cmap_str_emplace(&phone_book, c_pair(v)), cmap_str_raw, {
- {"Lilia Friedman", "(892) 670-4739"},
- {"Tariq Beltran", "(489) 600-7575"},
- {"Laiba Juarez", "(303) 885-5692"},
- {"Elliott Mooney", "(945) 616-4482"},
- });
-
- printf("Phone book:\n");
- print_phone_book(phone_book);
-
- cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1880");
- cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1990");
-
- printf("\nPhone book after adding Zak Byers:\n");
- print_phone_book(phone_book);
-
- if (cmap_str_contains(&phone_book, "Tariq Beltran"))
- printf("\nTariq Beltran is in phone book\n");
-
- cmap_str_erase(&phone_book, "Tariq Beltran");
- cmap_str_erase(&phone_book, "Elliott Mooney");
-
- printf("\nPhone book after erasing Tariq and Elliott:\n");
- print_phone_book(phone_book);
-
- cmap_str_emplace_or_assign(&phone_book, "Zak Byers", "(555) 396-188");
-
- printf("\nPhone book after update phone of Zak Byers:\n");
- print_phone_book(phone_book);
- }
- puts("done");
-}
+// The MIT License (MIT)
+// Copyright (c) 2018 Maksim Andrianov
+//
+// 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.
+
+// Program to emulates the phone book.
+
+#define i_implement
+#include <stc/cstr.h>
+
+#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)
+{
+ c_foreach (i, cmap_str, phone_book)
+ printf("%s\t- %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
+}
+
+int main(int argc, char **argv)
+{
+ c_auto (cset_str, names) {
+ c_apply(v, cset_str_emplace(&names, *v), const char*,
+ {"Hello", "Cool", "True"});
+ c_foreach (i, cset_str, names) printf("%s ", cstr_str(i.ref));
+ puts("");
+ }
+
+ c_auto (cmap_str, phone_book) {
+ c_apply(v, cmap_str_emplace(&phone_book, c_pair(v)), cmap_str_raw, {
+ {"Lilia Friedman", "(892) 670-4739"},
+ {"Tariq Beltran", "(489) 600-7575"},
+ {"Laiba Juarez", "(303) 885-5692"},
+ {"Elliott Mooney", "(945) 616-4482"},
+ });
+
+ printf("Phone book:\n");
+ print_phone_book(phone_book);
+
+ cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1880");
+ cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1990");
+
+ printf("\nPhone book after adding Zak Byers:\n");
+ print_phone_book(phone_book);
+
+ if (cmap_str_contains(&phone_book, "Tariq Beltran"))
+ printf("\nTariq Beltran is in phone book\n");
+
+ cmap_str_erase(&phone_book, "Tariq Beltran");
+ cmap_str_erase(&phone_book, "Elliott Mooney");
+
+ printf("\nPhone book after erasing Tariq and Elliott:\n");
+ print_phone_book(phone_book);
+
+ cmap_str_emplace_or_assign(&phone_book, "Zak Byers", "(555) 396-188");
+
+ printf("\nPhone book after update phone of Zak Byers:\n");
+ print_phone_book(phone_book);
+ }
+ puts("done");
+}
diff --git a/examples/prime.c b/examples/prime.c
index 92fafde4..f235f845 100644
--- a/examples/prime.c
+++ b/examples/prime.c
@@ -1,42 +1,42 @@
-#include <stdio.h>
-#include <math.h>
-#include <time.h>
-#define i_implement
-#include <stc/cbits.h>
-
-cbits sieveOfEratosthenes(size_t n)
-{
- cbits bits = cbits_with_size(n/2 + 1, true);
- size_t q = (size_t) sqrt((double) n) + 1;
- for (size_t i = 3; i < q; i += 2) {
- size_t j = i;
- for (; j < n; j += 2) {
- if (cbits_test(&bits, j>>1)) {
- i = j;
- break;
- }
- }
- for (size_t j = i*i; j < n; j += i*2)
- cbits_reset(&bits, j>>1);
- }
- return bits;
-}
-
-int main(void)
-{
- size_t n = 1000000000;
- printf("computing prime numbers up to %" PRIuMAX "\n", n);
-
- clock_t t1 = clock();
- c_autovar (cbits primes = sieveOfEratosthenes(n + 1), cbits_drop(&primes)) {
- puts("done");
- size_t np = cbits_count(&primes);
- clock_t t2 = clock();
-
- printf("number of primes: %" PRIuMAX ", time: %f\n", np, (t2 - t1) / (float)CLOCKS_PER_SEC);
- printf("2");
- for (size_t i = 3; i < 1000; i += 2)
- if (cbits_test(&primes, i>>1)) printf(" %" PRIuMAX "", i);
- puts("");
- }
-}
+#include <stdio.h>
+#include <math.h>
+#include <time.h>
+#define i_implement
+#include <stc/cbits.h>
+
+cbits sieveOfEratosthenes(size_t n)
+{
+ cbits bits = cbits_with_size(n/2 + 1, true);
+ size_t q = (size_t) sqrt((double) n) + 1;
+ for (size_t i = 3; i < q; i += 2) {
+ size_t j = i;
+ for (; j < n; j += 2) {
+ if (cbits_test(&bits, j>>1)) {
+ i = j;
+ break;
+ }
+ }
+ for (size_t j = i*i; j < n; j += i*2)
+ cbits_reset(&bits, j>>1);
+ }
+ return bits;
+}
+
+int main(void)
+{
+ size_t n = 1000000000;
+ printf("computing prime numbers up to %" PRIuMAX "\n", n);
+
+ clock_t t1 = clock();
+ c_autovar (cbits primes = sieveOfEratosthenes(n + 1), cbits_drop(&primes)) {
+ puts("done");
+ size_t np = cbits_count(&primes);
+ clock_t t2 = clock();
+
+ printf("number of primes: %" PRIuMAX ", time: %f\n", np, (t2 - t1) / (float)CLOCKS_PER_SEC);
+ printf("2");
+ for (size_t i = 3; i < 1000; i += 2)
+ if (cbits_test(&primes, i>>1)) printf(" %" PRIuMAX "", i);
+ puts("");
+ }
+}
diff --git a/examples/priority.c b/examples/priority.c
index 65543590..f4c45d76 100644
--- a/examples/priority.c
+++ b/examples/priority.c
@@ -1,35 +1,35 @@
-
-#include <stdio.h>
-#include <time.h>
-#define i_implement
-#include <stc/crandom.h>
-
-#define i_val int64_t
-#define i_cmp -c_default_cmp // min-heap (increasing values)
-#define i_tag i
-#include <stc/cpque.h>
-
-int main() {
- size_t N = 10000000;
- stc64_t rng = stc64_new(time(NULL));
- stc64_uniform_t dist = stc64_uniform_new(0, N * 10);
- c_auto (cpque_i, heap)
- {
- // Push ten million random numbers to priority queue
- printf("Push %" PRIuMAX " numbers\n", N);
- c_forrange (N)
- cpque_i_push(&heap, stc64_uniform(&rng, &dist));
-
- // push some negative numbers too.
- c_apply(v, cpque_i_push(&heap, *v), int, {-231, -32, -873, -4, -343});
-
- c_forrange (N)
- cpque_i_push(&heap, stc64_uniform(&rng, &dist));
-
- puts("Extract the hundred smallest.");
- c_forrange (100) {
- printf("%" PRIdMAX " ", *cpque_i_top(&heap));
- cpque_i_pop(&heap);
- }
- }
-}
+
+#include <stdio.h>
+#include <time.h>
+#define i_implement
+#include <stc/crandom.h>
+
+#define i_val int64_t
+#define i_cmp -c_default_cmp // min-heap (increasing values)
+#define i_tag i
+#include <stc/cpque.h>
+
+int main() {
+ size_t N = 10000000;
+ stc64_t rng = stc64_new(time(NULL));
+ stc64_uniform_t dist = stc64_uniform_new(0, N * 10);
+ c_auto (cpque_i, heap)
+ {
+ // Push ten million random numbers to priority queue
+ printf("Push %" PRIuMAX " numbers\n", N);
+ c_forrange (N)
+ cpque_i_push(&heap, stc64_uniform(&rng, &dist));
+
+ // push some negative numbers too.
+ c_apply(v, cpque_i_push(&heap, *v), int, {-231, -32, -873, -4, -343});
+
+ c_forrange (N)
+ cpque_i_push(&heap, stc64_uniform(&rng, &dist));
+
+ puts("Extract the hundred smallest.");
+ c_forrange (100) {
+ printf("%" PRIdMAX " ", *cpque_i_top(&heap));
+ cpque_i_pop(&heap);
+ }
+ }
+}
diff --git a/examples/queue.c b/examples/queue.c
index 1b56d96a..57e24fe6 100644
--- a/examples/queue.c
+++ b/examples/queue.c
@@ -1,32 +1,32 @@
-#define i_implement
-#include <stc/crandom.h>
-#include <stdio.h>
-
-#define i_val int
-#define i_tag i
-#include <stc/cqueue.h>
-
-int main() {
- int n = 100000000;
- stc64_uniform_t dist;
- stc64_t rng = stc64_new(1234);
- dist = stc64_uniform_new(0, n);
-
- c_auto (cqueue_i, queue)
- {
- // Push ten million random numbers onto the queue.
- c_forrange (n)
- cqueue_i_push(&queue, stc64_uniform(&rng, &dist));
-
- // Push or pop on the queue ten million times
- printf("%d\n", n);
- c_forrange (n) { // forrange uses initial n only.
- int r = stc64_uniform(&rng, &dist);
- if (r & 1)
- ++n, cqueue_i_push(&queue, r);
- else
- --n, cqueue_i_pop(&queue);
- }
- printf("%d, %" PRIuMAX "\n", n, cqueue_i_size(queue));
- }
-}
+#define i_implement
+#include <stc/crandom.h>
+#include <stdio.h>
+
+#define i_val int
+#define i_tag i
+#include <stc/cqueue.h>
+
+int main() {
+ int n = 100000000;
+ stc64_uniform_t dist;
+ stc64_t rng = stc64_new(1234);
+ dist = stc64_uniform_new(0, n);
+
+ c_auto (cqueue_i, queue)
+ {
+ // Push ten million random numbers onto the queue.
+ c_forrange (n)
+ cqueue_i_push(&queue, stc64_uniform(&rng, &dist));
+
+ // Push or pop on the queue ten million times
+ printf("%d\n", n);
+ c_forrange (n) { // forrange uses initial n only.
+ int r = stc64_uniform(&rng, &dist);
+ if (r & 1)
+ ++n, cqueue_i_push(&queue, r);
+ else
+ --n, cqueue_i_pop(&queue);
+ }
+ printf("%d, %" PRIuMAX "\n", n, cqueue_i_size(queue));
+ }
+}
diff --git a/examples/random.c b/examples/random.c
index 39fd7fa1..fc7745e5 100644
--- a/examples/random.c
+++ b/examples/random.c
@@ -1,43 +1,43 @@
-#include <stdio.h>
-#include <time.h>
-#define i_implement
-#include <stc/crandom.h>
-
-int main()
-{
- const size_t N = 1000000000;
- const uint64_t seed = time(NULL), range = 1000000;
- stc64_t rng = stc64_new(seed);
-
- uint64_t sum;
- clock_t diff, before;
-
- printf("Compare speed of full and unbiased ranged random numbers...\n");
- sum = 0;
- before = clock();
- c_forrange (N) {
- sum += (uint32_t) stc64_rand(&rng);
- }
- diff = clock() - before;
- printf("full range\t\t: %f secs, %" PRIuMAX ", avg: %f\n", (float) diff / CLOCKS_PER_SEC, N, (double) sum / N);
-
- stc64_uniform_t dist1 = stc64_uniform_new(0, range);
- rng = stc64_new(seed);
- sum = 0;
- before = clock();
- c_forrange (N) {
- sum += stc64_uniform(&rng, &dist1); // unbiased
- }
- diff = clock() - before;
- printf("unbiased 0-%" PRIuMAX "\t: %f secs, %" PRIuMAX ", avg: %f\n", range, (float) diff / CLOCKS_PER_SEC, N, (double) sum / N);
-
- sum = 0;
- rng = stc64_new(seed);
- before = clock();
- c_forrange (N) {
- sum += stc64_rand(&rng) % (range + 1); // biased
- }
- diff = clock() - before;
- printf("biased 0-%" PRIuMAX " \t: %f secs, %" PRIuMAX ", avg: %f\n", range, (float) diff / CLOCKS_PER_SEC, N, (double) sum / N);
-
-}
+#include <stdio.h>
+#include <time.h>
+#define i_implement
+#include <stc/crandom.h>
+
+int main()
+{
+ const size_t N = 1000000000;
+ const uint64_t seed = time(NULL), range = 1000000;
+ stc64_t rng = stc64_new(seed);
+
+ uint64_t sum;
+ clock_t diff, before;
+
+ printf("Compare speed of full and unbiased ranged random numbers...\n");
+ sum = 0;
+ before = clock();
+ c_forrange (N) {
+ sum += (uint32_t) stc64_rand(&rng);
+ }
+ diff = clock() - before;
+ printf("full range\t\t: %f secs, %" PRIuMAX ", avg: %f\n", (float) diff / CLOCKS_PER_SEC, N, (double) sum / N);
+
+ stc64_uniform_t dist1 = stc64_uniform_new(0, range);
+ rng = stc64_new(seed);
+ sum = 0;
+ before = clock();
+ c_forrange (N) {
+ sum += stc64_uniform(&rng, &dist1); // unbiased
+ }
+ diff = clock() - before;
+ printf("unbiased 0-%" PRIuMAX "\t: %f secs, %" PRIuMAX ", avg: %f\n", range, (float) diff / CLOCKS_PER_SEC, N, (double) sum / N);
+
+ sum = 0;
+ rng = stc64_new(seed);
+ before = clock();
+ c_forrange (N) {
+ sum += stc64_rand(&rng) % (range + 1); // biased
+ }
+ diff = clock() - before;
+ printf("biased 0-%" PRIuMAX " \t: %f secs, %" PRIuMAX ", avg: %f\n", range, (float) diff / CLOCKS_PER_SEC, N, (double) sum / N);
+
+}
diff --git a/examples/rawptr_elements.c b/examples/rawptr_elements.c
index 64d73843..cfeb459d 100644
--- a/examples/rawptr_elements.c
+++ b/examples/rawptr_elements.c
@@ -1,68 +1,68 @@
-#include <stc/ccommon.h>
-#include <stdio.h>
-
-struct { double x, y; } typedef Point;
-
-// Set of Point pointers: define all template parameters "in-line"
-// Note it may be simpler to use a cbox for this.
-#define i_key Point*
-#define i_keydrop(x) c_free(*(x))
-#define i_keyclone(x) c_new(Point, *(x))
-#define i_hash(x) c_default_hash(*(x))
-#define i_cmp(x, y) memcmp(*(x), *(y), sizeof **(x)) // not good!
-#define i_tag pnt
-#include <stc/cset.h>
-
-#define i_implement
-#include <stc/cstr.h>
-// Map of int64 pointers: Define i_valraw as int64_t for easy emplace calls!
-typedef int64_t inttype;
-#define i_key_str
-#define i_val inttype*
-#define i_valraw inttype
-#define i_valfrom(raw) (puts("from"), c_new(inttype, raw))
-#define i_valto(x) (puts("to"), **(x))
-#define i_valclone c_derived_valclone // enables clone via valto+valfrom
-#define i_valdrop(x) c_free(*(x))
-#include <stc/cmap.h>
-
-int main()
-{
- c_auto (cset_pnt, set, cpy)
- {
- printf("Set with pointer elements:\n");
- // c++: set.insert(new Point{1.2, 3.4});
- cset_pnt_insert(&set, c_new(Point, {1.2, 3.4}));
- Point* q = *cset_pnt_insert(&set, c_new(Point, {6.1, 4.7})).ref;
- cset_pnt_insert(&set, c_new(Point, {5.7, 2.3}));
-
- cpy = cset_pnt_clone(set);
- cset_pnt_erase(&cpy, q);
-
- printf("set:");
- c_foreach (i, cset_pnt, set)
- printf(" (%g %g)", i.ref[0]->x, i.ref[0]->y);
-
- printf("\ncpy:");
- c_foreach (i, cset_pnt, cpy)
- printf(" (%g %g)", i.ref[0]->x, i.ref[0]->y);
- puts("");
- }
-
- c_auto (cmap_str, map, m2)
- {
- printf("\nMap with pointer elements:\n");
- cmap_str_insert(&map, cstr_new("testing"), c_new(inttype, 999));
- cmap_str_insert(&map, cstr_new("done"), c_new(inttype, 111));
-
- // Emplace: implicit key, val construction using i_keyfrom/i_valfrom:
- cmap_str_emplace(&map, "hello", 200);
- cmap_str_emplace(&map, "goodbye", 400);
-
- // default uses i_valfrom+i_valto when no i_valclone defined:
- m2 = cmap_str_clone(map);
-
- c_forpair (name, number, cmap_str, m2)
- printf("%s: %" PRIdMAX "\n", cstr_str(_.name), **_.number);
- }
-}
+#include <stc/ccommon.h>
+#include <stdio.h>
+
+struct { double x, y; } typedef Point;
+
+// Set of Point pointers: define all template parameters "in-line"
+// Note it may be simpler to use a cbox for this.
+#define i_key Point*
+#define i_keydrop(x) c_free(*(x))
+#define i_keyclone(x) c_new(Point, *(x))
+#define i_hash(x) c_default_hash(*(x))
+#define i_cmp(x, y) memcmp(*(x), *(y), sizeof **(x)) // not good!
+#define i_tag pnt
+#include <stc/cset.h>
+
+#define i_implement
+#include <stc/cstr.h>
+// Map of int64 pointers: Define i_valraw as int64_t for easy emplace calls!
+typedef int64_t inttype;
+#define i_key_str
+#define i_val inttype*
+#define i_valraw inttype
+#define i_valfrom(raw) (puts("from"), c_new(inttype, raw))
+#define i_valto(x) (puts("to"), **(x))
+#define i_valclone c_derived_valclone // enables clone via valto+valfrom
+#define i_valdrop(x) c_free(*(x))
+#include <stc/cmap.h>
+
+int main()
+{
+ c_auto (cset_pnt, set, cpy)
+ {
+ printf("Set with pointer elements:\n");
+ // c++: set.insert(new Point{1.2, 3.4});
+ cset_pnt_insert(&set, c_new(Point, {1.2, 3.4}));
+ Point* q = *cset_pnt_insert(&set, c_new(Point, {6.1, 4.7})).ref;
+ cset_pnt_insert(&set, c_new(Point, {5.7, 2.3}));
+
+ cpy = cset_pnt_clone(set);
+ cset_pnt_erase(&cpy, q);
+
+ printf("set:");
+ c_foreach (i, cset_pnt, set)
+ printf(" (%g %g)", i.ref[0]->x, i.ref[0]->y);
+
+ printf("\ncpy:");
+ c_foreach (i, cset_pnt, cpy)
+ printf(" (%g %g)", i.ref[0]->x, i.ref[0]->y);
+ puts("");
+ }
+
+ c_auto (cmap_str, map, m2)
+ {
+ printf("\nMap with pointer elements:\n");
+ cmap_str_insert(&map, cstr_new("testing"), c_new(inttype, 999));
+ cmap_str_insert(&map, cstr_new("done"), c_new(inttype, 111));
+
+ // Emplace: implicit key, val construction using i_keyfrom/i_valfrom:
+ cmap_str_emplace(&map, "hello", 200);
+ cmap_str_emplace(&map, "goodbye", 400);
+
+ // default uses i_valfrom+i_valto when no i_valclone defined:
+ m2 = cmap_str_clone(map);
+
+ c_forpair (name, number, cmap_str, m2)
+ printf("%s: %" PRIdMAX "\n", cstr_str(_.name), **_.number);
+ }
+}
diff --git a/examples/read.c b/examples/read.c
index 67b7e67e..74375a4f 100644
--- a/examples/read.c
+++ b/examples/read.c
@@ -1,26 +1,26 @@
-#define i_implement
-#include <stc/cstr.h>
-#define i_val_str
-#include <stc/cvec.h>
-#include <errno.h>
-
-cvec_str read_file(const char* name)
-{
- cvec_str vec = cvec_str_init();
- c_autovar (FILE* f = fopen(name, "r"), fclose(f))
- c_autovar (cstr line = cstr_init(), cstr_drop(&line))
- while (cstr_getline(&line, f))
- cvec_str_emplace_back(&vec, cstr_str(&line));
- return vec;
-}
-
-int main()
-{
- int n = 0;
- c_autovar (cvec_str vec = read_file(__FILE__), cvec_str_drop(&vec))
- c_foreach (i, cvec_str, vec)
- printf("%5d: %s\n", ++n, cstr_str(i.ref));
-
- if (errno)
- printf("error: read_file(" __FILE__ "). errno: %d\n", errno);
-}
+#define i_implement
+#include <stc/cstr.h>
+#define i_val_str
+#include <stc/cvec.h>
+#include <errno.h>
+
+cvec_str read_file(const char* name)
+{
+ cvec_str vec = cvec_str_init();
+ c_autovar (FILE* f = fopen(name, "r"), fclose(f))
+ c_autovar (cstr line = cstr_init(), cstr_drop(&line))
+ while (cstr_getline(&line, f))
+ cvec_str_emplace_back(&vec, cstr_str(&line));
+ return vec;
+}
+
+int main()
+{
+ int n = 0;
+ c_autovar (cvec_str vec = read_file(__FILE__), cvec_str_drop(&vec))
+ c_foreach (i, cvec_str, vec)
+ printf("%5d: %s\n", ++n, cstr_str(i.ref));
+
+ if (errno)
+ printf("error: read_file(" __FILE__ "). errno: %d\n", errno);
+}
diff --git a/examples/replace.c b/examples/replace.c
index 57018618..6084ede0 100644
--- a/examples/replace.c
+++ b/examples/replace.c
@@ -1,31 +1,31 @@
-#define i_implement
-#include <stc/cstr.h>
-
-int main ()
-{
- const char *base = "this is a test string.";
- const char *s2 = "n example";
- const char *s3 = "sample phrase";
-
- // replace signatures used in the same order as described above:
-
- // Ustring positions: 0123456789*123456789*12345
- cstr s = cstr_from(base); // "this is a test string."
- cstr m = cstr_clone(s);
- c_autodefer (cstr_drop(&s), cstr_drop(&m)) {
- cstr_append(&m, cstr_str(&m));
- cstr_append(&m, cstr_str(&m));
- printf("%s\n", cstr_str(&m));
-
- cstr_replace(&s, 9, 5, s2); // "this is an example string." (1)
- printf("(1) %s\n", cstr_str(&s));
- cstr_replace_n(&s, 19, 6, s3+7, 6); // "this is an example phrase." (2)
- printf("(2) %s\n", cstr_str(&s));
- cstr_replace(&s, 8, 10, "just a"); // "this is just a phrase." (3)
- printf("(3) %s\n", cstr_str(&s));
- cstr_replace_n(&s, 8, 6,"a shorty", 7); // "this is a short phrase." (4)
- printf("(4) %s\n", cstr_str(&s));
- cstr_replace(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5)
- printf("(5) %s\n", cstr_str(&s));
- }
-}
+#define i_implement
+#include <stc/cstr.h>
+
+int main ()
+{
+ const char *base = "this is a test string.";
+ const char *s2 = "n example";
+ const char *s3 = "sample phrase";
+
+ // replace signatures used in the same order as described above:
+
+ // Ustring positions: 0123456789*123456789*12345
+ cstr s = cstr_from(base); // "this is a test string."
+ cstr m = cstr_clone(s);
+ c_autodefer (cstr_drop(&s), cstr_drop(&m)) {
+ cstr_append(&m, cstr_str(&m));
+ cstr_append(&m, cstr_str(&m));
+ printf("%s\n", cstr_str(&m));
+
+ cstr_replace(&s, 9, 5, s2); // "this is an example string." (1)
+ printf("(1) %s\n", cstr_str(&s));
+ cstr_replace_n(&s, 19, 6, s3+7, 6); // "this is an example phrase." (2)
+ printf("(2) %s\n", cstr_str(&s));
+ cstr_replace(&s, 8, 10, "just a"); // "this is just a phrase." (3)
+ printf("(3) %s\n", cstr_str(&s));
+ cstr_replace_n(&s, 8, 6,"a shorty", 7); // "this is a short phrase." (4)
+ printf("(4) %s\n", cstr_str(&s));
+ cstr_replace(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5)
+ printf("(5) %s\n", cstr_str(&s));
+ }
+}
diff --git a/examples/shape.c b/examples/shape.c
index d3534021..051e1c63 100644
--- a/examples/shape.c
+++ b/examples/shape.c
@@ -1,161 +1,161 @@
-// Demo of typesafe polymorphism in C99, using STC.
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stc/ccommon.h>
-
-#define c_dyn_ptr(T, s) \
- (&T##_api == (s)->api ? (T*)(s) : (T*)0)
-
-#define c_vtable(Api, T) \
- c_static_assert(offsetof(T, base) == 0); \
- static Api T##_api
-
-// Shape definition
-// ============================================================
-
-typedef struct {
- float x, y;
-} Point;
-
-typedef struct Shape Shape;
-
-struct ShapeAPI {
- void (*drop)(Shape*);
- void (*draw)(const Shape*);
-};
-
-struct Shape {
- struct ShapeAPI* api;
- uint32_t color;
- uint16_t style;
- uint8_t thickness;
- uint8_t hardness;
-};
-
-void Shape_drop(Shape* shape)
-{
- printf("base destructed\n");
-}
-
-void Shape_delete(Shape* shape)
-{
- if (shape) {
- shape->api->drop(shape);
- c_free(shape);
- }
-}
-
-// Triangle implementation
-// ============================================================
-
-typedef struct {
- Shape base;
- Point p[3];
-} Triangle;
-
-c_vtable(struct ShapeAPI, Triangle);
-
-
-Triangle* Triangle_new(Point a, Point b, Point c)
-{
- return c_new(Triangle, {{.api=&Triangle_api}, .p={a, b, c}});
-}
-
-static void Triangle_draw(const Shape* shape)
-{
- const Triangle* self = c_dyn_ptr(Triangle, shape);
- printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n",
- self->p[0].x, self->p[0].y,
- self->p[1].x, self->p[1].y,
- self->p[2].x, self->p[2].y);
-}
-
-static struct ShapeAPI Triangle_api = {
- .drop = Shape_drop,
- .draw = Triangle_draw,
-};
-
-// Polygon implementation
-// ============================================================
-
-#define i_type PointVec
-#define i_val Point
-#include <stc/cstack.h>
-
-typedef struct {
- Shape base;
- PointVec points;
-} Polygon;
-
-c_vtable(struct ShapeAPI, Polygon);
-
-
-Polygon* Polygon_new(void)
-{
- return c_new(Polygon, {{.api=&Polygon_api}, .points=PointVec_init()});
-}
-
-void Polygon_addPoint(Polygon* self, Point p)
-{
- PointVec_push(&self->points, p);
-}
-
-static void Polygon_drop(Shape* shape)
-{
- Polygon* self = c_dyn_ptr(Polygon, shape);
- printf("poly destructed\n");
- PointVec_drop(&self->points);
- Shape_drop(shape);
-}
-
-static void Polygon_draw(const Shape* shape)
-{
- const Polygon* self = c_dyn_ptr(Polygon, shape);
- printf("Polygon :");
- c_foreach (i, PointVec, self->points)
- printf(" (%g,%g)", i.ref->x, i.ref->y);
- puts("");
-}
-
-static struct ShapeAPI Polygon_api = {
- .drop = Polygon_drop,
- .draw = Polygon_draw,
-};
-
-// Test
-// ============================================================
-
-#define i_type Shapes
-#define i_val Shape*
-#define i_valdrop(x) Shape_delete(*x)
-#include <stc/cstack.h>
-
-void testShape(const Shape* shape)
-{
- shape->api->draw(shape);
-}
-
-
-int main(void)
-{
- c_auto (Shapes, shapes)
- {
- Triangle* tri1 = Triangle_new((Point){5, 7}, (Point){12, 7}, (Point){12, 20});
- Polygon* pol1 = Polygon_new();
- Polygon* pol2 = Polygon_new();
-
- c_apply(p, Polygon_addPoint(pol1, *p), Point,
- {{50, 72}, {123, 73}, {127, 201}, {828, 333}});
-
- c_apply(p, Polygon_addPoint(pol2, *p), Point,
- {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}});
-
- Shapes_push(&shapes, &tri1->base);
- Shapes_push(&shapes, &pol1->base);
- Shapes_push(&shapes, &pol2->base);
-
- c_foreach (i, Shapes, shapes)
- testShape(*i.ref);
- }
-}
+// Demo of typesafe polymorphism in C99, using STC.
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stc/ccommon.h>
+
+#define c_dyn_ptr(T, s) \
+ (&T##_api == (s)->api ? (T*)(s) : (T*)0)
+
+#define c_vtable(Api, T) \
+ c_static_assert(offsetof(T, base) == 0); \
+ static Api T##_api
+
+// Shape definition
+// ============================================================
+
+typedef struct {
+ float x, y;
+} Point;
+
+typedef struct Shape Shape;
+
+struct ShapeAPI {
+ void (*drop)(Shape*);
+ void (*draw)(const Shape*);
+};
+
+struct Shape {
+ struct ShapeAPI* api;
+ uint32_t color;
+ uint16_t style;
+ uint8_t thickness;
+ uint8_t hardness;
+};
+
+void Shape_drop(Shape* shape)
+{
+ printf("base destructed\n");
+}
+
+void Shape_delete(Shape* shape)
+{
+ if (shape) {
+ shape->api->drop(shape);
+ c_free(shape);
+ }
+}
+
+// Triangle implementation
+// ============================================================
+
+typedef struct {
+ Shape base;
+ Point p[3];
+} Triangle;
+
+c_vtable(struct ShapeAPI, Triangle);
+
+
+Triangle* Triangle_new(Point a, Point b, Point c)
+{
+ return c_new(Triangle, {{.api=&Triangle_api}, .p={a, b, c}});
+}
+
+static void Triangle_draw(const Shape* shape)
+{
+ const Triangle* self = c_dyn_ptr(Triangle, shape);
+ printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n",
+ self->p[0].x, self->p[0].y,
+ self->p[1].x, self->p[1].y,
+ self->p[2].x, self->p[2].y);
+}
+
+static struct ShapeAPI Triangle_api = {
+ .drop = Shape_drop,
+ .draw = Triangle_draw,
+};
+
+// Polygon implementation
+// ============================================================
+
+#define i_type PointVec
+#define i_val Point
+#include <stc/cstack.h>
+
+typedef struct {
+ Shape base;
+ PointVec points;
+} Polygon;
+
+c_vtable(struct ShapeAPI, Polygon);
+
+
+Polygon* Polygon_new(void)
+{
+ return c_new(Polygon, {{.api=&Polygon_api}, .points=PointVec_init()});
+}
+
+void Polygon_addPoint(Polygon* self, Point p)
+{
+ PointVec_push(&self->points, p);
+}
+
+static void Polygon_drop(Shape* shape)
+{
+ Polygon* self = c_dyn_ptr(Polygon, shape);
+ printf("poly destructed\n");
+ PointVec_drop(&self->points);
+ Shape_drop(shape);
+}
+
+static void Polygon_draw(const Shape* shape)
+{
+ const Polygon* self = c_dyn_ptr(Polygon, shape);
+ printf("Polygon :");
+ c_foreach (i, PointVec, self->points)
+ printf(" (%g,%g)", i.ref->x, i.ref->y);
+ puts("");
+}
+
+static struct ShapeAPI Polygon_api = {
+ .drop = Polygon_drop,
+ .draw = Polygon_draw,
+};
+
+// Test
+// ============================================================
+
+#define i_type Shapes
+#define i_val Shape*
+#define i_valdrop(x) Shape_delete(*x)
+#include <stc/cstack.h>
+
+void testShape(const Shape* shape)
+{
+ shape->api->draw(shape);
+}
+
+
+int main(void)
+{
+ c_auto (Shapes, shapes)
+ {
+ Triangle* tri1 = Triangle_new((Point){5, 7}, (Point){12, 7}, (Point){12, 20});
+ Polygon* pol1 = Polygon_new();
+ Polygon* pol2 = Polygon_new();
+
+ c_apply(p, Polygon_addPoint(pol1, *p), Point,
+ {{50, 72}, {123, 73}, {127, 201}, {828, 333}});
+
+ c_apply(p, Polygon_addPoint(pol2, *p), Point,
+ {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}});
+
+ Shapes_push(&shapes, &tri1->base);
+ Shapes_push(&shapes, &pol1->base);
+ Shapes_push(&shapes, &pol2->base);
+
+ c_foreach (i, Shapes, shapes)
+ testShape(*i.ref);
+ }
+}
diff --git a/examples/shape.cpp b/examples/shape.cpp
index b451b5ba..ea1f53d2 100644
--- a/examples/shape.cpp
+++ b/examples/shape.cpp
@@ -1,122 +1,122 @@
-// Demo of polymorphism in C++
-
-#include <iostream>
-#include <memory>
-#include <vector>
-
-// Shape definition
-// ============================================================
-
-struct Point {
- float x, y;
-};
-
-std::ostream& operator<<(std::ostream& os, const Point& p) {
- os << " (" << p.x << "," << p.y << ")";
- return os;
-}
-
-struct Shape {
- virtual ~Shape();
- virtual void draw() const = 0;
-
- uint32_t color;
- uint16_t style;
- uint8_t thickness;
- uint8_t hardness;
-};
-
-Shape::~Shape()
-{
- std::cout << "base destructed" << std::endl;
-}
-
-// Triangle implementation
-// ============================================================
-
-struct Triangle : public Shape
-{
- Triangle(Point a, Point b, Point c);
- void draw() const override;
-
- private: Point p[3];
-};
-
-
-Triangle::Triangle(Point a, Point b, Point c)
- : p{a, b, c} {}
-
-void Triangle::draw() const
-{
- std::cout << "Triangle :"
- << p[0] << p[1] << p[2]
- << std::endl;
-}
-
-
-// Polygon implementation
-// ============================================================
-
-
-struct Polygon : public Shape
-{
- ~Polygon();
- void draw() const override;
- void addPoint(const Point& p);
-
- private: std::vector<Point> points;
-};
-
-
-void Polygon::addPoint(const Point& p)
-{
- points.push_back(p);
-}
-
-Polygon::~Polygon()
-{
- std::cout << "poly destructed" << std::endl;
-}
-
-void Polygon::draw() const
-{
- std::cout << "Polygon :";
- for (auto& p : points)
- std::cout << p ;
- std::cout << std::endl;
-}
-
-
-// Test
-// ============================================================
-
-void testShape(const Shape* shape)
-{
- shape->draw();
-}
-
-#include <array>
-
-int main(void)
-{
- std::vector<std::unique_ptr<Shape>> shapes;
-
- auto tri1 = std::make_unique<Triangle>(Point{5, 7}, Point{12, 7}, Point{12, 20});
- auto pol1 = std::make_unique<Polygon>();
- auto pol2 = std::make_unique<Polygon>();
-
- for (auto& p: std::array<Point, 4>
- {{{50, 72}, {123, 73}, {127, 201}, {828, 333}}})
- pol1->addPoint(p);
-
- for (auto& p: std::array<Point, 5>
- {{{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}})
- pol2->addPoint(p);
-
- shapes.push_back(std::move(tri1));
- shapes.push_back(std::move(pol1));
- shapes.push_back(std::move(pol2));
-
- for (auto& shape: shapes)
- testShape(shape.get());
-}
+// Demo of polymorphism in C++
+
+#include <iostream>
+#include <memory>
+#include <vector>
+
+// Shape definition
+// ============================================================
+
+struct Point {
+ float x, y;
+};
+
+std::ostream& operator<<(std::ostream& os, const Point& p) {
+ os << " (" << p.x << "," << p.y << ")";
+ return os;
+}
+
+struct Shape {
+ virtual ~Shape();
+ virtual void draw() const = 0;
+
+ uint32_t color;
+ uint16_t style;
+ uint8_t thickness;
+ uint8_t hardness;
+};
+
+Shape::~Shape()
+{
+ std::cout << "base destructed" << std::endl;
+}
+
+// Triangle implementation
+// ============================================================
+
+struct Triangle : public Shape
+{
+ Triangle(Point a, Point b, Point c);
+ void draw() const override;
+
+ private: Point p[3];
+};
+
+
+Triangle::Triangle(Point a, Point b, Point c)
+ : p{a, b, c} {}
+
+void Triangle::draw() const
+{
+ std::cout << "Triangle :"
+ << p[0] << p[1] << p[2]
+ << std::endl;
+}
+
+
+// Polygon implementation
+// ============================================================
+
+
+struct Polygon : public Shape
+{
+ ~Polygon();
+ void draw() const override;
+ void addPoint(const Point& p);
+
+ private: std::vector<Point> points;
+};
+
+
+void Polygon::addPoint(const Point& p)
+{
+ points.push_back(p);
+}
+
+Polygon::~Polygon()
+{
+ std::cout << "poly destructed" << std::endl;
+}
+
+void Polygon::draw() const
+{
+ std::cout << "Polygon :";
+ for (auto& p : points)
+ std::cout << p ;
+ std::cout << std::endl;
+}
+
+
+// Test
+// ============================================================
+
+void testShape(const Shape* shape)
+{
+ shape->draw();
+}
+
+#include <array>
+
+int main(void)
+{
+ std::vector<std::unique_ptr<Shape>> shapes;
+
+ auto tri1 = std::make_unique<Triangle>(Point{5, 7}, Point{12, 7}, Point{12, 20});
+ auto pol1 = std::make_unique<Polygon>();
+ auto pol2 = std::make_unique<Polygon>();
+
+ for (auto& p: std::array<Point, 4>
+ {{{50, 72}, {123, 73}, {127, 201}, {828, 333}}})
+ pol1->addPoint(p);
+
+ for (auto& p: std::array<Point, 5>
+ {{{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}})
+ pol2->addPoint(p);
+
+ shapes.push_back(std::move(tri1));
+ shapes.push_back(std::move(pol1));
+ shapes.push_back(std::move(pol2));
+
+ for (auto& shape: shapes)
+ testShape(shape.get());
+}
diff --git a/examples/sidebyside.cpp b/examples/sidebyside.cpp
index 89446b23..4d63496b 100644
--- a/examples/sidebyside.cpp
+++ b/examples/sidebyside.cpp
@@ -1,54 +1,54 @@
-#include <iostream>
-#include <map>
-#include <string>
-
-#define i_key_str
-#define i_val int
-#define i_tag si
-#include <stc/cmap.h>
-
-#define i_key int
-#define i_val int
-#define i_tag ii
-#include <stc/csmap.h>
-
-int main() {
- {
- std::map<std::string, int> food =
- {{"burger", 5}, {"pizza", 12}, {"steak", 15}};
-
- for (auto i: food)
- std::cout << i.first << ", " << i.second << std::endl;
- std::cout << std::endl;
- }
- c_auto (cmap_si, food)
- {
- c_apply(v, cmap_si_emplace(&food, c_pair(v)), cmap_si_raw,
- {{"burger", 5}, {"pizza", 12}, {"steak", 15}});
-
- c_foreach (i, cmap_si, food)
- printf("%s, %d\n", i.ref->first.str, i.ref->second);
- puts("");
- }
-
- {
- std::map<int, int> hist;
- ++ hist.emplace(12, 100).first->second;
- ++ hist.emplace(13, 100).first->second;
- ++ hist.emplace(12, 100).first->second;
-
- for (auto i: hist)
- std::cout << i.first << ", " << i.second << std::endl;
- std::cout << std::endl;
- }
- c_auto (csmap_ii, hist)
- {
- ++ csmap_ii_insert(&hist, 12, 100).ref->second;
- ++ csmap_ii_insert(&hist, 13, 100).ref->second;
- ++ csmap_ii_insert(&hist, 12, 100).ref->second;
-
- c_foreach (i, csmap_ii, hist)
- printf("%d, %d\n", i.ref->first, i.ref->second);
- puts("");
- }
-}
+#include <iostream>
+#include <map>
+#include <string>
+
+#define i_key_str
+#define i_val int
+#define i_tag si
+#include <stc/cmap.h>
+
+#define i_key int
+#define i_val int
+#define i_tag ii
+#include <stc/csmap.h>
+
+int main() {
+ {
+ std::map<std::string, int> food =
+ {{"burger", 5}, {"pizza", 12}, {"steak", 15}};
+
+ for (auto i: food)
+ std::cout << i.first << ", " << i.second << std::endl;
+ std::cout << std::endl;
+ }
+ c_auto (cmap_si, food)
+ {
+ c_apply(v, cmap_si_emplace(&food, c_pair(v)), cmap_si_raw,
+ {{"burger", 5}, {"pizza", 12}, {"steak", 15}});
+
+ c_foreach (i, cmap_si, food)
+ printf("%s, %d\n", i.ref->first.str, i.ref->second);
+ puts("");
+ }
+
+ {
+ std::map<int, int> hist;
+ ++ hist.emplace(12, 100).first->second;
+ ++ hist.emplace(13, 100).first->second;
+ ++ hist.emplace(12, 100).first->second;
+
+ for (auto i: hist)
+ std::cout << i.first << ", " << i.second << std::endl;
+ std::cout << std::endl;
+ }
+ c_auto (csmap_ii, hist)
+ {
+ ++ csmap_ii_insert(&hist, 12, 100).ref->second;
+ ++ csmap_ii_insert(&hist, 13, 100).ref->second;
+ ++ csmap_ii_insert(&hist, 12, 100).ref->second;
+
+ c_foreach (i, csmap_ii, hist)
+ printf("%d, %d\n", i.ref->first, i.ref->second);
+ puts("");
+ }
+}
diff --git a/examples/splitstr.c b/examples/splitstr.c
index 0cd48067..a155830c 100644
--- a/examples/splitstr.c
+++ b/examples/splitstr.c
@@ -1,39 +1,39 @@
-#define i_implement
-#include <stc/cstr.h>
-#define i_implement
-#include <stc/csview.h>
-#define i_val_str
-#include <stc/cvec.h>
-
-void print_split(csview str, csview sep)
-{
- size_t pos = 0;
- while (pos != str.size) {
- csview tok = csview_token(str, sep, &pos);
- // print non-null-terminated csview
- printf("[%" c_PRIsv "]\n", c_ARGsv(tok));
- }
-}
-
-cvec_str string_split(csview str, csview sep)
-{
- cvec_str vec = cvec_str_init();
- size_t pos = 0;
- while (pos != str.size) {
- csview tok = csview_token(str, sep, &pos);
- cvec_str_push_back(&vec, cstr_from_sv(tok));
- }
- return vec;
-}
-
-int main()
-{
- print_split(c_sv("//This is a//double-slash//separated//string"), c_sv("//"));
- puts("");
- print_split(c_sv("This has no matching separator"), c_sv("xx"));
- puts("");
-
- c_autovar (cvec_str v = string_split(c_sv("Split,this,,string,now,"), c_sv(",")), cvec_str_drop(&v))
- c_foreach (i, cvec_str, v)
- printf("[%s]\n", cstr_str(i.ref));
-}
+#define i_implement
+#include <stc/cstr.h>
+#define i_implement
+#include <stc/csview.h>
+#define i_val_str
+#include <stc/cvec.h>
+
+void print_split(csview str, csview sep)
+{
+ size_t pos = 0;
+ while (pos != str.size) {
+ csview tok = csview_token(str, sep, &pos);
+ // print non-null-terminated csview
+ printf("[%" c_PRIsv "]\n", c_ARGsv(tok));
+ }
+}
+
+cvec_str string_split(csview str, csview sep)
+{
+ cvec_str vec = cvec_str_init();
+ size_t pos = 0;
+ while (pos != str.size) {
+ csview tok = csview_token(str, sep, &pos);
+ cvec_str_push_back(&vec, cstr_from_sv(tok));
+ }
+ return vec;
+}
+
+int main()
+{
+ print_split(c_sv("//This is a//double-slash//separated//string"), c_sv("//"));
+ puts("");
+ print_split(c_sv("This has no matching separator"), c_sv("xx"));
+ puts("");
+
+ c_autovar (cvec_str v = string_split(c_sv("Split,this,,string,now,"), c_sv(",")), cvec_str_drop(&v))
+ c_foreach (i, cvec_str, v)
+ printf("[%s]\n", cstr_str(i.ref));
+}
diff --git a/examples/sso_map.c b/examples/sso_map.c
index 53fac3e3..823398e1 100644
--- a/examples/sso_map.c
+++ b/examples/sso_map.c
@@ -1,18 +1,18 @@
-#define i_implement
-#include <stc/cstr.h>
-#define i_key_str
-#define i_val_str
-#include <stc/cmap.h>
-
-int main()
-{
- c_auto (cmap_str, m) {
- cmap_str_emplace(&m, "Test short", "This is a short string.");
- cmap_str_emplace(&m, "Test long ", "This is a longer string.");
-
- c_forpair (k, v, cmap_str, m)
- printf("%s: '%s' Len=%" PRIuMAX ", Is long: %s\n",
- cstr_str(_.k), cstr_str(_.v), cstr_size(*_.v),
- cstr_is_long(_.v)?"true":"false");
- }
-}
+#define i_implement
+#include <stc/cstr.h>
+#define i_key_str
+#define i_val_str
+#include <stc/cmap.h>
+
+int main()
+{
+ c_auto (cmap_str, m) {
+ cmap_str_emplace(&m, "Test short", "This is a short string.");
+ cmap_str_emplace(&m, "Test long ", "This is a longer string.");
+
+ c_forpair (k, v, cmap_str, m)
+ printf("%s: '%s' Len=%" PRIuMAX ", Is long: %s\n",
+ cstr_str(_.k), cstr_str(_.v), cstr_size(*_.v),
+ cstr_is_long(_.v)?"true":"false");
+ }
+}
diff --git a/examples/stack.c b/examples/stack.c
index 29b39aef..ca809c97 100644
--- a/examples/stack.c
+++ b/examples/stack.c
@@ -1,29 +1,29 @@
-
-#include <stdio.h>
-
-#define i_tag i
-#define i_val int
-#include <stc/cstack.h>
-
-#define i_tag c
-#define i_val char
-#include <stc/cstack.h>
-
-int main() {
- c_auto (cstack_i, stack)
- c_auto (cstack_c, chars)
- {
- c_forrange (i, int, 101)
- cstack_i_push(&stack, i*i);
-
- printf("%d\n", *cstack_i_top(&stack));
-
- c_forrange (i, int, 90)
- cstack_i_pop(&stack);
-
- c_foreach (i, cstack_i, stack)
- printf(" %d", *i.ref);
- puts("");
- printf("top: %d\n", *cstack_i_top(&stack));
- }
-}
+
+#include <stdio.h>
+
+#define i_tag i
+#define i_val int
+#include <stc/cstack.h>
+
+#define i_tag c
+#define i_val char
+#include <stc/cstack.h>
+
+int main() {
+ c_auto (cstack_i, stack)
+ c_auto (cstack_c, chars)
+ {
+ c_forrange (i, int, 101)
+ cstack_i_push(&stack, i*i);
+
+ printf("%d\n", *cstack_i_top(&stack));
+
+ c_forrange (i, int, 90)
+ cstack_i_pop(&stack);
+
+ c_foreach (i, cstack_i, stack)
+ printf(" %d", *i.ref);
+ puts("");
+ printf("top: %d\n", *cstack_i_top(&stack));
+ }
+}
diff --git a/examples/sview_split.c b/examples/sview_split.c
index 8c3d7120..2c7ce395 100644
--- a/examples/sview_split.c
+++ b/examples/sview_split.c
@@ -1,21 +1,21 @@
-#define STC_IMPLEMENT
-#include <stc/cstr.h>
-#include <stc/csview.h>
-
-int main()
-{
- // No memory allocations or string length calculations!
- const csview date = c_sv("2021/03/12");
- size_t pos = 0;
- const csview year = csview_token(date, c_sv("/"), &pos);
- const csview month = csview_token(date, c_sv("/"), &pos);
- const csview day = csview_token(date, c_sv("/"), &pos);
-
- printf("%" c_PRIsv ", %" c_PRIsv ", %" c_PRIsv "\n",
- c_ARGsv(year), c_ARGsv(month), c_ARGsv(day));
-
- c_auto (cstr, y, m, d) {
- y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day);
- printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d));
- }
-}
+#define STC_IMPLEMENT
+#include <stc/cstr.h>
+#include <stc/csview.h>
+
+int main()
+{
+ // No memory allocations or string length calculations!
+ const csview date = c_sv("2021/03/12");
+ size_t pos = 0;
+ const csview year = csview_token(date, c_sv("/"), &pos);
+ const csview month = csview_token(date, c_sv("/"), &pos);
+ const csview day = csview_token(date, c_sv("/"), &pos);
+
+ printf("%" c_PRIsv ", %" c_PRIsv ", %" c_PRIsv "\n",
+ c_ARGsv(year), c_ARGsv(month), c_ARGsv(day));
+
+ c_auto (cstr, y, m, d) {
+ y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day);
+ printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d));
+ }
+}
diff --git a/examples/unordered_map.c b/examples/unordered_map.c
index 7af6fa0a..c4a05c76 100644
--- a/examples/unordered_map.c
+++ b/examples/unordered_map.c
@@ -1,64 +1,64 @@
-// https://iq.opengenus.org/containers-cpp-stl/
-
-#define i_key int
-#define i_val int
-#include <stc/csmap.h>
-#include <stdio.h>
-
-int main()
-{
-
- // empty map containers
- c_auto (csmap_int, gquiz1, gquiz2)
- {
- // insert elements in random order
- csmap_int_insert(&gquiz1, 2, 30);
- csmap_int_insert(&gquiz1, 4, 20);
- csmap_int_insert(&gquiz1, 7, 10);
- csmap_int_insert(&gquiz1, 5, 50);
- csmap_int_insert(&gquiz1, 3, 60);
- csmap_int_insert(&gquiz1, 1, 40);
- csmap_int_insert(&gquiz1, 6, 50);
-
- // printing map gquiz1
- printf("\nThe map gquiz1 is :\n\tKEY\tELEMENT\n");
- c_foreach (itr, csmap_int, gquiz1)
- printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
- printf("\n");
-
- // assigning the elements from gquiz1 to gquiz2
- c_foreach (i, csmap_int, gquiz1)
- csmap_int_insert(&gquiz2, i.ref->first, i.ref->second);
-
- // print all elements of the map gquiz2
- printf("\nThe map gquiz2 is :\n\tKEY\tELEMENT\n");
- c_foreach (itr, csmap_int, gquiz2)
- printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
- printf("\n");
-
- // remove all elements up to element with key=3 in gquiz2
- printf("\ngquiz2 after removal of elements less than key=3 :\n");
- printf("\tKEY\tELEMENT\n");
- csmap_int_erase_range(&gquiz2, csmap_int_begin(&gquiz2),
- csmap_int_find(&gquiz2, 3));
- c_foreach (itr, csmap_int, gquiz2)
- printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
- printf("\n");
-
- // remove all elements with key = 4
- int num = csmap_int_erase(&gquiz2, 4);
- printf("\ngquiz2.erase(4) : %d removed\n", num);
- printf("\tKEY\tELEMENT\n");
- c_foreach (itr, csmap_int, gquiz2)
- printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
- printf("\n");
-
- // lower bound and upper bound for map gquiz1 key = 5
- printf("gquiz1.lower_bound(5) : ");
- printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5).ref->first);
- printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5).ref->second);
- printf("gquiz1.upper_bound(5) : ");
- printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5+1).ref->first);
- printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5+1).ref->second);
- }
-}
+// https://iq.opengenus.org/containers-cpp-stl/
+
+#define i_key int
+#define i_val int
+#include <stc/csmap.h>
+#include <stdio.h>
+
+int main()
+{
+
+ // empty map containers
+ c_auto (csmap_int, gquiz1, gquiz2)
+ {
+ // insert elements in random order
+ csmap_int_insert(&gquiz1, 2, 30);
+ csmap_int_insert(&gquiz1, 4, 20);
+ csmap_int_insert(&gquiz1, 7, 10);
+ csmap_int_insert(&gquiz1, 5, 50);
+ csmap_int_insert(&gquiz1, 3, 60);
+ csmap_int_insert(&gquiz1, 1, 40);
+ csmap_int_insert(&gquiz1, 6, 50);
+
+ // printing map gquiz1
+ printf("\nThe map gquiz1 is :\n\tKEY\tELEMENT\n");
+ c_foreach (itr, csmap_int, gquiz1)
+ printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
+ printf("\n");
+
+ // assigning the elements from gquiz1 to gquiz2
+ c_foreach (i, csmap_int, gquiz1)
+ csmap_int_insert(&gquiz2, i.ref->first, i.ref->second);
+
+ // print all elements of the map gquiz2
+ printf("\nThe map gquiz2 is :\n\tKEY\tELEMENT\n");
+ c_foreach (itr, csmap_int, gquiz2)
+ printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
+ printf("\n");
+
+ // remove all elements up to element with key=3 in gquiz2
+ printf("\ngquiz2 after removal of elements less than key=3 :\n");
+ printf("\tKEY\tELEMENT\n");
+ csmap_int_erase_range(&gquiz2, csmap_int_begin(&gquiz2),
+ csmap_int_find(&gquiz2, 3));
+ c_foreach (itr, csmap_int, gquiz2)
+ printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
+ printf("\n");
+
+ // remove all elements with key = 4
+ int num = csmap_int_erase(&gquiz2, 4);
+ printf("\ngquiz2.erase(4) : %d removed\n", num);
+ printf("\tKEY\tELEMENT\n");
+ c_foreach (itr, csmap_int, gquiz2)
+ printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
+ printf("\n");
+
+ // lower bound and upper bound for map gquiz1 key = 5
+ printf("gquiz1.lower_bound(5) : ");
+ printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5).ref->first);
+ printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5).ref->second);
+ printf("gquiz1.upper_bound(5) : ");
+ printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5+1).ref->first);
+ printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5+1).ref->second);
+ }
+}
diff --git a/examples/unordered_set.c b/examples/unordered_set.c
index 9ecd59fe..99a9da49 100644
--- a/examples/unordered_set.c
+++ b/examples/unordered_set.c
@@ -1,43 +1,43 @@
-// https://iq.opengenus.org/containers-cpp-stl/
-// C program to demonstrate various function of stc cset
-#define i_implement
-#include <stc/cstr.h>
-#define i_key_str
-#include <stc/cset.h>
-
-int main()
-{
- // declaring set for storing string data-type
- c_auto (cset_str, stringSet)
- {
- // inserting various string, same string will be stored
- // once in set
- cset_str_emplace(&stringSet, "code");
- cset_str_emplace(&stringSet, "in");
- cset_str_emplace(&stringSet, "C");
- cset_str_emplace(&stringSet, "is");
- cset_str_emplace(&stringSet, "fast");
-
- const char* key = "slow";
-
- // find returns end iterator if key is not found,
- // else it returns iterator to that key
-
- if (cset_str_find(&stringSet, key).ref == cset_str_end(&stringSet).ref)
- printf("\"%s\" not found\n", key);
- else
- printf("Found \"%s\"\n", key);
-
- key = "C";
- if (!cset_str_contains(&stringSet, key))
- printf("\"%s\" not found\n", key);
- else
- printf("Found \"%s\"\n", key);
-
- // now iterating over whole set and printing its
- // content
- printf("All elements :\n");
- c_foreach (itr, cset_str, stringSet)
- printf("%s\n", cstr_str(itr.ref));
- }
-}
+// https://iq.opengenus.org/containers-cpp-stl/
+// C program to demonstrate various function of stc cset
+#define i_implement
+#include <stc/cstr.h>
+#define i_key_str
+#include <stc/cset.h>
+
+int main()
+{
+ // declaring set for storing string data-type
+ c_auto (cset_str, stringSet)
+ {
+ // inserting various string, same string will be stored
+ // once in set
+ cset_str_emplace(&stringSet, "code");
+ cset_str_emplace(&stringSet, "in");
+ cset_str_emplace(&stringSet, "C");
+ cset_str_emplace(&stringSet, "is");
+ cset_str_emplace(&stringSet, "fast");
+
+ const char* key = "slow";
+
+ // find returns end iterator if key is not found,
+ // else it returns iterator to that key
+
+ if (cset_str_find(&stringSet, key).ref == cset_str_end(&stringSet).ref)
+ printf("\"%s\" not found\n", key);
+ else
+ printf("Found \"%s\"\n", key);
+
+ key = "C";
+ if (!cset_str_contains(&stringSet, key))
+ printf("\"%s\" not found\n", key);
+ else
+ printf("Found \"%s\"\n", key);
+
+ // now iterating over whole set and printing its
+ // content
+ printf("All elements :\n");
+ c_foreach (itr, cset_str, stringSet)
+ printf("%s\n", cstr_str(itr.ref));
+ }
+}
diff --git a/include/stc/alt/csmap.h b/include/stc/alt/csmap.h
index 1e6f1836..168cf480 100644
--- a/include/stc/alt/csmap.h
+++ b/include/stc/alt/csmap.h
@@ -1,512 +1,512 @@
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-
-// 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>
-
-int main(void) {
- c_autovar (csmap_sx m = csmap_sx_init(), csmap_sx_drop(&m))
- {
- 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_sx_value *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_sx, m)
- printf("map %s: %g\n", cstr_str(&i.ref->first), i.ref->second);
- }
-}
-*/
-#include <stc/ccommon.h>
-
-#ifndef CSMAP_H_INCLUDED
-#define STC_CSMAP_V1 1
-#include <stc/forward.h>
-#include <stdlib.h>
-#include <string.h>
-#endif // CSMAP_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix csmap_
-#endif
-#ifdef _i_isset
- #define _i_MAP_ONLY c_false
- #define _i_SET_ONLY c_true
- #define _i_keyref(vp) (vp)
-#else
- #define _i_ismap
- #define _i_MAP_ONLY c_true
- #define _i_SET_ONLY c_false
- #define _i_keyref(vp) (&(vp)->first)
-#endif
-#include <stc/template.h>
-
-#if !c_option(c_is_fwd)
-_cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_size, _i_MAP_ONLY, _i_SET_ONLY);
-#endif
-
-_i_MAP_ONLY( struct _cx_value {
- _cx_key first;
- _cx_mapped second;
-}; )
-struct _cx_node {
- struct _cx_node *link[2];
- uint8_t level;
- _cx_value value;
-};
-
-typedef i_keyraw _cx_rawkey;
-typedef i_valraw _cx_memb(_rawmapped);
-typedef _i_SET_ONLY( i_keyraw )
- _i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } )
- _cx_raw;
-
-#if !defined _i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
-#if !defined _i_no_emplace
-STC_API _cx_result _cx_memb(_emplace)(_cx_self* self, i_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped));
-#endif // !_i_no_emplace
-#endif // !_i_no_clone
-STC_API _cx_self _cx_memb(_init)(void);
-STC_API _cx_result _cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped));
-STC_API _cx_result _cx_memb(_push)(_cx_self* self, _cx_value _val);
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API _cx_value* _cx_memb(_find_it)(const _cx_self* self, i_keyraw rkey, _cx_iter* out);
-STC_API _cx_iter _cx_memb(_lower_bound)(const _cx_self* self, i_keyraw rkey);
-STC_API _cx_value* _cx_memb(_front)(const _cx_self* self);
-STC_API _cx_value* _cx_memb(_back)(const _cx_self* self);
-STC_API int _cx_memb(_erase)(_cx_self* self, i_keyraw rkey);
-STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it);
-STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2);
-STC_API void _cx_memb(_next)(_cx_iter* it);
-
-STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return cx.size == 0; }
-STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return cx.size; }
-STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); }
-STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, i_keyraw rkey)
- { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); return it; }
-STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, i_keyraw rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it) != NULL; }
-STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, i_keyraw rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
-STC_INLINE _cx_value* _cx_memb(_get_mut)(_cx_self* self, i_keyraw rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
-
-STC_INLINE void
-_cx_memb(_clear)(_cx_self* self)
- { _cx_memb(_drop)(self); *self = _cx_memb(_init)(); }
-
-STC_INLINE _cx_raw
-_cx_memb(_value_toraw)(_cx_value* val) {
- return _i_SET_ONLY( i_keyto(val) )
- _i_MAP_ONLY( c_make(_cx_raw){i_keyto((&val->first)),
- i_valto((&val->second))} );
-}
-
-STC_INLINE int
-_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- _cx_rawkey rx = i_keyto(_i_keyref(x)), ry = i_keyto(_i_keyref(y));
- return i_cmp((&rx), (&ry));
-}
-
-STC_INLINE void
-_cx_memb(_value_drop)(_cx_value* val) {
- i_keydrop(_i_keyref(val));
- _i_MAP_ONLY( i_valdrop((&val->second)); )
-}
-
-#if !defined _i_no_clone
-STC_INLINE _cx_value
-_cx_memb(_value_clone)(_cx_value _val) {
- *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val)));
- _i_MAP_ONLY( _val.second = i_valclone(_val.second); )
- return _val;
-}
-
-STC_INLINE void
-_cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->root == other.root)
- return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(other);
-}
-#endif // !_i_no_clone
-
-#ifndef _i_isset
- #if !defined _i_no_clone && !defined _i_no_emplace
- STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, i_keyraw rkey, i_valraw rmapped);
- #endif
- STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped);
-
- STC_INLINE const _cx_mapped*
- _cx_memb(_at)(const _cx_self* self, i_keyraw rkey)
- { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
- STC_INLINE _cx_mapped*
- _cx_memb(_at_mut)(_cx_self* self, i_keyraw rkey)
- { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
-#endif // !_i_isset
-
-STC_INLINE _cx_iter
-_cx_memb(_begin)(const _cx_self* self) {
- _cx_iter it;
- it.ref = NULL, it._top = 0, it._tn = self->root;
- _cx_memb(_next)(&it);
- return it;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_end)(const _cx_self* self) {
- (void)self;
- _cx_iter it; it.ref = NULL, it._top = 0, it._tn = NULL;
- return it;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_advance)(_cx_iter it, size_t n) {
- while (n-- && it.ref)
- _cx_memb(_next)(&it);
- return it;
-}
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-#ifndef CSMAP_H_INCLUDED
-static struct { void *link[2]; uint8_t level; }
-_csmap_sentinel = {{&_csmap_sentinel, &_csmap_sentinel}, 0};
-#endif
-
-static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, i_keyraw rkey);
-
-STC_DEF _cx_self
-_cx_memb(_init)(void) {
- _cx_self cx = {(_cx_node *)&_csmap_sentinel, 0};
- return cx;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_front)(const _cx_self* self) {
- _cx_node *tn = self->root;
- while (tn->link[0]->level)
- tn = tn->link[0];
- return &tn->value;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_back)(const _cx_self* self) {
- _cx_node *tn = self->root;
- while (tn->link[1]->level)
- tn = tn->link[1];
- return &tn->value;
-}
-
-STC_DEF _cx_result
-_cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped)) {
- _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key)));
- if (res.inserted)
- { *_i_keyref(res.ref) = key; _i_MAP_ONLY( res.ref->second = mapped; )}
- else
- { i_keydrop((&key)); _i_MAP_ONLY( i_valdrop((&mapped)); )}
- return res;
-}
-
-STC_DEF _cx_result
-_cx_memb(_push)(_cx_self* self, _cx_value _val) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
- if (_res.inserted)
- *_res.ref = _val;
- else
- _cx_memb(_value_drop)(&_val);
- return _res;
-}
-
-#ifndef _i_isset
- STC_DEF _cx_result
- _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped) {
- _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key)));
- if (res.inserted)
- res.ref->first = key;
- else
- { i_keydrop((&key)); i_valdrop((&res.ref->second)); }
- res.ref->second = mapped;
- return res;
- }
- #if !defined _i_no_clone && !defined _i_no_emplace
- STC_DEF _cx_result
- _cx_memb(_emplace_or_assign)(_cx_self* self, i_keyraw rkey, i_valraw rmapped) {
- _cx_result res = _cx_memb(_insert_entry_)(self, rkey);
- if (res.inserted)
- res.ref->first = i_keyfrom(rkey);
- else
- { i_valdrop((&res.ref->second)); }
- res.ref->second = i_valfrom(rmapped);
- return res;
- }
- #endif // !_i_no_clone && !_i_no_emplace
-#endif // !_i_isset
-
-STC_DEF _cx_value*
-_cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out) {
- _cx_node *tn = self->root;
- out->_top = 0;
- while (tn->level) {
- int c; _cx_rawkey raw = i_keyto(_i_keyref(&tn->value));
- if ((c = i_cmp((&raw), (&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
-_cx_memb(_lower_bound)(const _cx_self* self, i_keyraw rkey) {
- _cx_iter it;
- _cx_memb(_find_it)(self, rkey, &it);
- if (!it.ref && it._top) {
- _cx_node *tn = it._st[--it._top];
- it._tn = tn->link[1];
- it.ref = &tn->value;
- }
- return it;
-}
-
-STC_DEF void
-_cx_memb(_next)(_cx_iter *it) {
- _cx_node *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 *
-_cx_memb(_skew_)(_cx_node *tn) {
- if (tn && tn->link[0]->level == tn->level && tn->level) {
- _cx_node *tmp = tn->link[0];
- tn->link[0] = tmp->link[1];
- tmp->link[1] = tn;
- tn = tmp;
- }
- return tn;
-}
-
-static _cx_node *
-_cx_memb(_split_)(_cx_node *tn) {
- if (tn->link[1]->link[1]->level == tn->level && tn->level) {
- _cx_node *tmp = tn->link[1];
- tn->link[1] = tmp->link[0];
- tmp->link[0] = tn;
- tn = tmp;
- ++tn->level;
- }
- return tn;
-}
-
-static _cx_node*
-_cx_memb(_insert_entry_i_)(_cx_node* tn, const _cx_rawkey* rkey, _cx_result* res) {
- _cx_node *up[64], *tx = tn;
- int c, top = 0, dir = 0;
- while (tx->level) {
- up[top++] = tx;
- _cx_rawkey r = i_keyto(_i_keyref(&tx->value));
- if (!(c = (i_cmp((&r), rkey))))
- { res->ref = &tx->value; return tn; }
- dir = (c < 0);
- tx = tx->link[dir];
- }
- tn = c_alloc(_cx_node);
- tn->link[0] = tn->link[1] = (_cx_node*)&_csmap_sentinel;
- tn->level = 1;
- res->ref = &tn->value, res->inserted = true;
- 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
-_cx_memb(_insert_entry_)(_cx_self* self, i_keyraw rkey) {
- _cx_result res = {NULL};
- self->root = _cx_memb(_insert_entry_i_)(self->root, &rkey, &res);
- self->size += res.inserted;
- return res;
-}
-
-static _cx_node*
-_cx_memb(_erase_r_)(_cx_node *tn, const _cx_rawkey* rkey, int *erased) {
- if (tn->level == 0)
- return tn;
- _cx_rawkey raw = i_keyto(_i_keyref(&tn->value));
- _cx_node *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_drop)(&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(_i_keyref(&tn->value));
- tn->link[0] = _cx_memb(_erase_r_)(tn->link[0], &raw, erased);
- } else { /* unlink node */
- 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 int
-_cx_memb(_erase)(_cx_self* self, i_keyraw rkey) {
- int erased = 0;
- self->root = _cx_memb(_erase_r_)(self->root, &rkey, &erased);
- self->size -= erased;
- return erased;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- _cx_rawkey raw = i_keyto(_i_keyref(it.ref)), nxt;
- _cx_memb(_next)(&it);
- if (it.ref)
- nxt = i_keyto(_i_keyref(it.ref));
- _cx_memb(_erase)(self, raw);
- if (it.ref)
- _cx_memb(_find_it)(self, nxt, &it);
- return it;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
- if (!it2.ref) {
- while (it1.ref)
- it1 = _cx_memb(_erase_at)(self, it1);
- return it1;
- }
- _cx_key k1 = *_i_keyref(it1.ref), k2 = *_i_keyref(it2.ref);
- _cx_rawkey r1 = i_keyto((&k1));
- for (;;) {
- if (memcmp(&k1, &k2, sizeof k1) == 0)
- return it1;
- _cx_memb(_next)(&it1);
- k1 = *_i_keyref(it1.ref);
- _cx_memb(_erase)(self, r1);
- r1 = i_keyto((&k1));
- _cx_memb(_find_it)(self, r1, &it1);
- }
-}
-
-#if !defined _i_no_clone
-static _cx_node*
-_cx_memb(_clone_r_)(_cx_node *tn) {
- if (! tn->level)
- return tn;
- _cx_node *cn = c_alloc(_cx_node);
- cn->level = tn->level;
- cn->value = _cx_memb(_value_clone)(tn->value);
- cn->link[0] = _cx_memb(_clone_r_)(tn->link[0]);
- cn->link[1] = _cx_memb(_clone_r_)(tn->link[1]);
- return cn;
-}
-
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self cx) {
- return c_make(_cx_self){_cx_memb(_clone_r_)(cx.root), cx.size};
-}
-
-#if !defined _i_no_emplace
-STC_DEF _cx_result
-_cx_memb(_emplace)(_cx_self* self, i_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) {
- _cx_result res = _cx_memb(_insert_entry_)(self, rkey);
- if (res.inserted) {
- *_i_keyref(res.ref) = i_keyfrom(rkey);
- _i_MAP_ONLY(res.ref->second = i_valfrom(rmapped);)
- }
- return res;
-}
-#endif // _i_no_emplace
-#endif // !_i_no_clone
-
-static void
-_cx_memb(_drop_r_)(_cx_node* tn) {
- if (tn->level != 0) {
- _cx_memb(_drop_r_)(tn->link[0]);
- _cx_memb(_drop_r_)(tn->link[1]);
- _cx_memb(_value_drop)(&tn->value);
- c_free(tn);
- }
-}
-
-STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
- _cx_memb(_drop_r_)(self->root);
-}
-
-#endif // i_implement
-#undef _i_isset
-#undef _i_ismap
-#undef _i_keyref
-#undef _i_MAP_ONLY
-#undef _i_SET_ONLY
-#define CSMAP_H_INCLUDED
-#include <stc/template.h>
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+
+// 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>
+
+int main(void) {
+ c_autovar (csmap_sx m = csmap_sx_init(), csmap_sx_drop(&m))
+ {
+ 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_sx_value *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_sx, m)
+ printf("map %s: %g\n", cstr_str(&i.ref->first), i.ref->second);
+ }
+}
+*/
+#include <stc/ccommon.h>
+
+#ifndef CSMAP_H_INCLUDED
+#define STC_CSMAP_V1 1
+#include <stc/forward.h>
+#include <stdlib.h>
+#include <string.h>
+#endif // CSMAP_H_INCLUDED
+
+#ifndef _i_prefix
+#define _i_prefix csmap_
+#endif
+#ifdef _i_isset
+ #define _i_MAP_ONLY c_false
+ #define _i_SET_ONLY c_true
+ #define _i_keyref(vp) (vp)
+#else
+ #define _i_ismap
+ #define _i_MAP_ONLY c_true
+ #define _i_SET_ONLY c_false
+ #define _i_keyref(vp) (&(vp)->first)
+#endif
+#include <stc/template.h>
+
+#if !c_option(c_is_fwd)
+_cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_size, _i_MAP_ONLY, _i_SET_ONLY);
+#endif
+
+_i_MAP_ONLY( struct _cx_value {
+ _cx_key first;
+ _cx_mapped second;
+}; )
+struct _cx_node {
+ struct _cx_node *link[2];
+ uint8_t level;
+ _cx_value value;
+};
+
+typedef i_keyraw _cx_rawkey;
+typedef i_valraw _cx_memb(_rawmapped);
+typedef _i_SET_ONLY( i_keyraw )
+ _i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } )
+ _cx_raw;
+
+#if !defined _i_no_clone
+STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
+#if !defined _i_no_emplace
+STC_API _cx_result _cx_memb(_emplace)(_cx_self* self, i_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped));
+#endif // !_i_no_emplace
+#endif // !_i_no_clone
+STC_API _cx_self _cx_memb(_init)(void);
+STC_API _cx_result _cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped));
+STC_API _cx_result _cx_memb(_push)(_cx_self* self, _cx_value _val);
+STC_API void _cx_memb(_drop)(_cx_self* self);
+STC_API _cx_value* _cx_memb(_find_it)(const _cx_self* self, i_keyraw rkey, _cx_iter* out);
+STC_API _cx_iter _cx_memb(_lower_bound)(const _cx_self* self, i_keyraw rkey);
+STC_API _cx_value* _cx_memb(_front)(const _cx_self* self);
+STC_API _cx_value* _cx_memb(_back)(const _cx_self* self);
+STC_API int _cx_memb(_erase)(_cx_self* self, i_keyraw rkey);
+STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it);
+STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2);
+STC_API void _cx_memb(_next)(_cx_iter* it);
+
+STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return cx.size == 0; }
+STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return cx.size; }
+STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); }
+STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, i_keyraw rkey)
+ { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); return it; }
+STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, i_keyraw rkey)
+ { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it) != NULL; }
+STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, i_keyraw rkey)
+ { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
+STC_INLINE _cx_value* _cx_memb(_get_mut)(_cx_self* self, i_keyraw rkey)
+ { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
+
+STC_INLINE void
+_cx_memb(_clear)(_cx_self* self)
+ { _cx_memb(_drop)(self); *self = _cx_memb(_init)(); }
+
+STC_INLINE _cx_raw
+_cx_memb(_value_toraw)(_cx_value* val) {
+ return _i_SET_ONLY( i_keyto(val) )
+ _i_MAP_ONLY( c_make(_cx_raw){i_keyto((&val->first)),
+ i_valto((&val->second))} );
+}
+
+STC_INLINE int
+_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
+ _cx_rawkey rx = i_keyto(_i_keyref(x)), ry = i_keyto(_i_keyref(y));
+ return i_cmp((&rx), (&ry));
+}
+
+STC_INLINE void
+_cx_memb(_value_drop)(_cx_value* val) {
+ i_keydrop(_i_keyref(val));
+ _i_MAP_ONLY( i_valdrop((&val->second)); )
+}
+
+#if !defined _i_no_clone
+STC_INLINE _cx_value
+_cx_memb(_value_clone)(_cx_value _val) {
+ *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val)));
+ _i_MAP_ONLY( _val.second = i_valclone(_val.second); )
+ return _val;
+}
+
+STC_INLINE void
+_cx_memb(_copy)(_cx_self *self, _cx_self other) {
+ if (self->root == other.root)
+ return;
+ _cx_memb(_drop)(self);
+ *self = _cx_memb(_clone)(other);
+}
+#endif // !_i_no_clone
+
+#ifndef _i_isset
+ #if !defined _i_no_clone && !defined _i_no_emplace
+ STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, i_keyraw rkey, i_valraw rmapped);
+ #endif
+ STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped);
+
+ STC_INLINE const _cx_mapped*
+ _cx_memb(_at)(const _cx_self* self, i_keyraw rkey)
+ { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
+ STC_INLINE _cx_mapped*
+ _cx_memb(_at_mut)(_cx_self* self, i_keyraw rkey)
+ { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
+#endif // !_i_isset
+
+STC_INLINE _cx_iter
+_cx_memb(_begin)(const _cx_self* self) {
+ _cx_iter it;
+ it.ref = NULL, it._top = 0, it._tn = self->root;
+ _cx_memb(_next)(&it);
+ return it;
+}
+
+STC_INLINE _cx_iter
+_cx_memb(_end)(const _cx_self* self) {
+ (void)self;
+ _cx_iter it; it.ref = NULL, it._top = 0, it._tn = NULL;
+ return it;
+}
+
+STC_INLINE _cx_iter
+_cx_memb(_advance)(_cx_iter it, size_t n) {
+ while (n-- && it.ref)
+ _cx_memb(_next)(&it);
+ return it;
+}
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if defined(i_implement)
+
+#ifndef CSMAP_H_INCLUDED
+static struct { void *link[2]; uint8_t level; }
+_csmap_sentinel = {{&_csmap_sentinel, &_csmap_sentinel}, 0};
+#endif
+
+static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, i_keyraw rkey);
+
+STC_DEF _cx_self
+_cx_memb(_init)(void) {
+ _cx_self cx = {(_cx_node *)&_csmap_sentinel, 0};
+ return cx;
+}
+
+STC_DEF _cx_value*
+_cx_memb(_front)(const _cx_self* self) {
+ _cx_node *tn = self->root;
+ while (tn->link[0]->level)
+ tn = tn->link[0];
+ return &tn->value;
+}
+
+STC_DEF _cx_value*
+_cx_memb(_back)(const _cx_self* self) {
+ _cx_node *tn = self->root;
+ while (tn->link[1]->level)
+ tn = tn->link[1];
+ return &tn->value;
+}
+
+STC_DEF _cx_result
+_cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped)) {
+ _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key)));
+ if (res.inserted)
+ { *_i_keyref(res.ref) = key; _i_MAP_ONLY( res.ref->second = mapped; )}
+ else
+ { i_keydrop((&key)); _i_MAP_ONLY( i_valdrop((&mapped)); )}
+ return res;
+}
+
+STC_DEF _cx_result
+_cx_memb(_push)(_cx_self* self, _cx_value _val) {
+ _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
+ if (_res.inserted)
+ *_res.ref = _val;
+ else
+ _cx_memb(_value_drop)(&_val);
+ return _res;
+}
+
+#ifndef _i_isset
+ STC_DEF _cx_result
+ _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped) {
+ _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key)));
+ if (res.inserted)
+ res.ref->first = key;
+ else
+ { i_keydrop((&key)); i_valdrop((&res.ref->second)); }
+ res.ref->second = mapped;
+ return res;
+ }
+ #if !defined _i_no_clone && !defined _i_no_emplace
+ STC_DEF _cx_result
+ _cx_memb(_emplace_or_assign)(_cx_self* self, i_keyraw rkey, i_valraw rmapped) {
+ _cx_result res = _cx_memb(_insert_entry_)(self, rkey);
+ if (res.inserted)
+ res.ref->first = i_keyfrom(rkey);
+ else
+ { i_valdrop((&res.ref->second)); }
+ res.ref->second = i_valfrom(rmapped);
+ return res;
+ }
+ #endif // !_i_no_clone && !_i_no_emplace
+#endif // !_i_isset
+
+STC_DEF _cx_value*
+_cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out) {
+ _cx_node *tn = self->root;
+ out->_top = 0;
+ while (tn->level) {
+ int c; _cx_rawkey raw = i_keyto(_i_keyref(&tn->value));
+ if ((c = i_cmp((&raw), (&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
+_cx_memb(_lower_bound)(const _cx_self* self, i_keyraw rkey) {
+ _cx_iter it;
+ _cx_memb(_find_it)(self, rkey, &it);
+ if (!it.ref && it._top) {
+ _cx_node *tn = it._st[--it._top];
+ it._tn = tn->link[1];
+ it.ref = &tn->value;
+ }
+ return it;
+}
+
+STC_DEF void
+_cx_memb(_next)(_cx_iter *it) {
+ _cx_node *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 *
+_cx_memb(_skew_)(_cx_node *tn) {
+ if (tn && tn->link[0]->level == tn->level && tn->level) {
+ _cx_node *tmp = tn->link[0];
+ tn->link[0] = tmp->link[1];
+ tmp->link[1] = tn;
+ tn = tmp;
+ }
+ return tn;
+}
+
+static _cx_node *
+_cx_memb(_split_)(_cx_node *tn) {
+ if (tn->link[1]->link[1]->level == tn->level && tn->level) {
+ _cx_node *tmp = tn->link[1];
+ tn->link[1] = tmp->link[0];
+ tmp->link[0] = tn;
+ tn = tmp;
+ ++tn->level;
+ }
+ return tn;
+}
+
+static _cx_node*
+_cx_memb(_insert_entry_i_)(_cx_node* tn, const _cx_rawkey* rkey, _cx_result* res) {
+ _cx_node *up[64], *tx = tn;
+ int c, top = 0, dir = 0;
+ while (tx->level) {
+ up[top++] = tx;
+ _cx_rawkey r = i_keyto(_i_keyref(&tx->value));
+ if (!(c = (i_cmp((&r), rkey))))
+ { res->ref = &tx->value; return tn; }
+ dir = (c < 0);
+ tx = tx->link[dir];
+ }
+ tn = c_alloc(_cx_node);
+ tn->link[0] = tn->link[1] = (_cx_node*)&_csmap_sentinel;
+ tn->level = 1;
+ res->ref = &tn->value, res->inserted = true;
+ 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
+_cx_memb(_insert_entry_)(_cx_self* self, i_keyraw rkey) {
+ _cx_result res = {NULL};
+ self->root = _cx_memb(_insert_entry_i_)(self->root, &rkey, &res);
+ self->size += res.inserted;
+ return res;
+}
+
+static _cx_node*
+_cx_memb(_erase_r_)(_cx_node *tn, const _cx_rawkey* rkey, int *erased) {
+ if (tn->level == 0)
+ return tn;
+ _cx_rawkey raw = i_keyto(_i_keyref(&tn->value));
+ _cx_node *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_drop)(&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(_i_keyref(&tn->value));
+ tn->link[0] = _cx_memb(_erase_r_)(tn->link[0], &raw, erased);
+ } else { /* unlink node */
+ 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 int
+_cx_memb(_erase)(_cx_self* self, i_keyraw rkey) {
+ int erased = 0;
+ self->root = _cx_memb(_erase_r_)(self->root, &rkey, &erased);
+ self->size -= erased;
+ return erased;
+}
+
+STC_DEF _cx_iter
+_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
+ _cx_rawkey raw = i_keyto(_i_keyref(it.ref)), nxt;
+ _cx_memb(_next)(&it);
+ if (it.ref)
+ nxt = i_keyto(_i_keyref(it.ref));
+ _cx_memb(_erase)(self, raw);
+ if (it.ref)
+ _cx_memb(_find_it)(self, nxt, &it);
+ return it;
+}
+
+STC_DEF _cx_iter
+_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
+ if (!it2.ref) {
+ while (it1.ref)
+ it1 = _cx_memb(_erase_at)(self, it1);
+ return it1;
+ }
+ _cx_key k1 = *_i_keyref(it1.ref), k2 = *_i_keyref(it2.ref);
+ _cx_rawkey r1 = i_keyto((&k1));
+ for (;;) {
+ if (memcmp(&k1, &k2, sizeof k1) == 0)
+ return it1;
+ _cx_memb(_next)(&it1);
+ k1 = *_i_keyref(it1.ref);
+ _cx_memb(_erase)(self, r1);
+ r1 = i_keyto((&k1));
+ _cx_memb(_find_it)(self, r1, &it1);
+ }
+}
+
+#if !defined _i_no_clone
+static _cx_node*
+_cx_memb(_clone_r_)(_cx_node *tn) {
+ if (! tn->level)
+ return tn;
+ _cx_node *cn = c_alloc(_cx_node);
+ cn->level = tn->level;
+ cn->value = _cx_memb(_value_clone)(tn->value);
+ cn->link[0] = _cx_memb(_clone_r_)(tn->link[0]);
+ cn->link[1] = _cx_memb(_clone_r_)(tn->link[1]);
+ return cn;
+}
+
+STC_DEF _cx_self
+_cx_memb(_clone)(_cx_self cx) {
+ return c_make(_cx_self){_cx_memb(_clone_r_)(cx.root), cx.size};
+}
+
+#if !defined _i_no_emplace
+STC_DEF _cx_result
+_cx_memb(_emplace)(_cx_self* self, i_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) {
+ _cx_result res = _cx_memb(_insert_entry_)(self, rkey);
+ if (res.inserted) {
+ *_i_keyref(res.ref) = i_keyfrom(rkey);
+ _i_MAP_ONLY(res.ref->second = i_valfrom(rmapped);)
+ }
+ return res;
+}
+#endif // _i_no_emplace
+#endif // !_i_no_clone
+
+static void
+_cx_memb(_drop_r_)(_cx_node* tn) {
+ if (tn->level != 0) {
+ _cx_memb(_drop_r_)(tn->link[0]);
+ _cx_memb(_drop_r_)(tn->link[1]);
+ _cx_memb(_value_drop)(&tn->value);
+ c_free(tn);
+ }
+}
+
+STC_DEF void
+_cx_memb(_drop)(_cx_self* self) {
+ _cx_memb(_drop_r_)(self->root);
+}
+
+#endif // i_implement
+#undef _i_isset
+#undef _i_ismap
+#undef _i_keyref
+#undef _i_MAP_ONLY
+#undef _i_SET_ONLY
+#define CSMAP_H_INCLUDED
+#include <stc/template.h>
diff --git a/include/stc/alt/cstr.h b/include/stc/alt/cstr.h
index 0012d364..32dec09d 100644
--- a/include/stc/alt/cstr.h
+++ b/include/stc/alt/cstr.h
@@ -1,389 +1,389 @@
-/* MIT License
- *
- * Copyright (c) 2022 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 CSTR_H_INCLUDED
-#define CSTR_H_INCLUDED
-#define STC_CSTR_V1 1
-
-#include <stc/ccommon.h>
-#include <stc/forward.h>
-#include <stdlib.h> /* malloc */
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h> /* vsnprintf */
-#include <ctype.h>
-
-#define cstr_npos (SIZE_MAX >> 1)
-typedef struct { size_t size, cap; char chr[1]; } cstr_priv;
-#define _cstr_p(self) c_unchecked_container_of((self)->str, cstr_priv, chr)
-#ifdef i_static
- static cstr_priv _cstr_nullrep = {0, 0, {0}};
- static const cstr cstr_null = {_cstr_nullrep.chr};
-#else
- extern const cstr cstr_null;
-#endif
-/* optimal memory: based on malloc_usable_size() sequence: 24, 40, 56, ... */
-#define _cstr_opt_mem(cap) ((((offsetof(cstr_priv, chr) + (cap) + 8)>>4)<<4) + 8)
-/* optimal string capacity: 7, 23, 39, ... */
-#define _cstr_opt_cap(cap) (_cstr_opt_mem(cap) - offsetof(cstr_priv, chr) - 1)
-
-STC_API cstr cstr_from_n(const char* str, size_t n);
-STC_API cstr cstr_from_fmt(const char* fmt, ...);
-STC_API cstr cstr_from_replace_all(const char* str, size_t str_len,
- const char* find, size_t find_len,
- const char* repl, size_t repl_len);
-STC_API char* cstr_reserve(cstr* self, size_t cap);
-STC_API void cstr_resize(cstr* self, size_t len, char fill);
-STC_API cstr* cstr_assign_n(cstr* self, const char* str, size_t n);
-STC_API int cstr_printf(cstr* self, const char* fmt, ...);
-STC_API cstr* cstr_append_n(cstr* self, const char* str, size_t n);
-STC_API void cstr_replace_n(cstr* self, size_t pos, size_t len, const char* str, size_t n);
-STC_API void cstr_replace_all(cstr* self, const char* find, const char* replace);
-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_from(cstr s, size_t pos, const char* needle);
-STC_API bool cstr_getdelim(cstr *self, int delim, FILE *stream);
-STC_API void cstr_replace_all(cstr* self, const char* find, const char* repl);
-
-STC_INLINE cstr cstr_init() { return cstr_null; }
-STC_INLINE const char* cstr_str(const cstr* self) { return self->str; }
-#define cstr_toraw(self) (self)->str
-STC_INLINE csview cstr_sv(const cstr* self)
- { return c_make(csview){self->str, _cstr_p(self)->size}; }
-#define cstr_new(literal) \
- cstr_from_n(literal, c_strlen_lit(literal))
-STC_INLINE cstr cstr_from(const char* str)
- { return cstr_from_n(str, strlen(str)); }
-STC_INLINE char* cstr_data(cstr* self) { return self->str; }
-STC_INLINE size_t cstr_size(cstr s) { return _cstr_p(&s)->size; }
-STC_INLINE size_t cstr_length(cstr s) { return _cstr_p(&s)->size; }
-STC_INLINE size_t cstr_capacity(cstr s) { return _cstr_p(&s)->cap; }
-STC_INLINE bool cstr_empty(cstr s) { return _cstr_p(&s)->size == 0; }
-STC_INLINE void cstr_drop(cstr* self)
- { if (_cstr_p(self)->cap) c_free(_cstr_p(self)); }
-STC_INLINE cstr cstr_clone(cstr s)
- { return cstr_from_n(s.str, _cstr_p(&s)->size); }
-STC_INLINE void cstr_clear(cstr* self)
- { self->str[_cstr_p(self)->size = 0] = '\0'; }
-STC_INLINE cstr* cstr_assign(cstr* self, const char* str)
- { return cstr_assign_n(self, str, strlen(str)); }
-STC_INLINE cstr* cstr_copy(cstr* self, cstr s)
- { return cstr_assign_n(self, s.str, _cstr_p(&s)->size); }
-STC_INLINE cstr* cstr_append(cstr* self, const char* str)
- { return cstr_append_n(self, str, strlen(str)); }
-STC_INLINE cstr* cstr_append_s(cstr* self, cstr s)
- { return cstr_append_n(self, s.str, _cstr_p(&s)->size); }
-STC_INLINE void cstr_push_back(cstr* self, char value)
- { cstr_append_n(self, &value, 1); }
-STC_INLINE void cstr_pop_back(cstr* self)
- { self->str[ --_cstr_p(self)->size ] = '\0'; }
-STC_INLINE void cstr_insert_n(cstr* self, const size_t pos, const char* str, const size_t n)
- { cstr_replace_n(self, pos, 0, str, n); }
-STC_INLINE void cstr_insert(cstr* self, const size_t pos, const char* str)
- { cstr_replace_n(self, pos, 0, str, strlen(str)); }
-STC_INLINE void cstr_insert_s(cstr* self, const size_t pos, cstr s)
- { cstr_replace_n(self, pos, 0, s.str, _cstr_p(&s)->size); }
-STC_INLINE void cstr_replace(cstr* self, const size_t pos, const size_t len, const char* str)
- { cstr_replace_n(self, pos, len, str, strlen(str)); }
-STC_INLINE void cstr_replace_s(cstr* self, const size_t pos, const size_t len, cstr s)
- { cstr_replace_n(self, pos, len, s.str, _cstr_p(&s)->size); }
-STC_INLINE void cstr_erase(cstr* self, const size_t pos)
- { cstr_erase_n(self, pos, 1); }
-STC_INLINE char* cstr_front(cstr* self) { return self->str; }
-STC_INLINE char* cstr_back(cstr* self)
- { return self->str + _cstr_p(self)->size - 1; }
-STC_INLINE bool cstr_equals(cstr s, const char* str)
- { return strcmp(s.str, str) == 0; }
-STC_INLINE bool cstr_equals_s(cstr s1, cstr s2)
- { return strcmp(s1.str, s2.str) == 0; }
-STC_INLINE bool cstr_contains(cstr s, const char* needle)
- { return strstr(s.str, needle) != NULL; }
-STC_INLINE bool cstr_getline(cstr *self, FILE *stream)
- { return cstr_getdelim(self, '\n', stream); }
-
-STC_INLINE cstr_buf cstr_buffer(cstr* s) {
- cstr_priv* p = _cstr_p(s);
- return c_make(cstr_buf){s->str, p->size, p->cap};
-}
-
-STC_INLINE cstr cstr_with_capacity(const size_t cap) {
- cstr s = cstr_null;
- cstr_reserve(&s, cap);
- return s;
-}
-
-STC_INLINE cstr cstr_with_size(const size_t len, const char fill) {
- cstr s = cstr_null;
- cstr_resize(&s, len, fill);
- return s;
-}
-
-STC_INLINE char* cstr_expand_uninit(cstr *self, size_t n) {
- size_t len = cstr_size(*self); char* d;
- if (!(d = cstr_reserve(self, len + n))) return NULL;
- _cstr_p(self)->size += n;
- return d + len;
-}
-
-STC_INLINE cstr* cstr_take(cstr* self, cstr s) {
- if (self->str != s.str && _cstr_p(self)->cap)
- c_free(_cstr_p(self));
- self->str = s.str;
- return self;
-}
-
-STC_INLINE cstr cstr_move(cstr* self) {
- cstr tmp = *self;
- *self = cstr_null;
- return tmp;
-}
-
-STC_INLINE bool cstr_starts_with(cstr s, const char* sub) {
- while (*sub && *s.str == *sub) ++s.str, ++sub;
- return *sub == 0;
-}
-
-STC_INLINE bool cstr_ends_with(cstr s, const char* sub) {
- const size_t n = strlen(sub), sz = _cstr_p(&s)->size;
- return n <= sz && !memcmp(s.str + sz - n, sub, n);
-}
-
-STC_INLINE int c_strncasecmp(const char* s1, const char* s2, size_t nmax) {
- int ret = 0;
- while (nmax-- && (ret = tolower(*s1++) - tolower(*s2)) == 0 && *s2++)
- ;
- return ret;
-}
-
-/* container adaptor functions: */
-#define cstr_cmp(xp, yp) strcmp((xp)->str, (yp)->str)
-
-STC_INLINE bool cstr_eq(const cstr* x, const cstr* y) {
- size_t xs = _cstr_p(x)->size, ys = _cstr_p(y)->size;
- return xs == ys && !memcmp(x->str, y->str, xs);
-}
-STC_INLINE uint64_t cstr_hash(const cstr *self) {
- return c_fasthash(self->str, _cstr_p(self)->size);
-}
-
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-#ifndef i_static
-static cstr_priv _cstr_nullrep = {0, 0, {0}};
-const cstr cstr_null = {_cstr_nullrep.chr};
-#endif
-
-STC_DEF char*
-cstr_reserve(cstr* self, const size_t cap) {
- cstr_priv *p = _cstr_p(self);
- const size_t oldcap = p->cap;
- if (cap > oldcap) {
- p = (cstr_priv*) c_realloc(((oldcap != 0) & (p != &_cstr_nullrep)) ? p : NULL, _cstr_opt_mem(cap));
- if (!p) return NULL;
- self->str = p->chr;
- if (oldcap == 0) self->str[p->size = 0] = '\0';
- p->cap = _cstr_opt_cap(cap);
- }
- return self->str;
-}
-
-STC_DEF void
-cstr_resize(cstr* self, const size_t len, const char fill) {
- const size_t n = _cstr_p(self)->size;
- cstr_reserve(self, len);
- if (len > n) memset(self->str + n, fill, len - n);
- if (len | n) self->str[_cstr_p(self)->size = len] = '\0';
-}
-
-STC_DEF cstr
-cstr_from_n(const char* str, const size_t n) {
- if (n == 0) return cstr_null;
- cstr_priv* prv = (cstr_priv*) c_malloc(_cstr_opt_mem(n));
- cstr s = {(char *) memcpy(prv->chr, str, n)};
- s.str[prv->size = n] = '\0';
- prv->cap = _cstr_opt_cap(n);
- return s;
-}
-
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wdeprecated-declarations"
-#elif defined(_MSC_VER)
-# pragma warning(push)
-# pragma warning(disable: 4996)
-#endif
-
-STC_DEF int
-cstr_vfmt(cstr* self, const char* fmt, va_list args) {
- va_list args2;
- va_copy(args2, args);
- int len = vsnprintf(NULL, (size_t)0, fmt, args);
- cstr_reserve(self, len);
- vsprintf(self->str, fmt, args2);
- va_end(args2);
- return _cstr_p(self)->size = len;
-}
-
-#if defined(__clang__)
-# pragma clang diagnostic pop
-#elif defined(_MSC_VER)
-# pragma warning(pop)
-#endif
-
-STC_DEF cstr
-cstr_from_fmt(const char* fmt, ...) {
- cstr ret = cstr_null;
- va_list args; va_start(args, fmt);
- cstr_vfmt(&ret, fmt, args);
- va_end(args);
- return ret;
-}
-
-STC_DEF int
-cstr_printf(cstr* self, const char* fmt, ...) {
- cstr ret = cstr_null;
- va_list args;
- va_start(args, fmt);
- int n = cstr_vfmt(&ret, fmt, args);
- va_end(args);
- cstr_drop(self);
- *self = ret;
- return n;
-}
-
-STC_DEF cstr*
-cstr_assign_n(cstr* self, const char* str, const size_t n) {
- if (n || _cstr_p(self)->cap) {
- cstr_reserve(self, n);
- memmove(self->str, str, n);
- self->str[_cstr_p(self)->size = n] = '\0';
- }
- return self;
-}
-
-STC_DEF cstr*
-cstr_append_n(cstr* self, const char* str, const size_t n) {
- if (n == 0) return self;
- const size_t oldlen = _cstr_p(self)->size, newlen = oldlen + n;
- if (newlen > _cstr_p(self)->cap) {
- const size_t off = (size_t) (str - self->str); /* handle self append */
- cstr_reserve(self, (oldlen*3 >> 1) + n);
- if (off <= oldlen) str = self->str + off;
- }
- memcpy(&self->str[oldlen], str, n);
- self->str[_cstr_p(self)->size = newlen] = '\0';
- return self;
-}
-
-STC_INLINE void _cstr_internal_move(cstr* self, const size_t pos1, const size_t pos2) {
- if (pos1 == pos2)
- return;
- const size_t len = _cstr_p(self)->size, newlen = len + pos2 - pos1;
- if (newlen > _cstr_p(self)->cap)
- cstr_reserve(self, (len*3 >> 1) + pos2 - pos1);
- memmove(&self->str[pos2], &self->str[pos1], len - pos1);
- self->str[_cstr_p(self)->size = newlen] = '\0';
-}
-
-STC_DEF void
-cstr_replace_n(cstr* self, const size_t pos, size_t len, const char* str, const size_t n) {
- const size_t sz = cstr_size(*self);
- if (len > sz - pos) len = sz - pos;
- c_autobuf (xstr, char, n) {
- memcpy(xstr, str, n);
- _cstr_internal_move(self, pos + len, pos + n);
- memcpy(&self->str[pos], xstr, n);
- }
-}
-
-STC_DEF cstr
-cstr_from_replace_all(const char* str, const size_t str_len,
- const char* find, const size_t find_len,
- const char* repl, const size_t repl_len) {
- cstr out = cstr_null;
- size_t from = 0; char* res;
- if (find_len)
- while ((res = c_strnstrn(str + from, find, str_len - from, find_len))) {
- const size_t pos = res - str;
- cstr_append_n(&out, str + from, pos - from);
- cstr_append_n(&out, repl, repl_len);
- from = pos + find_len;
- }
- cstr_append_n(&out, str + from, str_len - from);
- return out;
-}
-
-STC_DEF void
-cstr_replace_all(cstr* self, const char* find, const char* repl) {
- cstr_take(self, cstr_from_replace_all(self->str, _cstr_p(self)->size,
- find, strlen(find), repl, strlen(repl)));
-}
-
-STC_DEF void
-cstr_erase_n(cstr* self, const size_t pos, size_t n) {
- const size_t len = _cstr_p(self)->size;
- if (n > len - pos) n = len - pos;
- if (len) {
- memmove(&self->str[pos], &self->str[pos + n], len - (pos + n));
- self->str[_cstr_p(self)->size -= n] = '\0';
- }
-}
-
-STC_DEF bool
-cstr_getdelim(cstr *self, const int delim, FILE *fp) {
- size_t pos = 0, cap = _cstr_p(self)->cap;
- char* d = self->str;
- int c = fgetc(fp);
- if (c == EOF)
- return false;
- for (;;) {
- if (c == delim || c == EOF) {
- if (cap) d[_cstr_p(self)->size = pos] = '\0';
- return true;
- }
- if (pos == cap) {
- d = cstr_reserve(self, (cap*3 >> 1) + 16);
- cap = cstr_capacity(*self);
- }
- d[pos++] = (char) c;
- c = fgetc(fp);
- }
-}
-
-STC_DEF size_t
-cstr_find(cstr s, const char* needle) {
- char* res = strstr(s.str, needle);
- return res ? res - s.str : cstr_npos;
-}
-
-STC_DEF size_t
-cstr_find_from(cstr s, const size_t pos, const char* needle) {
- if (pos > _cstr_p(&s)->size) return cstr_npos;
- char* res = strstr(s.str + pos, needle);
- return res ? res - s.str : cstr_npos;
-}
-
-#endif
-#endif // CSTR_H_INCLUDED
-#undef i_opt
+/* MIT License
+ *
+ * Copyright (c) 2022 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 CSTR_H_INCLUDED
+#define CSTR_H_INCLUDED
+#define STC_CSTR_V1 1
+
+#include <stc/ccommon.h>
+#include <stc/forward.h>
+#include <stdlib.h> /* malloc */
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h> /* vsnprintf */
+#include <ctype.h>
+
+#define cstr_npos (SIZE_MAX >> 1)
+typedef struct { size_t size, cap; char chr[1]; } cstr_priv;
+#define _cstr_p(self) c_unchecked_container_of((self)->str, cstr_priv, chr)
+#ifdef i_static
+ static cstr_priv _cstr_nullrep = {0, 0, {0}};
+ static const cstr cstr_null = {_cstr_nullrep.chr};
+#else
+ extern const cstr cstr_null;
+#endif
+/* optimal memory: based on malloc_usable_size() sequence: 24, 40, 56, ... */
+#define _cstr_opt_mem(cap) ((((offsetof(cstr_priv, chr) + (cap) + 8)>>4)<<4) + 8)
+/* optimal string capacity: 7, 23, 39, ... */
+#define _cstr_opt_cap(cap) (_cstr_opt_mem(cap) - offsetof(cstr_priv, chr) - 1)
+
+STC_API cstr cstr_from_n(const char* str, size_t n);
+STC_API cstr cstr_from_fmt(const char* fmt, ...);
+STC_API cstr cstr_from_replace_all(const char* str, size_t str_len,
+ const char* find, size_t find_len,
+ const char* repl, size_t repl_len);
+STC_API char* cstr_reserve(cstr* self, size_t cap);
+STC_API void cstr_resize(cstr* self, size_t len, char fill);
+STC_API cstr* cstr_assign_n(cstr* self, const char* str, size_t n);
+STC_API int cstr_printf(cstr* self, const char* fmt, ...);
+STC_API cstr* cstr_append_n(cstr* self, const char* str, size_t n);
+STC_API void cstr_replace_n(cstr* self, size_t pos, size_t len, const char* str, size_t n);
+STC_API void cstr_replace_all(cstr* self, const char* find, const char* replace);
+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_from(cstr s, size_t pos, const char* needle);
+STC_API bool cstr_getdelim(cstr *self, int delim, FILE *stream);
+STC_API void cstr_replace_all(cstr* self, const char* find, const char* repl);
+
+STC_INLINE cstr cstr_init() { return cstr_null; }
+STC_INLINE const char* cstr_str(const cstr* self) { return self->str; }
+#define cstr_toraw(self) (self)->str
+STC_INLINE csview cstr_sv(const cstr* self)
+ { return c_make(csview){self->str, _cstr_p(self)->size}; }
+#define cstr_new(literal) \
+ cstr_from_n(literal, c_strlen_lit(literal))
+STC_INLINE cstr cstr_from(const char* str)
+ { return cstr_from_n(str, strlen(str)); }
+STC_INLINE char* cstr_data(cstr* self) { return self->str; }
+STC_INLINE size_t cstr_size(cstr s) { return _cstr_p(&s)->size; }
+STC_INLINE size_t cstr_length(cstr s) { return _cstr_p(&s)->size; }
+STC_INLINE size_t cstr_capacity(cstr s) { return _cstr_p(&s)->cap; }
+STC_INLINE bool cstr_empty(cstr s) { return _cstr_p(&s)->size == 0; }
+STC_INLINE void cstr_drop(cstr* self)
+ { if (_cstr_p(self)->cap) c_free(_cstr_p(self)); }
+STC_INLINE cstr cstr_clone(cstr s)
+ { return cstr_from_n(s.str, _cstr_p(&s)->size); }
+STC_INLINE void cstr_clear(cstr* self)
+ { self->str[_cstr_p(self)->size = 0] = '\0'; }
+STC_INLINE cstr* cstr_assign(cstr* self, const char* str)
+ { return cstr_assign_n(self, str, strlen(str)); }
+STC_INLINE cstr* cstr_copy(cstr* self, cstr s)
+ { return cstr_assign_n(self, s.str, _cstr_p(&s)->size); }
+STC_INLINE cstr* cstr_append(cstr* self, const char* str)
+ { return cstr_append_n(self, str, strlen(str)); }
+STC_INLINE cstr* cstr_append_s(cstr* self, cstr s)
+ { return cstr_append_n(self, s.str, _cstr_p(&s)->size); }
+STC_INLINE void cstr_push_back(cstr* self, char value)
+ { cstr_append_n(self, &value, 1); }
+STC_INLINE void cstr_pop_back(cstr* self)
+ { self->str[ --_cstr_p(self)->size ] = '\0'; }
+STC_INLINE void cstr_insert_n(cstr* self, const size_t pos, const char* str, const size_t n)
+ { cstr_replace_n(self, pos, 0, str, n); }
+STC_INLINE void cstr_insert(cstr* self, const size_t pos, const char* str)
+ { cstr_replace_n(self, pos, 0, str, strlen(str)); }
+STC_INLINE void cstr_insert_s(cstr* self, const size_t pos, cstr s)
+ { cstr_replace_n(self, pos, 0, s.str, _cstr_p(&s)->size); }
+STC_INLINE void cstr_replace(cstr* self, const size_t pos, const size_t len, const char* str)
+ { cstr_replace_n(self, pos, len, str, strlen(str)); }
+STC_INLINE void cstr_replace_s(cstr* self, const size_t pos, const size_t len, cstr s)
+ { cstr_replace_n(self, pos, len, s.str, _cstr_p(&s)->size); }
+STC_INLINE void cstr_erase(cstr* self, const size_t pos)
+ { cstr_erase_n(self, pos, 1); }
+STC_INLINE char* cstr_front(cstr* self) { return self->str; }
+STC_INLINE char* cstr_back(cstr* self)
+ { return self->str + _cstr_p(self)->size - 1; }
+STC_INLINE bool cstr_equals(cstr s, const char* str)
+ { return strcmp(s.str, str) == 0; }
+STC_INLINE bool cstr_equals_s(cstr s1, cstr s2)
+ { return strcmp(s1.str, s2.str) == 0; }
+STC_INLINE bool cstr_contains(cstr s, const char* needle)
+ { return strstr(s.str, needle) != NULL; }
+STC_INLINE bool cstr_getline(cstr *self, FILE *stream)
+ { return cstr_getdelim(self, '\n', stream); }
+
+STC_INLINE cstr_buf cstr_buffer(cstr* s) {
+ cstr_priv* p = _cstr_p(s);
+ return c_make(cstr_buf){s->str, p->size, p->cap};
+}
+
+STC_INLINE cstr cstr_with_capacity(const size_t cap) {
+ cstr s = cstr_null;
+ cstr_reserve(&s, cap);
+ return s;
+}
+
+STC_INLINE cstr cstr_with_size(const size_t len, const char fill) {
+ cstr s = cstr_null;
+ cstr_resize(&s, len, fill);
+ return s;
+}
+
+STC_INLINE char* cstr_expand_uninit(cstr *self, size_t n) {
+ size_t len = cstr_size(*self); char* d;
+ if (!(d = cstr_reserve(self, len + n))) return NULL;
+ _cstr_p(self)->size += n;
+ return d + len;
+}
+
+STC_INLINE cstr* cstr_take(cstr* self, cstr s) {
+ if (self->str != s.str && _cstr_p(self)->cap)
+ c_free(_cstr_p(self));
+ self->str = s.str;
+ return self;
+}
+
+STC_INLINE cstr cstr_move(cstr* self) {
+ cstr tmp = *self;
+ *self = cstr_null;
+ return tmp;
+}
+
+STC_INLINE bool cstr_starts_with(cstr s, const char* sub) {
+ while (*sub && *s.str == *sub) ++s.str, ++sub;
+ return *sub == 0;
+}
+
+STC_INLINE bool cstr_ends_with(cstr s, const char* sub) {
+ const size_t n = strlen(sub), sz = _cstr_p(&s)->size;
+ return n <= sz && !memcmp(s.str + sz - n, sub, n);
+}
+
+STC_INLINE int c_strncasecmp(const char* s1, const char* s2, size_t nmax) {
+ int ret = 0;
+ while (nmax-- && (ret = tolower(*s1++) - tolower(*s2)) == 0 && *s2++)
+ ;
+ return ret;
+}
+
+/* container adaptor functions: */
+#define cstr_cmp(xp, yp) strcmp((xp)->str, (yp)->str)
+
+STC_INLINE bool cstr_eq(const cstr* x, const cstr* y) {
+ size_t xs = _cstr_p(x)->size, ys = _cstr_p(y)->size;
+ return xs == ys && !memcmp(x->str, y->str, xs);
+}
+STC_INLINE uint64_t cstr_hash(const cstr *self) {
+ return c_fasthash(self->str, _cstr_p(self)->size);
+}
+
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if defined(i_implement)
+
+#ifndef i_static
+static cstr_priv _cstr_nullrep = {0, 0, {0}};
+const cstr cstr_null = {_cstr_nullrep.chr};
+#endif
+
+STC_DEF char*
+cstr_reserve(cstr* self, const size_t cap) {
+ cstr_priv *p = _cstr_p(self);
+ const size_t oldcap = p->cap;
+ if (cap > oldcap) {
+ p = (cstr_priv*) c_realloc(((oldcap != 0) & (p != &_cstr_nullrep)) ? p : NULL, _cstr_opt_mem(cap));
+ if (!p) return NULL;
+ self->str = p->chr;
+ if (oldcap == 0) self->str[p->size = 0] = '\0';
+ p->cap = _cstr_opt_cap(cap);
+ }
+ return self->str;
+}
+
+STC_DEF void
+cstr_resize(cstr* self, const size_t len, const char fill) {
+ const size_t n = _cstr_p(self)->size;
+ cstr_reserve(self, len);
+ if (len > n) memset(self->str + n, fill, len - n);
+ if (len | n) self->str[_cstr_p(self)->size = len] = '\0';
+}
+
+STC_DEF cstr
+cstr_from_n(const char* str, const size_t n) {
+ if (n == 0) return cstr_null;
+ cstr_priv* prv = (cstr_priv*) c_malloc(_cstr_opt_mem(n));
+ cstr s = {(char *) memcpy(prv->chr, str, n)};
+ s.str[prv->size = n] = '\0';
+ prv->cap = _cstr_opt_cap(n);
+ return s;
+}
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable: 4996)
+#endif
+
+STC_DEF int
+cstr_vfmt(cstr* self, const char* fmt, va_list args) {
+ va_list args2;
+ va_copy(args2, args);
+ int len = vsnprintf(NULL, (size_t)0, fmt, args);
+ cstr_reserve(self, len);
+ vsprintf(self->str, fmt, args2);
+ va_end(args2);
+ return _cstr_p(self)->size = len;
+}
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#elif defined(_MSC_VER)
+# pragma warning(pop)
+#endif
+
+STC_DEF cstr
+cstr_from_fmt(const char* fmt, ...) {
+ cstr ret = cstr_null;
+ va_list args; va_start(args, fmt);
+ cstr_vfmt(&ret, fmt, args);
+ va_end(args);
+ return ret;
+}
+
+STC_DEF int
+cstr_printf(cstr* self, const char* fmt, ...) {
+ cstr ret = cstr_null;
+ va_list args;
+ va_start(args, fmt);
+ int n = cstr_vfmt(&ret, fmt, args);
+ va_end(args);
+ cstr_drop(self);
+ *self = ret;
+ return n;
+}
+
+STC_DEF cstr*
+cstr_assign_n(cstr* self, const char* str, const size_t n) {
+ if (n || _cstr_p(self)->cap) {
+ cstr_reserve(self, n);
+ memmove(self->str, str, n);
+ self->str[_cstr_p(self)->size = n] = '\0';
+ }
+ return self;
+}
+
+STC_DEF cstr*
+cstr_append_n(cstr* self, const char* str, const size_t n) {
+ if (n == 0) return self;
+ const size_t oldlen = _cstr_p(self)->size, newlen = oldlen + n;
+ if (newlen > _cstr_p(self)->cap) {
+ const size_t off = (size_t) (str - self->str); /* handle self append */
+ cstr_reserve(self, (oldlen*3 >> 1) + n);
+ if (off <= oldlen) str = self->str + off;
+ }
+ memcpy(&self->str[oldlen], str, n);
+ self->str[_cstr_p(self)->size = newlen] = '\0';
+ return self;
+}
+
+STC_INLINE void _cstr_internal_move(cstr* self, const size_t pos1, const size_t pos2) {
+ if (pos1 == pos2)
+ return;
+ const size_t len = _cstr_p(self)->size, newlen = len + pos2 - pos1;
+ if (newlen > _cstr_p(self)->cap)
+ cstr_reserve(self, (len*3 >> 1) + pos2 - pos1);
+ memmove(&self->str[pos2], &self->str[pos1], len - pos1);
+ self->str[_cstr_p(self)->size = newlen] = '\0';
+}
+
+STC_DEF void
+cstr_replace_n(cstr* self, const size_t pos, size_t len, const char* str, const size_t n) {
+ const size_t sz = cstr_size(*self);
+ if (len > sz - pos) len = sz - pos;
+ c_autobuf (xstr, char, n) {
+ memcpy(xstr, str, n);
+ _cstr_internal_move(self, pos + len, pos + n);
+ memcpy(&self->str[pos], xstr, n);
+ }
+}
+
+STC_DEF cstr
+cstr_from_replace_all(const char* str, const size_t str_len,
+ const char* find, const size_t find_len,
+ const char* repl, const size_t repl_len) {
+ cstr out = cstr_null;
+ size_t from = 0; char* res;
+ if (find_len)
+ while ((res = c_strnstrn(str + from, find, str_len - from, find_len))) {
+ const size_t pos = res - str;
+ cstr_append_n(&out, str + from, pos - from);
+ cstr_append_n(&out, repl, repl_len);
+ from = pos + find_len;
+ }
+ cstr_append_n(&out, str + from, str_len - from);
+ return out;
+}
+
+STC_DEF void
+cstr_replace_all(cstr* self, const char* find, const char* repl) {
+ cstr_take(self, cstr_from_replace_all(self->str, _cstr_p(self)->size,
+ find, strlen(find), repl, strlen(repl)));
+}
+
+STC_DEF void
+cstr_erase_n(cstr* self, const size_t pos, size_t n) {
+ const size_t len = _cstr_p(self)->size;
+ if (n > len - pos) n = len - pos;
+ if (len) {
+ memmove(&self->str[pos], &self->str[pos + n], len - (pos + n));
+ self->str[_cstr_p(self)->size -= n] = '\0';
+ }
+}
+
+STC_DEF bool
+cstr_getdelim(cstr *self, const int delim, FILE *fp) {
+ size_t pos = 0, cap = _cstr_p(self)->cap;
+ char* d = self->str;
+ int c = fgetc(fp);
+ if (c == EOF)
+ return false;
+ for (;;) {
+ if (c == delim || c == EOF) {
+ if (cap) d[_cstr_p(self)->size = pos] = '\0';
+ return true;
+ }
+ if (pos == cap) {
+ d = cstr_reserve(self, (cap*3 >> 1) + 16);
+ cap = cstr_capacity(*self);
+ }
+ d[pos++] = (char) c;
+ c = fgetc(fp);
+ }
+}
+
+STC_DEF size_t
+cstr_find(cstr s, const char* needle) {
+ char* res = strstr(s.str, needle);
+ return res ? res - s.str : cstr_npos;
+}
+
+STC_DEF size_t
+cstr_find_from(cstr s, const size_t pos, const char* needle) {
+ if (pos > _cstr_p(&s)->size) return cstr_npos;
+ char* res = strstr(s.str + pos, needle);
+ return res ? res - s.str : cstr_npos;
+}
+
+#endif
+#endif // CSTR_H_INCLUDED
+#undef i_opt
diff --git a/include/stc/carc.h b/include/stc/carc.h
index e4a69e80..73ccc5bf 100644
--- a/include/stc/carc.h
+++ b/include/stc/carc.h
@@ -1,199 +1,199 @@
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-
-/* carc: atomic reference counted shared_ptr
-#include <stc/cstr.h>
-
-typedef struct { cstr name, last; } Person;
-
-Person Person_new(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
-}
-void Person_drop(Person* p) {
- printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
- c_drop(cstr, &p->name, &p->last);
-}
-
-#define i_tag person
-#define i_key Person
-#define i_keydrop Person_drop
-#define i_opt c_no_cmp
-#include <stc/carc.h>
-
-int main() {
- carc_person p = carc_person_make(Person_new("John", "Smiths"));
- carc_person q = carc_person_clone(p); // share the pointer
-
- printf("%s %s. uses: %" PRIuMAX "\n", cstr_str(&q.get->name), cstr_str(&q.get->last), *q.use_count);
- c_drop(carc_person, &p, &q);
-}
-*/
-#include "ccommon.h"
-
-#ifndef CARC_H_INCLUDED
-#define CARC_H_INCLUDED
-#include "forward.h"
-#include <stdlib.h>
-
-#if defined(__GNUC__) || defined(__clang__)
- #define c_atomic_inc(v) (void)__atomic_add_fetch(v, 1, __ATOMIC_SEQ_CST)
- #define c_atomic_dec_and_test(v) !__atomic_sub_fetch(v, 1, __ATOMIC_SEQ_CST)
-#elif defined(_MSC_VER)
- #include <intrin.h>
- #define c_atomic_inc(v) (void)_InterlockedIncrement(v)
- #define c_atomic_dec_and_test(v) !_InterlockedDecrement(v)
-#else
- #include <stdatomic.h>
- #define c_atomic_inc(v) (void)atomic_fetch_add(v, 1)
- #define c_atomic_dec_and_test(v) (atomic_fetch_sub(v, 1) == 1)
-#endif
-
-#define carc_null {NULL, NULL}
-#define _cx_carc_rep struct _cx_memb(_rep_)
-#endif // CARC_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix carc_
-#endif
-#include "template.h"
-typedef i_keyraw _cx_raw;
-
-#if !c_option(c_no_atomic)
- #define _i_atomic_inc(v) c_atomic_inc(v)
- #define _i_atomic_dec_and_test(v) c_atomic_dec_and_test(v)
-#else
- #define _i_atomic_inc(v) (void)(++*(v))
- #define _i_atomic_dec_and_test(v) !(--*(v))
-#endif
-#if !c_option(c_is_fwd)
-_cx_deftypes(_c_carc_types, _cx_self, i_key);
-#endif
-_cx_carc_rep { long counter; i_key value; };
-
-STC_INLINE _cx_self _cx_memb(_init)(void)
- { return c_make(_cx_self){NULL, NULL}; }
-
-STC_INLINE long _cx_memb(_use_count)(_cx_self ptr)
- { return ptr.use_count ? *ptr.use_count : 0; }
-
-STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p) {
- _cx_self ptr = {p};
- if (p)
- *(ptr.use_count = c_alloc(long)) = 1;
- return ptr;
-}
-
-// c++: std::make_shared<_cx_value>(val)
-STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) {
- _cx_self ptr;
- _cx_carc_rep *rep = c_alloc(_cx_carc_rep);
- *(ptr.use_count = &rep->counter) = 1;
- *(ptr.get = &rep->value) = val;
- return ptr;
-}
-
-STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self)
- { return i_keyto(self->get); }
-
-STC_INLINE _cx_value _cx_memb(_toval)(const _cx_self* self)
- { return *self->get; }
-
-STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) {
- _cx_self ptr = *self;
- self->get = NULL, self->use_count = NULL;
- return ptr;
-}
-
-STC_INLINE void _cx_memb(_drop)(_cx_self* self) {
- if (self->use_count && _i_atomic_dec_and_test(self->use_count)) {
- i_keydrop(self->get);
- if ((char *)self->get != (char *)self->use_count + offsetof(_cx_carc_rep, value))
- c_free(self->get);
- c_free(self->use_count);
- }
-}
-
-STC_INLINE void _cx_memb(_reset)(_cx_self* self) {
- _cx_memb(_drop)(self);
- self->use_count = NULL, self->get = NULL;
-}
-
-STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) {
- _cx_memb(_drop)(self);
- *self = _cx_memb(_from_ptr)(p);
-}
-
-#if !defined _i_no_clone && !defined _i_no_emplace
- STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw)
- { return _cx_memb(_make)(i_keyfrom(raw)); }
-#endif // !_i_no_clone
-
-// does not use i_keyclone, so OK to always define.
-STC_INLINE _cx_self _cx_memb(_clone)(_cx_self ptr) {
- if (ptr.use_count)
- _i_atomic_inc(ptr.use_count);
- return ptr;
-}
-
-STC_INLINE void _cx_memb(_copy)(_cx_self* self, _cx_self ptr) {
- if (ptr.use_count)
- _i_atomic_inc(ptr.use_count);
- _cx_memb(_drop)(self);
- *self = ptr;
-}
-
-STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self ptr) {
- if (self->get != ptr.get)
- _cx_memb(_drop)(self);
- *self = ptr;
-}
-
-STC_INLINE uint64_t _cx_memb(_value_hash)(const _cx_value* x) {
- #if c_option(c_no_cmp)
- return c_default_hash(&x);
- #else
- _cx_raw rx = i_keyto(x);
- return i_hash((&rx));
- #endif
-}
-
-STC_INLINE int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- #if c_option(c_no_cmp)
- return c_default_cmp(&x, &y);
- #else
- _cx_raw rx = i_keyto(x), ry = i_keyto(y);
- return i_cmp((&rx), (&ry));
- #endif
-}
-
-STC_INLINE bool _cx_memb(_value_eq)(const _cx_value* x, const _cx_value* y) {
- #if c_option(c_no_cmp)
- return x == y;
- #else
- _cx_raw rx = i_keyto(x), ry = i_keyto(y);
- return i_eq((&rx), (&ry));
- #endif
-}
-#undef _i_atomic_inc
-#undef _i_atomic_dec_and_test
-#include "template.h"
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+
+/* carc: atomic reference counted shared_ptr
+#include <stc/cstr.h>
+
+typedef struct { cstr name, last; } Person;
+
+Person Person_new(const char* name, const char* last) {
+ return (Person){.name = cstr_from(name), .last = cstr_from(last)};
+}
+void Person_drop(Person* p) {
+ printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
+ c_drop(cstr, &p->name, &p->last);
+}
+
+#define i_tag person
+#define i_key Person
+#define i_keydrop Person_drop
+#define i_opt c_no_cmp
+#include <stc/carc.h>
+
+int main() {
+ carc_person p = carc_person_make(Person_new("John", "Smiths"));
+ carc_person q = carc_person_clone(p); // share the pointer
+
+ printf("%s %s. uses: %" PRIuMAX "\n", cstr_str(&q.get->name), cstr_str(&q.get->last), *q.use_count);
+ c_drop(carc_person, &p, &q);
+}
+*/
+#include "ccommon.h"
+
+#ifndef CARC_H_INCLUDED
+#define CARC_H_INCLUDED
+#include "forward.h"
+#include <stdlib.h>
+
+#if defined(__GNUC__) || defined(__clang__)
+ #define c_atomic_inc(v) (void)__atomic_add_fetch(v, 1, __ATOMIC_SEQ_CST)
+ #define c_atomic_dec_and_test(v) !__atomic_sub_fetch(v, 1, __ATOMIC_SEQ_CST)
+#elif defined(_MSC_VER)
+ #include <intrin.h>
+ #define c_atomic_inc(v) (void)_InterlockedIncrement(v)
+ #define c_atomic_dec_and_test(v) !_InterlockedDecrement(v)
+#else
+ #include <stdatomic.h>
+ #define c_atomic_inc(v) (void)atomic_fetch_add(v, 1)
+ #define c_atomic_dec_and_test(v) (atomic_fetch_sub(v, 1) == 1)
+#endif
+
+#define carc_null {NULL, NULL}
+#define _cx_carc_rep struct _cx_memb(_rep_)
+#endif // CARC_H_INCLUDED
+
+#ifndef _i_prefix
+#define _i_prefix carc_
+#endif
+#include "template.h"
+typedef i_keyraw _cx_raw;
+
+#if !c_option(c_no_atomic)
+ #define _i_atomic_inc(v) c_atomic_inc(v)
+ #define _i_atomic_dec_and_test(v) c_atomic_dec_and_test(v)
+#else
+ #define _i_atomic_inc(v) (void)(++*(v))
+ #define _i_atomic_dec_and_test(v) !(--*(v))
+#endif
+#if !c_option(c_is_fwd)
+_cx_deftypes(_c_carc_types, _cx_self, i_key);
+#endif
+_cx_carc_rep { long counter; i_key value; };
+
+STC_INLINE _cx_self _cx_memb(_init)(void)
+ { return c_make(_cx_self){NULL, NULL}; }
+
+STC_INLINE long _cx_memb(_use_count)(_cx_self ptr)
+ { return ptr.use_count ? *ptr.use_count : 0; }
+
+STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p) {
+ _cx_self ptr = {p};
+ if (p)
+ *(ptr.use_count = c_alloc(long)) = 1;
+ return ptr;
+}
+
+// c++: std::make_shared<_cx_value>(val)
+STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) {
+ _cx_self ptr;
+ _cx_carc_rep *rep = c_alloc(_cx_carc_rep);
+ *(ptr.use_count = &rep->counter) = 1;
+ *(ptr.get = &rep->value) = val;
+ return ptr;
+}
+
+STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self)
+ { return i_keyto(self->get); }
+
+STC_INLINE _cx_value _cx_memb(_toval)(const _cx_self* self)
+ { return *self->get; }
+
+STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) {
+ _cx_self ptr = *self;
+ self->get = NULL, self->use_count = NULL;
+ return ptr;
+}
+
+STC_INLINE void _cx_memb(_drop)(_cx_self* self) {
+ if (self->use_count && _i_atomic_dec_and_test(self->use_count)) {
+ i_keydrop(self->get);
+ if ((char *)self->get != (char *)self->use_count + offsetof(_cx_carc_rep, value))
+ c_free(self->get);
+ c_free(self->use_count);
+ }
+}
+
+STC_INLINE void _cx_memb(_reset)(_cx_self* self) {
+ _cx_memb(_drop)(self);
+ self->use_count = NULL, self->get = NULL;
+}
+
+STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) {
+ _cx_memb(_drop)(self);
+ *self = _cx_memb(_from_ptr)(p);
+}
+
+#if !defined _i_no_clone && !defined _i_no_emplace
+ STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw)
+ { return _cx_memb(_make)(i_keyfrom(raw)); }
+#endif // !_i_no_clone
+
+// does not use i_keyclone, so OK to always define.
+STC_INLINE _cx_self _cx_memb(_clone)(_cx_self ptr) {
+ if (ptr.use_count)
+ _i_atomic_inc(ptr.use_count);
+ return ptr;
+}
+
+STC_INLINE void _cx_memb(_copy)(_cx_self* self, _cx_self ptr) {
+ if (ptr.use_count)
+ _i_atomic_inc(ptr.use_count);
+ _cx_memb(_drop)(self);
+ *self = ptr;
+}
+
+STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self ptr) {
+ if (self->get != ptr.get)
+ _cx_memb(_drop)(self);
+ *self = ptr;
+}
+
+STC_INLINE uint64_t _cx_memb(_value_hash)(const _cx_value* x) {
+ #if c_option(c_no_cmp)
+ return c_default_hash(&x);
+ #else
+ _cx_raw rx = i_keyto(x);
+ return i_hash((&rx));
+ #endif
+}
+
+STC_INLINE int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
+ #if c_option(c_no_cmp)
+ return c_default_cmp(&x, &y);
+ #else
+ _cx_raw rx = i_keyto(x), ry = i_keyto(y);
+ return i_cmp((&rx), (&ry));
+ #endif
+}
+
+STC_INLINE bool _cx_memb(_value_eq)(const _cx_value* x, const _cx_value* y) {
+ #if c_option(c_no_cmp)
+ return x == y;
+ #else
+ _cx_raw rx = i_keyto(x), ry = i_keyto(y);
+ return i_eq((&rx), (&ry));
+ #endif
+}
+#undef _i_atomic_inc
+#undef _i_atomic_dec_and_test
+#include "template.h"
diff --git a/include/stc/cbits.h b/include/stc/cbits.h
index b3f5ac4d..bf5d5406 100644
--- a/include/stc/cbits.h
+++ b/include/stc/cbits.h
@@ -1,328 +1,328 @@
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-/*
-Similar to boost::dynamic_bitset / std::bitset
-
-#include <stdio.h>
-#include "cbits.h"
-
-int main() {
- c_autovar (cbits bset = cbits_with_size(23, true), cbits_drop(&bset))
- {
- cbits_reset(&bset, 9);
- cbits_resize(&bset, 43, false);
-
- printf("%4zu: ", cbits_size(&bset));
- c_forrange (i, cbits_size(&bset))
- printf("%d", cbits_at(&bset, i));
- puts("");
- cbits_set(&bset, 28);
- cbits_resize(&bset, 77, true);
- cbits_resize(&bset, 93, false);
- cbits_resize(&bset, 102, true);
- cbits_set_value(&bset, 99, false);
-
- printf("%4zu: ", cbits_size(&bset));
- c_forrange (i, cbits_size(&bset))
- printf("%d", cbits_at(&bset, i));
- puts("");
- }
-}
-*/
-
-#ifndef CBITS_H_INCLUDED
-#define i_header
-#include "ccommon.h"
-#include <stdlib.h>
-#include <string.h>
-
-#define _cbits_bit(i) ((uint64_t)1 << ((i) & 63))
-#define _cbits_words(n) (((n) + 63)>>6)
-#define _cbits_bytes(n) (_cbits_words(n) * sizeof(uint64_t))
-
-STC_API bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, size_t sz);
-STC_API bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, size_t sz);
-STC_API size_t _cbits_count(const uint64_t* set, const size_t sz);
-STC_API char* _cbits_to_str(const uint64_t* set, const size_t sz,
- char* out, size_t start, intptr_t stop);
-
-#if defined(__GNUC__) || defined(__clang__)
- STC_INLINE uint64_t cpopcount64(uint64_t x) {return __builtin_popcountll(x);}
-#elif defined(_MSC_VER) && defined(_WIN64)
- #include <intrin.h>
- STC_INLINE uint64_t cpopcount64(uint64_t x) {return __popcnt64(x);}
-#else
- STC_INLINE uint64_t cpopcount64(uint64_t x) { /* http://en.wikipedia.org/wiki/Hamming_weight */
- x -= (x >> 1) & 0x5555555555555555;
- x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333);
- x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;
- return (x * 0x0101010101010101) >> 56;
- }
-#endif
-#endif // CBITS_H_INCLUDED
-
-#define _i_memb(name) c_paste(i_type, name)
-
-#if !defined i_len
-
-#define _i_assert(x) assert(x)
-#define i_type cbits
-
-struct { uint64_t *data64; size_t _size; } typedef i_type;
-
-STC_INLINE cbits cbits_init(void) { return c_make(cbits){NULL}; }
-STC_INLINE void cbits_drop(cbits* self) { c_free(self->data64); }
-STC_INLINE size_t cbits_size(const cbits* self) { return self->_size; }
-STC_API void cbits_resize(cbits* self, size_t size, bool value);
-STC_API cbits* cbits_copy(cbits* self, const cbits* other);
-
-// predecl;
-STC_INLINE void cbits_set_all(cbits *self, const bool value);
-STC_INLINE void cbits_set_pattern(cbits *self, const uint64_t pattern);
-
-STC_INLINE cbits cbits_move(cbits* self) {
- cbits tmp = *self;
- self->data64 = NULL, self->_size = 0;
- return tmp;
-}
-
-STC_INLINE cbits* cbits_take(cbits* self, cbits other) {
- if (self->data64 != other.data64) {
- cbits_drop(self);
- *self = other;
- }
- return self;
-}
-
-STC_INLINE cbits cbits_clone(cbits other) {
- const size_t bytes = _cbits_bytes(other._size);
- cbits set = {(uint64_t *)memcpy(c_malloc(bytes), other.data64, bytes), other._size};
- return set;
-}
-
-STC_INLINE cbits cbits_with_size(const size_t size, const bool value) {
- cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size};
- cbits_set_all(&set, value);
- return set;
-}
-
-STC_INLINE cbits cbits_with_pattern(const size_t size, const uint64_t pattern) {
- cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size};
- cbits_set_pattern(&set, pattern);
- return set;
-}
-
-#else // i_len
-
-#define _i_assert(x) (void)0
-#if !defined i_type
- #define i_type c_paste(cbits, i_len)
-#endif
-
-struct { uint64_t data64[(i_len - 1)/64 + 1]; } typedef i_type;
-
-STC_INLINE i_type _i_memb(_init)(void) { return c_make(i_type){0}; }
-STC_INLINE void _i_memb(_drop)(i_type* self) {}
-STC_INLINE size_t _i_memb(_size)(const i_type* self) { return i_len; }
-STC_INLINE i_type _i_memb(_move)(i_type* self) { return *self; }
-
-STC_INLINE i_type* _i_memb(_take)(i_type* self, i_type other)
- { *self = other; return self; }
-
-STC_INLINE i_type _i_memb(_clone)(i_type other)
- { return other; }
-
-STC_INLINE i_type* _i_memb(_copy)(i_type* self, i_type other)
- { *self = other; return self; }
-
-STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value);
-STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern);
-
-STC_INLINE i_type _i_memb(_with_size)(const size_t size, const bool value) {
- assert(size <= i_len);
- i_type set; _i_memb(_set_all)(&set, value);
- return set;
-}
-
-STC_INLINE i_type _i_memb(_with_pattern)(const size_t size, const uint64_t pattern) {
- assert(size <= i_len);
- i_type set; _i_memb(_set_pattern)(&set, pattern);
- return set;
-}
-#endif // i_len
-
-
-STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value)
- { memset(self->data64, value? ~0 : 0, _cbits_bytes(_i_memb(_size)(self))); }
-
-STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern) {
- size_t n = _cbits_words(_i_memb(_size)(self));
- while (n--) self->data64[n] = pattern;
-}
-
-STC_INLINE bool _i_memb(_test)(const i_type* self, const size_t i)
- { return (self->data64[i>>6] & _cbits_bit(i)) != 0; }
-
-STC_INLINE bool _i_memb(_at)(const i_type* self, const size_t i)
- { return (self->data64[i>>6] & _cbits_bit(i)) != 0; }
-
-STC_INLINE void _i_memb(_set)(i_type *self, const size_t i)
- { self->data64[i>>6] |= _cbits_bit(i); }
-
-STC_INLINE void _i_memb(_reset)(i_type *self, const size_t i)
- { self->data64[i>>6] &= ~_cbits_bit(i); }
-
-STC_INLINE void _i_memb(_set_value)(i_type *self, const size_t i, const bool b) {
- self->data64[i>>6] ^= ((uint64_t)-(int)b ^ self->data64[i>>6]) & _cbits_bit(i);
-}
-
-STC_INLINE void _i_memb(_flip)(i_type *self, const size_t i)
- { self->data64[i>>6] ^= _cbits_bit(i); }
-
-STC_INLINE void _i_memb(_flip_all)(i_type *self) {
- size_t n = _cbits_words(_i_memb(_size)(self));
- while (n--) self->data64[n] ^= ~(uint64_t)0;
-}
-
-STC_INLINE i_type _i_memb(_from)(const char* str) {
- size_t n = strlen(str);
- i_type set = _i_memb(_with_size)(n, false);
- while (n--) if (str[n] == '1') _i_memb(_set)(&set, n);
- return set;
-}
-
-/* Intersection */
-STC_INLINE void _i_memb(_intersect)(i_type *self, const i_type* other) {
- _i_assert(self->_size == other->_size);
- size_t n = _cbits_words(_i_memb(_size)(self));
- while (n--) self->data64[n] &= other->data64[n];
-}
-/* Union */
-STC_INLINE void _i_memb(_union)(i_type *self, const i_type* other) {
- _i_assert(self->_size == other->_size);
- size_t n = _cbits_words(_i_memb(_size)(self));
- while (n--) self->data64[n] |= other->data64[n];
-}
-/* Exclusive disjunction */
-STC_INLINE void _i_memb(_xor)(i_type *self, const i_type* other) {
- _i_assert(self->_size == other->_size);
- size_t n = _cbits_words(_i_memb(_size)(self));
- while (n--) self->data64[n] ^= other->data64[n];
-}
-
-STC_INLINE size_t _i_memb(_count)(const i_type* self)
- { return _cbits_count(self->data64, _i_memb(_size)(self)); }
-
-STC_INLINE char* _i_memb(_to_str)(const i_type* self, char* out, size_t start, intptr_t stop)
- { return _cbits_to_str(self->data64, _i_memb(_size)(self), out, start, stop); }
-
-STC_INLINE bool _i_memb(_subset_of)(const i_type* self, const i_type* other) {
- _i_assert(self->_size == other->_size);
- return _cbits_subset_of(self->data64, other->data64, _i_memb(_size)(self));
-}
-
-STC_INLINE bool _i_memb(_disjoint)(const i_type* self, const i_type* other) {
- _i_assert(self->_size == other->_size);
- return _cbits_disjoint(self->data64, other->data64, _i_memb(_size)(self));
-}
-
-
-#if defined(i_implement)
-
-#if !defined i_len
-STC_DEF cbits* cbits_copy(cbits* self, const cbits* other) {
- if (self->data64 == other->data64)
- return self;
- if (self->_size != other->_size)
- return cbits_take(self, cbits_clone(*other));
- memcpy(self->data64, other->data64, _cbits_bytes(other->_size));
- return self;
-}
-
-STC_DEF void cbits_resize(cbits* self, const size_t size, const bool value) {
- const size_t new_n = _cbits_words(size), osize = self->_size, old_n = _cbits_words(osize);
- self->data64 = (uint64_t *)c_realloc(self->data64, new_n*8);
- self->_size = size;
- if (new_n >= old_n) {
- memset(self->data64 + old_n, -(int)value, (new_n - old_n)*8);
- if (old_n > 0) {
- uint64_t m = _cbits_bit(osize) - 1; /* mask */
- value ? (self->data64[old_n - 1] |= ~m)
- : (self->data64[old_n - 1] &= m);
- }
- }
-}
-#endif
-#ifndef CBITS_H_INCLUDED
-
-STC_DEF size_t _cbits_count(const uint64_t* set, const size_t sz) {
- const size_t n = sz>>6;
- size_t count = 0;
- for (size_t i = 0; i < n; ++i)
- count += cpopcount64(set[i]);
- if (sz & 63)
- count += cpopcount64(set[n] & (_cbits_bit(sz) - 1));
- return count;
-}
-
-STC_DEF char* _cbits_to_str(const uint64_t* set, const size_t sz,
- char* out, size_t start, intptr_t stop) {
- if (stop < 0)
- stop = sz;
- memset(out, '0', stop - start);
- for (intptr_t i = start; i < stop; ++i)
- if ((set[i>>6] & _cbits_bit(i)) != 0)
- out[i - start] = '1';
- out[stop - start] = '\0';
- return out;
-}
-
-#define _cbits_OPR(OPR, VAL) \
- const size_t n = sz>>6; \
- for (size_t i = 0; i < n; ++i) \
- if ((set[i] OPR other[i]) != VAL) \
- return false; \
- if (!(sz & 63)) \
- return true; \
- const uint64_t i = n, m = _cbits_bit(sz) - 1; \
- return ((set[i] OPR other[i]) & m) == (VAL & m)
-
-STC_DEF bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, const size_t sz)
- { _cbits_OPR(|, set[i]); }
-
-STC_DEF bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, const size_t sz)
- { _cbits_OPR(&, 0); }
-
-#endif // !CBITS_H_INCLUDED
-#endif // i_implement
-
-#define CBITS_H_INCLUDED
-#undef _i_memb
-#undef _i_assert
-#undef i_len
-#undef i_type
-#undef i_opt
-#undef i_header
-#undef i_implement
-#undef i_static
-#undef i_exterm
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+/*
+Similar to boost::dynamic_bitset / std::bitset
+
+#include <stdio.h>
+#include "cbits.h"
+
+int main() {
+ c_autovar (cbits bset = cbits_with_size(23, true), cbits_drop(&bset))
+ {
+ cbits_reset(&bset, 9);
+ cbits_resize(&bset, 43, false);
+
+ printf("%4zu: ", cbits_size(&bset));
+ c_forrange (i, cbits_size(&bset))
+ printf("%d", cbits_at(&bset, i));
+ puts("");
+ cbits_set(&bset, 28);
+ cbits_resize(&bset, 77, true);
+ cbits_resize(&bset, 93, false);
+ cbits_resize(&bset, 102, true);
+ cbits_set_value(&bset, 99, false);
+
+ printf("%4zu: ", cbits_size(&bset));
+ c_forrange (i, cbits_size(&bset))
+ printf("%d", cbits_at(&bset, i));
+ puts("");
+ }
+}
+*/
+
+#ifndef CBITS_H_INCLUDED
+#define i_header
+#include "ccommon.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define _cbits_bit(i) ((uint64_t)1 << ((i) & 63))
+#define _cbits_words(n) (((n) + 63)>>6)
+#define _cbits_bytes(n) (_cbits_words(n) * sizeof(uint64_t))
+
+STC_API bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, size_t sz);
+STC_API bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, size_t sz);
+STC_API size_t _cbits_count(const uint64_t* set, const size_t sz);
+STC_API char* _cbits_to_str(const uint64_t* set, const size_t sz,
+ char* out, size_t start, intptr_t stop);
+
+#if defined(__GNUC__) || defined(__clang__)
+ STC_INLINE uint64_t cpopcount64(uint64_t x) {return __builtin_popcountll(x);}
+#elif defined(_MSC_VER) && defined(_WIN64)
+ #include <intrin.h>
+ STC_INLINE uint64_t cpopcount64(uint64_t x) {return __popcnt64(x);}
+#else
+ STC_INLINE uint64_t cpopcount64(uint64_t x) { /* http://en.wikipedia.org/wiki/Hamming_weight */
+ x -= (x >> 1) & 0x5555555555555555;
+ x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333);
+ x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;
+ return (x * 0x0101010101010101) >> 56;
+ }
+#endif
+#endif // CBITS_H_INCLUDED
+
+#define _i_memb(name) c_paste(i_type, name)
+
+#if !defined i_len
+
+#define _i_assert(x) assert(x)
+#define i_type cbits
+
+struct { uint64_t *data64; size_t _size; } typedef i_type;
+
+STC_INLINE cbits cbits_init(void) { return c_make(cbits){NULL}; }
+STC_INLINE void cbits_drop(cbits* self) { c_free(self->data64); }
+STC_INLINE size_t cbits_size(const cbits* self) { return self->_size; }
+STC_API void cbits_resize(cbits* self, size_t size, bool value);
+STC_API cbits* cbits_copy(cbits* self, const cbits* other);
+
+// predecl;
+STC_INLINE void cbits_set_all(cbits *self, const bool value);
+STC_INLINE void cbits_set_pattern(cbits *self, const uint64_t pattern);
+
+STC_INLINE cbits cbits_move(cbits* self) {
+ cbits tmp = *self;
+ self->data64 = NULL, self->_size = 0;
+ return tmp;
+}
+
+STC_INLINE cbits* cbits_take(cbits* self, cbits other) {
+ if (self->data64 != other.data64) {
+ cbits_drop(self);
+ *self = other;
+ }
+ return self;
+}
+
+STC_INLINE cbits cbits_clone(cbits other) {
+ const size_t bytes = _cbits_bytes(other._size);
+ cbits set = {(uint64_t *)memcpy(c_malloc(bytes), other.data64, bytes), other._size};
+ return set;
+}
+
+STC_INLINE cbits cbits_with_size(const size_t size, const bool value) {
+ cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size};
+ cbits_set_all(&set, value);
+ return set;
+}
+
+STC_INLINE cbits cbits_with_pattern(const size_t size, const uint64_t pattern) {
+ cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size};
+ cbits_set_pattern(&set, pattern);
+ return set;
+}
+
+#else // i_len
+
+#define _i_assert(x) (void)0
+#if !defined i_type
+ #define i_type c_paste(cbits, i_len)
+#endif
+
+struct { uint64_t data64[(i_len - 1)/64 + 1]; } typedef i_type;
+
+STC_INLINE i_type _i_memb(_init)(void) { return c_make(i_type){0}; }
+STC_INLINE void _i_memb(_drop)(i_type* self) {}
+STC_INLINE size_t _i_memb(_size)(const i_type* self) { return i_len; }
+STC_INLINE i_type _i_memb(_move)(i_type* self) { return *self; }
+
+STC_INLINE i_type* _i_memb(_take)(i_type* self, i_type other)
+ { *self = other; return self; }
+
+STC_INLINE i_type _i_memb(_clone)(i_type other)
+ { return other; }
+
+STC_INLINE i_type* _i_memb(_copy)(i_type* self, i_type other)
+ { *self = other; return self; }
+
+STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value);
+STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern);
+
+STC_INLINE i_type _i_memb(_with_size)(const size_t size, const bool value) {
+ assert(size <= i_len);
+ i_type set; _i_memb(_set_all)(&set, value);
+ return set;
+}
+
+STC_INLINE i_type _i_memb(_with_pattern)(const size_t size, const uint64_t pattern) {
+ assert(size <= i_len);
+ i_type set; _i_memb(_set_pattern)(&set, pattern);
+ return set;
+}
+#endif // i_len
+
+
+STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value)
+ { memset(self->data64, value? ~0 : 0, _cbits_bytes(_i_memb(_size)(self))); }
+
+STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern) {
+ size_t n = _cbits_words(_i_memb(_size)(self));
+ while (n--) self->data64[n] = pattern;
+}
+
+STC_INLINE bool _i_memb(_test)(const i_type* self, const size_t i)
+ { return (self->data64[i>>6] & _cbits_bit(i)) != 0; }
+
+STC_INLINE bool _i_memb(_at)(const i_type* self, const size_t i)
+ { return (self->data64[i>>6] & _cbits_bit(i)) != 0; }
+
+STC_INLINE void _i_memb(_set)(i_type *self, const size_t i)
+ { self->data64[i>>6] |= _cbits_bit(i); }
+
+STC_INLINE void _i_memb(_reset)(i_type *self, const size_t i)
+ { self->data64[i>>6] &= ~_cbits_bit(i); }
+
+STC_INLINE void _i_memb(_set_value)(i_type *self, const size_t i, const bool b) {
+ self->data64[i>>6] ^= ((uint64_t)-(int)b ^ self->data64[i>>6]) & _cbits_bit(i);
+}
+
+STC_INLINE void _i_memb(_flip)(i_type *self, const size_t i)
+ { self->data64[i>>6] ^= _cbits_bit(i); }
+
+STC_INLINE void _i_memb(_flip_all)(i_type *self) {
+ size_t n = _cbits_words(_i_memb(_size)(self));
+ while (n--) self->data64[n] ^= ~(uint64_t)0;
+}
+
+STC_INLINE i_type _i_memb(_from)(const char* str) {
+ size_t n = strlen(str);
+ i_type set = _i_memb(_with_size)(n, false);
+ while (n--) if (str[n] == '1') _i_memb(_set)(&set, n);
+ return set;
+}
+
+/* Intersection */
+STC_INLINE void _i_memb(_intersect)(i_type *self, const i_type* other) {
+ _i_assert(self->_size == other->_size);
+ size_t n = _cbits_words(_i_memb(_size)(self));
+ while (n--) self->data64[n] &= other->data64[n];
+}
+/* Union */
+STC_INLINE void _i_memb(_union)(i_type *self, const i_type* other) {
+ _i_assert(self->_size == other->_size);
+ size_t n = _cbits_words(_i_memb(_size)(self));
+ while (n--) self->data64[n] |= other->data64[n];
+}
+/* Exclusive disjunction */
+STC_INLINE void _i_memb(_xor)(i_type *self, const i_type* other) {
+ _i_assert(self->_size == other->_size);
+ size_t n = _cbits_words(_i_memb(_size)(self));
+ while (n--) self->data64[n] ^= other->data64[n];
+}
+
+STC_INLINE size_t _i_memb(_count)(const i_type* self)
+ { return _cbits_count(self->data64, _i_memb(_size)(self)); }
+
+STC_INLINE char* _i_memb(_to_str)(const i_type* self, char* out, size_t start, intptr_t stop)
+ { return _cbits_to_str(self->data64, _i_memb(_size)(self), out, start, stop); }
+
+STC_INLINE bool _i_memb(_subset_of)(const i_type* self, const i_type* other) {
+ _i_assert(self->_size == other->_size);
+ return _cbits_subset_of(self->data64, other->data64, _i_memb(_size)(self));
+}
+
+STC_INLINE bool _i_memb(_disjoint)(const i_type* self, const i_type* other) {
+ _i_assert(self->_size == other->_size);
+ return _cbits_disjoint(self->data64, other->data64, _i_memb(_size)(self));
+}
+
+
+#if defined(i_implement)
+
+#if !defined i_len
+STC_DEF cbits* cbits_copy(cbits* self, const cbits* other) {
+ if (self->data64 == other->data64)
+ return self;
+ if (self->_size != other->_size)
+ return cbits_take(self, cbits_clone(*other));
+ memcpy(self->data64, other->data64, _cbits_bytes(other->_size));
+ return self;
+}
+
+STC_DEF void cbits_resize(cbits* self, const size_t size, const bool value) {
+ const size_t new_n = _cbits_words(size), osize = self->_size, old_n = _cbits_words(osize);
+ self->data64 = (uint64_t *)c_realloc(self->data64, new_n*8);
+ self->_size = size;
+ if (new_n >= old_n) {
+ memset(self->data64 + old_n, -(int)value, (new_n - old_n)*8);
+ if (old_n > 0) {
+ uint64_t m = _cbits_bit(osize) - 1; /* mask */
+ value ? (self->data64[old_n - 1] |= ~m)
+ : (self->data64[old_n - 1] &= m);
+ }
+ }
+}
+#endif
+#ifndef CBITS_H_INCLUDED
+
+STC_DEF size_t _cbits_count(const uint64_t* set, const size_t sz) {
+ const size_t n = sz>>6;
+ size_t count = 0;
+ for (size_t i = 0; i < n; ++i)
+ count += cpopcount64(set[i]);
+ if (sz & 63)
+ count += cpopcount64(set[n] & (_cbits_bit(sz) - 1));
+ return count;
+}
+
+STC_DEF char* _cbits_to_str(const uint64_t* set, const size_t sz,
+ char* out, size_t start, intptr_t stop) {
+ if (stop < 0)
+ stop = sz;
+ memset(out, '0', stop - start);
+ for (intptr_t i = start; i < stop; ++i)
+ if ((set[i>>6] & _cbits_bit(i)) != 0)
+ out[i - start] = '1';
+ out[stop - start] = '\0';
+ return out;
+}
+
+#define _cbits_OPR(OPR, VAL) \
+ const size_t n = sz>>6; \
+ for (size_t i = 0; i < n; ++i) \
+ if ((set[i] OPR other[i]) != VAL) \
+ return false; \
+ if (!(sz & 63)) \
+ return true; \
+ const uint64_t i = n, m = _cbits_bit(sz) - 1; \
+ return ((set[i] OPR other[i]) & m) == (VAL & m)
+
+STC_DEF bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, const size_t sz)
+ { _cbits_OPR(|, set[i]); }
+
+STC_DEF bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, const size_t sz)
+ { _cbits_OPR(&, 0); }
+
+#endif // !CBITS_H_INCLUDED
+#endif // i_implement
+
+#define CBITS_H_INCLUDED
+#undef _i_memb
+#undef _i_assert
+#undef i_len
+#undef i_type
+#undef i_opt
+#undef i_header
+#undef i_implement
+#undef i_static
+#undef i_exterm
diff --git a/include/stc/cbox.h b/include/stc/cbox.h
index 73b437d4..f1e410b1 100644
--- a/include/stc/cbox.h
+++ b/include/stc/cbox.h
@@ -1,182 +1,182 @@
-
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-
-/* cbox: heap allocated boxed type
-#include <stc/cstr.h>
-
-typedef struct { cstr name, email; } Person;
-
-Person Person_from(const char* name, const char* email) {
- return (Person){.name = cstr_from(name), .email = cstr_from(email)};
-}
-Person Person_clone(Person p) {
- p.name = cstr_clone(p.name);
- p.email = cstr_clone(p.email);
- return p;
-}
-void Person_drop(Person* p) {
- printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->email));
- c_drop(cstr, &p->name, &p->email);
-}
-
-#define i_key_bind Person // bind Person clone+drop fn's
-#define i_opt c_no_cmp // compare by .get addresses only
-#define i_type PBox
-#include <stc/cbox.h>
-
-int main() {
- c_auto (PBox, p, q)
- {
- p = PBox_make(Person_from("John Smiths", "[email protected]"));
- q = PBox_clone(p);
- cstr_assign(&q.get->name, "Joe Smiths");
-
- printf("%s %s.\n", cstr_str(&p.get->name), cstr_str(&p.get->email));
- printf("%s %s.\n", cstr_str(&q.get->name), cstr_str(&q.get->email));
- }
-}
-*/
-#include "ccommon.h"
-
-#ifndef CBOX_H_INCLUDED
-#define CBOX_H_INCLUDED
-#include "forward.h"
-#include <stdlib.h>
-#include <string.h>
-
-#define cbox_null {NULL}
-#endif // CBOX_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix cbox_
-#endif
-#include "template.h"
-typedef i_keyraw _cx_raw;
-
-#if !c_option(c_is_fwd)
-_cx_deftypes(_c_cbox_types, _cx_self, i_key);
-#endif
-
-// constructors (takes ownsership)
-STC_INLINE _cx_self _cx_memb(_init)(void)
- { return c_make(_cx_self){NULL}; }
-
-STC_INLINE long _cx_memb(_use_count)(_cx_self box)
- { return (long)(box.get != NULL); }
-
-STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p)
- { return c_make(_cx_self){p}; }
-
-// c++: std::make_unique<i_key>(val)
-STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) {
- _cx_self ptr = {c_alloc(_cx_value)};
- *ptr.get = val; return ptr;
-}
-
-STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self)
- { return i_keyto(self->get); }
-
-STC_INLINE _cx_value _cx_memb(_toval)(const _cx_self* self)
- { return *self->get; }
-
-// destructor
-STC_INLINE void _cx_memb(_drop)(_cx_self* self) {
- if (self->get) {
- i_keydrop(self->get);
- c_free(self->get);
- }
-}
-
-STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) {
- _cx_self ptr = *self;
- self->get = NULL;
- return ptr;
-}
-
-STC_INLINE void _cx_memb(_reset)(_cx_self* self) {
- _cx_memb(_drop)(self);
- self->get = NULL;
-}
-
-// take ownership of p
-STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) {
- if (self->get)
- i_keydrop(self->get);
- self->get = p;
-}
-
-#if !defined _i_no_clone
-#if !defined _i_no_emplace
- STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw)
- { return _cx_memb(_make)(i_keyfrom(raw)); }
-#endif
- STC_INLINE _cx_self _cx_memb(_clone)(_cx_self other) {
- if (!other.get)
- return other;
- _cx_self out = {c_alloc(i_key)};
- *out.get = i_keyclone(*other.get);
- return out;
- }
-
- STC_INLINE void _cx_memb(_copy)(_cx_self* self, _cx_self other) {
- if (self->get == other.get)
- return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(other);
- }
-#endif // !_i_no_clone
-
-STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self other) {
- if (other.get != self->get)
- _cx_memb(_drop)(self);
- *self = other;
-}
-
-STC_INLINE uint64_t _cx_memb(_value_hash)(const _cx_value* x) {
- #if c_option(c_no_cmp)
- return c_default_hash(&x);
- #else
- _cx_raw rx = i_keyto(x);
- return i_hash((&rx));
- #endif
-}
-
-STC_INLINE int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- #if c_option(c_no_cmp)
- return c_default_cmp(&x, &y);
- #else
- _cx_raw rx = i_keyto(x), ry = i_keyto(y);
- return i_cmp((&rx), (&ry));
- #endif
-}
-
-STC_INLINE bool _cx_memb(_value_eq)(const _cx_value* x, const _cx_value* y) {
- #if c_option(c_no_cmp)
- return x == y;
- #else
- _cx_raw rx = i_keyto(x), ry = i_keyto(y);
- return i_eq((&rx), (&ry));
- #endif
-}
-#include "template.h"
+
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+
+/* cbox: heap allocated boxed type
+#include <stc/cstr.h>
+
+typedef struct { cstr name, email; } Person;
+
+Person Person_from(const char* name, const char* email) {
+ return (Person){.name = cstr_from(name), .email = cstr_from(email)};
+}
+Person Person_clone(Person p) {
+ p.name = cstr_clone(p.name);
+ p.email = cstr_clone(p.email);
+ return p;
+}
+void Person_drop(Person* p) {
+ printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->email));
+ c_drop(cstr, &p->name, &p->email);
+}
+
+#define i_key_bind Person // bind Person clone+drop fn's
+#define i_opt c_no_cmp // compare by .get addresses only
+#define i_type PBox
+#include <stc/cbox.h>
+
+int main() {
+ c_auto (PBox, p, q)
+ {
+ p = PBox_make(Person_from("John Smiths", "[email protected]"));
+ q = PBox_clone(p);
+ cstr_assign(&q.get->name, "Joe Smiths");
+
+ printf("%s %s.\n", cstr_str(&p.get->name), cstr_str(&p.get->email));
+ printf("%s %s.\n", cstr_str(&q.get->name), cstr_str(&q.get->email));
+ }
+}
+*/
+#include "ccommon.h"
+
+#ifndef CBOX_H_INCLUDED
+#define CBOX_H_INCLUDED
+#include "forward.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define cbox_null {NULL}
+#endif // CBOX_H_INCLUDED
+
+#ifndef _i_prefix
+#define _i_prefix cbox_
+#endif
+#include "template.h"
+typedef i_keyraw _cx_raw;
+
+#if !c_option(c_is_fwd)
+_cx_deftypes(_c_cbox_types, _cx_self, i_key);
+#endif
+
+// constructors (takes ownsership)
+STC_INLINE _cx_self _cx_memb(_init)(void)
+ { return c_make(_cx_self){NULL}; }
+
+STC_INLINE long _cx_memb(_use_count)(_cx_self box)
+ { return (long)(box.get != NULL); }
+
+STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p)
+ { return c_make(_cx_self){p}; }
+
+// c++: std::make_unique<i_key>(val)
+STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) {
+ _cx_self ptr = {c_alloc(_cx_value)};
+ *ptr.get = val; return ptr;
+}
+
+STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self)
+ { return i_keyto(self->get); }
+
+STC_INLINE _cx_value _cx_memb(_toval)(const _cx_self* self)
+ { return *self->get; }
+
+// destructor
+STC_INLINE void _cx_memb(_drop)(_cx_self* self) {
+ if (self->get) {
+ i_keydrop(self->get);
+ c_free(self->get);
+ }
+}
+
+STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) {
+ _cx_self ptr = *self;
+ self->get = NULL;
+ return ptr;
+}
+
+STC_INLINE void _cx_memb(_reset)(_cx_self* self) {
+ _cx_memb(_drop)(self);
+ self->get = NULL;
+}
+
+// take ownership of p
+STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) {
+ if (self->get)
+ i_keydrop(self->get);
+ self->get = p;
+}
+
+#if !defined _i_no_clone
+#if !defined _i_no_emplace
+ STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw)
+ { return _cx_memb(_make)(i_keyfrom(raw)); }
+#endif
+ STC_INLINE _cx_self _cx_memb(_clone)(_cx_self other) {
+ if (!other.get)
+ return other;
+ _cx_self out = {c_alloc(i_key)};
+ *out.get = i_keyclone(*other.get);
+ return out;
+ }
+
+ STC_INLINE void _cx_memb(_copy)(_cx_self* self, _cx_self other) {
+ if (self->get == other.get)
+ return;
+ _cx_memb(_drop)(self);
+ *self = _cx_memb(_clone)(other);
+ }
+#endif // !_i_no_clone
+
+STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self other) {
+ if (other.get != self->get)
+ _cx_memb(_drop)(self);
+ *self = other;
+}
+
+STC_INLINE uint64_t _cx_memb(_value_hash)(const _cx_value* x) {
+ #if c_option(c_no_cmp)
+ return c_default_hash(&x);
+ #else
+ _cx_raw rx = i_keyto(x);
+ return i_hash((&rx));
+ #endif
+}
+
+STC_INLINE int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
+ #if c_option(c_no_cmp)
+ return c_default_cmp(&x, &y);
+ #else
+ _cx_raw rx = i_keyto(x), ry = i_keyto(y);
+ return i_cmp((&rx), (&ry));
+ #endif
+}
+
+STC_INLINE bool _cx_memb(_value_eq)(const _cx_value* x, const _cx_value* y) {
+ #if c_option(c_no_cmp)
+ return x == y;
+ #else
+ _cx_raw rx = i_keyto(x), ry = i_keyto(y);
+ return i_eq((&rx), (&ry));
+ #endif
+}
+#include "template.h"
diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h
index b67fb598..110114a0 100644
--- a/include/stc/ccommon.h
+++ b/include/stc/ccommon.h
@@ -1,269 +1,269 @@
-/* MIT License
- *
- * Copyright (c) 2022 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 CCOMMON_H_INCLUDED
-#define CCOMMON_H_INCLUDED
-
-#define _CRT_SECURE_NO_WARNINGS
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <string.h>
-#include <assert.h>
-
-#if defined(_MSC_VER)
-# pragma warning(disable: 4116 4996) // unnamed type definition in parentheses
-# define STC_FORCE_INLINE static __forceinline
-#elif defined(__GNUC__) || defined(__clang__)
-# define STC_FORCE_INLINE static inline __attribute((always_inline))
-#else
-# define STC_FORCE_INLINE static inline
-#endif
-#define STC_INLINE static inline
-
-/* Macro overloading feature support based on: https://rextester.com/ONP80107 */
-#define c_MACRO_OVERLOAD(name, ...) \
- c_paste(name, c_numargs(__VA_ARGS__))(__VA_ARGS__)
-#define c_concat(a, b) a ## b
-#define c_paste(a, b) c_concat(a, b)
-#define c_expand(...) __VA_ARGS__
-#define c_numargs(...) _c_APPLY_ARG_N((__VA_ARGS__, _c_RSEQ_N))
-
-#define _c_APPLY_ARG_N(args) c_expand(_c_ARG_N args)
-#define _c_RSEQ_N 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
-#define _c_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
- _14, _15, _16, N, ...) N
-
-#define c_static_assert(cond) \
- typedef char c_paste(_static_assert_line_, __LINE__)[(cond) ? 1 : -1]
-#define c_unchecked_container_of(ptr, type, member) \
- ((type *)((char *)(ptr) - offsetof(type, member)))
-#if __STDC_VERSION__ >= 202300L || defined STC_CHECKED_CONTAINER_OF
-# define c_container_of(ptr, type, member) \
- (((type *)((char *)(ptr) - offsetof(type, member))) + \
- ((typeof(ptr))0 != (typeof(&((type *)0)->member))0))
-#else
-# define c_container_of(p,t,m) c_unchecked_container_of(p,t,m)
-#endif
-#ifndef __cplusplus
-# define c_alloc(T) c_malloc(sizeof(T))
-# define c_alloc_n(T, n) c_malloc(sizeof(T)*(n))
-# define c_make(T) (T)
-# define c_new(T, ...) (T*)memcpy(c_alloc(T), (T[]){__VA_ARGS__}, sizeof(T))
-#else
-# include <new>
-# define c_alloc(T) static_cast<T*>(c_malloc(sizeof(T)))
-# define c_alloc_n(T, n) static_cast<T*>(c_malloc(sizeof(T)*(n)))
-# define c_make(T) T
-# define c_new(T, ...) new (c_alloc(T)) T(__VA_ARGS__)
-#endif
-#ifndef c_malloc
-# define c_malloc(sz) malloc(sz)
-# define c_calloc(n, sz) calloc(n, sz)
-# define c_realloc(p, sz) realloc(p, sz)
-# define c_free(p) free(p)
-#endif
-
-#define c_delete(T, ptr) do { T *_c_p = ptr; T##_drop(_c_p); c_free(_c_p); } while (0)
-#define c_swap(T, x, y) do { T _c_t = x; x = y; y = _c_t; } while (0)
-#define c_arraylen(a) (sizeof (a)/sizeof *(a))
-
-// x and y are i_keyraw* type, defaults to i_key*:
-#define c_less_cmp(less, x, y) ((less((y), (x))) - (less((x), (y))))
-#define c_default_cmp(x, y) c_less_cmp(c_default_less, x, y)
-#define c_default_less(x, y) (*(x) < *(y))
-#define c_default_eq(x, y) (*(x) == *(y))
-#define c_memcmp_eq(x, y) (memcmp(x, y, sizeof *(x)) == 0)
-#define c_default_hash(x) c_fasthash(x, sizeof *(x))
-
-#define c_default_clone(v) (v)
-#define c_default_toraw(vp) (*(vp))
-#define c_default_drop(vp) ((void) (vp))
-#define c_derived_keyclone(v) i_keyfrom((i_keyto((&(v)))))
-#define c_derived_valclone(v) i_valfrom((i_valto((&(v)))))
-
-#define c_option(flag) ((i_opt) & (flag))
-#define c_is_fwd (1<<0)
-#define c_no_atomic (1<<1)
-#define c_no_clone (1<<2)
-#define c_no_cmp (1<<3)
-
-/* Generic algorithms */
-
-typedef const char* crawstr;
-#define crawstr_cmp(xp, yp) strcmp(*(xp), *(yp))
-#define crawstr_hash(p) c_strhash(*(p))
-#define c_strlen_lit(literal) (sizeof "" literal - 1U)
-#define c_sv(lit) c_make(csview){lit, c_strlen_lit(lit)}
-#define c_PRIsv ".*s"
-#define c_ARGsv(sv) (int)(sv).size, (sv).str
-
-#define _c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k)))
-
-STC_INLINE uint64_t c_fasthash(const void* key, size_t len) {
- const uint8_t *x = (const uint8_t*) key;
- uint64_t u8, h = 1; size_t n = len >> 3;
- uint32_t u4;
- while (n--) {
- memcpy(&u8, x, 8), x += 8;
- h += (_c_ROTL(u8, 26) ^ u8)*0xc6a4a7935bd1e99d;
- }
- switch (len &= 7) {
- case 0: return h;
- case 4: memcpy(&u4, x, 4);
- return h + u4*0xc6a4a7935bd1e99d;
- }
- h += *x++;
- while (--len) h = (h << 10) - h + *x++;
- return _c_ROTL(h, 26) ^ h;
-}
-
-STC_INLINE uint64_t c_strhash(const char *str)
- { return c_fasthash(str, strlen(str)); }
-
-STC_INLINE char* c_strnstrn(const char *s, const char *needle,
- size_t slen, const 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;
-}
-
-#define c_foreach(...) c_MACRO_OVERLOAD(c_foreach, __VA_ARGS__)
-#define c_foreach3(it, C, cnt) \
- for (C##_iter it = C##_begin(&cnt), it##_end_ = C##_end(&cnt) \
- ; it.ref != it##_end_.ref; C##_next(&it))
-#define c_foreach4(it, C, start, finish) \
- for (C##_iter it = start, it##_end_ = finish \
- ; it.ref != it##_end_.ref; C##_next(&it))
-
-#define c_forpair(key, val, C, cnt) /* structured binding */ \
- for (struct {C##_iter _it; C##_value* _endref; const C##_key* key; C##_mapped* val;} \
- _ = {C##_begin(&cnt), C##_end(&cnt).ref} \
- ; _._it.ref != _._endref && (_.key = &_._it.ref->first, _.val = &_._it.ref->second) \
- ; C##_next(&_._it))
-
-#define c_forrange(...) c_MACRO_OVERLOAD(c_forrange, __VA_ARGS__)
-#define c_forrange1(stop) for (size_t _c_ii=0, _c_end=stop; _c_ii < _c_end; ++_c_ii)
-#define c_forrange2(i, stop) for (size_t i=0, _c_end=stop; i < _c_end; ++i)
-#define c_forrange3(i, type, stop) for (type i=0, _c_end=stop; i < _c_end; ++i)
-#define c_forrange4(i, type, start, stop) for (type i=start, _c_end=stop; i < _c_end; ++i)
-#define c_forrange5(i, type, start, stop, step) \
- for (type i=start, _c_inc=step, _c_end=(stop) - (0 < _c_inc) \
- ; (i <= _c_end) == (0 < _c_inc); i += _c_inc)
-
-#define c_autovar(...) c_MACRO_OVERLOAD(c_autovar, __VA_ARGS__)
-#define c_autovar2(declvar, drop) for (declvar, **_c_ii = NULL; !_c_ii; ++_c_ii, drop)
-#define c_autovar3(declvar, pred, drop) for (declvar, **_c_ii = NULL; !_c_ii && (pred); ++_c_ii, drop)
-#define c_autoscope(init, drop) for (int _c_ii = (init, 0); !_c_ii; ++_c_ii, drop)
-#define c_autodefer(...) for (int _c_ii = 0; !_c_ii; ++_c_ii, __VA_ARGS__)
-#define c_breakauto continue
-
-#define c_auto(...) c_MACRO_OVERLOAD(c_auto, __VA_ARGS__)
-#define c_auto2(C, a) \
- c_autovar2(C a = C##_init(), C##_drop(&a))
-#define c_auto3(C, a, b) \
- c_autovar2(c_expand(C a = C##_init(), b = C##_init()), \
- (C##_drop(&b), C##_drop(&a)))
-#define c_auto4(C, a, b, c) \
- c_autovar2(c_expand(C a = C##_init(), b = C##_init(), c = C##_init()), \
- (C##_drop(&c), C##_drop(&b), C##_drop(&a)))
-#define c_auto5(C, a, b, c, d) \
- c_autovar2(c_expand(C a = C##_init(), b = C##_init(), c = C##_init(), d = C##_init()), \
- (C##_drop(&d), C##_drop(&c), C##_drop(&b), C##_drop(&a)))
-
-#define c_autobuf(b, type, n) c_autobuf_N(b, type, n, 256)
-#define c_autobuf_N(b, type, n, BYTES) \
- for (type _c_b[((BYTES) - 1) / sizeof(type) + 1], \
- *b = (n)*sizeof *b > (BYTES) ? c_alloc_n(type, n) : _c_b \
- ; b; b != _c_b ? c_free(b) : (void)0, b = NULL)
-
-#define c_apply(v, action, T, ...) do { \
- typedef T _c_T; \
- const _c_T _c_arr[] = __VA_ARGS__, *v = _c_arr, \
- *_c_end = v + c_arraylen(_c_arr); \
- while (v != _c_end) { action; ++v; } \
-} while (0)
-
-#define c_apply_arr(v, action, T, arr, n) do { \
- typedef T _c_T; \
- _c_T *v = arr, *_c_end = v + (n); \
- while (v != _c_end) { action; ++v; } \
-} while (0)
-
-#define c_pair(v) (v)->first, (v)->second
-
-#define c_find_if(C, cnt, it, pred) \
- c_find_in(C, C##_begin(&cnt), C##_end(&cnt), it, pred)
-#define c_find_from(C, cnt, it, pred) \
- c_find_in(C, it, C##_end(&cnt), it, pred)
-// NB: it.ref == NULL when not found, not end.ref:
-#define c_find_in(C, start, end, it, pred) do { \
- size_t index = 0; \
- C##_iter _end = end; \
- for (it = start; it.ref != _end.ref && !(pred); C##_next(&it)) \
- ++index; \
- if (it.ref == _end.ref) it.ref = NULL; \
-} while (0)
-
-#define c_drop(C, ...) do { \
- C* _c_arr[] = {__VA_ARGS__}; \
- for (size_t _c_i = 0; _c_i < c_arraylen(_c_arr); ++_c_i) \
- C##_drop(_c_arr[_c_i]); \
-} while (0)
-
-#if defined(__SIZEOF_INT128__)
- #define c_umul128(a, b, lo, hi) \
- do { __uint128_t _z = (__uint128_t)(a)*(b); \
- *(lo) = (uint64_t)_z, *(hi) = _z >> 64; } while(0)
-#elif defined(_MSC_VER) && defined(_WIN64)
- #include <intrin.h>
- #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi)))
-#elif defined(__x86_64__)
- #define c_umul128(a, b, lo, hi) \
- asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b))
-#endif
-#endif // CCOMMON_H_INCLUDED
-
-#undef STC_API
-#undef STC_DEF
-
-#if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \
- defined(i_implement) || defined(STC_IMPLEMENT))
-# define STC_API extern
-# define STC_DEF
-#else
-# define i_static
-# define STC_API static inline
-# define STC_DEF static inline
-#endif
-#if defined(STC_EXTERN)
-# define i_extern
-#endif
-#if defined(i_static) || defined(STC_IMPLEMENT)
-# define i_implement
-#endif
+/* MIT License
+ *
+ * Copyright (c) 2022 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 CCOMMON_H_INCLUDED
+#define CCOMMON_H_INCLUDED
+
+#define _CRT_SECURE_NO_WARNINGS
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <string.h>
+#include <assert.h>
+
+#if defined(_MSC_VER)
+# pragma warning(disable: 4116 4996) // unnamed type definition in parentheses
+# define STC_FORCE_INLINE static __forceinline
+#elif defined(__GNUC__) || defined(__clang__)
+# define STC_FORCE_INLINE static inline __attribute((always_inline))
+#else
+# define STC_FORCE_INLINE static inline
+#endif
+#define STC_INLINE static inline
+
+/* Macro overloading feature support based on: https://rextester.com/ONP80107 */
+#define c_MACRO_OVERLOAD(name, ...) \
+ c_paste(name, c_numargs(__VA_ARGS__))(__VA_ARGS__)
+#define c_concat(a, b) a ## b
+#define c_paste(a, b) c_concat(a, b)
+#define c_expand(...) __VA_ARGS__
+#define c_numargs(...) _c_APPLY_ARG_N((__VA_ARGS__, _c_RSEQ_N))
+
+#define _c_APPLY_ARG_N(args) c_expand(_c_ARG_N args)
+#define _c_RSEQ_N 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+#define _c_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
+ _14, _15, _16, N, ...) N
+
+#define c_static_assert(cond) \
+ typedef char c_paste(_static_assert_line_, __LINE__)[(cond) ? 1 : -1]
+#define c_unchecked_container_of(ptr, type, member) \
+ ((type *)((char *)(ptr) - offsetof(type, member)))
+#if __STDC_VERSION__ >= 202300L || defined STC_CHECKED_CONTAINER_OF
+# define c_container_of(ptr, type, member) \
+ (((type *)((char *)(ptr) - offsetof(type, member))) + \
+ ((typeof(ptr))0 != (typeof(&((type *)0)->member))0))
+#else
+# define c_container_of(p,t,m) c_unchecked_container_of(p,t,m)
+#endif
+#ifndef __cplusplus
+# define c_alloc(T) c_malloc(sizeof(T))
+# define c_alloc_n(T, n) c_malloc(sizeof(T)*(n))
+# define c_make(T) (T)
+# define c_new(T, ...) (T*)memcpy(c_alloc(T), (T[]){__VA_ARGS__}, sizeof(T))
+#else
+# include <new>
+# define c_alloc(T) static_cast<T*>(c_malloc(sizeof(T)))
+# define c_alloc_n(T, n) static_cast<T*>(c_malloc(sizeof(T)*(n)))
+# define c_make(T) T
+# define c_new(T, ...) new (c_alloc(T)) T(__VA_ARGS__)
+#endif
+#ifndef c_malloc
+# define c_malloc(sz) malloc(sz)
+# define c_calloc(n, sz) calloc(n, sz)
+# define c_realloc(p, sz) realloc(p, sz)
+# define c_free(p) free(p)
+#endif
+
+#define c_delete(T, ptr) do { T *_c_p = ptr; T##_drop(_c_p); c_free(_c_p); } while (0)
+#define c_swap(T, x, y) do { T _c_t = x; x = y; y = _c_t; } while (0)
+#define c_arraylen(a) (sizeof (a)/sizeof *(a))
+
+// x and y are i_keyraw* type, defaults to i_key*:
+#define c_less_cmp(less, x, y) ((less((y), (x))) - (less((x), (y))))
+#define c_default_cmp(x, y) c_less_cmp(c_default_less, x, y)
+#define c_default_less(x, y) (*(x) < *(y))
+#define c_default_eq(x, y) (*(x) == *(y))
+#define c_memcmp_eq(x, y) (memcmp(x, y, sizeof *(x)) == 0)
+#define c_default_hash(x) c_fasthash(x, sizeof *(x))
+
+#define c_default_clone(v) (v)
+#define c_default_toraw(vp) (*(vp))
+#define c_default_drop(vp) ((void) (vp))
+#define c_derived_keyclone(v) i_keyfrom((i_keyto((&(v)))))
+#define c_derived_valclone(v) i_valfrom((i_valto((&(v)))))
+
+#define c_option(flag) ((i_opt) & (flag))
+#define c_is_fwd (1<<0)
+#define c_no_atomic (1<<1)
+#define c_no_clone (1<<2)
+#define c_no_cmp (1<<3)
+
+/* Generic algorithms */
+
+typedef const char* crawstr;
+#define crawstr_cmp(xp, yp) strcmp(*(xp), *(yp))
+#define crawstr_hash(p) c_strhash(*(p))
+#define c_strlen_lit(literal) (sizeof "" literal - 1U)
+#define c_sv(lit) c_make(csview){lit, c_strlen_lit(lit)}
+#define c_PRIsv ".*s"
+#define c_ARGsv(sv) (int)(sv).size, (sv).str
+
+#define _c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k)))
+
+STC_INLINE uint64_t c_fasthash(const void* key, size_t len) {
+ const uint8_t *x = (const uint8_t*) key;
+ uint64_t u8, h = 1; size_t n = len >> 3;
+ uint32_t u4;
+ while (n--) {
+ memcpy(&u8, x, 8), x += 8;
+ h += (_c_ROTL(u8, 26) ^ u8)*0xc6a4a7935bd1e99d;
+ }
+ switch (len &= 7) {
+ case 0: return h;
+ case 4: memcpy(&u4, x, 4);
+ return h + u4*0xc6a4a7935bd1e99d;
+ }
+ h += *x++;
+ while (--len) h = (h << 10) - h + *x++;
+ return _c_ROTL(h, 26) ^ h;
+}
+
+STC_INLINE uint64_t c_strhash(const char *str)
+ { return c_fasthash(str, strlen(str)); }
+
+STC_INLINE char* c_strnstrn(const char *s, const char *needle,
+ size_t slen, const 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;
+}
+
+#define c_foreach(...) c_MACRO_OVERLOAD(c_foreach, __VA_ARGS__)
+#define c_foreach3(it, C, cnt) \
+ for (C##_iter it = C##_begin(&cnt), it##_end_ = C##_end(&cnt) \
+ ; it.ref != it##_end_.ref; C##_next(&it))
+#define c_foreach4(it, C, start, finish) \
+ for (C##_iter it = start, it##_end_ = finish \
+ ; it.ref != it##_end_.ref; C##_next(&it))
+
+#define c_forpair(key, val, C, cnt) /* structured binding */ \
+ for (struct {C##_iter _it; C##_value* _endref; const C##_key* key; C##_mapped* val;} \
+ _ = {C##_begin(&cnt), C##_end(&cnt).ref} \
+ ; _._it.ref != _._endref && (_.key = &_._it.ref->first, _.val = &_._it.ref->second) \
+ ; C##_next(&_._it))
+
+#define c_forrange(...) c_MACRO_OVERLOAD(c_forrange, __VA_ARGS__)
+#define c_forrange1(stop) for (size_t _c_ii=0, _c_end=stop; _c_ii < _c_end; ++_c_ii)
+#define c_forrange2(i, stop) for (size_t i=0, _c_end=stop; i < _c_end; ++i)
+#define c_forrange3(i, type, stop) for (type i=0, _c_end=stop; i < _c_end; ++i)
+#define c_forrange4(i, type, start, stop) for (type i=start, _c_end=stop; i < _c_end; ++i)
+#define c_forrange5(i, type, start, stop, step) \
+ for (type i=start, _c_inc=step, _c_end=(stop) - (0 < _c_inc) \
+ ; (i <= _c_end) == (0 < _c_inc); i += _c_inc)
+
+#define c_autovar(...) c_MACRO_OVERLOAD(c_autovar, __VA_ARGS__)
+#define c_autovar2(declvar, drop) for (declvar, **_c_ii = NULL; !_c_ii; ++_c_ii, drop)
+#define c_autovar3(declvar, pred, drop) for (declvar, **_c_ii = NULL; !_c_ii && (pred); ++_c_ii, drop)
+#define c_autoscope(init, drop) for (int _c_ii = (init, 0); !_c_ii; ++_c_ii, drop)
+#define c_autodefer(...) for (int _c_ii = 0; !_c_ii; ++_c_ii, __VA_ARGS__)
+#define c_breakauto continue
+
+#define c_auto(...) c_MACRO_OVERLOAD(c_auto, __VA_ARGS__)
+#define c_auto2(C, a) \
+ c_autovar2(C a = C##_init(), C##_drop(&a))
+#define c_auto3(C, a, b) \
+ c_autovar2(c_expand(C a = C##_init(), b = C##_init()), \
+ (C##_drop(&b), C##_drop(&a)))
+#define c_auto4(C, a, b, c) \
+ c_autovar2(c_expand(C a = C##_init(), b = C##_init(), c = C##_init()), \
+ (C##_drop(&c), C##_drop(&b), C##_drop(&a)))
+#define c_auto5(C, a, b, c, d) \
+ c_autovar2(c_expand(C a = C##_init(), b = C##_init(), c = C##_init(), d = C##_init()), \
+ (C##_drop(&d), C##_drop(&c), C##_drop(&b), C##_drop(&a)))
+
+#define c_autobuf(b, type, n) c_autobuf_N(b, type, n, 256)
+#define c_autobuf_N(b, type, n, BYTES) \
+ for (type _c_b[((BYTES) - 1) / sizeof(type) + 1], \
+ *b = (n)*sizeof *b > (BYTES) ? c_alloc_n(type, n) : _c_b \
+ ; b; b != _c_b ? c_free(b) : (void)0, b = NULL)
+
+#define c_apply(v, action, T, ...) do { \
+ typedef T _c_T; \
+ const _c_T _c_arr[] = __VA_ARGS__, *v = _c_arr, \
+ *_c_end = v + c_arraylen(_c_arr); \
+ while (v != _c_end) { action; ++v; } \
+} while (0)
+
+#define c_apply_arr(v, action, T, arr, n) do { \
+ typedef T _c_T; \
+ _c_T *v = arr, *_c_end = v + (n); \
+ while (v != _c_end) { action; ++v; } \
+} while (0)
+
+#define c_pair(v) (v)->first, (v)->second
+
+#define c_find_if(C, cnt, it, pred) \
+ c_find_in(C, C##_begin(&cnt), C##_end(&cnt), it, pred)
+#define c_find_from(C, cnt, it, pred) \
+ c_find_in(C, it, C##_end(&cnt), it, pred)
+// NB: it.ref == NULL when not found, not end.ref:
+#define c_find_in(C, start, end, it, pred) do { \
+ size_t index = 0; \
+ C##_iter _end = end; \
+ for (it = start; it.ref != _end.ref && !(pred); C##_next(&it)) \
+ ++index; \
+ if (it.ref == _end.ref) it.ref = NULL; \
+} while (0)
+
+#define c_drop(C, ...) do { \
+ C* _c_arr[] = {__VA_ARGS__}; \
+ for (size_t _c_i = 0; _c_i < c_arraylen(_c_arr); ++_c_i) \
+ C##_drop(_c_arr[_c_i]); \
+} while (0)
+
+#if defined(__SIZEOF_INT128__)
+ #define c_umul128(a, b, lo, hi) \
+ do { __uint128_t _z = (__uint128_t)(a)*(b); \
+ *(lo) = (uint64_t)_z, *(hi) = _z >> 64; } while(0)
+#elif defined(_MSC_VER) && defined(_WIN64)
+ #include <intrin.h>
+ #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi)))
+#elif defined(__x86_64__)
+ #define c_umul128(a, b, lo, hi) \
+ asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b))
+#endif
+#endif // CCOMMON_H_INCLUDED
+
+#undef STC_API
+#undef STC_DEF
+
+#if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \
+ defined(i_implement) || defined(STC_IMPLEMENT))
+# define STC_API extern
+# define STC_DEF
+#else
+# define i_static
+# define STC_API static inline
+# define STC_DEF static inline
+#endif
+#if defined(STC_EXTERN)
+# define i_extern
+#endif
+#if defined(i_static) || defined(STC_IMPLEMENT)
+# define i_implement
+#endif
diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h
index b0198678..afe01165 100644
--- a/include/stc/cdeq.h
+++ b/include/stc/cdeq.h
@@ -1,437 +1,437 @@
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-#include "ccommon.h"
-
-#ifndef CDEQ_H_INCLUDED
-#include "forward.h"
-#include <stdlib.h>
-#include <string.h>
-
-struct cdeq_rep { size_t size, cap; unsigned base[1]; };
-#define cdeq_rep_(self) c_unchecked_container_of((self)->_base, struct cdeq_rep, base)
-#endif // CDEQ_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix cdeq_
-#endif
-#include "template.h"
-
-#if !c_option(c_is_fwd)
-_cx_deftypes(_c_cdeq_types, _cx_self, i_key);
-#endif
-typedef i_keyraw _cx_raw;
-
-STC_API _cx_self _cx_memb(_init)(void);
-STC_API _cx_self _cx_memb(_with_capacity)(const size_t n);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, const size_t n);
-STC_API void _cx_memb(_clear)(_cx_self* self);
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value);
-STC_API void _cx_memb(_shrink_to_fit)(_cx_self *self);
-#if !defined _i_queue
-#if !defined _i_no_clone
-STC_API _cx_value* _cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
-#if !defined _i_no_emplace
-STC_API _cx_value* _cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_raw* p1, const _cx_raw* p2);
-#endif // _i_no_emplace
-#endif // !_i_no_clone
-
-#if !c_option(c_no_cmp)
-STC_API _cx_iter _cx_memb(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw);
-STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y);
-#endif
-STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value);
-STC_API _cx_iter _cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2);
-STC_API _cx_value* _cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
-#endif // !_i_queue
-
-#if !defined _i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
-#if !defined _i_no_emplace
-STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-#endif
-STC_INLINE i_key _cx_memb(_value_clone)(i_key val)
- { return i_keyclone(val); }
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->data == other.data) return;
- _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other);
- }
-#endif // !_i_no_clone
-STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return cdeq_rep_(&cx)->size; }
-STC_INLINE size_t _cx_memb(_capacity)(_cx_self cx) { return cdeq_rep_(&cx)->cap; }
-STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return !cdeq_rep_(&cx)->size; }
-STC_INLINE _cx_raw _cx_memb(_value_toraw)(_cx_value* pval) { return i_keyto(pval); }
-STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); }
-STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->data; }
-STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self)
- { return self->data + cdeq_rep_(self)->size - 1; }
-STC_INLINE void _cx_memb(_pop_front)(_cx_self* self) // == _pop() when _i_queue
- { i_keydrop(self->data); ++self->data; --cdeq_rep_(self)->size; }
-STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self)
- { return c_make(_cx_iter){self->data}; }
-STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
- { return c_make(_cx_iter){self->data + cdeq_rep_(self)->size}; }
-STC_INLINE void _cx_memb(_next)(_cx_iter* it) { ++it->ref; }
-STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t offs)
- { it.ref += offs; return it; }
-
-#if !defined _i_queue
-
-STC_INLINE size_t _cx_memb(_index)(_cx_self cx, _cx_iter it)
- { return it.ref - cx.data; }
-STC_INLINE void _cx_memb(_pop_back)(_cx_self* self)
- { _cx_value* p = &self->data[--cdeq_rep_(self)->size]; i_keydrop(p); }
-
-STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, const size_t idx) {
- assert(idx < cdeq_rep_(self)->size); return self->data + idx;
-}
-STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, const size_t idx) {
- assert(idx < cdeq_rep_(self)->size); return self->data + idx;
-}
-
-STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value) {
- return _cx_memb(_push)(self, value);
-}
-STC_INLINE _cx_value*
-_cx_memb(_insert)(_cx_self* self, const size_t idx, i_key value) {
- return _cx_memb(_insert_range_p)(self, self->data + idx, &value, &value + 1);
-}
-STC_INLINE _cx_value*
-_cx_memb(_insert_n)(_cx_self* self, const size_t idx, const _cx_value arr[], const size_t n) {
- return _cx_memb(_insert_range_p)(self, self->data + idx, arr, arr + n);
-}
-STC_INLINE _cx_value*
-_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
- return _cx_memb(_insert_range_p)(self, it.ref, &value, &value + 1);
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_erase_n)(_cx_self* self, const size_t idx, const size_t n) {
- return _cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n);
-}
-STC_INLINE _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- return _cx_memb(_erase_range_p)(self, it.ref, it.ref + 1);
-}
-STC_INLINE _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
- return _cx_memb(_erase_range_p)(self, it1.ref, it2.ref);
-}
-
-#if !defined _i_no_clone && !defined _i_no_emplace
-STC_INLINE _cx_value*
-_cx_memb(_emplace_range)(_cx_self* self, _cx_iter it, _cx_iter it1, _cx_iter it2) {
- return _cx_memb(_clone_range_p)(self, it.ref, it1.ref, it2.ref);
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw) {
- return _cx_memb(_push_front)(self, i_keyfrom(raw));
-}
-
-STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) {
- return _cx_memb(_push)(self, i_keyfrom(raw));
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_emplace_n)(_cx_self* self, const size_t idx, const _cx_raw arr[], const size_t n) {
- return _cx_memb(_emplace_range_p)(self, self->data + idx, arr, arr + n);
-}
-STC_INLINE _cx_value*
-_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) {
- return _cx_memb(_emplace_range_p)(self, it.ref, &raw, &raw + 1);
-}
-#endif // !_i_no_clone && !_i_no_emplace
-
-#if !c_option(c_no_cmp)
-
-STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_raw raw) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw);
-}
-
-STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_raw raw) {
- _cx_iter end = _cx_memb(_end)(self);
- _cx_value* val = _cx_memb(_find_in)(_cx_memb(_begin)(self), end, raw).ref;
- return val == end.ref ? NULL : val;
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_get_mut)(_cx_self* self, _cx_raw raw)
- { return (_cx_value *) _cx_memb(_get)(self, raw); }
-
-STC_INLINE void
-_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2,
- int(*_cmp_)(const _cx_value*, const _cx_value*)) {
- qsort(i1.ref, i2.ref - i1.ref, sizeof *i1.ref, (int(*)(const void*, const void*)) _cmp_);
-}
-
-STC_INLINE void
-_cx_memb(_sort)(_cx_self* self) {
- _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp));
-}
-#endif // !c_no_cmp
-#endif // _i_queue
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-#ifndef CDEQ_H_INCLUDED
-static struct cdeq_rep _cdeq_sentinel = {0, 0};
-#define _cdeq_nfront(self) ((self)->data - (self)->_base)
-#endif
-
-STC_DEF _cx_self
-_cx_memb(_init)(void) {
- _cx_value *b = (_cx_value *) _cdeq_sentinel.base;
- return c_make(_cx_self){b, b};
-}
-
-STC_DEF void
-_cx_memb(_clear)(_cx_self* self) {
- struct cdeq_rep* rep = cdeq_rep_(self);
- if (rep->cap) {
- for (_cx_value *p = self->data, *q = p + rep->size; p != q; ) {
- --q; i_keydrop(q);
- }
- rep->size = 0;
- }
-}
-
-STC_DEF void
-_cx_memb(_shrink_to_fit)(_cx_self *self) {
- if (_cx_memb(_size)(*self) != _cx_memb(_capacity)(*self)) {
- struct cdeq_rep* rep = cdeq_rep_(self);
- const size_t sz = rep->size;
- memmove(self->_base, self->data, sz*sizeof(i_key));
- rep = (struct cdeq_rep*) c_realloc(rep, offsetof(struct cdeq_rep, base) + sz*sizeof(i_key));
- if (rep) {
- self->_base = self->data = (_cx_value*)rep->base;
- rep->cap = sz;
- }
- }
-}
-
-STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
- struct cdeq_rep* rep = cdeq_rep_(self);
- // second test to supress gcc -O2 warn: -Wfree-nonheap-object
- if (rep->cap == 0 || rep == &_cdeq_sentinel)
- return;
- _cx_memb(_clear)(self);
- c_free(rep);
-}
-
-static size_t
-_cx_memb(_realloc_)(_cx_self* self, const size_t n) {
- struct cdeq_rep* rep = cdeq_rep_(self);
- const size_t sz = rep->size, cap = (size_t) (sz*1.7) + n + 7;
- const size_t nfront = _cdeq_nfront(self);
- rep = (struct cdeq_rep*) c_realloc(rep->cap ? rep : NULL,
- offsetof(struct cdeq_rep, base) + cap*sizeof(i_key));
- if (!rep)
- return 0;
- rep->size = sz, rep->cap = cap;
- self->_base = (_cx_value *) rep->base;
- self->data = self->_base + nfront;
- return cap;
-}
-
-static bool
-_cx_memb(_expand_right_half_)(_cx_self* self, const size_t idx, const size_t n) {
- struct cdeq_rep* rep = cdeq_rep_(self);
- const size_t sz = rep->size, cap = rep->cap;
- const size_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront;
- if (nback >= n || sz*1.3 + n > cap) {
- if (!_cx_memb(_realloc_)(self, n))
- return false;
- memmove(self->data + idx + n, self->data + idx, (sz - idx)*sizeof(i_key));
- } else {
-#if !defined _i_queue
- const size_t unused = cap - (sz + n);
- const size_t pos = (nfront*2 < unused) ? nfront : unused/2;
-#else
- const size_t pos = 0;
-#endif
- memmove(self->_base + pos, self->data, idx*sizeof(i_key));
- memmove(self->data + pos + idx + n, self->data + idx, (sz - idx)*sizeof(i_key));
- self->data = self->_base + pos;
- }
- return true;
-}
-
-STC_DEF _cx_self
-_cx_memb(_with_capacity)(const size_t n) {
- _cx_self cx = _cx_memb(_init)();
- _cx_memb(_expand_right_half_)(&cx, 0, n);
- return cx;
-}
-
-STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const size_t n) {
- const size_t sz = cdeq_rep_(self)->size;
- return n <= sz || _cx_memb(_expand_right_half_)(self, sz, n - sz);
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push)(_cx_self* self, i_key value) {
- struct cdeq_rep* r = cdeq_rep_(self);
- if (_cdeq_nfront(self) + r->size == r->cap) {
- _cx_memb(_expand_right_half_)(self, r->size, 1);
- r = cdeq_rep_(self);
- }
- _cx_value *v = self->data + r->size++;
- *v = value; return v;
-}
-
-#if !c_option(c_no_clone)
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self cx) {
- const size_t sz = cdeq_rep_(&cx)->size;
- _cx_self out = _cx_memb(_with_capacity)(sz);
- if (cdeq_rep_(&out)->cap) {
- cdeq_rep_(&out)->size = sz;
- for (size_t i = 0; i < sz; ++i)
- out.data[i] = i_keyclone(cx.data[i]);
- }
- return out;
-}
-#endif
-
-#if !defined _i_queue
-
-static void
-_cx_memb(_expand_left_half_)(_cx_self* self, const size_t idx, const size_t n) {
- struct cdeq_rep* rep = cdeq_rep_(self);
- size_t cap = rep->cap;
- const size_t sz = rep->size;
- const size_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront;
- if (nfront >= n) {
- self->data = (_cx_value *)memmove(self->data - n, self->data, idx*sizeof(i_key));
- } else {
- if (sz*1.3 + n > cap)
- cap = _cx_memb(_realloc_)(self, n);
- const size_t unused = cap - (sz + n);
- const size_t pos = (nback*2 < unused) ? unused - nback : unused/2;
- memmove(self->_base + pos + idx + n, self->data + idx, (sz - idx)*sizeof(i_key));
- self->data = (_cx_value *)memmove(self->_base + pos, self->data, idx*sizeof(i_key));
- }
-}
-
-static _cx_value*
-_cx_memb(_expand_uninit_p)(_cx_self* self, const _cx_value* pos, const size_t n) {
- const 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*
-_cx_memb(_push_front)(_cx_self* self, i_key value) {
- if (self->data == self->_base)
- _cx_memb(_expand_left_half_)(self, 0, 1);
- else
- --self->data;
- ++cdeq_rep_(self)->size;
- *self->data = value;
- return self->data;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
- if (pos)
- memcpy(pos, p1, (p2 - p1)*sizeof *p1);
- return pos;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2) {
- const size_t n = p2 - p1;
- if (n > 0) {
- _cx_value* p = p1, *end = self->data + cdeq_rep_(self)->size;
- for (; p != p2; ++p) { i_keydrop(p); }
- if (p1 == self->data)
- self->data += n;
- else memmove(p1, p2, (end - p2) * sizeof(i_key));
- cdeq_rep_(self)->size -= n;
- }
- return c_make(_cx_iter){p1};
-}
-
-#if !defined _i_no_clone
-#if !defined _i_no_emplace
-STC_DEF _cx_value*
-_cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos, const _cx_raw* p1, const _cx_raw* p2) {
- pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
- _cx_value* it = pos;
- if (pos) for (; p1 != p2; ++p1)
- *pos++ = i_keyfrom((*p1));
- return it;
-}
-#endif // !_i_no_emplace
-
-STC_DEF _cx_value*
-_cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
- _cx_value* it = pos;
- if (pos) for (; p1 != p2; ++p1)
- *pos++ = i_keyclone((*p1));
- return it;
-}
-#endif // !_i_no_clone
-
-#if !c_option(c_no_cmp)
-
-STC_DEF _cx_iter
-_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
- for (; i1.ref != i2.ref; ++i1.ref) {
- _cx_raw r = i_keyto(i1.ref);
- if (i_eq((&raw), (&r)))
- return i1;
- }
- return i2;
-}
-
-STC_DEF int
-_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- const _cx_raw rx = i_keyto(x);
- const _cx_raw ry = i_keyto(y);
- return i_cmp((&rx), (&ry));
-}
-#endif // !c_no_cmp
-#endif // !_i_queue
-#endif // IMPLEMENTATION
-#include "template.h"
-#define CDEQ_H_INCLUDED
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+#include "ccommon.h"
+
+#ifndef CDEQ_H_INCLUDED
+#include "forward.h"
+#include <stdlib.h>
+#include <string.h>
+
+struct cdeq_rep { size_t size, cap; unsigned base[1]; };
+#define cdeq_rep_(self) c_unchecked_container_of((self)->_base, struct cdeq_rep, base)
+#endif // CDEQ_H_INCLUDED
+
+#ifndef _i_prefix
+#define _i_prefix cdeq_
+#endif
+#include "template.h"
+
+#if !c_option(c_is_fwd)
+_cx_deftypes(_c_cdeq_types, _cx_self, i_key);
+#endif
+typedef i_keyraw _cx_raw;
+
+STC_API _cx_self _cx_memb(_init)(void);
+STC_API _cx_self _cx_memb(_with_capacity)(const size_t n);
+STC_API bool _cx_memb(_reserve)(_cx_self* self, const size_t n);
+STC_API void _cx_memb(_clear)(_cx_self* self);
+STC_API void _cx_memb(_drop)(_cx_self* self);
+STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value);
+STC_API void _cx_memb(_shrink_to_fit)(_cx_self *self);
+#if !defined _i_queue
+#if !defined _i_no_clone
+STC_API _cx_value* _cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos,
+ const _cx_value* p1, const _cx_value* p2);
+#if !defined _i_no_emplace
+STC_API _cx_value* _cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos,
+ const _cx_raw* p1, const _cx_raw* p2);
+#endif // _i_no_emplace
+#endif // !_i_no_clone
+
+#if !c_option(c_no_cmp)
+STC_API _cx_iter _cx_memb(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw);
+STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y);
+#endif
+STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value);
+STC_API _cx_iter _cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2);
+STC_API _cx_value* _cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos,
+ const _cx_value* p1, const _cx_value* p2);
+#endif // !_i_queue
+
+#if !defined _i_no_clone
+STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
+#if !defined _i_no_emplace
+STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
+ { return _cx_memb(_push)(self, i_keyfrom(raw)); }
+#endif
+STC_INLINE i_key _cx_memb(_value_clone)(i_key val)
+ { return i_keyclone(val); }
+STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
+ if (self->data == other.data) return;
+ _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other);
+ }
+#endif // !_i_no_clone
+STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return cdeq_rep_(&cx)->size; }
+STC_INLINE size_t _cx_memb(_capacity)(_cx_self cx) { return cdeq_rep_(&cx)->cap; }
+STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return !cdeq_rep_(&cx)->size; }
+STC_INLINE _cx_raw _cx_memb(_value_toraw)(_cx_value* pval) { return i_keyto(pval); }
+STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); }
+STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->data; }
+STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self)
+ { return self->data + cdeq_rep_(self)->size - 1; }
+STC_INLINE void _cx_memb(_pop_front)(_cx_self* self) // == _pop() when _i_queue
+ { i_keydrop(self->data); ++self->data; --cdeq_rep_(self)->size; }
+STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self)
+ { return c_make(_cx_iter){self->data}; }
+STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
+ { return c_make(_cx_iter){self->data + cdeq_rep_(self)->size}; }
+STC_INLINE void _cx_memb(_next)(_cx_iter* it) { ++it->ref; }
+STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t offs)
+ { it.ref += offs; return it; }
+
+#if !defined _i_queue
+
+STC_INLINE size_t _cx_memb(_index)(_cx_self cx, _cx_iter it)
+ { return it.ref - cx.data; }
+STC_INLINE void _cx_memb(_pop_back)(_cx_self* self)
+ { _cx_value* p = &self->data[--cdeq_rep_(self)->size]; i_keydrop(p); }
+
+STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, const size_t idx) {
+ assert(idx < cdeq_rep_(self)->size); return self->data + idx;
+}
+STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, const size_t idx) {
+ assert(idx < cdeq_rep_(self)->size); return self->data + idx;
+}
+
+STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value) {
+ return _cx_memb(_push)(self, value);
+}
+STC_INLINE _cx_value*
+_cx_memb(_insert)(_cx_self* self, const size_t idx, i_key value) {
+ return _cx_memb(_insert_range_p)(self, self->data + idx, &value, &value + 1);
+}
+STC_INLINE _cx_value*
+_cx_memb(_insert_n)(_cx_self* self, const size_t idx, const _cx_value arr[], const size_t n) {
+ return _cx_memb(_insert_range_p)(self, self->data + idx, arr, arr + n);
+}
+STC_INLINE _cx_value*
+_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
+ return _cx_memb(_insert_range_p)(self, it.ref, &value, &value + 1);
+}
+
+STC_INLINE _cx_iter
+_cx_memb(_erase_n)(_cx_self* self, const size_t idx, const size_t n) {
+ return _cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n);
+}
+STC_INLINE _cx_iter
+_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
+ return _cx_memb(_erase_range_p)(self, it.ref, it.ref + 1);
+}
+STC_INLINE _cx_iter
+_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
+ return _cx_memb(_erase_range_p)(self, it1.ref, it2.ref);
+}
+
+#if !defined _i_no_clone && !defined _i_no_emplace
+STC_INLINE _cx_value*
+_cx_memb(_emplace_range)(_cx_self* self, _cx_iter it, _cx_iter it1, _cx_iter it2) {
+ return _cx_memb(_clone_range_p)(self, it.ref, it1.ref, it2.ref);
+}
+
+STC_INLINE _cx_value*
+_cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw) {
+ return _cx_memb(_push_front)(self, i_keyfrom(raw));
+}
+
+STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) {
+ return _cx_memb(_push)(self, i_keyfrom(raw));
+}
+
+STC_INLINE _cx_value*
+_cx_memb(_emplace_n)(_cx_self* self, const size_t idx, const _cx_raw arr[], const size_t n) {
+ return _cx_memb(_emplace_range_p)(self, self->data + idx, arr, arr + n);
+}
+STC_INLINE _cx_value*
+_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) {
+ return _cx_memb(_emplace_range_p)(self, it.ref, &raw, &raw + 1);
+}
+#endif // !_i_no_clone && !_i_no_emplace
+
+#if !c_option(c_no_cmp)
+
+STC_INLINE _cx_iter
+_cx_memb(_find)(const _cx_self* self, _cx_raw raw) {
+ return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw);
+}
+
+STC_INLINE const _cx_value*
+_cx_memb(_get)(const _cx_self* self, _cx_raw raw) {
+ _cx_iter end = _cx_memb(_end)(self);
+ _cx_value* val = _cx_memb(_find_in)(_cx_memb(_begin)(self), end, raw).ref;
+ return val == end.ref ? NULL : val;
+}
+
+STC_INLINE _cx_value*
+_cx_memb(_get_mut)(_cx_self* self, _cx_raw raw)
+ { return (_cx_value *) _cx_memb(_get)(self, raw); }
+
+STC_INLINE void
+_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2,
+ int(*_cmp_)(const _cx_value*, const _cx_value*)) {
+ qsort(i1.ref, i2.ref - i1.ref, sizeof *i1.ref, (int(*)(const void*, const void*)) _cmp_);
+}
+
+STC_INLINE void
+_cx_memb(_sort)(_cx_self* self) {
+ _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp));
+}
+#endif // !c_no_cmp
+#endif // _i_queue
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if defined(i_implement)
+
+#ifndef CDEQ_H_INCLUDED
+static struct cdeq_rep _cdeq_sentinel = {0, 0};
+#define _cdeq_nfront(self) ((self)->data - (self)->_base)
+#endif
+
+STC_DEF _cx_self
+_cx_memb(_init)(void) {
+ _cx_value *b = (_cx_value *) _cdeq_sentinel.base;
+ return c_make(_cx_self){b, b};
+}
+
+STC_DEF void
+_cx_memb(_clear)(_cx_self* self) {
+ struct cdeq_rep* rep = cdeq_rep_(self);
+ if (rep->cap) {
+ for (_cx_value *p = self->data, *q = p + rep->size; p != q; ) {
+ --q; i_keydrop(q);
+ }
+ rep->size = 0;
+ }
+}
+
+STC_DEF void
+_cx_memb(_shrink_to_fit)(_cx_self *self) {
+ if (_cx_memb(_size)(*self) != _cx_memb(_capacity)(*self)) {
+ struct cdeq_rep* rep = cdeq_rep_(self);
+ const size_t sz = rep->size;
+ memmove(self->_base, self->data, sz*sizeof(i_key));
+ rep = (struct cdeq_rep*) c_realloc(rep, offsetof(struct cdeq_rep, base) + sz*sizeof(i_key));
+ if (rep) {
+ self->_base = self->data = (_cx_value*)rep->base;
+ rep->cap = sz;
+ }
+ }
+}
+
+STC_DEF void
+_cx_memb(_drop)(_cx_self* self) {
+ struct cdeq_rep* rep = cdeq_rep_(self);
+ // second test to supress gcc -O2 warn: -Wfree-nonheap-object
+ if (rep->cap == 0 || rep == &_cdeq_sentinel)
+ return;
+ _cx_memb(_clear)(self);
+ c_free(rep);
+}
+
+static size_t
+_cx_memb(_realloc_)(_cx_self* self, const size_t n) {
+ struct cdeq_rep* rep = cdeq_rep_(self);
+ const size_t sz = rep->size, cap = (size_t) (sz*1.7) + n + 7;
+ const size_t nfront = _cdeq_nfront(self);
+ rep = (struct cdeq_rep*) c_realloc(rep->cap ? rep : NULL,
+ offsetof(struct cdeq_rep, base) + cap*sizeof(i_key));
+ if (!rep)
+ return 0;
+ rep->size = sz, rep->cap = cap;
+ self->_base = (_cx_value *) rep->base;
+ self->data = self->_base + nfront;
+ return cap;
+}
+
+static bool
+_cx_memb(_expand_right_half_)(_cx_self* self, const size_t idx, const size_t n) {
+ struct cdeq_rep* rep = cdeq_rep_(self);
+ const size_t sz = rep->size, cap = rep->cap;
+ const size_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront;
+ if (nback >= n || sz*1.3 + n > cap) {
+ if (!_cx_memb(_realloc_)(self, n))
+ return false;
+ memmove(self->data + idx + n, self->data + idx, (sz - idx)*sizeof(i_key));
+ } else {
+#if !defined _i_queue
+ const size_t unused = cap - (sz + n);
+ const size_t pos = (nfront*2 < unused) ? nfront : unused/2;
+#else
+ const size_t pos = 0;
+#endif
+ memmove(self->_base + pos, self->data, idx*sizeof(i_key));
+ memmove(self->data + pos + idx + n, self->data + idx, (sz - idx)*sizeof(i_key));
+ self->data = self->_base + pos;
+ }
+ return true;
+}
+
+STC_DEF _cx_self
+_cx_memb(_with_capacity)(const size_t n) {
+ _cx_self cx = _cx_memb(_init)();
+ _cx_memb(_expand_right_half_)(&cx, 0, n);
+ return cx;
+}
+
+STC_DEF bool
+_cx_memb(_reserve)(_cx_self* self, const size_t n) {
+ const size_t sz = cdeq_rep_(self)->size;
+ return n <= sz || _cx_memb(_expand_right_half_)(self, sz, n - sz);
+}
+
+STC_DEF _cx_value*
+_cx_memb(_push)(_cx_self* self, i_key value) {
+ struct cdeq_rep* r = cdeq_rep_(self);
+ if (_cdeq_nfront(self) + r->size == r->cap) {
+ _cx_memb(_expand_right_half_)(self, r->size, 1);
+ r = cdeq_rep_(self);
+ }
+ _cx_value *v = self->data + r->size++;
+ *v = value; return v;
+}
+
+#if !c_option(c_no_clone)
+STC_DEF _cx_self
+_cx_memb(_clone)(_cx_self cx) {
+ const size_t sz = cdeq_rep_(&cx)->size;
+ _cx_self out = _cx_memb(_with_capacity)(sz);
+ if (cdeq_rep_(&out)->cap) {
+ cdeq_rep_(&out)->size = sz;
+ for (size_t i = 0; i < sz; ++i)
+ out.data[i] = i_keyclone(cx.data[i]);
+ }
+ return out;
+}
+#endif
+
+#if !defined _i_queue
+
+static void
+_cx_memb(_expand_left_half_)(_cx_self* self, const size_t idx, const size_t n) {
+ struct cdeq_rep* rep = cdeq_rep_(self);
+ size_t cap = rep->cap;
+ const size_t sz = rep->size;
+ const size_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront;
+ if (nfront >= n) {
+ self->data = (_cx_value *)memmove(self->data - n, self->data, idx*sizeof(i_key));
+ } else {
+ if (sz*1.3 + n > cap)
+ cap = _cx_memb(_realloc_)(self, n);
+ const size_t unused = cap - (sz + n);
+ const size_t pos = (nback*2 < unused) ? unused - nback : unused/2;
+ memmove(self->_base + pos + idx + n, self->data + idx, (sz - idx)*sizeof(i_key));
+ self->data = (_cx_value *)memmove(self->_base + pos, self->data, idx*sizeof(i_key));
+ }
+}
+
+static _cx_value*
+_cx_memb(_expand_uninit_p)(_cx_self* self, const _cx_value* pos, const size_t n) {
+ const 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*
+_cx_memb(_push_front)(_cx_self* self, i_key value) {
+ if (self->data == self->_base)
+ _cx_memb(_expand_left_half_)(self, 0, 1);
+ else
+ --self->data;
+ ++cdeq_rep_(self)->size;
+ *self->data = value;
+ return self->data;
+}
+
+STC_DEF _cx_value*
+_cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos,
+ const _cx_value* p1, const _cx_value* p2) {
+ pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
+ if (pos)
+ memcpy(pos, p1, (p2 - p1)*sizeof *p1);
+ return pos;
+}
+
+STC_DEF _cx_iter
+_cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2) {
+ const size_t n = p2 - p1;
+ if (n > 0) {
+ _cx_value* p = p1, *end = self->data + cdeq_rep_(self)->size;
+ for (; p != p2; ++p) { i_keydrop(p); }
+ if (p1 == self->data)
+ self->data += n;
+ else memmove(p1, p2, (end - p2) * sizeof(i_key));
+ cdeq_rep_(self)->size -= n;
+ }
+ return c_make(_cx_iter){p1};
+}
+
+#if !defined _i_no_clone
+#if !defined _i_no_emplace
+STC_DEF _cx_value*
+_cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos, const _cx_raw* p1, const _cx_raw* p2) {
+ pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
+ _cx_value* it = pos;
+ if (pos) for (; p1 != p2; ++p1)
+ *pos++ = i_keyfrom((*p1));
+ return it;
+}
+#endif // !_i_no_emplace
+
+STC_DEF _cx_value*
+_cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos,
+ const _cx_value* p1, const _cx_value* p2) {
+ pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
+ _cx_value* it = pos;
+ if (pos) for (; p1 != p2; ++p1)
+ *pos++ = i_keyclone((*p1));
+ return it;
+}
+#endif // !_i_no_clone
+
+#if !c_option(c_no_cmp)
+
+STC_DEF _cx_iter
+_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
+ for (; i1.ref != i2.ref; ++i1.ref) {
+ _cx_raw r = i_keyto(i1.ref);
+ if (i_eq((&raw), (&r)))
+ return i1;
+ }
+ return i2;
+}
+
+STC_DEF int
+_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
+ const _cx_raw rx = i_keyto(x);
+ const _cx_raw ry = i_keyto(y);
+ return i_cmp((&rx), (&ry));
+}
+#endif // !c_no_cmp
+#endif // !_i_queue
+#endif // IMPLEMENTATION
+#include "template.h"
+#define CDEQ_H_INCLUDED
diff --git a/include/stc/clist.h b/include/stc/clist.h
index 9380dc11..29bf56f3 100644
--- a/include/stc/clist.h
+++ b/include/stc/clist.h
@@ -1,424 +1,424 @@
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-
-/* Circular Singly-linked Lists.
- This implements a std::forward_list-like class in C. Because it is circular,
- it also support both push_back() and push_front(), unlike std::forward_list:
-
- #include <stdio.h>
- #include <stc/crandom.h>
-
- #define i_key int64_t
- #define i_tag ix
- #include <stc/clist.h>
-
- int main()
- {
- c_auto (clist_ix, list)
- {
- int n;
- for (int i = 0; i < 1000000; ++i) // one million
- clist_ix_push_back(&list, crandom() >> 32);
- n = 0;
- c_foreach (i, clist_ix, list)
- if (++n % 10000 == 0) printf("%8d: %10zu\n", n, *i.ref);
- // 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: %10zu\n", n, *i.ref);
- }
- }
-*/
-#include "ccommon.h"
-
-#ifndef CLIST_H_INCLUDED
-#include "forward.h"
-#include <stdlib.h>
-#include <string.h>
-
-#define _c_clist_complete_types(SELF, dummy) \
- struct SELF##_node { \
- struct SELF##_node *next; \
- SELF##_value value; \
- }
-
-#define clist_node_(vp) c_unchecked_container_of(vp, _cx_node, value)
-
-_c_clist_types(clist_VOID, int);
-_c_clist_complete_types(clist_VOID, dummy);
-
-#define _c_clist_insert_after(self, _cx_self, node, val) \
- _cx_node *entry = c_alloc(_cx_node); \
- if (node) entry->next = node->next, node->next = entry; \
- else entry->next = entry; \
- entry->value = val
- // +: set self->last based on node
-
-#define _c_clist_insert_node_after(self, _cx_self, node, entry) \
- if (node) entry->next = node->next, node->next = entry; \
- else entry->next = entry
-
-#endif // CLIST_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix clist_
-#endif
-#include "template.h"
-
-#if !c_option(c_is_fwd)
- _cx_deftypes(_c_clist_types, _cx_self, i_key);
-#endif
-_cx_deftypes(_c_clist_complete_types, _cx_self, dummy);
-typedef i_keyraw _cx_raw;
-
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value);
-STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value);
-STC_API _cx_value* _cx_memb(_push_node_back)(_cx_self* self, _cx_node* node);
-STC_API _cx_value* _cx_memb(_push_node_front)(_cx_self* self, _cx_node* node);
-STC_API _cx_iter _cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value);
-STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it);
-STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2);
-#if !c_option(c_no_cmp)
-STC_API size_t _cx_memb(_remove)(_cx_self* self, _cx_raw val);
-STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val);
-STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y);
-STC_API int _cx_memb(_sort_cmp_)(const clist_VOID_node* x, const clist_VOID_node* y);
-#endif
-STC_API _cx_iter _cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other);
-STC_API _cx_self _cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2);
-STC_API _cx_node* _cx_memb(_erase_after_)(_cx_self* self, _cx_node* node);
-
-#if !defined _i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
-STC_INLINE i_key _cx_memb(_value_clone)(i_key val)
- { return i_keyclone(val); }
-STC_INLINE void
-_cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->last == other.last) return;
- _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other);
-}
-#if !defined _i_no_emplace
-STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push_back)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push_front)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_iter _cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw)
- { return _cx_memb(_insert_at)(self, it, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push_back)(self, i_keyfrom(raw)); }
-#endif // !_i_no_emplace
-#endif // !_i_no_clone
-
-STC_INLINE _cx_self _cx_memb(_init)(void) { return c_make(_cx_self){NULL}; }
-STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, size_t n) { return true; }
-STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return cx.last == NULL; }
-STC_INLINE void _cx_memb(_clear)(_cx_self* self) { _cx_memb(_drop)(self); }
-STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, i_key value)
- { return _cx_memb(_push_back)(self, value); }
-STC_INLINE void _cx_memb(_pop_front)(_cx_self* self)
- { _cx_memb(_erase_after_)(self, self->last); }
-STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return &self->last->next->value; }
-STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) { return &self->last->value; }
-
-STC_INLINE size_t
-_cx_memb(_count)(_cx_self cx) {
- size_t n = 1; const _cx_node *node = cx.last;
- if (!node) return 0;
- while ((node = node->next) != cx.last) ++n;
- return n;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_begin)(const _cx_self* self) {
- _cx_value* head = self->last ? &self->last->next->value : NULL;
- return c_make(_cx_iter){head, &self->last, self->last};
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_end)(const _cx_self* self) {
- return c_make(_cx_iter){NULL};
-}
-
-STC_INLINE void
-_cx_memb(_next)(_cx_iter* it) {
- _cx_node* node = it->prev = clist_node_(it->ref);
- it->ref = (node == *it->_last ? NULL : &node->next->value);
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_advance)(_cx_iter it, size_t n) {
- while (n-- && it.ref) _cx_memb(_next)(&it);
- return it;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_splice_range)(_cx_self* self, _cx_iter it,
- _cx_self* other, _cx_iter it1, _cx_iter it2) {
- _cx_self tmp = _cx_memb(_split_off)(other, it1, it2);
- return _cx_memb(_splice)(self, it, &tmp);
-}
-
-#if !c_option(c_no_cmp)
-STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_raw val) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val);
-}
-
-STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_raw val) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref;
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_get_mut)(_cx_self* self, _cx_raw val) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref;
-}
-
-STC_INLINE void
-_cx_memb(_sort)(_cx_self* self) {
- extern clist_VOID_node*
- _clist_mergesort(clist_VOID_node *list, int (*cmp)(const clist_VOID_node*, const clist_VOID_node*));
-
- if (self->last)
- self->last = (_cx_node *)_clist_mergesort((clist_VOID_node *)self->last->next, _cx_memb(_sort_cmp_));
-}
-#endif
-
-#if defined(i_extern)
-/* Implement non-templated extern functions */
-// Singly linked list Mergesort implementation by Simon Tatham. O(n*log n).
-// https://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
-clist_VOID_node *
-_clist_mergesort(clist_VOID_node *list, int (*cmp)(const clist_VOID_node*, const clist_VOID_node*)) {
- clist_VOID_node *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;
- }
-}
-#endif // i_extern
-
-// -------------------------- IMPLEMENTATION -------------------------
-#if defined(i_implement)
-
-#if !defined _i_no_clone
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self cx) {
- _cx_self out = _cx_memb(_init)();
- c_foreach (it, _cx_self, cx)
- _cx_memb(_push_back)(&out, i_keyclone((*it.ref)));
- return out;
-}
-#endif
-
-STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
- while (self->last) _cx_memb(_erase_after_)(self, self->last);
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push_back)(_cx_self* self, i_key value) {
- _c_clist_insert_after(self, _cx_self, self->last, value);
- self->last = entry;
- return &entry->value;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push_node_back)(_cx_self* self, _cx_node* entry) {
- _c_clist_insert_node_after(self, _cx_self, self->last, entry);
- self->last = entry;
- return &entry->value;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push_front)(_cx_self* self, i_key value) {
- _c_clist_insert_after(self, _cx_self, self->last, value);
- if (!self->last)
- self->last = entry;
- return &entry->value;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push_node_front)(_cx_self* self, _cx_node* entry) {
- _c_clist_insert_node_after(self, _cx_self, self->last, entry);
- if (!self->last)
- self->last = entry;
- return &entry->value;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
- _cx_node* node = it.ref ? it.prev : self->last;
- _c_clist_insert_after(self, _cx_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
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- _cx_node *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
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
- _cx_node *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_node*
-_cx_memb(_erase_after_)(_cx_self* self, _cx_node* node) {
- _cx_node* 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_keydrop((&del->value)); c_free(del);
- return node;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other) {
- if (!self->last)
- self->last = other->last;
- else if (other->last) {
- _cx_node *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_self
-_cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
- _cx_self cx = {NULL};
- if (it1.ref == it2.ref)
- return cx;
- _cx_node *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;
-}
-
-#if !c_option(c_no_cmp)
-
-STC_DEF _cx_iter
-_cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) {
- c_foreach (it, _cx_self, it1, it2) {
- _cx_raw r = i_keyto(it.ref);
- if (i_eq((&r), (&val)))
- return it;
- }
- it2.ref = NULL; return it2;
-}
-
-STC_DEF size_t
-_cx_memb(_remove)(_cx_self* self, _cx_raw val) {
- size_t n = 0;
- _cx_node* prev = self->last, *node;
- while (prev) {
- node = prev->next;
- _cx_raw r = i_keyto((&node->value));
- if (i_eq((&r), (&val)))
- prev = _cx_memb(_erase_after_)(self, prev), ++n;
- else
- prev = (node == self->last ? NULL : node);
- }
- return n;
-}
-
-STC_DEF int
-_cx_memb(_sort_cmp_)(const clist_VOID_node* x, const clist_VOID_node* y) {
- const _cx_raw a = i_keyto((&((const _cx_node *) x)->value));
- const _cx_raw b = i_keyto((&((const _cx_node *) y)->value));
- return i_cmp((&a), (&b));
-}
-
-STC_DEF int
-_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- const _cx_raw rx = i_keyto(x);
- const _cx_raw ry = i_keyto(y);
- return i_cmp((&rx), (&ry));
-}
-#endif // !c_no_cmp
-#endif // i_implement
-#define CLIST_H_INCLUDED
-#include "template.h"
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+
+/* Circular Singly-linked Lists.
+ This implements a std::forward_list-like class in C. Because it is circular,
+ it also support both push_back() and push_front(), unlike std::forward_list:
+
+ #include <stdio.h>
+ #include <stc/crandom.h>
+
+ #define i_key int64_t
+ #define i_tag ix
+ #include <stc/clist.h>
+
+ int main()
+ {
+ c_auto (clist_ix, list)
+ {
+ int n;
+ for (int i = 0; i < 1000000; ++i) // one million
+ clist_ix_push_back(&list, crandom() >> 32);
+ n = 0;
+ c_foreach (i, clist_ix, list)
+ if (++n % 10000 == 0) printf("%8d: %10zu\n", n, *i.ref);
+ // 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: %10zu\n", n, *i.ref);
+ }
+ }
+*/
+#include "ccommon.h"
+
+#ifndef CLIST_H_INCLUDED
+#include "forward.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define _c_clist_complete_types(SELF, dummy) \
+ struct SELF##_node { \
+ struct SELF##_node *next; \
+ SELF##_value value; \
+ }
+
+#define clist_node_(vp) c_unchecked_container_of(vp, _cx_node, value)
+
+_c_clist_types(clist_VOID, int);
+_c_clist_complete_types(clist_VOID, dummy);
+
+#define _c_clist_insert_after(self, _cx_self, node, val) \
+ _cx_node *entry = c_alloc(_cx_node); \
+ if (node) entry->next = node->next, node->next = entry; \
+ else entry->next = entry; \
+ entry->value = val
+ // +: set self->last based on node
+
+#define _c_clist_insert_node_after(self, _cx_self, node, entry) \
+ if (node) entry->next = node->next, node->next = entry; \
+ else entry->next = entry
+
+#endif // CLIST_H_INCLUDED
+
+#ifndef _i_prefix
+#define _i_prefix clist_
+#endif
+#include "template.h"
+
+#if !c_option(c_is_fwd)
+ _cx_deftypes(_c_clist_types, _cx_self, i_key);
+#endif
+_cx_deftypes(_c_clist_complete_types, _cx_self, dummy);
+typedef i_keyraw _cx_raw;
+
+STC_API void _cx_memb(_drop)(_cx_self* self);
+STC_API _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value);
+STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value);
+STC_API _cx_value* _cx_memb(_push_node_back)(_cx_self* self, _cx_node* node);
+STC_API _cx_value* _cx_memb(_push_node_front)(_cx_self* self, _cx_node* node);
+STC_API _cx_iter _cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value);
+STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it);
+STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2);
+#if !c_option(c_no_cmp)
+STC_API size_t _cx_memb(_remove)(_cx_self* self, _cx_raw val);
+STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val);
+STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y);
+STC_API int _cx_memb(_sort_cmp_)(const clist_VOID_node* x, const clist_VOID_node* y);
+#endif
+STC_API _cx_iter _cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other);
+STC_API _cx_self _cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2);
+STC_API _cx_node* _cx_memb(_erase_after_)(_cx_self* self, _cx_node* node);
+
+#if !defined _i_no_clone
+STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
+STC_INLINE i_key _cx_memb(_value_clone)(i_key val)
+ { return i_keyclone(val); }
+STC_INLINE void
+_cx_memb(_copy)(_cx_self *self, _cx_self other) {
+ if (self->last == other.last) return;
+ _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other);
+}
+#if !defined _i_no_emplace
+STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw)
+ { return _cx_memb(_push_back)(self, i_keyfrom(raw)); }
+STC_INLINE _cx_value* _cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw)
+ { return _cx_memb(_push_front)(self, i_keyfrom(raw)); }
+STC_INLINE _cx_iter _cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw)
+ { return _cx_memb(_insert_at)(self, it, i_keyfrom(raw)); }
+STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
+ { return _cx_memb(_push_back)(self, i_keyfrom(raw)); }
+#endif // !_i_no_emplace
+#endif // !_i_no_clone
+
+STC_INLINE _cx_self _cx_memb(_init)(void) { return c_make(_cx_self){NULL}; }
+STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, size_t n) { return true; }
+STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return cx.last == NULL; }
+STC_INLINE void _cx_memb(_clear)(_cx_self* self) { _cx_memb(_drop)(self); }
+STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, i_key value)
+ { return _cx_memb(_push_back)(self, value); }
+STC_INLINE void _cx_memb(_pop_front)(_cx_self* self)
+ { _cx_memb(_erase_after_)(self, self->last); }
+STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return &self->last->next->value; }
+STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) { return &self->last->value; }
+
+STC_INLINE size_t
+_cx_memb(_count)(_cx_self cx) {
+ size_t n = 1; const _cx_node *node = cx.last;
+ if (!node) return 0;
+ while ((node = node->next) != cx.last) ++n;
+ return n;
+}
+
+STC_INLINE _cx_iter
+_cx_memb(_begin)(const _cx_self* self) {
+ _cx_value* head = self->last ? &self->last->next->value : NULL;
+ return c_make(_cx_iter){head, &self->last, self->last};
+}
+
+STC_INLINE _cx_iter
+_cx_memb(_end)(const _cx_self* self) {
+ return c_make(_cx_iter){NULL};
+}
+
+STC_INLINE void
+_cx_memb(_next)(_cx_iter* it) {
+ _cx_node* node = it->prev = clist_node_(it->ref);
+ it->ref = (node == *it->_last ? NULL : &node->next->value);
+}
+
+STC_INLINE _cx_iter
+_cx_memb(_advance)(_cx_iter it, size_t n) {
+ while (n-- && it.ref) _cx_memb(_next)(&it);
+ return it;
+}
+
+STC_INLINE _cx_iter
+_cx_memb(_splice_range)(_cx_self* self, _cx_iter it,
+ _cx_self* other, _cx_iter it1, _cx_iter it2) {
+ _cx_self tmp = _cx_memb(_split_off)(other, it1, it2);
+ return _cx_memb(_splice)(self, it, &tmp);
+}
+
+#if !c_option(c_no_cmp)
+STC_INLINE _cx_iter
+_cx_memb(_find)(const _cx_self* self, _cx_raw val) {
+ return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val);
+}
+
+STC_INLINE const _cx_value*
+_cx_memb(_get)(const _cx_self* self, _cx_raw val) {
+ return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref;
+}
+
+STC_INLINE _cx_value*
+_cx_memb(_get_mut)(_cx_self* self, _cx_raw val) {
+ return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref;
+}
+
+STC_INLINE void
+_cx_memb(_sort)(_cx_self* self) {
+ extern clist_VOID_node*
+ _clist_mergesort(clist_VOID_node *list, int (*cmp)(const clist_VOID_node*, const clist_VOID_node*));
+
+ if (self->last)
+ self->last = (_cx_node *)_clist_mergesort((clist_VOID_node *)self->last->next, _cx_memb(_sort_cmp_));
+}
+#endif
+
+#if defined(i_extern)
+/* Implement non-templated extern functions */
+// Singly linked list Mergesort implementation by Simon Tatham. O(n*log n).
+// https://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
+clist_VOID_node *
+_clist_mergesort(clist_VOID_node *list, int (*cmp)(const clist_VOID_node*, const clist_VOID_node*)) {
+ clist_VOID_node *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;
+ }
+}
+#endif // i_extern
+
+// -------------------------- IMPLEMENTATION -------------------------
+#if defined(i_implement)
+
+#if !defined _i_no_clone
+STC_DEF _cx_self
+_cx_memb(_clone)(_cx_self cx) {
+ _cx_self out = _cx_memb(_init)();
+ c_foreach (it, _cx_self, cx)
+ _cx_memb(_push_back)(&out, i_keyclone((*it.ref)));
+ return out;
+}
+#endif
+
+STC_DEF void
+_cx_memb(_drop)(_cx_self* self) {
+ while (self->last) _cx_memb(_erase_after_)(self, self->last);
+}
+
+STC_DEF _cx_value*
+_cx_memb(_push_back)(_cx_self* self, i_key value) {
+ _c_clist_insert_after(self, _cx_self, self->last, value);
+ self->last = entry;
+ return &entry->value;
+}
+
+STC_DEF _cx_value*
+_cx_memb(_push_node_back)(_cx_self* self, _cx_node* entry) {
+ _c_clist_insert_node_after(self, _cx_self, self->last, entry);
+ self->last = entry;
+ return &entry->value;
+}
+
+STC_DEF _cx_value*
+_cx_memb(_push_front)(_cx_self* self, i_key value) {
+ _c_clist_insert_after(self, _cx_self, self->last, value);
+ if (!self->last)
+ self->last = entry;
+ return &entry->value;
+}
+
+STC_DEF _cx_value*
+_cx_memb(_push_node_front)(_cx_self* self, _cx_node* entry) {
+ _c_clist_insert_node_after(self, _cx_self, self->last, entry);
+ if (!self->last)
+ self->last = entry;
+ return &entry->value;
+}
+
+STC_DEF _cx_iter
+_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
+ _cx_node* node = it.ref ? it.prev : self->last;
+ _c_clist_insert_after(self, _cx_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
+_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
+ _cx_node *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
+_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
+ _cx_node *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_node*
+_cx_memb(_erase_after_)(_cx_self* self, _cx_node* node) {
+ _cx_node* 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_keydrop((&del->value)); c_free(del);
+ return node;
+}
+
+STC_DEF _cx_iter
+_cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other) {
+ if (!self->last)
+ self->last = other->last;
+ else if (other->last) {
+ _cx_node *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_self
+_cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
+ _cx_self cx = {NULL};
+ if (it1.ref == it2.ref)
+ return cx;
+ _cx_node *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;
+}
+
+#if !c_option(c_no_cmp)
+
+STC_DEF _cx_iter
+_cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) {
+ c_foreach (it, _cx_self, it1, it2) {
+ _cx_raw r = i_keyto(it.ref);
+ if (i_eq((&r), (&val)))
+ return it;
+ }
+ it2.ref = NULL; return it2;
+}
+
+STC_DEF size_t
+_cx_memb(_remove)(_cx_self* self, _cx_raw val) {
+ size_t n = 0;
+ _cx_node* prev = self->last, *node;
+ while (prev) {
+ node = prev->next;
+ _cx_raw r = i_keyto((&node->value));
+ if (i_eq((&r), (&val)))
+ prev = _cx_memb(_erase_after_)(self, prev), ++n;
+ else
+ prev = (node == self->last ? NULL : node);
+ }
+ return n;
+}
+
+STC_DEF int
+_cx_memb(_sort_cmp_)(const clist_VOID_node* x, const clist_VOID_node* y) {
+ const _cx_raw a = i_keyto((&((const _cx_node *) x)->value));
+ const _cx_raw b = i_keyto((&((const _cx_node *) y)->value));
+ return i_cmp((&a), (&b));
+}
+
+STC_DEF int
+_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
+ const _cx_raw rx = i_keyto(x);
+ const _cx_raw ry = i_keyto(y);
+ return i_cmp((&rx), (&ry));
+}
+#endif // !c_no_cmp
+#endif // i_implement
+#define CLIST_H_INCLUDED
+#include "template.h"
diff --git a/include/stc/cmap.h b/include/stc/cmap.h
index eabd5f1c..e193a8d0 100644
--- a/include/stc/cmap.h
+++ b/include/stc/cmap.h
@@ -1,423 +1,423 @@
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-
-// Unordered set/map - implemented as closed hashing with linear probing and no tombstones.
-/*
-#include <stdio.h>
-
-#define i_tag ichar // Map int => char
-#define i_key int
-#define i_val char
-#include <stc/cmap.h>
-
-int main(void) {
- c_autovar (cmap_ichar m = cmap_ichar_init(), cmap_ichar_drop(&m))
- {
- cmap_ichar_emplace(&m, 5, 'a');
- cmap_ichar_emplace(&m, 8, 'b');
- cmap_ichar_emplace(&m, 12, 'c');
-
- cmap_ichar_value* 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_ichar, m)
- printf("map %d: %c\n", i.ref->first, i.ref->second);
- }
-}
-*/
-#include "ccommon.h"
-
-#ifndef CMAP_H_INCLUDED
-#include "forward.h"
-#include <stdlib.h>
-#include <string.h>
-#define _cmap_inits {NULL, NULL, 0, 0, 0.85f}
-typedef struct { size_t idx; uint8_t hx; } chash_bucket_t;
-#endif // CMAP_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix cmap_
-#endif
-#ifdef _i_isset
- #define _i_MAP_ONLY c_false
- #define _i_SET_ONLY c_true
- #define _i_keyref(vp) (vp)
-#else
- #define _i_ismap
- #define _i_MAP_ONLY c_true
- #define _i_SET_ONLY c_false
- #define _i_keyref(vp) (&(vp)->first)
-#endif
-#define _i_ishash
-#include "template.h"
-#if !c_option(c_is_fwd)
- _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_size, _i_MAP_ONLY, _i_SET_ONLY);
-#endif
-
-_i_MAP_ONLY( struct _cx_value {
- _cx_key first;
- _cx_mapped second;
-}; )
-
-typedef i_keyraw _cx_rawkey;
-typedef i_valraw _cx_memb(_rawmapped);
-typedef _i_SET_ONLY( i_keyraw )
- _i_MAP_ONLY( struct { i_keyraw first;
- i_valraw second; } )
-_cx_raw;
-
-STC_API _cx_self _cx_memb(_with_capacity)(size_t cap);
-#if !defined _i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self map);
-#endif
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API void _cx_memb(_clear)(_cx_self* self);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, size_t capacity);
-STC_API chash_bucket_t _cx_memb(_bucket_)(const _cx_self* self, const _cx_rawkey* rkeyptr);
-STC_API _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey);
-STC_API void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* val);
-
-STC_INLINE _cx_self _cx_memb(_init)(void) { return c_make(_cx_self)_cmap_inits; }
-STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) { _cx_memb(_reserve)(self, self->size); }
-STC_INLINE void _cx_memb(_max_load_factor)(_cx_self* self, float ml) {self->max_load_factor = ml; }
-STC_INLINE bool _cx_memb(_empty)(_cx_self m) { return m.size == 0; }
-STC_INLINE size_t _cx_memb(_size)(_cx_self m) { return m.size; }
-STC_INLINE size_t _cx_memb(_bucket_count)(_cx_self map) { return map.bucket_count; }
-STC_INLINE size_t _cx_memb(_capacity)(_cx_self map)
- { return map.bucket_count ? (size_t)((map.bucket_count - 2)*map.max_load_factor) : 0u; }
-STC_INLINE void _cx_memb(_swap)(_cx_self *map1, _cx_self *map2) {c_swap(_cx_self, *map1, *map2); }
-STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_rawkey rkey)
- { return self->size && self->_hashx[_cx_memb(_bucket_)(self, &rkey).idx]; }
-
-#ifndef _i_isset
- STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped);
- #if !defined _i_no_clone && !defined _i_no_emplace
- STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped);
- #endif
-
- STC_INLINE const _cx_mapped*
- _cx_memb(_at)(const _cx_self* self, _cx_rawkey rkey) {
- chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey);
- assert(self->_hashx[b.idx]);
- return &self->table[b.idx].second;
- }
- STC_INLINE _cx_mapped*
- _cx_memb(_at_mut)(_cx_self* self, _cx_rawkey rkey)
- { return (_cx_mapped*)_cx_memb(_at)(self, rkey); }
-#endif // !_i_isset
-
-#if !defined _i_no_clone
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->table == other.table)
- return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(other);
-}
-
-STC_INLINE _cx_value
-_cx_memb(_value_clone)(_cx_value _val) {
- *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val)));
- _i_MAP_ONLY( _val.second = i_valclone(_val.second); )
- return _val;
-}
-
-#if !defined _i_no_emplace
-STC_INLINE _cx_result
-_cx_memb(_emplace)(_cx_self* self, _cx_rawkey rkey _i_MAP_ONLY(, i_valraw rmapped)) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, rkey);
- if (_res.inserted) {
- *_i_keyref(_res.ref) = i_keyfrom(rkey);
- _i_MAP_ONLY( _res.ref->second = i_valfrom(rmapped); )
- }
- return _res;
-}
-#endif // !_i_no_emplace
-#endif // !_i_no_clone
-
-STC_INLINE _cx_raw
-_cx_memb(_value_toraw)(_cx_value* val) {
- return _i_SET_ONLY( i_keyto(val) )
- _i_MAP_ONLY( c_make(_cx_raw){i_keyto((&val->first)), i_valto((&val->second))} );
-}
-
-STC_INLINE void
-_cx_memb(_value_drop)(_cx_value* _val) {
- i_keydrop(_i_keyref(_val));
- _i_MAP_ONLY( i_valdrop((&_val->second)); )
-}
-
-STC_INLINE _cx_result
-_cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key)));
- if (_res.inserted)
- { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )}
- else
- { i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )}
- return _res;
-}
-
-STC_INLINE _cx_result
-_cx_memb(_push)(_cx_self* self, _cx_value _val) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
- if (_res.inserted)
- *_res.ref = _val;
- else
- _cx_memb(_value_drop)(&_val);
- return _res;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_rawkey rkey) {
- i_size idx;
- if (!(self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx]))
- idx = self->bucket_count;
- return c_make(_cx_iter){self->table+idx, self->_hashx+idx};
-}
-
-STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_rawkey rkey) {
- i_size idx;
- if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx])
- return self->table + idx;
- return NULL;
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_get_mut)(const _cx_self* self, _cx_rawkey rkey)
- { return (_cx_value*)_cx_memb(_get)(self, rkey); }
-
-STC_INLINE _cx_iter
-_cx_memb(_begin)(const _cx_self* self) {
- _cx_iter it = {self->table, self->_hashx};
- if (it._hx)
- while (*it._hx == 0)
- ++it.ref, ++it._hx;
- return it;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_end)(const _cx_self* self)
- { return c_make(_cx_iter){self->table + self->bucket_count}; }
-
-STC_INLINE void
-_cx_memb(_next)(_cx_iter* it)
- { while ((++it->ref, *++it->_hx == 0)) ; }
-
-STC_INLINE _cx_iter
-_cx_memb(_advance)(_cx_iter it, size_t n) {
- // UB if n > elements left
- while (n--) _cx_memb(_next)(&it);
- return it;
-}
-
-STC_INLINE size_t
-_cx_memb(_erase)(_cx_self* self, _cx_rawkey 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
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- _cx_memb(_erase_entry)(self, it.ref);
- if (*it._hx == 0)
- _cx_memb(_next)(&it);
- return it;
-}
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-#ifndef CMAP_H_INCLUDED
-STC_INLINE size_t fastrange_size_t(uint64_t x, uint64_t n)
- { uint64_t lo, hi; c_umul128(x, n, &lo, &hi); return (size_t)hi; }
-STC_INLINE size_t fastrange_uint32_t(uint64_t x, uint64_t n)
- { return (size_t)((uint32_t)x*n >> 32); }
-#endif // CMAP_H_INCLUDED
-
-STC_DEF _cx_self
-_cx_memb(_with_capacity)(const size_t cap) {
- _cx_self h = _cmap_inits;
- _cx_memb(_reserve)(&h, cap);
- return h;
-}
-
-STC_INLINE void _cx_memb(_wipe_)(_cx_self* self) {
- if (self->size == 0)
- return;
- _cx_value* e = self->table, *end = e + self->bucket_count;
- uint8_t *hx = self->_hashx;
- for (; e != end; ++e)
- if (*hx++)
- _cx_memb(_value_drop)(e);
-}
-
-STC_DEF void _cx_memb(_drop)(_cx_self* self) {
- _cx_memb(_wipe_)(self);
- c_free(self->_hashx);
- c_free((void *) self->table);
-}
-
-STC_DEF void _cx_memb(_clear)(_cx_self* self) {
- _cx_memb(_wipe_)(self);
- self->size = 0;
- memset(self->_hashx, 0, self->bucket_count);
-}
-
-#ifndef _i_isset
- STC_DEF _cx_result
- _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key)));
- if (_res.inserted)
- _res.ref->first = _key;
- else
- { i_keydrop((&_key)); i_valdrop((&_res.ref->second)); }
- _res.ref->second = _mapped;
- return _res;
- }
-
- #if !defined _i_no_clone && !defined _i_no_emplace
- STC_DEF _cx_result
- _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, rkey);
- if (_res.inserted)
- _res.ref->first = i_keyfrom(rkey);
- else
- { i_valdrop((&_res.ref->second)); }
- _res.ref->second = i_valfrom(rmapped);
- return _res;
- }
- #endif // !_i_no_clone && !_i_no_emplace
-#endif // !_i_isset
-
-STC_DEF chash_bucket_t
-_cx_memb(_bucket_)(const _cx_self* self, const _cx_rawkey* rkeyptr) {
- const uint64_t _hash = i_hash(rkeyptr);
- i_size _cap = self->bucket_count;
- chash_bucket_t b = {c_paste(fastrange_,i_size)(_hash, _cap), (uint8_t)(_hash | 0x80)};
- const uint8_t* _hx = self->_hashx;
- while (_hx[b.idx]) {
- if (_hx[b.idx] == b.hx) {
- const _cx_rawkey _raw = i_keyto(_i_keyref(self->table + b.idx));
- if (i_eq((&_raw), rkeyptr))
- break;
- }
- if (++b.idx == _cap)
- b.idx = 0;
- }
- return b;
-}
-
-STC_DEF _cx_result
-_cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey) {
- bool nomem = false;
- if (self->size + 1 >= (i_size)(self->bucket_count*self->max_load_factor))
- nomem = !_cx_memb(_reserve)(self, ((size_t)self->size*3 >> 1) + 4);
- chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey);
- _cx_result res = {&self->table[b.idx], !self->_hashx[b.idx], nomem};
- if (res.inserted) {
- self->_hashx[b.idx] = b.hx;
- ++self->size;
- }
- return res;
-}
-
-#if !defined _i_no_clone
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self m) {
- _cx_value *t = c_alloc_n(_cx_value, m.bucket_count), *dst = t, *m_end = m.table + m.bucket_count;
- uint8_t *h = (uint8_t *)memcpy(c_malloc(m.bucket_count + 1), m._hashx, m.bucket_count + 1);
- if (!(t && h))
- { c_free(t), c_free(h), t = 0, h = 0, m.bucket_count = 0; }
- else
- for (; m.table != m_end; ++m.table, ++m._hashx, ++dst)
- if (*m._hashx)
- *dst = _cx_memb(_value_clone)(*m.table);
- m.table = t, m._hashx = h;
- return m;
-}
-#endif
-
-STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const size_t _newcap) {
- const i_size _oldbuckets = self->bucket_count;
- const i_size _nbuckets = ((i_size)(_newcap/self->max_load_factor) + 2) | 1;
- if (_newcap != self->size && _newcap <= _oldbuckets)
- return true;
- _cx_self m = {
- c_alloc_n(_cx_value, _nbuckets),
- (uint8_t *) c_calloc(_nbuckets + 1, 1),
- self->size, (i_size)_nbuckets,
- self->max_load_factor
- };
- bool ok = m.table && m._hashx;
- if (ok) { /* Rehash: */
- m._hashx[_nbuckets] = 0xff;
- const _cx_value* e = self->table;
- const uint8_t* h = self->_hashx;
- for (size_t i = 0; i < _oldbuckets; ++i, ++e) if (*h++) {
- _cx_rawkey r = i_keyto(_i_keyref(e));
- chash_bucket_t b = _cx_memb(_bucket_)(&m, &r);
- m.table[b.idx] = *e;
- m._hashx[b.idx] = (uint8_t)b.hx;
- }
- c_swap(_cx_self, *self, m);
- }
- c_free(m._hashx);
- c_free(m.table);
- return ok;
-}
-
-STC_DEF void
-_cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) {
- i_size i = _val - self->table, j = i, k;
- const i_size _cap = self->bucket_count;
- _cx_value* _slot = self->table;
- uint8_t* _hashx = self->_hashx;
- _cx_memb(_value_drop)(_val);
- for (;;) { /* delete without leaving tombstone */
- if (++j == _cap)
- j = 0;
- if (! _hashx[j])
- break;
- const _cx_rawkey _raw = i_keyto(_i_keyref(_slot + j));
- k = c_paste(fastrange_,i_size)(i_hash((&_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 // i_implement
-#undef _i_isset
-#undef _i_ismap
-#undef _i_ishash
-#undef _i_keyref
-#undef _i_MAP_ONLY
-#undef _i_SET_ONLY
-#define CMAP_H_INCLUDED
-#include "template.h"
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+
+// Unordered set/map - implemented as closed hashing with linear probing and no tombstones.
+/*
+#include <stdio.h>
+
+#define i_tag ichar // Map int => char
+#define i_key int
+#define i_val char
+#include <stc/cmap.h>
+
+int main(void) {
+ c_autovar (cmap_ichar m = cmap_ichar_init(), cmap_ichar_drop(&m))
+ {
+ cmap_ichar_emplace(&m, 5, 'a');
+ cmap_ichar_emplace(&m, 8, 'b');
+ cmap_ichar_emplace(&m, 12, 'c');
+
+ cmap_ichar_value* 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_ichar, m)
+ printf("map %d: %c\n", i.ref->first, i.ref->second);
+ }
+}
+*/
+#include "ccommon.h"
+
+#ifndef CMAP_H_INCLUDED
+#include "forward.h"
+#include <stdlib.h>
+#include <string.h>
+#define _cmap_inits {NULL, NULL, 0, 0, 0.85f}
+typedef struct { size_t idx; uint8_t hx; } chash_bucket_t;
+#endif // CMAP_H_INCLUDED
+
+#ifndef _i_prefix
+#define _i_prefix cmap_
+#endif
+#ifdef _i_isset
+ #define _i_MAP_ONLY c_false
+ #define _i_SET_ONLY c_true
+ #define _i_keyref(vp) (vp)
+#else
+ #define _i_ismap
+ #define _i_MAP_ONLY c_true
+ #define _i_SET_ONLY c_false
+ #define _i_keyref(vp) (&(vp)->first)
+#endif
+#define _i_ishash
+#include "template.h"
+#if !c_option(c_is_fwd)
+ _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_size, _i_MAP_ONLY, _i_SET_ONLY);
+#endif
+
+_i_MAP_ONLY( struct _cx_value {
+ _cx_key first;
+ _cx_mapped second;
+}; )
+
+typedef i_keyraw _cx_rawkey;
+typedef i_valraw _cx_memb(_rawmapped);
+typedef _i_SET_ONLY( i_keyraw )
+ _i_MAP_ONLY( struct { i_keyraw first;
+ i_valraw second; } )
+_cx_raw;
+
+STC_API _cx_self _cx_memb(_with_capacity)(size_t cap);
+#if !defined _i_no_clone
+STC_API _cx_self _cx_memb(_clone)(_cx_self map);
+#endif
+STC_API void _cx_memb(_drop)(_cx_self* self);
+STC_API void _cx_memb(_clear)(_cx_self* self);
+STC_API bool _cx_memb(_reserve)(_cx_self* self, size_t capacity);
+STC_API chash_bucket_t _cx_memb(_bucket_)(const _cx_self* self, const _cx_rawkey* rkeyptr);
+STC_API _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey);
+STC_API void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* val);
+
+STC_INLINE _cx_self _cx_memb(_init)(void) { return c_make(_cx_self)_cmap_inits; }
+STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) { _cx_memb(_reserve)(self, self->size); }
+STC_INLINE void _cx_memb(_max_load_factor)(_cx_self* self, float ml) {self->max_load_factor = ml; }
+STC_INLINE bool _cx_memb(_empty)(_cx_self m) { return m.size == 0; }
+STC_INLINE size_t _cx_memb(_size)(_cx_self m) { return m.size; }
+STC_INLINE size_t _cx_memb(_bucket_count)(_cx_self map) { return map.bucket_count; }
+STC_INLINE size_t _cx_memb(_capacity)(_cx_self map)
+ { return map.bucket_count ? (size_t)((map.bucket_count - 2)*map.max_load_factor) : 0u; }
+STC_INLINE void _cx_memb(_swap)(_cx_self *map1, _cx_self *map2) {c_swap(_cx_self, *map1, *map2); }
+STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_rawkey rkey)
+ { return self->size && self->_hashx[_cx_memb(_bucket_)(self, &rkey).idx]; }
+
+#ifndef _i_isset
+ STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped);
+ #if !defined _i_no_clone && !defined _i_no_emplace
+ STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped);
+ #endif
+
+ STC_INLINE const _cx_mapped*
+ _cx_memb(_at)(const _cx_self* self, _cx_rawkey rkey) {
+ chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey);
+ assert(self->_hashx[b.idx]);
+ return &self->table[b.idx].second;
+ }
+ STC_INLINE _cx_mapped*
+ _cx_memb(_at_mut)(_cx_self* self, _cx_rawkey rkey)
+ { return (_cx_mapped*)_cx_memb(_at)(self, rkey); }
+#endif // !_i_isset
+
+#if !defined _i_no_clone
+STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
+ if (self->table == other.table)
+ return;
+ _cx_memb(_drop)(self);
+ *self = _cx_memb(_clone)(other);
+}
+
+STC_INLINE _cx_value
+_cx_memb(_value_clone)(_cx_value _val) {
+ *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val)));
+ _i_MAP_ONLY( _val.second = i_valclone(_val.second); )
+ return _val;
+}
+
+#if !defined _i_no_emplace
+STC_INLINE _cx_result
+_cx_memb(_emplace)(_cx_self* self, _cx_rawkey rkey _i_MAP_ONLY(, i_valraw rmapped)) {
+ _cx_result _res = _cx_memb(_insert_entry_)(self, rkey);
+ if (_res.inserted) {
+ *_i_keyref(_res.ref) = i_keyfrom(rkey);
+ _i_MAP_ONLY( _res.ref->second = i_valfrom(rmapped); )
+ }
+ return _res;
+}
+#endif // !_i_no_emplace
+#endif // !_i_no_clone
+
+STC_INLINE _cx_raw
+_cx_memb(_value_toraw)(_cx_value* val) {
+ return _i_SET_ONLY( i_keyto(val) )
+ _i_MAP_ONLY( c_make(_cx_raw){i_keyto((&val->first)), i_valto((&val->second))} );
+}
+
+STC_INLINE void
+_cx_memb(_value_drop)(_cx_value* _val) {
+ i_keydrop(_i_keyref(_val));
+ _i_MAP_ONLY( i_valdrop((&_val->second)); )
+}
+
+STC_INLINE _cx_result
+_cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) {
+ _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key)));
+ if (_res.inserted)
+ { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )}
+ else
+ { i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )}
+ return _res;
+}
+
+STC_INLINE _cx_result
+_cx_memb(_push)(_cx_self* self, _cx_value _val) {
+ _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
+ if (_res.inserted)
+ *_res.ref = _val;
+ else
+ _cx_memb(_value_drop)(&_val);
+ return _res;
+}
+
+STC_INLINE _cx_iter
+_cx_memb(_find)(const _cx_self* self, _cx_rawkey rkey) {
+ i_size idx;
+ if (!(self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx]))
+ idx = self->bucket_count;
+ return c_make(_cx_iter){self->table+idx, self->_hashx+idx};
+}
+
+STC_INLINE const _cx_value*
+_cx_memb(_get)(const _cx_self* self, _cx_rawkey rkey) {
+ i_size idx;
+ if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx])
+ return self->table + idx;
+ return NULL;
+}
+
+STC_INLINE _cx_value*
+_cx_memb(_get_mut)(const _cx_self* self, _cx_rawkey rkey)
+ { return (_cx_value*)_cx_memb(_get)(self, rkey); }
+
+STC_INLINE _cx_iter
+_cx_memb(_begin)(const _cx_self* self) {
+ _cx_iter it = {self->table, self->_hashx};
+ if (it._hx)
+ while (*it._hx == 0)
+ ++it.ref, ++it._hx;
+ return it;
+}
+
+STC_INLINE _cx_iter
+_cx_memb(_end)(const _cx_self* self)
+ { return c_make(_cx_iter){self->table + self->bucket_count}; }
+
+STC_INLINE void
+_cx_memb(_next)(_cx_iter* it)
+ { while ((++it->ref, *++it->_hx == 0)) ; }
+
+STC_INLINE _cx_iter
+_cx_memb(_advance)(_cx_iter it, size_t n) {
+ // UB if n > elements left
+ while (n--) _cx_memb(_next)(&it);
+ return it;
+}
+
+STC_INLINE size_t
+_cx_memb(_erase)(_cx_self* self, _cx_rawkey 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
+_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
+ _cx_memb(_erase_entry)(self, it.ref);
+ if (*it._hx == 0)
+ _cx_memb(_next)(&it);
+ return it;
+}
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if defined(i_implement)
+
+#ifndef CMAP_H_INCLUDED
+STC_INLINE size_t fastrange_size_t(uint64_t x, uint64_t n)
+ { uint64_t lo, hi; c_umul128(x, n, &lo, &hi); return (size_t)hi; }
+STC_INLINE size_t fastrange_uint32_t(uint64_t x, uint64_t n)
+ { return (size_t)((uint32_t)x*n >> 32); }
+#endif // CMAP_H_INCLUDED
+
+STC_DEF _cx_self
+_cx_memb(_with_capacity)(const size_t cap) {
+ _cx_self h = _cmap_inits;
+ _cx_memb(_reserve)(&h, cap);
+ return h;
+}
+
+STC_INLINE void _cx_memb(_wipe_)(_cx_self* self) {
+ if (self->size == 0)
+ return;
+ _cx_value* e = self->table, *end = e + self->bucket_count;
+ uint8_t *hx = self->_hashx;
+ for (; e != end; ++e)
+ if (*hx++)
+ _cx_memb(_value_drop)(e);
+}
+
+STC_DEF void _cx_memb(_drop)(_cx_self* self) {
+ _cx_memb(_wipe_)(self);
+ c_free(self->_hashx);
+ c_free((void *) self->table);
+}
+
+STC_DEF void _cx_memb(_clear)(_cx_self* self) {
+ _cx_memb(_wipe_)(self);
+ self->size = 0;
+ memset(self->_hashx, 0, self->bucket_count);
+}
+
+#ifndef _i_isset
+ STC_DEF _cx_result
+ _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped) {
+ _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key)));
+ if (_res.inserted)
+ _res.ref->first = _key;
+ else
+ { i_keydrop((&_key)); i_valdrop((&_res.ref->second)); }
+ _res.ref->second = _mapped;
+ return _res;
+ }
+
+ #if !defined _i_no_clone && !defined _i_no_emplace
+ STC_DEF _cx_result
+ _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped) {
+ _cx_result _res = _cx_memb(_insert_entry_)(self, rkey);
+ if (_res.inserted)
+ _res.ref->first = i_keyfrom(rkey);
+ else
+ { i_valdrop((&_res.ref->second)); }
+ _res.ref->second = i_valfrom(rmapped);
+ return _res;
+ }
+ #endif // !_i_no_clone && !_i_no_emplace
+#endif // !_i_isset
+
+STC_DEF chash_bucket_t
+_cx_memb(_bucket_)(const _cx_self* self, const _cx_rawkey* rkeyptr) {
+ const uint64_t _hash = i_hash(rkeyptr);
+ i_size _cap = self->bucket_count;
+ chash_bucket_t b = {c_paste(fastrange_,i_size)(_hash, _cap), (uint8_t)(_hash | 0x80)};
+ const uint8_t* _hx = self->_hashx;
+ while (_hx[b.idx]) {
+ if (_hx[b.idx] == b.hx) {
+ const _cx_rawkey _raw = i_keyto(_i_keyref(self->table + b.idx));
+ if (i_eq((&_raw), rkeyptr))
+ break;
+ }
+ if (++b.idx == _cap)
+ b.idx = 0;
+ }
+ return b;
+}
+
+STC_DEF _cx_result
+_cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey) {
+ bool nomem = false;
+ if (self->size + 1 >= (i_size)(self->bucket_count*self->max_load_factor))
+ nomem = !_cx_memb(_reserve)(self, ((size_t)self->size*3 >> 1) + 4);
+ chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey);
+ _cx_result res = {&self->table[b.idx], !self->_hashx[b.idx], nomem};
+ if (res.inserted) {
+ self->_hashx[b.idx] = b.hx;
+ ++self->size;
+ }
+ return res;
+}
+
+#if !defined _i_no_clone
+STC_DEF _cx_self
+_cx_memb(_clone)(_cx_self m) {
+ _cx_value *t = c_alloc_n(_cx_value, m.bucket_count), *dst = t, *m_end = m.table + m.bucket_count;
+ uint8_t *h = (uint8_t *)memcpy(c_malloc(m.bucket_count + 1), m._hashx, m.bucket_count + 1);
+ if (!(t && h))
+ { c_free(t), c_free(h), t = 0, h = 0, m.bucket_count = 0; }
+ else
+ for (; m.table != m_end; ++m.table, ++m._hashx, ++dst)
+ if (*m._hashx)
+ *dst = _cx_memb(_value_clone)(*m.table);
+ m.table = t, m._hashx = h;
+ return m;
+}
+#endif
+
+STC_DEF bool
+_cx_memb(_reserve)(_cx_self* self, const size_t _newcap) {
+ const i_size _oldbuckets = self->bucket_count;
+ const i_size _nbuckets = ((i_size)(_newcap/self->max_load_factor) + 2) | 1;
+ if (_newcap != self->size && _newcap <= _oldbuckets)
+ return true;
+ _cx_self m = {
+ c_alloc_n(_cx_value, _nbuckets),
+ (uint8_t *) c_calloc(_nbuckets + 1, 1),
+ self->size, (i_size)_nbuckets,
+ self->max_load_factor
+ };
+ bool ok = m.table && m._hashx;
+ if (ok) { /* Rehash: */
+ m._hashx[_nbuckets] = 0xff;
+ const _cx_value* e = self->table;
+ const uint8_t* h = self->_hashx;
+ for (size_t i = 0; i < _oldbuckets; ++i, ++e) if (*h++) {
+ _cx_rawkey r = i_keyto(_i_keyref(e));
+ chash_bucket_t b = _cx_memb(_bucket_)(&m, &r);
+ m.table[b.idx] = *e;
+ m._hashx[b.idx] = (uint8_t)b.hx;
+ }
+ c_swap(_cx_self, *self, m);
+ }
+ c_free(m._hashx);
+ c_free(m.table);
+ return ok;
+}
+
+STC_DEF void
+_cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) {
+ i_size i = _val - self->table, j = i, k;
+ const i_size _cap = self->bucket_count;
+ _cx_value* _slot = self->table;
+ uint8_t* _hashx = self->_hashx;
+ _cx_memb(_value_drop)(_val);
+ for (;;) { /* delete without leaving tombstone */
+ if (++j == _cap)
+ j = 0;
+ if (! _hashx[j])
+ break;
+ const _cx_rawkey _raw = i_keyto(_i_keyref(_slot + j));
+ k = c_paste(fastrange_,i_size)(i_hash((&_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 // i_implement
+#undef _i_isset
+#undef _i_ismap
+#undef _i_ishash
+#undef _i_keyref
+#undef _i_MAP_ONLY
+#undef _i_SET_ONLY
+#define CMAP_H_INCLUDED
+#include "template.h"
diff --git a/include/stc/cpque.h b/include/stc/cpque.h
index cb4b6e70..3a7cc0a1 100644
--- a/include/stc/cpque.h
+++ b/include/stc/cpque.h
@@ -1,157 +1,157 @@
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-#include "ccommon.h"
-
-#ifndef CPQUE_H_INCLUDED
-#include <stdlib.h>
-#include "forward.h"
-#endif
-
-#ifndef _i_prefix
-#define _i_prefix cpque_
-#endif
-
-#include "template.h"
-
-#if !c_option(c_is_fwd)
- _cx_deftypes(_c_cpque_types, _cx_self, i_key);
-#endif
-typedef i_keyraw _cx_raw;
-
-STC_API void _cx_memb(_make_heap)(_cx_self* self);
-STC_API void _cx_memb(_erase_at)(_cx_self* self, size_t idx);
-STC_API void _cx_memb(_push)(_cx_self* self, _cx_value value);
-
-STC_INLINE _cx_self _cx_memb(_init)(void)
- { return c_make(_cx_self){NULL}; }
-
-STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, const size_t cap) {
- if (cap != self->size && cap <= self->capacity) return true;
- _cx_value *d = (_cx_value *)c_realloc(self->data, cap*sizeof *d);
- return d ? (self->data = d, self->capacity = cap, true) : false;
-}
-
-STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self)
- { _cx_memb(_reserve)(self, self->size); }
-
-STC_INLINE _cx_self _cx_memb(_with_capacity)(const size_t cap) {
- _cx_self out = {NULL}; _cx_memb(_reserve)(&out, cap);
- return out;
-}
-
-STC_INLINE _cx_self _cx_memb(_with_size)(const size_t size, i_key null) {
- _cx_self out = {NULL}; _cx_memb(_reserve)(&out, size);
- while (out.size < size) out.data[out.size++] = null;
- return out;
-}
-
-STC_INLINE void _cx_memb(_clear)(_cx_self* self) {
- size_t i = self->size; self->size = 0;
- while (i--) { i_keydrop((self->data + i)); }
-}
-
-STC_INLINE void _cx_memb(_drop)(_cx_self* self)
- { _cx_memb(_clear)(self); c_free(self->data); }
-
-STC_INLINE size_t _cx_memb(_size)(_cx_self q)
- { return q.size; }
-
-STC_INLINE bool _cx_memb(_empty)(_cx_self q)
- { return !q.size; }
-
-STC_INLINE size_t _cx_memb(_capacity)(_cx_self q)
- { return q.capacity; }
-
-STC_INLINE _cx_value* _cx_memb(_top)(const _cx_self* self)
- { return &self->data[0]; }
-
-STC_INLINE void _cx_memb(_pop)(_cx_self* self)
- { _cx_memb(_erase_at)(self, 0); }
-
-#if !defined _i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self q);
-
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->data == other.data) return;
- _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other);
-}
-STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val)
- { return i_keyclone(val); }
-
-#if !defined _i_no_emplace
-STC_INLINE void _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { _cx_memb(_push)(self, i_keyfrom(raw)); }
-#endif // !_i_no_emplace
-#endif // !_i_no_clone
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-STC_DEF void
-_cx_memb(_sift_down_)(_cx_value* arr, const size_t idx, const size_t n) {
- for (size_t r = idx, c = idx << 1; c <= n; c <<= 1) {
- c += (c < n && (i_cmp((&arr[c]), (&arr[c + 1]))) < 0);
- if ((i_cmp((&arr[r]), (&arr[c]))) >= 0) return;
- _cx_value t = arr[r]; arr[r] = arr[c]; arr[r = c] = t;
- }
-}
-
-STC_DEF void
-_cx_memb(_make_heap)(_cx_self* self) {
- size_t n = _cx_memb(_size)(*self);
- _cx_value *arr = self->data - 1;
- for (size_t k = n >> 1; k != 0; --k)
- _cx_memb(_sift_down_)(arr, k, n);
-}
-
-#if !defined _i_no_clone
-STC_DEF _cx_self _cx_memb(_clone)(_cx_self q) {
- _cx_self out = _cx_memb(_with_capacity)(q.size);
- for (; out.size < out.capacity; ++q.data)
- out.data[out.size++] = i_keyclone((*q.data));
- return out;
-}
-#endif
-
-STC_DEF void
-_cx_memb(_erase_at)(_cx_self* self, const size_t idx) {
- i_keydrop((self->data + idx));
- const size_t n = --self->size;
- self->data[idx] = self->data[n];
- _cx_memb(_sift_down_)(self->data - 1, idx + 1, n);
-}
-
-STC_DEF void
-_cx_memb(_push)(_cx_self* self, _cx_value value) {
- if (self->size == self->capacity)
- _cx_memb(_reserve)(self, self->size*3/2 + 4);
- _cx_value *arr = self->data - 1; /* base 1 */
- size_t c = ++self->size;
- for (; c > 1 && (i_cmp((&arr[c >> 1]), (&value))) < 0; c >>= 1)
- arr[c] = arr[c >> 1];
- arr[c] = value;
-}
-
-#endif
-#define CPQUE_H_INCLUDED
-#include "template.h"
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+#include "ccommon.h"
+
+#ifndef CPQUE_H_INCLUDED
+#include <stdlib.h>
+#include "forward.h"
+#endif
+
+#ifndef _i_prefix
+#define _i_prefix cpque_
+#endif
+
+#include "template.h"
+
+#if !c_option(c_is_fwd)
+ _cx_deftypes(_c_cpque_types, _cx_self, i_key);
+#endif
+typedef i_keyraw _cx_raw;
+
+STC_API void _cx_memb(_make_heap)(_cx_self* self);
+STC_API void _cx_memb(_erase_at)(_cx_self* self, size_t idx);
+STC_API void _cx_memb(_push)(_cx_self* self, _cx_value value);
+
+STC_INLINE _cx_self _cx_memb(_init)(void)
+ { return c_make(_cx_self){NULL}; }
+
+STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, const size_t cap) {
+ if (cap != self->size && cap <= self->capacity) return true;
+ _cx_value *d = (_cx_value *)c_realloc(self->data, cap*sizeof *d);
+ return d ? (self->data = d, self->capacity = cap, true) : false;
+}
+
+STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self)
+ { _cx_memb(_reserve)(self, self->size); }
+
+STC_INLINE _cx_self _cx_memb(_with_capacity)(const size_t cap) {
+ _cx_self out = {NULL}; _cx_memb(_reserve)(&out, cap);
+ return out;
+}
+
+STC_INLINE _cx_self _cx_memb(_with_size)(const size_t size, i_key null) {
+ _cx_self out = {NULL}; _cx_memb(_reserve)(&out, size);
+ while (out.size < size) out.data[out.size++] = null;
+ return out;
+}
+
+STC_INLINE void _cx_memb(_clear)(_cx_self* self) {
+ size_t i = self->size; self->size = 0;
+ while (i--) { i_keydrop((self->data + i)); }
+}
+
+STC_INLINE void _cx_memb(_drop)(_cx_self* self)
+ { _cx_memb(_clear)(self); c_free(self->data); }
+
+STC_INLINE size_t _cx_memb(_size)(_cx_self q)
+ { return q.size; }
+
+STC_INLINE bool _cx_memb(_empty)(_cx_self q)
+ { return !q.size; }
+
+STC_INLINE size_t _cx_memb(_capacity)(_cx_self q)
+ { return q.capacity; }
+
+STC_INLINE _cx_value* _cx_memb(_top)(const _cx_self* self)
+ { return &self->data[0]; }
+
+STC_INLINE void _cx_memb(_pop)(_cx_self* self)
+ { _cx_memb(_erase_at)(self, 0); }
+
+#if !defined _i_no_clone
+STC_API _cx_self _cx_memb(_clone)(_cx_self q);
+
+STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
+ if (self->data == other.data) return;
+ _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other);
+}
+STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val)
+ { return i_keyclone(val); }
+
+#if !defined _i_no_emplace
+STC_INLINE void _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
+ { _cx_memb(_push)(self, i_keyfrom(raw)); }
+#endif // !_i_no_emplace
+#endif // !_i_no_clone
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if defined(i_implement)
+
+STC_DEF void
+_cx_memb(_sift_down_)(_cx_value* arr, const size_t idx, const size_t n) {
+ for (size_t r = idx, c = idx << 1; c <= n; c <<= 1) {
+ c += (c < n && (i_cmp((&arr[c]), (&arr[c + 1]))) < 0);
+ if ((i_cmp((&arr[r]), (&arr[c]))) >= 0) return;
+ _cx_value t = arr[r]; arr[r] = arr[c]; arr[r = c] = t;
+ }
+}
+
+STC_DEF void
+_cx_memb(_make_heap)(_cx_self* self) {
+ size_t n = _cx_memb(_size)(*self);
+ _cx_value *arr = self->data - 1;
+ for (size_t k = n >> 1; k != 0; --k)
+ _cx_memb(_sift_down_)(arr, k, n);
+}
+
+#if !defined _i_no_clone
+STC_DEF _cx_self _cx_memb(_clone)(_cx_self q) {
+ _cx_self out = _cx_memb(_with_capacity)(q.size);
+ for (; out.size < out.capacity; ++q.data)
+ out.data[out.size++] = i_keyclone((*q.data));
+ return out;
+}
+#endif
+
+STC_DEF void
+_cx_memb(_erase_at)(_cx_self* self, const size_t idx) {
+ i_keydrop((self->data + idx));
+ const size_t n = --self->size;
+ self->data[idx] = self->data[n];
+ _cx_memb(_sift_down_)(self->data - 1, idx + 1, n);
+}
+
+STC_DEF void
+_cx_memb(_push)(_cx_self* self, _cx_value value) {
+ if (self->size == self->capacity)
+ _cx_memb(_reserve)(self, self->size*3/2 + 4);
+ _cx_value *arr = self->data - 1; /* base 1 */
+ size_t c = ++self->size;
+ for (; c > 1 && (i_cmp((&arr[c >> 1]), (&value))) < 0; c >>= 1)
+ arr[c] = arr[c >> 1];
+ arr[c] = value;
+}
+
+#endif
+#define CPQUE_H_INCLUDED
+#include "template.h"
diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h
index 920f8eac..00874f35 100644
--- a/include/stc/cqueue.h
+++ b/include/stc/cqueue.h
@@ -1,65 +1,65 @@
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-// STC queue
-/*
-#include <stc/crandom.h>
-#include <stdio.h>
-
-#define i_key int
-#include <stc/cqueue.h>
-
-int main() {
- int n = 10000000;
- stc64_t rng = stc64_new(1234);
- stc64_uniform_t dist = stc64_uniform_new(0, n);
-
- c_auto (cqueue_int, Q)
- {
- // Push ten million random numbers onto the queue.
- for (int i=0; i<n; ++i)
- cqueue_int_push(&Q, stc64_uniform(&rng, &dist));
-
- // Push or pop on the queue ten million times
- printf("before: size, capacity: %d, %d\n", n, cqueue_int_size(Q), cqueue_int_capacity(Q));
- for (int i=n; i>0; --i) {
- int r = stc64_uniform(&rng, &dist);
- if (r & 1)
- ++n, cqueue_int_push(&Q, r);
- else
- --n, cqueue_int_pop(&Q);
- }
- printf("after: size, capacity: %d, %d\n", n, cqueue_int_size(Q), cqueue_int_capacity(Q));
- }
-}
-*/
-
-#ifndef _i_prefix
-#define _i_prefix cqueue_
-#endif
-#define _i_queue
-#define _pop_front _pop
-
-#include "cdeq.h"
-
-#undef _pop_front
-#undef _i_queue
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+// STC queue
+/*
+#include <stc/crandom.h>
+#include <stdio.h>
+
+#define i_key int
+#include <stc/cqueue.h>
+
+int main() {
+ int n = 10000000;
+ stc64_t rng = stc64_new(1234);
+ stc64_uniform_t dist = stc64_uniform_new(0, n);
+
+ c_auto (cqueue_int, Q)
+ {
+ // Push ten million random numbers onto the queue.
+ for (int i=0; i<n; ++i)
+ cqueue_int_push(&Q, stc64_uniform(&rng, &dist));
+
+ // Push or pop on the queue ten million times
+ printf("before: size, capacity: %d, %d\n", n, cqueue_int_size(Q), cqueue_int_capacity(Q));
+ for (int i=n; i>0; --i) {
+ int r = stc64_uniform(&rng, &dist);
+ if (r & 1)
+ ++n, cqueue_int_push(&Q, r);
+ else
+ --n, cqueue_int_pop(&Q);
+ }
+ printf("after: size, capacity: %d, %d\n", n, cqueue_int_size(Q), cqueue_int_capacity(Q));
+ }
+}
+*/
+
+#ifndef _i_prefix
+#define _i_prefix cqueue_
+#endif
+#define _i_queue
+#define _pop_front _pop
+
+#include "cdeq.h"
+
+#undef _pop_front
+#undef _i_queue
diff --git a/include/stc/crandom.h b/include/stc/crandom.h
index 88ac3af6..ea26eba3 100644
--- a/include/stc/crandom.h
+++ b/include/stc/crandom.h
@@ -1,195 +1,195 @@
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-#define i_header
-#include "ccommon.h"
-
-#ifndef CRANDOM_H_INCLUDED
-#define CRANDOM_H_INCLUDED
-/*
-// crandom: Pseudo-random number generator
-#include "stc/crandom.h"
-int main() {
- uint64_t seed = 123456789;
- stc64_t rng = stc64_new(seed);
- stc64_uniform_t dist1 = stc64_uniform_new(1, 6);
- stc64_uniformf_t dist2 = stc64_uniformf_new(1.0, 10.0);
- stc64_normalf_t dist3 = stc64_normalf_new(1.0, 10.0);
-
- uint64_t i = stc64_rand(&rng);
- int64_t iu = stc64_uniform(&rng, &dist1);
- double xu = stc64_uniformf(&rng, &dist2);
- double xn = stc64_normalf(&rng, &dist3);
-}
-*/
-#include <string.h>
-#include <math.h>
-
-typedef struct stc64 { uint64_t state[5]; } stc64_t;
-typedef struct stc64_uniform { int64_t lower; uint64_t range, threshold; } stc64_uniform_t;
-typedef struct stc64_uniformf { double lower, range; } stc64_uniformf_t;
-typedef struct stc64_normalf { double mean, stddev, next; 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
- * Romu, but these have restricted capacity for larger parallel jobs or unknown minimum periods.
- * stc64 supports 2^63 unique threads with a minimum 2^64 period lengths each.
- * Passes all statistical tests, e.g PractRand and correlation tests, i.e. interleaved
- * streams with one-bit diff state. Even the 16-bit version (LR=6, RS=5, LS=3) passes
- * PractRand to multiple TB input.
- */
-
-/* Global stc64 PRNGs */
-STC_API void csrandom(uint64_t seed);
-STC_API uint64_t crandom(void);
-STC_API double crandomf(void);
-
-/* Init stc64 prng with and without sequence number */
-STC_API stc64_t stc64_with_seq(uint64_t seed, uint64_t seq);
-STC_INLINE stc64_t stc64_new(uint64_t seed)
- { return stc64_with_seq(seed, seed + 0x3504f333d3aa0b37); }
-
-/* Unbiased bounded uniform distribution. range [low, high] */
-STC_API stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high);
-STC_API int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* dist);
-
-/* Normal distribution PRNG */
-STC_API double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist);
-
-
-/* Main stc64 prng */
-STC_INLINE uint64_t stc64_rand(stc64_t* rng) {
- uint64_t *s = rng->state; enum {LR=24, RS=11, LS=3};
- const uint64_t result = (s[0] ^ (s[3] += s[4])) + s[1];
- s[0] = s[1] ^ (s[1] >> RS);
- s[1] = s[2] + (s[2] << LS);
- s[2] = ((s[2] << LR) | (s[2] >> (64 - LR))) + result;
- return result;
-}
-
-/* Float64 random number in range [0.0, 1.0). */
-STC_INLINE double stc64_randf(stc64_t* rng) {
- union {uint64_t i; double f;} u = {0x3FF0000000000000ull | (stc64_rand(rng) >> 12)};
- return u.f - 1.0;
-}
-
-/* Float64 uniform distributed RNG, range [low, high). */
-STC_INLINE double stc64_uniformf(stc64_t* rng, stc64_uniformf_t* dist) {
- return stc64_randf(rng)*dist->range + dist->lower;
-}
-
-/* Init uniform distributed float64 RNG, range [low, high). */
-STC_INLINE stc64_uniformf_t stc64_uniformf_new(double low, double high) {
- return c_make(stc64_uniformf_t){low, high - low};
-}
-
-/* Marsaglia polar method for gaussian/normal distribution, float64. */
-STC_INLINE stc64_normalf_t stc64_normalf_new(double mean, double stddev) {
- return c_make(stc64_normalf_t){mean, stddev, 0.0, 0};
-}
-
-/* Following functions are deprecated (will be removed in the future): */
-STC_INLINE void stc64_srandom(uint64_t seed) { csrandom(seed); }
-STC_INLINE uint64_t stc64_random() { return crandom(); }
-STC_INLINE stc64_t stc64_init(uint64_t seed) { return stc64_new(seed); }
-STC_INLINE stc64_uniformf_t stc64_uniformf_init(double low, double high)
- { return stc64_uniformf_new(low, high); }
-STC_INLINE stc64_normalf_t stc64_normalf_init(double mean, double stddev)
- { return stc64_normalf_new(mean, stddev); }
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-/* Global random() */
-static stc64_t stc64_global = {{
- 0x26aa069ea2fb1a4d, 0x70c72c95cd592d04,
- 0x504f333d3aa0b359, 0x9e3779b97f4a7c15,
- 0x6a09e667a754166b
-}};
-
-STC_DEF void csrandom(uint64_t seed) {
- stc64_global = stc64_new(seed);
-}
-
-STC_DEF uint64_t crandom(void) {
- return stc64_rand(&stc64_global);
-}
-
-STC_DEF double crandomf(void) {
- return stc64_randf(&stc64_global);
-}
-
-/* rng.state[4] must be odd */
-STC_DEF stc64_t stc64_with_seq(uint64_t seed, uint64_t seq) {
- stc64_t rng = {{seed+0x26aa069ea2fb1a4d, seed+0x70c72c95cd592d04,
- seed+0x504f333d3aa0b359, seed, seed<<1 | 1}};
- for (int i = 0; i < 6; ++i) stc64_rand(&rng);
- return rng;
-}
-
-/* Init unbiased uniform uint RNG with bounds [low, high] */
-STC_DEF stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high) {
- stc64_uniform_t dist = {low, (uint64_t) (high - low + 1)};
- dist.threshold = (uint64_t)-(int64_t)dist.range % dist.range;
- return dist;
-}
-
-/* Int uniform distributed RNG, range [low, high]. */
-STC_DEF int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* d) {
-#ifdef c_umul128
- uint64_t lo, hi;
- do { c_umul128(stc64_rand(rng), d->range, &lo, &hi); } while (lo < d->threshold);
- return d->lower + hi;
-#else
- uint64_t x, r;
- do {
- x = stc64_rand(rng);
- r = x % d->range;
- } while (x - r > -d->range);
- return d->lower + r;
-#endif
-}
-
-/* Normal distribution PRNG */
-STC_DEF double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist) {
- double u1, u2, s, m;
- if (dist->has_next++ & 1)
- return dist->next * dist->stddev + dist->mean;
- do {
- u1 = 2.0 * stc64_randf(rng) - 1.0;
- u2 = 2.0 * stc64_randf(rng) - 1.0;
- s = u1*u1 + u2*u2;
- } while (s >= 1.0 || s == 0.0);
- m = sqrt(-2.0 * log(s) / s);
- dist->next = u2 * m;
- return (u1 * m) * dist->stddev + dist->mean;
-}
-
-#endif
-#endif
-#undef i_opt
-#undef i_static
-#undef i_header
-#undef i_implement
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+#define i_header
+#include "ccommon.h"
+
+#ifndef CRANDOM_H_INCLUDED
+#define CRANDOM_H_INCLUDED
+/*
+// crandom: Pseudo-random number generator
+#include "stc/crandom.h"
+int main() {
+ uint64_t seed = 123456789;
+ stc64_t rng = stc64_new(seed);
+ stc64_uniform_t dist1 = stc64_uniform_new(1, 6);
+ stc64_uniformf_t dist2 = stc64_uniformf_new(1.0, 10.0);
+ stc64_normalf_t dist3 = stc64_normalf_new(1.0, 10.0);
+
+ uint64_t i = stc64_rand(&rng);
+ int64_t iu = stc64_uniform(&rng, &dist1);
+ double xu = stc64_uniformf(&rng, &dist2);
+ double xn = stc64_normalf(&rng, &dist3);
+}
+*/
+#include <string.h>
+#include <math.h>
+
+typedef struct stc64 { uint64_t state[5]; } stc64_t;
+typedef struct stc64_uniform { int64_t lower; uint64_t range, threshold; } stc64_uniform_t;
+typedef struct stc64_uniformf { double lower, range; } stc64_uniformf_t;
+typedef struct stc64_normalf { double mean, stddev, next; 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
+ * Romu, but these have restricted capacity for larger parallel jobs or unknown minimum periods.
+ * stc64 supports 2^63 unique threads with a minimum 2^64 period lengths each.
+ * Passes all statistical tests, e.g PractRand and correlation tests, i.e. interleaved
+ * streams with one-bit diff state. Even the 16-bit version (LR=6, RS=5, LS=3) passes
+ * PractRand to multiple TB input.
+ */
+
+/* Global stc64 PRNGs */
+STC_API void csrandom(uint64_t seed);
+STC_API uint64_t crandom(void);
+STC_API double crandomf(void);
+
+/* Init stc64 prng with and without sequence number */
+STC_API stc64_t stc64_with_seq(uint64_t seed, uint64_t seq);
+STC_INLINE stc64_t stc64_new(uint64_t seed)
+ { return stc64_with_seq(seed, seed + 0x3504f333d3aa0b37); }
+
+/* Unbiased bounded uniform distribution. range [low, high] */
+STC_API stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high);
+STC_API int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* dist);
+
+/* Normal distribution PRNG */
+STC_API double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist);
+
+
+/* Main stc64 prng */
+STC_INLINE uint64_t stc64_rand(stc64_t* rng) {
+ uint64_t *s = rng->state; enum {LR=24, RS=11, LS=3};
+ const uint64_t result = (s[0] ^ (s[3] += s[4])) + s[1];
+ s[0] = s[1] ^ (s[1] >> RS);
+ s[1] = s[2] + (s[2] << LS);
+ s[2] = ((s[2] << LR) | (s[2] >> (64 - LR))) + result;
+ return result;
+}
+
+/* Float64 random number in range [0.0, 1.0). */
+STC_INLINE double stc64_randf(stc64_t* rng) {
+ union {uint64_t i; double f;} u = {0x3FF0000000000000ull | (stc64_rand(rng) >> 12)};
+ return u.f - 1.0;
+}
+
+/* Float64 uniform distributed RNG, range [low, high). */
+STC_INLINE double stc64_uniformf(stc64_t* rng, stc64_uniformf_t* dist) {
+ return stc64_randf(rng)*dist->range + dist->lower;
+}
+
+/* Init uniform distributed float64 RNG, range [low, high). */
+STC_INLINE stc64_uniformf_t stc64_uniformf_new(double low, double high) {
+ return c_make(stc64_uniformf_t){low, high - low};
+}
+
+/* Marsaglia polar method for gaussian/normal distribution, float64. */
+STC_INLINE stc64_normalf_t stc64_normalf_new(double mean, double stddev) {
+ return c_make(stc64_normalf_t){mean, stddev, 0.0, 0};
+}
+
+/* Following functions are deprecated (will be removed in the future): */
+STC_INLINE void stc64_srandom(uint64_t seed) { csrandom(seed); }
+STC_INLINE uint64_t stc64_random() { return crandom(); }
+STC_INLINE stc64_t stc64_init(uint64_t seed) { return stc64_new(seed); }
+STC_INLINE stc64_uniformf_t stc64_uniformf_init(double low, double high)
+ { return stc64_uniformf_new(low, high); }
+STC_INLINE stc64_normalf_t stc64_normalf_init(double mean, double stddev)
+ { return stc64_normalf_new(mean, stddev); }
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if defined(i_implement)
+
+/* Global random() */
+static stc64_t stc64_global = {{
+ 0x26aa069ea2fb1a4d, 0x70c72c95cd592d04,
+ 0x504f333d3aa0b359, 0x9e3779b97f4a7c15,
+ 0x6a09e667a754166b
+}};
+
+STC_DEF void csrandom(uint64_t seed) {
+ stc64_global = stc64_new(seed);
+}
+
+STC_DEF uint64_t crandom(void) {
+ return stc64_rand(&stc64_global);
+}
+
+STC_DEF double crandomf(void) {
+ return stc64_randf(&stc64_global);
+}
+
+/* rng.state[4] must be odd */
+STC_DEF stc64_t stc64_with_seq(uint64_t seed, uint64_t seq) {
+ stc64_t rng = {{seed+0x26aa069ea2fb1a4d, seed+0x70c72c95cd592d04,
+ seed+0x504f333d3aa0b359, seed, seed<<1 | 1}};
+ for (int i = 0; i < 6; ++i) stc64_rand(&rng);
+ return rng;
+}
+
+/* Init unbiased uniform uint RNG with bounds [low, high] */
+STC_DEF stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high) {
+ stc64_uniform_t dist = {low, (uint64_t) (high - low + 1)};
+ dist.threshold = (uint64_t)-(int64_t)dist.range % dist.range;
+ return dist;
+}
+
+/* Int uniform distributed RNG, range [low, high]. */
+STC_DEF int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* d) {
+#ifdef c_umul128
+ uint64_t lo, hi;
+ do { c_umul128(stc64_rand(rng), d->range, &lo, &hi); } while (lo < d->threshold);
+ return d->lower + hi;
+#else
+ uint64_t x, r;
+ do {
+ x = stc64_rand(rng);
+ r = x % d->range;
+ } while (x - r > -d->range);
+ return d->lower + r;
+#endif
+}
+
+/* Normal distribution PRNG */
+STC_DEF double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist) {
+ double u1, u2, s, m;
+ if (dist->has_next++ & 1)
+ return dist->next * dist->stddev + dist->mean;
+ do {
+ u1 = 2.0 * stc64_randf(rng) - 1.0;
+ u2 = 2.0 * stc64_randf(rng) - 1.0;
+ s = u1*u1 + u2*u2;
+ } while (s >= 1.0 || s == 0.0);
+ m = sqrt(-2.0 * log(s) / s);
+ dist->next = u2 * m;
+ return (u1 * m) * dist->stddev + dist->mean;
+}
+
+#endif
+#endif
+#undef i_opt
+#undef i_static
+#undef i_header
+#undef i_implement
#undef i_extern \ No newline at end of file
diff --git a/include/stc/cregex.h b/include/stc/cregex.h
index 0a4508b7..1afe484f 100644
--- a/include/stc/cregex.h
+++ b/include/stc/cregex.h
@@ -1,90 +1,90 @@
-/*
-This is a Unix port of the Plan 9 regular expression library, by Rob Pike.
-Please send comments about the packaging to Russ Cox <[email protected]>.
-
-Copyright © 2021 Plan 9 Foundation
-Copyright © 2022 Tyge Løvset, for additions made in 2022.
-
-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 CREGEX9_H_
-#define CREGEX9_H_
-/*
- * cregex9.h
- *
- * This is a extended version of regexp9, supporting UTF8 input, common
- * shorthand character classes, ++.
- */
-#include "forward.h" // csview
-
-typedef enum {
- creg_nomatch = -1,
- creg_matcherror = -2,
- creg_outofmemory = -3,
- creg_unmatchedleftparenthesis = -4,
- creg_unmatchedrightparenthesis = -5,
- creg_toomanysubexpressions = -6,
- creg_toomanycharacterclasses = -7,
- creg_malformedcharacterclass = -8,
- creg_missingoperand = -9,
- creg_unknownoperator = -10,
- creg_operandstackoverflow = -11,
- creg_operatorstackoverflow = -12,
- creg_operatorstackunderflow = -13,
-} cregex_error_t;
-
-enum {
- /* compile flags */
- creg_dotall = 1<<0,
- creg_caseless = 1<<1,
- /* execution flags */
- creg_fullmatch = 1<<2,
- creg_next = 1<<3,
- creg_startend = 1<<4,
- /* limits */
- creg_max_classes = 16,
- creg_max_captures = 32,
-};
-
-typedef struct {
- struct Reprog* prog;
-} cregex;
-
-typedef csview cregmatch;
-
-static inline cregex cregex_init(void) {
- cregex rx = {NULL}; return rx;
-}
-
-/* return number of capture groups on success, or (negative) error code on failure. */
-int cregex_compile(cregex *self, const char* pattern, int cflags);
-
-/* number of capture groups in a regex pattern */
-int cregex_captures(cregex rx);
-
-/* return number of capture groups on success, or (negative) error code on failure. */
-int cregex_find(const cregex *self, const char* string,
- size_t nmatch, cregmatch match[], int mflags);
-
-void cregex_replace(const char* src, char* dst, int dsize,
- int nmatch, const cregmatch match[]);
-
-void cregex_drop(cregex* self);
-
-#endif
+/*
+This is a Unix port of the Plan 9 regular expression library, by Rob Pike.
+Please send comments about the packaging to Russ Cox <[email protected]>.
+
+Copyright © 2021 Plan 9 Foundation
+Copyright © 2022 Tyge Løvset, for additions made in 2022.
+
+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 CREGEX9_H_
+#define CREGEX9_H_
+/*
+ * cregex9.h
+ *
+ * This is a extended version of regexp9, supporting UTF8 input, common
+ * shorthand character classes, ++.
+ */
+#include "forward.h" // csview
+
+typedef enum {
+ creg_nomatch = -1,
+ creg_matcherror = -2,
+ creg_outofmemory = -3,
+ creg_unmatchedleftparenthesis = -4,
+ creg_unmatchedrightparenthesis = -5,
+ creg_toomanysubexpressions = -6,
+ creg_toomanycharacterclasses = -7,
+ creg_malformedcharacterclass = -8,
+ creg_missingoperand = -9,
+ creg_unknownoperator = -10,
+ creg_operandstackoverflow = -11,
+ creg_operatorstackoverflow = -12,
+ creg_operatorstackunderflow = -13,
+} cregex_error_t;
+
+enum {
+ /* compile flags */
+ creg_dotall = 1<<0,
+ creg_caseless = 1<<1,
+ /* execution flags */
+ creg_fullmatch = 1<<2,
+ creg_next = 1<<3,
+ creg_startend = 1<<4,
+ /* limits */
+ creg_max_classes = 16,
+ creg_max_captures = 32,
+};
+
+typedef struct {
+ struct Reprog* prog;
+} cregex;
+
+typedef csview cregmatch;
+
+static inline cregex cregex_init(void) {
+ cregex rx = {NULL}; return rx;
+}
+
+/* return number of capture groups on success, or (negative) error code on failure. */
+int cregex_compile(cregex *self, const char* pattern, int cflags);
+
+/* number of capture groups in a regex pattern */
+int cregex_captures(cregex rx);
+
+/* return number of capture groups on success, or (negative) error code on failure. */
+int cregex_find(const cregex *self, const char* string,
+ size_t nmatch, cregmatch match[], int mflags);
+
+void cregex_replace(const char* src, char* dst, int dsize,
+ int nmatch, const cregmatch match[]);
+
+void cregex_drop(cregex* self);
+
+#endif
diff --git a/include/stc/cset.h b/include/stc/cset.h
index 335ce753..0dddc02f 100644
--- a/include/stc/cset.h
+++ b/include/stc/cset.h
@@ -1,46 +1,46 @@
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-
-// 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>
-
-int main(void) {
- cset_sx s = cset_sx_init();
- cset_sx_insert(&s, 5);
- cset_sx_insert(&s, 8);
-
- c_foreach (i, cset_sx, s)
- printf("set %d\n", *i.ref);
- cset_sx_drop(&s);
-}
-*/
-
-#ifndef _i_prefix
-#define _i_prefix cset_
-#endif
-#define _i_isset
-#include "cmap.h"
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+
+// 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>
+
+int main(void) {
+ cset_sx s = cset_sx_init();
+ cset_sx_insert(&s, 5);
+ cset_sx_insert(&s, 8);
+
+ c_foreach (i, cset_sx, s)
+ printf("set %d\n", *i.ref);
+ cset_sx_drop(&s);
+}
+*/
+
+#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 a723185d..a463d381 100644
--- a/include/stc/csmap.h
+++ b/include/stc/csmap.h
@@ -1,594 +1,594 @@
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-
-// 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>
-
-int main(void) {
- c_autovar (csmap_sx m = csmap_sx_init(), csmap_sx_drop(&m))
- {
- 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_sx_value *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_sx, m)
- printf("map %s: %g\n", cstr_str(&i.ref->first), i.ref->second);
- }
-}
-*/
-#ifdef STC_CSMAP_V1
-#include "alt/csmap.h"
-#else
-#include "ccommon.h"
-
-#ifndef CSMAP_H_INCLUDED
-#include "forward.h"
-#include <stdlib.h>
-#include <string.h>
-
-struct csmap_rep { size_t root, disp, head, size, cap; unsigned nodes[1]; };
-#define _csmap_rep(self) c_unchecked_container_of((self)->nodes, struct csmap_rep, nodes)
-#endif // CSMAP_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix csmap_
-#endif
-#ifdef _i_isset
- #define _i_MAP_ONLY c_false
- #define _i_SET_ONLY c_true
- #define _i_keyref(vp) (vp)
-#else
- #define _i_ismap
- #define _i_MAP_ONLY c_true
- #define _i_SET_ONLY c_false
- #define _i_keyref(vp) (&(vp)->first)
-#endif
-#include "template.h"
-
-#if !c_option(c_is_fwd)
-_cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_size, _i_MAP_ONLY, _i_SET_ONLY);
-#endif
-
-_i_MAP_ONLY( struct _cx_value {
- _cx_key first;
- _cx_mapped second;
-}; )
-struct _cx_node {
- i_size link[2];
- int8_t level;
- _cx_value value;
-};
-
-typedef i_keyraw _cx_rawkey;
-typedef i_valraw _cx_memb(_rawmapped);
-typedef _i_SET_ONLY( i_keyraw )
- _i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } )
- _cx_raw;
-
-#if !defined _i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self tree);
-#if !defined _i_no_emplace
-STC_API _cx_result _cx_memb(_emplace)(_cx_self* self, _cx_rawkey rkey _i_MAP_ONLY(, i_valraw rmapped));
-#endif // !_i_no_emplace
-#endif // !_i_no_clone
-STC_API _cx_self _cx_memb(_init)(void);
-STC_API _cx_result _cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped));
-STC_API _cx_result _cx_memb(_push)(_cx_self* self, _cx_value _val);
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, size_t cap);
-STC_API _cx_value* _cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out);
-STC_API _cx_iter _cx_memb(_lower_bound)(const _cx_self* self, _cx_rawkey rkey);
-STC_API _cx_value* _cx_memb(_front)(const _cx_self* self);
-STC_API _cx_value* _cx_memb(_back)(const _cx_self* self);
-STC_API int _cx_memb(_erase)(_cx_self* self, _cx_rawkey rkey);
-STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it);
-STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2);
-STC_API void _cx_memb(_next)(_cx_iter* it);
-
-STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return _csmap_rep(&cx)->size == 0; }
-STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return _csmap_rep(&cx)->size; }
-STC_INLINE size_t _cx_memb(_capacity)(_cx_self cx) { return _csmap_rep(&cx)->cap; }
-STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); }
-STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, _cx_rawkey rkey)
- { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); return it; }
-STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_rawkey rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it) != NULL; }
-STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, _cx_rawkey rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
-STC_INLINE _cx_value* _cx_memb(_get_mut)(_cx_self* self, _cx_rawkey rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
-
-STC_INLINE _cx_self
-_cx_memb(_with_capacity)(const size_t cap) {
- _cx_self tree = _cx_memb(_init)();
- _cx_memb(_reserve)(&tree, cap);
- return tree;
-}
-
-STC_INLINE void
-_cx_memb(_clear)(_cx_self* self)
- { _cx_memb(_drop)(self); *self = _cx_memb(_init)(); }
-
-STC_INLINE _cx_raw
-_cx_memb(_value_toraw)(_cx_value* val) {
- return _i_SET_ONLY( i_keyto(val) )
- _i_MAP_ONLY( c_make(_cx_raw){i_keyto((&val->first)),
- i_valto((&val->second))} );
-}
-
-STC_INLINE int
-_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- const _cx_rawkey rx = i_keyto(_i_keyref(x)), ry = i_keyto(_i_keyref(y));
- return i_cmp((&rx), (&ry));
-}
-
-STC_INLINE void
-_cx_memb(_value_drop)(_cx_value* val) {
- i_keydrop(_i_keyref(val));
- _i_MAP_ONLY( i_valdrop((&val->second)); )
-}
-
-#if !defined _i_no_clone
-STC_INLINE _cx_value
-_cx_memb(_value_clone)(_cx_value _val) {
- *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val)));
- _i_MAP_ONLY( _val.second = i_valclone(_val.second); )
- return _val;
-}
-
-STC_INLINE void
-_cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->nodes == other.nodes)
- return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(other);
-}
-
-STC_INLINE void
-_cx_memb(_shrink_to_fit)(_cx_self *self) {
- _cx_self tmp = _cx_memb(_clone)(*self);
- _cx_memb(_drop)(self); *self = tmp;
-}
-#endif // !_i_no_clone
-
-#ifndef _i_isset
- #if !defined _i_no_clone && !defined _i_no_emplace
- STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped);
- #endif
- STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped);
-
- STC_INLINE const _cx_mapped*
- _cx_memb(_at)(const _cx_self* self, _cx_rawkey rkey)
- { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
- STC_INLINE _cx_mapped*
- _cx_memb(_at_mut)(_cx_self* self, _cx_rawkey rkey)
- { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
-#endif // !_i_isset
-
-STC_INLINE _cx_iter
-_cx_memb(_begin)(const _cx_self* self) {
- _cx_iter it;
- it._d = self->nodes, it._top = 0;
- it._tn = (i_size) _csmap_rep(self)->root;
- if (it._tn)
- _cx_memb(_next)(&it);
- return it;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_end)(const _cx_self* self) {
- (void)self;
- _cx_iter it; it.ref = NULL, it._top = 0, it._tn = 0;
- return it;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_advance)(_cx_iter it, size_t n) {
- while (n-- && it.ref)
- _cx_memb(_next)(&it);
- return it;
-}
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-#ifndef CSMAP_H_INCLUDED
-static struct csmap_rep _csmap_sentinel = {0, 0, 0, 0, 0};
-#endif
-
-STC_DEF _cx_self
-_cx_memb(_init)(void) {
- _cx_self tree = {(_cx_node *)_csmap_sentinel.nodes};
- return tree;
-}
-
-STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const size_t cap) {
- struct csmap_rep* rep = _csmap_rep(self), *oldrep;
- if (cap >= rep->size) {
- // second test is bogus, but supresses gcc warning:
- oldrep = rep->cap && rep != &_csmap_sentinel ? rep : NULL;
- rep = (struct csmap_rep*) c_realloc(oldrep, offsetof(struct csmap_rep, nodes) +
- (cap + 1)*sizeof(_cx_node));
- if (!rep)
- return false;
- if (oldrep == NULL)
- memset(rep, 0, offsetof(struct csmap_rep, nodes) + sizeof(_cx_node));
- rep->cap = cap;
- self->nodes = (_cx_node *) rep->nodes;
- }
- return true;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_front)(const _cx_self* self) {
- _cx_node *d = self->nodes;
- i_size tn = (i_size) _csmap_rep(self)->root;
- while (d[tn].link[0])
- tn = d[tn].link[0];
- return &d[tn].value;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_back)(const _cx_self* self) {
- _cx_node *d = self->nodes;
- i_size tn = (i_size) _csmap_rep(self)->root;
- while (d[tn].link[1])
- tn = d[tn].link[1];
- return &d[tn].value;
-}
-
-static i_size
-_cx_memb(_new_node_)(_cx_self* self, int level) {
- i_size tn; struct csmap_rep *rep = _csmap_rep(self);
- if (rep->disp) {
- tn = rep->disp;
- rep->disp = self->nodes[tn].link[1];
- } else {
- if (rep->head == rep->cap)
- if (!_cx_memb(_reserve)(self, rep->head*3/2 + 4))
- return 0;
- tn = ++_csmap_rep(self)->head; /* start with 1, 0 is nullnode. */
- }
- _cx_node* dn = &self->nodes[tn];
- dn->link[0] = dn->link[1] = 0; dn->level = level;
- return tn;
-}
-
-static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey);
-
-STC_DEF _cx_result
-_cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped)) {
- _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key)));
- if (res.inserted)
- { *_i_keyref(res.ref) = key; _i_MAP_ONLY( res.ref->second = mapped; )}
- else
- { i_keydrop((&key)); _i_MAP_ONLY( i_valdrop((&mapped)); )}
- return res;
-}
-
-STC_DEF _cx_result
-_cx_memb(_push)(_cx_self* self, _cx_value _val) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
- if (_res.inserted)
- *_res.ref = _val;
- else
- _cx_memb(_value_drop)(&_val);
- return _res;
-}
-
-#ifndef _i_isset
- STC_DEF _cx_result
- _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped) {
- _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key)));
- if (!res.nomem_error) {
- if (res.inserted)
- res.ref->first = key;
- else
- { i_keydrop((&key)); i_valdrop((&res.ref->second)); }
- res.ref->second = mapped;
- }
- return res;
- }
-
- #if !defined _i_no_clone && !defined _i_no_emplace
- STC_DEF _cx_result
- _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped) {
- _cx_result res = _cx_memb(_insert_entry_)(self, rkey);
- if (!res.nomem_error) {
- if (res.inserted)
- res.ref->first = i_keyfrom(rkey);
- else
- { i_valdrop((&res.ref->second)); }
- res.ref->second = i_valfrom(rmapped);
- }
- return res;
- }
- #endif // !_i_no_clone && !_i_no_emplace
-#endif // !_i_isset
-
-STC_DEF _cx_value*
-_cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out) {
- i_size tn = _csmap_rep(self)->root;
- _cx_node *d = out->_d = self->nodes;
- out->_top = 0;
- while (tn) {
- int c; const _cx_rawkey raw = i_keyto(_i_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
-_cx_memb(_lower_bound)(const _cx_self* self, _cx_rawkey rkey) {
- _cx_iter it;
- _cx_memb(_find_it)(self, rkey, &it);
- if (!it.ref && it._top) {
- i_size tn = it._st[--it._top];
- it._tn = it._d[tn].link[1];
- it.ref = &it._d[tn].value;
- }
- return it;
-}
-
-STC_DEF void
-_cx_memb(_next)(_cx_iter *it) {
- i_size tn = it->_tn;
- if (it->_top || tn) {
- while (tn) {
- it->_st[it->_top++] = tn;
- tn = it->_d[tn].link[0];
- }
- tn = it->_st[--it->_top];
- it->_tn = it->_d[tn].link[1];
- it->ref = &it->_d[tn].value;
- } else
- it->ref = NULL;
-}
-
-STC_DEF i_size
-_cx_memb(_skew_)(_cx_node *d, i_size tn) {
- if (tn && d[d[tn].link[0]].level == d[tn].level) {
- i_size tmp = d[tn].link[0];
- d[tn].link[0] = d[tmp].link[1];
- d[tmp].link[1] = tn;
- tn = tmp;
- }
- return tn;
-}
-
-STC_DEF i_size
-_cx_memb(_split_)(_cx_node *d, i_size tn) {
- if (d[d[d[tn].link[1]].link[1]].level == d[tn].level) {
- i_size 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;
-}
-
-static i_size
-_cx_memb(_insert_entry_i_)(_cx_self* self, i_size tn, const _cx_rawkey* rkey, _cx_result* res) {
- i_size up[64], tx = tn;
- _cx_node* d = self->nodes;
- int c, top = 0, dir = 0;
- while (tx) {
- up[top++] = tx;
- const _cx_rawkey raw = i_keyto(_i_keyref(&d[tx].value));
- if (!(c = i_cmp((&raw), rkey)))
- { res->ref = &d[tx].value; return tn; }
- dir = (c < 0);
- tx = d[tx].link[dir];
- }
- if ((tx = _cx_memb(_new_node_)(self, 1)) == 0)
- { res->nomem_error = true; return 0; }
- 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];
-}
-
-static _cx_result
-_cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey) {
- _cx_result res = {NULL};
- i_size tn = _cx_memb(_insert_entry_i_)(self, (i_size) _csmap_rep(self)->root, &rkey, &res);
- _csmap_rep(self)->root = tn;
- _csmap_rep(self)->size += res.inserted;
- return res;
-}
-
-static i_size
-_cx_memb(_erase_r_)(_cx_node *d, i_size tn, const _cx_rawkey* rkey, int *erased) {
- if (tn == 0)
- return 0;
- _cx_rawkey raw = i_keyto(_i_keyref(&d[tn].value));
- i_size 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_drop)(&d[tn].value);
- if (d[tn].link[0] && d[tn].link[1]) {
- tx = d[tn].link[0];
- while (d[tx].link[1])
- tx = d[tx].link[1];
- d[tn].value = d[tx].value; /* move */
- raw = i_keyto(_i_keyref(&d[tn].value));
- d[tn].link[0] = _cx_memb(_erase_r_)(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_unchecked_container_of(d, struct csmap_rep, nodes);
- d[tx].link[1] = (i_size) 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)(_cx_self* self, _cx_rawkey rkey) {
- int erased = 0;
- i_size root = _cx_memb(_erase_r_)(self->nodes, (i_size) _csmap_rep(self)->root, &rkey, &erased);
- if (erased) {
- _csmap_rep(self)->root = root;
- --_csmap_rep(self)->size;
- return 1;
- }
- return 0;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- _cx_rawkey raw = i_keyto(_i_keyref(it.ref)), nxt;
- _cx_memb(_next)(&it);
- if (it.ref)
- nxt = i_keyto(_i_keyref(it.ref));
- _cx_memb(_erase)(self, raw);
- if (it.ref)
- _cx_memb(_find_it)(self, nxt, &it);
- return it;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
- if (!it2.ref) {
- while (it1.ref)
- it1 = _cx_memb(_erase_at)(self, it1);
- return it1;
- }
- _cx_key k1 = *_i_keyref(it1.ref), k2 = *_i_keyref(it2.ref);
- _cx_rawkey r1 = i_keyto((&k1));
- for (;;) {
- if (memcmp(&k1, &k2, sizeof k1) == 0)
- return it1;
- _cx_memb(_next)(&it1);
- k1 = *_i_keyref(it1.ref);
- _cx_memb(_erase)(self, r1);
- r1 = i_keyto((&k1));
- _cx_memb(_find_it)(self, r1, &it1);
- }
-}
-
-#if !defined _i_no_clone
-static i_size
-_cx_memb(_clone_r_)(_cx_self* self, _cx_node* src, i_size sn) {
- if (sn == 0)
- return 0;
- i_size tx, tn = _cx_memb(_new_node_)(self, src[sn].level);
- self->nodes[tn].value = _cx_memb(_value_clone)(src[sn].value);
- tx = _cx_memb(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx;
- tx = _cx_memb(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx;
- return tn;
-}
-
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self tree) {
- _cx_self clone = _cx_memb(_with_capacity)(_csmap_rep(&tree)->size);
- i_size root = _cx_memb(_clone_r_)(&clone, tree.nodes, (i_size) _csmap_rep(&tree)->root);
- _csmap_rep(&clone)->root = root;
- _csmap_rep(&clone)->size = _csmap_rep(&tree)->size;
- return clone;
-}
-
-#if !defined _i_no_emplace
-STC_DEF _cx_result
-_cx_memb(_emplace)(_cx_self* self, _cx_rawkey rkey _i_MAP_ONLY(, i_valraw rmapped)) {
- _cx_result res = _cx_memb(_insert_entry_)(self, rkey);
- if (res.inserted) {
- *_i_keyref(res.ref) = i_keyfrom(rkey);
- _i_MAP_ONLY(res.ref->second = i_valfrom(rmapped);)
- }
- return res;
-}
-#endif // _i_no_emplace
-#endif // !_i_no_clone
-
-static void
-_cx_memb(_drop_r_)(_cx_node* d, i_size tn) {
- if (tn) {
- _cx_memb(_drop_r_)(d, d[tn].link[0]);
- _cx_memb(_drop_r_)(d, d[tn].link[1]);
- _cx_memb(_value_drop)(&d[tn].value);
- }
-}
-
-STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
- struct csmap_rep* rep = _csmap_rep(self);
- // second test is bogus, but supresses gcc warning:
- if (rep->cap && rep != &_csmap_sentinel) {
- _cx_memb(_drop_r_)(self->nodes, (i_size) rep->root);
- c_free(rep); // correct, but may give warning
- }
-}
-
-#endif // i_implement
-#undef _i_isset
-#undef _i_ismap
-#undef _i_keyref
-#undef _i_MAP_ONLY
-#undef _i_SET_ONLY
-#define CSMAP_H_INCLUDED
-#include "template.h"
-#endif // !STC_CSMAP_V1
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+
+// 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>
+
+int main(void) {
+ c_autovar (csmap_sx m = csmap_sx_init(), csmap_sx_drop(&m))
+ {
+ 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_sx_value *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_sx, m)
+ printf("map %s: %g\n", cstr_str(&i.ref->first), i.ref->second);
+ }
+}
+*/
+#ifdef STC_CSMAP_V1
+#include "alt/csmap.h"
+#else
+#include "ccommon.h"
+
+#ifndef CSMAP_H_INCLUDED
+#include "forward.h"
+#include <stdlib.h>
+#include <string.h>
+
+struct csmap_rep { size_t root, disp, head, size, cap; unsigned nodes[1]; };
+#define _csmap_rep(self) c_unchecked_container_of((self)->nodes, struct csmap_rep, nodes)
+#endif // CSMAP_H_INCLUDED
+
+#ifndef _i_prefix
+#define _i_prefix csmap_
+#endif
+#ifdef _i_isset
+ #define _i_MAP_ONLY c_false
+ #define _i_SET_ONLY c_true
+ #define _i_keyref(vp) (vp)
+#else
+ #define _i_ismap
+ #define _i_MAP_ONLY c_true
+ #define _i_SET_ONLY c_false
+ #define _i_keyref(vp) (&(vp)->first)
+#endif
+#include "template.h"
+
+#if !c_option(c_is_fwd)
+_cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_size, _i_MAP_ONLY, _i_SET_ONLY);
+#endif
+
+_i_MAP_ONLY( struct _cx_value {
+ _cx_key first;
+ _cx_mapped second;
+}; )
+struct _cx_node {
+ i_size link[2];
+ int8_t level;
+ _cx_value value;
+};
+
+typedef i_keyraw _cx_rawkey;
+typedef i_valraw _cx_memb(_rawmapped);
+typedef _i_SET_ONLY( i_keyraw )
+ _i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } )
+ _cx_raw;
+
+#if !defined _i_no_clone
+STC_API _cx_self _cx_memb(_clone)(_cx_self tree);
+#if !defined _i_no_emplace
+STC_API _cx_result _cx_memb(_emplace)(_cx_self* self, _cx_rawkey rkey _i_MAP_ONLY(, i_valraw rmapped));
+#endif // !_i_no_emplace
+#endif // !_i_no_clone
+STC_API _cx_self _cx_memb(_init)(void);
+STC_API _cx_result _cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped));
+STC_API _cx_result _cx_memb(_push)(_cx_self* self, _cx_value _val);
+STC_API void _cx_memb(_drop)(_cx_self* self);
+STC_API bool _cx_memb(_reserve)(_cx_self* self, size_t cap);
+STC_API _cx_value* _cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out);
+STC_API _cx_iter _cx_memb(_lower_bound)(const _cx_self* self, _cx_rawkey rkey);
+STC_API _cx_value* _cx_memb(_front)(const _cx_self* self);
+STC_API _cx_value* _cx_memb(_back)(const _cx_self* self);
+STC_API int _cx_memb(_erase)(_cx_self* self, _cx_rawkey rkey);
+STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it);
+STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2);
+STC_API void _cx_memb(_next)(_cx_iter* it);
+
+STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return _csmap_rep(&cx)->size == 0; }
+STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return _csmap_rep(&cx)->size; }
+STC_INLINE size_t _cx_memb(_capacity)(_cx_self cx) { return _csmap_rep(&cx)->cap; }
+STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); }
+STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, _cx_rawkey rkey)
+ { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); return it; }
+STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_rawkey rkey)
+ { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it) != NULL; }
+STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, _cx_rawkey rkey)
+ { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
+STC_INLINE _cx_value* _cx_memb(_get_mut)(_cx_self* self, _cx_rawkey rkey)
+ { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
+
+STC_INLINE _cx_self
+_cx_memb(_with_capacity)(const size_t cap) {
+ _cx_self tree = _cx_memb(_init)();
+ _cx_memb(_reserve)(&tree, cap);
+ return tree;
+}
+
+STC_INLINE void
+_cx_memb(_clear)(_cx_self* self)
+ { _cx_memb(_drop)(self); *self = _cx_memb(_init)(); }
+
+STC_INLINE _cx_raw
+_cx_memb(_value_toraw)(_cx_value* val) {
+ return _i_SET_ONLY( i_keyto(val) )
+ _i_MAP_ONLY( c_make(_cx_raw){i_keyto((&val->first)),
+ i_valto((&val->second))} );
+}
+
+STC_INLINE int
+_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
+ const _cx_rawkey rx = i_keyto(_i_keyref(x)), ry = i_keyto(_i_keyref(y));
+ return i_cmp((&rx), (&ry));
+}
+
+STC_INLINE void
+_cx_memb(_value_drop)(_cx_value* val) {
+ i_keydrop(_i_keyref(val));
+ _i_MAP_ONLY( i_valdrop((&val->second)); )
+}
+
+#if !defined _i_no_clone
+STC_INLINE _cx_value
+_cx_memb(_value_clone)(_cx_value _val) {
+ *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val)));
+ _i_MAP_ONLY( _val.second = i_valclone(_val.second); )
+ return _val;
+}
+
+STC_INLINE void
+_cx_memb(_copy)(_cx_self *self, _cx_self other) {
+ if (self->nodes == other.nodes)
+ return;
+ _cx_memb(_drop)(self);
+ *self = _cx_memb(_clone)(other);
+}
+
+STC_INLINE void
+_cx_memb(_shrink_to_fit)(_cx_self *self) {
+ _cx_self tmp = _cx_memb(_clone)(*self);
+ _cx_memb(_drop)(self); *self = tmp;
+}
+#endif // !_i_no_clone
+
+#ifndef _i_isset
+ #if !defined _i_no_clone && !defined _i_no_emplace
+ STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped);
+ #endif
+ STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped);
+
+ STC_INLINE const _cx_mapped*
+ _cx_memb(_at)(const _cx_self* self, _cx_rawkey rkey)
+ { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
+ STC_INLINE _cx_mapped*
+ _cx_memb(_at_mut)(_cx_self* self, _cx_rawkey rkey)
+ { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
+#endif // !_i_isset
+
+STC_INLINE _cx_iter
+_cx_memb(_begin)(const _cx_self* self) {
+ _cx_iter it;
+ it._d = self->nodes, it._top = 0;
+ it._tn = (i_size) _csmap_rep(self)->root;
+ if (it._tn)
+ _cx_memb(_next)(&it);
+ return it;
+}
+
+STC_INLINE _cx_iter
+_cx_memb(_end)(const _cx_self* self) {
+ (void)self;
+ _cx_iter it; it.ref = NULL, it._top = 0, it._tn = 0;
+ return it;
+}
+
+STC_INLINE _cx_iter
+_cx_memb(_advance)(_cx_iter it, size_t n) {
+ while (n-- && it.ref)
+ _cx_memb(_next)(&it);
+ return it;
+}
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if defined(i_implement)
+
+#ifndef CSMAP_H_INCLUDED
+static struct csmap_rep _csmap_sentinel = {0, 0, 0, 0, 0};
+#endif
+
+STC_DEF _cx_self
+_cx_memb(_init)(void) {
+ _cx_self tree = {(_cx_node *)_csmap_sentinel.nodes};
+ return tree;
+}
+
+STC_DEF bool
+_cx_memb(_reserve)(_cx_self* self, const size_t cap) {
+ struct csmap_rep* rep = _csmap_rep(self), *oldrep;
+ if (cap >= rep->size) {
+ // second test is bogus, but supresses gcc warning:
+ oldrep = rep->cap && rep != &_csmap_sentinel ? rep : NULL;
+ rep = (struct csmap_rep*) c_realloc(oldrep, offsetof(struct csmap_rep, nodes) +
+ (cap + 1)*sizeof(_cx_node));
+ if (!rep)
+ return false;
+ if (oldrep == NULL)
+ memset(rep, 0, offsetof(struct csmap_rep, nodes) + sizeof(_cx_node));
+ rep->cap = cap;
+ self->nodes = (_cx_node *) rep->nodes;
+ }
+ return true;
+}
+
+STC_DEF _cx_value*
+_cx_memb(_front)(const _cx_self* self) {
+ _cx_node *d = self->nodes;
+ i_size tn = (i_size) _csmap_rep(self)->root;
+ while (d[tn].link[0])
+ tn = d[tn].link[0];
+ return &d[tn].value;
+}
+
+STC_DEF _cx_value*
+_cx_memb(_back)(const _cx_self* self) {
+ _cx_node *d = self->nodes;
+ i_size tn = (i_size) _csmap_rep(self)->root;
+ while (d[tn].link[1])
+ tn = d[tn].link[1];
+ return &d[tn].value;
+}
+
+static i_size
+_cx_memb(_new_node_)(_cx_self* self, int level) {
+ i_size tn; struct csmap_rep *rep = _csmap_rep(self);
+ if (rep->disp) {
+ tn = rep->disp;
+ rep->disp = self->nodes[tn].link[1];
+ } else {
+ if (rep->head == rep->cap)
+ if (!_cx_memb(_reserve)(self, rep->head*3/2 + 4))
+ return 0;
+ tn = ++_csmap_rep(self)->head; /* start with 1, 0 is nullnode. */
+ }
+ _cx_node* dn = &self->nodes[tn];
+ dn->link[0] = dn->link[1] = 0; dn->level = level;
+ return tn;
+}
+
+static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey);
+
+STC_DEF _cx_result
+_cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped)) {
+ _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key)));
+ if (res.inserted)
+ { *_i_keyref(res.ref) = key; _i_MAP_ONLY( res.ref->second = mapped; )}
+ else
+ { i_keydrop((&key)); _i_MAP_ONLY( i_valdrop((&mapped)); )}
+ return res;
+}
+
+STC_DEF _cx_result
+_cx_memb(_push)(_cx_self* self, _cx_value _val) {
+ _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
+ if (_res.inserted)
+ *_res.ref = _val;
+ else
+ _cx_memb(_value_drop)(&_val);
+ return _res;
+}
+
+#ifndef _i_isset
+ STC_DEF _cx_result
+ _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped) {
+ _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key)));
+ if (!res.nomem_error) {
+ if (res.inserted)
+ res.ref->first = key;
+ else
+ { i_keydrop((&key)); i_valdrop((&res.ref->second)); }
+ res.ref->second = mapped;
+ }
+ return res;
+ }
+
+ #if !defined _i_no_clone && !defined _i_no_emplace
+ STC_DEF _cx_result
+ _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped) {
+ _cx_result res = _cx_memb(_insert_entry_)(self, rkey);
+ if (!res.nomem_error) {
+ if (res.inserted)
+ res.ref->first = i_keyfrom(rkey);
+ else
+ { i_valdrop((&res.ref->second)); }
+ res.ref->second = i_valfrom(rmapped);
+ }
+ return res;
+ }
+ #endif // !_i_no_clone && !_i_no_emplace
+#endif // !_i_isset
+
+STC_DEF _cx_value*
+_cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out) {
+ i_size tn = _csmap_rep(self)->root;
+ _cx_node *d = out->_d = self->nodes;
+ out->_top = 0;
+ while (tn) {
+ int c; const _cx_rawkey raw = i_keyto(_i_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
+_cx_memb(_lower_bound)(const _cx_self* self, _cx_rawkey rkey) {
+ _cx_iter it;
+ _cx_memb(_find_it)(self, rkey, &it);
+ if (!it.ref && it._top) {
+ i_size tn = it._st[--it._top];
+ it._tn = it._d[tn].link[1];
+ it.ref = &it._d[tn].value;
+ }
+ return it;
+}
+
+STC_DEF void
+_cx_memb(_next)(_cx_iter *it) {
+ i_size tn = it->_tn;
+ if (it->_top || tn) {
+ while (tn) {
+ it->_st[it->_top++] = tn;
+ tn = it->_d[tn].link[0];
+ }
+ tn = it->_st[--it->_top];
+ it->_tn = it->_d[tn].link[1];
+ it->ref = &it->_d[tn].value;
+ } else
+ it->ref = NULL;
+}
+
+STC_DEF i_size
+_cx_memb(_skew_)(_cx_node *d, i_size tn) {
+ if (tn && d[d[tn].link[0]].level == d[tn].level) {
+ i_size tmp = d[tn].link[0];
+ d[tn].link[0] = d[tmp].link[1];
+ d[tmp].link[1] = tn;
+ tn = tmp;
+ }
+ return tn;
+}
+
+STC_DEF i_size
+_cx_memb(_split_)(_cx_node *d, i_size tn) {
+ if (d[d[d[tn].link[1]].link[1]].level == d[tn].level) {
+ i_size 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;
+}
+
+static i_size
+_cx_memb(_insert_entry_i_)(_cx_self* self, i_size tn, const _cx_rawkey* rkey, _cx_result* res) {
+ i_size up[64], tx = tn;
+ _cx_node* d = self->nodes;
+ int c, top = 0, dir = 0;
+ while (tx) {
+ up[top++] = tx;
+ const _cx_rawkey raw = i_keyto(_i_keyref(&d[tx].value));
+ if (!(c = i_cmp((&raw), rkey)))
+ { res->ref = &d[tx].value; return tn; }
+ dir = (c < 0);
+ tx = d[tx].link[dir];
+ }
+ if ((tx = _cx_memb(_new_node_)(self, 1)) == 0)
+ { res->nomem_error = true; return 0; }
+ 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];
+}
+
+static _cx_result
+_cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey) {
+ _cx_result res = {NULL};
+ i_size tn = _cx_memb(_insert_entry_i_)(self, (i_size) _csmap_rep(self)->root, &rkey, &res);
+ _csmap_rep(self)->root = tn;
+ _csmap_rep(self)->size += res.inserted;
+ return res;
+}
+
+static i_size
+_cx_memb(_erase_r_)(_cx_node *d, i_size tn, const _cx_rawkey* rkey, int *erased) {
+ if (tn == 0)
+ return 0;
+ _cx_rawkey raw = i_keyto(_i_keyref(&d[tn].value));
+ i_size 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_drop)(&d[tn].value);
+ if (d[tn].link[0] && d[tn].link[1]) {
+ tx = d[tn].link[0];
+ while (d[tx].link[1])
+ tx = d[tx].link[1];
+ d[tn].value = d[tx].value; /* move */
+ raw = i_keyto(_i_keyref(&d[tn].value));
+ d[tn].link[0] = _cx_memb(_erase_r_)(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_unchecked_container_of(d, struct csmap_rep, nodes);
+ d[tx].link[1] = (i_size) 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)(_cx_self* self, _cx_rawkey rkey) {
+ int erased = 0;
+ i_size root = _cx_memb(_erase_r_)(self->nodes, (i_size) _csmap_rep(self)->root, &rkey, &erased);
+ if (erased) {
+ _csmap_rep(self)->root = root;
+ --_csmap_rep(self)->size;
+ return 1;
+ }
+ return 0;
+}
+
+STC_DEF _cx_iter
+_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
+ _cx_rawkey raw = i_keyto(_i_keyref(it.ref)), nxt;
+ _cx_memb(_next)(&it);
+ if (it.ref)
+ nxt = i_keyto(_i_keyref(it.ref));
+ _cx_memb(_erase)(self, raw);
+ if (it.ref)
+ _cx_memb(_find_it)(self, nxt, &it);
+ return it;
+}
+
+STC_DEF _cx_iter
+_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
+ if (!it2.ref) {
+ while (it1.ref)
+ it1 = _cx_memb(_erase_at)(self, it1);
+ return it1;
+ }
+ _cx_key k1 = *_i_keyref(it1.ref), k2 = *_i_keyref(it2.ref);
+ _cx_rawkey r1 = i_keyto((&k1));
+ for (;;) {
+ if (memcmp(&k1, &k2, sizeof k1) == 0)
+ return it1;
+ _cx_memb(_next)(&it1);
+ k1 = *_i_keyref(it1.ref);
+ _cx_memb(_erase)(self, r1);
+ r1 = i_keyto((&k1));
+ _cx_memb(_find_it)(self, r1, &it1);
+ }
+}
+
+#if !defined _i_no_clone
+static i_size
+_cx_memb(_clone_r_)(_cx_self* self, _cx_node* src, i_size sn) {
+ if (sn == 0)
+ return 0;
+ i_size tx, tn = _cx_memb(_new_node_)(self, src[sn].level);
+ self->nodes[tn].value = _cx_memb(_value_clone)(src[sn].value);
+ tx = _cx_memb(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx;
+ tx = _cx_memb(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx;
+ return tn;
+}
+
+STC_DEF _cx_self
+_cx_memb(_clone)(_cx_self tree) {
+ _cx_self clone = _cx_memb(_with_capacity)(_csmap_rep(&tree)->size);
+ i_size root = _cx_memb(_clone_r_)(&clone, tree.nodes, (i_size) _csmap_rep(&tree)->root);
+ _csmap_rep(&clone)->root = root;
+ _csmap_rep(&clone)->size = _csmap_rep(&tree)->size;
+ return clone;
+}
+
+#if !defined _i_no_emplace
+STC_DEF _cx_result
+_cx_memb(_emplace)(_cx_self* self, _cx_rawkey rkey _i_MAP_ONLY(, i_valraw rmapped)) {
+ _cx_result res = _cx_memb(_insert_entry_)(self, rkey);
+ if (res.inserted) {
+ *_i_keyref(res.ref) = i_keyfrom(rkey);
+ _i_MAP_ONLY(res.ref->second = i_valfrom(rmapped);)
+ }
+ return res;
+}
+#endif // _i_no_emplace
+#endif // !_i_no_clone
+
+static void
+_cx_memb(_drop_r_)(_cx_node* d, i_size tn) {
+ if (tn) {
+ _cx_memb(_drop_r_)(d, d[tn].link[0]);
+ _cx_memb(_drop_r_)(d, d[tn].link[1]);
+ _cx_memb(_value_drop)(&d[tn].value);
+ }
+}
+
+STC_DEF void
+_cx_memb(_drop)(_cx_self* self) {
+ struct csmap_rep* rep = _csmap_rep(self);
+ // second test is bogus, but supresses gcc warning:
+ if (rep->cap && rep != &_csmap_sentinel) {
+ _cx_memb(_drop_r_)(self->nodes, (i_size) rep->root);
+ c_free(rep); // correct, but may give warning
+ }
+}
+
+#endif // i_implement
+#undef _i_isset
+#undef _i_ismap
+#undef _i_keyref
+#undef _i_MAP_ONLY
+#undef _i_SET_ONLY
+#define CSMAP_H_INCLUDED
+#include "template.h"
+#endif // !STC_CSMAP_V1
diff --git a/include/stc/csset.h b/include/stc/csset.h
index 6fb29845..753ed063 100644
--- a/include/stc/csset.h
+++ b/include/stc/csset.h
@@ -1,49 +1,49 @@
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-
-// Sorted set - implemented as an AA-tree (balanced binary tree).
-/*
-#include <stdio.h>
-
-#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();
- csset_i_insert(&s, 5);
- csset_i_insert(&s, 8);
- csset_i_insert(&s, 3);
- csset_i_insert(&s, 5);
-
- c_foreach (k, csset_i, s)
- printf("set %d\n", *k.ref);
- csset_i_drop(&s);
-}
-*/
-
-#ifndef _i_prefix
-#define _i_prefix csset_
-#endif
-#define _i_isset
-#include "csmap.h"
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+
+// Sorted set - implemented as an AA-tree (balanced binary tree).
+/*
+#include <stdio.h>
+
+#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();
+ csset_i_insert(&s, 5);
+ csset_i_insert(&s, 8);
+ csset_i_insert(&s, 3);
+ csset_i_insert(&s, 5);
+
+ c_foreach (k, csset_i, s)
+ printf("set %d\n", *k.ref);
+ csset_i_drop(&s);
+}
+*/
+
+#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 61d69f0c..52137d33 100644
--- a/include/stc/cstack.h
+++ b/include/stc/cstack.h
@@ -1,150 +1,150 @@
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-#include "ccommon.h"
-
-#ifndef CSTACK_H_INCLUDED
-#define CSTACK_H_INCLUDED
-#include <stdlib.h>
-#include "forward.h"
-#endif // CSTACK_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix cstack_
-#endif
-#include "template.h"
-
-#if !c_option(c_is_fwd)
-_cx_deftypes(_c_cstack_types, _cx_self, i_key);
-#endif
-typedef i_keyraw _cx_raw;
-
-STC_INLINE _cx_self _cx_memb(_init)(void)
- { return c_make(_cx_self){0, 0, 0}; }
-
-STC_INLINE _cx_self _cx_memb(_with_capacity)(size_t cap) {
- _cx_self out = {(_cx_value *) c_malloc(cap*sizeof(i_key)), 0, cap};
- return out;
-}
-
-STC_INLINE _cx_self _cx_memb(_with_size)(size_t size, i_key null) {
- _cx_self out = {(_cx_value *) c_malloc(size*sizeof null), size, size};
- while (size) out.data[--size] = null;
- return out;
-}
-
-STC_INLINE void _cx_memb(_clear)(_cx_self* self) {
- _cx_value *p = self->data + self->size;
- while (p-- != self->data) { i_keydrop(p); }
- self->size = 0;
-}
-
-STC_INLINE void _cx_memb(_drop)(_cx_self* self)
- { _cx_memb(_clear)(self); c_free(self->data); }
-
-STC_INLINE size_t _cx_memb(_size)(_cx_self v)
- { return v.size; }
-
-STC_INLINE bool _cx_memb(_empty)(_cx_self v)
- { return !v.size; }
-
-STC_INLINE size_t _cx_memb(_capacity)(_cx_self v)
- { return v.capacity; }
-
-STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, size_t n) {
- if (n < self->size) return true;
- _cx_value *t = (_cx_value *)c_realloc(self->data, n*sizeof *t);
- if (t) { self->capacity = n, self->data = t; return true; }
- return false;
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_expand_uninit)(_cx_self *self, size_t n) {
- size_t len = self->size;
- if (!_cx_memb(_reserve)(self, len + n)) return NULL;
- self->size += n;
- return self->data + len;
-}
-
-STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self)
- { _cx_memb(_reserve)(self, self->size); }
-
-STC_INLINE _cx_value* _cx_memb(_top)(const _cx_self* self)
- { return &self->data[self->size - 1]; }
-
-STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value val) {
- if (self->size == self->capacity)
- if (!_cx_memb(_reserve)(self, self->size*3/2 + 4))
- return NULL;
- _cx_value* vp = self->data + self->size++;
- *vp = val; return vp;
-}
-STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, _cx_value val)
- { return _cx_memb(_push)(self, val); }
-
-STC_INLINE void _cx_memb(_pop)(_cx_self* self)
- { _cx_value* p = &self->data[--self->size]; i_keydrop(p); }
-STC_INLINE void _cx_memb(_pop_back)(_cx_self* self)
- { _cx_memb(_pop)(self); }
-
-STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, size_t idx)
- { assert(idx < self->size); return self->data + idx; }
-STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, size_t idx)
- { assert(idx < self->size); return self->data + idx; }
-
-#if !defined _i_no_clone
-#if !defined _i_no_emplace
-STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-#endif // !_i_no_emplace
-
-STC_INLINE _cx_self _cx_memb(_clone)(_cx_self v) {
- _cx_self out = {(_cx_value *) c_malloc(v.size*sizeof(_cx_value)), v.size, v.size};
- if (!out.data) out.capacity = 0;
- else for (size_t i = 0; i < v.size; ++v.data)
- out.data[i++] = i_keyclone((*v.data));
- return out;
-}
-
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->data == other.data) return;
- _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other);
-}
-
-STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val)
- { return i_keyclone(val); }
-
-STC_INLINE i_keyraw _cx_memb(_value_toraw)(_cx_value* val)
- { return i_keyto(val); }
-#endif // !_i_no_clone
-
-STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self)
- { return c_make(_cx_iter){self->data}; }
-STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
- { return c_make(_cx_iter){self->data + self->size}; }
-STC_INLINE void _cx_memb(_next)(_cx_iter* it) { ++it->ref; }
-STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t offs)
- { it.ref += offs; return it; }
-
-#include "template.h"
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+#include "ccommon.h"
+
+#ifndef CSTACK_H_INCLUDED
+#define CSTACK_H_INCLUDED
+#include <stdlib.h>
+#include "forward.h"
+#endif // CSTACK_H_INCLUDED
+
+#ifndef _i_prefix
+#define _i_prefix cstack_
+#endif
+#include "template.h"
+
+#if !c_option(c_is_fwd)
+_cx_deftypes(_c_cstack_types, _cx_self, i_key);
+#endif
+typedef i_keyraw _cx_raw;
+
+STC_INLINE _cx_self _cx_memb(_init)(void)
+ { return c_make(_cx_self){0, 0, 0}; }
+
+STC_INLINE _cx_self _cx_memb(_with_capacity)(size_t cap) {
+ _cx_self out = {(_cx_value *) c_malloc(cap*sizeof(i_key)), 0, cap};
+ return out;
+}
+
+STC_INLINE _cx_self _cx_memb(_with_size)(size_t size, i_key null) {
+ _cx_self out = {(_cx_value *) c_malloc(size*sizeof null), size, size};
+ while (size) out.data[--size] = null;
+ return out;
+}
+
+STC_INLINE void _cx_memb(_clear)(_cx_self* self) {
+ _cx_value *p = self->data + self->size;
+ while (p-- != self->data) { i_keydrop(p); }
+ self->size = 0;
+}
+
+STC_INLINE void _cx_memb(_drop)(_cx_self* self)
+ { _cx_memb(_clear)(self); c_free(self->data); }
+
+STC_INLINE size_t _cx_memb(_size)(_cx_self v)
+ { return v.size; }
+
+STC_INLINE bool _cx_memb(_empty)(_cx_self v)
+ { return !v.size; }
+
+STC_INLINE size_t _cx_memb(_capacity)(_cx_self v)
+ { return v.capacity; }
+
+STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, size_t n) {
+ if (n < self->size) return true;
+ _cx_value *t = (_cx_value *)c_realloc(self->data, n*sizeof *t);
+ if (t) { self->capacity = n, self->data = t; return true; }
+ return false;
+}
+
+STC_INLINE _cx_value*
+_cx_memb(_expand_uninit)(_cx_self *self, size_t n) {
+ size_t len = self->size;
+ if (!_cx_memb(_reserve)(self, len + n)) return NULL;
+ self->size += n;
+ return self->data + len;
+}
+
+STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self)
+ { _cx_memb(_reserve)(self, self->size); }
+
+STC_INLINE _cx_value* _cx_memb(_top)(const _cx_self* self)
+ { return &self->data[self->size - 1]; }
+
+STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value val) {
+ if (self->size == self->capacity)
+ if (!_cx_memb(_reserve)(self, self->size*3/2 + 4))
+ return NULL;
+ _cx_value* vp = self->data + self->size++;
+ *vp = val; return vp;
+}
+STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, _cx_value val)
+ { return _cx_memb(_push)(self, val); }
+
+STC_INLINE void _cx_memb(_pop)(_cx_self* self)
+ { _cx_value* p = &self->data[--self->size]; i_keydrop(p); }
+STC_INLINE void _cx_memb(_pop_back)(_cx_self* self)
+ { _cx_memb(_pop)(self); }
+
+STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, size_t idx)
+ { assert(idx < self->size); return self->data + idx; }
+STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, size_t idx)
+ { assert(idx < self->size); return self->data + idx; }
+
+#if !defined _i_no_clone
+#if !defined _i_no_emplace
+STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
+ { return _cx_memb(_push)(self, i_keyfrom(raw)); }
+STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw)
+ { return _cx_memb(_push)(self, i_keyfrom(raw)); }
+#endif // !_i_no_emplace
+
+STC_INLINE _cx_self _cx_memb(_clone)(_cx_self v) {
+ _cx_self out = {(_cx_value *) c_malloc(v.size*sizeof(_cx_value)), v.size, v.size};
+ if (!out.data) out.capacity = 0;
+ else for (size_t i = 0; i < v.size; ++v.data)
+ out.data[i++] = i_keyclone((*v.data));
+ return out;
+}
+
+STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
+ if (self->data == other.data) return;
+ _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other);
+}
+
+STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val)
+ { return i_keyclone(val); }
+
+STC_INLINE i_keyraw _cx_memb(_value_toraw)(_cx_value* val)
+ { return i_keyto(val); }
+#endif // !_i_no_clone
+
+STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self)
+ { return c_make(_cx_iter){self->data}; }
+STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
+ { return c_make(_cx_iter){self->data + self->size}; }
+STC_INLINE void _cx_memb(_next)(_cx_iter* it) { ++it->ref; }
+STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter 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 7dabd0c0..b33faf43 100644
--- a/include/stc/cstr.h
+++ b/include/stc/cstr.h
@@ -1,555 +1,555 @@
-/* MIT License
- *
- * Copyright (c) 2022 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).
- */
-#ifdef STC_CSTR_V1
-#include "alt/cstr.h"
-#else
-#ifndef CSTR_H_INCLUDED
-#define CSTR_H_INCLUDED
-
-#define i_header
-#include "ccommon.h"
-#include "forward.h"
-#include "utf8.h"
-#include <stdlib.h> /* malloc */
-#include <stdarg.h>
-#include <stdio.h> /* vsnprintf */
-#include <ctype.h>
-
-/**************************** PRIVATE API **********************************/
-
-#if defined __GNUC__ && !defined __clang__
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Warray-bounds"
-# pragma GCC diagnostic ignored "-Wstringop-overflow="
-#endif
-
-enum { cstr_s_cap = sizeof(cstr_buf) - 1 };
-#define cstr_s_size(s) ((size_t)(cstr_s_cap - (s)->sml.last))
-#define cstr_s_set_size(s, len) ((s)->sml.last = cstr_s_cap - (len), (s)->sml.data[len] = 0)
-#define cstr_s_data(s) (s)->sml.data
-#define cstr_s_end(s) ((s)->sml.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_drop(s) c_free((s)->lon.data)
-
-#define cstr_is_long(s) ((s)->sml.last > 127)
-STC_API char* _cstr_init(cstr* self, size_t len, size_t cap);
-STC_API char* _cstr_internal_move(cstr* self, size_t pos1, size_t pos2);
-
-/**************************** PUBLIC API **********************************/
-
-#define cstr_new(literal) cstr_from_n(literal, c_strlen_lit(literal))
-#define cstr_npos (SIZE_MAX >> 1)
-#define cstr_null (c_make(cstr){.sml = {.last = cstr_s_cap}})
-#define cstr_toraw(self) cstr_str(self)
-
-STC_API char* cstr_reserve(cstr* self, size_t cap);
-STC_API void cstr_shrink_to_fit(cstr* self);
-STC_API void cstr_resize(cstr* self, size_t size, char value);
-STC_API size_t cstr_find_from(cstr s, size_t pos, const char* search);
-STC_API char* cstr_assign_n(cstr* self, const char* str, size_t n);
-STC_API char* cstr_append_n(cstr* self, const char* str, 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_API cstr cstr_from_fmt(const char* fmt, ...);
-STC_API int cstr_printf(cstr* self, const char* fmt, ...);
-STC_API void cstr_replace_all(cstr* self, const char* search, const char* repl);
-
-STC_INLINE cstr_buf cstr_buffer(cstr* s) {
- return cstr_is_long(s)
- ? c_make(cstr_buf){s->lon.data, cstr_l_size(s), cstr_l_cap(s)}
- : c_make(cstr_buf){s->sml.data, cstr_s_size(s), cstr_s_cap};
-}
-STC_INLINE csview cstr_sv(const cstr* s) {
- return cstr_is_long(s) ? c_make(csview){s->lon.data, cstr_l_size(s)}
- : c_make(csview){s->sml.data, cstr_s_size(s)};
-}
-
-STC_INLINE cstr cstr_init(void)
- { return cstr_null; }
-
-STC_INLINE cstr cstr_from_n(const char* str, const 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(const size_t size, const char value) {
- cstr s;
- memset(_cstr_init(&s, size, size), value, size);
- return s;
-}
-
-STC_INLINE cstr cstr_with_capacity(const size_t cap) {
- cstr s;
- _cstr_init(&s, 0, cap);
- return s;
-}
-
-STC_INLINE cstr* cstr_take(cstr* self, const cstr s) {
- if (cstr_is_long(self) && self->lon.data != s.lon.data)
- cstr_l_drop(self);
- *self = s;
- return self;
-}
-
-STC_INLINE cstr cstr_move(cstr* self) {
- cstr tmp = *self;
- *self = cstr_null;
- return tmp;
-}
-
-STC_INLINE cstr cstr_clone(cstr s) {
- csview sv = cstr_sv(&s);
- return cstr_from_n(sv.str, sv.size);
-}
-
-STC_INLINE void cstr_drop(cstr* self) {
- if (cstr_is_long(self))
- cstr_l_drop(self);
-}
-
-#define SSO_CALL(s, call) (cstr_is_long(s) ? cstr_l_##call : cstr_s_##call)
-
-STC_INLINE void _cstr_set_size(cstr* self, size_t len)
- { SSO_CALL(self, set_size(self, len)); }
-
-STC_INLINE char* cstr_data(cstr* self)
- { return SSO_CALL(self, data(self)); }
-
-STC_INLINE const char* cstr_str(const cstr* self)
- { return SSO_CALL(self, data(self)); }
-
-STC_INLINE bool cstr_empty(cstr s)
- { return s.sml.last == cstr_s_cap; }
-
-STC_INLINE size_t cstr_size(cstr s)
- { return SSO_CALL(&s, size(&s)); }
-
-STC_INLINE size_t cstr_length(cstr s)
- { return SSO_CALL(&s, size(&s)); }
-
-STC_INLINE size_t cstr_capacity(cstr s)
- { return cstr_is_long(&s) ? cstr_l_cap(&s) : cstr_s_cap; }
-
-// utf8 methods defined in/depending on src/utf8code.c:
-
-extern cstr cstr_tolower(const cstr* self);
-extern cstr cstr_toupper(const cstr* self);
-extern void cstr_lowercase(cstr* self);
-extern void cstr_uppercase(cstr* self);
-
-STC_INLINE bool cstr_valid_u8(const cstr* self)
- { return utf8_valid(cstr_str(self)); }
-
-// other utf8
-
-STC_INLINE size_t cstr_size_u8(cstr s)
- { return utf8_size(cstr_str(&s)); }
-
-STC_INLINE size_t cstr_size_n_u8(cstr s, size_t nbytes)
- { return utf8_size_n(cstr_str(&s), nbytes); }
-
-STC_INLINE csview cstr_at(const cstr* self, size_t bytepos) {
- csview sv = cstr_sv(self);
- sv.str += bytepos;
- sv.size = utf8_codep_size(sv.str);
- return sv;
-}
-
-STC_INLINE csview cstr_at_u8(const cstr* self, size_t u8idx) {
- csview sv = cstr_sv(self);
- sv.str = utf8_at(sv.str, u8idx);
- sv.size = utf8_codep_size(sv.str);
- return sv;
-}
-
-STC_INLINE size_t cstr_pos_u8(const cstr* self, size_t u8idx)
- { return utf8_pos(cstr_str(self), u8idx); }
-
-// utf8 iterator
-
-STC_INLINE cstr_iter cstr_begin(const cstr* self) {
- const char* str = cstr_str(self);
- return c_make(cstr_iter){.chr = {str, utf8_codep_size(str)}};
-}
-STC_INLINE cstr_iter cstr_end(const cstr* self) {
- csview sv = cstr_sv(self);
- return c_make(cstr_iter){sv.str + sv.size};
-}
-STC_INLINE void cstr_next(cstr_iter* it) {
- it->ref += it->chr.size;
- it->chr.size = utf8_codep_size(it->ref);
-}
-
-
-STC_INLINE void cstr_clear(cstr* self)
- { _cstr_set_size(self, 0); }
-
-STC_INLINE char* cstr_expand_uninit(cstr *self, size_t n) {
- size_t len = cstr_size(*self); char* d;
- if (!(d = cstr_reserve(self, len + n))) return NULL;
- _cstr_set_size(self, len + n);
- return d + len;
-}
-
-STC_INLINE int cstr_cmp(const cstr* s1, const cstr* s2)
- { return strcmp(cstr_str(s1), cstr_str(s2)); }
-
-STC_INLINE int cstr_icmp(const cstr* s1, const cstr* s2)
- { return utf8_icmp(cstr_str(s1), cstr_str(s2)); }
-
-STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) {
- csview x = cstr_sv(s1), y = cstr_sv(s2);
- return x.size == y.size && !memcmp(x.str, y.str, x.size);
-}
-
-STC_INLINE bool cstr_equals(cstr s1, const char* str)
- { return !strcmp(cstr_str(&s1), str); }
-
-STC_INLINE bool cstr_iequals(cstr s1, const char* str)
- { return !utf8_icmp(cstr_str(&s1), str); }
-
-STC_INLINE bool cstr_equals_s(cstr s1, cstr s2)
- { return !cstr_cmp(&s1, &s2); }
-
-STC_INLINE size_t cstr_find(cstr s, const char* search) {
- const char *str = cstr_str(&s), *res = strstr((char*)str, search);
- return res ? res - str : cstr_npos;
-}
-
-STC_INLINE size_t cstr_find_s(cstr s, cstr search)
- { return cstr_find(s, cstr_str(&search)); }
-
-STC_INLINE bool cstr_contains(cstr s, const char* search)
- { return strstr(cstr_data(&s), search) != NULL; }
-
-STC_INLINE bool cstr_contains_s(cstr s, cstr search)
- { return strstr(cstr_data(&s), cstr_str(&search)) != 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;
-}
-STC_INLINE bool cstr_istarts_with(cstr s, const char* sub) {
- csview sv = cstr_sv(&s);
- size_t n = strlen(sub);
- return n <= sv.size && !utf8_icmp_n(cstr_npos, sv.str, sv.size, sub, n);
-}
-
-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) {
- csview sv = cstr_sv(&s);
- size_t n = strlen(sub);
- return n <= sv.size && !memcmp(sv.str + sv.size - n, sub, n);
-}
-
-STC_INLINE bool cstr_iends_with(cstr s, const char* sub) {
- csview sv = cstr_sv(&s);
- size_t n = strlen(sub);
- return n <= sv.size && !utf8_icmp(sv.str + sv.size - n, sub);
-}
-
-STC_INLINE bool cstr_ends_with_s(cstr s, cstr sub)
- { return cstr_ends_with(s, cstr_str(&sub)); }
-
-STC_INLINE char* cstr_assign(cstr* self, const char* str)
- { return cstr_assign_n(self, str, strlen(str)); }
-
-STC_INLINE char* cstr_assign_s(cstr* self, cstr s) {
- csview sv = cstr_sv(&s);
- return cstr_assign_n(self, sv.str, sv.size);
-}
-
-STC_INLINE void cstr_copy(cstr* self, cstr s)
- { cstr_assign_s(self, s); }
-
-STC_INLINE char* cstr_append(cstr* self, const char* str)
- { return cstr_append_n(self, str, strlen(str)); }
-
-STC_INLINE char* cstr_append_s(cstr* self, cstr s) {
- csview sv = cstr_sv(&s);
- return cstr_append_n(self, sv.str, sv.size);
-}
-
-STC_INLINE void cstr_replace_n(cstr* self, size_t pos, size_t len, const char* repl, size_t n) {
- char* d = _cstr_internal_move(self, pos + len, pos + n);
- memcpy(d + pos, repl, n);
-}
-
-STC_INLINE void cstr_replace(cstr* self, size_t pos, size_t len, const char* repl)
- { cstr_replace_n(self, pos, len, repl, strlen(repl)); }
-
-STC_INLINE size_t cstr_replace_one(cstr* self, size_t pos, const char* search, const char* repl) {
- pos = cstr_find_from(*self, pos, search);
- if (pos == cstr_npos)
- return pos;
- const size_t rlen = strlen(repl);
- cstr_replace_n(self, pos, strlen(search), repl, rlen);
- return pos + rlen;
-}
-
-STC_INLINE void cstr_replace_s(cstr* self, size_t pos, size_t len, cstr s) {
- csview sv = cstr_sv(&s);
- cstr_replace_n(self, pos, len, sv.str, sv.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) {
- csview sv = cstr_sv(&s);
- cstr_replace_n(self, pos, 0, sv.str, sv.size);
-}
-
-STC_INLINE bool cstr_getline(cstr *self, FILE *fp)
- { return cstr_getdelim(self, '\n', fp); }
-
-STC_INLINE uint64_t cstr_hash(const cstr *self) {
- csview sv = cstr_sv(self);
- return c_fasthash(sv.str, sv.size);
-}
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-STC_DEF char* _cstr_internal_move(cstr* self, const size_t pos1, const size_t pos2) {
- cstr_buf r = cstr_buffer(self);
- if (pos1 != pos2) {
- const size_t newlen = r.size + pos2 - pos1;
- if (newlen > r.cap)
- r.data = cstr_reserve(self, (r.size*3 >> 1) + pos2 - pos1);
- memmove(&r.data[pos2], &r.data[pos1], r.size - pos1);
- _cstr_set_size(self, newlen);
- }
- return r.data;
-}
-
-STC_DEF char* _cstr_init(cstr* self, const size_t len, const size_t cap) {
- if (cap > cstr_s_cap) {
- self->lon.data = (char *)c_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->sml.data;
-}
-
-STC_DEF void cstr_shrink_to_fit(cstr* self) {
- cstr_buf r = cstr_buffer(self);
- if (r.size == r.cap)
- return;
- if (r.size > cstr_s_cap) {
- self->lon.data = (char *)c_realloc(self->lon.data, r.size + 1);
- cstr_l_set_cap(self, r.size);
- } else if (r.cap > cstr_s_cap) {
- memcpy(self->sml.data, r.data, r.size + 1);
- cstr_s_set_size(self, r.size);
- c_free(r.data);
- }
-}
-
-STC_DEF char* cstr_reserve(cstr* self, const size_t cap) {
- if (cstr_is_long(self)) {
- if (cap > cstr_l_cap(self)) {
- self->lon.data = (char *)c_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) {
- char* data = (char *)c_malloc(cap + 1);
- const size_t len = cstr_s_size(self);
- memcpy(data, self->sml.data, len);
- self->lon.data = data;
- cstr_l_set_size(self, len);
- cstr_l_set_cap(self, cap);
- return data;
- }
- return self->sml.data;
-}
-
-STC_DEF void cstr_resize(cstr* self, const size_t size, const char value) {
- cstr_buf r = cstr_buffer(self);
- if (size > r.size) {
- if (size > r.cap) r.data = cstr_reserve(self, size);
- memset(r.data + r.size, value, size - r.size);
- }
- _cstr_set_size(self, size);
-}
-
-STC_DEF size_t cstr_find_from(cstr s, const size_t pos, const char* search) {
- csview sv = cstr_sv(&s);
- if (pos > sv.size) return cstr_npos;
- const char* res = strstr((char*)sv.str + pos, search);
- return res ? res - sv.str : cstr_npos;
-}
-
-STC_DEF char* cstr_assign_n(cstr* self, const char* str, const size_t n) {
- char* d = cstr_reserve(self, n);
- memmove(d, str, n);
- _cstr_set_size(self, n);
- return d;
-}
-
-STC_DEF char* cstr_append_n(cstr* self, const char* str, const size_t n) {
- cstr_buf r = cstr_buffer(self);
- if (r.size + n > r.cap) {
- const size_t off = (size_t)(str - r.data);
- r.data = cstr_reserve(self, (r.size*3 >> 1) + n);
- if (off <= r.size) str = r.data + off; /* handle self append */
- }
- memcpy(r.data + r.size, str, n);
- _cstr_set_size(self, r.size + n);
- return r.data;
-}
-
-STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) {
- int c = fgetc(fp);
- if (c == EOF)
- return false;
- size_t pos = 0;
- cstr_buf r = cstr_buffer(self);
- for (;;) {
- if (c == delim || c == EOF) {
- _cstr_set_size(self, pos);
- return true;
- }
- if (pos == r.cap) {
- _cstr_set_size(self, pos);
- r.data = cstr_reserve(self, (r.cap = (r.cap*3 >> 1) + 16));
- }
- r.data[pos++] = (char) c;
- c = fgetc(fp);
- }
-}
-
-STC_DEF cstr
-cstr_from_replace_all(const char* str, const size_t str_len,
- const char* search, const size_t search_len,
- const char* repl, const size_t repl_len) {
- cstr out = cstr_null;
- size_t from = 0; char* res;
- if (search_len)
- while ((res = c_strnstrn(str + from, search, str_len - from, search_len))) {
- const size_t pos = res - str;
- cstr_append_n(&out, str + from, pos - from);
- cstr_append_n(&out, repl, repl_len);
- from = pos + search_len;
- }
- cstr_append_n(&out, str + from, str_len - from);
- return out;
-}
-
-STC_DEF void
-cstr_replace_all(cstr* self, const char* search, const char* repl) {
- csview sv = cstr_sv(self);
- cstr_take(self, cstr_from_replace_all(sv.str, sv.size, search, strlen(search),
- repl, strlen(repl)));
-}
-
-STC_DEF void cstr_erase_n(cstr* self, const size_t pos, size_t n) {
- cstr_buf r = cstr_buffer(self);
- if (n > r.size - pos) n = r.size - pos;
- memmove(&r.data[pos], &r.data[pos + n], r.size - (pos + n));
- _cstr_set_size(self, r.size - n);
-}
-
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wdeprecated-declarations"
-#elif defined(_MSC_VER)
-# pragma warning(push)
-# pragma warning(disable: 4996)
-#endif
-
-STC_DEF int cstr_vfmt(cstr* self, const char* fmt, va_list args) {
- va_list args2;
- va_copy(args2, args);
- const int n = vsnprintf(NULL, (size_t)0, fmt, args);
- cstr_reserve(self, n);
- vsprintf(cstr_data(self), fmt, args2);
- va_end(args2);
- _cstr_set_size(self, n);
- return n;
-}
-#if defined(__clang__)
-# pragma clang diagnostic pop
-#elif defined(_MSC_VER)
-# pragma warning(pop)
-#endif
-
-STC_DEF cstr cstr_from_fmt(const char* fmt, ...) {
- cstr s = cstr_null;
- va_list args; va_start(args, fmt);
- cstr_vfmt(&s, fmt, args);
- va_end(args);
- return s;
-}
-
-STC_DEF int cstr_printf(cstr* self, const char* fmt, ...) {
- cstr s = cstr_null;
- va_list args; va_start(args, fmt);
- const int n = cstr_vfmt(&s, fmt, args);
- va_end(args);
- cstr_drop(self); *self = s;
- return n;
-}
-
-#endif // i_implement
-#if defined __GNUC__ && !defined __clang__
-# pragma GCC diagnostic pop
-#endif
-#endif // CSTR_H_INCLUDED
-#undef i_opt
-#undef i_header
-#undef i_static
-#undef i_implement
-#undef i_extern
-#endif // !STC_CSTR_V1
+/* MIT License
+ *
+ * Copyright (c) 2022 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).
+ */
+#ifdef STC_CSTR_V1
+#include "alt/cstr.h"
+#else
+#ifndef CSTR_H_INCLUDED
+#define CSTR_H_INCLUDED
+
+#define i_header
+#include "ccommon.h"
+#include "forward.h"
+#include "utf8.h"
+#include <stdlib.h> /* malloc */
+#include <stdarg.h>
+#include <stdio.h> /* vsnprintf */
+#include <ctype.h>
+
+/**************************** PRIVATE API **********************************/
+
+#if defined __GNUC__ && !defined __clang__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Warray-bounds"
+# pragma GCC diagnostic ignored "-Wstringop-overflow="
+#endif
+
+enum { cstr_s_cap = sizeof(cstr_buf) - 1 };
+#define cstr_s_size(s) ((size_t)(cstr_s_cap - (s)->sml.last))
+#define cstr_s_set_size(s, len) ((s)->sml.last = cstr_s_cap - (len), (s)->sml.data[len] = 0)
+#define cstr_s_data(s) (s)->sml.data
+#define cstr_s_end(s) ((s)->sml.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_drop(s) c_free((s)->lon.data)
+
+#define cstr_is_long(s) ((s)->sml.last > 127)
+STC_API char* _cstr_init(cstr* self, size_t len, size_t cap);
+STC_API char* _cstr_internal_move(cstr* self, size_t pos1, size_t pos2);
+
+/**************************** PUBLIC API **********************************/
+
+#define cstr_new(literal) cstr_from_n(literal, c_strlen_lit(literal))
+#define cstr_npos (SIZE_MAX >> 1)
+#define cstr_null (c_make(cstr){.sml = {.last = cstr_s_cap}})
+#define cstr_toraw(self) cstr_str(self)
+
+STC_API char* cstr_reserve(cstr* self, size_t cap);
+STC_API void cstr_shrink_to_fit(cstr* self);
+STC_API void cstr_resize(cstr* self, size_t size, char value);
+STC_API size_t cstr_find_from(cstr s, size_t pos, const char* search);
+STC_API char* cstr_assign_n(cstr* self, const char* str, size_t n);
+STC_API char* cstr_append_n(cstr* self, const char* str, 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_API cstr cstr_from_fmt(const char* fmt, ...);
+STC_API int cstr_printf(cstr* self, const char* fmt, ...);
+STC_API void cstr_replace_all(cstr* self, const char* search, const char* repl);
+
+STC_INLINE cstr_buf cstr_buffer(cstr* s) {
+ return cstr_is_long(s)
+ ? c_make(cstr_buf){s->lon.data, cstr_l_size(s), cstr_l_cap(s)}
+ : c_make(cstr_buf){s->sml.data, cstr_s_size(s), cstr_s_cap};
+}
+STC_INLINE csview cstr_sv(const cstr* s) {
+ return cstr_is_long(s) ? c_make(csview){s->lon.data, cstr_l_size(s)}
+ : c_make(csview){s->sml.data, cstr_s_size(s)};
+}
+
+STC_INLINE cstr cstr_init(void)
+ { return cstr_null; }
+
+STC_INLINE cstr cstr_from_n(const char* str, const 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(const size_t size, const char value) {
+ cstr s;
+ memset(_cstr_init(&s, size, size), value, size);
+ return s;
+}
+
+STC_INLINE cstr cstr_with_capacity(const size_t cap) {
+ cstr s;
+ _cstr_init(&s, 0, cap);
+ return s;
+}
+
+STC_INLINE cstr* cstr_take(cstr* self, const cstr s) {
+ if (cstr_is_long(self) && self->lon.data != s.lon.data)
+ cstr_l_drop(self);
+ *self = s;
+ return self;
+}
+
+STC_INLINE cstr cstr_move(cstr* self) {
+ cstr tmp = *self;
+ *self = cstr_null;
+ return tmp;
+}
+
+STC_INLINE cstr cstr_clone(cstr s) {
+ csview sv = cstr_sv(&s);
+ return cstr_from_n(sv.str, sv.size);
+}
+
+STC_INLINE void cstr_drop(cstr* self) {
+ if (cstr_is_long(self))
+ cstr_l_drop(self);
+}
+
+#define SSO_CALL(s, call) (cstr_is_long(s) ? cstr_l_##call : cstr_s_##call)
+
+STC_INLINE void _cstr_set_size(cstr* self, size_t len)
+ { SSO_CALL(self, set_size(self, len)); }
+
+STC_INLINE char* cstr_data(cstr* self)
+ { return SSO_CALL(self, data(self)); }
+
+STC_INLINE const char* cstr_str(const cstr* self)
+ { return SSO_CALL(self, data(self)); }
+
+STC_INLINE bool cstr_empty(cstr s)
+ { return s.sml.last == cstr_s_cap; }
+
+STC_INLINE size_t cstr_size(cstr s)
+ { return SSO_CALL(&s, size(&s)); }
+
+STC_INLINE size_t cstr_length(cstr s)
+ { return SSO_CALL(&s, size(&s)); }
+
+STC_INLINE size_t cstr_capacity(cstr s)
+ { return cstr_is_long(&s) ? cstr_l_cap(&s) : cstr_s_cap; }
+
+// utf8 methods defined in/depending on src/utf8code.c:
+
+extern cstr cstr_tolower(const cstr* self);
+extern cstr cstr_toupper(const cstr* self);
+extern void cstr_lowercase(cstr* self);
+extern void cstr_uppercase(cstr* self);
+
+STC_INLINE bool cstr_valid_u8(const cstr* self)
+ { return utf8_valid(cstr_str(self)); }
+
+// other utf8
+
+STC_INLINE size_t cstr_size_u8(cstr s)
+ { return utf8_size(cstr_str(&s)); }
+
+STC_INLINE size_t cstr_size_n_u8(cstr s, size_t nbytes)
+ { return utf8_size_n(cstr_str(&s), nbytes); }
+
+STC_INLINE csview cstr_at(const cstr* self, size_t bytepos) {
+ csview sv = cstr_sv(self);
+ sv.str += bytepos;
+ sv.size = utf8_codep_size(sv.str);
+ return sv;
+}
+
+STC_INLINE csview cstr_at_u8(const cstr* self, size_t u8idx) {
+ csview sv = cstr_sv(self);
+ sv.str = utf8_at(sv.str, u8idx);
+ sv.size = utf8_codep_size(sv.str);
+ return sv;
+}
+
+STC_INLINE size_t cstr_pos_u8(const cstr* self, size_t u8idx)
+ { return utf8_pos(cstr_str(self), u8idx); }
+
+// utf8 iterator
+
+STC_INLINE cstr_iter cstr_begin(const cstr* self) {
+ const char* str = cstr_str(self);
+ return c_make(cstr_iter){.chr = {str, utf8_codep_size(str)}};
+}
+STC_INLINE cstr_iter cstr_end(const cstr* self) {
+ csview sv = cstr_sv(self);
+ return c_make(cstr_iter){sv.str + sv.size};
+}
+STC_INLINE void cstr_next(cstr_iter* it) {
+ it->ref += it->chr.size;
+ it->chr.size = utf8_codep_size(it->ref);
+}
+
+
+STC_INLINE void cstr_clear(cstr* self)
+ { _cstr_set_size(self, 0); }
+
+STC_INLINE char* cstr_expand_uninit(cstr *self, size_t n) {
+ size_t len = cstr_size(*self); char* d;
+ if (!(d = cstr_reserve(self, len + n))) return NULL;
+ _cstr_set_size(self, len + n);
+ return d + len;
+}
+
+STC_INLINE int cstr_cmp(const cstr* s1, const cstr* s2)
+ { return strcmp(cstr_str(s1), cstr_str(s2)); }
+
+STC_INLINE int cstr_icmp(const cstr* s1, const cstr* s2)
+ { return utf8_icmp(cstr_str(s1), cstr_str(s2)); }
+
+STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) {
+ csview x = cstr_sv(s1), y = cstr_sv(s2);
+ return x.size == y.size && !memcmp(x.str, y.str, x.size);
+}
+
+STC_INLINE bool cstr_equals(cstr s1, const char* str)
+ { return !strcmp(cstr_str(&s1), str); }
+
+STC_INLINE bool cstr_iequals(cstr s1, const char* str)
+ { return !utf8_icmp(cstr_str(&s1), str); }
+
+STC_INLINE bool cstr_equals_s(cstr s1, cstr s2)
+ { return !cstr_cmp(&s1, &s2); }
+
+STC_INLINE size_t cstr_find(cstr s, const char* search) {
+ const char *str = cstr_str(&s), *res = strstr((char*)str, search);
+ return res ? res - str : cstr_npos;
+}
+
+STC_INLINE size_t cstr_find_s(cstr s, cstr search)
+ { return cstr_find(s, cstr_str(&search)); }
+
+STC_INLINE bool cstr_contains(cstr s, const char* search)
+ { return strstr(cstr_data(&s), search) != NULL; }
+
+STC_INLINE bool cstr_contains_s(cstr s, cstr search)
+ { return strstr(cstr_data(&s), cstr_str(&search)) != 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;
+}
+STC_INLINE bool cstr_istarts_with(cstr s, const char* sub) {
+ csview sv = cstr_sv(&s);
+ size_t n = strlen(sub);
+ return n <= sv.size && !utf8_icmp_n(cstr_npos, sv.str, sv.size, sub, n);
+}
+
+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) {
+ csview sv = cstr_sv(&s);
+ size_t n = strlen(sub);
+ return n <= sv.size && !memcmp(sv.str + sv.size - n, sub, n);
+}
+
+STC_INLINE bool cstr_iends_with(cstr s, const char* sub) {
+ csview sv = cstr_sv(&s);
+ size_t n = strlen(sub);
+ return n <= sv.size && !utf8_icmp(sv.str + sv.size - n, sub);
+}
+
+STC_INLINE bool cstr_ends_with_s(cstr s, cstr sub)
+ { return cstr_ends_with(s, cstr_str(&sub)); }
+
+STC_INLINE char* cstr_assign(cstr* self, const char* str)
+ { return cstr_assign_n(self, str, strlen(str)); }
+
+STC_INLINE char* cstr_assign_s(cstr* self, cstr s) {
+ csview sv = cstr_sv(&s);
+ return cstr_assign_n(self, sv.str, sv.size);
+}
+
+STC_INLINE void cstr_copy(cstr* self, cstr s)
+ { cstr_assign_s(self, s); }
+
+STC_INLINE char* cstr_append(cstr* self, const char* str)
+ { return cstr_append_n(self, str, strlen(str)); }
+
+STC_INLINE char* cstr_append_s(cstr* self, cstr s) {
+ csview sv = cstr_sv(&s);
+ return cstr_append_n(self, sv.str, sv.size);
+}
+
+STC_INLINE void cstr_replace_n(cstr* self, size_t pos, size_t len, const char* repl, size_t n) {
+ char* d = _cstr_internal_move(self, pos + len, pos + n);
+ memcpy(d + pos, repl, n);
+}
+
+STC_INLINE void cstr_replace(cstr* self, size_t pos, size_t len, const char* repl)
+ { cstr_replace_n(self, pos, len, repl, strlen(repl)); }
+
+STC_INLINE size_t cstr_replace_one(cstr* self, size_t pos, const char* search, const char* repl) {
+ pos = cstr_find_from(*self, pos, search);
+ if (pos == cstr_npos)
+ return pos;
+ const size_t rlen = strlen(repl);
+ cstr_replace_n(self, pos, strlen(search), repl, rlen);
+ return pos + rlen;
+}
+
+STC_INLINE void cstr_replace_s(cstr* self, size_t pos, size_t len, cstr s) {
+ csview sv = cstr_sv(&s);
+ cstr_replace_n(self, pos, len, sv.str, sv.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) {
+ csview sv = cstr_sv(&s);
+ cstr_replace_n(self, pos, 0, sv.str, sv.size);
+}
+
+STC_INLINE bool cstr_getline(cstr *self, FILE *fp)
+ { return cstr_getdelim(self, '\n', fp); }
+
+STC_INLINE uint64_t cstr_hash(const cstr *self) {
+ csview sv = cstr_sv(self);
+ return c_fasthash(sv.str, sv.size);
+}
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if defined(i_implement)
+
+STC_DEF char* _cstr_internal_move(cstr* self, const size_t pos1, const size_t pos2) {
+ cstr_buf r = cstr_buffer(self);
+ if (pos1 != pos2) {
+ const size_t newlen = r.size + pos2 - pos1;
+ if (newlen > r.cap)
+ r.data = cstr_reserve(self, (r.size*3 >> 1) + pos2 - pos1);
+ memmove(&r.data[pos2], &r.data[pos1], r.size - pos1);
+ _cstr_set_size(self, newlen);
+ }
+ return r.data;
+}
+
+STC_DEF char* _cstr_init(cstr* self, const size_t len, const size_t cap) {
+ if (cap > cstr_s_cap) {
+ self->lon.data = (char *)c_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->sml.data;
+}
+
+STC_DEF void cstr_shrink_to_fit(cstr* self) {
+ cstr_buf r = cstr_buffer(self);
+ if (r.size == r.cap)
+ return;
+ if (r.size > cstr_s_cap) {
+ self->lon.data = (char *)c_realloc(self->lon.data, r.size + 1);
+ cstr_l_set_cap(self, r.size);
+ } else if (r.cap > cstr_s_cap) {
+ memcpy(self->sml.data, r.data, r.size + 1);
+ cstr_s_set_size(self, r.size);
+ c_free(r.data);
+ }
+}
+
+STC_DEF char* cstr_reserve(cstr* self, const size_t cap) {
+ if (cstr_is_long(self)) {
+ if (cap > cstr_l_cap(self)) {
+ self->lon.data = (char *)c_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) {
+ char* data = (char *)c_malloc(cap + 1);
+ const size_t len = cstr_s_size(self);
+ memcpy(data, self->sml.data, len);
+ self->lon.data = data;
+ cstr_l_set_size(self, len);
+ cstr_l_set_cap(self, cap);
+ return data;
+ }
+ return self->sml.data;
+}
+
+STC_DEF void cstr_resize(cstr* self, const size_t size, const char value) {
+ cstr_buf r = cstr_buffer(self);
+ if (size > r.size) {
+ if (size > r.cap) r.data = cstr_reserve(self, size);
+ memset(r.data + r.size, value, size - r.size);
+ }
+ _cstr_set_size(self, size);
+}
+
+STC_DEF size_t cstr_find_from(cstr s, const size_t pos, const char* search) {
+ csview sv = cstr_sv(&s);
+ if (pos > sv.size) return cstr_npos;
+ const char* res = strstr((char*)sv.str + pos, search);
+ return res ? res - sv.str : cstr_npos;
+}
+
+STC_DEF char* cstr_assign_n(cstr* self, const char* str, const size_t n) {
+ char* d = cstr_reserve(self, n);
+ memmove(d, str, n);
+ _cstr_set_size(self, n);
+ return d;
+}
+
+STC_DEF char* cstr_append_n(cstr* self, const char* str, const size_t n) {
+ cstr_buf r = cstr_buffer(self);
+ if (r.size + n > r.cap) {
+ const size_t off = (size_t)(str - r.data);
+ r.data = cstr_reserve(self, (r.size*3 >> 1) + n);
+ if (off <= r.size) str = r.data + off; /* handle self append */
+ }
+ memcpy(r.data + r.size, str, n);
+ _cstr_set_size(self, r.size + n);
+ return r.data;
+}
+
+STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) {
+ int c = fgetc(fp);
+ if (c == EOF)
+ return false;
+ size_t pos = 0;
+ cstr_buf r = cstr_buffer(self);
+ for (;;) {
+ if (c == delim || c == EOF) {
+ _cstr_set_size(self, pos);
+ return true;
+ }
+ if (pos == r.cap) {
+ _cstr_set_size(self, pos);
+ r.data = cstr_reserve(self, (r.cap = (r.cap*3 >> 1) + 16));
+ }
+ r.data[pos++] = (char) c;
+ c = fgetc(fp);
+ }
+}
+
+STC_DEF cstr
+cstr_from_replace_all(const char* str, const size_t str_len,
+ const char* search, const size_t search_len,
+ const char* repl, const size_t repl_len) {
+ cstr out = cstr_null;
+ size_t from = 0; char* res;
+ if (search_len)
+ while ((res = c_strnstrn(str + from, search, str_len - from, search_len))) {
+ const size_t pos = res - str;
+ cstr_append_n(&out, str + from, pos - from);
+ cstr_append_n(&out, repl, repl_len);
+ from = pos + search_len;
+ }
+ cstr_append_n(&out, str + from, str_len - from);
+ return out;
+}
+
+STC_DEF void
+cstr_replace_all(cstr* self, const char* search, const char* repl) {
+ csview sv = cstr_sv(self);
+ cstr_take(self, cstr_from_replace_all(sv.str, sv.size, search, strlen(search),
+ repl, strlen(repl)));
+}
+
+STC_DEF void cstr_erase_n(cstr* self, const size_t pos, size_t n) {
+ cstr_buf r = cstr_buffer(self);
+ if (n > r.size - pos) n = r.size - pos;
+ memmove(&r.data[pos], &r.data[pos + n], r.size - (pos + n));
+ _cstr_set_size(self, r.size - n);
+}
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable: 4996)
+#endif
+
+STC_DEF int cstr_vfmt(cstr* self, const char* fmt, va_list args) {
+ va_list args2;
+ va_copy(args2, args);
+ const int n = vsnprintf(NULL, (size_t)0, fmt, args);
+ cstr_reserve(self, n);
+ vsprintf(cstr_data(self), fmt, args2);
+ va_end(args2);
+ _cstr_set_size(self, n);
+ return n;
+}
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#elif defined(_MSC_VER)
+# pragma warning(pop)
+#endif
+
+STC_DEF cstr cstr_from_fmt(const char* fmt, ...) {
+ cstr s = cstr_null;
+ va_list args; va_start(args, fmt);
+ cstr_vfmt(&s, fmt, args);
+ va_end(args);
+ return s;
+}
+
+STC_DEF int cstr_printf(cstr* self, const char* fmt, ...) {
+ cstr s = cstr_null;
+ va_list args; va_start(args, fmt);
+ const int n = cstr_vfmt(&s, fmt, args);
+ va_end(args);
+ cstr_drop(self); *self = s;
+ return n;
+}
+
+#endif // i_implement
+#if defined __GNUC__ && !defined __clang__
+# pragma GCC diagnostic pop
+#endif
+#endif // CSTR_H_INCLUDED
+#undef i_opt
+#undef i_header
+#undef i_static
+#undef i_implement
+#undef i_extern
+#endif // !STC_CSTR_V1
diff --git a/include/stc/csview.h b/include/stc/csview.h
index 36e6ad7b..90e1b10b 100644
--- a/include/stc/csview.h
+++ b/include/stc/csview.h
@@ -1,219 +1,219 @@
-/* MIT License
- *
- * Copyright (c) 2022 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 CSVIEW_H_INCLUDED
-#define CSVIEW_H_INCLUDED
-
-#define i_header
-#include "ccommon.h"
-#include "forward.h"
-#include "utf8.h"
-
-#define csview_null c_sv("")
-#define csview_new(literal) c_sv(literal)
-#define csview_npos (SIZE_MAX >> 1)
-
-STC_API csview csview_substr_ex(csview sv, intptr_t pos, size_t n);
-STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2);
-STC_API csview csview_token(csview sv, csview sep, size_t* start);
-
-STC_INLINE csview csview_init() { return csview_null; }
-STC_INLINE csview csview_from(const char* str)
- { return c_make(csview){str, strlen(str)}; }
-STC_INLINE csview csview_from_n(const char* str, size_t n)
- { return c_make(csview){str, n}; }
-STC_INLINE void csview_clear(csview* self) { *self = csview_null; }
-
-STC_INLINE size_t csview_size(csview sv) { return sv.size; }
-STC_INLINE size_t csview_length(csview sv) { return sv.size; }
-STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; }
-STC_INLINE char csview_front(csview sv) { return sv.str[0]; }
-STC_INLINE char csview_back(csview sv) { return sv.str[sv.size - 1]; }
-
-STC_INLINE bool csview_equals(csview sv, csview sv2)
- { return sv.size == sv2.size && !memcmp(sv.str, sv2.str, sv.size); }
-
-STC_INLINE size_t csview_find(csview sv, csview needle) {
- char* res = c_strnstrn(sv.str, needle.str, sv.size, needle.size);
- return res ? res - sv.str : csview_npos;
-}
-
-STC_INLINE bool csview_contains(csview sv, csview needle)
- { return c_strnstrn(sv.str, needle.str, sv.size, needle.size) != NULL; }
-
-STC_INLINE bool csview_starts_with(csview sv, csview sub) {
- if (sub.size > sv.size) return false;
- return !memcmp(sv.str, sub.str, sub.size);
-}
-
-STC_INLINE bool csview_ends_with(csview sv, csview sub) {
- if (sub.size > sv.size) return false;
- return !memcmp(sv.str + sv.size - sub.size, sub.str, sub.size);
-}
-
-STC_INLINE csview csview_substr(csview sv, size_t pos, size_t n) {
- if (pos + n > sv.size) n = sv.size - pos;
- sv.str += pos, sv.size = n;
- return sv;
-}
-
-STC_INLINE csview csview_slice(csview sv, size_t p1, size_t p2) {
- if (p2 > sv.size) p2 = sv.size;
- sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0;
- return sv;
-}
-
-/* iterator */
-STC_INLINE csview_iter csview_begin(const csview* self)
- { return c_make(csview_iter){.chr = {self->str, utf8_codep_size(self->str)}}; }
-
-STC_INLINE csview_iter csview_end(const csview* self)
- { return c_make(csview_iter){self->str + self->size}; }
-
-STC_INLINE void csview_next(csview_iter* it)
- { it->ref += it->chr.size; it->chr.size = utf8_codep_size(it->ref); }
-
-/* utf8 */
-STC_INLINE size_t csview_size_u8(csview sv)
- { return utf8_size_n(sv.str, sv.size); }
-
-STC_INLINE csview csview_substr_u8(csview sv, size_t u8pos, size_t u8len) {
- sv.str = utf8_at(sv.str, u8pos);
- sv.size = utf8_pos(sv.str, u8len);
- return sv;
-}
-
-STC_INLINE bool csview_valid_u8(csview sv) // depends on src/utf8code.c
- { return utf8_valid_n(sv.str, sv.size); }
-
-
-/* csview interaction with cstr: */
-#ifdef CSTR_H_INCLUDED
-
-STC_INLINE csview csview_from_s(const cstr* self)
- { return c_make(csview){cstr_str(self), cstr_size(*self)}; }
-
-STC_INLINE cstr cstr_from_sv(csview sv)
- { return cstr_from_n(sv.str, sv.size); }
-
-STC_INLINE csview cstr_substr(const cstr* self, size_t pos, size_t n)
- { return csview_substr(csview_from_s(self), pos, n); }
-
-STC_INLINE csview cstr_slice(const cstr* self, size_t p1, size_t p2)
- { return csview_slice(csview_from_s(self), p1, p2); }
-
-STC_INLINE csview cstr_substr_ex(const cstr* self, intptr_t pos, size_t n)
- { return csview_substr_ex(csview_from_s(self), pos, n); }
-
-STC_INLINE csview cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2)
- { return csview_slice_ex(csview_from_s(self), p1, p2); }
-
-STC_INLINE csview cstr_assign_sv(cstr* self, csview sv)
- { return c_make(csview){cstr_assign_n(self, sv.str, sv.size), sv.size}; }
-
-STC_INLINE void cstr_append_sv(cstr* self, csview sv)
- { cstr_append_n(self, sv.str, sv.size); }
-
-STC_INLINE void cstr_insert_sv(cstr* self, size_t pos, csview sv)
- { cstr_replace_n(self, pos, 0, sv.str, sv.size); }
-
-STC_INLINE void cstr_replace_sv(cstr* self, csview sub, csview with)
- { cstr_replace_n(self, sub.str - cstr_str(self), sub.size, with.str, with.size); }
-
-STC_INLINE bool cstr_equals_sv(cstr s, csview sv)
- { return sv.size == cstr_size(s) && !memcmp(cstr_str(&s), sv.str, sv.size); }
-
-STC_INLINE size_t cstr_find_sv(cstr s, csview needle) {
- char* res = c_strnstrn(cstr_str(&s), needle.str, cstr_size(s), needle.size);
- return res ? res - cstr_str(&s) : cstr_npos;
-}
-
-STC_INLINE bool cstr_contains_sv(cstr s, csview needle)
- { return c_strnstrn(cstr_str(&s), needle.str, cstr_size(s), needle.size) != NULL; }
-
-STC_INLINE bool cstr_starts_with_sv(cstr s, csview sub) {
- if (sub.size > cstr_size(s)) return false;
- return !memcmp(cstr_str(&s), sub.str, sub.size);
-}
-
-STC_INLINE bool cstr_ends_with_sv(cstr s, csview sub) {
- if (sub.size > cstr_size(s)) return false;
- return !memcmp(cstr_str(&s) + cstr_size(s) - sub.size, sub.str, sub.size);
-}
-#endif
-/* ---- Container helper functions ---- */
-
-STC_INLINE int csview_cmp(const csview* x, const csview* y)
- { return strcmp(x->str, y->str); }
-
-STC_INLINE int csview_icmp(const csview* x, const csview* y)
- { return utf8_icmp_n(~(size_t)0, x->str, x->size, y->str, y->size); }
-
-STC_INLINE bool csview_eq(const csview* x, const csview* y)
- { return x->size == y->size && !memcmp(x->str, y->str, x->size); }
-
-STC_INLINE uint64_t csview_hash(const csview *self)
- { return c_fasthash(self->str, self->size); }
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-STC_DEF csview
-csview_substr_ex(csview sv, intptr_t pos, size_t n) {
- if (pos < 0) {
- pos += sv.size;
- if (pos < 0) pos = 0;
- }
- if (pos > (intptr_t)sv.size) pos = sv.size;
- if (pos + n > sv.size) n = sv.size - pos;
- sv.str += pos, sv.size = n;
- return sv;
-}
-
-STC_DEF csview
-csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) {
- if (p1 < 0) {
- p1 += sv.size;
- if (p1 < 0) p1 = 0;
- }
- if (p2 < 0) p2 += sv.size;
- if (p2 > (intptr_t)sv.size) p2 = sv.size;
- sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0;
- return sv;
-}
-
-STC_DEF csview
-csview_token(csview sv, csview sep, size_t* start) {
- csview slice = {sv.str + *start, sv.size - *start};
- const char* res = c_strnstrn(slice.str, sep.str, slice.size, sep.size);
- csview tok = {slice.str, res ? res - slice.str : (sep.size = 0, slice.size)};
- *start += tok.size + sep.size;
- return tok;
-}
-
-#endif
-#endif
-#undef i_opt
-#undef i_header
-#undef i_implement
-#undef i_static
-#undef i_extern
+/* MIT License
+ *
+ * Copyright (c) 2022 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 CSVIEW_H_INCLUDED
+#define CSVIEW_H_INCLUDED
+
+#define i_header
+#include "ccommon.h"
+#include "forward.h"
+#include "utf8.h"
+
+#define csview_null c_sv("")
+#define csview_new(literal) c_sv(literal)
+#define csview_npos (SIZE_MAX >> 1)
+
+STC_API csview csview_substr_ex(csview sv, intptr_t pos, size_t n);
+STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2);
+STC_API csview csview_token(csview sv, csview sep, size_t* start);
+
+STC_INLINE csview csview_init() { return csview_null; }
+STC_INLINE csview csview_from(const char* str)
+ { return c_make(csview){str, strlen(str)}; }
+STC_INLINE csview csview_from_n(const char* str, size_t n)
+ { return c_make(csview){str, n}; }
+STC_INLINE void csview_clear(csview* self) { *self = csview_null; }
+
+STC_INLINE size_t csview_size(csview sv) { return sv.size; }
+STC_INLINE size_t csview_length(csview sv) { return sv.size; }
+STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; }
+STC_INLINE char csview_front(csview sv) { return sv.str[0]; }
+STC_INLINE char csview_back(csview sv) { return sv.str[sv.size - 1]; }
+
+STC_INLINE bool csview_equals(csview sv, csview sv2)
+ { return sv.size == sv2.size && !memcmp(sv.str, sv2.str, sv.size); }
+
+STC_INLINE size_t csview_find(csview sv, csview needle) {
+ char* res = c_strnstrn(sv.str, needle.str, sv.size, needle.size);
+ return res ? res - sv.str : csview_npos;
+}
+
+STC_INLINE bool csview_contains(csview sv, csview needle)
+ { return c_strnstrn(sv.str, needle.str, sv.size, needle.size) != NULL; }
+
+STC_INLINE bool csview_starts_with(csview sv, csview sub) {
+ if (sub.size > sv.size) return false;
+ return !memcmp(sv.str, sub.str, sub.size);
+}
+
+STC_INLINE bool csview_ends_with(csview sv, csview sub) {
+ if (sub.size > sv.size) return false;
+ return !memcmp(sv.str + sv.size - sub.size, sub.str, sub.size);
+}
+
+STC_INLINE csview csview_substr(csview sv, size_t pos, size_t n) {
+ if (pos + n > sv.size) n = sv.size - pos;
+ sv.str += pos, sv.size = n;
+ return sv;
+}
+
+STC_INLINE csview csview_slice(csview sv, size_t p1, size_t p2) {
+ if (p2 > sv.size) p2 = sv.size;
+ sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0;
+ return sv;
+}
+
+/* iterator */
+STC_INLINE csview_iter csview_begin(const csview* self)
+ { return c_make(csview_iter){.chr = {self->str, utf8_codep_size(self->str)}}; }
+
+STC_INLINE csview_iter csview_end(const csview* self)
+ { return c_make(csview_iter){self->str + self->size}; }
+
+STC_INLINE void csview_next(csview_iter* it)
+ { it->ref += it->chr.size; it->chr.size = utf8_codep_size(it->ref); }
+
+/* utf8 */
+STC_INLINE size_t csview_size_u8(csview sv)
+ { return utf8_size_n(sv.str, sv.size); }
+
+STC_INLINE csview csview_substr_u8(csview sv, size_t u8pos, size_t u8len) {
+ sv.str = utf8_at(sv.str, u8pos);
+ sv.size = utf8_pos(sv.str, u8len);
+ return sv;
+}
+
+STC_INLINE bool csview_valid_u8(csview sv) // depends on src/utf8code.c
+ { return utf8_valid_n(sv.str, sv.size); }
+
+
+/* csview interaction with cstr: */
+#ifdef CSTR_H_INCLUDED
+
+STC_INLINE csview csview_from_s(const cstr* self)
+ { return c_make(csview){cstr_str(self), cstr_size(*self)}; }
+
+STC_INLINE cstr cstr_from_sv(csview sv)
+ { return cstr_from_n(sv.str, sv.size); }
+
+STC_INLINE csview cstr_substr(const cstr* self, size_t pos, size_t n)
+ { return csview_substr(csview_from_s(self), pos, n); }
+
+STC_INLINE csview cstr_slice(const cstr* self, size_t p1, size_t p2)
+ { return csview_slice(csview_from_s(self), p1, p2); }
+
+STC_INLINE csview cstr_substr_ex(const cstr* self, intptr_t pos, size_t n)
+ { return csview_substr_ex(csview_from_s(self), pos, n); }
+
+STC_INLINE csview cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2)
+ { return csview_slice_ex(csview_from_s(self), p1, p2); }
+
+STC_INLINE csview cstr_assign_sv(cstr* self, csview sv)
+ { return c_make(csview){cstr_assign_n(self, sv.str, sv.size), sv.size}; }
+
+STC_INLINE void cstr_append_sv(cstr* self, csview sv)
+ { cstr_append_n(self, sv.str, sv.size); }
+
+STC_INLINE void cstr_insert_sv(cstr* self, size_t pos, csview sv)
+ { cstr_replace_n(self, pos, 0, sv.str, sv.size); }
+
+STC_INLINE void cstr_replace_sv(cstr* self, csview sub, csview with)
+ { cstr_replace_n(self, sub.str - cstr_str(self), sub.size, with.str, with.size); }
+
+STC_INLINE bool cstr_equals_sv(cstr s, csview sv)
+ { return sv.size == cstr_size(s) && !memcmp(cstr_str(&s), sv.str, sv.size); }
+
+STC_INLINE size_t cstr_find_sv(cstr s, csview needle) {
+ char* res = c_strnstrn(cstr_str(&s), needle.str, cstr_size(s), needle.size);
+ return res ? res - cstr_str(&s) : cstr_npos;
+}
+
+STC_INLINE bool cstr_contains_sv(cstr s, csview needle)
+ { return c_strnstrn(cstr_str(&s), needle.str, cstr_size(s), needle.size) != NULL; }
+
+STC_INLINE bool cstr_starts_with_sv(cstr s, csview sub) {
+ if (sub.size > cstr_size(s)) return false;
+ return !memcmp(cstr_str(&s), sub.str, sub.size);
+}
+
+STC_INLINE bool cstr_ends_with_sv(cstr s, csview sub) {
+ if (sub.size > cstr_size(s)) return false;
+ return !memcmp(cstr_str(&s) + cstr_size(s) - sub.size, sub.str, sub.size);
+}
+#endif
+/* ---- Container helper functions ---- */
+
+STC_INLINE int csview_cmp(const csview* x, const csview* y)
+ { return strcmp(x->str, y->str); }
+
+STC_INLINE int csview_icmp(const csview* x, const csview* y)
+ { return utf8_icmp_n(~(size_t)0, x->str, x->size, y->str, y->size); }
+
+STC_INLINE bool csview_eq(const csview* x, const csview* y)
+ { return x->size == y->size && !memcmp(x->str, y->str, x->size); }
+
+STC_INLINE uint64_t csview_hash(const csview *self)
+ { return c_fasthash(self->str, self->size); }
+
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if defined(i_implement)
+
+STC_DEF csview
+csview_substr_ex(csview sv, intptr_t pos, size_t n) {
+ if (pos < 0) {
+ pos += sv.size;
+ if (pos < 0) pos = 0;
+ }
+ if (pos > (intptr_t)sv.size) pos = sv.size;
+ if (pos + n > sv.size) n = sv.size - pos;
+ sv.str += pos, sv.size = n;
+ return sv;
+}
+
+STC_DEF csview
+csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) {
+ if (p1 < 0) {
+ p1 += sv.size;
+ if (p1 < 0) p1 = 0;
+ }
+ if (p2 < 0) p2 += sv.size;
+ if (p2 > (intptr_t)sv.size) p2 = sv.size;
+ sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0;
+ return sv;
+}
+
+STC_DEF csview
+csview_token(csview sv, csview sep, size_t* start) {
+ csview slice = {sv.str + *start, sv.size - *start};
+ const char* res = c_strnstrn(slice.str, sep.str, slice.size, sep.size);
+ csview tok = {slice.str, res ? res - slice.str : (sep.size = 0, slice.size)};
+ *start += tok.size + sep.size;
+ return tok;
+}
+
+#endif
+#endif
+#undef i_opt
+#undef i_header
+#undef i_implement
+#undef i_static
+#undef i_extern
diff --git a/include/stc/cvec.h b/include/stc/cvec.h
index f4fc0fb6..cd9c8f9e 100644
--- a/include/stc/cvec.h
+++ b/include/stc/cvec.h
@@ -1,436 +1,436 @@
-/* MIT License
- *
- * Copyright (c) 2022 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.
- */
-
-/*
-#include <stc/cstr.h>
-#include <stc/forward.h>
-
-forward_cvec(cvec_i32, int);
-
-struct MyStruct {
- cvec_i32 int_vec;
- cstr name;
-} typedef MyStruct;
-
-#define i_key float
-#include <stc/cvec.h>
-
-#define i_key_str // special for cstr
-#include <stc/cvec.h>
-
-#define i_key int
-#define i_opt c_is_fwd // forward declared
-#define i_tag i32
-#include <stc/cvec.h>
-
-int main() {
- cvec_i32 vec = cvec_i32_init();
- cvec_i32_push_back(&vec, 123);
- cvec_i32_drop(&vec);
-
- cvec_float fvec = cvec_float_init();
- cvec_float_push_back(&fvec, 123.3);
- cvec_float_drop(&fvec);
-
- cvec_str svec = cvec_str_init();
- cvec_str_emplace_back(&svec, "Hello, friend");
- cvec_str_drop(&svec);
-}
-*/
-#include "ccommon.h"
-
-#ifndef CVEC_H_INCLUDED
-#include "forward.h"
-#include <stdlib.h>
-#include <string.h>
-
-struct cvec_rep { size_t size, cap; unsigned data[1]; };
-#define cvec_rep_(self) c_unchecked_container_of((self)->data, struct cvec_rep, data)
-#endif // CVEC_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix cvec_
-#endif
-#include "template.h"
-
-#if !c_option(c_is_fwd)
- _cx_deftypes(_c_cvec_types, _cx_self, i_key);
-#endif
-typedef i_keyraw _cx_raw;
-STC_API _cx_self _cx_memb(_init)(void);
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API void _cx_memb(_clear)(_cx_self* self);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, size_t cap);
-STC_API bool _cx_memb(_resize)(_cx_self* self, size_t size, i_key null);
-STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value);
-STC_API _cx_iter _cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2);
-STC_API _cx_value* _cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
-STC_API _cx_value* _cx_memb(_expand_uninit_p)(_cx_self* self, _cx_value* pos, const size_t n);
-#if !c_option(c_no_cmp)
-STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y);
-STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw);
-STC_API _cx_iter _cx_memb(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound);
-#endif
-
-#if !defined _i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
-STC_API _cx_value* _cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
-STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val)
- { return i_keyclone(val); }
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->data == other.data) return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(other);
- }
-#if !defined _i_no_emplace
-STC_API _cx_value* _cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_raw* p1, const _cx_raw* p2);
-STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_value*
-_cx_memb(_emplace_n)(_cx_self* self, const size_t idx, const _cx_raw arr[], const size_t n) {
- return _cx_memb(_emplace_range_p)(self, self->data + idx, arr, arr + n);
-}
-STC_INLINE _cx_value*
-_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) {
- return _cx_memb(_emplace_range_p)(self, it.ref, &raw, &raw + 1);
-}
-STC_INLINE _cx_value*
-_cx_memb(_emplace_range)(_cx_self* self, _cx_iter it, _cx_iter it1, _cx_iter it2) {
- return _cx_memb(_clone_range_p)(self, it.ref, it1.ref, it2.ref);
-}
-#endif // !_i_no_emplace
-#endif // !_i_no_clone
-
-STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return cvec_rep_(&cx)->size; }
-STC_INLINE size_t _cx_memb(_capacity)(_cx_self cx) { return cvec_rep_(&cx)->cap; }
-STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return !cvec_rep_(&cx)->size; }
-STC_INLINE _cx_raw _cx_memb(_value_toraw)(_cx_value* val) { return i_keyto(val); }
-STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); }
-STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->data; }
-STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self)
- { return self->data + cvec_rep_(self)->size - 1; }
-STC_INLINE void _cx_memb(_pop)(_cx_self* self)
- { _cx_value* p = &self->data[--cvec_rep_(self)->size]; i_keydrop(p); }
-STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value)
- { return _cx_memb(_push)(self, value); }
-STC_INLINE void _cx_memb(_pop_back)(_cx_self* self) { _cx_memb(_pop)(self); }
-STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self)
- { return c_make(_cx_iter){self->data}; }
-STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
- { return c_make(_cx_iter){self->data + cvec_rep_(self)->size}; }
-STC_INLINE void _cx_memb(_next)(_cx_iter* it) { ++it->ref; }
-STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t offs)
- { it.ref += offs; return it; }
-STC_INLINE size_t _cx_memb(_index)(_cx_self cx, _cx_iter it) { return it.ref - cx.data; }
-
-STC_INLINE _cx_self
-_cx_memb(_with_size)(const size_t size, i_key null) {
- _cx_self cx = _cx_memb(_init)();
- _cx_memb(_resize)(&cx, size, null);
- return cx;
-}
-
-STC_INLINE _cx_self
-_cx_memb(_with_capacity)(const size_t cap) {
- _cx_self cx = _cx_memb(_init)();
- _cx_memb(_reserve)(&cx, cap);
- return cx;
-}
-
-STC_INLINE void
-_cx_memb(_shrink_to_fit)(_cx_self *self) {
- _cx_memb(_reserve)(self, _cx_memb(_size)(*self));
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_expand_uninit)(_cx_self *self, const size_t n) {
- return _cx_memb(_expand_uninit_p)(self, self->data + _cx_memb(_size)(*self), n);
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_insert)(_cx_self* self, const size_t idx, i_key value) {
- return _cx_memb(_insert_range_p)(self, self->data + idx, &value, &value + 1);
-}
-STC_INLINE _cx_value*
-_cx_memb(_insert_n)(_cx_self* self, const size_t idx, const _cx_value arr[], const size_t n) {
- return _cx_memb(_insert_range_p)(self, self->data + idx, arr, arr + n);
-}
-STC_INLINE _cx_value*
-_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
- return _cx_memb(_insert_range_p)(self, it.ref, &value, &value + 1);
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_erase_n)(_cx_self* self, const size_t idx, const size_t n) {
- return _cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n);
-}
-STC_INLINE _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- return _cx_memb(_erase_range_p)(self, it.ref, it.ref + 1);
-}
-STC_INLINE _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
- return _cx_memb(_erase_range_p)(self, it1.ref, it2.ref);
-}
-
-STC_INLINE const _cx_value*
-_cx_memb(_at)(const _cx_self* self, const size_t idx) {
- assert(idx < cvec_rep_(self)->size); return self->data + idx;
-}
-STC_INLINE _cx_value*
-_cx_memb(_at_mut)(_cx_self* self, const size_t idx) {
- assert(idx < cvec_rep_(self)->size); return self->data + idx;
-}
-
-#if !c_option(c_no_cmp)
-
-STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_raw raw) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw);
-}
-
-STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_raw raw) {
- _cx_iter end = _cx_memb(_end)(self);
- _cx_value* val = _cx_memb(_find)(self, raw).ref;
- return val == end.ref ? NULL : val;
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_get_mut)(const _cx_self* self, _cx_raw raw)
- { return (_cx_value*) _cx_memb(_get)(self, raw); }
-
-STC_INLINE _cx_iter
-_cx_memb(_binary_search)(const _cx_self* self, _cx_raw raw) {
- _cx_iter lower;
- return _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower);
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_lower_bound)(const _cx_self* self, _cx_raw raw) {
- _cx_iter lower;
- _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower);
- return lower;
-}
-
-STC_INLINE void
-_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2,
- int(*_cmp_)(const _cx_value*, const _cx_value*)) {
- qsort(i1.ref, i2.ref - i1.ref, sizeof(_cx_value), (int(*)(const void*, const void*)) _cmp_);
-}
-STC_INLINE void
-_cx_memb(_sort)(_cx_self* self) {
- _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp));
-}
-#endif // !c_no_cmp
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-#ifndef CVEC_H_INCLUDED
-static struct cvec_rep _cvec_sentinel = {0, 0};
-#endif
-
-STC_DEF _cx_self
-_cx_memb(_init)(void) {
- _cx_self cx = {(_cx_value *) _cvec_sentinel.data};
- return cx;
-}
-
-STC_DEF void
-_cx_memb(_clear)(_cx_self* self) {
- struct cvec_rep* rep = cvec_rep_(self);
- if (rep->cap) {
- for (_cx_value *p = self->data, *q = p + rep->size; p != q; ) {
- --q; i_keydrop(q);
- }
- rep->size = 0;
- }
-}
-
-STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
- struct cvec_rep* rep = cvec_rep_(self);
- // second test to supress gcc -O2 warn: -Wfree-nonheap-object
- if (rep->cap == 0 || rep == &_cvec_sentinel)
- return;
- _cx_memb(_clear)(self);
- c_free(rep);
-}
-
-STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const size_t cap) {
- struct cvec_rep* rep = cvec_rep_(self);
- const size_t len = rep->size;
- if (cap > rep->cap || (cap && cap == len)) {
- rep = (struct cvec_rep*) c_realloc(rep->cap ? rep : NULL,
- offsetof(struct cvec_rep, data) + cap*sizeof(i_key));
- if (!rep)
- return false;
- self->data = (_cx_value*) rep->data;
- rep->size = len;
- rep->cap = cap;
- }
- return true;
-}
-
-STC_DEF bool
-_cx_memb(_resize)(_cx_self* self, const size_t len, i_key null) {
- if (!_cx_memb(_reserve)(self, len)) return false;
- struct cvec_rep *rep = cvec_rep_(self);
- const size_t n = rep->size;
- for (size_t i = len; i < n; ++i)
- { i_keydrop((self->data + i)); }
- for (size_t i = n; i < len; ++i)
- self->data[i] = null;
- if (rep->cap)
- rep->size = len;
- return true;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push)(_cx_self* self, i_key value) {
- struct cvec_rep *r = cvec_rep_(self);
- if (r->size == r->cap) {
- if (!_cx_memb(_reserve)(self, (r->size*3 >> 1) + 4))
- return NULL;
- r = cvec_rep_(self);
- }
- _cx_value *v = self->data + r->size++;
- *v = value; return v;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_expand_uninit_p)(_cx_self* self, _cx_value* pos, const size_t n) {
- const size_t idx = pos - self->data;
- struct cvec_rep* r = cvec_rep_(self);
- if (!n)
- return pos;
- if (r->size + n > r->cap) {
- if (!_cx_memb(_reserve)(self, r->size*3/2 + n))
- return NULL;
- r = cvec_rep_(self);
- pos = self->data + idx;
- }
- memmove(pos + n, pos, (r->size - idx)*sizeof *pos);
- r->size += n;
- return pos;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
- if (pos)
- memcpy(pos, p1, (p2 - p1)*sizeof *p1);
- return pos;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2) {
- intptr_t len = p2 - p1;
- if (len > 0) {
- _cx_value* p = p1, *end = self->data + cvec_rep_(self)->size;
- for (; p != p2; ++p)
- { i_keydrop(p); }
- memmove(p1, p2, (end - p2) * sizeof(i_key));
- cvec_rep_(self)->size -= len;
- }
- return c_make(_cx_iter){.ref = p1};
-}
-
-#if !defined _i_no_clone
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self cx) {
- const size_t len = cvec_rep_(&cx)->size;
- _cx_self out = _cx_memb(_with_capacity)(len);
- if (cvec_rep_(&out)->cap)
- _cx_memb(_clone_range_p)(&out, out.data, cx.data, cx.data + len);
- return out;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
- _cx_value* it = pos;
- if (pos) for (; p1 != p2; ++p1)
- *pos++ = i_keyclone((*p1));
- return it;
-}
-
-#if !defined _i_no_emplace
-STC_DEF _cx_value*
-_cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_raw* p1, const _cx_raw* p2) {
- pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
- _cx_value* it = pos;
- if (pos) for (; p1 != p2; ++p1)
- *pos++ = i_keyfrom((*p1));
- return it;
-}
-#endif // !_i_no_emplace
-#endif // !_i_no_clone
-
-#if !c_option(c_no_cmp)
-STC_DEF _cx_iter
-_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
- for (; i1.ref != i2.ref; ++i1.ref) {
- const _cx_raw r = i_keyto(i1.ref);
- if (i_eq((&raw), (&r)))
- return i1;
- }
- return i2;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_binary_search_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw, _cx_iter* lower_bound) {
- _cx_iter mid, last = i2;
- while (i1.ref != i2.ref) {
- mid.ref = i1.ref + ((i2.ref - i1.ref) >> 1);
- int c; const _cx_raw m = i_keyto(mid.ref);
- if (!(c = i_cmp((&raw), (&m))))
- return *lower_bound = mid;
- else if (c < 0)
- i2.ref = mid.ref;
- else
- i1.ref = mid.ref + 1;
- }
- *lower_bound = i1;
- return last;
-}
-
-STC_DEF int
-_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- const _cx_raw rx = i_keyto(x);
- const _cx_raw ry = i_keyto(y);
- return i_cmp((&rx), (&ry));
-}
-#endif // !c_no_cmp
-#endif // i_implement
-#define CVEC_H_INCLUDED
-#include "template.h"
+/* MIT License
+ *
+ * Copyright (c) 2022 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.
+ */
+
+/*
+#include <stc/cstr.h>
+#include <stc/forward.h>
+
+forward_cvec(cvec_i32, int);
+
+struct MyStruct {
+ cvec_i32 int_vec;
+ cstr name;
+} typedef MyStruct;
+
+#define i_key float
+#include <stc/cvec.h>
+
+#define i_key_str // special for cstr
+#include <stc/cvec.h>
+
+#define i_key int
+#define i_opt c_is_fwd // forward declared
+#define i_tag i32
+#include <stc/cvec.h>
+
+int main() {
+ cvec_i32 vec = cvec_i32_init();
+ cvec_i32_push_back(&vec, 123);
+ cvec_i32_drop(&vec);
+
+ cvec_float fvec = cvec_float_init();
+ cvec_float_push_back(&fvec, 123.3);
+ cvec_float_drop(&fvec);
+
+ cvec_str svec = cvec_str_init();
+ cvec_str_emplace_back(&svec, "Hello, friend");
+ cvec_str_drop(&svec);
+}
+*/
+#include "ccommon.h"
+
+#ifndef CVEC_H_INCLUDED
+#include "forward.h"
+#include <stdlib.h>
+#include <string.h>
+
+struct cvec_rep { size_t size, cap; unsigned data[1]; };
+#define cvec_rep_(self) c_unchecked_container_of((self)->data, struct cvec_rep, data)
+#endif // CVEC_H_INCLUDED
+
+#ifndef _i_prefix
+#define _i_prefix cvec_
+#endif
+#include "template.h"
+
+#if !c_option(c_is_fwd)
+ _cx_deftypes(_c_cvec_types, _cx_self, i_key);
+#endif
+typedef i_keyraw _cx_raw;
+STC_API _cx_self _cx_memb(_init)(void);
+STC_API void _cx_memb(_drop)(_cx_self* self);
+STC_API void _cx_memb(_clear)(_cx_self* self);
+STC_API bool _cx_memb(_reserve)(_cx_self* self, size_t cap);
+STC_API bool _cx_memb(_resize)(_cx_self* self, size_t size, i_key null);
+STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value);
+STC_API _cx_iter _cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2);
+STC_API _cx_value* _cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos,
+ const _cx_value* p1, const _cx_value* p2);
+STC_API _cx_value* _cx_memb(_expand_uninit_p)(_cx_self* self, _cx_value* pos, const size_t n);
+#if !c_option(c_no_cmp)
+STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y);
+STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw);
+STC_API _cx_iter _cx_memb(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound);
+#endif
+
+#if !defined _i_no_clone
+STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
+STC_API _cx_value* _cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos,
+ const _cx_value* p1, const _cx_value* p2);
+STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val)
+ { return i_keyclone(val); }
+STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
+ if (self->data == other.data) return;
+ _cx_memb(_drop)(self);
+ *self = _cx_memb(_clone)(other);
+ }
+#if !defined _i_no_emplace
+STC_API _cx_value* _cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos,
+ const _cx_raw* p1, const _cx_raw* p2);
+STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
+ { return _cx_memb(_push)(self, i_keyfrom(raw)); }
+STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw)
+ { return _cx_memb(_push)(self, i_keyfrom(raw)); }
+STC_INLINE _cx_value*
+_cx_memb(_emplace_n)(_cx_self* self, const size_t idx, const _cx_raw arr[], const size_t n) {
+ return _cx_memb(_emplace_range_p)(self, self->data + idx, arr, arr + n);
+}
+STC_INLINE _cx_value*
+_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) {
+ return _cx_memb(_emplace_range_p)(self, it.ref, &raw, &raw + 1);
+}
+STC_INLINE _cx_value*
+_cx_memb(_emplace_range)(_cx_self* self, _cx_iter it, _cx_iter it1, _cx_iter it2) {
+ return _cx_memb(_clone_range_p)(self, it.ref, it1.ref, it2.ref);
+}
+#endif // !_i_no_emplace
+#endif // !_i_no_clone
+
+STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return cvec_rep_(&cx)->size; }
+STC_INLINE size_t _cx_memb(_capacity)(_cx_self cx) { return cvec_rep_(&cx)->cap; }
+STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return !cvec_rep_(&cx)->size; }
+STC_INLINE _cx_raw _cx_memb(_value_toraw)(_cx_value* val) { return i_keyto(val); }
+STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); }
+STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->data; }
+STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self)
+ { return self->data + cvec_rep_(self)->size - 1; }
+STC_INLINE void _cx_memb(_pop)(_cx_self* self)
+ { _cx_value* p = &self->data[--cvec_rep_(self)->size]; i_keydrop(p); }
+STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value)
+ { return _cx_memb(_push)(self, value); }
+STC_INLINE void _cx_memb(_pop_back)(_cx_self* self) { _cx_memb(_pop)(self); }
+STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self)
+ { return c_make(_cx_iter){self->data}; }
+STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
+ { return c_make(_cx_iter){self->data + cvec_rep_(self)->size}; }
+STC_INLINE void _cx_memb(_next)(_cx_iter* it) { ++it->ref; }
+STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t offs)
+ { it.ref += offs; return it; }
+STC_INLINE size_t _cx_memb(_index)(_cx_self cx, _cx_iter it) { return it.ref - cx.data; }
+
+STC_INLINE _cx_self
+_cx_memb(_with_size)(const size_t size, i_key null) {
+ _cx_self cx = _cx_memb(_init)();
+ _cx_memb(_resize)(&cx, size, null);
+ return cx;
+}
+
+STC_INLINE _cx_self
+_cx_memb(_with_capacity)(const size_t cap) {
+ _cx_self cx = _cx_memb(_init)();
+ _cx_memb(_reserve)(&cx, cap);
+ return cx;
+}
+
+STC_INLINE void
+_cx_memb(_shrink_to_fit)(_cx_self *self) {
+ _cx_memb(_reserve)(self, _cx_memb(_size)(*self));
+}
+
+STC_INLINE _cx_value*
+_cx_memb(_expand_uninit)(_cx_self *self, const size_t n) {
+ return _cx_memb(_expand_uninit_p)(self, self->data + _cx_memb(_size)(*self), n);
+}
+
+STC_INLINE _cx_value*
+_cx_memb(_insert)(_cx_self* self, const size_t idx, i_key value) {
+ return _cx_memb(_insert_range_p)(self, self->data + idx, &value, &value + 1);
+}
+STC_INLINE _cx_value*
+_cx_memb(_insert_n)(_cx_self* self, const size_t idx, const _cx_value arr[], const size_t n) {
+ return _cx_memb(_insert_range_p)(self, self->data + idx, arr, arr + n);
+}
+STC_INLINE _cx_value*
+_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
+ return _cx_memb(_insert_range_p)(self, it.ref, &value, &value + 1);
+}
+
+STC_INLINE _cx_iter
+_cx_memb(_erase_n)(_cx_self* self, const size_t idx, const size_t n) {
+ return _cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n);
+}
+STC_INLINE _cx_iter
+_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
+ return _cx_memb(_erase_range_p)(self, it.ref, it.ref + 1);
+}
+STC_INLINE _cx_iter
+_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
+ return _cx_memb(_erase_range_p)(self, it1.ref, it2.ref);
+}
+
+STC_INLINE const _cx_value*
+_cx_memb(_at)(const _cx_self* self, const size_t idx) {
+ assert(idx < cvec_rep_(self)->size); return self->data + idx;
+}
+STC_INLINE _cx_value*
+_cx_memb(_at_mut)(_cx_self* self, const size_t idx) {
+ assert(idx < cvec_rep_(self)->size); return self->data + idx;
+}
+
+#if !c_option(c_no_cmp)
+
+STC_INLINE _cx_iter
+_cx_memb(_find)(const _cx_self* self, _cx_raw raw) {
+ return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw);
+}
+
+STC_INLINE const _cx_value*
+_cx_memb(_get)(const _cx_self* self, _cx_raw raw) {
+ _cx_iter end = _cx_memb(_end)(self);
+ _cx_value* val = _cx_memb(_find)(self, raw).ref;
+ return val == end.ref ? NULL : val;
+}
+
+STC_INLINE _cx_value*
+_cx_memb(_get_mut)(const _cx_self* self, _cx_raw raw)
+ { return (_cx_value*) _cx_memb(_get)(self, raw); }
+
+STC_INLINE _cx_iter
+_cx_memb(_binary_search)(const _cx_self* self, _cx_raw raw) {
+ _cx_iter lower;
+ return _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower);
+}
+
+STC_INLINE _cx_iter
+_cx_memb(_lower_bound)(const _cx_self* self, _cx_raw raw) {
+ _cx_iter lower;
+ _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower);
+ return lower;
+}
+
+STC_INLINE void
+_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2,
+ int(*_cmp_)(const _cx_value*, const _cx_value*)) {
+ qsort(i1.ref, i2.ref - i1.ref, sizeof(_cx_value), (int(*)(const void*, const void*)) _cmp_);
+}
+STC_INLINE void
+_cx_memb(_sort)(_cx_self* self) {
+ _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp));
+}
+#endif // !c_no_cmp
+/* -------------------------- IMPLEMENTATION ------------------------- */
+#if defined(i_implement)
+
+#ifndef CVEC_H_INCLUDED
+static struct cvec_rep _cvec_sentinel = {0, 0};
+#endif
+
+STC_DEF _cx_self
+_cx_memb(_init)(void) {
+ _cx_self cx = {(_cx_value *) _cvec_sentinel.data};
+ return cx;
+}
+
+STC_DEF void
+_cx_memb(_clear)(_cx_self* self) {
+ struct cvec_rep* rep = cvec_rep_(self);
+ if (rep->cap) {
+ for (_cx_value *p = self->data, *q = p + rep->size; p != q; ) {
+ --q; i_keydrop(q);
+ }
+ rep->size = 0;
+ }
+}
+
+STC_DEF void
+_cx_memb(_drop)(_cx_self* self) {
+ struct cvec_rep* rep = cvec_rep_(self);
+ // second test to supress gcc -O2 warn: -Wfree-nonheap-object
+ if (rep->cap == 0 || rep == &_cvec_sentinel)
+ return;
+ _cx_memb(_clear)(self);
+ c_free(rep);
+}
+
+STC_DEF bool
+_cx_memb(_reserve)(_cx_self* self, const size_t cap) {
+ struct cvec_rep* rep = cvec_rep_(self);
+ const size_t len = rep->size;
+ if (cap > rep->cap || (cap && cap == len)) {
+ rep = (struct cvec_rep*) c_realloc(rep->cap ? rep : NULL,
+ offsetof(struct cvec_rep, data) + cap*sizeof(i_key));
+ if (!rep)
+ return false;
+ self->data = (_cx_value*) rep->data;
+ rep->size = len;
+ rep->cap = cap;
+ }
+ return true;
+}
+
+STC_DEF bool
+_cx_memb(_resize)(_cx_self* self, const size_t len, i_key null) {
+ if (!_cx_memb(_reserve)(self, len)) return false;
+ struct cvec_rep *rep = cvec_rep_(self);
+ const size_t n = rep->size;
+ for (size_t i = len; i < n; ++i)
+ { i_keydrop((self->data + i)); }
+ for (size_t i = n; i < len; ++i)
+ self->data[i] = null;
+ if (rep->cap)
+ rep->size = len;
+ return true;
+}
+
+STC_DEF _cx_value*
+_cx_memb(_push)(_cx_self* self, i_key value) {
+ struct cvec_rep *r = cvec_rep_(self);
+ if (r->size == r->cap) {
+ if (!_cx_memb(_reserve)(self, (r->size*3 >> 1) + 4))
+ return NULL;
+ r = cvec_rep_(self);
+ }
+ _cx_value *v = self->data + r->size++;
+ *v = value; return v;
+}
+
+STC_DEF _cx_value*
+_cx_memb(_expand_uninit_p)(_cx_self* self, _cx_value* pos, const size_t n) {
+ const size_t idx = pos - self->data;
+ struct cvec_rep* r = cvec_rep_(self);
+ if (!n)
+ return pos;
+ if (r->size + n > r->cap) {
+ if (!_cx_memb(_reserve)(self, r->size*3/2 + n))
+ return NULL;
+ r = cvec_rep_(self);
+ pos = self->data + idx;
+ }
+ memmove(pos + n, pos, (r->size - idx)*sizeof *pos);
+ r->size += n;
+ return pos;
+}
+
+STC_DEF _cx_value*
+_cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos,
+ const _cx_value* p1, const _cx_value* p2) {
+ pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
+ if (pos)
+ memcpy(pos, p1, (p2 - p1)*sizeof *p1);
+ return pos;
+}
+
+STC_DEF _cx_iter
+_cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2) {
+ intptr_t len = p2 - p1;
+ if (len > 0) {
+ _cx_value* p = p1, *end = self->data + cvec_rep_(self)->size;
+ for (; p != p2; ++p)
+ { i_keydrop(p); }
+ memmove(p1, p2, (end - p2) * sizeof(i_key));
+ cvec_rep_(self)->size -= len;
+ }
+ return c_make(_cx_iter){.ref = p1};
+}
+
+#if !defined _i_no_clone
+STC_DEF _cx_self
+_cx_memb(_clone)(_cx_self cx) {
+ const size_t len = cvec_rep_(&cx)->size;
+ _cx_self out = _cx_memb(_with_capacity)(len);
+ if (cvec_rep_(&out)->cap)
+ _cx_memb(_clone_range_p)(&out, out.data, cx.data, cx.data + len);
+ return out;
+}
+
+STC_DEF _cx_value*
+_cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos,
+ const _cx_value* p1, const _cx_value* p2) {
+ pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
+ _cx_value* it = pos;
+ if (pos) for (; p1 != p2; ++p1)
+ *pos++ = i_keyclone((*p1));
+ return it;
+}
+
+#if !defined _i_no_emplace
+STC_DEF _cx_value*
+_cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos,
+ const _cx_raw* p1, const _cx_raw* p2) {
+ pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
+ _cx_value* it = pos;
+ if (pos) for (; p1 != p2; ++p1)
+ *pos++ = i_keyfrom((*p1));
+ return it;
+}
+#endif // !_i_no_emplace
+#endif // !_i_no_clone
+
+#if !c_option(c_no_cmp)
+STC_DEF _cx_iter
+_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
+ for (; i1.ref != i2.ref; ++i1.ref) {
+ const _cx_raw r = i_keyto(i1.ref);
+ if (i_eq((&raw), (&r)))
+ return i1;
+ }
+ return i2;
+}
+
+STC_DEF _cx_iter
+_cx_memb(_binary_search_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw, _cx_iter* lower_bound) {
+ _cx_iter mid, last = i2;
+ while (i1.ref != i2.ref) {
+ mid.ref = i1.ref + ((i2.ref - i1.ref) >> 1);
+ int c; const _cx_raw m = i_keyto(mid.ref);
+ if (!(c = i_cmp((&raw), (&m))))
+ return *lower_bound = mid;
+ else if (c < 0)
+ i2.ref = mid.ref;
+ else
+ i1.ref = mid.ref + 1;
+ }
+ *lower_bound = i1;
+ return last;
+}
+
+STC_DEF int
+_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
+ const _cx_raw rx = i_keyto(x);
+ const _cx_raw ry = i_keyto(y);
+ return i_cmp((&rx), (&ry));
+}
+#endif // !c_no_cmp
+#endif // i_implement
+#define CVEC_H_INCLUDED
+#include "template.h"
diff --git a/include/stc/forward.h b/include/stc/forward.h
index 67f5f0f2..18c3d7b0 100644
--- a/include/stc/forward.h
+++ b/include/stc/forward.h
@@ -1,207 +1,207 @@
-/* MIT License
- *
- * Copyright (c) 2022 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_carc(CX, VAL) _c_carc_types(CX, VAL)
-#define forward_carr2(CX, VAL) _c_carr2_types(CX, VAL)
-#define forward_carr3(CX, VAL) _c_carr3_types(CX, VAL)
-#define forward_cbox(CX, VAL) _c_cbox_types(CX, VAL)
-#define forward_cdeq(CX, VAL) _c_cdeq_types(CX, VAL)
-#define forward_clist(CX, VAL) _c_clist_types(CX, VAL)
-#define forward_cmap(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, uint32_t, c_true, c_false)
-#define forward_cmap_huge(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, size_t, c_true, c_false)
-#define forward_cset(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, uint32_t, c_false, c_true)
-#define forward_cset_huge(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, size_t, c_false, c_true)
-#define forward_csmap(CX, KEY, VAL) _c_aatree_types(CX, KEY, VAL, uint32_t, c_true, c_false)
-#define forward_csset(CX, KEY) _c_aatree_types(CX, KEY, KEY, uint32_t, c_false, c_true)
-#define forward_cstack(CX, VAL) _c_cstack_types(CX, VAL)
-#define forward_cpque(CX, VAL) _c_cpque_types(CX, VAL)
-#define forward_cqueue(CX, VAL) _c_cdeq_types(CX, VAL)
-#define forward_cvec(CX, VAL) _c_cvec_types(CX, VAL)
-
-typedef struct { char* data; size_t size, cap; } cstr_buf;
-typedef char cstr_value;
-#if defined STC_CSTR_V1
- typedef struct { char* str; } cstr;
-#else
- typedef union {
- struct { char data[sizeof(cstr_buf) - 1]; unsigned char last; } sml;
- struct { char* data; size_t size, ncap; } lon;
- } cstr;
-#endif
-
-typedef struct { const char* str; size_t size; } csview;
-typedef char csview_value;
-typedef union {
- const char *ref;
- csview chr;
-} csview_iter, cstr_iter;
-
-#define c_true(...) __VA_ARGS__
-#define c_false(...)
-
-#define _c_carc_types(SELF, VAL) \
- typedef VAL SELF##_value; \
-\
- typedef struct { \
- SELF##_value* get; \
- long* use_count; \
- } SELF
-
-#define _c_carr2_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct { SELF##_value *ref; } SELF##_iter; \
- typedef struct { SELF##_value **data; size_t xdim, ydim; } SELF
-
-#define _c_carr3_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct { SELF##_value *ref; } SELF##_iter; \
- typedef struct { SELF##_value ***data; size_t xdim, ydim, zdim; } SELF
-
-#define _c_cbox_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct { \
- SELF##_value* get; \
- } SELF
-
-#define _c_cdeq_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct {SELF##_value *ref; } SELF##_iter; \
- typedef struct {SELF##_value *_base, *data;} SELF
-
-#define _c_clist_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct SELF##_node SELF##_node; \
-\
- typedef struct { \
- SELF##_value *ref; \
- SELF##_node *const *_last, *prev; \
- } SELF##_iter; \
-\
- typedef struct { \
- SELF##_node *last; \
- } SELF
-
-#define _c_chash_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \
- typedef KEY SELF##_key; \
- typedef VAL SELF##_mapped; \
- typedef SZ SELF##_size_t; \
-\
- typedef SET_ONLY( SELF##_key ) \
- MAP_ONLY( struct SELF##_value ) \
- SELF##_value; \
-\
- typedef struct { \
- SELF##_value *ref; \
- bool inserted, nomem_error; \
- } SELF##_result; \
-\
- typedef struct { \
- SELF##_value *ref; \
- uint8_t* _hx; \
- } SELF##_iter; \
-\
- typedef struct { \
- SELF##_value* table; \
- uint8_t* _hashx; \
- SELF##_size_t size, bucket_count; \
- float max_load_factor; \
- } SELF
-
-#if defined STC_CSMAP_V1
-#define _c_aatree_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \
- typedef KEY SELF##_key; \
- typedef VAL SELF##_mapped; \
- typedef SZ SELF##_size_t; \
- typedef struct SELF##_node SELF##_node; \
-\
- typedef SET_ONLY( SELF##_key ) \
- MAP_ONLY( struct SELF##_value ) \
- SELF##_value; \
-\
- typedef struct { \
- SELF##_value *ref; \
- bool inserted, nomem_error; \
- } SELF##_result; \
-\
- typedef struct { \
- SELF##_value *ref; \
- int _top; \
- SELF##_node *_tn, *_st[36]; \
- } SELF##_iter; \
-\
- typedef struct { \
- SELF##_node *root; \
- SELF##_size_t size; \
- } SELF
-#else
-#define _c_aatree_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \
- typedef KEY SELF##_key; \
- typedef VAL SELF##_mapped; \
- typedef SZ SELF##_size_t; \
- typedef struct SELF##_node SELF##_node; \
-\
- typedef SET_ONLY( SELF##_key ) \
- MAP_ONLY( struct SELF##_value ) \
- SELF##_value; \
-\
- typedef struct { \
- SELF##_value *ref; \
- bool inserted, nomem_error; \
- } SELF##_result; \
-\
- typedef struct { \
- SELF##_value *ref; \
- SELF##_node *_d; \
- int _top; \
- SELF##_size_t _tn, _st[36]; \
- } SELF##_iter; \
-\
- typedef struct { \
- SELF##_node *nodes; \
- } SELF
-#endif
-#define _c_cstack_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct { SELF##_value *ref; } SELF##_iter; \
- typedef struct SELF { \
- SELF##_value* data; \
- size_t size, capacity; \
- } SELF
-
-#define _c_cpque_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct SELF { \
- SELF##_value* data; \
- size_t size, capacity; \
- } SELF
-
-#define _c_cvec_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct { SELF##_value *ref; } SELF##_iter; \
- typedef struct { SELF##_value *data; } SELF
-
-#endif // STC_FORWARD_H_INCLUDED
+/* MIT License
+ *
+ * Copyright (c) 2022 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_carc(CX, VAL) _c_carc_types(CX, VAL)
+#define forward_carr2(CX, VAL) _c_carr2_types(CX, VAL)
+#define forward_carr3(CX, VAL) _c_carr3_types(CX, VAL)
+#define forward_cbox(CX, VAL) _c_cbox_types(CX, VAL)
+#define forward_cdeq(CX, VAL) _c_cdeq_types(CX, VAL)
+#define forward_clist(CX, VAL) _c_clist_types(CX, VAL)
+#define forward_cmap(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, uint32_t, c_true, c_false)
+#define forward_cmap_huge(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, size_t, c_true, c_false)
+#define forward_cset(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, uint32_t, c_false, c_true)
+#define forward_cset_huge(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, size_t, c_false, c_true)
+#define forward_csmap(CX, KEY, VAL) _c_aatree_types(CX, KEY, VAL, uint32_t, c_true, c_false)
+#define forward_csset(CX, KEY) _c_aatree_types(CX, KEY, KEY, uint32_t, c_false, c_true)
+#define forward_cstack(CX, VAL) _c_cstack_types(CX, VAL)
+#define forward_cpque(CX, VAL) _c_cpque_types(CX, VAL)
+#define forward_cqueue(CX, VAL) _c_cdeq_types(CX, VAL)
+#define forward_cvec(CX, VAL) _c_cvec_types(CX, VAL)
+
+typedef struct { char* data; size_t size, cap; } cstr_buf;
+typedef char cstr_value;
+#if defined STC_CSTR_V1
+ typedef struct { char* str; } cstr;
+#else
+ typedef union {
+ struct { char data[sizeof(cstr_buf) - 1]; unsigned char last; } sml;
+ struct { char* data; size_t size, ncap; } lon;
+ } cstr;
+#endif
+
+typedef struct { const char* str; size_t size; } csview;
+typedef char csview_value;
+typedef union {
+ const char *ref;
+ csview chr;
+} csview_iter, cstr_iter;
+
+#define c_true(...) __VA_ARGS__
+#define c_false(...)
+
+#define _c_carc_types(SELF, VAL) \
+ typedef VAL SELF##_value; \
+\
+ typedef struct { \
+ SELF##_value* get; \
+ long* use_count; \
+ } SELF
+
+#define _c_carr2_types(SELF, VAL) \
+ typedef VAL SELF##_value; \
+ typedef struct { SELF##_value *ref; } SELF##_iter; \
+ typedef struct { SELF##_value **data; size_t xdim, ydim; } SELF
+
+#define _c_carr3_types(SELF, VAL) \
+ typedef VAL SELF##_value; \
+ typedef struct { SELF##_value *ref; } SELF##_iter; \
+ typedef struct { SELF##_value ***data; size_t xdim, ydim, zdim; } SELF
+
+#define _c_cbox_types(SELF, VAL) \
+ typedef VAL SELF##_value; \
+ typedef struct { \
+ SELF##_value* get; \
+ } SELF
+
+#define _c_cdeq_types(SELF, VAL) \
+ typedef VAL SELF##_value; \
+ typedef struct {SELF##_value *ref; } SELF##_iter; \
+ typedef struct {SELF##_value *_base, *data;} SELF
+
+#define _c_clist_types(SELF, VAL) \
+ typedef VAL SELF##_value; \
+ typedef struct SELF##_node SELF##_node; \
+\
+ typedef struct { \
+ SELF##_value *ref; \
+ SELF##_node *const *_last, *prev; \
+ } SELF##_iter; \
+\
+ typedef struct { \
+ SELF##_node *last; \
+ } SELF
+
+#define _c_chash_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \
+ typedef KEY SELF##_key; \
+ typedef VAL SELF##_mapped; \
+ typedef SZ SELF##_size_t; \
+\
+ typedef SET_ONLY( SELF##_key ) \
+ MAP_ONLY( struct SELF##_value ) \
+ SELF##_value; \
+\
+ typedef struct { \
+ SELF##_value *ref; \
+ bool inserted, nomem_error; \
+ } SELF##_result; \
+\
+ typedef struct { \
+ SELF##_value *ref; \
+ uint8_t* _hx; \
+ } SELF##_iter; \
+\
+ typedef struct { \
+ SELF##_value* table; \
+ uint8_t* _hashx; \
+ SELF##_size_t size, bucket_count; \
+ float max_load_factor; \
+ } SELF
+
+#if defined STC_CSMAP_V1
+#define _c_aatree_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \
+ typedef KEY SELF##_key; \
+ typedef VAL SELF##_mapped; \
+ typedef SZ SELF##_size_t; \
+ typedef struct SELF##_node SELF##_node; \
+\
+ typedef SET_ONLY( SELF##_key ) \
+ MAP_ONLY( struct SELF##_value ) \
+ SELF##_value; \
+\
+ typedef struct { \
+ SELF##_value *ref; \
+ bool inserted, nomem_error; \
+ } SELF##_result; \
+\
+ typedef struct { \
+ SELF##_value *ref; \
+ int _top; \
+ SELF##_node *_tn, *_st[36]; \
+ } SELF##_iter; \
+\
+ typedef struct { \
+ SELF##_node *root; \
+ SELF##_size_t size; \
+ } SELF
+#else
+#define _c_aatree_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \
+ typedef KEY SELF##_key; \
+ typedef VAL SELF##_mapped; \
+ typedef SZ SELF##_size_t; \
+ typedef struct SELF##_node SELF##_node; \
+\
+ typedef SET_ONLY( SELF##_key ) \
+ MAP_ONLY( struct SELF##_value ) \
+ SELF##_value; \
+\
+ typedef struct { \
+ SELF##_value *ref; \
+ bool inserted, nomem_error; \
+ } SELF##_result; \
+\
+ typedef struct { \
+ SELF##_value *ref; \
+ SELF##_node *_d; \
+ int _top; \
+ SELF##_size_t _tn, _st[36]; \
+ } SELF##_iter; \
+\
+ typedef struct { \
+ SELF##_node *nodes; \
+ } SELF
+#endif
+#define _c_cstack_types(SELF, VAL) \
+ typedef VAL SELF##_value; \
+ typedef struct { SELF##_value *ref; } SELF##_iter; \
+ typedef struct SELF { \
+ SELF##_value* data; \
+ size_t size, capacity; \
+ } SELF
+
+#define _c_cpque_types(SELF, VAL) \
+ typedef VAL SELF##_value; \
+ typedef struct SELF { \
+ SELF##_value* data; \
+ size_t size, capacity; \
+ } SELF
+
+#define _c_cvec_types(SELF, VAL) \
+ typedef VAL SELF##_value; \
+ typedef struct { SELF##_value *ref; } SELF##_iter; \
+ typedef struct { SELF##_value *data; } SELF
+
+#endif // STC_FORWARD_H_INCLUDED
diff --git a/include/stc/template.h b/include/stc/template.h
index 9bf7e378..5de248e7 100644
--- a/include/stc/template.h
+++ b/include/stc/template.h
@@ -1,296 +1,296 @@
-/* MIT License
- *
- * Copyright (c) 2022 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_self c_paste(_i_prefix, i_tag)
- #define _cx_memb(name) c_paste(_cx_self, name)
- #define _cx_deftypes(macro, SELF, ...) c_expand(macro(SELF, __VA_ARGS__))
- #define _cx_value _cx_memb(_value)
- #define _cx_key _cx_memb(_key)
- #define _cx_mapped _cx_memb(_mapped)
- #define _cx_raw _cx_memb(_raw)
- #define _cx_rawkey _cx_memb(_rawkey)
- #define _cx_rawmapped _cx_memb(_rawmapped)
- #define _cx_iter _cx_memb(_iter)
- #define _cx_result _cx_memb(_result)
- #define _cx_node _cx_memb(_node)
-#endif
-
-#ifdef i_type
- #define i_tag i_type
- #undef _i_prefix
- #define _i_prefix
-#endif
-
-#ifndef i_size
- #define i_size uint32_t
-#endif
-
-#if !(defined i_key || defined i_key_str || defined i_key_ssv || \
- defined i_key_bind || defined i_key_arcbox)
- #define _i_key_from_val
- #if defined _i_ismap
- #error "i_key* must be defined for maps."
- #endif
-
- #if defined i_val_str
- #define i_key_str i_val_str
- #endif
- #if defined i_val_ssv
- #define i_key_ssv i_val_ssv
- #endif
- #if defined i_val_arcbox
- #define i_key_arcbox i_val_arcbox
- #endif
- #if defined i_val_bind
- #define i_key_bind i_val_bind
- #endif
- #if defined i_val
- #define i_key i_val
- #endif
- #if defined i_valraw
- #define i_keyraw i_valraw
- #endif
- #if defined i_valclone
- #define i_keyclone i_valclone
- #endif
- #if defined i_valfrom
- #define i_keyfrom i_valfrom
- #endif
- #if defined i_valto
- #define i_keyto i_valto
- #endif
- #if defined i_valdrop
- #define i_keydrop i_valdrop
- #endif
-#endif
-
-#if defined i_key_str
- #define i_key_bind cstr
- #define i_keyraw crawstr
- #define i_keyfrom cstr_from
- #ifndef i_tag
- #define i_tag str
- #endif
-#elif defined i_key_ssv
- #define i_key_bind cstr
- #define i_keyraw csview
- #define i_keyfrom cstr_from_sv
- #define i_keyto cstr_sv
- #define i_eq csview_eq
- #ifndef i_tag
- #define i_tag ssv
- #endif
-#elif defined i_key_arcbox
- #define i_key_bind i_key_arcbox
- #define i_keyraw c_paste(i_key_arcbox, _value)
- #define i_keyto c_paste(i_key, _toval)
- #define i_eq c_paste(i_key_arcbox, _value_eq)
-#endif
-
-#ifdef i_key_bind
- #define i_key i_key_bind
- #ifndef i_keyclone
- #define i_keyclone c_paste(i_key, _clone)
- #endif
- #if !defined i_keyto && defined i_keyraw
- #define i_keyto c_paste(i_key, _toraw)
- #endif
- #ifndef i_keydrop
- #define i_keydrop c_paste(i_key, _drop)
- #endif
- #ifndef i_cmp
- #define i_cmp c_paste(i_keyraw, _cmp)
- #endif
- #if !defined i_hash
- #define i_hash c_paste(i_keyraw, _hash)
- #endif
-#endif
-
-#if !defined i_key
- #error "no i_key or i_val defined"
-#elif defined i_keyraw ^ defined i_keyto
- #error "both i_keyraw and i_keyto must be defined, if any"
-#elif defined i_keyfrom && !defined i_keyraw
- #error "i_keyfrom defined without i_keyraw"
-#elif defined i_from || defined i_drop
- #error "i_from / i_drop not supported. Define i_keyfrom/i_valfrom and/or i_keydrop/i_valdrop instead"
-#endif
-
-#ifndef i_tag
- #define i_tag i_key
-#endif
-#if c_option(c_no_clone) || (!defined i_keyclone && (defined i_keydrop || defined i_keyraw))
- #define _i_no_clone
-#endif
-#ifndef i_keyraw
- #define i_keyraw i_key
-#endif
-#ifndef i_keyfrom
- #define i_keyfrom c_default_clone
-#else
- #define _i_has_from
-#endif
-#ifndef i_keyto
- #define i_keyto c_default_toraw
-#endif
-#ifndef i_keyclone
- #define i_keyclone c_default_clone
-#endif
-#ifndef i_keydrop
- #define i_keydrop c_default_drop
-#endif
-#ifdef i_less
- #define i_cmp(x, y) c_less_cmp(i_less, x, y)
-#endif
-#if !defined i_eq && defined i_cmp
- #define i_eq(x, y) !(i_cmp(x, y))
-#elif !defined i_eq
- #define i_eq c_default_eq
-#endif
-#ifndef i_cmp
- #define i_cmp c_default_cmp
-#endif
-#ifndef i_hash
- #define i_hash c_default_hash
-#endif
-
-#if defined _i_ismap // ---- process cmap/csmap value i_val, ... ----
-
-#ifdef i_val_str
- #define i_val_bind cstr
- #define i_valraw crawstr
- #define i_valfrom cstr_from
-#elif defined i_val_ssv
- #define i_val_bind cstr
- #define i_valraw csview
- #define i_valfrom cstr_from_sv
- #define i_valto cstr_sv
-#elif defined i_val_arcbox
- #define i_val_bind i_val_arcbox
- #define i_valraw c_paste(i_val_arcbox, _value)
- #define i_valto c_paste(i_val, _toval)
-#endif
-
-#ifdef i_val_bind
- #define i_val i_val_bind
- #ifndef i_valclone
- #define i_valclone c_paste(i_val, _clone)
- #endif
- #if !defined i_valto && defined i_valraw
- #define i_valto c_paste(i_val, _toraw)
- #endif
- #ifndef i_valdrop
- #define i_valdrop c_paste(i_val, _drop)
- #endif
-#endif
-
-#if defined i_valraw ^ defined i_valto
- #error "both i_valto and i_valraw must be defined, if any"
-#elif defined i_valfrom && !defined i_valraw
- #error "i_valfrom defined without i_valraw"
-#endif
-
-#if !defined i_valclone && (defined i_valdrop || defined i_valraw)
- #define _i_no_clone
-#endif
-#ifndef i_valraw
- #define i_valraw i_val
-#endif
-#ifndef i_valfrom
- #define i_valfrom c_default_clone
-#else
- #define _i_has_from
-#endif
-#ifndef i_valto
- #define i_valto c_default_toraw
-#endif
-#ifndef i_valclone
- #define i_valclone c_default_clone
-#endif
-#ifndef i_valdrop
- #define i_valdrop c_default_drop
-#endif
-
-#endif // !_i_ismap
-
-#ifndef i_val
- #define i_val i_key
-#endif
-#ifndef i_valraw
- #define i_valraw i_keyraw
-#endif
-#ifndef _i_has_from
- #define _i_no_emplace
-#endif
-
-#else // ============================================================
-
-#undef i_type
-#undef i_tag
-#undef i_imp
-#undef i_opt
-#undef i_less
-#undef i_cmp
-#undef i_eq
-#undef i_hash
-#undef i_size
-
-#undef i_val
-#undef i_val_str
-#undef i_val_ssv
-#undef i_val_arcbox
-#undef i_val_bind
-#undef i_valraw
-#undef i_valclone
-#undef i_valfrom
-#undef i_valto
-#undef i_valdrop
-
-#undef i_key
-#undef i_key_str
-#undef i_key_ssv
-#undef i_key_arcbox
-#undef i_key_bind
-#undef i_keyraw
-#undef i_keyclone
-#undef i_keyfrom
-#undef i_keyto
-#undef i_keydrop
-
-#undef i_header
-#undef i_implement
-#undef i_static
-#undef i_extern
-
-#undef _i_prefix
-#undef _i_has_from
-#undef _i_key_from_val
-#undef _i_no_clone
-#undef _i_no_emplace
-#undef _i_no_hash
-#undef _i_template
-#endif
+/* MIT License
+ *
+ * Copyright (c) 2022 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_self c_paste(_i_prefix, i_tag)
+ #define _cx_memb(name) c_paste(_cx_self, name)
+ #define _cx_deftypes(macro, SELF, ...) c_expand(macro(SELF, __VA_ARGS__))
+ #define _cx_value _cx_memb(_value)
+ #define _cx_key _cx_memb(_key)
+ #define _cx_mapped _cx_memb(_mapped)
+ #define _cx_raw _cx_memb(_raw)
+ #define _cx_rawkey _cx_memb(_rawkey)
+ #define _cx_rawmapped _cx_memb(_rawmapped)
+ #define _cx_iter _cx_memb(_iter)
+ #define _cx_result _cx_memb(_result)
+ #define _cx_node _cx_memb(_node)
+#endif
+
+#ifdef i_type
+ #define i_tag i_type
+ #undef _i_prefix
+ #define _i_prefix
+#endif
+
+#ifndef i_size
+ #define i_size uint32_t
+#endif
+
+#if !(defined i_key || defined i_key_str || defined i_key_ssv || \
+ defined i_key_bind || defined i_key_arcbox)
+ #define _i_key_from_val
+ #if defined _i_ismap
+ #error "i_key* must be defined for maps."
+ #endif
+
+ #if defined i_val_str
+ #define i_key_str i_val_str
+ #endif
+ #if defined i_val_ssv
+ #define i_key_ssv i_val_ssv
+ #endif
+ #if defined i_val_arcbox
+ #define i_key_arcbox i_val_arcbox
+ #endif
+ #if defined i_val_bind
+ #define i_key_bind i_val_bind
+ #endif
+ #if defined i_val
+ #define i_key i_val
+ #endif
+ #if defined i_valraw
+ #define i_keyraw i_valraw
+ #endif
+ #if defined i_valclone
+ #define i_keyclone i_valclone
+ #endif
+ #if defined i_valfrom
+ #define i_keyfrom i_valfrom
+ #endif
+ #if defined i_valto
+ #define i_keyto i_valto
+ #endif
+ #if defined i_valdrop
+ #define i_keydrop i_valdrop
+ #endif
+#endif
+
+#if defined i_key_str
+ #define i_key_bind cstr
+ #define i_keyraw crawstr
+ #define i_keyfrom cstr_from
+ #ifndef i_tag
+ #define i_tag str
+ #endif
+#elif defined i_key_ssv
+ #define i_key_bind cstr
+ #define i_keyraw csview
+ #define i_keyfrom cstr_from_sv
+ #define i_keyto cstr_sv
+ #define i_eq csview_eq
+ #ifndef i_tag
+ #define i_tag ssv
+ #endif
+#elif defined i_key_arcbox
+ #define i_key_bind i_key_arcbox
+ #define i_keyraw c_paste(i_key_arcbox, _value)
+ #define i_keyto c_paste(i_key, _toval)
+ #define i_eq c_paste(i_key_arcbox, _value_eq)
+#endif
+
+#ifdef i_key_bind
+ #define i_key i_key_bind
+ #ifndef i_keyclone
+ #define i_keyclone c_paste(i_key, _clone)
+ #endif
+ #if !defined i_keyto && defined i_keyraw
+ #define i_keyto c_paste(i_key, _toraw)
+ #endif
+ #ifndef i_keydrop
+ #define i_keydrop c_paste(i_key, _drop)
+ #endif
+ #ifndef i_cmp
+ #define i_cmp c_paste(i_keyraw, _cmp)
+ #endif
+ #if !defined i_hash
+ #define i_hash c_paste(i_keyraw, _hash)
+ #endif
+#endif
+
+#if !defined i_key
+ #error "no i_key or i_val defined"
+#elif defined i_keyraw ^ defined i_keyto
+ #error "both i_keyraw and i_keyto must be defined, if any"
+#elif defined i_keyfrom && !defined i_keyraw
+ #error "i_keyfrom defined without i_keyraw"
+#elif defined i_from || defined i_drop
+ #error "i_from / i_drop not supported. Define i_keyfrom/i_valfrom and/or i_keydrop/i_valdrop instead"
+#endif
+
+#ifndef i_tag
+ #define i_tag i_key
+#endif
+#if c_option(c_no_clone) || (!defined i_keyclone && (defined i_keydrop || defined i_keyraw))
+ #define _i_no_clone
+#endif
+#ifndef i_keyraw
+ #define i_keyraw i_key
+#endif
+#ifndef i_keyfrom
+ #define i_keyfrom c_default_clone
+#else
+ #define _i_has_from
+#endif
+#ifndef i_keyto
+ #define i_keyto c_default_toraw
+#endif
+#ifndef i_keyclone
+ #define i_keyclone c_default_clone
+#endif
+#ifndef i_keydrop
+ #define i_keydrop c_default_drop
+#endif
+#ifdef i_less
+ #define i_cmp(x, y) c_less_cmp(i_less, x, y)
+#endif
+#if !defined i_eq && defined i_cmp
+ #define i_eq(x, y) !(i_cmp(x, y))
+#elif !defined i_eq
+ #define i_eq c_default_eq
+#endif
+#ifndef i_cmp
+ #define i_cmp c_default_cmp
+#endif
+#ifndef i_hash
+ #define i_hash c_default_hash
+#endif
+
+#if defined _i_ismap // ---- process cmap/csmap value i_val, ... ----
+
+#ifdef i_val_str
+ #define i_val_bind cstr
+ #define i_valraw crawstr
+ #define i_valfrom cstr_from
+#elif defined i_val_ssv
+ #define i_val_bind cstr
+ #define i_valraw csview
+ #define i_valfrom cstr_from_sv
+ #define i_valto cstr_sv
+#elif defined i_val_arcbox
+ #define i_val_bind i_val_arcbox
+ #define i_valraw c_paste(i_val_arcbox, _value)
+ #define i_valto c_paste(i_val, _toval)
+#endif
+
+#ifdef i_val_bind
+ #define i_val i_val_bind
+ #ifndef i_valclone
+ #define i_valclone c_paste(i_val, _clone)
+ #endif
+ #if !defined i_valto && defined i_valraw
+ #define i_valto c_paste(i_val, _toraw)
+ #endif
+ #ifndef i_valdrop
+ #define i_valdrop c_paste(i_val, _drop)
+ #endif
+#endif
+
+#if defined i_valraw ^ defined i_valto
+ #error "both i_valto and i_valraw must be defined, if any"
+#elif defined i_valfrom && !defined i_valraw
+ #error "i_valfrom defined without i_valraw"
+#endif
+
+#if !defined i_valclone && (defined i_valdrop || defined i_valraw)
+ #define _i_no_clone
+#endif
+#ifndef i_valraw
+ #define i_valraw i_val
+#endif
+#ifndef i_valfrom
+ #define i_valfrom c_default_clone
+#else
+ #define _i_has_from
+#endif
+#ifndef i_valto
+ #define i_valto c_default_toraw
+#endif
+#ifndef i_valclone
+ #define i_valclone c_default_clone
+#endif
+#ifndef i_valdrop
+ #define i_valdrop c_default_drop
+#endif
+
+#endif // !_i_ismap
+
+#ifndef i_val
+ #define i_val i_key
+#endif
+#ifndef i_valraw
+ #define i_valraw i_keyraw
+#endif
+#ifndef _i_has_from
+ #define _i_no_emplace
+#endif
+
+#else // ============================================================
+
+#undef i_type
+#undef i_tag
+#undef i_imp
+#undef i_opt
+#undef i_less
+#undef i_cmp
+#undef i_eq
+#undef i_hash
+#undef i_size
+
+#undef i_val
+#undef i_val_str
+#undef i_val_ssv
+#undef i_val_arcbox
+#undef i_val_bind
+#undef i_valraw
+#undef i_valclone
+#undef i_valfrom
+#undef i_valto
+#undef i_valdrop
+
+#undef i_key
+#undef i_key_str
+#undef i_key_ssv
+#undef i_key_arcbox
+#undef i_key_bind
+#undef i_keyraw
+#undef i_keyclone
+#undef i_keyfrom
+#undef i_keyto
+#undef i_keydrop
+
+#undef i_header
+#undef i_implement
+#undef i_static
+#undef i_extern
+
+#undef _i_prefix
+#undef _i_has_from
+#undef _i_key_from_val
+#undef _i_no_clone
+#undef _i_no_emplace
+#undef _i_no_hash
+#undef _i_template
+#endif
diff --git a/include/stc/utf8.h b/include/stc/utf8.h
index 4910900c..b80d8594 100644
--- a/include/stc/utf8.h
+++ b/include/stc/utf8.h
@@ -1,95 +1,95 @@
-#ifndef UTF8_H_INCLUDED
-#define UTF8_H_INCLUDED
-/*
-// Example:
-#include <stc/cstr.h>
-#include <stc/csview.h>
-
-int main()
-{
- c_auto (cstr, s1) {
- s1 = cstr_new("hell😀 w😀rld");
- printf("%s\n", cstr_str(&s1));
- cstr_replace_sv(&s1, utf8_substr(cstr_str(&s1), 7, 1), c_sv("🐨"));
- printf("%s\n", cstr_str(&s1));
-
- c_foreach (i, cstr, s1)
- printf("%" c_PRIsv ",", c_ARGsv(i.chr));
- }
-}
-// Output:
-// hell😀 w😀rld
-// hell😀 w🐨rld
-// h,e,l,l,😀, ,w,🐨,r,l,d,
-*/
-#include "ccommon.h"
-#include <ctype.h>
-
-// utf8 methods defined in src/utf8code.c:
-bool utf8_islower(uint32_t c);
-bool utf8_isupper(uint32_t c);
-bool utf8_isspace(uint32_t c);
-bool utf8_isdigit(uint32_t c);
-bool utf8_isxdigit(uint32_t c);
-bool utf8_isalpha(uint32_t c);
-bool utf8_isalnum(uint32_t c);
-uint32_t utf8_tolower(uint32_t c);
-uint32_t utf8_toupper(uint32_t c);
-bool utf8_valid(const char* s);
-bool utf8_valid_n(const char* s, size_t n);
-int utf8_icmp_n(size_t u8max, const char* s1, size_t n1,
- const char* s2, size_t n2);
-unsigned utf8_encode(char *out, uint32_t c);
-
-/* decode next utf8 codepoint. https://bjoern.hoehrmann.de/utf-8/decoder/dfa */
-typedef struct { uint32_t state, codep; } utf8_decode_t;
-
-STC_INLINE uint32_t utf8_decode(utf8_decode_t* d, const uint32_t byte) {
- extern const uint8_t utf8_dtab[]; /* utf8code.c */
- const uint32_t type = utf8_dtab[byte];
- d->codep = d->state ? (byte & 0x3fu) | (d->codep << 6)
- : (0xff >> type) & byte;
- return d->state = utf8_dtab[256 + d->state + type];
-}
-
-/* case-insensitive utf8 string comparison */
-STC_INLINE int utf8_icmp(const char* s1, const char* s2) {
- return utf8_icmp_n(~(size_t)0, s1, ~(size_t)0, s2, ~(size_t)0);
-}
-
-/* number of characters in the utf8 codepoint from s */
-STC_INLINE unsigned utf8_codep_size(const char *s) {
- unsigned b = (uint8_t)*s;
- if (b < 0x80) return 1;
- if (b < 0xC2) return 0;
- if (b < 0xE0) return 2;
- if (b < 0xF0) return 3;
- if (b < 0xF5) return 4;
- return 0;
-}
-
-/* number of codepoints in the utf8 string s */
-STC_INLINE size_t utf8_size(const char *s) {
- size_t size = 0;
- while (*s)
- size += (*s++ & 0xC0) != 0x80;
- return size;
-}
-
-STC_INLINE size_t utf8_size_n(const char *s, size_t n) {
- size_t size = 0;
- while ((n-- != 0) & (*s != 0))
- size += (*s++ & 0xC0) != 0x80;
- return size;
-}
-
-STC_INLINE const char* utf8_at(const char *s, size_t index) {
- while ((index > 0) & (*s != 0))
- index -= (*++s & 0xC0) != 0x80;
- return s;
-}
-
-STC_INLINE size_t utf8_pos(const char* s, size_t index)
- { return utf8_at(s, index) - s; }
-
-#endif
+#ifndef UTF8_H_INCLUDED
+#define UTF8_H_INCLUDED
+/*
+// Example:
+#include <stc/cstr.h>
+#include <stc/csview.h>
+
+int main()
+{
+ c_auto (cstr, s1) {
+ s1 = cstr_new("hell😀 w😀rld");
+ printf("%s\n", cstr_str(&s1));
+ cstr_replace_sv(&s1, utf8_substr(cstr_str(&s1), 7, 1), c_sv("🐨"));
+ printf("%s\n", cstr_str(&s1));
+
+ c_foreach (i, cstr, s1)
+ printf("%" c_PRIsv ",", c_ARGsv(i.chr));
+ }
+}
+// Output:
+// hell😀 w😀rld
+// hell😀 w🐨rld
+// h,e,l,l,😀, ,w,🐨,r,l,d,
+*/
+#include "ccommon.h"
+#include <ctype.h>
+
+// utf8 methods defined in src/utf8code.c:
+bool utf8_islower(uint32_t c);
+bool utf8_isupper(uint32_t c);
+bool utf8_isspace(uint32_t c);
+bool utf8_isdigit(uint32_t c);
+bool utf8_isxdigit(uint32_t c);
+bool utf8_isalpha(uint32_t c);
+bool utf8_isalnum(uint32_t c);
+uint32_t utf8_tolower(uint32_t c);
+uint32_t utf8_toupper(uint32_t c);
+bool utf8_valid(const char* s);
+bool utf8_valid_n(const char* s, size_t n);
+int utf8_icmp_n(size_t u8max, const char* s1, size_t n1,
+ const char* s2, size_t n2);
+unsigned utf8_encode(char *out, uint32_t c);
+
+/* decode next utf8 codepoint. https://bjoern.hoehrmann.de/utf-8/decoder/dfa */
+typedef struct { uint32_t state, codep; } utf8_decode_t;
+
+STC_INLINE uint32_t utf8_decode(utf8_decode_t* d, const uint32_t byte) {
+ extern const uint8_t utf8_dtab[]; /* utf8code.c */
+ const uint32_t type = utf8_dtab[byte];
+ d->codep = d->state ? (byte & 0x3fu) | (d->codep << 6)
+ : (0xff >> type) & byte;
+ return d->state = utf8_dtab[256 + d->state + type];
+}
+
+/* case-insensitive utf8 string comparison */
+STC_INLINE int utf8_icmp(const char* s1, const char* s2) {
+ return utf8_icmp_n(~(size_t)0, s1, ~(size_t)0, s2, ~(size_t)0);
+}
+
+/* number of characters in the utf8 codepoint from s */
+STC_INLINE unsigned utf8_codep_size(const char *s) {
+ unsigned b = (uint8_t)*s;
+ if (b < 0x80) return 1;
+ if (b < 0xC2) return 0;
+ if (b < 0xE0) return 2;
+ if (b < 0xF0) return 3;
+ if (b < 0xF5) return 4;
+ return 0;
+}
+
+/* number of codepoints in the utf8 string s */
+STC_INLINE size_t utf8_size(const char *s) {
+ size_t size = 0;
+ while (*s)
+ size += (*s++ & 0xC0) != 0x80;
+ return size;
+}
+
+STC_INLINE size_t utf8_size_n(const char *s, size_t n) {
+ size_t size = 0;
+ while ((n-- != 0) & (*s != 0))
+ size += (*s++ & 0xC0) != 0x80;
+ return size;
+}
+
+STC_INLINE const char* utf8_at(const char *s, size_t index) {
+ while ((index > 0) & (*s != 0))
+ index -= (*++s & 0xC0) != 0x80;
+ return s;
+}
+
+STC_INLINE size_t utf8_pos(const char* s, size_t index)
+ { return utf8_at(s, index) - s; }
+
+#endif
diff --git a/src/cregex.c b/src/cregex.c
index 7ca9a336..712056c4 100644
--- a/src/cregex.c
+++ b/src/cregex.c
@@ -1,1186 +1,1186 @@
-/*
-This is a Unix port of the Plan 9 regular expression library, by Rob Pike.
-Please send comments about the packaging to Russ Cox <[email protected]>.
-
-Copyright © 2021 Plan 9 Foundation
-Copyright © 2022 Tyge Løvset, for additions made in 2022.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <setjmp.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stc/cregex.h>
-#include <stc/utf8.h>
-
-typedef uint32_t Rune; /* Utf8 code point */
-typedef int32_t Token;
-/* max character classes per program */
-#define NCLASS creg_max_classes
-/* max subexpressions */
-#define NSUBEXP creg_max_captures
-/* max rune ranges per character class */
-#define NCCRUNE (NSUBEXP * 2)
-
-/*
- * character class, each pair of rune's defines a range
- */
-typedef struct
-{
- Rune *end;
- Rune spans[NCCRUNE];
-} Reclass;
-
-/*
- * Machine instructions
- */
-typedef struct Reinst
-{
- Token type;
- union {
- Reclass *classp; /* class pointer */
- Rune rune; /* character */
- int subid; /* sub-expression id for RBRA and LBRA */
- struct Reinst *right; /* right child of OR */
- } r;
- union { /* regexp relies on these two being in the same union */
- struct Reinst *left; /* left child of OR */
- struct Reinst *next; /* next instruction for CAT & LBRA */
- } l;
-} Reinst;
-
-typedef struct {
- bool caseless;
- bool dotall;
-} Reflags;
-
-/*
- * Reprogram definition
- */
-typedef struct Reprog
-{
- Reinst *startinst; /* start pc */
- Reflags flags;
- int nsubids;
- Reclass cclass[NCLASS]; /* .data */
- Reinst firstinst[]; /* .text : originally 5 elements? */
-} Reprog;
-
-/*
- * Sub expression matches
- */
-typedef cregmatch Resub;
-
-/*
- * substitution list
- */
-typedef struct Resublist
-{
- Resub m[NSUBEXP];
-} Resublist;
-
-/*
- * Actions and Tokens (Reinst types)
- *
- * 0x800000-0x80FFFF: operators, value => precedence
- * 0x810000-0x81FFFF: RUNE and char classes.
- * 0x820000-0x82FFFF: tokens, i.e. operands for operators
- */
-enum {
- MASK = 0xFF00000,
- OPERATOR = 0x8000000, /* Bitmask of all operators */
- START = 0x8000001, /* Start, used for marker on stack */
- RBRA , /* Right bracket, ) */
- LBRA , /* Left bracket, ( */
- OR , /* Alternation, | */
- CAT , /* Concatentation, implicit operator */
- STAR , /* Closure, * */
- PLUS , /* a+ == aa* */
- QUEST , /* a? == a|nothing, i.e. 0 or 1 a's */
- RUNE = 0x8100000,
- IRUNE,
- ASC_bl , ASC_BL, /* blank */
- ASC_ct , ASC_CT, /* ctrl */
- ASC_gr , ASC_GR, /* graphic */
- ASC_pr , ASC_PR, /* print */
- ASC_pt , ASC_PT, /* punct */
- U8_Nd , U8N_Nd, /* dec digit, non-digit */
- U8_LC , U8N_LC, /* utf8 letter cased */
- U8_Ll , U8N_Ll, /* utf8 letter lower */
- U8_Lu , U8N_Lu, /* utf8 letter upper */
- U8_Zs , U8N_Zs, /* utf8 white space */
- U8_Xnx , U8N_Xnx, /* utf8 hex digit */
- U8_Xan , U8N_Xan, /* utf8 alphanumeric */
- U8_Xw , U8N_Xw, /* utf8 word */
- ANY = 0x8200000, /* Any character except newline, . */
- ANYNL , /* Any character including newline, . */
- NOP , /* No operation, internal use only */
- BOL , BOS, /* Beginning of line, string, ^ */
- EOL , EOS, EOZ, /* End of line, string, $ */
- CCLASS , /* Character class, [] */
- NCCLASS , /* Negated character class, [] */
- WBOUND , /* Non-word boundary, not consuming meta char */
- NWBOUND , /* Word boundary, not consuming meta char */
- END = 0x82FFFFF, /* Terminate: match found */
-};
-
-/*
- * regexec execution lists
- */
-#define LISTSIZE 10
-#define BIGLISTSIZE (10*LISTSIZE)
-
-typedef struct Relist
-{
- Reinst* inst; /* Reinstruction of the thread */
- Resublist se; /* matched subexpressions in this thread */
-} Relist;
-
-typedef struct Reljunk
-{
- Relist* relist[2];
- Relist* reliste[2];
- int starttype;
- Rune startchar;
- const char* starts;
- const char* eol;
-} Reljunk;
-
-/*
- * utf8 and Rune code
- */
-
-static int
-chartorune(Rune *rune, const char *s)
-{
- utf8_decode_t ctx = {.state=0};
- const uint8_t *b = (const uint8_t*)s;
- do { utf8_decode(&ctx, *b++); } while (ctx.state);
- *rune = ctx.codep;
- return (const char*)b - s;
-}
-
-static const char*
-utfrune(const char *s, Rune c)
-{
- Rune r;
-
- if (c < 128) /* ascii */
- return strchr((char *)s, c);
-
- for (;;) {
- int n = chartorune(&r, s);
- if (r == c) return s;
- if ((r == 0) | (n == 0)) return NULL;
- s += n;
- }
-}
-
-static const char*
-utfruneicase(const char *s, Rune c)
-{
- Rune r;
- c = utf8_tolower(c);
- for (;;) {
- int n = chartorune(&r, s);
- if (utf8_tolower(r) == c) return s;
- if ((r == 0) | (n == 0)) return NULL;
- s += n;
- }
-}
-
-/************
- * regaux.c *
- ************/
-
-/*
- * save a new match in mp
- */
-static void
-_renewmatch(Resub *mp, int ms, Resublist *sp, int nsubids)
-{
- int i;
-
- if (mp==NULL || ms<=0)
- return;
- if (mp[0].str == NULL || sp->m[0].str < mp[0].str ||
- (sp->m[0].str == mp[0].str && sp->m[0].size > mp[0].size)) {
- for (i=0; i<ms && i<=nsubids; i++)
- mp[i] = sp->m[i];
- }
-}
-
-/*
- * Note optimization in _renewthread:
- * *lp must be pending when _renewthread called; if *l has been looked
- * at already, the optimization is a bug.
- */
-static Relist*
-_renewthread(Relist *lp, /* _relist to add to */
- Reinst *ip, /* instruction to add */
- int ms,
- Resublist *sep) /* pointers to subexpressions */
-{
- Relist *p;
-
- for (p=lp; p->inst; p++) {
- if (p->inst == ip) {
- if (sep->m[0].str < p->se.m[0].str) {
- if (ms > 1)
- p->se = *sep;
- else
- p->se.m[0] = sep->m[0];
- }
- return 0;
- }
- }
- p->inst = ip;
- if (ms > 1)
- p->se = *sep;
- else
- p->se.m[0] = sep->m[0];
- (++p)->inst = NULL;
- return p;
-}
-
-/*
- * same as renewthread, but called with
- * initial empty start pointer.
- */
-static Relist*
-_renewemptythread(Relist *lp, /* _relist to add to */
- Reinst *ip, /* instruction to add */
- int ms,
- const char *sp) /* pointers to subexpressions */
-{
- Relist *p;
-
- for (p=lp; p->inst; p++) {
- if (p->inst == ip) {
- if (sp < p->se.m[0].str) {
- if (ms > 1)
- memset(&p->se, 0, sizeof(p->se));
- p->se.m[0].str = sp;
- }
- return 0;
- }
- }
- p->inst = ip;
- if (ms > 1)
- memset(&p->se, 0, sizeof(p->se));
- p->se.m[0].str = sp;
- (++p)->inst = NULL;
- return p;
-}
-
-/*
- * Parser Information
- */
-typedef struct Node
-{
- Reinst* first;
- Reinst* last;
-} Node;
-
-#define NSTACK 20
-typedef struct Parser
-{
- const char* exprp; /* pointer to next character in source expression */
- Node andstack[NSTACK];
- Node* andp;
- Token atorstack[NSTACK];
- Token* atorp;
- short subidstack[NSTACK]; /* parallel to atorstack */
- short* subidp;
- short cursubid; /* id of current subexpression */
- int errors;
- Reflags flags;
- int dot_type;
- int rune_type;
- bool litmode;
- bool lastwasand; /* Last token was operand */
- bool lexdone;
- short nbra;
- short nclass;
- Rune yyrune; /* last lex'd rune */
- Reclass *yyclassp; /* last lex'd class */
- Reclass* classp;
- Reinst* freep;
- jmp_buf regkaboom;
-} Parser;
-
-/* predeclared crap */
-static void _operator(Parser *par, Token type);
-static void pushand(Parser *par, Reinst *first, Reinst *last);
-static void pushator(Parser *par, Token type);
-static void evaluntil(Parser *par, Token type);
-static int bldcclass(Parser *par);
-
-static void
-rcerror(Parser *par, cregex_error_t err)
-{
- par->errors = err;
- longjmp(par->regkaboom, 1);
-}
-
-static Reinst*
-newinst(Parser *par, Token t)
-{
- par->freep->type = t;
- par->freep->l.left = 0;
- par->freep->r.right = 0;
- return par->freep++;
-}
-
-static void
-operand(Parser *par, Token t)
-{
- Reinst *i;
-
- if (par->lastwasand)
- _operator(par, CAT); /* catenate is implicit */
- i = newinst(par, t);
-
- if ((t == CCLASS) | (t == NCCLASS))
- i->r.classp = par->yyclassp;
- if ((t == RUNE) | (t == IRUNE))
- i->r.rune = par->yyrune;
-
- pushand(par, i, i);
- par->lastwasand = true;
-}
-
-static void
-_operator(Parser *par, Token t)
-{
- if (t==RBRA && --par->nbra<0)
- rcerror(par, creg_unmatchedrightparenthesis);
- if (t==LBRA) {
- if (++par->cursubid >= NSUBEXP)
- rcerror(par, creg_toomanysubexpressions);
- par->nbra++;
- if (par->lastwasand)
- _operator(par, CAT);
- } else
- evaluntil(par, t);
- if (t != RBRA)
- pushator(par, t);
- par->lastwasand = 0;
- if (t==STAR || t==QUEST || t==PLUS || t==RBRA)
- par->lastwasand = true; /* these look like operands */
-}
-
-static void
-pushand(Parser *par, Reinst *f, Reinst *l)
-{
- if (par->andp >= &par->andstack[NSTACK])
- rcerror(par, creg_operandstackoverflow);
- par->andp->first = f;
- par->andp->last = l;
- par->andp++;
-}
-
-static void
-pushator(Parser *par, Token t)
-{
- if (par->atorp >= &par->atorstack[NSTACK])
- rcerror(par, creg_operatorstackoverflow);
- *par->atorp++ = t;
- *par->subidp++ = par->cursubid;
-}
-
-static Node*
-popand(Parser *par, Token op)
-{
- Reinst *inst;
-
- if (par->andp <= &par->andstack[0]) {
- rcerror(par, creg_missingoperand);
- inst = newinst(par, NOP);
- pushand(par, inst, inst);
- }
- return --par->andp;
-}
-
-static Token
-popator(Parser *par)
-{
- if (par->atorp <= &par->atorstack[0])
- rcerror(par, creg_operatorstackunderflow);
- --par->subidp;
- return *--par->atorp;
-}
-
-static void
-evaluntil(Parser *par, Token pri)
-{
- Node *op1, *op2;
- Reinst *inst1, *inst2;
-
- while (pri==RBRA || par->atorp[-1]>=pri) {
- switch (popator(par)) {
- default:
- rcerror(par, creg_unknownoperator);
- break;
- case LBRA: /* must have been RBRA */
- op1 = popand(par, '(');
- inst2 = newinst(par, RBRA);
- inst2->r.subid = *par->subidp;
- op1->last->l.next = inst2;
- inst1 = newinst(par, LBRA);
- inst1->r.subid = *par->subidp;
- inst1->l.next = op1->first;
- pushand(par, inst1, inst2);
- return;
- case OR:
- op2 = popand(par, '|');
- op1 = popand(par, '|');
- inst2 = newinst(par, NOP);
- op2->last->l.next = inst2;
- op1->last->l.next = inst2;
- inst1 = newinst(par, OR);
- inst1->r.right = op1->first;
- inst1->l.left = op2->first;
- pushand(par, inst1, inst2);
- break;
- case CAT:
- op2 = popand(par, 0);
- op1 = popand(par, 0);
- op1->last->l.next = op2->first;
- pushand(par, op1->first, op2->last);
- break;
- case STAR:
- op2 = popand(par, '*');
- inst1 = newinst(par, OR);
- op2->last->l.next = inst1;
- inst1->r.right = op2->first;
- pushand(par, inst1, inst1);
- break;
- case PLUS:
- op2 = popand(par, '+');
- inst1 = newinst(par, OR);
- op2->last->l.next = inst1;
- inst1->r.right = op2->first;
- pushand(par, op2->first, inst1);
- break;
- case QUEST:
- op2 = popand(par, '?');
- inst1 = newinst(par, OR);
- inst2 = newinst(par, NOP);
- inst1->l.left = inst2;
- inst1->r.right = op2->first;
- op2->last->l.next = inst2;
- pushand(par, inst1, inst2);
- break;
- }
- }
-}
-
-static Reprog*
-optimize(Parser *par, Reprog *pp)
-{
- Reinst *inst, *target;
- size_t size;
- Reprog *npp;
- Reclass *cl;
- ptrdiff_t diff;
-
- /*
- * get rid of NOOP chains
- */
- for (inst = pp->firstinst; inst->type != END; inst++) {
- target = inst->l.next;
- while (target->type == NOP)
- target = target->l.next;
- inst->l.next = target;
- }
-
- /*
- * The original allocation is for an area larger than
- * necessary. Reallocate to the actual space used
- * and then relocate the code.
- */
- size = sizeof(Reprog) + (par->freep - pp->firstinst)*sizeof(Reinst);
- npp = (Reprog *)realloc(pp, size);
- if (npp==NULL || npp==pp)
- return pp;
- diff = (char *)npp - (char *)pp;
- par->freep = (Reinst *)((char *)par->freep + diff);
- for (inst = npp->firstinst; inst < par->freep; inst++) {
- switch (inst->type) {
- case OR:
- case STAR:
- case PLUS:
- case QUEST:
- inst->r.right = (Reinst *)((char*)inst->r.right + diff);
- break;
- case CCLASS:
- case NCCLASS:
- inst->r.right = (Reinst *)((char*)inst->r.right + diff);
- cl = inst->r.classp;
- cl->end = (Rune *)((char*)cl->end + diff);
- break;
- }
- inst->l.left = (Reinst *)((char*)inst->l.left + diff);
- }
- npp->startinst = (Reinst *)((char*)npp->startinst + diff);
- return npp;
-}
-
-static Reclass*
-newclass(Parser *par)
-{
- if (par->nclass >= NCLASS)
- rcerror(par, creg_toomanycharacterclasses);
- return &(par->classp[par->nclass++]);
-}
-
-static int
-nextc(Parser *par, Rune *rp)
-{
- if (par->lexdone) {
- *rp = 0;
- return 1;
- }
- par->exprp += chartorune(rp, par->exprp);
- if (*rp == '\\') {
- if (par->litmode && *par->exprp != 'E')
- return 1;
- par->exprp += chartorune(rp, par->exprp);
- switch (*rp) {
- case 'E': return par->litmode + 1;
- case 't': *rp = '\t'; break;
- case 'n': *rp = '\n'; break;
- case 'r': *rp = '\r'; break;
- case 'v': *rp = '\v'; break;
- case 'f': *rp = '\f'; break;
- case 'd': *rp = U8_Nd; break;
- case 'D': *rp = U8N_Nd; break;
- case 's': *rp = U8_Zs; break;
- case 'S': *rp = U8N_Zs; break;
- case 'w': *rp = U8_Xw; break;
- case 'W': *rp = U8N_Xw; break;
- case 'x': if (*par->exprp != '{') break;
- *rp = 0; sscanf(++par->exprp, "%x", rp);
- while (*par->exprp) if (*(par->exprp++) == '}') break;
- if (par->exprp[-1] != '}')
- rcerror(par, creg_unmatchedrightparenthesis);
- return 2;
- case 'p': case 'P': { /* https://www.regular-expressions.info/unicode.html */
- static struct { const char* c; int n, r; } cls[] = {
- {"{Alpha}", 7, U8_LC}, {"{LC}", 4, U8_LC},
- {"{Alnum}", 7, U8_Xan},
- {"{Digit}", 7, U8_Nd}, {"{Nd}", 4, U8_Nd},
- {"{Lower}", 7, U8_Ll}, {"{Ll}", 4, U8_Ll},
- {"{Space}", 7, U8_Zs}, {"{Zs}", 4, U8_Zs},
- {"{Upper}", 7, U8_Lu}, {"{Lu}", 4, U8_Lu},
- {"{XDigit}", 8, U8_Xnx},
- {"{Blank}", 7, ASC_bl},
- {"{Graph}", 7, ASC_gr},
- {"{Print}", 7, ASC_pr},
- {"{Punct}", 7, ASC_pt},
- };
- int inv = *rp == 'P';
- for (unsigned i = 0; i < (sizeof cls/sizeof *cls); ++i)
- if (!strncmp(par->exprp, cls[i].c, cls[i].n)) {
- if (par->rune_type == IRUNE && (cls[i].r == U8_Ll || cls[i].r == U8_Lu))
- *rp = U8_LC + inv;
- else
- *rp = cls[i].r + inv;
- par->exprp += cls[i].n;
- break;
- }
- if (*rp < OPERATOR) {
- rcerror(par, creg_unknownoperator);
- *rp = 0;
- }
- break;
- }
- }
- return 1;
- }
- if (*rp == 0)
- par->lexdone = true;
- return par->litmode;
-}
-
-static Token
-lex(Parser *par)
-{
- int quoted;
- start:
- quoted = nextc(par, &par->yyrune);
- if (quoted) {
- if (quoted == 2) {
- if (par->litmode && par->yyrune == 'E') {
- par->litmode = false;
- goto start;
- }
- return par->yyrune == 0 ? END : par->rune_type;
- }
- switch (par->yyrune) {
- case 0 : return END;
- case 'b': return WBOUND;
- case 'B': return NWBOUND;
- case 'A': return BOS;
- case 'z': return EOS;
- case 'Z': return EOZ;
- case 'Q': par->litmode = true;
- goto start;
- default : return par->rune_type;
- }
- }
-
- switch (par->yyrune) {
- case 0 : return END;
- case '*': return STAR;
- case '?': return QUEST;
- case '+': return PLUS;
- case '|': return OR;
- case '.': return par->dot_type;
- case '(':
- if (par->exprp[0] == '?') {
- for (int k = 1, enable = 1; ; ++k) switch (par->exprp[k]) {
- case 0 : par->exprp += k; return END;
- case ')': par->exprp += k + 1; goto start;
- case '-': enable = 0; break;
- case 's': if (!par->flags.dotall) par->dot_type = ANY + enable; break;
- case 'i': if (!par->flags.caseless) par->rune_type = RUNE + enable; break;
- default: rcerror(par, creg_unknownoperator); return 0;
- }
- }
- return LBRA;
- case ')': return RBRA;
- case '^': return BOL;
- case '$': return EOL;
- case '[': return bldcclass(par);
- }
- return par->rune_type;
-}
-
-static Token
-bldcclass(Parser *par)
-{
- Token type;
- Rune r[NCCRUNE];
- Rune *p, *ep, *np;
- Rune rune;
- int quoted;
-
- /* we have already seen the '[' */
- type = CCLASS;
- par->yyclassp = newclass(par);
-
- /* look ahead for negation */
- /* SPECIAL CASE!!! negated classes don't match \n */
- ep = r;
- quoted = nextc(par, &rune);
- if (!quoted && rune == '^') {
- type = NCCLASS;
- quoted = nextc(par, &rune);
- *ep++ = '\n';
- *ep++ = '\n';
- }
-
- /* parse class into a set of spans */
- for (; ep < &r[NCCRUNE]; quoted = nextc(par, &rune)) {
- if (rune == 0) {
- rcerror(par, creg_malformedcharacterclass);
- return 0;
- }
- if (!quoted) {
- if (rune == ']')
- break;
- if (rune == '-') {
- if (ep != r && *par->exprp != ']') {
- quoted = nextc(par, &rune);
- if (rune == 0) {
- rcerror(par, creg_malformedcharacterclass);
- return 0;
- }
- ep[-1] = rune;
- continue;
- }
- }
- }
- *ep++ = rune;
- *ep++ = rune;
- }
-
- /* sort on span start */
- for (p = r; p < ep; p += 2) {
- for (np = p; np < ep; np += 2)
- if (*np < *p) {
- rune = np[0];
- np[0] = p[0];
- p[0] = rune;
- rune = np[1];
- np[1] = p[1];
- p[1] = rune;
- }
- }
-
- /* merge spans */
- np = par->yyclassp->spans;
- p = r;
- if (r == ep)
- par->yyclassp->end = np;
- else {
- np[0] = *p++;
- np[1] = *p++;
- for (; p < ep; p += 2)
- if (p[0] <= np[1]) {
- if (p[1] > np[1])
- np[1] = p[1];
- } else {
- np += 2;
- np[0] = p[0];
- np[1] = p[1];
- }
- par->yyclassp->end = np+2;
- }
-
- return type;
-}
-
-static Reprog*
-regcomp1(Parser *par, const char *s, int cflags)
-{
- Token token;
- Reprog *volatile pp;
-
- /* get memory for the program. estimated max usage */
- const int instcap = 5 + 6*strlen(s);
- pp = (Reprog *)malloc(sizeof(Reprog) + instcap*sizeof(Reinst));
- if (pp == NULL) {
- rcerror(par, creg_outofmemory);
- return NULL;
- }
- pp->flags.caseless = (cflags & creg_caseless) != 0;
- pp->flags.dotall = (cflags & creg_dotall) != 0;
- par->freep = pp->firstinst;
- par->classp = pp->cclass;
- par->errors = 0;
-
- if (setjmp(par->regkaboom))
- goto out;
-
- /* go compile the sucker */
- par->lexdone = false;
- par->flags = pp->flags;
- par->rune_type = pp->flags.caseless ? IRUNE : RUNE;
- par->dot_type = pp->flags.dotall ? ANYNL : ANY;
- par->litmode = false;
- par->exprp = s;
- par->nclass = 0;
- par->nbra = 0;
- par->atorp = par->atorstack;
- par->andp = par->andstack;
- par->subidp = par->subidstack;
- par->lastwasand = false;
- par->cursubid = 0;
-
- /* Start with a low priority operator to prime parser */
- pushator(par, START-1);
- while ((token = lex(par)) != END) {
- if ((token & MASK) == OPERATOR)
- _operator(par, token);
- else
- operand(par, token);
- }
-
- /* Close with a low priority operator */
- evaluntil(par, START);
-
- /* Force END */
- operand(par, END);
- evaluntil(par, START);
-#ifdef DEBUG
- dumpstack(par);
-#endif
- if (par->nbra)
- rcerror(par, creg_unmatchedleftparenthesis);
- --par->andp; /* points to first and only operand */
- pp->startinst = par->andp->first;
-#ifdef DEBUG
- dump(pp);
-#endif
- pp = optimize(par, pp);
- pp->nsubids = par->cursubid;
-#ifdef DEBUG
- print("start: %d\n", par->andp->first-pp->firstinst);
- dump(pp);
-#endif
-out:
- if (par->errors) {
- free(pp);
- pp = NULL;
- }
- return pp;
-}
-
-
-static int
-runematch(Rune s, Rune r, bool icase)
-{
- int inv = 0;
- switch (s) {
- case ASC_BL: inv = 1; /* fallthrough */
- case ASC_bl: return inv ^ ((r == ' ') | (r == '\t'));
- case ASC_CT: inv = 1;
- case ASC_ct: return inv ^ (iscntrl(r) != 0);
- case ASC_GR: inv = 1;
- case ASC_gr: return inv ^ (isgraph(r) != 0);
- case ASC_PR: inv = 1;
- case ASC_pr: return inv ^ (isprint(r) != 0);
- case ASC_PT: inv = 1;
- case ASC_pt: return inv ^ (ispunct(r) != 0);
- case U8N_Nd: inv = 1;
- case U8_Nd: return inv ^ (utf8_isdigit(r));
- case U8N_LC: inv = 1;
- case U8_LC: return inv ^ utf8_isalpha(r);
- case U8N_Ll: inv = 1;
- case U8_Ll: return inv ^ utf8_islower(r);
- case U8N_Lu: inv = 1;
- case U8_Lu: return inv ^ utf8_isupper(r);
- case U8N_Zs: inv = 1;
- case U8_Zs: return inv ^ utf8_isspace(r);
- case U8N_Xan: inv = 1;
- case U8_Xan: return inv ^ utf8_isalnum(r);
- case U8N_Xnx: inv = 1;
- case U8_Xnx: return inv ^ utf8_isxdigit(r);
- case U8N_Xw: inv = 1;
- case U8_Xw: return inv ^ (utf8_isalnum(r) | (r == '_'));
- }
- return icase ? utf8_tolower(s) == utf8_tolower(r) : s == r;
-}
-
-/*
- * return 0 if no match
- * >0 if a match
- * <0 if we ran out of _relist space
- */
-static int
-regexec1(const Reprog *progp, /* program to run */
- const char *bol, /* string to run machine on */
- Resub *mp, /* subexpression elements */
- int ms, /* number of elements at mp */
- Reljunk *j,
- int mflags
-)
-{
- int flag=0;
- Reinst *inst;
- Relist *tlp;
- Relist *tl, *nl; /* This list, next list */
- Relist *tle, *nle; /* Ends of this and next list */
- const char *s, *p;
- int i, n, checkstart;
- Rune r, *rp, *ep;
- int match = 0;
-
- bool icase = progp->flags.caseless;
- checkstart = j->starttype;
- if (mp)
- for (i=0; i<ms; i++) {
- mp[i].str = NULL;
- mp[i].size = 0;
- }
- j->relist[0][0].inst = NULL;
- j->relist[1][0].inst = NULL;
-
- /* Execute machine once for each character, including terminal NUL */
- s = j->starts;
- do {
- /* fast check for first char */
- if (checkstart) {
- switch (j->starttype) {
- case IRUNE:
- p = utfruneicase(s, j->startchar);
- goto next1;
- case RUNE:
- p = utfrune(s, j->startchar);
- next1:
- if (p == NULL || s == j->eol)
- return match;
- s = p;
- break;
- case BOL:
- if (s == bol)
- break;
- p = utfrune(s, '\n');
- if (p == NULL || s == j->eol)
- return match;
- s = p+1;
- break;
- }
- }
- n = chartorune(&r, s);
-
- /* switch run lists */
- tl = j->relist[flag];
- tle = j->reliste[flag];
- nl = j->relist[flag^=1];
- nle = j->reliste[flag];
- nl->inst = NULL;
-
- /* Add first instruction to current list */
- if (match == 0)
- _renewemptythread(tl, progp->startinst, ms, s);
-
- /* Execute machine until current list is empty */
- for (tlp=tl; tlp->inst; tlp++) { /* assignment = */
- for (inst = tlp->inst; ; inst = inst->l.next) {
- int ok = false;
-
- switch (inst->type) {
- case RUNE:
- case IRUNE: /* regular character */
- ok = runematch(inst->r.rune, r, (icase = inst->type==IRUNE));
- break;
- case LBRA:
- tlp->se.m[inst->r.subid].str = s;
- continue;
- case RBRA:
- tlp->se.m[inst->r.subid].size = s - tlp->se.m[inst->r.subid].str;
- continue;
- case ANY:
- ok = (r != '\n');
- break;
- case ANYNL:
- ok = true;
- break;
- case BOL:
- if (s == bol || s[-1] == '\n') continue;
- break;
- case BOS:
- if (s == bol) continue;
- break;
- case EOL:
- if (r == '\n') continue;
- case EOS: /* fallthrough */
- if (s == j->eol || r == 0) continue;
- break;
- case EOZ:
- if (s == j->eol || r == 0 || (r == '\n' && s[1] == 0)) continue;
- break;
- case NWBOUND:
- ok = true;
- case WBOUND: /* fallthrough */
- if (ok ^ (s == bol || s == j->eol || ((utf8_isalnum(s[-1]) || s[-1] == '_')
- ^ (utf8_isalnum(s[ 0]) || s[ 0] == '_'))))
- continue;
- break;
- case NCCLASS:
- ok = true;
- case CCLASS: /* fallthrough */
- ep = inst->r.classp->end;
- for (rp = inst->r.classp->spans; rp < ep; rp += 2) {
- if ((r >= rp[0] && r <= rp[1]) || (rp[0] == rp[1] && runematch(rp[0], r, icase)))
- break;
- }
- ok ^= (rp < ep);
- break;
- case OR:
- /* evaluate right choice later */
- if (_renewthread(tlp, inst->r.right, ms, &tlp->se) == tle)
- return -1;
- /* efficiency: advance and re-evaluate */
- continue;
- case END: /* Match! */
- match = !(mflags & creg_fullmatch) ||
- ((s == j->eol || r == 0 || r == '\n') &&
- (tlp->se.m[0].str == bol || tlp->se.m[0].str[-1] == '\n'));
- tlp->se.m[0].size = s - tlp->se.m[0].str;
- if (mp != NULL)
- _renewmatch(mp, ms, &tlp->se, progp->nsubids);
- break;
- }
-
- if (ok && _renewthread(nl, inst->l.next, ms, &tlp->se) == nle)
- return -1;
- break;
- }
- }
- if (s == j->eol)
- break;
- checkstart = j->starttype && nl->inst==NULL;
- s += n;
- } while (r);
- return match;
-}
-
-static int
-regexec2(const Reprog *progp, /* program to run */
- const char *bol, /* string to run machine on */
- Resub *mp, /* subexpression elements */
- int ms, /* number of elements at mp */
- Reljunk *j,
- int mflags
-)
-{
- int rv;
- Relist *relists;
-
- /* mark space */
- relists = (Relist *)malloc(2 * BIGLISTSIZE*sizeof(Relist));
- if (relists == NULL)
- return -1;
-
- j->relist[0] = relists;
- j->relist[1] = relists + BIGLISTSIZE;
- j->reliste[0] = relists + BIGLISTSIZE - 2;
- j->reliste[1] = relists + 2*BIGLISTSIZE - 2;
-
- rv = regexec1(progp, bol, mp, ms, j, mflags);
- free(relists);
- return rv;
-}
-
-static int
-regexec9(const Reprog *progp, /* program to run */
- const char *bol, /* string to run machine on */
- int ms, /* number of elements at mp */
- Resub mp[], /* subexpression elements */
- int mflags)
-{
- Reljunk j;
- Relist relist0[LISTSIZE], relist1[LISTSIZE];
- int rv;
-
- /*
- * use user-specified starting/ending location if specified
- */
- j.starts = bol;
- j.eol = NULL;
-
- if (mp && mp->str && ms>0) {
- if (mflags & creg_startend)
- j.starts = mp->str, j.eol = mp->str + mp->size;
- else if (mflags & creg_next)
- j.starts = mp->str + mp->size;
- }
-
- j.starttype = 0;
- j.startchar = 0;
- int rune_type = progp->flags.caseless ? IRUNE : RUNE;
- if (progp->startinst->type == rune_type && progp->startinst->r.rune < 128) {
- j.starttype = rune_type;
- j.startchar = progp->startinst->r.rune;
- }
- if (progp->startinst->type == BOL)
- j.starttype = BOL;
-
- /* mark space */
- j.relist[0] = relist0;
- j.relist[1] = relist1;
- j.reliste[0] = relist0 + LISTSIZE - 2;
- j.reliste[1] = relist1 + LISTSIZE - 2;
-
- rv = regexec1(progp, bol, mp, ms, &j, mflags);
- if (rv >= 0)
- return rv;
- rv = regexec2(progp, bol, mp, ms, &j, mflags);
- return rv;
-}
-
-/*
- * API functions
- */
-
-/* substitute into one string using the matches from the last regexec() */
-void cregex_replace(
- const char *sp, /* source string */
- char *dp, /* destination string */
- int dlen,
- int ms, /* number of elements pointed to by mp */
- const cregmatch mp[]) /* subexpression elements */
-{
- const char *ssp, *ep;
- int i;
-
- ep = dp+dlen-1;
- while (*sp != '\0') {
- if (*sp == '\\') {
- switch (*++sp) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- i = *sp - '0';
- if (mp[i].str != NULL && mp != NULL && ms > i)
- for (ssp = mp[i].str; ssp < (mp[i].str + mp[i].size); ssp++)
- if (dp < ep)
- *dp++ = *ssp;
- break;
- case '\\':
- if (dp < ep)
- *dp++ = '\\';
- break;
- case '\0':
- sp--;
- break;
- default:
- if (dp < ep)
- *dp++ = *sp;
- break;
- }
- } else if (*sp == '&') {
- if (mp[0].str != NULL && mp != NULL && ms > 0)
- for (ssp = mp[0].str; ssp < (mp[0].str + mp[0].size); ssp++)
- if (dp < ep)
- *dp++ = *ssp;
- } else {
- if (dp < ep)
- *dp++ = *sp;
- }
- sp++;
- }
- *dp = '\0';
-}
-
-int cregex_compile(cregex *rx, const char* pattern, int cflags) {
- Parser par;
- rx->prog = regcomp1(&par, pattern, cflags);
- if (rx->prog)
- return 1 + rx->prog->nsubids;
- return par.errors;
-}
-
-int cregex_captures(cregex rx) {
- return rx.prog ? 1 + rx.prog->nsubids : 0;
-}
-
-int cregex_find(const cregex *rx, const char* string,
- size_t nmatch, cregmatch match[], int mflags) {
- int res = regexec9(rx->prog, string, nmatch, match, mflags);
- switch (res) {
- case 1: return 1 + rx->prog->nsubids;
- case 0: return creg_nomatch;
- default: return creg_matcherror;
- }
-}
-
-void cregex_drop(cregex* self) {
- free(self->prog);
-}
+/*
+This is a Unix port of the Plan 9 regular expression library, by Rob Pike.
+Please send comments about the packaging to Russ Cox <[email protected]>.
+
+Copyright © 2021 Plan 9 Foundation
+Copyright © 2022 Tyge Løvset, for additions made in 2022.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <setjmp.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stc/cregex.h>
+#include <stc/utf8.h>
+
+typedef uint32_t Rune; /* Utf8 code point */
+typedef int32_t Token;
+/* max character classes per program */
+#define NCLASS creg_max_classes
+/* max subexpressions */
+#define NSUBEXP creg_max_captures
+/* max rune ranges per character class */
+#define NCCRUNE (NSUBEXP * 2)
+
+/*
+ * character class, each pair of rune's defines a range
+ */
+typedef struct
+{
+ Rune *end;
+ Rune spans[NCCRUNE];
+} Reclass;
+
+/*
+ * Machine instructions
+ */
+typedef struct Reinst
+{
+ Token type;
+ union {
+ Reclass *classp; /* class pointer */
+ Rune rune; /* character */
+ int subid; /* sub-expression id for RBRA and LBRA */
+ struct Reinst *right; /* right child of OR */
+ } r;
+ union { /* regexp relies on these two being in the same union */
+ struct Reinst *left; /* left child of OR */
+ struct Reinst *next; /* next instruction for CAT & LBRA */
+ } l;
+} Reinst;
+
+typedef struct {
+ bool caseless;
+ bool dotall;
+} Reflags;
+
+/*
+ * Reprogram definition
+ */
+typedef struct Reprog
+{
+ Reinst *startinst; /* start pc */
+ Reflags flags;
+ int nsubids;
+ Reclass cclass[NCLASS]; /* .data */
+ Reinst firstinst[]; /* .text : originally 5 elements? */
+} Reprog;
+
+/*
+ * Sub expression matches
+ */
+typedef cregmatch Resub;
+
+/*
+ * substitution list
+ */
+typedef struct Resublist
+{
+ Resub m[NSUBEXP];
+} Resublist;
+
+/*
+ * Actions and Tokens (Reinst types)
+ *
+ * 0x800000-0x80FFFF: operators, value => precedence
+ * 0x810000-0x81FFFF: RUNE and char classes.
+ * 0x820000-0x82FFFF: tokens, i.e. operands for operators
+ */
+enum {
+ MASK = 0xFF00000,
+ OPERATOR = 0x8000000, /* Bitmask of all operators */
+ START = 0x8000001, /* Start, used for marker on stack */
+ RBRA , /* Right bracket, ) */
+ LBRA , /* Left bracket, ( */
+ OR , /* Alternation, | */
+ CAT , /* Concatentation, implicit operator */
+ STAR , /* Closure, * */
+ PLUS , /* a+ == aa* */
+ QUEST , /* a? == a|nothing, i.e. 0 or 1 a's */
+ RUNE = 0x8100000,
+ IRUNE,
+ ASC_bl , ASC_BL, /* blank */
+ ASC_ct , ASC_CT, /* ctrl */
+ ASC_gr , ASC_GR, /* graphic */
+ ASC_pr , ASC_PR, /* print */
+ ASC_pt , ASC_PT, /* punct */
+ U8_Nd , U8N_Nd, /* dec digit, non-digit */
+ U8_LC , U8N_LC, /* utf8 letter cased */
+ U8_Ll , U8N_Ll, /* utf8 letter lower */
+ U8_Lu , U8N_Lu, /* utf8 letter upper */
+ U8_Zs , U8N_Zs, /* utf8 white space */
+ U8_Xnx , U8N_Xnx, /* utf8 hex digit */
+ U8_Xan , U8N_Xan, /* utf8 alphanumeric */
+ U8_Xw , U8N_Xw, /* utf8 word */
+ ANY = 0x8200000, /* Any character except newline, . */
+ ANYNL , /* Any character including newline, . */
+ NOP , /* No operation, internal use only */
+ BOL , BOS, /* Beginning of line, string, ^ */
+ EOL , EOS, EOZ, /* End of line, string, $ */
+ CCLASS , /* Character class, [] */
+ NCCLASS , /* Negated character class, [] */
+ WBOUND , /* Non-word boundary, not consuming meta char */
+ NWBOUND , /* Word boundary, not consuming meta char */
+ END = 0x82FFFFF, /* Terminate: match found */
+};
+
+/*
+ * regexec execution lists
+ */
+#define LISTSIZE 10
+#define BIGLISTSIZE (10*LISTSIZE)
+
+typedef struct Relist
+{
+ Reinst* inst; /* Reinstruction of the thread */
+ Resublist se; /* matched subexpressions in this thread */
+} Relist;
+
+typedef struct Reljunk
+{
+ Relist* relist[2];
+ Relist* reliste[2];
+ int starttype;
+ Rune startchar;
+ const char* starts;
+ const char* eol;
+} Reljunk;
+
+/*
+ * utf8 and Rune code
+ */
+
+static int
+chartorune(Rune *rune, const char *s)
+{
+ utf8_decode_t ctx = {.state=0};
+ const uint8_t *b = (const uint8_t*)s;
+ do { utf8_decode(&ctx, *b++); } while (ctx.state);
+ *rune = ctx.codep;
+ return (const char*)b - s;
+}
+
+static const char*
+utfrune(const char *s, Rune c)
+{
+ Rune r;
+
+ if (c < 128) /* ascii */
+ return strchr((char *)s, c);
+
+ for (;;) {
+ int n = chartorune(&r, s);
+ if (r == c) return s;
+ if ((r == 0) | (n == 0)) return NULL;
+ s += n;
+ }
+}
+
+static const char*
+utfruneicase(const char *s, Rune c)
+{
+ Rune r;
+ c = utf8_tolower(c);
+ for (;;) {
+ int n = chartorune(&r, s);
+ if (utf8_tolower(r) == c) return s;
+ if ((r == 0) | (n == 0)) return NULL;
+ s += n;
+ }
+}
+
+/************
+ * regaux.c *
+ ************/
+
+/*
+ * save a new match in mp
+ */
+static void
+_renewmatch(Resub *mp, int ms, Resublist *sp, int nsubids)
+{
+ int i;
+
+ if (mp==NULL || ms<=0)
+ return;
+ if (mp[0].str == NULL || sp->m[0].str < mp[0].str ||
+ (sp->m[0].str == mp[0].str && sp->m[0].size > mp[0].size)) {
+ for (i=0; i<ms && i<=nsubids; i++)
+ mp[i] = sp->m[i];
+ }
+}
+
+/*
+ * Note optimization in _renewthread:
+ * *lp must be pending when _renewthread called; if *l has been looked
+ * at already, the optimization is a bug.
+ */
+static Relist*
+_renewthread(Relist *lp, /* _relist to add to */
+ Reinst *ip, /* instruction to add */
+ int ms,
+ Resublist *sep) /* pointers to subexpressions */
+{
+ Relist *p;
+
+ for (p=lp; p->inst; p++) {
+ if (p->inst == ip) {
+ if (sep->m[0].str < p->se.m[0].str) {
+ if (ms > 1)
+ p->se = *sep;
+ else
+ p->se.m[0] = sep->m[0];
+ }
+ return 0;
+ }
+ }
+ p->inst = ip;
+ if (ms > 1)
+ p->se = *sep;
+ else
+ p->se.m[0] = sep->m[0];
+ (++p)->inst = NULL;
+ return p;
+}
+
+/*
+ * same as renewthread, but called with
+ * initial empty start pointer.
+ */
+static Relist*
+_renewemptythread(Relist *lp, /* _relist to add to */
+ Reinst *ip, /* instruction to add */
+ int ms,
+ const char *sp) /* pointers to subexpressions */
+{
+ Relist *p;
+
+ for (p=lp; p->inst; p++) {
+ if (p->inst == ip) {
+ if (sp < p->se.m[0].str) {
+ if (ms > 1)
+ memset(&p->se, 0, sizeof(p->se));
+ p->se.m[0].str = sp;
+ }
+ return 0;
+ }
+ }
+ p->inst = ip;
+ if (ms > 1)
+ memset(&p->se, 0, sizeof(p->se));
+ p->se.m[0].str = sp;
+ (++p)->inst = NULL;
+ return p;
+}
+
+/*
+ * Parser Information
+ */
+typedef struct Node
+{
+ Reinst* first;
+ Reinst* last;
+} Node;
+
+#define NSTACK 20
+typedef struct Parser
+{
+ const char* exprp; /* pointer to next character in source expression */
+ Node andstack[NSTACK];
+ Node* andp;
+ Token atorstack[NSTACK];
+ Token* atorp;
+ short subidstack[NSTACK]; /* parallel to atorstack */
+ short* subidp;
+ short cursubid; /* id of current subexpression */
+ int errors;
+ Reflags flags;
+ int dot_type;
+ int rune_type;
+ bool litmode;
+ bool lastwasand; /* Last token was operand */
+ bool lexdone;
+ short nbra;
+ short nclass;
+ Rune yyrune; /* last lex'd rune */
+ Reclass *yyclassp; /* last lex'd class */
+ Reclass* classp;
+ Reinst* freep;
+ jmp_buf regkaboom;
+} Parser;
+
+/* predeclared crap */
+static void _operator(Parser *par, Token type);
+static void pushand(Parser *par, Reinst *first, Reinst *last);
+static void pushator(Parser *par, Token type);
+static void evaluntil(Parser *par, Token type);
+static int bldcclass(Parser *par);
+
+static void
+rcerror(Parser *par, cregex_error_t err)
+{
+ par->errors = err;
+ longjmp(par->regkaboom, 1);
+}
+
+static Reinst*
+newinst(Parser *par, Token t)
+{
+ par->freep->type = t;
+ par->freep->l.left = 0;
+ par->freep->r.right = 0;
+ return par->freep++;
+}
+
+static void
+operand(Parser *par, Token t)
+{
+ Reinst *i;
+
+ if (par->lastwasand)
+ _operator(par, CAT); /* catenate is implicit */
+ i = newinst(par, t);
+
+ if ((t == CCLASS) | (t == NCCLASS))
+ i->r.classp = par->yyclassp;
+ if ((t == RUNE) | (t == IRUNE))
+ i->r.rune = par->yyrune;
+
+ pushand(par, i, i);
+ par->lastwasand = true;
+}
+
+static void
+_operator(Parser *par, Token t)
+{
+ if (t==RBRA && --par->nbra<0)
+ rcerror(par, creg_unmatchedrightparenthesis);
+ if (t==LBRA) {
+ if (++par->cursubid >= NSUBEXP)
+ rcerror(par, creg_toomanysubexpressions);
+ par->nbra++;
+ if (par->lastwasand)
+ _operator(par, CAT);
+ } else
+ evaluntil(par, t);
+ if (t != RBRA)
+ pushator(par, t);
+ par->lastwasand = 0;
+ if (t==STAR || t==QUEST || t==PLUS || t==RBRA)
+ par->lastwasand = true; /* these look like operands */
+}
+
+static void
+pushand(Parser *par, Reinst *f, Reinst *l)
+{
+ if (par->andp >= &par->andstack[NSTACK])
+ rcerror(par, creg_operandstackoverflow);
+ par->andp->first = f;
+ par->andp->last = l;
+ par->andp++;
+}
+
+static void
+pushator(Parser *par, Token t)
+{
+ if (par->atorp >= &par->atorstack[NSTACK])
+ rcerror(par, creg_operatorstackoverflow);
+ *par->atorp++ = t;
+ *par->subidp++ = par->cursubid;
+}
+
+static Node*
+popand(Parser *par, Token op)
+{
+ Reinst *inst;
+
+ if (par->andp <= &par->andstack[0]) {
+ rcerror(par, creg_missingoperand);
+ inst = newinst(par, NOP);
+ pushand(par, inst, inst);
+ }
+ return --par->andp;
+}
+
+static Token
+popator(Parser *par)
+{
+ if (par->atorp <= &par->atorstack[0])
+ rcerror(par, creg_operatorstackunderflow);
+ --par->subidp;
+ return *--par->atorp;
+}
+
+static void
+evaluntil(Parser *par, Token pri)
+{
+ Node *op1, *op2;
+ Reinst *inst1, *inst2;
+
+ while (pri==RBRA || par->atorp[-1]>=pri) {
+ switch (popator(par)) {
+ default:
+ rcerror(par, creg_unknownoperator);
+ break;
+ case LBRA: /* must have been RBRA */
+ op1 = popand(par, '(');
+ inst2 = newinst(par, RBRA);
+ inst2->r.subid = *par->subidp;
+ op1->last->l.next = inst2;
+ inst1 = newinst(par, LBRA);
+ inst1->r.subid = *par->subidp;
+ inst1->l.next = op1->first;
+ pushand(par, inst1, inst2);
+ return;
+ case OR:
+ op2 = popand(par, '|');
+ op1 = popand(par, '|');
+ inst2 = newinst(par, NOP);
+ op2->last->l.next = inst2;
+ op1->last->l.next = inst2;
+ inst1 = newinst(par, OR);
+ inst1->r.right = op1->first;
+ inst1->l.left = op2->first;
+ pushand(par, inst1, inst2);
+ break;
+ case CAT:
+ op2 = popand(par, 0);
+ op1 = popand(par, 0);
+ op1->last->l.next = op2->first;
+ pushand(par, op1->first, op2->last);
+ break;
+ case STAR:
+ op2 = popand(par, '*');
+ inst1 = newinst(par, OR);
+ op2->last->l.next = inst1;
+ inst1->r.right = op2->first;
+ pushand(par, inst1, inst1);
+ break;
+ case PLUS:
+ op2 = popand(par, '+');
+ inst1 = newinst(par, OR);
+ op2->last->l.next = inst1;
+ inst1->r.right = op2->first;
+ pushand(par, op2->first, inst1);
+ break;
+ case QUEST:
+ op2 = popand(par, '?');
+ inst1 = newinst(par, OR);
+ inst2 = newinst(par, NOP);
+ inst1->l.left = inst2;
+ inst1->r.right = op2->first;
+ op2->last->l.next = inst2;
+ pushand(par, inst1, inst2);
+ break;
+ }
+ }
+}
+
+static Reprog*
+optimize(Parser *par, Reprog *pp)
+{
+ Reinst *inst, *target;
+ size_t size;
+ Reprog *npp;
+ Reclass *cl;
+ ptrdiff_t diff;
+
+ /*
+ * get rid of NOOP chains
+ */
+ for (inst = pp->firstinst; inst->type != END; inst++) {
+ target = inst->l.next;
+ while (target->type == NOP)
+ target = target->l.next;
+ inst->l.next = target;
+ }
+
+ /*
+ * The original allocation is for an area larger than
+ * necessary. Reallocate to the actual space used
+ * and then relocate the code.
+ */
+ size = sizeof(Reprog) + (par->freep - pp->firstinst)*sizeof(Reinst);
+ npp = (Reprog *)realloc(pp, size);
+ if (npp==NULL || npp==pp)
+ return pp;
+ diff = (char *)npp - (char *)pp;
+ par->freep = (Reinst *)((char *)par->freep + diff);
+ for (inst = npp->firstinst; inst < par->freep; inst++) {
+ switch (inst->type) {
+ case OR:
+ case STAR:
+ case PLUS:
+ case QUEST:
+ inst->r.right = (Reinst *)((char*)inst->r.right + diff);
+ break;
+ case CCLASS:
+ case NCCLASS:
+ inst->r.right = (Reinst *)((char*)inst->r.right + diff);
+ cl = inst->r.classp;
+ cl->end = (Rune *)((char*)cl->end + diff);
+ break;
+ }
+ inst->l.left = (Reinst *)((char*)inst->l.left + diff);
+ }
+ npp->startinst = (Reinst *)((char*)npp->startinst + diff);
+ return npp;
+}
+
+static Reclass*
+newclass(Parser *par)
+{
+ if (par->nclass >= NCLASS)
+ rcerror(par, creg_toomanycharacterclasses);
+ return &(par->classp[par->nclass++]);
+}
+
+static int
+nextc(Parser *par, Rune *rp)
+{
+ if (par->lexdone) {
+ *rp = 0;
+ return 1;
+ }
+ par->exprp += chartorune(rp, par->exprp);
+ if (*rp == '\\') {
+ if (par->litmode && *par->exprp != 'E')
+ return 1;
+ par->exprp += chartorune(rp, par->exprp);
+ switch (*rp) {
+ case 'E': return par->litmode + 1;
+ case 't': *rp = '\t'; break;
+ case 'n': *rp = '\n'; break;
+ case 'r': *rp = '\r'; break;
+ case 'v': *rp = '\v'; break;
+ case 'f': *rp = '\f'; break;
+ case 'd': *rp = U8_Nd; break;
+ case 'D': *rp = U8N_Nd; break;
+ case 's': *rp = U8_Zs; break;
+ case 'S': *rp = U8N_Zs; break;
+ case 'w': *rp = U8_Xw; break;
+ case 'W': *rp = U8N_Xw; break;
+ case 'x': if (*par->exprp != '{') break;
+ *rp = 0; sscanf(++par->exprp, "%x", rp);
+ while (*par->exprp) if (*(par->exprp++) == '}') break;
+ if (par->exprp[-1] != '}')
+ rcerror(par, creg_unmatchedrightparenthesis);
+ return 2;
+ case 'p': case 'P': { /* https://www.regular-expressions.info/unicode.html */
+ static struct { const char* c; int n, r; } cls[] = {
+ {"{Alpha}", 7, U8_LC}, {"{LC}", 4, U8_LC},
+ {"{Alnum}", 7, U8_Xan},
+ {"{Digit}", 7, U8_Nd}, {"{Nd}", 4, U8_Nd},
+ {"{Lower}", 7, U8_Ll}, {"{Ll}", 4, U8_Ll},
+ {"{Space}", 7, U8_Zs}, {"{Zs}", 4, U8_Zs},
+ {"{Upper}", 7, U8_Lu}, {"{Lu}", 4, U8_Lu},
+ {"{XDigit}", 8, U8_Xnx},
+ {"{Blank}", 7, ASC_bl},
+ {"{Graph}", 7, ASC_gr},
+ {"{Print}", 7, ASC_pr},
+ {"{Punct}", 7, ASC_pt},
+ };
+ int inv = *rp == 'P';
+ for (unsigned i = 0; i < (sizeof cls/sizeof *cls); ++i)
+ if (!strncmp(par->exprp, cls[i].c, cls[i].n)) {
+ if (par->rune_type == IRUNE && (cls[i].r == U8_Ll || cls[i].r == U8_Lu))
+ *rp = U8_LC + inv;
+ else
+ *rp = cls[i].r + inv;
+ par->exprp += cls[i].n;
+ break;
+ }
+ if (*rp < OPERATOR) {
+ rcerror(par, creg_unknownoperator);
+ *rp = 0;
+ }
+ break;
+ }
+ }
+ return 1;
+ }
+ if (*rp == 0)
+ par->lexdone = true;
+ return par->litmode;
+}
+
+static Token
+lex(Parser *par)
+{
+ int quoted;
+ start:
+ quoted = nextc(par, &par->yyrune);
+ if (quoted) {
+ if (quoted == 2) {
+ if (par->litmode && par->yyrune == 'E') {
+ par->litmode = false;
+ goto start;
+ }
+ return par->yyrune == 0 ? END : par->rune_type;
+ }
+ switch (par->yyrune) {
+ case 0 : return END;
+ case 'b': return WBOUND;
+ case 'B': return NWBOUND;
+ case 'A': return BOS;
+ case 'z': return EOS;
+ case 'Z': return EOZ;
+ case 'Q': par->litmode = true;
+ goto start;
+ default : return par->rune_type;
+ }
+ }
+
+ switch (par->yyrune) {
+ case 0 : return END;
+ case '*': return STAR;
+ case '?': return QUEST;
+ case '+': return PLUS;
+ case '|': return OR;
+ case '.': return par->dot_type;
+ case '(':
+ if (par->exprp[0] == '?') {
+ for (int k = 1, enable = 1; ; ++k) switch (par->exprp[k]) {
+ case 0 : par->exprp += k; return END;
+ case ')': par->exprp += k + 1; goto start;
+ case '-': enable = 0; break;
+ case 's': if (!par->flags.dotall) par->dot_type = ANY + enable; break;
+ case 'i': if (!par->flags.caseless) par->rune_type = RUNE + enable; break;
+ default: rcerror(par, creg_unknownoperator); return 0;
+ }
+ }
+ return LBRA;
+ case ')': return RBRA;
+ case '^': return BOL;
+ case '$': return EOL;
+ case '[': return bldcclass(par);
+ }
+ return par->rune_type;
+}
+
+static Token
+bldcclass(Parser *par)
+{
+ Token type;
+ Rune r[NCCRUNE];
+ Rune *p, *ep, *np;
+ Rune rune;
+ int quoted;
+
+ /* we have already seen the '[' */
+ type = CCLASS;
+ par->yyclassp = newclass(par);
+
+ /* look ahead for negation */
+ /* SPECIAL CASE!!! negated classes don't match \n */
+ ep = r;
+ quoted = nextc(par, &rune);
+ if (!quoted && rune == '^') {
+ type = NCCLASS;
+ quoted = nextc(par, &rune);
+ *ep++ = '\n';
+ *ep++ = '\n';
+ }
+
+ /* parse class into a set of spans */
+ for (; ep < &r[NCCRUNE]; quoted = nextc(par, &rune)) {
+ if (rune == 0) {
+ rcerror(par, creg_malformedcharacterclass);
+ return 0;
+ }
+ if (!quoted) {
+ if (rune == ']')
+ break;
+ if (rune == '-') {
+ if (ep != r && *par->exprp != ']') {
+ quoted = nextc(par, &rune);
+ if (rune == 0) {
+ rcerror(par, creg_malformedcharacterclass);
+ return 0;
+ }
+ ep[-1] = rune;
+ continue;
+ }
+ }
+ }
+ *ep++ = rune;
+ *ep++ = rune;
+ }
+
+ /* sort on span start */
+ for (p = r; p < ep; p += 2) {
+ for (np = p; np < ep; np += 2)
+ if (*np < *p) {
+ rune = np[0];
+ np[0] = p[0];
+ p[0] = rune;
+ rune = np[1];
+ np[1] = p[1];
+ p[1] = rune;
+ }
+ }
+
+ /* merge spans */
+ np = par->yyclassp->spans;
+ p = r;
+ if (r == ep)
+ par->yyclassp->end = np;
+ else {
+ np[0] = *p++;
+ np[1] = *p++;
+ for (; p < ep; p += 2)
+ if (p[0] <= np[1]) {
+ if (p[1] > np[1])
+ np[1] = p[1];
+ } else {
+ np += 2;
+ np[0] = p[0];
+ np[1] = p[1];
+ }
+ par->yyclassp->end = np+2;
+ }
+
+ return type;
+}
+
+static Reprog*
+regcomp1(Parser *par, const char *s, int cflags)
+{
+ Token token;
+ Reprog *volatile pp;
+
+ /* get memory for the program. estimated max usage */
+ const int instcap = 5 + 6*strlen(s);
+ pp = (Reprog *)malloc(sizeof(Reprog) + instcap*sizeof(Reinst));
+ if (pp == NULL) {
+ rcerror(par, creg_outofmemory);
+ return NULL;
+ }
+ pp->flags.caseless = (cflags & creg_caseless) != 0;
+ pp->flags.dotall = (cflags & creg_dotall) != 0;
+ par->freep = pp->firstinst;
+ par->classp = pp->cclass;
+ par->errors = 0;
+
+ if (setjmp(par->regkaboom))
+ goto out;
+
+ /* go compile the sucker */
+ par->lexdone = false;
+ par->flags = pp->flags;
+ par->rune_type = pp->flags.caseless ? IRUNE : RUNE;
+ par->dot_type = pp->flags.dotall ? ANYNL : ANY;
+ par->litmode = false;
+ par->exprp = s;
+ par->nclass = 0;
+ par->nbra = 0;
+ par->atorp = par->atorstack;
+ par->andp = par->andstack;
+ par->subidp = par->subidstack;
+ par->lastwasand = false;
+ par->cursubid = 0;
+
+ /* Start with a low priority operator to prime parser */
+ pushator(par, START-1);
+ while ((token = lex(par)) != END) {
+ if ((token & MASK) == OPERATOR)
+ _operator(par, token);
+ else
+ operand(par, token);
+ }
+
+ /* Close with a low priority operator */
+ evaluntil(par, START);
+
+ /* Force END */
+ operand(par, END);
+ evaluntil(par, START);
+#ifdef DEBUG
+ dumpstack(par);
+#endif
+ if (par->nbra)
+ rcerror(par, creg_unmatchedleftparenthesis);
+ --par->andp; /* points to first and only operand */
+ pp->startinst = par->andp->first;
+#ifdef DEBUG
+ dump(pp);
+#endif
+ pp = optimize(par, pp);
+ pp->nsubids = par->cursubid;
+#ifdef DEBUG
+ print("start: %d\n", par->andp->first-pp->firstinst);
+ dump(pp);
+#endif
+out:
+ if (par->errors) {
+ free(pp);
+ pp = NULL;
+ }
+ return pp;
+}
+
+
+static int
+runematch(Rune s, Rune r, bool icase)
+{
+ int inv = 0;
+ switch (s) {
+ case ASC_BL: inv = 1; /* fallthrough */
+ case ASC_bl: return inv ^ ((r == ' ') | (r == '\t'));
+ case ASC_CT: inv = 1;
+ case ASC_ct: return inv ^ (iscntrl(r) != 0);
+ case ASC_GR: inv = 1;
+ case ASC_gr: return inv ^ (isgraph(r) != 0);
+ case ASC_PR: inv = 1;
+ case ASC_pr: return inv ^ (isprint(r) != 0);
+ case ASC_PT: inv = 1;
+ case ASC_pt: return inv ^ (ispunct(r) != 0);
+ case U8N_Nd: inv = 1;
+ case U8_Nd: return inv ^ (utf8_isdigit(r));
+ case U8N_LC: inv = 1;
+ case U8_LC: return inv ^ utf8_isalpha(r);
+ case U8N_Ll: inv = 1;
+ case U8_Ll: return inv ^ utf8_islower(r);
+ case U8N_Lu: inv = 1;
+ case U8_Lu: return inv ^ utf8_isupper(r);
+ case U8N_Zs: inv = 1;
+ case U8_Zs: return inv ^ utf8_isspace(r);
+ case U8N_Xan: inv = 1;
+ case U8_Xan: return inv ^ utf8_isalnum(r);
+ case U8N_Xnx: inv = 1;
+ case U8_Xnx: return inv ^ utf8_isxdigit(r);
+ case U8N_Xw: inv = 1;
+ case U8_Xw: return inv ^ (utf8_isalnum(r) | (r == '_'));
+ }
+ return icase ? utf8_tolower(s) == utf8_tolower(r) : s == r;
+}
+
+/*
+ * return 0 if no match
+ * >0 if a match
+ * <0 if we ran out of _relist space
+ */
+static int
+regexec1(const Reprog *progp, /* program to run */
+ const char *bol, /* string to run machine on */
+ Resub *mp, /* subexpression elements */
+ int ms, /* number of elements at mp */
+ Reljunk *j,
+ int mflags
+)
+{
+ int flag=0;
+ Reinst *inst;
+ Relist *tlp;
+ Relist *tl, *nl; /* This list, next list */
+ Relist *tle, *nle; /* Ends of this and next list */
+ const char *s, *p;
+ int i, n, checkstart;
+ Rune r, *rp, *ep;
+ int match = 0;
+
+ bool icase = progp->flags.caseless;
+ checkstart = j->starttype;
+ if (mp)
+ for (i=0; i<ms; i++) {
+ mp[i].str = NULL;
+ mp[i].size = 0;
+ }
+ j->relist[0][0].inst = NULL;
+ j->relist[1][0].inst = NULL;
+
+ /* Execute machine once for each character, including terminal NUL */
+ s = j->starts;
+ do {
+ /* fast check for first char */
+ if (checkstart) {
+ switch (j->starttype) {
+ case IRUNE:
+ p = utfruneicase(s, j->startchar);
+ goto next1;
+ case RUNE:
+ p = utfrune(s, j->startchar);
+ next1:
+ if (p == NULL || s == j->eol)
+ return match;
+ s = p;
+ break;
+ case BOL:
+ if (s == bol)
+ break;
+ p = utfrune(s, '\n');
+ if (p == NULL || s == j->eol)
+ return match;
+ s = p+1;
+ break;
+ }
+ }
+ n = chartorune(&r, s);
+
+ /* switch run lists */
+ tl = j->relist[flag];
+ tle = j->reliste[flag];
+ nl = j->relist[flag^=1];
+ nle = j->reliste[flag];
+ nl->inst = NULL;
+
+ /* Add first instruction to current list */
+ if (match == 0)
+ _renewemptythread(tl, progp->startinst, ms, s);
+
+ /* Execute machine until current list is empty */
+ for (tlp=tl; tlp->inst; tlp++) { /* assignment = */
+ for (inst = tlp->inst; ; inst = inst->l.next) {
+ int ok = false;
+
+ switch (inst->type) {
+ case RUNE:
+ case IRUNE: /* regular character */
+ ok = runematch(inst->r.rune, r, (icase = inst->type==IRUNE));
+ break;
+ case LBRA:
+ tlp->se.m[inst->r.subid].str = s;
+ continue;
+ case RBRA:
+ tlp->se.m[inst->r.subid].size = s - tlp->se.m[inst->r.subid].str;
+ continue;
+ case ANY:
+ ok = (r != '\n');
+ break;
+ case ANYNL:
+ ok = true;
+ break;
+ case BOL:
+ if (s == bol || s[-1] == '\n') continue;
+ break;
+ case BOS:
+ if (s == bol) continue;
+ break;
+ case EOL:
+ if (r == '\n') continue;
+ case EOS: /* fallthrough */
+ if (s == j->eol || r == 0) continue;
+ break;
+ case EOZ:
+ if (s == j->eol || r == 0 || (r == '\n' && s[1] == 0)) continue;
+ break;
+ case NWBOUND:
+ ok = true;
+ case WBOUND: /* fallthrough */
+ if (ok ^ (s == bol || s == j->eol || ((utf8_isalnum(s[-1]) || s[-1] == '_')
+ ^ (utf8_isalnum(s[ 0]) || s[ 0] == '_'))))
+ continue;
+ break;
+ case NCCLASS:
+ ok = true;
+ case CCLASS: /* fallthrough */
+ ep = inst->r.classp->end;
+ for (rp = inst->r.classp->spans; rp < ep; rp += 2) {
+ if ((r >= rp[0] && r <= rp[1]) || (rp[0] == rp[1] && runematch(rp[0], r, icase)))
+ break;
+ }
+ ok ^= (rp < ep);
+ break;
+ case OR:
+ /* evaluate right choice later */
+ if (_renewthread(tlp, inst->r.right, ms, &tlp->se) == tle)
+ return -1;
+ /* efficiency: advance and re-evaluate */
+ continue;
+ case END: /* Match! */
+ match = !(mflags & creg_fullmatch) ||
+ ((s == j->eol || r == 0 || r == '\n') &&
+ (tlp->se.m[0].str == bol || tlp->se.m[0].str[-1] == '\n'));
+ tlp->se.m[0].size = s - tlp->se.m[0].str;
+ if (mp != NULL)
+ _renewmatch(mp, ms, &tlp->se, progp->nsubids);
+ break;
+ }
+
+ if (ok && _renewthread(nl, inst->l.next, ms, &tlp->se) == nle)
+ return -1;
+ break;
+ }
+ }
+ if (s == j->eol)
+ break;
+ checkstart = j->starttype && nl->inst==NULL;
+ s += n;
+ } while (r);
+ return match;
+}
+
+static int
+regexec2(const Reprog *progp, /* program to run */
+ const char *bol, /* string to run machine on */
+ Resub *mp, /* subexpression elements */
+ int ms, /* number of elements at mp */
+ Reljunk *j,
+ int mflags
+)
+{
+ int rv;
+ Relist *relists;
+
+ /* mark space */
+ relists = (Relist *)malloc(2 * BIGLISTSIZE*sizeof(Relist));
+ if (relists == NULL)
+ return -1;
+
+ j->relist[0] = relists;
+ j->relist[1] = relists + BIGLISTSIZE;
+ j->reliste[0] = relists + BIGLISTSIZE - 2;
+ j->reliste[1] = relists + 2*BIGLISTSIZE - 2;
+
+ rv = regexec1(progp, bol, mp, ms, j, mflags);
+ free(relists);
+ return rv;
+}
+
+static int
+regexec9(const Reprog *progp, /* program to run */
+ const char *bol, /* string to run machine on */
+ int ms, /* number of elements at mp */
+ Resub mp[], /* subexpression elements */
+ int mflags)
+{
+ Reljunk j;
+ Relist relist0[LISTSIZE], relist1[LISTSIZE];
+ int rv;
+
+ /*
+ * use user-specified starting/ending location if specified
+ */
+ j.starts = bol;
+ j.eol = NULL;
+
+ if (mp && mp->str && ms>0) {
+ if (mflags & creg_startend)
+ j.starts = mp->str, j.eol = mp->str + mp->size;
+ else if (mflags & creg_next)
+ j.starts = mp->str + mp->size;
+ }
+
+ j.starttype = 0;
+ j.startchar = 0;
+ int rune_type = progp->flags.caseless ? IRUNE : RUNE;
+ if (progp->startinst->type == rune_type && progp->startinst->r.rune < 128) {
+ j.starttype = rune_type;
+ j.startchar = progp->startinst->r.rune;
+ }
+ if (progp->startinst->type == BOL)
+ j.starttype = BOL;
+
+ /* mark space */
+ j.relist[0] = relist0;
+ j.relist[1] = relist1;
+ j.reliste[0] = relist0 + LISTSIZE - 2;
+ j.reliste[1] = relist1 + LISTSIZE - 2;
+
+ rv = regexec1(progp, bol, mp, ms, &j, mflags);
+ if (rv >= 0)
+ return rv;
+ rv = regexec2(progp, bol, mp, ms, &j, mflags);
+ return rv;
+}
+
+/*
+ * API functions
+ */
+
+/* substitute into one string using the matches from the last regexec() */
+void cregex_replace(
+ const char *sp, /* source string */
+ char *dp, /* destination string */
+ int dlen,
+ int ms, /* number of elements pointed to by mp */
+ const cregmatch mp[]) /* subexpression elements */
+{
+ const char *ssp, *ep;
+ int i;
+
+ ep = dp+dlen-1;
+ while (*sp != '\0') {
+ if (*sp == '\\') {
+ switch (*++sp) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ i = *sp - '0';
+ if (mp[i].str != NULL && mp != NULL && ms > i)
+ for (ssp = mp[i].str; ssp < (mp[i].str + mp[i].size); ssp++)
+ if (dp < ep)
+ *dp++ = *ssp;
+ break;
+ case '\\':
+ if (dp < ep)
+ *dp++ = '\\';
+ break;
+ case '\0':
+ sp--;
+ break;
+ default:
+ if (dp < ep)
+ *dp++ = *sp;
+ break;
+ }
+ } else if (*sp == '&') {
+ if (mp[0].str != NULL && mp != NULL && ms > 0)
+ for (ssp = mp[0].str; ssp < (mp[0].str + mp[0].size); ssp++)
+ if (dp < ep)
+ *dp++ = *ssp;
+ } else {
+ if (dp < ep)
+ *dp++ = *sp;
+ }
+ sp++;
+ }
+ *dp = '\0';
+}
+
+int cregex_compile(cregex *rx, const char* pattern, int cflags) {
+ Parser par;
+ rx->prog = regcomp1(&par, pattern, cflags);
+ if (rx->prog)
+ return 1 + rx->prog->nsubids;
+ return par.errors;
+}
+
+int cregex_captures(cregex rx) {
+ return rx.prog ? 1 + rx.prog->nsubids : 0;
+}
+
+int cregex_find(const cregex *rx, const char* string,
+ size_t nmatch, cregmatch match[], int mflags) {
+ int res = regexec9(rx->prog, string, nmatch, match, mflags);
+ switch (res) {
+ case 1: return 1 + rx->prog->nsubids;
+ case 0: return creg_nomatch;
+ default: return creg_matcherror;
+ }
+}
+
+void cregex_drop(cregex* self) {
+ free(self->prog);
+}