From de629774cb912aa3d563f24d99258142713c3fcd Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Wed, 1 Jun 2022 16:28:07 +0200 Subject: Converted all files with DOS line endings to LINUX. --- benchmarks/misc/prng_bench.cpp | 412 +++--- benchmarks/misc/rust_cmap.c | 120 +- benchmarks/picobench/picobench_cmap.cpp | 604 ++++---- benchmarks/picobench/picobench_csmap.cpp | 644 ++++---- benchmarks/plotbench/cdeq_benchmark.cpp | 260 ++-- benchmarks/plotbench/clist_benchmark.cpp | 252 ++-- benchmarks/plotbench/cmap_benchmark.cpp | 266 ++-- benchmarks/plotbench/cpque_benchmark.cpp | 142 +- benchmarks/plotbench/csmap_benchmark.cpp | 270 ++-- benchmarks/plotbench/cvec_benchmark.cpp | 252 ++-- docs/cset_api.md | 246 ++-- docs/csset_api.md | 246 ++-- examples/README.md | 8 +- examples/arc_containers.c | 154 +- examples/arc_demo.c | 112 +- examples/arcvec_erase.c | 106 +- examples/astar.c | 334 ++--- examples/birthday.c | 132 +- examples/bits.c | 126 +- examples/bits2.c | 86 +- examples/books.c | 122 +- examples/box.c | 150 +- examples/box2.c | 176 +-- examples/city.c | 166 +-- examples/complex.c | 126 +- examples/csmap_insert.c | 224 +-- examples/csset_erase.c | 84 +- examples/cstr_match.c | 46 +- examples/demos.c | 458 +++--- examples/gauss1.c | 114 +- examples/gauss2.c | 86 +- examples/hashmap.c | 98 +- examples/inits.c | 228 +-- examples/list.c | 122 +- examples/list_erase.c | 58 +- examples/lower_bound.c | 128 +- examples/mapmap.c | 146 +- examples/mmap.c | 152 +- examples/multimap.c | 200 +-- examples/music_arc.c | 118 +- examples/new_deq.c | 124 +- examples/new_map.c | 146 +- examples/new_pque.c | 130 +- examples/new_queue.c | 90 +- examples/new_smap.c | 152 +- examples/new_sptr.c | 112 +- examples/new_vec.c | 114 +- examples/person_arc.c | 144 +- examples/phonebook.c | 162 +- examples/prime.c | 84 +- examples/priority.c | 70 +- examples/queue.c | 64 +- examples/random.c | 86 +- examples/rawptr_elements.c | 136 +- examples/read.c | 52 +- examples/replace.c | 62 +- examples/shape.c | 322 ++-- examples/shape.cpp | 244 +-- examples/sidebyside.cpp | 108 +- examples/splitstr.c | 78 +- examples/sso_map.c | 36 +- examples/stack.c | 58 +- examples/sview_split.c | 42 +- examples/unordered_map.c | 128 +- examples/unordered_set.c | 86 +- include/stc/alt/csmap.h | 1024 ++++++------- include/stc/alt/cstr.h | 778 +++++----- include/stc/carc.h | 398 ++--- include/stc/cbits.h | 656 ++++----- include/stc/cbox.h | 364 ++--- include/stc/ccommon.h | 538 +++---- include/stc/cdeq.h | 874 +++++------ include/stc/clist.h | 848 +++++------ include/stc/cmap.h | 846 +++++------ include/stc/cpque.h | 314 ++-- include/stc/cqueue.h | 130 +- include/stc/crandom.h | 388 ++--- include/stc/cregex.h | 180 +-- include/stc/cset.h | 92 +- include/stc/csmap.h | 1188 +++++++-------- include/stc/csset.h | 98 +- include/stc/cstack.h | 300 ++-- include/stc/cstr.h | 1110 +++++++------- include/stc/csview.h | 438 +++--- include/stc/cvec.h | 872 +++++------ include/stc/forward.h | 414 +++--- include/stc/template.h | 592 ++++---- include/stc/utf8.h | 190 +-- src/cregex.c | 2372 +++++++++++++++--------------- 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 -#include -#include -#include -#include - -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>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 +#include +#include +#include +#include + +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>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 -#include -#define i_key uint64_t -#define i_val uint64_t -#define i_tag u64 -#include - -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 +#include +#define i_key uint64_t +#define i_val uint64_t +#define i_tag u64 +#include + +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 -#define i_static -#include -#include -#include -#include -#include -#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 using umap = std::unordered_map; -template using bmap = ska::bytell_hash_map; -template using fmap = ska::flat_hash_map; -template using hmap = tsl::hopscotch_map; -template using pmap = phmap::flat_hash_map; -template using rmap = robin_hood::unordered_flat_map, std::equal_to, 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, ); -DEFMAP(map_x, ); -DEFMAP(map_s, ); - -#define i_key int32_t -#define i_val int32_t -#define i_tag i -#include - -#define i_key uint64_t -#define i_val uint64_t -#define i_tag x -#include - -#define i_key_str -#define i_val_str -#include - -PICOBENCH_SUITE("Map1"); - -template -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).P; -PICOBENCH(ins_and_erase_i).P; -PICOBENCH(ins_and_erase_i).P; -PICOBENCH(ins_and_erase_i).P; -PICOBENCH(ins_and_erase_i).P; -PICOBENCH(ins_and_erase_i).P; -PICOBENCH(ins_and_erase_cmap_x).P; -#undef P - -PICOBENCH_SUITE("Map2"); - -template -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).P; -PICOBENCH(ins_and_access_i).P; -PICOBENCH(ins_and_access_i).P; -PICOBENCH(ins_and_access_i).P; -PICOBENCH(ins_and_access_i).P; -PICOBENCH(ins_and_access_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 -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).P; -PICOBENCH(ins_and_access_s).P; -PICOBENCH(ins_and_access_s).P; -PICOBENCH(ins_and_access_s).P; -PICOBENCH(ins_and_access_s).P; -PICOBENCH(ins_and_access_s).P; -PICOBENCH(ins_and_access_cmap_s).P; -#undef P - -PICOBENCH_SUITE("Map4"); - -template -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).P; -PICOBENCH(iterate_x).P; -PICOBENCH(iterate_x).P; -PICOBENCH(iterate_x).P; -PICOBENCH(iterate_x).P; -PICOBENCH(iterate_x).P; -PICOBENCH(iterate_cmap_x).P; -#undef P +#define i_static +#include +#define i_static +#include +#include +#include +#include +#include +#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 using umap = std::unordered_map; +template using bmap = ska::bytell_hash_map; +template using fmap = ska::flat_hash_map; +template using hmap = tsl::hopscotch_map; +template using pmap = phmap::flat_hash_map; +template using rmap = robin_hood::unordered_flat_map, std::equal_to, 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, ); +DEFMAP(map_x, ); +DEFMAP(map_s, ); + +#define i_key int32_t +#define i_val int32_t +#define i_tag i +#include + +#define i_key uint64_t +#define i_val uint64_t +#define i_tag x +#include + +#define i_key_str +#define i_val_str +#include + +PICOBENCH_SUITE("Map1"); + +template +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).P; +PICOBENCH(ins_and_erase_i).P; +PICOBENCH(ins_and_erase_i).P; +PICOBENCH(ins_and_erase_i).P; +PICOBENCH(ins_and_erase_i).P; +PICOBENCH(ins_and_erase_i).P; +PICOBENCH(ins_and_erase_cmap_x).P; +#undef P + +PICOBENCH_SUITE("Map2"); + +template +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).P; +PICOBENCH(ins_and_access_i).P; +PICOBENCH(ins_and_access_i).P; +PICOBENCH(ins_and_access_i).P; +PICOBENCH(ins_and_access_i).P; +PICOBENCH(ins_and_access_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 +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).P; +PICOBENCH(ins_and_access_s).P; +PICOBENCH(ins_and_access_s).P; +PICOBENCH(ins_and_access_s).P; +PICOBENCH(ins_and_access_s).P; +PICOBENCH(ins_and_access_s).P; +PICOBENCH(ins_and_access_cmap_s).P; +#undef P + +PICOBENCH_SUITE("Map4"); + +template +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).P; +PICOBENCH(iterate_x).P; +PICOBENCH(iterate_x).P; +PICOBENCH(iterate_x).P; +PICOBENCH(iterate_x).P; +PICOBENCH(iterate_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 -#define i_static -#include -#define i_static -#include -#include -#include -#include - -#define PICOBENCH_IMPLEMENT_WITH_MAIN -#include "picobench.hpp" - -enum {N1 = 1000000, S1 = 1}; -uint64_t seed = time(NULL); // 18237129837891; - -using omap_i = std::map; -using omap_x = std::map; -using omap_s = std::map; - -#define i_key int -#define i_val int -#define i_tag i -#include - -#define i_key size_t -#define i_val size_t -#define i_tag x -#include - -#define i_key_str -#define i_val_str -#include - -PICOBENCH_SUITE("Map1"); - -template -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).P; -//PICOBENCH(ctor_and_ins_one_csmap_i).P; -#undef P - - -PICOBENCH_SUITE("Map_insert_only"); - -template -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).P; -PICOBENCH(insert_csmap_i).P; -#undef P - - -PICOBENCH_SUITE("Map2"); - -template -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).P; -PICOBENCH(ins_and_erase_csmap_i).P; -#undef P - -PICOBENCH_SUITE("Map3"); - -template -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).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 -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).P; -PICOBENCH(ins_and_access_csmap_s).P; -#undef P - -PICOBENCH_SUITE("Map5"); - -template -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).P; -//PICOBENCH(iterate_csmap_x).P; -#undef P +#include +#define i_static +#include +#define i_static +#include +#include +#include +#include + +#define PICOBENCH_IMPLEMENT_WITH_MAIN +#include "picobench.hpp" + +enum {N1 = 1000000, S1 = 1}; +uint64_t seed = time(NULL); // 18237129837891; + +using omap_i = std::map; +using omap_x = std::map; +using omap_s = std::map; + +#define i_key int +#define i_val int +#define i_tag i +#include + +#define i_key size_t +#define i_val size_t +#define i_tag x +#include + +#define i_key_str +#define i_val_str +#include + +PICOBENCH_SUITE("Map1"); + +template +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).P; +//PICOBENCH(ctor_and_ins_one_csmap_i).P; +#undef P + + +PICOBENCH_SUITE("Map_insert_only"); + +template +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).P; +PICOBENCH(insert_csmap_i).P; +#undef P + + +PICOBENCH_SUITE("Map2"); + +template +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).P; +PICOBENCH(ins_and_erase_csmap_i).P; +#undef P + +PICOBENCH_SUITE("Map3"); + +template +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).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 +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).P; +PICOBENCH(ins_and_access_csmap_s).P; +#undef P + +PICOBENCH_SUITE("Map5"); + +template +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).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 -#include -#define i_static -#include - -#ifdef __cplusplus -#include -#include -#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 - -#ifdef __cplusplus -Sample test_std_deque() { - typedef std::deque 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 +#include +#define i_static +#include + +#ifdef __cplusplus +#include +#include +#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 + +#ifdef __cplusplus +Sample test_std_deque() { + typedef std::deque 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 -#include -#define i_static -#include - -#ifdef __cplusplus -#include -#include -#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 - -#ifdef __cplusplus -Sample test_std_forward_list() { - typedef std::forward_list 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 +#include +#define i_static +#include + +#ifdef __cplusplus +#include +#include +#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 + +#ifdef __cplusplus +Sample test_std_forward_list() { + typedef std::forward_list 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 -#include -#define i_static -#include - -#ifdef __cplusplus -#include -#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 - -#ifdef __cplusplus -Sample test_std_unordered_map() { - typedef std::unordered_map 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 +#include +#define i_static +#include + +#ifdef __cplusplus +#include +#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 + +#ifdef __cplusplus +Sample test_std_unordered_map() { + typedef std::unordered_map 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 -#include -#define i_static -#include - -#define i_val float -#define i_cmp -c_default_cmp -#define i_tag f -#include - -#include - -static const uint32_t seed = 1234; - -void std_test() -{ - stc64_t rng; - int N = 10000000, M = 10; - - std::priority_queue, std::greater> 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 +#include +#define i_static +#include + +#define i_val float +#define i_cmp -c_default_cmp +#define i_tag f +#include + +#include + +static const uint32_t seed = 1234; + +void std_test() +{ + stc64_t rng; + int N = 10000000, M = 10; + + std::priority_queue, std::greater> 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 -#include -#define i_static -#include - -#ifdef __cplusplus -#include -#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 - -#ifdef __cplusplus -Sample test_std_map() { - typedef std::map 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 +#include +#define i_static +#include + +#ifdef __cplusplus +#include +#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 + +#ifdef __cplusplus +Sample test_std_map() { + typedef std::map 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 -#include -#define i_static -#include - -#ifdef __cplusplus -#include -#include -#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 - -#ifdef __cplusplus -Sample test_std_vector() { - typedef std::vector 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 +#include +#define i_static +#include + +#ifdef __cplusplus +#include +#include +#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 + +#ifdef __cplusplus +Sample test_std_vector() { + typedef std::vector 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 -``` -`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 - -#define i_key_str -#include - -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 +``` +`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 + +#define i_key_str +#include + +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 -``` -`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 - -#define i_key_str -#include - -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 +``` +`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 + +#define i_key_str +#include + +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 -#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 - -#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 - -#define i_type Stack -#define i_val_arcbox Arc // define i_val_bind for carc/cbox value (not i_val) -#include - -#define i_type List -#define i_val_arcbox Arc // as above -#include - -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 +#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 + +#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 + +#define i_type Stack +#define i_val_arcbox Arc // define i_val_bind for carc/cbox value (not i_val) +#include + +#define i_type List +#define i_val_arcbox Arc // as above +#include + +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 -#include - -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 // Arc - -#define i_key_arcbox Arc // note: use i_key_bind instead of i_key for carc/cbox elements -#include // csset_Arc (like: std::set>) - -#define i_val_arcbox Arc // note: as above. -#include // cvec_Arc (like: std::vector>) - -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 +#include + +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 // Arc + +#define i_key_arcbox Arc // note: use i_key_bind instead of i_key for carc/cbox elements +#include // csset_Arc (like: std::set>) + +#define i_val_arcbox Arc // note: as above. +#include // cvec_Arc (like: std::vector>) + +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 - -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 // Shared pointer to int - -#define i_type Vec -#define i_val_arcbox Arc -#include // Vec: cvec - - -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 + +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 // Shared pointer to int + +#define i_type Vec +#define i_val_arcbox Arc +#include // Vec: cvec + + +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 -#include - -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 - -#define i_val point -#define i_opt c_no_cmp -#include - -#define i_key point -#define i_val int -#define i_cmp point_key_cmp -#define i_tag pcost -#include - -#define i_key point -#define i_val point -#define i_cmp point_key_cmp -#define i_tag pstep -#include - -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(¤t, &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(¤t, &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 +#include + +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 + +#define i_val point +#define i_opt c_no_cmp +#include + +#define i_key point +#define i_val int +#define i_cmp point_key_cmp +#define i_tag pcost +#include + +#define i_key point +#define i_val point +#define i_cmp point_key_cmp +#define i_tag pstep +#include + +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(¤t, &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(¤t, &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 -#include -#include -#define i_implement -#include - -#define i_tag ic -#define i_key uint64_t -#define i_val uint8_t -#include - -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 - -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 +#include +#include +#define i_implement +#include + +#define i_tag ic +#define i_key uint64_t +#define i_val uint8_t +#include + +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 + +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 -#define i_implement -#include - -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 +#define i_implement +#include + +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 -// 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 - -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 +// 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 + +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 -#define i_key_str -#define i_val_str -#include - -// Type inference lets us omit an explicit type signature (which -// would be `HashMap` 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 +#define i_key_str +#define i_val_str +#include + +// Type inference lets us omit an explicit type signature (which +// would be `HashMap` 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 - -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 - -#define i_type Persons -#define i_val_arcbox PBox // informs that PBox is a smart pointer. -#include - -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 + +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 + +#define i_type Persons +#define i_val_arcbox PBox // informs that PBox is a smart pointer. +#include + +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 -#include -#include -#include - -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 // cbox_Point - -#define i_val Rectangle -#define i_opt c_no_cmp -#include // 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 // 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 +#include +#include +#include + +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 // cbox_Point + +#define i_val Rectangle +#define i_opt c_no_cmp +#include // 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 // 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 - -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 -//#include // try instead of cbox.h - -#define i_type Cities -#define i_key_arcbox CityArc -#include - -#define i_type CityMap -#define i_key int -#define i_val_arcbox CityArc -#include - - -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 + +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 +//#include // try instead of cbox.h + +#define i_type Cities +#define i_key_arcbox CityArc +#include + +#define i_type CityMap +#define i_key int +#define i_val_arcbox CityArc +#include + + +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 - -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 - -#define i_type StackList -#define i_val_bind FloatStack -#define i_opt c_no_cmp -#include - -#define i_type ListMap -#define i_key int -#define i_val_bind StackList -#include - -#define i_type MapMap -#define i_key_str -#define i_val_bind ListMap -#include - -// c++: -// using FloatStack = std::stack; -// using map_lst = std::unordered_map>; -// using map_map = std::unordered_map; - -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 + +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 + +#define i_type StackList +#define i_val_bind FloatStack +#define i_opt c_no_cmp +#include + +#define i_type ListMap +#define i_key int +#define i_val_bind StackList +#include + +#define i_type MapMap +#define i_key_str +#define i_val_bind ListMap +#include + +// c++: +// using FloatStack = std::stack; +// using map_lst = std::unordered_map>; +// using map_map = std::unordered_map; + +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 - -// 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 - -#define i_key int -#define i_val_str -#define i_tag istr // Map of int => cstr -#include - -#define i_val csmap_ii_raw -#define i_opt c_no_cmp -#define i_tag ii -#include - -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 + +// 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 + +#define i_key int +#define i_val_str +#define i_tag istr // Map of int => cstr +#include + +#define i_val csmap_ii_raw +#define i_opt c_no_cmp +#define i_tag ii +#include + +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 - -#define i_key int -#include - -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 + +#define i_key int +#include + +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 -#include -#include - -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 ? "" : 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 +#include +#include + +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 ? "" : 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 - -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 - -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 - -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 - -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 - -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 - -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 - -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 - -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 - -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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 + +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 -#include - -#define STC_IMPLEMENT -#include -#include - -// Declare int -> int hashmap. Uses typetag 'ii' for ints. -#define i_key int -#define i_val int -#define i_tag ii -#include - -// 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 - -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 +#include + +#define STC_IMPLEMENT +#include +#include + +// Declare int -> int hashmap. Uses typetag 'ii' for ints. +#define i_key int +#define i_val int +#define i_tag ii +#include + +// 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 + +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 -#include - -#define STC_IMPLEMENT -#include -#include - -// Declare int -> int sorted map. -#define i_key int -#define i_val size_t -#include - -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 +#include + +#define STC_IMPLEMENT +#include +#include + +// Declare int -> int sorted map. +#define i_key int +#define i_val size_t +#include + +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 -#define i_key_str -#define i_val_str -#include -#include - -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 +#define i_key_str +#define i_val_str +#include +#include + +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 - -#define i_key int -#define i_val_str -#define i_tag id // Map of int => cstr -#include - -#define i_key_str -#define i_val int -#define i_tag cnt // Map of cstr => int -#include - -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 - -#define i_val ipair_t -#define i_cmp ipair_cmp -#define i_tag ip -#define i_extern // define _clist_mergesort() once -#include - -#define i_val float -#define i_tag f -#include - -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 + +#define i_key int +#define i_val_str +#define i_tag id // Map of int => cstr +#include + +#define i_key_str +#define i_val int +#define i_tag cnt // Map of cstr => int +#include + +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 + +#define i_val ipair_t +#define i_cmp ipair_cmp +#define i_tag ip +#define i_extern // define _clist_mergesort() once +#include + +#define i_val float +#define i_tag f +#include + +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 -#include - -#define STC_IMPLEMENT -#define STC_EXTERN - -#define i_val double -#define i_tag fx -#include -#include - -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 +#include + +#define STC_IMPLEMENT +#define STC_EXTERN + +#define i_val double +#define i_tag fx +#include +#include + +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 - -#define i_val int -#include - -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 + +#define i_val int +#include + +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 - -#define i_val int -#include - -#define i_val int -#include - -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 + +#define i_val int +#include + +#define i_val int +#include + +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>: -#define i_implement -#include -#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 - -#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 - -#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 - -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", "Anna@myplace.com", "Support"); - add(&map, "Terry Dane", "Terry@myplace.com", "Development"); - add(&map, "Kik Winston", "Kik@myplace.com", "Finance"); - add(&map, "Nancy Drew", "Nancy@live.com", "Development"); - add(&map, "Nick Denton", "Nick@myplace.com", "Finance"); - add(&map, "Stan Whiteword", "Stan@myplace.com", "Marketing"); - add(&map, "Serena Bath", "Serena@myplace.com", "Support"); - add(&map, "Patrick Dust", "Patrick@myplace.com", "Finance"); - add(&map, "Red Winger", "Red@gmail.com", "Marketing"); - add(&map, "Nick Denton", "Nick@yahoo.com", "Support"); - add(&map, "Colin Turth", "Colin@myplace.com", "Support"); - add(&map, "Dennis Kay", "Dennis@mail.com", "Marketing"); - add(&map, "Anne Dickens", "Anne@myplace.com", "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>: +#define i_implement +#include +#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 + +#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 + +#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 + +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", "Anna@myplace.com", "Support"); + add(&map, "Terry Dane", "Terry@myplace.com", "Development"); + add(&map, "Kik Winston", "Kik@myplace.com", "Finance"); + add(&map, "Nancy Drew", "Nancy@live.com", "Development"); + add(&map, "Nick Denton", "Nick@myplace.com", "Finance"); + add(&map, "Stan Whiteword", "Stan@myplace.com", "Marketing"); + add(&map, "Serena Bath", "Serena@myplace.com", "Support"); + add(&map, "Patrick Dust", "Patrick@myplace.com", "Finance"); + add(&map, "Red Winger", "Red@gmail.com", "Marketing"); + add(&map, "Nick Denton", "Nick@yahoo.com", "Support"); + add(&map, "Colin Turth", "Colin@myplace.com", "Support"); + add(&map, "Dennis Kay", "Dennis@mail.com", "Marketing"); + add(&map, "Anne Dickens", "Anne@myplace.com", "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 -#define i_val_str -#define i_extern // define _clist_mergesort() once -#include - -// 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 -#include - -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 +#define i_val_str +#define i_extern // define _clist_mergesort() once +#include + +// 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 +#include + +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 - -// 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, 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 - -// Create a csmap 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 - -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 + +// 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, 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 + +// Create a csmap 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 + +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 - -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 - -#define i_type SongVec -#define i_val_arcbox SongPtr -#include - -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 + +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 + +#define i_type SongVec +#define i_val_arcbox SongPtr +#include + +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 -#include - -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 - -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 - -#define i_val float -#include - -#define i_val_str -#include - - -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 +#include + +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 + +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 + +#define i_val float +#include + +#define i_val_str +#include + + +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 -#include - -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 - -// 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 - -// cstr => cstr map -#define i_key_str -#define i_val_str -#include - -// string set -#define i_key_str -#include - - -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 +#include + +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 + +// 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 + +// cstr => cstr map +#define i_key_str +#define i_val_str +#include + +// string set +#define i_key_str +#include + + +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 - -forward_cpque(cpque_pnt, struct Point); - -struct MyStruct { - cpque_pnt priority_queue; - int id; -}; - -#define i_val int -#include - -#define i_val int -#include - -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 - -#include - -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 + +forward_cpque(cpque_pnt, struct Point); + +struct MyStruct { + cpque_pnt priority_queue; + int id; +}; + +#define i_val int +#include + +#define i_val int +#include + +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 + +#include + +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 -#include -#include -#include - -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 - -#define i_val int -#include - -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; i0; --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 +#include +#include +#include + +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 + +#define i_val int +#include + +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; i0; --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 -#include - -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 - -// 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 - -// cstr => cstr map -#define i_type SMap -#define i_key_str -#define i_val_str -#include - -// cstr set -#define i_type SSet -#define i_key_str -#include - - -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 +#include + +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 + +// 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 + +// cstr => cstr map +#define i_type SMap +#define i_key_str +#define i_val_str +#include + +// cstr set +#define i_type SSet +#define i_key_str +#include + + +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 - -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 - -// ... -#define i_type SPtr -#define i_val int -#define i_valdrop(x) printf("drop: %d\n", *x) -#include - -#define i_val_arcbox SPtr -#define i_tag iptr -#include - -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 + +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 + +// ... +#define i_type SPtr +#define i_val int +#define i_valdrop(x) printf("drop: %d\n", *x) +#include + +#define i_val_arcbox SPtr +#define i_tag iptr +#include + +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 -#include - -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 - -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 - -#define i_val float -#include - -#define i_val_str -#include - - -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 +#include + +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 + +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 + +#define i_val float +#include + +#define i_val_str +#include + + +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 - -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 - -#define i_type Persons -#define i_val_arcbox PSPtr // binds PSPtr_cmp, ... -#include - - -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 + +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 + +#define i_type Persons +#define i_val_arcbox PSPtr // binds PSPtr_cmp, ... +#include + + +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 - -#define i_key_str -#define i_val_str -#include - -#define i_key_str -#include - -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 + +#define i_key_str +#define i_val_str +#include + +#define i_key_str +#include + +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 -#include -#include -#define i_implement -#include - -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 +#include +#include +#define i_implement +#include + +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 -#include -#define i_implement -#include - -#define i_val int64_t -#define i_cmp -c_default_cmp // min-heap (increasing values) -#define i_tag i -#include - -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 +#include +#define i_implement +#include + +#define i_val int64_t +#define i_cmp -c_default_cmp // min-heap (increasing values) +#define i_tag i +#include + +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 -#include - -#define i_val int -#define i_tag i -#include - -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 +#include + +#define i_val int +#define i_tag i +#include + +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 -#include -#define i_implement -#include - -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 +#include +#define i_implement +#include + +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 -#include - -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 - -#define i_implement -#include -// 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 - -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 +#include + +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 + +#define i_implement +#include +// 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 + +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 -#define i_val_str -#include -#include - -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 +#define i_val_str +#include +#include + +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 - -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 + +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 -#include -#include - -#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 - -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 - -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 +#include +#include + +#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 + +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 + +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 -#include -#include - -// 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 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 - -int main(void) -{ - std::vector> shapes; - - auto tri1 = std::make_unique(Point{5, 7}, Point{12, 7}, Point{12, 20}); - auto pol1 = std::make_unique(); - auto pol2 = std::make_unique(); - - for (auto& p: std::array - {{{50, 72}, {123, 73}, {127, 201}, {828, 333}}}) - pol1->addPoint(p); - - for (auto& p: std::array - {{{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 +#include +#include + +// 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 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 + +int main(void) +{ + std::vector> shapes; + + auto tri1 = std::make_unique(Point{5, 7}, Point{12, 7}, Point{12, 20}); + auto pol1 = std::make_unique(); + auto pol2 = std::make_unique(); + + for (auto& p: std::array + {{{50, 72}, {123, 73}, {127, 201}, {828, 333}}}) + pol1->addPoint(p); + + for (auto& p: std::array + {{{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 -#include -#include - -#define i_key_str -#define i_val int -#define i_tag si -#include - -#define i_key int -#define i_val int -#define i_tag ii -#include - -int main() { - { - std::map 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 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 +#include +#include + +#define i_key_str +#define i_val int +#define i_tag si +#include + +#define i_key int +#define i_val int +#define i_tag ii +#include + +int main() { + { + std::map 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 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 -#define i_implement -#include -#define i_val_str -#include - -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 +#define i_implement +#include +#define i_val_str +#include + +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 -#define i_key_str -#define i_val_str -#include - -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 +#define i_key_str +#define i_val_str +#include + +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 - -#define i_tag i -#define i_val int -#include - -#define i_tag c -#define i_val char -#include - -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 + +#define i_tag i +#define i_val int +#include + +#define i_tag c +#define i_val char +#include + +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 -#include - -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 +#include + +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 -#include - -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 +#include + +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 -#define i_key_str -#include - -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 +#define i_key_str +#include + +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 -#include - -#define i_tag sx // Sorted map -#define i_key_str -#define i_val double -#include - -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 - -#ifndef CSMAP_H_INCLUDED -#define STC_CSMAP_V1 1 -#include -#include -#include -#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 - -#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 +/* 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 +#include + +#define i_tag sx // Sorted map +#define i_key_str +#define i_val double +#include + +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 + +#ifndef CSMAP_H_INCLUDED +#define STC_CSMAP_V1 1 +#include +#include +#include +#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 + +#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 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 -#include -#include /* malloc */ -#include -#include -#include /* vsnprintf */ -#include - -#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 +#include +#include /* malloc */ +#include +#include +#include /* vsnprintf */ +#include + +#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 - -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 - -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 - -#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 - #define c_atomic_inc(v) (void)_InterlockedIncrement(v) - #define c_atomic_dec_and_test(v) !_InterlockedDecrement(v) -#else - #include - #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 + +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 + +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 + +#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 + #define c_atomic_inc(v) (void)_InterlockedIncrement(v) + #define c_atomic_dec_and_test(v) !_InterlockedDecrement(v) +#else + #include + #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 -#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 -#include - -#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 - 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 +#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 +#include + +#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 + 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 - -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 - -int main() { - c_auto (PBox, p, q) - { - p = PBox_make(Person_from("John Smiths", "josmiths@gmail.com")); - 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 -#include - -#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(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 + +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 + +int main() { + c_auto (PBox, p, q) + { + p = PBox_make(Person_from("John Smiths", "josmiths@gmail.com")); + 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 +#include + +#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(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 -#include -#include -#include -#include - -#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 -# define c_alloc(T) static_cast(c_malloc(sizeof(T))) -# define c_alloc_n(T, n) static_cast(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 - #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 +#include +#include +#include +#include + +#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 +# define c_alloc(T) static_cast(c_malloc(sizeof(T))) +# define c_alloc_n(T, n) static_cast(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 + #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 -#include - -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 +#include + +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 - #include - - #define i_key int64_t - #define i_tag ix - #include - - 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 -#include - -#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 + #include + + #define i_key int64_t + #define i_tag ix + #include + + 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 +#include + +#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 - -#define i_tag ichar // Map int => char -#define i_key int -#define i_val char -#include - -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 -#include -#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 + +#define i_tag ichar // Map int => char +#define i_key int +#define i_val char +#include + +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 +#include +#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 -#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 +#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 -#include - -#define i_key int -#include - -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; i0; --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 +#include + +#define i_key int +#include + +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; i0; --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 -#include - -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 +#include + +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 . - -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 . + +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 -#include - -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 +#include + +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 -#include - -#define i_tag sx // Sorted map -#define i_key_str -#define i_val double -#include - -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 -#include - -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 +#include + +#define i_tag sx // Sorted map +#define i_key_str +#define i_val double +#include + +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 +#include + +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 - -#define i_tag i -#define i_key int -#include // 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 + +#define i_tag i +#define i_key int +#include // 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 -#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 +#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 /* malloc */ -#include -#include /* vsnprintf */ -#include - -/**************************** 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 /* malloc */ +#include +#include /* vsnprintf */ +#include + +/**************************** 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 -#include - -forward_cvec(cvec_i32, int); - -struct MyStruct { - cvec_i32 int_vec; - cstr name; -} typedef MyStruct; - -#define i_key float -#include - -#define i_key_str // special for cstr -#include - -#define i_key int -#define i_opt c_is_fwd // forward declared -#define i_tag i32 -#include - -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 -#include - -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 +#include + +forward_cvec(cvec_i32, int); + +struct MyStruct { + cvec_i32 int_vec; + cstr name; +} typedef MyStruct; + +#define i_key float +#include + +#define i_key_str // special for cstr +#include + +#define i_key int +#define i_opt c_is_fwd // forward declared +#define i_tag i32 +#include + +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 +#include + +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 - -#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 + +#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 -#include - -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 - -// 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 +#include + +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 + +// 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 . - -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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; im[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; irelist[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 . + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; im[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; irelist[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); +} -- cgit v1.2.3