diff options
| author | Tyge Løvset <[email protected]> | 2022-06-01 16:28:07 +0200 |
|---|---|---|
| committer | Tyge Løvset <[email protected]> | 2022-06-01 16:28:07 +0200 |
| commit | de629774cb912aa3d563f24d99258142713c3fcd (patch) | |
| tree | c37e2851d6cb049bc0863a59b6ecf5945fb88619 | |
| parent | 7fb43a24a17da787dd809114ca26c1231b058493 (diff) | |
| download | STC-modified-de629774cb912aa3d563f24d99258142713c3fcd.tar.gz STC-modified-de629774cb912aa3d563f24d99258142713c3fcd.zip | |
Converted all files with DOS line endings to LINUX.
89 files changed, 12804 insertions, 12804 deletions
diff --git a/benchmarks/misc/prng_bench.cpp b/benchmarks/misc/prng_bench.cpp index 9d840316..2bb25429 100644 --- a/benchmarks/misc/prng_bench.cpp +++ b/benchmarks/misc/prng_bench.cpp @@ -1,206 +1,206 @@ -#include <cstdint>
-#include <iostream>
-#include <ctime>
-#include <random>
-#include <stc/crandom.h>
-
-static inline uint64_t rotl64(const uint64_t x, const int k)
- { return (x << k) | (x >> (64 - k)); }
-
-static uint64_t splitmix64_x = 87213627321ull; /* The state can be seeded with any value. */
-
-uint64_t splitmix64(void) {
- uint64_t z = (splitmix64_x += 0x9e3779b97f4a7c15);
- z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
- z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
- return z ^ (z >> 31);
-}
-
-static void init_state(uint64_t *rng, uint64_t seed) {
- splitmix64_x = seed;
- for (int i=0; i<4; ++i) rng[i] = splitmix64();
-}
-
-/* romu_trio */
-
-uint64_t romu_trio(uint64_t s[3]) {
- uint64_t xp = s[0], yp = s[1], zp = s[2];
- s[0] = 15241094284759029579u * zp;
- s[1] = yp - xp; s[1] = rotl64(s[1], 12);
- s[2] = zp - yp; s[2] = rotl64(s[2], 44);
- return xp;
-}
-
-/* sfc64 */
-
-static inline uint64_t sfc64(uint64_t s[4]) {
- uint64_t result = s[0] + s[1] + s[3]++;
- s[0] = s[1] ^ (s[1] >> 11);
- s[1] = s[2] + (s[2] << 3);
- s[2] = rotl64(s[2], 24) + result;
- return result;
-}
-
-uint32_t sfc32(uint32_t s[4]) {
- uint32_t t = s[0] + s[1] + s[3]++;
- s[0] = s[1] ^ (s[1] >> 9);
- s[1] = s[2] + (s[2] << 3);
- s[2] = (s[2] << 21) | (s[2] >> 11) + t;
- return t;
-}
-
-uint32_t stc32(uint32_t s[5]) {
- uint32_t t = (s[0] ^ (s[3] += s[4])) + s[1];
- s[0] = s[1] ^ (s[1] >> 9);
- s[1] = s[2] + (s[2] << 3);
- s[2] = (s[2] << 21) | (s[2] >> 11) + t;
- return t;
-}
-
-/* xoshiro128+ */
-
-uint64_t xoroshiro128plus(uint64_t s[2]) {
- const uint64_t s0 = s[0];
- uint64_t s1 = s[1];
- const uint64_t result = s0 + s1;
-
- s1 ^= s0;
- s[0] = rotl64(s0, 24) ^ s1 ^ (s1 << 16); // a, b
- s[1] = rotl64(s1, 37); // c
-
- return result;
-}
-
-
-/* xoshiro256** */
-
-static inline uint64_t xoshiro256starstar(uint64_t s[4]) {
- const uint64_t result = rotl64(s[1] * 5, 7) * 9;
- const uint64_t t = s[1] << 17;
- s[2] ^= s[0];
- s[3] ^= s[1];
- s[1] ^= s[2];
- s[0] ^= s[3];
- s[2] ^= t;
- s[3] = rotl64(s[3], 45);
- return result;
-}
-
-// wyrand - 2020-12-07
-static inline void _wymum(uint64_t *A, uint64_t *B){
-#if defined(__SIZEOF_INT128__)
- __uint128_t r = *A; r *= *B;
- *A = (uint64_t) r; *B = (uint64_t ) (r >> 64);
-#elif defined(_MSC_VER) && defined(_M_X64)
- *A = _umul128(*A, *B, B);
-#else
- uint64_t ha=*A>>32, hb=*B>>32, la=(uint32_t)*A, lb=(uint32_t)*B, hi, lo;
- uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t<rl;
- lo=t+(rm1<<32); c+=lo<t; hi=rh+(rm0>>32)+(rm1>>32)+c;
- *A=lo; *B=hi;
-#endif
-}
-static inline uint64_t _wymix(uint64_t A, uint64_t B){
- _wymum(&A,&B); return A^B;
-}
-static inline uint64_t wyrand64(uint64_t *seed){
- static const uint64_t _wyp[] = {0xa0761d6478bd642full, 0xe7037ed1a0b428dbull};
- *seed+=_wyp[0]; return _wymix(*seed,*seed^_wyp[1]);
-}
-
-
-using namespace std;
-
-int main(void)
-{
- enum {N = 2000000000};
- uint16_t* recipient = new uint16_t[N];
- static stc64_t rng;
- init_state(rng.state, 12345123);
- std::mt19937 mt(12345123);
-
- cout << "WARMUP" << endl;
- for (size_t i = 0; i < N; i++)
- recipient[i] = wyrand64(rng.state);
-
- clock_t beg, end;
- for (size_t ti = 0; ti < 2; ti++) {
- init_state(rng.state, 12345123);
- cout << endl << "ROUND " << ti+1 << " ---------" << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = romu_trio(rng.state);
- end = clock();
- cout << "romu_trio:\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = wyrand64(rng.state);
- end = clock();
- cout << "wyrand64:\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = sfc32((uint32_t *)rng.state);
- end = clock();
- cout << "sfc32:\t\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = stc32((uint32_t *)rng.state);
- end = clock();
- cout << "stc32:\t\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = sfc64(rng.state);
- end = clock();
- cout << "sfc64:\t\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = stc64_rand(&rng);
- end = clock();
- cout << "stc64:\t\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = xoroshiro128plus(rng.state);
- end = clock();
- cout << "xoroshiro128+:\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = xoshiro256starstar(rng.state);
- end = clock();
- cout << "xoshiro256**:\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
-
- beg = clock();
- for (size_t i = 0; i < N; i++)
- recipient[i] = mt();
- end = clock();
- cout << "std::mt19937:\t"
- << (float(end - beg) / CLOCKS_PER_SEC)
- << "s: " << recipient[312] << endl;
- }
- delete[] recipient;
- return 0;
-}
+#include <cstdint> +#include <iostream> +#include <ctime> +#include <random> +#include <stc/crandom.h> + +static inline uint64_t rotl64(const uint64_t x, const int k) + { return (x << k) | (x >> (64 - k)); } + +static uint64_t splitmix64_x = 87213627321ull; /* The state can be seeded with any value. */ + +uint64_t splitmix64(void) { + uint64_t z = (splitmix64_x += 0x9e3779b97f4a7c15); + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + return z ^ (z >> 31); +} + +static void init_state(uint64_t *rng, uint64_t seed) { + splitmix64_x = seed; + for (int i=0; i<4; ++i) rng[i] = splitmix64(); +} + +/* romu_trio */ + +uint64_t romu_trio(uint64_t s[3]) { + uint64_t xp = s[0], yp = s[1], zp = s[2]; + s[0] = 15241094284759029579u * zp; + s[1] = yp - xp; s[1] = rotl64(s[1], 12); + s[2] = zp - yp; s[2] = rotl64(s[2], 44); + return xp; +} + +/* sfc64 */ + +static inline uint64_t sfc64(uint64_t s[4]) { + uint64_t result = s[0] + s[1] + s[3]++; + s[0] = s[1] ^ (s[1] >> 11); + s[1] = s[2] + (s[2] << 3); + s[2] = rotl64(s[2], 24) + result; + return result; +} + +uint32_t sfc32(uint32_t s[4]) { + uint32_t t = s[0] + s[1] + s[3]++; + s[0] = s[1] ^ (s[1] >> 9); + s[1] = s[2] + (s[2] << 3); + s[2] = (s[2] << 21) | (s[2] >> 11) + t; + return t; +} + +uint32_t stc32(uint32_t s[5]) { + uint32_t t = (s[0] ^ (s[3] += s[4])) + s[1]; + s[0] = s[1] ^ (s[1] >> 9); + s[1] = s[2] + (s[2] << 3); + s[2] = (s[2] << 21) | (s[2] >> 11) + t; + return t; +} + +/* xoshiro128+ */ + +uint64_t xoroshiro128plus(uint64_t s[2]) { + const uint64_t s0 = s[0]; + uint64_t s1 = s[1]; + const uint64_t result = s0 + s1; + + s1 ^= s0; + s[0] = rotl64(s0, 24) ^ s1 ^ (s1 << 16); // a, b + s[1] = rotl64(s1, 37); // c + + return result; +} + + +/* xoshiro256** */ + +static inline uint64_t xoshiro256starstar(uint64_t s[4]) { + const uint64_t result = rotl64(s[1] * 5, 7) * 9; + const uint64_t t = s[1] << 17; + s[2] ^= s[0]; + s[3] ^= s[1]; + s[1] ^= s[2]; + s[0] ^= s[3]; + s[2] ^= t; + s[3] = rotl64(s[3], 45); + return result; +} + +// wyrand - 2020-12-07 +static inline void _wymum(uint64_t *A, uint64_t *B){ +#if defined(__SIZEOF_INT128__) + __uint128_t r = *A; r *= *B; + *A = (uint64_t) r; *B = (uint64_t ) (r >> 64); +#elif defined(_MSC_VER) && defined(_M_X64) + *A = _umul128(*A, *B, B); +#else + uint64_t ha=*A>>32, hb=*B>>32, la=(uint32_t)*A, lb=(uint32_t)*B, hi, lo; + uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t<rl; + lo=t+(rm1<<32); c+=lo<t; hi=rh+(rm0>>32)+(rm1>>32)+c; + *A=lo; *B=hi; +#endif +} +static inline uint64_t _wymix(uint64_t A, uint64_t B){ + _wymum(&A,&B); return A^B; +} +static inline uint64_t wyrand64(uint64_t *seed){ + static const uint64_t _wyp[] = {0xa0761d6478bd642full, 0xe7037ed1a0b428dbull}; + *seed+=_wyp[0]; return _wymix(*seed,*seed^_wyp[1]); +} + + +using namespace std; + +int main(void) +{ + enum {N = 2000000000}; + uint16_t* recipient = new uint16_t[N]; + static stc64_t rng; + init_state(rng.state, 12345123); + std::mt19937 mt(12345123); + + cout << "WARMUP" << endl; + for (size_t i = 0; i < N; i++) + recipient[i] = wyrand64(rng.state); + + clock_t beg, end; + for (size_t ti = 0; ti < 2; ti++) { + init_state(rng.state, 12345123); + cout << endl << "ROUND " << ti+1 << " ---------" << endl; + + beg = clock(); + for (size_t i = 0; i < N; i++) + recipient[i] = romu_trio(rng.state); + end = clock(); + cout << "romu_trio:\t" + << (float(end - beg) / CLOCKS_PER_SEC) + << "s: " << recipient[312] << endl; + + beg = clock(); + for (size_t i = 0; i < N; i++) + recipient[i] = wyrand64(rng.state); + end = clock(); + cout << "wyrand64:\t" + << (float(end - beg) / CLOCKS_PER_SEC) + << "s: " << recipient[312] << endl; + + beg = clock(); + for (size_t i = 0; i < N; i++) + recipient[i] = sfc32((uint32_t *)rng.state); + end = clock(); + cout << "sfc32:\t\t" + << (float(end - beg) / CLOCKS_PER_SEC) + << "s: " << recipient[312] << endl; + + beg = clock(); + for (size_t i = 0; i < N; i++) + recipient[i] = stc32((uint32_t *)rng.state); + end = clock(); + cout << "stc32:\t\t" + << (float(end - beg) / CLOCKS_PER_SEC) + << "s: " << recipient[312] << endl; + + beg = clock(); + for (size_t i = 0; i < N; i++) + recipient[i] = sfc64(rng.state); + end = clock(); + cout << "sfc64:\t\t" + << (float(end - beg) / CLOCKS_PER_SEC) + << "s: " << recipient[312] << endl; + + beg = clock(); + for (size_t i = 0; i < N; i++) + recipient[i] = stc64_rand(&rng); + end = clock(); + cout << "stc64:\t\t" + << (float(end - beg) / CLOCKS_PER_SEC) + << "s: " << recipient[312] << endl; + + + beg = clock(); + for (size_t i = 0; i < N; i++) + recipient[i] = xoroshiro128plus(rng.state); + end = clock(); + cout << "xoroshiro128+:\t" + << (float(end - beg) / CLOCKS_PER_SEC) + << "s: " << recipient[312] << endl; + + beg = clock(); + for (size_t i = 0; i < N; i++) + recipient[i] = xoshiro256starstar(rng.state); + end = clock(); + cout << "xoshiro256**:\t" + << (float(end - beg) / CLOCKS_PER_SEC) + << "s: " << recipient[312] << endl; + + beg = clock(); + for (size_t i = 0; i < N; i++) + recipient[i] = mt(); + end = clock(); + cout << "std::mt19937:\t" + << (float(end - beg) / CLOCKS_PER_SEC) + << "s: " << recipient[312] << endl; + } + delete[] recipient; + return 0; +} diff --git a/benchmarks/misc/rust_cmap.c b/benchmarks/misc/rust_cmap.c index 5a052915..1e763bde 100644 --- a/benchmarks/misc/rust_cmap.c +++ b/benchmarks/misc/rust_cmap.c @@ -1,61 +1,61 @@ -#include <time.h>
-#include <stdio.h>
-#define i_key uint64_t
-#define i_val uint64_t
-#define i_tag u64
-#include <stc/cmap.h>
-
-uint64_t romu_rotl(uint64_t val, uint32_t r) {
- return (val << r) | (val >> (64 - r));
-}
-
-uint64_t romu_trio(uint64_t s[3]) {
- const uint64_t xp = s[0],
- yp = s[1],
- zp = s[2];
- s[0] = 15241094284759029579u * zp;
- s[1] = yp - xp;
- s[1] = romu_rotl(s[1], 12);
- s[2] = zp - yp;
- s[2] = romu_rotl(s[2], 44);
- return xp;
-}
-
-int main()
-{
- c_auto (cmap_u64, m) {
- const size_t n = 50000000,
- mask = (1 << 25) - 1,
- ms = CLOCKS_PER_SEC/1000;
- cmap_u64_max_load_factor(&m, 0.8);
- cmap_u64_reserve(&m, n);
- printf("STC cmap n = %" PRIuMAX ", mask = 0x%" PRIxMAX "\n", n, mask);
-
- uint64_t rng[3] = {1872361123, 123879177, 87739234}, sum;
- clock_t now = clock();
- c_forrange (n) {
- uint64_t key = romu_trio(rng) & mask;
- cmap_u64_insert(&m, key, 0).ref->second += 1;
- }
- printf("insert : %zums \tsize : %" PRIuMAX "\n", (clock() - now)/ms, cmap_u64_size(m));
-
- now = clock();
- sum = 0;
- c_forrange (key, mask + 1) { sum += cmap_u64_contains(&m, key); }
- printf("lookup : %zums \tsum : %" PRIuMAX "\n", (clock() - now)/ms, sum);
-
- now = clock();
- sum = 0;
- c_foreach (i, cmap_u64, m) { sum += i.ref->second; }
- printf("iterate : %zums \tsum : %" PRIuMAX "\n", (clock() - now)/ms, sum);
-
- uint64_t rng2[3] = {1872361123, 123879177, 87739234};
- now = clock();
- c_forrange (n) {
- uint64_t key = romu_trio(rng2) & mask;
- cmap_u64_erase(&m, key);
- }
- printf("remove : %zums \tsize : %" PRIuMAX "\n", (clock() - now)/ms, cmap_u64_size(m));
- printf("press a key:\n"); getchar();
- }
+#include <time.h> +#include <stdio.h> +#define i_key uint64_t +#define i_val uint64_t +#define i_tag u64 +#include <stc/cmap.h> + +uint64_t romu_rotl(uint64_t val, uint32_t r) { + return (val << r) | (val >> (64 - r)); +} + +uint64_t romu_trio(uint64_t s[3]) { + const uint64_t xp = s[0], + yp = s[1], + zp = s[2]; + s[0] = 15241094284759029579u * zp; + s[1] = yp - xp; + s[1] = romu_rotl(s[1], 12); + s[2] = zp - yp; + s[2] = romu_rotl(s[2], 44); + return xp; +} + +int main() +{ + c_auto (cmap_u64, m) { + const size_t n = 50000000, + mask = (1 << 25) - 1, + ms = CLOCKS_PER_SEC/1000; + cmap_u64_max_load_factor(&m, 0.8); + cmap_u64_reserve(&m, n); + printf("STC cmap n = %" PRIuMAX ", mask = 0x%" PRIxMAX "\n", n, mask); + + uint64_t rng[3] = {1872361123, 123879177, 87739234}, sum; + clock_t now = clock(); + c_forrange (n) { + uint64_t key = romu_trio(rng) & mask; + cmap_u64_insert(&m, key, 0).ref->second += 1; + } + printf("insert : %zums \tsize : %" PRIuMAX "\n", (clock() - now)/ms, cmap_u64_size(m)); + + now = clock(); + sum = 0; + c_forrange (key, mask + 1) { sum += cmap_u64_contains(&m, key); } + printf("lookup : %zums \tsum : %" PRIuMAX "\n", (clock() - now)/ms, sum); + + now = clock(); + sum = 0; + c_foreach (i, cmap_u64, m) { sum += i.ref->second; } + printf("iterate : %zums \tsum : %" PRIuMAX "\n", (clock() - now)/ms, sum); + + uint64_t rng2[3] = {1872361123, 123879177, 87739234}; + now = clock(); + c_forrange (n) { + uint64_t key = romu_trio(rng2) & mask; + cmap_u64_erase(&m, key); + } + printf("remove : %zums \tsize : %" PRIuMAX "\n", (clock() - now)/ms, cmap_u64_size(m)); + printf("press a key:\n"); getchar(); + } }
\ No newline at end of file diff --git a/benchmarks/picobench/picobench_cmap.cpp b/benchmarks/picobench/picobench_cmap.cpp index 30170061..4a330019 100644 --- a/benchmarks/picobench/picobench_cmap.cpp +++ b/benchmarks/picobench/picobench_cmap.cpp @@ -1,302 +1,302 @@ -#define i_static
-#include <stc/crandom.h>
-#define i_static
-#include <stc/cstr.h>
-#include <cmath>
-#include <string>
-#include <unordered_map>
-#include <stdexcept>
-#include "../external/robin_hood.h"
-#include "../external/skarupke/bytell_hash_map.hpp"
-#include "../external/tsl/hopscotch_map.h"
-#include "../external/parallel_hashmap/phmap.h"
-
-#define PICOBENCH_IMPLEMENT_WITH_MAIN
-#include "picobench.hpp"
-
-enum {N1 = 4000000, S1 = 1, MaxLoadFactor100 = 80};
-uint64_t seed = time(NULL);
-
-template <class K, class V> using umap = std::unordered_map<K, V>;
-template <class K, class V> using bmap = ska::bytell_hash_map<K, V>;
-template <class K, class V> using fmap = ska::flat_hash_map<K, V>;
-template <class K, class V> using hmap = tsl::hopscotch_map<K, V>;
-template <class K, class V> using pmap = phmap::flat_hash_map<K, V>;
-template <class K, class V> using rmap = robin_hood::unordered_flat_map<K, V,
- robin_hood::hash<K>, std::equal_to<K>, MaxLoadFactor100>;
-#define DEFMAP(map, ...) \
- using u##map = umap __VA_ARGS__; \
- using b##map = bmap __VA_ARGS__; \
- using f##map = fmap __VA_ARGS__; \
- using h##map = hmap __VA_ARGS__; \
- using p##map = pmap __VA_ARGS__; \
- using r##map = rmap __VA_ARGS__
-
-
-DEFMAP(map_i, <int32_t, int32_t>);
-DEFMAP(map_x, <uint64_t, uint64_t>);
-DEFMAP(map_s, <std::string, std::string>);
-
-#define i_key int32_t
-#define i_val int32_t
-#define i_tag i
-#include <stc/cmap.h>
-
-#define i_key uint64_t
-#define i_val uint64_t
-#define i_tag x
-#include <stc/cmap.h>
-
-#define i_key_str
-#define i_val_str
-#include <stc/cmap.h>
-
-PICOBENCH_SUITE("Map1");
-
-template <class MapInt>
-static void ins_and_erase_i(picobench::state& s)
-{
- size_t result = 0;
- MapInt map;
- map.max_load_factor((int)MaxLoadFactor100 / 100.0);
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (s.iterations())
- map[crandom()];
- map.clear();
- csrandom(seed);
- c_forrange (s.iterations())
- map[crandom()];
- csrandom(seed);
- c_forrange (s.iterations())
- map.erase(crandom());
- s.set_result(map.size());
-}
-
-static void ins_and_erase_cmap_i(picobench::state& s)
-{
- cmap_i map = cmap_i_init();
- cmap_i_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (s.iterations())
- cmap_i_insert(&map, crandom(), 0);
- cmap_i_clear(&map);
- csrandom(seed);
- c_forrange (s.iterations())
- cmap_i_insert(&map, crandom(), 0);
- csrandom(seed);
- c_forrange (s.iterations())
- cmap_i_erase(&map, crandom());
- s.set_result(cmap_i_size(map));
- cmap_i_drop(&map);
-}
-
-static void ins_and_erase_cmap_x(picobench::state& s)
-{
- cmap_x map = cmap_x_init();
- cmap_x_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (s.iterations())
- cmap_x_insert(&map, crandom(), 0);
- cmap_x_clear(&map);
- csrandom(seed);
- c_forrange (s.iterations())
- cmap_x_insert(&map, crandom(), 0);
- csrandom(seed);
- c_forrange (s.iterations())
- cmap_x_erase(&map, crandom());
- s.set_result(cmap_x_size(map));
- cmap_x_drop(&map);
-}
-
-#define P samples(S1).iterations({N1/4})
-PICOBENCH(ins_and_erase_i<umap_x>).P;
-PICOBENCH(ins_and_erase_i<bmap_x>).P;
-PICOBENCH(ins_and_erase_i<fmap_x>).P;
-PICOBENCH(ins_and_erase_i<hmap_x>).P;
-PICOBENCH(ins_and_erase_i<pmap_x>).P;
-PICOBENCH(ins_and_erase_i<rmap_x>).P;
-PICOBENCH(ins_and_erase_cmap_x).P;
-#undef P
-
-PICOBENCH_SUITE("Map2");
-
-template <class MapInt>
-static void ins_and_access_i(picobench::state& s)
-{
- uint64_t mask = (1ull << s.arg()) - 1;
- size_t result = 0;
- MapInt map;
- map.max_load_factor((int)MaxLoadFactor100 / 100.0);
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (N1)
- result += ++map[crandom() & mask];
- s.set_result(result);
-}
-
-static void ins_and_access_cmap_i(picobench::state& s)
-{
- uint64_t mask = (1ull << s.arg()) - 1;
- size_t result = 0;
- cmap_i map = cmap_i_init();
- cmap_i_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (N1)
- result += ++cmap_i_insert(&map, crandom() & mask, 0).ref->second;
- s.set_result(result);
- cmap_i_drop(&map);
-}
-
-#define P samples(S1).iterations({N1, N1, N1, N1}).args({18, 23, 25, 31})
-PICOBENCH(ins_and_access_i<umap_i>).P;
-PICOBENCH(ins_and_access_i<bmap_i>).P;
-PICOBENCH(ins_and_access_i<fmap_i>).P;
-PICOBENCH(ins_and_access_i<hmap_i>).P;
-PICOBENCH(ins_and_access_i<pmap_i>).P;
-PICOBENCH(ins_and_access_i<rmap_i>).P;
-PICOBENCH(ins_and_access_cmap_i).P;
-#undef P
-
-PICOBENCH_SUITE("Map3");
-
-static void randomize(char* str, size_t len) {
- for (int k=0; k < len; ++k) {
- union {uint64_t i; char c[8];} r = {.i = crandom()};
- for (int i=0; i<8 && k<len; ++k, ++i)
- str[k] = (r.c[i] & 63) + 48;
- }
-}
-
-template <class MapStr>
-static void ins_and_access_s(picobench::state& s)
-{
- std::string str(s.arg(), 'x');
- size_t result = 0;
- MapStr map;
- map.max_load_factor((int)MaxLoadFactor100 / 100.0);
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (s.iterations()) {
- randomize(&str[0], str.size());
- map.emplace(str, str);
- randomize(&str[0], str.size());
- result += map.erase(str);
- }
- s.set_result(result + map.size());
-}
-
-static void ins_and_access_cmap_s(picobench::state& s)
-{
- cstr str = cstr_with_size(s.arg(), 'x');
- char* buf = cstr_data(&str);
- size_t result = 0;
- cmap_str map = cmap_str_init();
- cmap_str_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (s.iterations()) {
- randomize(buf, s.arg());
- //if (s.arg() > 30) { printf("%s\n", buf); exit(0); }
- cmap_str_emplace(&map, buf, buf);
-
- randomize(buf, s.arg());
- result += cmap_str_erase(&map, buf);
- }
- s.set_result(result + cmap_str_size(map));
- cstr_drop(&str);
- cmap_str_drop(&map);
-}
-
-#define P samples(S1).iterations({N1/5, N1/5, N1/5, N1/10, N1/40}).args({13, 7, 8, 100, 1000})
-PICOBENCH(ins_and_access_s<umap_s>).P;
-PICOBENCH(ins_and_access_s<bmap_s>).P;
-PICOBENCH(ins_and_access_s<fmap_s>).P;
-PICOBENCH(ins_and_access_s<hmap_s>).P;
-PICOBENCH(ins_and_access_s<pmap_s>).P;
-PICOBENCH(ins_and_access_s<rmap_s>).P;
-PICOBENCH(ins_and_access_cmap_s).P;
-#undef P
-
-PICOBENCH_SUITE("Map4");
-
-template <class MapX>
-static void iterate_x(picobench::state& s)
-{
- MapX map;
- map.max_load_factor((int)MaxLoadFactor100 / 100.0);
- uint64_t K = (1ull << s.arg()) - 1;
-
- picobench::scope scope(s);
- csrandom(seed);
- size_t result = 0;
-
- // measure insert then iterate whole map
- c_forrange (n, s.iterations()) {
- map[crandom()] = n;
- if (!(n & K)) for (auto const& keyVal : map)
- result += keyVal.second;
- }
-
- // reset rng back to inital state
- csrandom(seed);
-
- // measure erase then iterate whole map
- c_forrange (n, s.iterations()) {
- map.erase(crandom());
- if (!(n & K)) for (auto const& keyVal : map)
- result += keyVal.second;
- }
- s.set_result(result);
-}
-
-static void iterate_cmap_x(picobench::state& s)
-{
- cmap_x map = cmap_x_init();
- cmap_x_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0);
- uint64_t K = (1ull << s.arg()) - 1;
-
- picobench::scope scope(s);
- csrandom(seed);
- size_t result = 0;
-
- // measure insert then iterate whole map
- c_forrange (n, s.iterations()) {
- cmap_x_insert_or_assign(&map, crandom(), n);
- if (!(n & K)) c_foreach (i, cmap_x, map)
- result += i.ref->second;
- }
-
- // reset rng back to inital state
- csrandom(seed);
-
- // measure erase then iterate whole map
- c_forrange (n, s.iterations()) {
- cmap_x_erase(&map, crandom());
- if (!(n & K)) c_foreach (i, cmap_x, map)
- result += i.ref->second;
- }
- s.set_result(result);
- cmap_x_drop(&map);
-}
-
-
-#define P samples(S1).iterations({N1/20}).args({12})
-PICOBENCH(iterate_x<umap_x>).P;
-PICOBENCH(iterate_x<bmap_x>).P;
-PICOBENCH(iterate_x<fmap_x>).P;
-PICOBENCH(iterate_x<hmap_x>).P;
-PICOBENCH(iterate_x<pmap_x>).P;
-PICOBENCH(iterate_x<rmap_x>).P;
-PICOBENCH(iterate_cmap_x).P;
-#undef P
+#define i_static +#include <stc/crandom.h> +#define i_static +#include <stc/cstr.h> +#include <cmath> +#include <string> +#include <unordered_map> +#include <stdexcept> +#include "../external/robin_hood.h" +#include "../external/skarupke/bytell_hash_map.hpp" +#include "../external/tsl/hopscotch_map.h" +#include "../external/parallel_hashmap/phmap.h" + +#define PICOBENCH_IMPLEMENT_WITH_MAIN +#include "picobench.hpp" + +enum {N1 = 4000000, S1 = 1, MaxLoadFactor100 = 80}; +uint64_t seed = time(NULL); + +template <class K, class V> using umap = std::unordered_map<K, V>; +template <class K, class V> using bmap = ska::bytell_hash_map<K, V>; +template <class K, class V> using fmap = ska::flat_hash_map<K, V>; +template <class K, class V> using hmap = tsl::hopscotch_map<K, V>; +template <class K, class V> using pmap = phmap::flat_hash_map<K, V>; +template <class K, class V> using rmap = robin_hood::unordered_flat_map<K, V, + robin_hood::hash<K>, std::equal_to<K>, MaxLoadFactor100>; +#define DEFMAP(map, ...) \ + using u##map = umap __VA_ARGS__; \ + using b##map = bmap __VA_ARGS__; \ + using f##map = fmap __VA_ARGS__; \ + using h##map = hmap __VA_ARGS__; \ + using p##map = pmap __VA_ARGS__; \ + using r##map = rmap __VA_ARGS__ + + +DEFMAP(map_i, <int32_t, int32_t>); +DEFMAP(map_x, <uint64_t, uint64_t>); +DEFMAP(map_s, <std::string, std::string>); + +#define i_key int32_t +#define i_val int32_t +#define i_tag i +#include <stc/cmap.h> + +#define i_key uint64_t +#define i_val uint64_t +#define i_tag x +#include <stc/cmap.h> + +#define i_key_str +#define i_val_str +#include <stc/cmap.h> + +PICOBENCH_SUITE("Map1"); + +template <class MapInt> +static void ins_and_erase_i(picobench::state& s) +{ + size_t result = 0; + MapInt map; + map.max_load_factor((int)MaxLoadFactor100 / 100.0); + csrandom(seed); + + picobench::scope scope(s); + c_forrange (s.iterations()) + map[crandom()]; + map.clear(); + csrandom(seed); + c_forrange (s.iterations()) + map[crandom()]; + csrandom(seed); + c_forrange (s.iterations()) + map.erase(crandom()); + s.set_result(map.size()); +} + +static void ins_and_erase_cmap_i(picobench::state& s) +{ + cmap_i map = cmap_i_init(); + cmap_i_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0); + csrandom(seed); + + picobench::scope scope(s); + c_forrange (s.iterations()) + cmap_i_insert(&map, crandom(), 0); + cmap_i_clear(&map); + csrandom(seed); + c_forrange (s.iterations()) + cmap_i_insert(&map, crandom(), 0); + csrandom(seed); + c_forrange (s.iterations()) + cmap_i_erase(&map, crandom()); + s.set_result(cmap_i_size(map)); + cmap_i_drop(&map); +} + +static void ins_and_erase_cmap_x(picobench::state& s) +{ + cmap_x map = cmap_x_init(); + cmap_x_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0); + csrandom(seed); + + picobench::scope scope(s); + c_forrange (s.iterations()) + cmap_x_insert(&map, crandom(), 0); + cmap_x_clear(&map); + csrandom(seed); + c_forrange (s.iterations()) + cmap_x_insert(&map, crandom(), 0); + csrandom(seed); + c_forrange (s.iterations()) + cmap_x_erase(&map, crandom()); + s.set_result(cmap_x_size(map)); + cmap_x_drop(&map); +} + +#define P samples(S1).iterations({N1/4}) +PICOBENCH(ins_and_erase_i<umap_x>).P; +PICOBENCH(ins_and_erase_i<bmap_x>).P; +PICOBENCH(ins_and_erase_i<fmap_x>).P; +PICOBENCH(ins_and_erase_i<hmap_x>).P; +PICOBENCH(ins_and_erase_i<pmap_x>).P; +PICOBENCH(ins_and_erase_i<rmap_x>).P; +PICOBENCH(ins_and_erase_cmap_x).P; +#undef P + +PICOBENCH_SUITE("Map2"); + +template <class MapInt> +static void ins_and_access_i(picobench::state& s) +{ + uint64_t mask = (1ull << s.arg()) - 1; + size_t result = 0; + MapInt map; + map.max_load_factor((int)MaxLoadFactor100 / 100.0); + csrandom(seed); + + picobench::scope scope(s); + c_forrange (N1) + result += ++map[crandom() & mask]; + s.set_result(result); +} + +static void ins_and_access_cmap_i(picobench::state& s) +{ + uint64_t mask = (1ull << s.arg()) - 1; + size_t result = 0; + cmap_i map = cmap_i_init(); + cmap_i_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0); + csrandom(seed); + + picobench::scope scope(s); + c_forrange (N1) + result += ++cmap_i_insert(&map, crandom() & mask, 0).ref->second; + s.set_result(result); + cmap_i_drop(&map); +} + +#define P samples(S1).iterations({N1, N1, N1, N1}).args({18, 23, 25, 31}) +PICOBENCH(ins_and_access_i<umap_i>).P; +PICOBENCH(ins_and_access_i<bmap_i>).P; +PICOBENCH(ins_and_access_i<fmap_i>).P; +PICOBENCH(ins_and_access_i<hmap_i>).P; +PICOBENCH(ins_and_access_i<pmap_i>).P; +PICOBENCH(ins_and_access_i<rmap_i>).P; +PICOBENCH(ins_and_access_cmap_i).P; +#undef P + +PICOBENCH_SUITE("Map3"); + +static void randomize(char* str, size_t len) { + for (int k=0; k < len; ++k) { + union {uint64_t i; char c[8];} r = {.i = crandom()}; + for (int i=0; i<8 && k<len; ++k, ++i) + str[k] = (r.c[i] & 63) + 48; + } +} + +template <class MapStr> +static void ins_and_access_s(picobench::state& s) +{ + std::string str(s.arg(), 'x'); + size_t result = 0; + MapStr map; + map.max_load_factor((int)MaxLoadFactor100 / 100.0); + csrandom(seed); + + picobench::scope scope(s); + c_forrange (s.iterations()) { + randomize(&str[0], str.size()); + map.emplace(str, str); + randomize(&str[0], str.size()); + result += map.erase(str); + } + s.set_result(result + map.size()); +} + +static void ins_and_access_cmap_s(picobench::state& s) +{ + cstr str = cstr_with_size(s.arg(), 'x'); + char* buf = cstr_data(&str); + size_t result = 0; + cmap_str map = cmap_str_init(); + cmap_str_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0); + csrandom(seed); + + picobench::scope scope(s); + c_forrange (s.iterations()) { + randomize(buf, s.arg()); + //if (s.arg() > 30) { printf("%s\n", buf); exit(0); } + cmap_str_emplace(&map, buf, buf); + + randomize(buf, s.arg()); + result += cmap_str_erase(&map, buf); + } + s.set_result(result + cmap_str_size(map)); + cstr_drop(&str); + cmap_str_drop(&map); +} + +#define P samples(S1).iterations({N1/5, N1/5, N1/5, N1/10, N1/40}).args({13, 7, 8, 100, 1000}) +PICOBENCH(ins_and_access_s<umap_s>).P; +PICOBENCH(ins_and_access_s<bmap_s>).P; +PICOBENCH(ins_and_access_s<fmap_s>).P; +PICOBENCH(ins_and_access_s<hmap_s>).P; +PICOBENCH(ins_and_access_s<pmap_s>).P; +PICOBENCH(ins_and_access_s<rmap_s>).P; +PICOBENCH(ins_and_access_cmap_s).P; +#undef P + +PICOBENCH_SUITE("Map4"); + +template <class MapX> +static void iterate_x(picobench::state& s) +{ + MapX map; + map.max_load_factor((int)MaxLoadFactor100 / 100.0); + uint64_t K = (1ull << s.arg()) - 1; + + picobench::scope scope(s); + csrandom(seed); + size_t result = 0; + + // measure insert then iterate whole map + c_forrange (n, s.iterations()) { + map[crandom()] = n; + if (!(n & K)) for (auto const& keyVal : map) + result += keyVal.second; + } + + // reset rng back to inital state + csrandom(seed); + + // measure erase then iterate whole map + c_forrange (n, s.iterations()) { + map.erase(crandom()); + if (!(n & K)) for (auto const& keyVal : map) + result += keyVal.second; + } + s.set_result(result); +} + +static void iterate_cmap_x(picobench::state& s) +{ + cmap_x map = cmap_x_init(); + cmap_x_max_load_factor(&map, (int)MaxLoadFactor100 / 100.0); + uint64_t K = (1ull << s.arg()) - 1; + + picobench::scope scope(s); + csrandom(seed); + size_t result = 0; + + // measure insert then iterate whole map + c_forrange (n, s.iterations()) { + cmap_x_insert_or_assign(&map, crandom(), n); + if (!(n & K)) c_foreach (i, cmap_x, map) + result += i.ref->second; + } + + // reset rng back to inital state + csrandom(seed); + + // measure erase then iterate whole map + c_forrange (n, s.iterations()) { + cmap_x_erase(&map, crandom()); + if (!(n & K)) c_foreach (i, cmap_x, map) + result += i.ref->second; + } + s.set_result(result); + cmap_x_drop(&map); +} + + +#define P samples(S1).iterations({N1/20}).args({12}) +PICOBENCH(iterate_x<umap_x>).P; +PICOBENCH(iterate_x<bmap_x>).P; +PICOBENCH(iterate_x<fmap_x>).P; +PICOBENCH(iterate_x<hmap_x>).P; +PICOBENCH(iterate_x<pmap_x>).P; +PICOBENCH(iterate_x<rmap_x>).P; +PICOBENCH(iterate_cmap_x).P; +#undef P diff --git a/benchmarks/picobench/picobench_csmap.cpp b/benchmarks/picobench/picobench_csmap.cpp index 3f203cc8..ea2174fa 100644 --- a/benchmarks/picobench/picobench_csmap.cpp +++ b/benchmarks/picobench/picobench_csmap.cpp @@ -1,322 +1,322 @@ -#include <iostream>
-#define i_static
-#include <stc/crandom.h>
-#define i_static
-#include <stc/cstr.h>
-#include <cmath>
-#include <string>
-#include <map>
-
-#define PICOBENCH_IMPLEMENT_WITH_MAIN
-#include "picobench.hpp"
-
-enum {N1 = 1000000, S1 = 1};
-uint64_t seed = time(NULL); // 18237129837891;
-
-using omap_i = std::map<int, int>;
-using omap_x = std::map<uint64_t, uint64_t>;
-using omap_s = std::map<std::string, std::string>;
-
-#define i_key int
-#define i_val int
-#define i_tag i
-#include <stc/csmap.h>
-
-#define i_key size_t
-#define i_val size_t
-#define i_tag x
-#include <stc/csmap.h>
-
-#define i_key_str
-#define i_val_str
-#include <stc/csmap.h>
-
-PICOBENCH_SUITE("Map1");
-
-template <class MapInt>
-static void ctor_and_ins_one_i(picobench::state& s)
-{
- size_t result = 0;
- picobench::scope scope(s);
- c_forrange (n, s.iterations()) {
- MapInt map;
- map[n];
- result += map.size();
- }
- s.set_result(result);
-}
-
-static void ctor_and_ins_one_csmap_i(picobench::state& s)
-{
- size_t result = 0;
- picobench::scope scope(s);
- c_forrange (n, s.iterations()) {
- csmap_i map = csmap_i_init();
- csmap_i_insert(&map, n, 0);
- result += csmap_i_size(map);
- csmap_i_drop(&map);
- }
- s.set_result(result);
-}
-
-#define P samples(S1).iterations({N1})
-//PICOBENCH(ctor_and_ins_one_i<omap_i>).P;
-//PICOBENCH(ctor_and_ins_one_csmap_i).P;
-#undef P
-
-
-PICOBENCH_SUITE("Map_insert_only");
-
-template <class MapInt>
-static void insert_i(picobench::state& s)
-{
- size_t result = 0;
- MapInt map;
- csrandom(seed);
- picobench::scope scope(s);
- c_forrange (n, s.iterations())
- map.emplace(crandom() & 0xfffffff, n);
- s.set_result(map.size());
-}
-
-static void insert_csmap_i(picobench::state& s)
-{
- size_t result = 0;
- csmap_i map = csmap_i_init();
- csrandom(seed);
- picobench::scope scope(s);
- c_forrange (n, s.iterations())
- csmap_i_insert(&map, crandom() & 0xfffffff, n);
- s.set_result(csmap_i_size(map));
- csmap_i_drop(&map);
-}
-
-#define P samples(S1).iterations({N1})
-PICOBENCH(insert_i<omap_i>).P;
-PICOBENCH(insert_csmap_i).P;
-#undef P
-
-
-PICOBENCH_SUITE("Map2");
-
-template <class MapInt>
-static void ins_and_erase_i(picobench::state& s)
-{
- size_t result = 0;
- uint64_t mask = (1ull << s.arg()) - 1;
- MapInt map;
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (i, s.iterations())
- map.emplace(crandom() & mask, i);
- result = map.size();
-
- map.clear();
- csrandom(seed);
- c_forrange (i, s.iterations())
- map[crandom() & mask] = i;
-
- csrandom(seed);
- c_forrange (s.iterations())
- map.erase(crandom() & mask);
- s.set_result(result);
-}
-
-static void ins_and_erase_csmap_i(picobench::state& s)
-{
- size_t result = 0;
- uint64_t mask = (1ull << s.arg()) - 1;
- csmap_i map = csmap_i_init();
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (i, s.iterations())
- csmap_i_insert(&map, crandom() & mask, i);
- result = csmap_i_size(map);
-
- csmap_i_clear(&map);
- csrandom(seed);
- c_forrange (i, s.iterations())
- csmap_i_insert_or_assign(&map, crandom() & mask, i);
-
- csrandom(seed);
- c_forrange (s.iterations())
- csmap_i_erase(&map, crandom() & mask);
- s.set_result(result);
- csmap_i_drop(&map);
-}
-
-#define P samples(S1).iterations({N1/2, N1/2, N1/2, N1/2}).args({18, 23, 25, 31})
-PICOBENCH(ins_and_erase_i<omap_i>).P;
-PICOBENCH(ins_and_erase_csmap_i).P;
-#undef P
-
-PICOBENCH_SUITE("Map3");
-
-template <class MapInt>
-static void ins_and_access_i(picobench::state& s)
-{
- uint64_t mask = (1ull << s.arg()) - 1;
- size_t result = 0;
- MapInt map;
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (s.iterations()) {
- result += ++map[crandom() & mask];
- auto it = map.find(crandom() & mask);
- if (it != map.end()) map.erase(it->first);
- }
- s.set_result(result + map.size());
-}
-
-static void ins_and_access_csmap_i(picobench::state& s)
-{
- uint64_t mask = (1ull << s.arg()) - 1;
- size_t result = 0;
- csmap_i map = csmap_i_init();
- csrandom(seed);
-
- picobench::scope scope(s);
- c_forrange (s.iterations()) {
- result += ++csmap_i_insert(&map, crandom() & mask, 0).ref->second;
- const csmap_i_value* val = csmap_i_get(&map, crandom() & mask);
- if (val) csmap_i_erase(&map, val->first);
- }
- s.set_result(result + csmap_i_size(map));
- csmap_i_drop(&map);
-}
-
-#define P samples(S1).iterations({N1, N1, N1, N1}).args({18, 23, 25, 31})
-PICOBENCH(ins_and_access_i<omap_i>).P;
-PICOBENCH(ins_and_access_csmap_i).P;
-#undef P
-
-PICOBENCH_SUITE("Map4");
-
-static void randomize(char* str, size_t len) {
- union {uint64_t i; char c[8];} r = {.i = crandom()};
- for (int i = len - 7, j = 0; i < len; ++j, ++i)
- str[i] = (r.c[j] & 63) + 48;
-}
-
-template <class MapStr>
-static void ins_and_access_s(picobench::state& s)
-{
- std::string str(s.arg(), 'x');
- size_t result = 0;
- MapStr map;
-
- picobench::scope scope(s);
- csrandom(seed);
- c_forrange (s.iterations()) {
- randomize(&str[0], str.size());
- map.emplace(str, str);
- }
- csrandom(seed);
- c_forrange (s.iterations()) {
- randomize(&str[0], str.size());
- result += map.erase(str);
- }
- s.set_result(result + map.size());
-}
-
-static void ins_and_access_csmap_s(picobench::state& s)
-{
- cstr str = cstr_with_size(s.arg(), 'x');
- char* buf = cstr_data(&str);
- size_t result = 0;
- csmap_str map = csmap_str_init();
-
- picobench::scope scope(s);
- csrandom(seed);
- c_forrange (s.iterations()) {
- randomize(buf, s.arg());
- csmap_str_emplace(&map, buf, buf);
- }
- csrandom(seed);
- c_forrange (s.iterations()) {
- randomize(buf, s.arg());
- result += csmap_str_erase(&map, buf);
- /*csmap_str_iter it = csmap_str_find(&map, buf);
- if (it.ref) {
- ++result;
- csmap_str_erase(&map, cstr_str(&it.ref->first));
- }*/
- }
- s.set_result(result + csmap_str_size(map));
- cstr_drop(&str);
- csmap_str_drop(&map);
-}
-
-#define P samples(S1).iterations({N1/5, N1/5, N1/5, N1/10, N1/40}).args({13, 7, 8, 100, 1000})
-PICOBENCH(ins_and_access_s<omap_s>).P;
-PICOBENCH(ins_and_access_csmap_s).P;
-#undef P
-
-PICOBENCH_SUITE("Map5");
-
-template <class MapX>
-static void iterate_x(picobench::state& s)
-{
- MapX map;
- uint64_t K = (1ull << s.arg()) - 1;
-
- picobench::scope scope(s);
- csrandom(seed);
- size_t result = 0;
-
- // measure insert then iterate whole map
- c_forrange (n, s.iterations()) {
- map[crandom()] = n;
- if (!(n & K)) for (auto const& keyVal : map)
- result += keyVal.second;
- }
-
- // reset rng back to inital state
- csrandom(seed);
-
- // measure erase then iterate whole map
- c_forrange (n, s.iterations()) {
- map.erase(crandom());
- if (!(n & K)) for (auto const& keyVal : map)
- result += keyVal.second;
- }
- s.set_result(result);
-}
-
-static void iterate_csmap_x(picobench::state& s)
-{
- csmap_x map = csmap_x_init();
- uint64_t K = (1ull << s.arg()) - 1;
-
- picobench::scope scope(s);
- csrandom(seed);
- size_t result = 0;
-
- // measure insert then iterate whole map
- c_forrange (n, s.iterations()) {
- csmap_x_insert_or_assign(&map, crandom(), n);
- if (!(n & K)) c_foreach (i, csmap_x, map)
- result += i.ref->second;
- }
-
- // reset rng back to inital state
- csrandom(seed);
-
- // measure erase then iterate whole map
- c_forrange (n, s.iterations()) {
- csmap_x_erase(&map, crandom());
- if (!(n & K)) c_foreach (i, csmap_x, map)
- result += i.ref->second;
- }
- s.set_result(result);
- csmap_x_drop(&map);
-}
-
-
-#define P samples(S1).iterations({N1/20}).args({12})
-//PICOBENCH(iterate_x<omap_x>).P;
-//PICOBENCH(iterate_csmap_x).P;
-#undef P
+#include <iostream> +#define i_static +#include <stc/crandom.h> +#define i_static +#include <stc/cstr.h> +#include <cmath> +#include <string> +#include <map> + +#define PICOBENCH_IMPLEMENT_WITH_MAIN +#include "picobench.hpp" + +enum {N1 = 1000000, S1 = 1}; +uint64_t seed = time(NULL); // 18237129837891; + +using omap_i = std::map<int, int>; +using omap_x = std::map<uint64_t, uint64_t>; +using omap_s = std::map<std::string, std::string>; + +#define i_key int +#define i_val int +#define i_tag i +#include <stc/csmap.h> + +#define i_key size_t +#define i_val size_t +#define i_tag x +#include <stc/csmap.h> + +#define i_key_str +#define i_val_str +#include <stc/csmap.h> + +PICOBENCH_SUITE("Map1"); + +template <class MapInt> +static void ctor_and_ins_one_i(picobench::state& s) +{ + size_t result = 0; + picobench::scope scope(s); + c_forrange (n, s.iterations()) { + MapInt map; + map[n]; + result += map.size(); + } + s.set_result(result); +} + +static void ctor_and_ins_one_csmap_i(picobench::state& s) +{ + size_t result = 0; + picobench::scope scope(s); + c_forrange (n, s.iterations()) { + csmap_i map = csmap_i_init(); + csmap_i_insert(&map, n, 0); + result += csmap_i_size(map); + csmap_i_drop(&map); + } + s.set_result(result); +} + +#define P samples(S1).iterations({N1}) +//PICOBENCH(ctor_and_ins_one_i<omap_i>).P; +//PICOBENCH(ctor_and_ins_one_csmap_i).P; +#undef P + + +PICOBENCH_SUITE("Map_insert_only"); + +template <class MapInt> +static void insert_i(picobench::state& s) +{ + size_t result = 0; + MapInt map; + csrandom(seed); + picobench::scope scope(s); + c_forrange (n, s.iterations()) + map.emplace(crandom() & 0xfffffff, n); + s.set_result(map.size()); +} + +static void insert_csmap_i(picobench::state& s) +{ + size_t result = 0; + csmap_i map = csmap_i_init(); + csrandom(seed); + picobench::scope scope(s); + c_forrange (n, s.iterations()) + csmap_i_insert(&map, crandom() & 0xfffffff, n); + s.set_result(csmap_i_size(map)); + csmap_i_drop(&map); +} + +#define P samples(S1).iterations({N1}) +PICOBENCH(insert_i<omap_i>).P; +PICOBENCH(insert_csmap_i).P; +#undef P + + +PICOBENCH_SUITE("Map2"); + +template <class MapInt> +static void ins_and_erase_i(picobench::state& s) +{ + size_t result = 0; + uint64_t mask = (1ull << s.arg()) - 1; + MapInt map; + csrandom(seed); + + picobench::scope scope(s); + c_forrange (i, s.iterations()) + map.emplace(crandom() & mask, i); + result = map.size(); + + map.clear(); + csrandom(seed); + c_forrange (i, s.iterations()) + map[crandom() & mask] = i; + + csrandom(seed); + c_forrange (s.iterations()) + map.erase(crandom() & mask); + s.set_result(result); +} + +static void ins_and_erase_csmap_i(picobench::state& s) +{ + size_t result = 0; + uint64_t mask = (1ull << s.arg()) - 1; + csmap_i map = csmap_i_init(); + csrandom(seed); + + picobench::scope scope(s); + c_forrange (i, s.iterations()) + csmap_i_insert(&map, crandom() & mask, i); + result = csmap_i_size(map); + + csmap_i_clear(&map); + csrandom(seed); + c_forrange (i, s.iterations()) + csmap_i_insert_or_assign(&map, crandom() & mask, i); + + csrandom(seed); + c_forrange (s.iterations()) + csmap_i_erase(&map, crandom() & mask); + s.set_result(result); + csmap_i_drop(&map); +} + +#define P samples(S1).iterations({N1/2, N1/2, N1/2, N1/2}).args({18, 23, 25, 31}) +PICOBENCH(ins_and_erase_i<omap_i>).P; +PICOBENCH(ins_and_erase_csmap_i).P; +#undef P + +PICOBENCH_SUITE("Map3"); + +template <class MapInt> +static void ins_and_access_i(picobench::state& s) +{ + uint64_t mask = (1ull << s.arg()) - 1; + size_t result = 0; + MapInt map; + csrandom(seed); + + picobench::scope scope(s); + c_forrange (s.iterations()) { + result += ++map[crandom() & mask]; + auto it = map.find(crandom() & mask); + if (it != map.end()) map.erase(it->first); + } + s.set_result(result + map.size()); +} + +static void ins_and_access_csmap_i(picobench::state& s) +{ + uint64_t mask = (1ull << s.arg()) - 1; + size_t result = 0; + csmap_i map = csmap_i_init(); + csrandom(seed); + + picobench::scope scope(s); + c_forrange (s.iterations()) { + result += ++csmap_i_insert(&map, crandom() & mask, 0).ref->second; + const csmap_i_value* val = csmap_i_get(&map, crandom() & mask); + if (val) csmap_i_erase(&map, val->first); + } + s.set_result(result + csmap_i_size(map)); + csmap_i_drop(&map); +} + +#define P samples(S1).iterations({N1, N1, N1, N1}).args({18, 23, 25, 31}) +PICOBENCH(ins_and_access_i<omap_i>).P; +PICOBENCH(ins_and_access_csmap_i).P; +#undef P + +PICOBENCH_SUITE("Map4"); + +static void randomize(char* str, size_t len) { + union {uint64_t i; char c[8];} r = {.i = crandom()}; + for (int i = len - 7, j = 0; i < len; ++j, ++i) + str[i] = (r.c[j] & 63) + 48; +} + +template <class MapStr> +static void ins_and_access_s(picobench::state& s) +{ + std::string str(s.arg(), 'x'); + size_t result = 0; + MapStr map; + + picobench::scope scope(s); + csrandom(seed); + c_forrange (s.iterations()) { + randomize(&str[0], str.size()); + map.emplace(str, str); + } + csrandom(seed); + c_forrange (s.iterations()) { + randomize(&str[0], str.size()); + result += map.erase(str); + } + s.set_result(result + map.size()); +} + +static void ins_and_access_csmap_s(picobench::state& s) +{ + cstr str = cstr_with_size(s.arg(), 'x'); + char* buf = cstr_data(&str); + size_t result = 0; + csmap_str map = csmap_str_init(); + + picobench::scope scope(s); + csrandom(seed); + c_forrange (s.iterations()) { + randomize(buf, s.arg()); + csmap_str_emplace(&map, buf, buf); + } + csrandom(seed); + c_forrange (s.iterations()) { + randomize(buf, s.arg()); + result += csmap_str_erase(&map, buf); + /*csmap_str_iter it = csmap_str_find(&map, buf); + if (it.ref) { + ++result; + csmap_str_erase(&map, cstr_str(&it.ref->first)); + }*/ + } + s.set_result(result + csmap_str_size(map)); + cstr_drop(&str); + csmap_str_drop(&map); +} + +#define P samples(S1).iterations({N1/5, N1/5, N1/5, N1/10, N1/40}).args({13, 7, 8, 100, 1000}) +PICOBENCH(ins_and_access_s<omap_s>).P; +PICOBENCH(ins_and_access_csmap_s).P; +#undef P + +PICOBENCH_SUITE("Map5"); + +template <class MapX> +static void iterate_x(picobench::state& s) +{ + MapX map; + uint64_t K = (1ull << s.arg()) - 1; + + picobench::scope scope(s); + csrandom(seed); + size_t result = 0; + + // measure insert then iterate whole map + c_forrange (n, s.iterations()) { + map[crandom()] = n; + if (!(n & K)) for (auto const& keyVal : map) + result += keyVal.second; + } + + // reset rng back to inital state + csrandom(seed); + + // measure erase then iterate whole map + c_forrange (n, s.iterations()) { + map.erase(crandom()); + if (!(n & K)) for (auto const& keyVal : map) + result += keyVal.second; + } + s.set_result(result); +} + +static void iterate_csmap_x(picobench::state& s) +{ + csmap_x map = csmap_x_init(); + uint64_t K = (1ull << s.arg()) - 1; + + picobench::scope scope(s); + csrandom(seed); + size_t result = 0; + + // measure insert then iterate whole map + c_forrange (n, s.iterations()) { + csmap_x_insert_or_assign(&map, crandom(), n); + if (!(n & K)) c_foreach (i, csmap_x, map) + result += i.ref->second; + } + + // reset rng back to inital state + csrandom(seed); + + // measure erase then iterate whole map + c_forrange (n, s.iterations()) { + csmap_x_erase(&map, crandom()); + if (!(n & K)) c_foreach (i, csmap_x, map) + result += i.ref->second; + } + s.set_result(result); + csmap_x_drop(&map); +} + + +#define P samples(S1).iterations({N1/20}).args({12}) +//PICOBENCH(iterate_x<omap_x>).P; +//PICOBENCH(iterate_csmap_x).P; +#undef P diff --git a/benchmarks/plotbench/cdeq_benchmark.cpp b/benchmarks/plotbench/cdeq_benchmark.cpp index 057a50b8..d938450a 100644 --- a/benchmarks/plotbench/cdeq_benchmark.cpp +++ b/benchmarks/plotbench/cdeq_benchmark.cpp @@ -1,130 +1,130 @@ -#include <stdio.h>
-#include <time.h>
-#define i_static
-#include <stc/crandom.h>
-
-#ifdef __cplusplus
-#include <deque>
-#include <algorithm>
-#endif
-
-enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
-typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
-typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 100000000, S = 0x3ffc, R = 4};
-uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
-
-static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-
-#define i_tag x
-#define i_val size_t
-#include <stc/cdeq.h>
-
-#ifdef __cplusplus
-Sample test_std_deque() {
- typedef std::deque<size_t> container;
- Sample s = {"std,deque"};
- {
- s.test[INSERT].t1 = clock();
- container con;
- csrandom(seed);
- c_forrange (N/3) con.push_front(crandom() & mask1);
- c_forrange (N/3) {con.push_back(crandom() & mask1); con.pop_front();}
- c_forrange (N/3) con.push_back(crandom() & mask1);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = con.size();
- s.test[ERASE].t1 = clock();
- c_forrange (con.size()/2) { con.pop_front(); con.pop_back(); }
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = con.size();
- }{
- container con;
- csrandom(seed);
- c_forrange (N) con.push_back(crandom() & mask2);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- // Iteration - not inherent find - skipping
- //container::iterator it;
- //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con[i];
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-#else
-Sample test_std_deque() { Sample s = {"std-deque"}; return s;}
-#endif
-
-
-Sample test_stc_deque() {
- typedef cdeq_x container;
- Sample s = {"STC,deque"};
- {
- s.test[INSERT].t1 = clock();
- container con = cdeq_x_init();
- //cdeq_x_reserve(&con, N);
- csrandom(seed);
- c_forrange (N/3) cdeq_x_push_front(&con, crandom() & mask1);
- c_forrange (N/3) {cdeq_x_push_back(&con, crandom() & mask1); cdeq_x_pop_front(&con);}
- c_forrange (N/3) cdeq_x_push_back(&con, crandom() & mask1);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = cdeq_x_size(con);
- s.test[ERASE].t1 = clock();
- c_forrange (cdeq_x_size(con)/2) { cdeq_x_pop_front(&con); cdeq_x_pop_back(&con); }
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = cdeq_x_size(con);
- cdeq_x_drop(&con);
- }{
- csrandom(seed);
- container con = cdeq_x_init();
- c_forrange (N) cdeq_x_push_back(&con, crandom() & mask2);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- //cdeq_x_iter it, end = cdeq_x_end(&con);
- //c_forrange (S) if ((it = cdeq_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con.data[i];
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- cdeq_x_drop(&con);
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-
-int main(int argc, char* argv[])
-{
- Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1];
- c_forrange (i, int, SAMPLES) {
- std_s[i] = test_std_deque();
- stc_s[i] = test_stc_deque();
- if (i > 0) c_forrange (j, int, N_TESTS) {
- if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
- if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
- if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
- }
- }
- const char* comp = argc > 1 ? argv[1] : "test";
- bool header = (argc > 2 && argv[2][0] == '1');
- float std_sum = 0, stc_sum = 0;
- c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
- if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
-}
+#include <stdio.h> +#include <time.h> +#define i_static +#include <stc/crandom.h> + +#ifdef __cplusplus +#include <deque> +#include <algorithm> +#endif + +enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; +const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; +typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; +typedef struct { const char* name; Range test[N_TESTS]; } Sample; +enum {SAMPLES = 2, N = 100000000, S = 0x3ffc, R = 4}; +uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; + +static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } + +#define i_tag x +#define i_val size_t +#include <stc/cdeq.h> + +#ifdef __cplusplus +Sample test_std_deque() { + typedef std::deque<size_t> container; + Sample s = {"std,deque"}; + { + s.test[INSERT].t1 = clock(); + container con; + csrandom(seed); + c_forrange (N/3) con.push_front(crandom() & mask1); + c_forrange (N/3) {con.push_back(crandom() & mask1); con.pop_front();} + c_forrange (N/3) con.push_back(crandom() & mask1); + s.test[INSERT].t2 = clock(); + s.test[INSERT].sum = con.size(); + s.test[ERASE].t1 = clock(); + c_forrange (con.size()/2) { con.pop_front(); con.pop_back(); } + s.test[ERASE].t2 = clock(); + s.test[ERASE].sum = con.size(); + }{ + container con; + csrandom(seed); + c_forrange (N) con.push_back(crandom() & mask2); + s.test[FIND].t1 = clock(); + size_t sum = 0; + // Iteration - not inherent find - skipping + //container::iterator it; + //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it; + s.test[FIND].t2 = clock(); + s.test[FIND].sum = sum; + s.test[ITER].t1 = clock(); + sum = 0; + c_forrange (R) c_forrange (i, N) sum += con[i]; + s.test[ITER].t2 = clock(); + s.test[ITER].sum = sum; + s.test[DESTRUCT].t1 = clock(); + } + s.test[DESTRUCT].t2 = clock(); + s.test[DESTRUCT].sum = 0; + return s; +} +#else +Sample test_std_deque() { Sample s = {"std-deque"}; return s;} +#endif + + +Sample test_stc_deque() { + typedef cdeq_x container; + Sample s = {"STC,deque"}; + { + s.test[INSERT].t1 = clock(); + container con = cdeq_x_init(); + //cdeq_x_reserve(&con, N); + csrandom(seed); + c_forrange (N/3) cdeq_x_push_front(&con, crandom() & mask1); + c_forrange (N/3) {cdeq_x_push_back(&con, crandom() & mask1); cdeq_x_pop_front(&con);} + c_forrange (N/3) cdeq_x_push_back(&con, crandom() & mask1); + s.test[INSERT].t2 = clock(); + s.test[INSERT].sum = cdeq_x_size(con); + s.test[ERASE].t1 = clock(); + c_forrange (cdeq_x_size(con)/2) { cdeq_x_pop_front(&con); cdeq_x_pop_back(&con); } + s.test[ERASE].t2 = clock(); + s.test[ERASE].sum = cdeq_x_size(con); + cdeq_x_drop(&con); + }{ + csrandom(seed); + container con = cdeq_x_init(); + c_forrange (N) cdeq_x_push_back(&con, crandom() & mask2); + s.test[FIND].t1 = clock(); + size_t sum = 0; + //cdeq_x_iter it, end = cdeq_x_end(&con); + //c_forrange (S) if ((it = cdeq_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref; + s.test[FIND].t2 = clock(); + s.test[FIND].sum = sum; + s.test[ITER].t1 = clock(); + sum = 0; + c_forrange (R) c_forrange (i, N) sum += con.data[i]; + s.test[ITER].t2 = clock(); + s.test[ITER].sum = sum; + s.test[DESTRUCT].t1 = clock(); + cdeq_x_drop(&con); + } + s.test[DESTRUCT].t2 = clock(); + s.test[DESTRUCT].sum = 0; + return s; +} + +int main(int argc, char* argv[]) +{ + Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1]; + c_forrange (i, int, SAMPLES) { + std_s[i] = test_std_deque(); + stc_s[i] = test_stc_deque(); + if (i > 0) c_forrange (j, int, N_TESTS) { + if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j]; + if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j]; + if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j); + } + } + const char* comp = argc > 1 ? argv[1] : "test"; + bool header = (argc > 2 && argv[2][0] == '1'); + float std_sum = 0, stc_sum = 0; + c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); } + if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n"); + c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f); + printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f); + c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f); + printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum); +} diff --git a/benchmarks/plotbench/clist_benchmark.cpp b/benchmarks/plotbench/clist_benchmark.cpp index dfa043f0..0f5a3f8f 100644 --- a/benchmarks/plotbench/clist_benchmark.cpp +++ b/benchmarks/plotbench/clist_benchmark.cpp @@ -1,127 +1,127 @@ -#include <stdio.h>
-#include <time.h>
-#define i_static
-#include <stc/crandom.h>
-
-#ifdef __cplusplus
-#include <forward_list>
-#include <algorithm>
-#endif
-
-enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
-typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
-typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 50000000, S = 0x3ffc, R = 4};
-uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
-
-static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-
-#define i_val size_t
-#define i_tag x
-#include <stc/clist.h>
-
-#ifdef __cplusplus
-Sample test_std_forward_list() {
- typedef std::forward_list<size_t> container;
- Sample s = {"std,forward_list"};
- {
- s.test[INSERT].t1 = clock();
- container con;
- csrandom(seed);
- c_forrange (N/2) con.push_front(crandom() & mask1);
- c_forrange (N/2) con.push_front(crandom() & mask1);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = 0;
- s.test[ERASE].t1 = clock();
- c_forrange (N) con.pop_front();
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = 0;
- }{
- container con;
- csrandom(seed);
- c_forrange (N) con.push_front(crandom() & mask2);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- container::iterator it;
- // Iteration - not inherent find - skipping
- //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) for (auto i: con) sum += i;
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-#else
-Sample test_std_forward_list() { Sample s = {"std-forward_list"}; return s;}
-#endif
-
-
-Sample test_stc_forward_list() {
- typedef clist_x container;
- Sample s = {"STC,forward_list"};
- {
- s.test[INSERT].t1 = clock();
- container con = clist_x_init();
- csrandom(seed);
- c_forrange (N/2) clist_x_push_front(&con, crandom() & mask1);
- c_forrange (N/2) clist_x_push_back(&con, crandom() & mask1);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = 0;
- s.test[ERASE].t1 = clock();
- c_forrange (N) clist_x_pop_front(&con);
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = 0;
- clist_x_drop(&con);
- }{
- csrandom(seed);
- container con = clist_x_init();
- c_forrange (N) clist_x_push_front(&con, crandom() & mask2);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- //clist_x_iter it, end = clist_x_end(&con);
- //c_forrange (S) if ((it = clist_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) c_foreach (i, clist_x, con) sum += *i.ref;
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- clist_x_drop(&con);
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-
-int main(int argc, char* argv[])
-{
- Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1];
- c_forrange (i, int, SAMPLES) {
- std_s[i] = test_std_forward_list();
- stc_s[i] = test_stc_forward_list();
- if (i > 0) c_forrange (j, int, N_TESTS) {
- if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
- if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
- if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
- }
- }
- const char* comp = argc > 1 ? argv[1] : "test";
- bool header = (argc > 2 && argv[2][0] == '1');
- float std_sum = 0, stc_sum = 0;
- c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
- if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
+#include <stdio.h> +#include <time.h> +#define i_static +#include <stc/crandom.h> + +#ifdef __cplusplus +#include <forward_list> +#include <algorithm> +#endif + +enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; +const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; +typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; +typedef struct { const char* name; Range test[N_TESTS]; } Sample; +enum {SAMPLES = 2, N = 50000000, S = 0x3ffc, R = 4}; +uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; + +static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } + +#define i_val size_t +#define i_tag x +#include <stc/clist.h> + +#ifdef __cplusplus +Sample test_std_forward_list() { + typedef std::forward_list<size_t> container; + Sample s = {"std,forward_list"}; + { + s.test[INSERT].t1 = clock(); + container con; + csrandom(seed); + c_forrange (N/2) con.push_front(crandom() & mask1); + c_forrange (N/2) con.push_front(crandom() & mask1); + s.test[INSERT].t2 = clock(); + s.test[INSERT].sum = 0; + s.test[ERASE].t1 = clock(); + c_forrange (N) con.pop_front(); + s.test[ERASE].t2 = clock(); + s.test[ERASE].sum = 0; + }{ + container con; + csrandom(seed); + c_forrange (N) con.push_front(crandom() & mask2); + s.test[FIND].t1 = clock(); + size_t sum = 0; + container::iterator it; + // Iteration - not inherent find - skipping + //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it; + s.test[FIND].t2 = clock(); + s.test[FIND].sum = sum; + s.test[ITER].t1 = clock(); + sum = 0; + c_forrange (R) for (auto i: con) sum += i; + s.test[ITER].t2 = clock(); + s.test[ITER].sum = sum; + s.test[DESTRUCT].t1 = clock(); + } + s.test[DESTRUCT].t2 = clock(); + s.test[DESTRUCT].sum = 0; + return s; +} +#else +Sample test_std_forward_list() { Sample s = {"std-forward_list"}; return s;} +#endif + + +Sample test_stc_forward_list() { + typedef clist_x container; + Sample s = {"STC,forward_list"}; + { + s.test[INSERT].t1 = clock(); + container con = clist_x_init(); + csrandom(seed); + c_forrange (N/2) clist_x_push_front(&con, crandom() & mask1); + c_forrange (N/2) clist_x_push_back(&con, crandom() & mask1); + s.test[INSERT].t2 = clock(); + s.test[INSERT].sum = 0; + s.test[ERASE].t1 = clock(); + c_forrange (N) clist_x_pop_front(&con); + s.test[ERASE].t2 = clock(); + s.test[ERASE].sum = 0; + clist_x_drop(&con); + }{ + csrandom(seed); + container con = clist_x_init(); + c_forrange (N) clist_x_push_front(&con, crandom() & mask2); + s.test[FIND].t1 = clock(); + size_t sum = 0; + //clist_x_iter it, end = clist_x_end(&con); + //c_forrange (S) if ((it = clist_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref; + s.test[FIND].t2 = clock(); + s.test[FIND].sum = sum; + s.test[ITER].t1 = clock(); + sum = 0; + c_forrange (R) c_foreach (i, clist_x, con) sum += *i.ref; + s.test[ITER].t2 = clock(); + s.test[ITER].sum = sum; + s.test[DESTRUCT].t1 = clock(); + clist_x_drop(&con); + } + s.test[DESTRUCT].t2 = clock(); + s.test[DESTRUCT].sum = 0; + return s; +} + +int main(int argc, char* argv[]) +{ + Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1]; + c_forrange (i, int, SAMPLES) { + std_s[i] = test_std_forward_list(); + stc_s[i] = test_stc_forward_list(); + if (i > 0) c_forrange (j, int, N_TESTS) { + if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j]; + if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j]; + if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j); + } + } + const char* comp = argc > 1 ? argv[1] : "test"; + bool header = (argc > 2 && argv[2][0] == '1'); + float std_sum = 0, stc_sum = 0; + c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); } + if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n"); + c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f); + printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f); + c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f); + printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum); }
\ No newline at end of file diff --git a/benchmarks/plotbench/cmap_benchmark.cpp b/benchmarks/plotbench/cmap_benchmark.cpp index 1021ab1c..781ad720 100644 --- a/benchmarks/plotbench/cmap_benchmark.cpp +++ b/benchmarks/plotbench/cmap_benchmark.cpp @@ -1,134 +1,134 @@ -#include <stdio.h>
-#include <time.h>
-#define i_static
-#include <stc/crandom.h>
-
-#ifdef __cplusplus
-#include <unordered_map>
-#endif
-
-enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
-typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
-typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 8000000, R = 4};
-uint64_t seed = 1, mask1 = 0xffffffff;
-
-static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-
-#define i_key uint64_t
-#define i_val uint64_t
-#define i_tag x
-#include <stc/cmap.h>
-
-#ifdef __cplusplus
-Sample test_std_unordered_map() {
- typedef std::unordered_map<uint64_t, uint64_t> container;
- Sample s = {"std,unordered_map"};
- {
- csrandom(seed);
- s.test[INSERT].t1 = clock();
- container con;
- c_forrange (i, N/2) con.emplace(crandom() & mask1, i);
- c_forrange (i, N/2) con.emplace(i, i);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = con.size();
- csrandom(seed);
- s.test[ERASE].t1 = clock();
- c_forrange (N) con.erase(crandom() & mask1);
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = con.size();
- }{
- container con;
- csrandom(seed);
- c_forrange (i, N/2) con.emplace(crandom() & mask1, i);
- c_forrange (i, N/2) con.emplace(i, i);
- csrandom(seed);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- container::iterator it;
- c_forrange (N) if ((it = con.find(crandom() & mask1)) != con.end()) sum += it->second;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) for (auto i: con) sum += i.second;
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-#else
-Sample test_std_unordered_map() { Sample s = {"std-unordered_map"}; return s;}
-#endif
-
-
-Sample test_stc_unordered_map() {
- typedef cmap_x container;
- Sample s = {"STC,unordered_map"};
- {
- csrandom(seed);
- s.test[INSERT].t1 = clock();
- container con = cmap_x_init();
- c_forrange (i, N/2) cmap_x_insert(&con, crandom() & mask1, i);
- c_forrange (i, N/2) cmap_x_insert(&con, i, i);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = cmap_x_size(con);
- csrandom(seed);
- s.test[ERASE].t1 = clock();
- c_forrange (N) cmap_x_erase(&con, crandom() & mask1);
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = cmap_x_size(con);
- cmap_x_drop(&con);
- }{
- container con = cmap_x_init();
- csrandom(seed);
- c_forrange (i, N/2) cmap_x_insert(&con, crandom() & mask1, i);
- c_forrange (i, N/2) cmap_x_insert(&con, i, i);
- csrandom(seed);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- const cmap_x_value* val;
- c_forrange (N)
- if ((val = cmap_x_get(&con, crandom() & mask1)))
- sum += val->second;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) c_foreach (i, cmap_x, con) sum += i.ref->second;
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- cmap_x_drop(&con);
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-
-int main(int argc, char* argv[])
-{
- Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1];
- c_forrange (i, int, SAMPLES) {
- std_s[i] = test_std_unordered_map();
- stc_s[i] = test_stc_unordered_map();
- if (i > 0) c_forrange (j, int, N_TESTS) {
- if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
- if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
- if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
- }
- }
- const char* comp = argc > 1 ? argv[1] : "test";
- bool header = (argc > 2 && argv[2][0] == '1');
- float std_sum = 0, stc_sum = 0;
- c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
- if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
+#include <stdio.h> +#include <time.h> +#define i_static +#include <stc/crandom.h> + +#ifdef __cplusplus +#include <unordered_map> +#endif + +enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; +const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; +typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; +typedef struct { const char* name; Range test[N_TESTS]; } Sample; +enum {SAMPLES = 2, N = 8000000, R = 4}; +uint64_t seed = 1, mask1 = 0xffffffff; + +static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } + +#define i_key uint64_t +#define i_val uint64_t +#define i_tag x +#include <stc/cmap.h> + +#ifdef __cplusplus +Sample test_std_unordered_map() { + typedef std::unordered_map<uint64_t, uint64_t> container; + Sample s = {"std,unordered_map"}; + { + csrandom(seed); + s.test[INSERT].t1 = clock(); + container con; + c_forrange (i, N/2) con.emplace(crandom() & mask1, i); + c_forrange (i, N/2) con.emplace(i, i); + s.test[INSERT].t2 = clock(); + s.test[INSERT].sum = con.size(); + csrandom(seed); + s.test[ERASE].t1 = clock(); + c_forrange (N) con.erase(crandom() & mask1); + s.test[ERASE].t2 = clock(); + s.test[ERASE].sum = con.size(); + }{ + container con; + csrandom(seed); + c_forrange (i, N/2) con.emplace(crandom() & mask1, i); + c_forrange (i, N/2) con.emplace(i, i); + csrandom(seed); + s.test[FIND].t1 = clock(); + size_t sum = 0; + container::iterator it; + c_forrange (N) if ((it = con.find(crandom() & mask1)) != con.end()) sum += it->second; + s.test[FIND].t2 = clock(); + s.test[FIND].sum = sum; + s.test[ITER].t1 = clock(); + sum = 0; + c_forrange (R) for (auto i: con) sum += i.second; + s.test[ITER].t2 = clock(); + s.test[ITER].sum = sum; + s.test[DESTRUCT].t1 = clock(); + } + s.test[DESTRUCT].t2 = clock(); + s.test[DESTRUCT].sum = 0; + return s; +} +#else +Sample test_std_unordered_map() { Sample s = {"std-unordered_map"}; return s;} +#endif + + +Sample test_stc_unordered_map() { + typedef cmap_x container; + Sample s = {"STC,unordered_map"}; + { + csrandom(seed); + s.test[INSERT].t1 = clock(); + container con = cmap_x_init(); + c_forrange (i, N/2) cmap_x_insert(&con, crandom() & mask1, i); + c_forrange (i, N/2) cmap_x_insert(&con, i, i); + s.test[INSERT].t2 = clock(); + s.test[INSERT].sum = cmap_x_size(con); + csrandom(seed); + s.test[ERASE].t1 = clock(); + c_forrange (N) cmap_x_erase(&con, crandom() & mask1); + s.test[ERASE].t2 = clock(); + s.test[ERASE].sum = cmap_x_size(con); + cmap_x_drop(&con); + }{ + container con = cmap_x_init(); + csrandom(seed); + c_forrange (i, N/2) cmap_x_insert(&con, crandom() & mask1, i); + c_forrange (i, N/2) cmap_x_insert(&con, i, i); + csrandom(seed); + s.test[FIND].t1 = clock(); + size_t sum = 0; + const cmap_x_value* val; + c_forrange (N) + if ((val = cmap_x_get(&con, crandom() & mask1))) + sum += val->second; + s.test[FIND].t2 = clock(); + s.test[FIND].sum = sum; + s.test[ITER].t1 = clock(); + sum = 0; + c_forrange (R) c_foreach (i, cmap_x, con) sum += i.ref->second; + s.test[ITER].t2 = clock(); + s.test[ITER].sum = sum; + s.test[DESTRUCT].t1 = clock(); + cmap_x_drop(&con); + } + s.test[DESTRUCT].t2 = clock(); + s.test[DESTRUCT].sum = 0; + return s; +} + +int main(int argc, char* argv[]) +{ + Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1]; + c_forrange (i, int, SAMPLES) { + std_s[i] = test_std_unordered_map(); + stc_s[i] = test_stc_unordered_map(); + if (i > 0) c_forrange (j, int, N_TESTS) { + if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j]; + if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j]; + if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j); + } + } + const char* comp = argc > 1 ? argv[1] : "test"; + bool header = (argc > 2 && argv[2][0] == '1'); + float std_sum = 0, stc_sum = 0; + c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); } + if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n"); + c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f); + printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f); + c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f); + printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum); }
\ No newline at end of file diff --git a/benchmarks/plotbench/cpque_benchmark.cpp b/benchmarks/plotbench/cpque_benchmark.cpp index b38bed1a..afa9c07e 100644 --- a/benchmarks/plotbench/cpque_benchmark.cpp +++ b/benchmarks/plotbench/cpque_benchmark.cpp @@ -1,71 +1,71 @@ -#include <stdio.h>
-#include <time.h>
-#define i_static
-#include <stc/crandom.h>
-
-#define i_val float
-#define i_cmp -c_default_cmp
-#define i_tag f
-#include <stc/cpque.h>
-
-#include <queue>
-
-static const uint32_t seed = 1234;
-
-void std_test()
-{
- stc64_t rng;
- int N = 10000000, M = 10;
-
- std::priority_queue<float, std::vector<float>, std::greater<float>> pq;
- rng = stc64_new(seed);
- clock_t start = clock();
- c_forrange (i, N)
- pq.push((float) stc64_randf(&rng)*100000);
-
- printf("Built priority queue: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC);
- printf("%g ", pq.top());
-
- start = clock();
- c_forrange (i, N) {
- pq.pop();
- }
-
- printf("\npopped PQ: %f secs\n\n", (clock() - start) / (float) CLOCKS_PER_SEC);
-}
-
-
-void stc_test()
-{
- stc64_t rng;
- int N = 10000000, M = 10;
-
- c_auto (cpque_f, pq)
- {
- rng = stc64_new(seed);
- clock_t start = clock();
- c_forrange (i, N)
- cpque_f_push(&pq, (float) stc64_randf(&rng)*100000);
-
- printf("Built priority queue: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC);
- printf("%g ", *cpque_f_top(&pq));
-
- c_forrange (i, int, M) {
- cpque_f_pop(&pq);
- }
-
- start = clock();
- c_forrange (i, int, M, N)
- cpque_f_pop(&pq);
- printf("\npopped PQ: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC);
- }
-}
-
-
-int main()
-{
- puts("STD P.QUEUE:");
- std_test();
- puts("\nSTC P.QUEUE:");
- stc_test();
-}
+#include <stdio.h> +#include <time.h> +#define i_static +#include <stc/crandom.h> + +#define i_val float +#define i_cmp -c_default_cmp +#define i_tag f +#include <stc/cpque.h> + +#include <queue> + +static const uint32_t seed = 1234; + +void std_test() +{ + stc64_t rng; + int N = 10000000, M = 10; + + std::priority_queue<float, std::vector<float>, std::greater<float>> pq; + rng = stc64_new(seed); + clock_t start = clock(); + c_forrange (i, N) + pq.push((float) stc64_randf(&rng)*100000); + + printf("Built priority queue: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC); + printf("%g ", pq.top()); + + start = clock(); + c_forrange (i, N) { + pq.pop(); + } + + printf("\npopped PQ: %f secs\n\n", (clock() - start) / (float) CLOCKS_PER_SEC); +} + + +void stc_test() +{ + stc64_t rng; + int N = 10000000, M = 10; + + c_auto (cpque_f, pq) + { + rng = stc64_new(seed); + clock_t start = clock(); + c_forrange (i, N) + cpque_f_push(&pq, (float) stc64_randf(&rng)*100000); + + printf("Built priority queue: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC); + printf("%g ", *cpque_f_top(&pq)); + + c_forrange (i, int, M) { + cpque_f_pop(&pq); + } + + start = clock(); + c_forrange (i, int, M, N) + cpque_f_pop(&pq); + printf("\npopped PQ: %f secs\n", (clock() - start) / (float) CLOCKS_PER_SEC); + } +} + + +int main() +{ + puts("STD P.QUEUE:"); + std_test(); + puts("\nSTC P.QUEUE:"); + stc_test(); +} diff --git a/benchmarks/plotbench/csmap_benchmark.cpp b/benchmarks/plotbench/csmap_benchmark.cpp index 778d6894..3fb8a0a4 100644 --- a/benchmarks/plotbench/csmap_benchmark.cpp +++ b/benchmarks/plotbench/csmap_benchmark.cpp @@ -1,135 +1,135 @@ -#include <stdio.h>
-#include <time.h>
-#define i_static
-#include <stc/crandom.h>
-
-#ifdef __cplusplus
-#include <map>
-#endif
-
-enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
-typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
-typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 4000000, R = 4};
-uint64_t seed = 1, mask1 = 0xfffffff;
-
-static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-
-#define i_key size_t
-#define i_val size_t
-#define i_tag x
-#include <stc/csmap.h>
-
-#ifdef __cplusplus
-Sample test_std_map() {
- typedef std::map<size_t, size_t> container;
- Sample s = {"std,map"};
- {
- csrandom(seed);
- s.test[INSERT].t1 = clock();
- container con;
- c_forrange (i, N/2) con.emplace(crandom() & mask1, i);
- c_forrange (i, N/2) con.emplace(i, i);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = con.size();
- csrandom(seed);
- s.test[ERASE].t1 = clock();
- c_forrange (N) con.erase(crandom() & mask1);
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = con.size();
- }{
- container con;
- csrandom(seed);
- c_forrange (i, N/2) con.emplace(crandom() & mask1, i);
- c_forrange (i, N/2) con.emplace(i, i);
- csrandom(seed);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- container::iterator it;
- c_forrange (N) if ((it = con.find(crandom() & mask1)) != con.end()) sum += it->second;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) for (auto i: con) sum += i.second;
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-#else
-Sample test_std_map() { Sample s = {"std-map"}; return s;}
-#endif
-
-
-
-Sample test_stc_map() {
- typedef csmap_x container;
- Sample s = {"STC,map"};
- {
- csrandom(seed);
- s.test[INSERT].t1 = clock();
- container con = csmap_x_init();
- c_forrange (i, N/2) csmap_x_insert(&con, crandom() & mask1, i);
- c_forrange (i, N/2) csmap_x_insert(&con, i, i);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = csmap_x_size(con);
- csrandom(seed);
- s.test[ERASE].t1 = clock();
- c_forrange (N) csmap_x_erase(&con, crandom() & mask1);
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = csmap_x_size(con);
- csmap_x_drop(&con);
- }{
- container con = csmap_x_init();
- csrandom(seed);
- c_forrange (i, N/2) csmap_x_insert(&con, crandom() & mask1, i);
- c_forrange (i, N/2) csmap_x_insert(&con, i, i);
- csrandom(seed);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- const csmap_x_value* val;
- c_forrange (N)
- if ((val = csmap_x_get(&con, crandom() & mask1)))
- sum += val->second;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) c_foreach (i, csmap_x, con) sum += i.ref->second;
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- csmap_x_drop(&con);
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-
-int main(int argc, char* argv[])
-{
- Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1];
- c_forrange (i, int, SAMPLES) {
- std_s[i] = test_std_map();
- stc_s[i] = test_stc_map();
- if (i > 0) c_forrange (j, int, N_TESTS) {
- if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
- if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
- if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
- }
- }
- const char* comp = argc > 1 ? argv[1] : "test";
- bool header = (argc > 2 && argv[2][0] == '1');
- float std_sum = 0, stc_sum = 0;
- c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
- if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
-}
+#include <stdio.h> +#include <time.h> +#define i_static +#include <stc/crandom.h> + +#ifdef __cplusplus +#include <map> +#endif + +enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; +const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; +typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; +typedef struct { const char* name; Range test[N_TESTS]; } Sample; +enum {SAMPLES = 2, N = 4000000, R = 4}; +uint64_t seed = 1, mask1 = 0xfffffff; + +static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } + +#define i_key size_t +#define i_val size_t +#define i_tag x +#include <stc/csmap.h> + +#ifdef __cplusplus +Sample test_std_map() { + typedef std::map<size_t, size_t> container; + Sample s = {"std,map"}; + { + csrandom(seed); + s.test[INSERT].t1 = clock(); + container con; + c_forrange (i, N/2) con.emplace(crandom() & mask1, i); + c_forrange (i, N/2) con.emplace(i, i); + s.test[INSERT].t2 = clock(); + s.test[INSERT].sum = con.size(); + csrandom(seed); + s.test[ERASE].t1 = clock(); + c_forrange (N) con.erase(crandom() & mask1); + s.test[ERASE].t2 = clock(); + s.test[ERASE].sum = con.size(); + }{ + container con; + csrandom(seed); + c_forrange (i, N/2) con.emplace(crandom() & mask1, i); + c_forrange (i, N/2) con.emplace(i, i); + csrandom(seed); + s.test[FIND].t1 = clock(); + size_t sum = 0; + container::iterator it; + c_forrange (N) if ((it = con.find(crandom() & mask1)) != con.end()) sum += it->second; + s.test[FIND].t2 = clock(); + s.test[FIND].sum = sum; + s.test[ITER].t1 = clock(); + sum = 0; + c_forrange (R) for (auto i: con) sum += i.second; + s.test[ITER].t2 = clock(); + s.test[ITER].sum = sum; + s.test[DESTRUCT].t1 = clock(); + } + s.test[DESTRUCT].t2 = clock(); + s.test[DESTRUCT].sum = 0; + return s; +} +#else +Sample test_std_map() { Sample s = {"std-map"}; return s;} +#endif + + + +Sample test_stc_map() { + typedef csmap_x container; + Sample s = {"STC,map"}; + { + csrandom(seed); + s.test[INSERT].t1 = clock(); + container con = csmap_x_init(); + c_forrange (i, N/2) csmap_x_insert(&con, crandom() & mask1, i); + c_forrange (i, N/2) csmap_x_insert(&con, i, i); + s.test[INSERT].t2 = clock(); + s.test[INSERT].sum = csmap_x_size(con); + csrandom(seed); + s.test[ERASE].t1 = clock(); + c_forrange (N) csmap_x_erase(&con, crandom() & mask1); + s.test[ERASE].t2 = clock(); + s.test[ERASE].sum = csmap_x_size(con); + csmap_x_drop(&con); + }{ + container con = csmap_x_init(); + csrandom(seed); + c_forrange (i, N/2) csmap_x_insert(&con, crandom() & mask1, i); + c_forrange (i, N/2) csmap_x_insert(&con, i, i); + csrandom(seed); + s.test[FIND].t1 = clock(); + size_t sum = 0; + const csmap_x_value* val; + c_forrange (N) + if ((val = csmap_x_get(&con, crandom() & mask1))) + sum += val->second; + s.test[FIND].t2 = clock(); + s.test[FIND].sum = sum; + s.test[ITER].t1 = clock(); + sum = 0; + c_forrange (R) c_foreach (i, csmap_x, con) sum += i.ref->second; + s.test[ITER].t2 = clock(); + s.test[ITER].sum = sum; + s.test[DESTRUCT].t1 = clock(); + csmap_x_drop(&con); + } + s.test[DESTRUCT].t2 = clock(); + s.test[DESTRUCT].sum = 0; + return s; +} + +int main(int argc, char* argv[]) +{ + Sample std_s[SAMPLES + 1], stc_s[SAMPLES + 1]; + c_forrange (i, int, SAMPLES) { + std_s[i] = test_std_map(); + stc_s[i] = test_stc_map(); + if (i > 0) c_forrange (j, int, N_TESTS) { + if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j]; + if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j]; + if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j); + } + } + const char* comp = argc > 1 ? argv[1] : "test"; + bool header = (argc > 2 && argv[2][0] == '1'); + float std_sum = 0, stc_sum = 0; + c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); } + if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n"); + c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f); + printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f); + c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f); + printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum); +} diff --git a/benchmarks/plotbench/cvec_benchmark.cpp b/benchmarks/plotbench/cvec_benchmark.cpp index c23b689a..9ba95f31 100644 --- a/benchmarks/plotbench/cvec_benchmark.cpp +++ b/benchmarks/plotbench/cvec_benchmark.cpp @@ -1,126 +1,126 @@ -#include <stdio.h>
-#include <time.h>
-#define i_static
-#include <stc/crandom.h>
-
-#ifdef __cplusplus
-#include <vector>
-#include <algorithm>
-#endif
-
-enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS};
-const char* operations[] = {"insert", "erase", "find", "iter", "destruct"};
-typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range;
-typedef struct { const char* name; Range test[N_TESTS]; } Sample;
-enum {SAMPLES = 2, N = 150000000, S = 0x3ffc, R = 4};
-uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff;
-
-static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; }
-
-#define i_val size_t
-#define i_tag x
-#include <stc/cvec.h>
-
-#ifdef __cplusplus
-Sample test_std_vector() {
- typedef std::vector<size_t> container;
- Sample s = {"std,vector"};
- {
- s.test[INSERT].t1 = clock();
- container con;
- csrandom(seed);
- c_forrange (N) con.push_back(crandom() & mask1);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = con.size();
- s.test[ERASE].t1 = clock();
- c_forrange (N) con.pop_back();
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = con.size();
- }{
- container con;
- csrandom(seed);
- c_forrange (N) con.push_back(crandom() & mask2);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- container::iterator it;
- // Iteration - not inherent find - skipping
- //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con[i];
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-#else
-Sample test_std_vector() { Sample s = {"std-vector"}; return s;}
-#endif
-
-
-
-Sample test_stc_vector() {
- typedef cvec_x container;
- Sample s = {"STC,vector"};
- {
- s.test[INSERT].t1 = clock();
- container con = cvec_x_init();
- csrandom(seed);
- c_forrange (N) cvec_x_push_back(&con, crandom() & mask1);
- s.test[INSERT].t2 = clock();
- s.test[INSERT].sum = cvec_x_size(con);
- s.test[ERASE].t1 = clock();
- c_forrange (N) { cvec_x_pop_back(&con); }
- s.test[ERASE].t2 = clock();
- s.test[ERASE].sum = cvec_x_size(con);
- cvec_x_drop(&con);
- }{
- csrandom(seed);
- container con = cvec_x_init();
- c_forrange (N) cvec_x_push_back(&con, crandom() & mask2);
- s.test[FIND].t1 = clock();
- size_t sum = 0;
- //cvec_x_iter it, end = cvec_x_end(&con);
- //c_forrange (S) if ((it = cvec_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref;
- s.test[FIND].t2 = clock();
- s.test[FIND].sum = sum;
- s.test[ITER].t1 = clock();
- sum = 0;
- c_forrange (R) c_forrange (i, N) sum += con.data[i];
- s.test[ITER].t2 = clock();
- s.test[ITER].sum = sum;
- s.test[DESTRUCT].t1 = clock();
- cvec_x_drop(&con);
- }
- s.test[DESTRUCT].t2 = clock();
- s.test[DESTRUCT].sum = 0;
- return s;
-}
-
-int main(int argc, char* argv[])
-{
- Sample std_s[SAMPLES + 1] = {0}, stc_s[SAMPLES + 1] = {0};
- c_forrange (i, int, SAMPLES) {
- std_s[i] = test_std_vector();
- stc_s[i] = test_stc_vector();
- if (i > 0) c_forrange (j, int, N_TESTS) {
- if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j];
- if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j];
- if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j);
- }
- }
- const char* comp = argc > 1 ? argv[1] : "test";
- bool header = (argc > 2 && argv[2][0] == '1');
- float std_sum = 0, stc_sum = 0;
- c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); }
- if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n");
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f);
- c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f);
- printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum);
-}
+#include <stdio.h> +#include <time.h> +#define i_static +#include <stc/crandom.h> + +#ifdef __cplusplus +#include <vector> +#include <algorithm> +#endif + +enum {INSERT, ERASE, FIND, ITER, DESTRUCT, N_TESTS}; +const char* operations[] = {"insert", "erase", "find", "iter", "destruct"}; +typedef struct { time_t t1, t2; uint64_t sum; float fac; } Range; +typedef struct { const char* name; Range test[N_TESTS]; } Sample; +enum {SAMPLES = 2, N = 150000000, S = 0x3ffc, R = 4}; +uint64_t seed = 1, mask1 = 0xfffffff, mask2 = 0xffff; + +static float secs(Range s) { return (float)(s.t2 - s.t1) / CLOCKS_PER_SEC; } + +#define i_val size_t +#define i_tag x +#include <stc/cvec.h> + +#ifdef __cplusplus +Sample test_std_vector() { + typedef std::vector<size_t> container; + Sample s = {"std,vector"}; + { + s.test[INSERT].t1 = clock(); + container con; + csrandom(seed); + c_forrange (N) con.push_back(crandom() & mask1); + s.test[INSERT].t2 = clock(); + s.test[INSERT].sum = con.size(); + s.test[ERASE].t1 = clock(); + c_forrange (N) con.pop_back(); + s.test[ERASE].t2 = clock(); + s.test[ERASE].sum = con.size(); + }{ + container con; + csrandom(seed); + c_forrange (N) con.push_back(crandom() & mask2); + s.test[FIND].t1 = clock(); + size_t sum = 0; + container::iterator it; + // Iteration - not inherent find - skipping + //c_forrange (S) if ((it = std::find(con.begin(), con.end(), crandom() & mask2)) != con.end()) sum += *it; + s.test[FIND].t2 = clock(); + s.test[FIND].sum = sum; + s.test[ITER].t1 = clock(); + sum = 0; + c_forrange (R) c_forrange (i, N) sum += con[i]; + s.test[ITER].t2 = clock(); + s.test[ITER].sum = sum; + s.test[DESTRUCT].t1 = clock(); + } + s.test[DESTRUCT].t2 = clock(); + s.test[DESTRUCT].sum = 0; + return s; +} +#else +Sample test_std_vector() { Sample s = {"std-vector"}; return s;} +#endif + + + +Sample test_stc_vector() { + typedef cvec_x container; + Sample s = {"STC,vector"}; + { + s.test[INSERT].t1 = clock(); + container con = cvec_x_init(); + csrandom(seed); + c_forrange (N) cvec_x_push_back(&con, crandom() & mask1); + s.test[INSERT].t2 = clock(); + s.test[INSERT].sum = cvec_x_size(con); + s.test[ERASE].t1 = clock(); + c_forrange (N) { cvec_x_pop_back(&con); } + s.test[ERASE].t2 = clock(); + s.test[ERASE].sum = cvec_x_size(con); + cvec_x_drop(&con); + }{ + csrandom(seed); + container con = cvec_x_init(); + c_forrange (N) cvec_x_push_back(&con, crandom() & mask2); + s.test[FIND].t1 = clock(); + size_t sum = 0; + //cvec_x_iter it, end = cvec_x_end(&con); + //c_forrange (S) if ((it = cvec_x_find(&con, crandom() & mask2)).ref != end.ref) sum += *it.ref; + s.test[FIND].t2 = clock(); + s.test[FIND].sum = sum; + s.test[ITER].t1 = clock(); + sum = 0; + c_forrange (R) c_forrange (i, N) sum += con.data[i]; + s.test[ITER].t2 = clock(); + s.test[ITER].sum = sum; + s.test[DESTRUCT].t1 = clock(); + cvec_x_drop(&con); + } + s.test[DESTRUCT].t2 = clock(); + s.test[DESTRUCT].sum = 0; + return s; +} + +int main(int argc, char* argv[]) +{ + Sample std_s[SAMPLES + 1] = {0}, stc_s[SAMPLES + 1] = {0}; + c_forrange (i, int, SAMPLES) { + std_s[i] = test_std_vector(); + stc_s[i] = test_stc_vector(); + if (i > 0) c_forrange (j, int, N_TESTS) { + if (secs(std_s[i].test[j]) < secs(std_s[0].test[j])) std_s[0].test[j] = std_s[i].test[j]; + if (secs(stc_s[i].test[j]) < secs(stc_s[0].test[j])) stc_s[0].test[j] = stc_s[i].test[j]; + if (stc_s[i].test[j].sum != stc_s[0].test[j].sum) printf("Error in sum: test %d, sample %d\n", i, j); + } + } + const char* comp = argc > 1 ? argv[1] : "test"; + bool header = (argc > 2 && argv[2][0] == '1'); + float std_sum = 0, stc_sum = 0; + c_forrange (j, N_TESTS) { std_sum += secs(std_s[0].test[j]); stc_sum += secs(stc_s[0].test[j]); } + if (header) printf("Compiler,Library,C,Method,Seconds,Ratio\n"); + c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, operations[j], secs(std_s[0].test[j]), 1.0f); + printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, std_s[0].name, N, "total", std_sum, 1.0f); + c_forrange (j, N_TESTS) printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, operations[j], secs(stc_s[0].test[j]), secs(std_s[0].test[j]) ? secs(stc_s[0].test[j])/secs(std_s[0].test[j]) : 1.0f); + printf("%s,%s n:%d,%s,%.3f,%.3f\n", comp, stc_s[0].name, N, "total", stc_sum, stc_sum/std_sum); +} diff --git a/docs/cset_api.md b/docs/cset_api.md index 2d20c303..b325eaca 100644 --- a/docs/cset_api.md +++ b/docs/cset_api.md @@ -1,123 +1,123 @@ -# STC [cset](../include/stc/cset.h): Unordered Set
-
-
-A **cset** is an associative container that contains a set of unique objects of type i_key. Search, insertion, and removal have average constant-time complexity. See the c++ class
-[std::unordered_set](https://en.cppreference.com/w/cpp/container/unordered_set) for a functional description.
-
-## Header file and declaration
-
-```c
-#define i_key // hash key: REQUIRED.
-#define i_hash // hash func: REQUIRED IF i_keyraw is a non-pod type.
-#define i_eq // equality comparison two i_keyraw*: !i_cmp will be used if not defined.
-#define i_keydrop // destroy key func - defaults to empty destruct
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy
-#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
-#define i_tag // typename tag. defaults to i_key
-#define i_type // full typename of the container
-#include <stc/cset.h>
-```
-`X` should be replaced by the value of `i_tag` in all of the following documentation.
-
-## Methods
-
-```c
-cset_X cset_X_init(void);
-cset_X cset_X_with_capacity(size_t cap);
-cset_X cset_X_clone(cset_x set);
-
-void cset_X_clear(cset_X* self);
-void cset_X_copy(cset_X* self, cset_X other);
-void cset_X_max_load_factor(cset_X* self, float max_load); // default: 0.85
-bool cset_X_reserve(cset_X* self, size_t size);
-void cset_X_shrink_to_fit(cset_X* self);
-void cset_X_swap(cset_X* a, cset_X* b);
-void cset_X_drop(cset_X* self); // destructor
-
-size_t cset_X_size(cset_X set); // num. of allocated buckets
-size_t cset_X_capacity(cset_X set); // buckets * max_load_factor
-bool cset_X_empty(cset_X set);
-size_t cset_X_bucket_count(cset_X set);
-
-bool cset_X_contains(const cset_X* self, i_keyraw rkey);
-const cset_X_value* cset_X_get(const cset_X* self, i_keyraw rkey); // return NULL if not found
-cset_X_value* cset_X_get_mut(cset_X* self, i_keyraw rkey); // mutable get
-cset_X_iter cset_X_find(const cset_X* self, i_keyraw rkey);
-
-cset_X_result cset_X_insert(cset_X* self, i_key key);
-cset_X_result cset_X_push(cset_X* self, i_key key); // alias for insert.
-cset_X_result cset_X_emplace(cset_X* self, i_keyraw rkey);
-
-size_t cset_X_erase(cset_X* self, i_keyraw rkey); // return 0 or 1
-cset_X_iter cset_X_erase_at(cset_X* self, cset_X_iter it); // return iter after it
-void cset_X_erase_entry(cset_X* self, cset_X_value* entry);
-
-cset_X_iter cset_X_begin(const cset_X* self);
-cset_X_iter cset_X_end(const cset_X* self);
-void cset_X_next(cset_X_iter* it);
-
-cset_X_value cset_X_value_clone(cset_X_value val);
-```
-
-## Types
-
-| Type name | Type definition | Used to represent... |
-|:-------------------|:-------------------------------------------------|:----------------------------|
-| `cset_X` | `struct { ... }` | The cset type |
-| `cset_X_rawkey` | `i_keyraw` | The raw key type |
-| `cset_X_raw` | `i_keyraw` | The raw value type |
-| `cset_X_key` | `i_key` | The key type |
-| `cset_X_value` | `i_key` | The value |
-| `cset_X_result` | `struct { cset_X_value* ref; bool inserted; }` | Result of insert/emplace |
-| `cset_X_iter` | `struct { cset_X_value *ref; ... }` | Iterator type |
-
-## Example
-```c
-#include <stc/cstr.h>
-
-#define i_key_str
-#include <stc/cset.h>
-
-int main ()
-{
- c_auto (cset_str, fifth)
- {
- c_auto (cset_str, first, second)
- c_auto (cset_str, third, fourth)
- {
- c_apply(v, cset_str_emplace(&second, *v), const char*,
- {"red", "green", "blue"});
- c_apply(v, cset_str_emplace(&third, *v), const char*,
- {"orange", "pink", "yellow"});
-
- cset_str_emplace(&fourth, "potatoes");
- cset_str_emplace(&fourth, "milk");
- cset_str_emplace(&fourth, "flour");
-
- fifth = cset_str_clone(second);
- c_foreach (i, cset_str, third)
- cset_str_emplace(&fifth, cstr_str(i.ref));
- c_foreach (i, cset_str, fourth)
- cset_str_emplace(&fifth, cstr_str(i.ref));
- }
- printf("fifth contains:\n\n");
- c_foreach (i, cset_str, fifth)
- printf("%s\n", cstr_str(i.ref));
- }
-}
-```
-Output:
-```
-fifth contains:
-
-red
-green
-flour
-orange
-blue
-pink
-yellow
-milk
-potatoes
-```
+# STC [cset](../include/stc/cset.h): Unordered Set + + +A **cset** is an associative container that contains a set of unique objects of type i_key. Search, insertion, and removal have average constant-time complexity. See the c++ class +[std::unordered_set](https://en.cppreference.com/w/cpp/container/unordered_set) for a functional description. + +## Header file and declaration + +```c +#define i_key // hash key: REQUIRED. +#define i_hash // hash func: REQUIRED IF i_keyraw is a non-pod type. +#define i_eq // equality comparison two i_keyraw*: !i_cmp will be used if not defined. +#define i_keydrop // destroy key func - defaults to empty destruct +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy +#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy +#define i_tag // typename tag. defaults to i_key +#define i_type // full typename of the container +#include <stc/cset.h> +``` +`X` should be replaced by the value of `i_tag` in all of the following documentation. + +## Methods + +```c +cset_X cset_X_init(void); +cset_X cset_X_with_capacity(size_t cap); +cset_X cset_X_clone(cset_x set); + +void cset_X_clear(cset_X* self); +void cset_X_copy(cset_X* self, cset_X other); +void cset_X_max_load_factor(cset_X* self, float max_load); // default: 0.85 +bool cset_X_reserve(cset_X* self, size_t size); +void cset_X_shrink_to_fit(cset_X* self); +void cset_X_swap(cset_X* a, cset_X* b); +void cset_X_drop(cset_X* self); // destructor + +size_t cset_X_size(cset_X set); // num. of allocated buckets +size_t cset_X_capacity(cset_X set); // buckets * max_load_factor +bool cset_X_empty(cset_X set); +size_t cset_X_bucket_count(cset_X set); + +bool cset_X_contains(const cset_X* self, i_keyraw rkey); +const cset_X_value* cset_X_get(const cset_X* self, i_keyraw rkey); // return NULL if not found +cset_X_value* cset_X_get_mut(cset_X* self, i_keyraw rkey); // mutable get +cset_X_iter cset_X_find(const cset_X* self, i_keyraw rkey); + +cset_X_result cset_X_insert(cset_X* self, i_key key); +cset_X_result cset_X_push(cset_X* self, i_key key); // alias for insert. +cset_X_result cset_X_emplace(cset_X* self, i_keyraw rkey); + +size_t cset_X_erase(cset_X* self, i_keyraw rkey); // return 0 or 1 +cset_X_iter cset_X_erase_at(cset_X* self, cset_X_iter it); // return iter after it +void cset_X_erase_entry(cset_X* self, cset_X_value* entry); + +cset_X_iter cset_X_begin(const cset_X* self); +cset_X_iter cset_X_end(const cset_X* self); +void cset_X_next(cset_X_iter* it); + +cset_X_value cset_X_value_clone(cset_X_value val); +``` + +## Types + +| Type name | Type definition | Used to represent... | +|:-------------------|:-------------------------------------------------|:----------------------------| +| `cset_X` | `struct { ... }` | The cset type | +| `cset_X_rawkey` | `i_keyraw` | The raw key type | +| `cset_X_raw` | `i_keyraw` | The raw value type | +| `cset_X_key` | `i_key` | The key type | +| `cset_X_value` | `i_key` | The value | +| `cset_X_result` | `struct { cset_X_value* ref; bool inserted; }` | Result of insert/emplace | +| `cset_X_iter` | `struct { cset_X_value *ref; ... }` | Iterator type | + +## Example +```c +#include <stc/cstr.h> + +#define i_key_str +#include <stc/cset.h> + +int main () +{ + c_auto (cset_str, fifth) + { + c_auto (cset_str, first, second) + c_auto (cset_str, third, fourth) + { + c_apply(v, cset_str_emplace(&second, *v), const char*, + {"red", "green", "blue"}); + c_apply(v, cset_str_emplace(&third, *v), const char*, + {"orange", "pink", "yellow"}); + + cset_str_emplace(&fourth, "potatoes"); + cset_str_emplace(&fourth, "milk"); + cset_str_emplace(&fourth, "flour"); + + fifth = cset_str_clone(second); + c_foreach (i, cset_str, third) + cset_str_emplace(&fifth, cstr_str(i.ref)); + c_foreach (i, cset_str, fourth) + cset_str_emplace(&fifth, cstr_str(i.ref)); + } + printf("fifth contains:\n\n"); + c_foreach (i, cset_str, fifth) + printf("%s\n", cstr_str(i.ref)); + } +} +``` +Output: +``` +fifth contains: + +red +green +flour +orange +blue +pink +yellow +milk +potatoes +``` diff --git a/docs/csset_api.md b/docs/csset_api.md index 83b7e11b..e7a7b044 100644 --- a/docs/csset_api.md +++ b/docs/csset_api.md @@ -1,123 +1,123 @@ -# STC [csset](../include/stc/csset.h): Sorted Set
-
-
-A **csset** is an associative container that contains a sorted set of unique objects of type *i_key*. Sorting is done using the key comparison function *keyCompare*. Search, removal, and insertion operations have logarithmic complexity. **csset** is implemented as an AA-tree.
-
-See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) for a functional description.
-
-## Header file and declaration
-
-```c
-#define i_key // key: REQUIRED
-#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type
-#define i_keydrop // destroy key func - defaults to empty destruct
-#define i_keyraw // convertion "raw" type - defaults to i_key
-#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy
-#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy
-#define i_tag // typename tag. defaults to i_key
-#define i_type // full typename of the container
-#include <stc/csset.h>
-```
-`X` should be replaced by the value of `i_tag` in all of the following documentation.
-
-## Methods
-
-```c
-csset_X csset_X_init(void);
-csset_X csset_X_with_capacity(size_t cap);
-bool csset_X_reserve(csset_X* self, size_t cap);
-void csset_X_shrink_to_fit(csset_X* self);
-csset_X csset_X_clone(csset_x set);
-
-void csset_X_clear(csset_X* self);
-void csset_X_copy(csset_X* self, csset_X other);
-void csset_X_swap(csset_X* a, csset_X* b);
-void csset_X_drop(csset_X* self); // destructor
-
-size_t csset_X_size(csset_X set);
-bool csset_X_empty(csset_X set);
-
-const csset_X_value* csset_X_get(const csset_X* self, i_keyraw rkey); // const get
-csset_X_value* csset_X_get_mut(csset_X* self, i_keyraw rkey); // return NULL if not found
-bool csset_X_contains(const csset_X* self, i_keyraw rkey);
-csset_X_iter csset_X_find(const csset_X* self, i_keyraw rkey);
-csset_X_value* csset_X_find_it(const csset_X* self, i_keyraw rkey, csset_X_iter* out); // return NULL if not found
-csset_X_iter csset_X_lower_bound(const csset_X* self, i_keyraw rkey); // find closest entry >= rkey
-
-csset_X_result csset_X_insert(csset_X* self, i_key key);
-csset_X_result csset_X_push(csset_X* self, i_key key); // alias for insert()
-csset_X_result csset_X_emplace(csset_X* self, i_keyraw rkey);
-
-size_t csset_X_erase(csset_X* self, i_keyraw rkey);
-csset_X_iter csset_X_erase_at(csset_X* self, csset_X_iter it); // return iter after it
-csset_X_iter csset_X_erase_range(csset_X* self, csset_X_iter it1, csset_X_iter it2); // return updated it2
-
-csset_X_iter csset_X_begin(const csset_X* self);
-csset_X_iter csset_X_end(const csset_X* self);
-void csset_X_next(csset_X_iter* it);
-
-csset_X_value csset_X_value_clone(csset_X_value val);
-```
-
-## Types
-
-| Type name | Type definition | Used to represent... |
-|:-------------------|:--------------------------------------------------|:----------------------------|
-| `csset_X` | `struct { ... }` | The csset type |
-| `csset_X_rawkey` | `i_keyraw` | The raw key type |
-| `csset_X_raw` | `i_keyraw` | The raw key type |
-| `csset_X_key` | `i_key` | The key type |
-| `csset_X_value` | `i_key ` | The value: key is immutable |
-| `csset_X_result` | `struct { csset_X_value* ref; bool inserted; }` | Result of insert/emplace |
-| `csset_X_iter` | `struct { csset_X_value *ref; ... }` | Iterator type |
-
-## Example
-```c
-#define i_implement
-#include <stc/cstr.h>
-
-#define i_key_str
-#include <stc/csset.h>
-
-int main ()
-{
-c_auto (csset_str, fifth)
- {
- c_auto (csset_str, first, second)
- c_auto (csset_str, third, fourth)
- {
- c_apply(v, csset_str_emplace(&second, *v), const char*,
- {"red", "green", "blue"});
- c_apply(v, csset_str_emplace(&third, *v), const char*,
- {"orange", "pink", "yellow"});
-
- csset_str_emplace(&fourth, "potatoes");
- csset_str_emplace(&fourth, "milk");
- csset_str_emplace(&fourth, "flour");
-
- fifth = csset_str_clone(second);
- c_foreach (i, csset_str, third)
- csset_str_emplace(&fifth, cstr_str(i.ref));
- c_foreach (i, csset_str, fourth)
- csset_str_emplace(&fifth, cstr_str(i.ref));
- }
- printf("fifth contains:\n\n");
- c_foreach (i, csset_str, fifth)
- printf("%s\n", cstr_str(i.ref));
- }
-}
-```
-Output:
-```
-fifth contains:
-
-blue
-flour
-green
-milk
-orange
-pink
-potatoes
-red
-yellow
-```
+# STC [csset](../include/stc/csset.h): Sorted Set + + +A **csset** is an associative container that contains a sorted set of unique objects of type *i_key*. Sorting is done using the key comparison function *keyCompare*. Search, removal, and insertion operations have logarithmic complexity. **csset** is implemented as an AA-tree. + +See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) for a functional description. + +## Header file and declaration + +```c +#define i_key // key: REQUIRED +#define i_cmp // three-way compare two i_keyraw* : REQUIRED IF i_keyraw is a non-integral type +#define i_keydrop // destroy key func - defaults to empty destruct +#define i_keyraw // convertion "raw" type - defaults to i_key +#define i_keyfrom // convertion func i_keyraw => i_key - defaults to plain copy +#define i_keyto // convertion func i_key* => i_keyraw - defaults to plain copy +#define i_tag // typename tag. defaults to i_key +#define i_type // full typename of the container +#include <stc/csset.h> +``` +`X` should be replaced by the value of `i_tag` in all of the following documentation. + +## Methods + +```c +csset_X csset_X_init(void); +csset_X csset_X_with_capacity(size_t cap); +bool csset_X_reserve(csset_X* self, size_t cap); +void csset_X_shrink_to_fit(csset_X* self); +csset_X csset_X_clone(csset_x set); + +void csset_X_clear(csset_X* self); +void csset_X_copy(csset_X* self, csset_X other); +void csset_X_swap(csset_X* a, csset_X* b); +void csset_X_drop(csset_X* self); // destructor + +size_t csset_X_size(csset_X set); +bool csset_X_empty(csset_X set); + +const csset_X_value* csset_X_get(const csset_X* self, i_keyraw rkey); // const get +csset_X_value* csset_X_get_mut(csset_X* self, i_keyraw rkey); // return NULL if not found +bool csset_X_contains(const csset_X* self, i_keyraw rkey); +csset_X_iter csset_X_find(const csset_X* self, i_keyraw rkey); +csset_X_value* csset_X_find_it(const csset_X* self, i_keyraw rkey, csset_X_iter* out); // return NULL if not found +csset_X_iter csset_X_lower_bound(const csset_X* self, i_keyraw rkey); // find closest entry >= rkey + +csset_X_result csset_X_insert(csset_X* self, i_key key); +csset_X_result csset_X_push(csset_X* self, i_key key); // alias for insert() +csset_X_result csset_X_emplace(csset_X* self, i_keyraw rkey); + +size_t csset_X_erase(csset_X* self, i_keyraw rkey); +csset_X_iter csset_X_erase_at(csset_X* self, csset_X_iter it); // return iter after it +csset_X_iter csset_X_erase_range(csset_X* self, csset_X_iter it1, csset_X_iter it2); // return updated it2 + +csset_X_iter csset_X_begin(const csset_X* self); +csset_X_iter csset_X_end(const csset_X* self); +void csset_X_next(csset_X_iter* it); + +csset_X_value csset_X_value_clone(csset_X_value val); +``` + +## Types + +| Type name | Type definition | Used to represent... | +|:-------------------|:--------------------------------------------------|:----------------------------| +| `csset_X` | `struct { ... }` | The csset type | +| `csset_X_rawkey` | `i_keyraw` | The raw key type | +| `csset_X_raw` | `i_keyraw` | The raw key type | +| `csset_X_key` | `i_key` | The key type | +| `csset_X_value` | `i_key ` | The value: key is immutable | +| `csset_X_result` | `struct { csset_X_value* ref; bool inserted; }` | Result of insert/emplace | +| `csset_X_iter` | `struct { csset_X_value *ref; ... }` | Iterator type | + +## Example +```c +#define i_implement +#include <stc/cstr.h> + +#define i_key_str +#include <stc/csset.h> + +int main () +{ +c_auto (csset_str, fifth) + { + c_auto (csset_str, first, second) + c_auto (csset_str, third, fourth) + { + c_apply(v, csset_str_emplace(&second, *v), const char*, + {"red", "green", "blue"}); + c_apply(v, csset_str_emplace(&third, *v), const char*, + {"orange", "pink", "yellow"}); + + csset_str_emplace(&fourth, "potatoes"); + csset_str_emplace(&fourth, "milk"); + csset_str_emplace(&fourth, "flour"); + + fifth = csset_str_clone(second); + c_foreach (i, csset_str, third) + csset_str_emplace(&fifth, cstr_str(i.ref)); + c_foreach (i, csset_str, fourth) + csset_str_emplace(&fifth, cstr_str(i.ref)); + } + printf("fifth contains:\n\n"); + c_foreach (i, csset_str, fifth) + printf("%s\n", cstr_str(i.ref)); + } +} +``` +Output: +``` +fifth contains: + +blue +flour +green +milk +orange +pink +potatoes +red +yellow +``` diff --git a/examples/README.md b/examples/README.md index ad7726d4..4c0aa763 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,4 +1,4 @@ -Examples
-========
-This folder contains various examples of STC container usage.
-
+Examples +======== +This folder contains various examples of STC container usage. + diff --git a/examples/arc_containers.c b/examples/arc_containers.c index 1fe227f7..969825eb 100644 --- a/examples/arc_containers.c +++ b/examples/arc_containers.c @@ -1,77 +1,77 @@ -// Create a stack and a list of shared pointers to maps,
-// and demonstrate sharing and cloning of maps.
-#define i_static
-#include <stc/cstr.h>
-#define i_type Map
-#define i_key_str // strings
-#define i_val int
-#define i_keydrop(p) (printf("drop name: %s\n", cstr_str(p)), cstr_drop(p))
-#include <stc/csmap.h>
-
-#define i_type Arc // (atomic) ref. counted type
-#define i_val Map
-#define i_valdrop(p) (printf("drop Arc:\n"), Map_drop(p))
-// no need for atomic ref. count in single thread:
-// no compare function available for csmap:
-#define i_opt c_no_atomic|c_no_cmp
-#include <stc/carc.h>
-
-#define i_type Stack
-#define i_val_arcbox Arc // define i_val_bind for carc/cbox value (not i_val)
-#include <stc/cstack.h>
-
-#define i_type List
-#define i_val_arcbox Arc // as above
-#include <stc/clist.h>
-
-int main()
-{
- c_auto (Stack, stack)
- c_auto (List, list)
- {
- // POPULATE stack with shared pointers to Maps:
- Map *map;
- map = Stack_push(&stack, Arc_make(Map_init()))->get;
- c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, {
- {"Joey", 1990}, {"Mary", 1995}, {"Joanna", 1992}
- });
- map = Stack_push(&stack, Arc_make(Map_init()))->get;
- c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, {
- {"Rosanna", 2001}, {"Brad", 1999}, {"Jack", 1980}
- });
-
- // POPULATE list:
- map = List_push_back(&list, Arc_make(Map_init()))->get;
- c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, {
- {"Steve", 1979}, {"Rick", 1974}, {"Tracy", 2003}
- });
-
- // Share two Maps from the stack with the list using emplace (clone the carc):
- List_push_back(&list, Arc_clone(stack.data[0]));
- List_push_back(&list, Arc_clone(stack.data[1]));
-
- // Clone (deep copy) a Map from the stack to the list
- // List will contain two shared and two unshared maps.
- map = List_push_back(&list, Arc_make(Map_clone(*stack.data[1].get)))->get;
-
- // Add one more element to the cloned map:
- Map_emplace_or_assign(map, "CLONED", 2021);
-
- // Add one more element to the shared map:
- Map_emplace_or_assign(stack.data[1].get, "SHARED", 2021);
-
-
- puts("STACKS");
- c_foreach (i, Stack, stack) {
- c_forpair (name, year, Map, *i.ref->get)
- printf(" %s:%d", cstr_str(_.name), *_.year);
- puts("");
- }
- puts("LIST");
- c_foreach (i, List, list) {
- c_forpair (name, year, Map, *i.ref->get)
- printf(" %s:%d", cstr_str(_.name), *_.year);
- puts("");
- }
- }
-}
+// Create a stack and a list of shared pointers to maps, +// and demonstrate sharing and cloning of maps. +#define i_static +#include <stc/cstr.h> +#define i_type Map +#define i_key_str // strings +#define i_val int +#define i_keydrop(p) (printf("drop name: %s\n", cstr_str(p)), cstr_drop(p)) +#include <stc/csmap.h> + +#define i_type Arc // (atomic) ref. counted type +#define i_val Map +#define i_valdrop(p) (printf("drop Arc:\n"), Map_drop(p)) +// no need for atomic ref. count in single thread: +// no compare function available for csmap: +#define i_opt c_no_atomic|c_no_cmp +#include <stc/carc.h> + +#define i_type Stack +#define i_val_arcbox Arc // define i_val_bind for carc/cbox value (not i_val) +#include <stc/cstack.h> + +#define i_type List +#define i_val_arcbox Arc // as above +#include <stc/clist.h> + +int main() +{ + c_auto (Stack, stack) + c_auto (List, list) + { + // POPULATE stack with shared pointers to Maps: + Map *map; + map = Stack_push(&stack, Arc_make(Map_init()))->get; + c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, { + {"Joey", 1990}, {"Mary", 1995}, {"Joanna", 1992} + }); + map = Stack_push(&stack, Arc_make(Map_init()))->get; + c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, { + {"Rosanna", 2001}, {"Brad", 1999}, {"Jack", 1980} + }); + + // POPULATE list: + map = List_push_back(&list, Arc_make(Map_init()))->get; + c_apply(v, Map_emplace(map, c_pair(v)), Map_raw, { + {"Steve", 1979}, {"Rick", 1974}, {"Tracy", 2003} + }); + + // Share two Maps from the stack with the list using emplace (clone the carc): + List_push_back(&list, Arc_clone(stack.data[0])); + List_push_back(&list, Arc_clone(stack.data[1])); + + // Clone (deep copy) a Map from the stack to the list + // List will contain two shared and two unshared maps. + map = List_push_back(&list, Arc_make(Map_clone(*stack.data[1].get)))->get; + + // Add one more element to the cloned map: + Map_emplace_or_assign(map, "CLONED", 2021); + + // Add one more element to the shared map: + Map_emplace_or_assign(stack.data[1].get, "SHARED", 2021); + + + puts("STACKS"); + c_foreach (i, Stack, stack) { + c_forpair (name, year, Map, *i.ref->get) + printf(" %s:%d", cstr_str(_.name), *_.year); + puts(""); + } + puts("LIST"); + c_foreach (i, List, list) { + c_forpair (name, year, Map, *i.ref->get) + printf(" %s:%d", cstr_str(_.name), *_.year); + puts(""); + } + } +} diff --git a/examples/arc_demo.c b/examples/arc_demo.c index daeb5a68..85e3886f 100644 --- a/examples/arc_demo.c +++ b/examples/arc_demo.c @@ -1,56 +1,56 @@ -#include <stdio.h>
-#include <string.h>
-
-void int_drop(int* x) {
- printf("drop: %d\n", *x);
-}
-
-// carc implements its own clone method using reference counting,
-// so 'i_valclone' is not required to be defined (ignored).
-
-#define i_type Arc // set type name to be defined (instead of 'carc_int')
-#define i_val int
-#define i_valdrop int_drop // optional, just to display the elements destroyed
-#include <stc/carc.h> // Arc
-
-#define i_key_arcbox Arc // note: use i_key_bind instead of i_key for carc/cbox elements
-#include <stc/csset.h> // csset_Arc (like: std::set<std::shared_ptr<int>>)
-
-#define i_val_arcbox Arc // note: as above.
-#include <stc/cvec.h> // cvec_Arc (like: std::vector<std::shared_ptr<int>>)
-
-int main()
-{
- c_auto (cvec_Arc, vec) // declare and init vec, call cvec_Arc_drop() at scope exit
- c_auto (csset_Arc, set) // declare and init set, call csset_Arc_drop() at scope exit
- {
- const int years[] = {2021, 2012, 2022, 2015};
- c_forrange (i, c_arraylen(years))
- cvec_Arc_push_back(&vec, Arc_make(years[i]));
-
- printf("vec:");
- c_foreach (i, cvec_Arc, vec) printf(" %d", *i.ref->get);
- puts("");
-
- // add odd numbers from vec to set
- c_foreach (i, cvec_Arc, vec)
- if (*i.ref->get & 1)
- csset_Arc_insert(&set, Arc_clone(*i.ref)); // copy shared pointer => increments counter.
-
- // erase the two last elements in vec
- cvec_Arc_pop_back(&vec);
- cvec_Arc_pop_back(&vec);
-
- printf("vec:");
- c_foreach (i, cvec_Arc, vec) printf(" %d", *i.ref->get);
-
- printf("\nset:");
- c_foreach (i, csset_Arc, set) printf(" %d", *i.ref->get);
-
- c_autovar (Arc p = Arc_clone(vec.data[0]), Arc_drop(&p)) {
- printf("\n%d is now owned by %ld objects\n", *p.get, *p.use_count);
- }
-
- puts("\nDone");
- }
-}
+#include <stdio.h> +#include <string.h> + +void int_drop(int* x) { + printf("drop: %d\n", *x); +} + +// carc implements its own clone method using reference counting, +// so 'i_valclone' is not required to be defined (ignored). + +#define i_type Arc // set type name to be defined (instead of 'carc_int') +#define i_val int +#define i_valdrop int_drop // optional, just to display the elements destroyed +#include <stc/carc.h> // Arc + +#define i_key_arcbox Arc // note: use i_key_bind instead of i_key for carc/cbox elements +#include <stc/csset.h> // csset_Arc (like: std::set<std::shared_ptr<int>>) + +#define i_val_arcbox Arc // note: as above. +#include <stc/cvec.h> // cvec_Arc (like: std::vector<std::shared_ptr<int>>) + +int main() +{ + c_auto (cvec_Arc, vec) // declare and init vec, call cvec_Arc_drop() at scope exit + c_auto (csset_Arc, set) // declare and init set, call csset_Arc_drop() at scope exit + { + const int years[] = {2021, 2012, 2022, 2015}; + c_forrange (i, c_arraylen(years)) + cvec_Arc_push_back(&vec, Arc_make(years[i])); + + printf("vec:"); + c_foreach (i, cvec_Arc, vec) printf(" %d", *i.ref->get); + puts(""); + + // add odd numbers from vec to set + c_foreach (i, cvec_Arc, vec) + if (*i.ref->get & 1) + csset_Arc_insert(&set, Arc_clone(*i.ref)); // copy shared pointer => increments counter. + + // erase the two last elements in vec + cvec_Arc_pop_back(&vec); + cvec_Arc_pop_back(&vec); + + printf("vec:"); + c_foreach (i, cvec_Arc, vec) printf(" %d", *i.ref->get); + + printf("\nset:"); + c_foreach (i, csset_Arc, set) printf(" %d", *i.ref->get); + + c_autovar (Arc p = Arc_clone(vec.data[0]), Arc_drop(&p)) { + printf("\n%d is now owned by %ld objects\n", *p.get, *p.use_count); + } + + puts("\nDone"); + } +} diff --git a/examples/arcvec_erase.c b/examples/arcvec_erase.c index e4497486..eba77f51 100644 --- a/examples/arcvec_erase.c +++ b/examples/arcvec_erase.c @@ -1,53 +1,53 @@ -#include <stdio.h>
-
-void show_drop(int* x) { printf("drop: %d\n", *x); }
-
-#define i_type Arc
-#define i_val int
-#define i_valdrop show_drop
-// carc/cbox will use pointer address comparison of i_val
-// if 'i_opt c_no_cmp' is defined, otherwise i_cmp is used
-// to compare object values. See the two differences by
-// commenting out the next line.
-#include <stc/carc.h> // Shared pointer to int
-
-#define i_type Vec
-#define i_val_arcbox Arc
-#include <stc/cvec.h> // Vec: cvec<Arc>
-
-
-int main()
-{
- c_auto (Vec, vec)
- {
- const int v[] = {2012, 1990, 2012, 2019, 2015};
- c_forrange (i, c_arraylen(v))
- Vec_push_back(&vec, Arc_make(v[i]));
-
- // clone the second 2012 and push it back.
- // note: cloning make sure that vec.data[2] has ref count 2.
- Vec_push_back(&vec, Arc_clone(vec.data[2]));
-
- printf("vec before erase :");
- c_foreach (i, Vec, vec)
- printf(" %d", *i.ref->get);
- puts("");
-
- printf("erase vec.data[2]; or first matching value depending on compare.\n");
- Vec_iter it;
- it = Vec_find(&vec, *vec.data[2].get);
- if (it.ref != Vec_end(&vec).ref)
- Vec_erase_at(&vec, it);
-
- int year = 2015;
- it = Vec_find(&vec, year); // Ok as tmp only.
- if (it.ref != Vec_end(&vec).ref)
- Vec_erase_at(&vec, it);
-
- printf("vec after erase :");
- c_foreach (i, Vec, vec)
- printf(" %d", *i.ref->get);
-
- puts("\nDone");
- }
-}
+#include <stdio.h> + +void show_drop(int* x) { printf("drop: %d\n", *x); } + +#define i_type Arc +#define i_val int +#define i_valdrop show_drop +// carc/cbox will use pointer address comparison of i_val +// if 'i_opt c_no_cmp' is defined, otherwise i_cmp is used +// to compare object values. See the two differences by +// commenting out the next line. +#include <stc/carc.h> // Shared pointer to int + +#define i_type Vec +#define i_val_arcbox Arc +#include <stc/cvec.h> // Vec: cvec<Arc> + + +int main() +{ + c_auto (Vec, vec) + { + const int v[] = {2012, 1990, 2012, 2019, 2015}; + c_forrange (i, c_arraylen(v)) + Vec_push_back(&vec, Arc_make(v[i])); + + // clone the second 2012 and push it back. + // note: cloning make sure that vec.data[2] has ref count 2. + Vec_push_back(&vec, Arc_clone(vec.data[2])); + + printf("vec before erase :"); + c_foreach (i, Vec, vec) + printf(" %d", *i.ref->get); + puts(""); + + printf("erase vec.data[2]; or first matching value depending on compare.\n"); + Vec_iter it; + it = Vec_find(&vec, *vec.data[2].get); + if (it.ref != Vec_end(&vec).ref) + Vec_erase_at(&vec, it); + + int year = 2015; + it = Vec_find(&vec, year); // Ok as tmp only. + if (it.ref != Vec_end(&vec).ref) + Vec_erase_at(&vec, it); + + printf("vec after erase :"); + c_foreach (i, Vec, vec) + printf(" %d", *i.ref->get); + + puts("\nDone"); + } +} diff --git a/examples/astar.c b/examples/astar.c index 5bcbe7e9..db2d128c 100644 --- a/examples/astar.c +++ b/examples/astar.c @@ -1,167 +1,167 @@ -//
-// -- An A* pathfinder inspired by the excellent tutorial at Red Blob Games --
-//
-// This is a reimplementation of the CTL example to STC:
-// https://github.com/glouw/ctl/blob/master/examples/astar.c
-// https://www.redblobgames.com/pathfinding/a-star/introduction.html
-#define i_implement
-#include <stc/cstr.h>
-#include <stdio.h>
-
-typedef struct
-{
- int x;
- int y;
- int priorty;
- int width;
-}
-point;
-
-point
-point_init(int x, int y, int width)
-{
- return (point) { x, y, 0, width };
-}
-
-int
-point_cmp_priority(const point* a, const point* b)
-{
- return c_default_cmp(&a->priorty, &b->priorty);
-}
-
-int
-point_equal(const point* a, const point* b)
-{
- return a->x == b->x && a->y == b->y;
-}
-
-point
-point_from(const cstr* maze, const char* c, int width)
-{
- int index = cstr_find(*maze, c);
- return point_init(index % width, index / width, width);
-}
-
-int
-point_index(const point* p)
-{
- return p->x + p->width * p->y;
-}
-
-int
-point_key_cmp(const point* a, const point* b)
-{
- int i = point_index(a);
- int j = point_index(b);
- return (i == j) ? 0 : (i < j) ? -1 : 1;
-}
-
-#define i_val point
-#define i_cmp point_cmp_priority
-#include <stc/cpque.h>
-
-#define i_val point
-#define i_opt c_no_cmp
-#include <stc/cdeq.h>
-
-#define i_key point
-#define i_val int
-#define i_cmp point_key_cmp
-#define i_tag pcost
-#include <stc/csmap.h>
-
-#define i_key point
-#define i_val point
-#define i_cmp point_key_cmp
-#define i_tag pstep
-#include <stc/csmap.h>
-
-cdeq_point
-astar(cstr* maze, int width)
-{
- cdeq_point path = cdeq_point_init();
-
- c_auto (cpque_point, front)
- c_auto (csmap_pstep, from)
- c_auto (csmap_pcost, costs)
- {
- point start = point_from(maze, "@", width);
- point goal = point_from(maze, "!", width);
- csmap_pcost_insert(&costs, start, 0);
- cpque_point_push(&front, start);
- while (!cpque_point_empty(front))
- {
- point current = *cpque_point_top(&front);
- cpque_point_pop(&front);
- if (point_equal(¤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 <stc/cstr.h> +#include <stdio.h> + +typedef struct +{ + int x; + int y; + int priorty; + int width; +} +point; + +point +point_init(int x, int y, int width) +{ + return (point) { x, y, 0, width }; +} + +int +point_cmp_priority(const point* a, const point* b) +{ + return c_default_cmp(&a->priorty, &b->priorty); +} + +int +point_equal(const point* a, const point* b) +{ + return a->x == b->x && a->y == b->y; +} + +point +point_from(const cstr* maze, const char* c, int width) +{ + int index = cstr_find(*maze, c); + return point_init(index % width, index / width, width); +} + +int +point_index(const point* p) +{ + return p->x + p->width * p->y; +} + +int +point_key_cmp(const point* a, const point* b) +{ + int i = point_index(a); + int j = point_index(b); + return (i == j) ? 0 : (i < j) ? -1 : 1; +} + +#define i_val point +#define i_cmp point_cmp_priority +#include <stc/cpque.h> + +#define i_val point +#define i_opt c_no_cmp +#include <stc/cdeq.h> + +#define i_key point +#define i_val int +#define i_cmp point_key_cmp +#define i_tag pcost +#include <stc/csmap.h> + +#define i_key point +#define i_val point +#define i_cmp point_key_cmp +#define i_tag pstep +#include <stc/csmap.h> + +cdeq_point +astar(cstr* maze, int width) +{ + cdeq_point path = cdeq_point_init(); + + c_auto (cpque_point, front) + c_auto (csmap_pstep, from) + c_auto (csmap_pcost, costs) + { + point start = point_from(maze, "@", width); + point goal = point_from(maze, "!", width); + csmap_pcost_insert(&costs, start, 0); + cpque_point_push(&front, start); + while (!cpque_point_empty(front)) + { + point current = *cpque_point_top(&front); + cpque_point_pop(&front); + if (point_equal(¤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 <math.h>
-#include <stdio.h>
-#include <time.h>
-#define i_implement
-#include <stc/crandom.h>
-
-#define i_tag ic
-#define i_key uint64_t
-#define i_val uint8_t
-#include <stc/cmap.h>
-
-static uint64_t seed = 12345;
-
-static void test_repeats(void)
-{
- enum {BITS = 46, BITS_TEST = BITS/2 + 2};
- const static uint64_t N = 1ull << BITS_TEST;
- const static uint64_t mask = (1ull << BITS) - 1;
-
- printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST);
- stc64_t rng = stc64_new(seed);
- c_auto (cmap_ic, m)
- {
- cmap_ic_reserve(&m, N);
- c_forrange (i, N) {
- uint64_t k = stc64_rand(&rng) & mask;
- int v = cmap_ic_insert(&m, k, 0).ref->second += 1;
- if (v > 1) printf("repeated value %" PRIuMAX " (%d) at 2^%d\n", k, v, (int) log2((double) i));
- }
- }
-}
-
-#define i_key uint32_t
-#define i_val uint64_t
-#define i_tag x
-#include <stc/cmap.h>
-
-void test_distribution(void)
-{
- enum {BITS = 26};
- printf("distribution test: 2^%d values\n", BITS);
- stc64_t rng = stc64_new(seed);
- const size_t N = 1ull << BITS ;
-
- c_auto (cmap_x, map) {
- c_forrange (N) {
- uint64_t k = stc64_rand(&rng);
- cmap_x_insert(&map, k & 0xf, 0).ref->second += 1;
- }
-
- uint64_t sum = 0;
- c_foreach (i, cmap_x, map) sum += i.ref->second;
- sum /= map.size;
-
- c_foreach (i, cmap_x, map) {
- printf("%4u: %" PRIuMAX " - %" PRIuMAX ": %11.8f\n", i.ref->first, i.ref->second, sum, (1 - (double) i.ref->second / sum));
- }
- }
-}
-
-int main()
-{
- seed = time(NULL);
- test_distribution();
- test_repeats();
-}
+#include <math.h> +#include <stdio.h> +#include <time.h> +#define i_implement +#include <stc/crandom.h> + +#define i_tag ic +#define i_key uint64_t +#define i_val uint8_t +#include <stc/cmap.h> + +static uint64_t seed = 12345; + +static void test_repeats(void) +{ + enum {BITS = 46, BITS_TEST = BITS/2 + 2}; + const static uint64_t N = 1ull << BITS_TEST; + const static uint64_t mask = (1ull << BITS) - 1; + + printf("birthday paradox: value range: 2^%d, testing repeats of 2^%d values\n", BITS, BITS_TEST); + stc64_t rng = stc64_new(seed); + c_auto (cmap_ic, m) + { + cmap_ic_reserve(&m, N); + c_forrange (i, N) { + uint64_t k = stc64_rand(&rng) & mask; + int v = cmap_ic_insert(&m, k, 0).ref->second += 1; + if (v > 1) printf("repeated value %" PRIuMAX " (%d) at 2^%d\n", k, v, (int) log2((double) i)); + } + } +} + +#define i_key uint32_t +#define i_val uint64_t +#define i_tag x +#include <stc/cmap.h> + +void test_distribution(void) +{ + enum {BITS = 26}; + printf("distribution test: 2^%d values\n", BITS); + stc64_t rng = stc64_new(seed); + const size_t N = 1ull << BITS ; + + c_auto (cmap_x, map) { + c_forrange (N) { + uint64_t k = stc64_rand(&rng); + cmap_x_insert(&map, k & 0xf, 0).ref->second += 1; + } + + uint64_t sum = 0; + c_foreach (i, cmap_x, map) sum += i.ref->second; + sum /= map.size; + + c_foreach (i, cmap_x, map) { + printf("%4u: %" PRIuMAX " - %" PRIuMAX ": %11.8f\n", i.ref->first, i.ref->second, sum, (1 - (double) i.ref->second / sum)); + } + } +} + +int main() +{ + seed = time(NULL); + test_distribution(); + test_repeats(); +} diff --git a/examples/bits.c b/examples/bits.c index 051beb02..71fe1ee0 100644 --- a/examples/bits.c +++ b/examples/bits.c @@ -1,63 +1,63 @@ -#include <stdio.h>
-#define i_implement
-#include <stc/cbits.h>
-
-int main()
-{
- c_autovar (cbits set = cbits_with_size(23, true), cbits_drop(&set)) {
- printf("count %" PRIuMAX ", %" PRIuMAX "\n", cbits_count(&set), cbits_size(&set));
- cbits s1 = cbits_from("1110100110111");
- char buf[256];
- cbits_to_str(&s1, buf, 0, -1);
- printf("buf: %s: %" PRIuMAX "\n", buf, cbits_count(&s1));
- cbits_drop(&s1);
-
- cbits_reset(&set, 9);
- cbits_resize(&set, 43, false);
- c_autobuf (str, char, cbits_size(&set) + 1)
- printf(" str: %s\n", cbits_to_str(&set, str, 0, -1));
-
- printf("%4" PRIuMAX ": ", cbits_size(&set));
- c_forrange (i, cbits_size(&set))
- printf("%d", cbits_test(&set, i));
- puts("");
-
- cbits_set(&set, 28);
- cbits_resize(&set, 77, true);
- cbits_resize(&set, 93, false);
- cbits_resize(&set, 102, true);
- cbits_set_value(&set, 99, false);
- printf("%4" PRIuMAX ": ", cbits_size(&set));
- c_forrange (i, cbits_size(&set))
- printf("%d", cbits_test(&set, i));
-
- puts("\nIterate:");
- printf("%4" PRIuMAX ": ", cbits_size(&set));
- c_forrange (i, cbits_size(&set))
- printf("%d", cbits_test(&set, i));
- puts("");
-
- c_autovar (cbits s2 = cbits_clone(set), cbits_drop(&s2)) {
- cbits_flip_all(&s2);
- cbits_set(&s2, 16);
- cbits_set(&s2, 17);
- cbits_set(&s2, 18);
- printf(" new: ");
- c_forrange (i, cbits_size(&s2))
- printf("%d", cbits_test(&s2, i));
- puts("");
-
- printf(" xor: ");
- cbits_xor(&set, &s2);
- c_forrange (i, cbits_size(&set))
- printf("%d", cbits_test(&set, i));
- puts("");
-
- cbits_set_all(&set, false);
- printf("%4" PRIuMAX ": ", cbits_size(&set));
- c_forrange (i, cbits_size(&set))
- printf("%d", cbits_test(&set, i));
- puts("");
- }
- }
-}
+#include <stdio.h> +#define i_implement +#include <stc/cbits.h> + +int main() +{ + c_autovar (cbits set = cbits_with_size(23, true), cbits_drop(&set)) { + printf("count %" PRIuMAX ", %" PRIuMAX "\n", cbits_count(&set), cbits_size(&set)); + cbits s1 = cbits_from("1110100110111"); + char buf[256]; + cbits_to_str(&s1, buf, 0, -1); + printf("buf: %s: %" PRIuMAX "\n", buf, cbits_count(&s1)); + cbits_drop(&s1); + + cbits_reset(&set, 9); + cbits_resize(&set, 43, false); + c_autobuf (str, char, cbits_size(&set) + 1) + printf(" str: %s\n", cbits_to_str(&set, str, 0, -1)); + + printf("%4" PRIuMAX ": ", cbits_size(&set)); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + puts(""); + + cbits_set(&set, 28); + cbits_resize(&set, 77, true); + cbits_resize(&set, 93, false); + cbits_resize(&set, 102, true); + cbits_set_value(&set, 99, false); + printf("%4" PRIuMAX ": ", cbits_size(&set)); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + + puts("\nIterate:"); + printf("%4" PRIuMAX ": ", cbits_size(&set)); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + puts(""); + + c_autovar (cbits s2 = cbits_clone(set), cbits_drop(&s2)) { + cbits_flip_all(&s2); + cbits_set(&s2, 16); + cbits_set(&s2, 17); + cbits_set(&s2, 18); + printf(" new: "); + c_forrange (i, cbits_size(&s2)) + printf("%d", cbits_test(&s2, i)); + puts(""); + + printf(" xor: "); + cbits_xor(&set, &s2); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + puts(""); + + cbits_set_all(&set, false); + printf("%4" PRIuMAX ": ", cbits_size(&set)); + c_forrange (i, cbits_size(&set)) + printf("%d", cbits_test(&set, i)); + puts(""); + } + } +} diff --git a/examples/bits2.c b/examples/bits2.c index af87df42..4b16ad76 100644 --- a/examples/bits2.c +++ b/examples/bits2.c @@ -1,43 +1,43 @@ -#include <stdio.h>
-// Example of static sized (stack allocated) bitsets
-
-#define i_type Bits
-#define i_len 80 // enable fixed bitset on the stack
-#define i_implement
-#include <stc/cbits.h>
-
-int main()
-{
- Bits s1 = Bits_from("1110100110111");
-
- printf("size %" PRIuMAX "\n", Bits_size(&s1));
- char buf[256];
- Bits_to_str(&s1, buf, 0, -1);
- printf("buf: %s: count=%" PRIuMAX "\n", buf, Bits_count(&s1));
-
- Bits_reset(&s1, 8);
- c_autobuf (str, char, Bits_size(&s1) + 1)
- printf(" s1: %s\n", Bits_to_str(&s1, str, 0, -1));
-
- Bits s2 = Bits_clone(s1);
-
- Bits_flip_all(&s2);
- Bits_reset(&s2, 66);
- Bits_reset(&s2, 67);
- printf(" s2: ");
- c_forrange (i, Bits_size(&s2))
- printf("%d", Bits_test(&s2, i));
- puts("");
-
- printf("xor: ");
- Bits_xor(&s1, &s2);
- c_forrange (i, Bits_size(&s1))
- printf("%d", Bits_test(&s1, i));
- puts("");
-
- printf("all: ");
- Bits_set_pattern(&s1, 0x3333333333333333);
- c_forrange (i, Bits_size(&s1))
- printf("%d", Bits_test(&s1, i));
- puts("");
-}
+#include <stdio.h> +// Example of static sized (stack allocated) bitsets + +#define i_type Bits +#define i_len 80 // enable fixed bitset on the stack +#define i_implement +#include <stc/cbits.h> + +int main() +{ + Bits s1 = Bits_from("1110100110111"); + + printf("size %" PRIuMAX "\n", Bits_size(&s1)); + char buf[256]; + Bits_to_str(&s1, buf, 0, -1); + printf("buf: %s: count=%" PRIuMAX "\n", buf, Bits_count(&s1)); + + Bits_reset(&s1, 8); + c_autobuf (str, char, Bits_size(&s1) + 1) + printf(" s1: %s\n", Bits_to_str(&s1, str, 0, -1)); + + Bits s2 = Bits_clone(s1); + + Bits_flip_all(&s2); + Bits_reset(&s2, 66); + Bits_reset(&s2, 67); + printf(" s2: "); + c_forrange (i, Bits_size(&s2)) + printf("%d", Bits_test(&s2, i)); + puts(""); + + printf("xor: "); + Bits_xor(&s1, &s2); + c_forrange (i, Bits_size(&s1)) + printf("%d", Bits_test(&s1, i)); + puts(""); + + printf("all: "); + Bits_set_pattern(&s1, 0x3333333333333333); + c_forrange (i, Bits_size(&s1)) + printf("%d", Bits_test(&s1, i)); + puts(""); +} diff --git a/examples/books.c b/examples/books.c index de724a19..5677ff3a 100644 --- a/examples/books.c +++ b/examples/books.c @@ -1,61 +1,61 @@ -// https://doc.rust-lang.org/std/collections/struct.HashMap.html
-#define i_implement
-#include <stc/cstr.h>
-#define i_key_str
-#define i_val_str
-#include <stc/cmap.h>
-
-// Type inference lets us omit an explicit type signature (which
-// would be `HashMap<String, String>` in this example).
-int main()
-{
- c_auto (cmap_str, book_reviews)
- {
- // Review some books.
- cmap_str_emplace(&book_reviews,
- "Adventures of Huckleberry Finn",
- "My favorite book."
- );
- cmap_str_emplace(&book_reviews,
- "Grimms' Fairy Tales",
- "Masterpiece."
- );
- cmap_str_emplace(&book_reviews,
- "Pride and Prejudice",
- "Very enjoyable"
- );
- cmap_str_insert(&book_reviews,
- cstr_new("The Adventures of Sherlock Holmes"),
- cstr_new("Eye lyked it alot.")
- );
-
- // Check for a specific one.
- // When collections store owned values (String), they can still be
- // queried using references (&str).
- if (cmap_str_contains(&book_reviews, "Les Misérables")) {
- printf("We've got %" PRIuMAX " reviews, but Les Misérables ain't one.",
- cmap_str_size(book_reviews));
- }
-
- // oops, this review has a lot of spelling mistakes, let's delete it.
- cmap_str_erase(&book_reviews, "The Adventures of Sherlock Holmes");
-
- // Look up the values associated with some keys.
- const char* to_find[] = {"Pride and Prejudice", "Alice's Adventure in Wonderland"};
- c_forrange (i, c_arraylen(to_find)) {
- const cmap_str_value* b;
- if ((b = cmap_str_get(&book_reviews, to_find[i])))
- printf("%s: %s\n", cstr_str(&b->first), cstr_str(&b->second));
- else
- printf("%s is unreviewed.\n", to_find[i]);
- }
-
- // Look up the value for a key (will panic if the key is not found).
- printf("Review for Jane: %s\n", cstr_str(cmap_str_at(&book_reviews, "Pride and Prejudice")));
-
- // Iterate over everything.
- c_forpair (book, review, cmap_str, book_reviews) {
- printf("%s: \"%s\"\n", cstr_str(_.book), cstr_str(_.review));
- }
- }
-}
+// https://doc.rust-lang.org/std/collections/struct.HashMap.html +#define i_implement +#include <stc/cstr.h> +#define i_key_str +#define i_val_str +#include <stc/cmap.h> + +// Type inference lets us omit an explicit type signature (which +// would be `HashMap<String, String>` in this example). +int main() +{ + c_auto (cmap_str, book_reviews) + { + // Review some books. + cmap_str_emplace(&book_reviews, + "Adventures of Huckleberry Finn", + "My favorite book." + ); + cmap_str_emplace(&book_reviews, + "Grimms' Fairy Tales", + "Masterpiece." + ); + cmap_str_emplace(&book_reviews, + "Pride and Prejudice", + "Very enjoyable" + ); + cmap_str_insert(&book_reviews, + cstr_new("The Adventures of Sherlock Holmes"), + cstr_new("Eye lyked it alot.") + ); + + // Check for a specific one. + // When collections store owned values (String), they can still be + // queried using references (&str). + if (cmap_str_contains(&book_reviews, "Les Misérables")) { + printf("We've got %" PRIuMAX " reviews, but Les Misérables ain't one.", + cmap_str_size(book_reviews)); + } + + // oops, this review has a lot of spelling mistakes, let's delete it. + cmap_str_erase(&book_reviews, "The Adventures of Sherlock Holmes"); + + // Look up the values associated with some keys. + const char* to_find[] = {"Pride and Prejudice", "Alice's Adventure in Wonderland"}; + c_forrange (i, c_arraylen(to_find)) { + const cmap_str_value* b; + if ((b = cmap_str_get(&book_reviews, to_find[i]))) + printf("%s: %s\n", cstr_str(&b->first), cstr_str(&b->second)); + else + printf("%s is unreviewed.\n", to_find[i]); + } + + // Look up the value for a key (will panic if the key is not found). + printf("Review for Jane: %s\n", cstr_str(cmap_str_at(&book_reviews, "Pride and Prejudice"))); + + // Iterate over everything. + c_forpair (book, review, cmap_str, book_reviews) { + printf("%s: \"%s\"\n", cstr_str(_.book), cstr_str(_.review)); + } + } +} diff --git a/examples/box.c b/examples/box.c index 4502f479..7a984a21 100644 --- a/examples/box.c +++ b/examples/box.c @@ -1,75 +1,75 @@ -/* cbox: heap allocated boxed type */
-#define i_implement
-#include <stc/cstr.h>
-
-typedef struct { cstr name, last; } Person;
-
-Person Person_new(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
-}
-
-uint64_t Person_hash(const Person* a) {
- return cstr_hash(&a->name) ^ cstr_hash(&a->last);
-}
-
-int Person_cmp(const Person* a, const Person* b) {
- int c = cstr_cmp(&a->name, &b->name);
- return c ? c : cstr_cmp(&a->last, &b->last);
-}
-
-Person Person_clone(Person p) {
- p.name = cstr_clone(p.name);
- p.last = cstr_clone(p.last);
- return p;
-}
-
-void Person_drop(Person* p) {
- printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
- c_drop(cstr, &p->name, &p->last);
-}
-
-#define i_type PBox
-#define i_val_bind Person // binds Person_cmp, ...
-#include <stc/cbox.h>
-
-#define i_type Persons
-#define i_val_arcbox PBox // informs that PBox is a smart pointer.
-#include <stc/cvec.h>
-
-int main()
-{
- c_auto (Persons, vec)
- c_auto (PBox, p, q)
- {
- p = PBox_make(Person_new("Laura", "Palmer"));
-
- q = PBox_clone(p);
- cstr_assign(&q.get->name, "Leland");
-
- printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last));
- printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last));
-
- Persons_push_back(&vec, PBox_make(Person_new("Dale", "Cooper")));
- Persons_push_back(&vec, PBox_make(Person_new("Audrey", "Home")));
-
- // NB! Clone p and q to the vector using emplace_back()
- c_apply(v, Persons_push_back(&vec, PBox_clone(*v)), PBox, {p, q});
-
- c_foreach (i, Persons, vec)
- printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last));
- puts("");
-
- // Look-up Audrey! Use a (fake) temporary PBox for lookup.
- c_autovar (Person a = Person_new("Audrey", "Home"), Person_drop(&a)) {
- const PBox *v = Persons_get(&vec, a);
- if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last));
- }
- puts("");
-
- // Alternative to use cbox (when not placed in container).
- Person *she = c_new(Person, Person_new("Shelly", "Johnson"));
- printf("%s %s\n", cstr_str(&she->name), cstr_str(&she->last));
- c_delete(Person, she); // drop and free
- puts("");
- }
-}
+/* cbox: heap allocated boxed type */ +#define i_implement +#include <stc/cstr.h> + +typedef struct { cstr name, last; } Person; + +Person Person_new(const char* name, const char* last) { + return (Person){.name = cstr_from(name), .last = cstr_from(last)}; +} + +uint64_t Person_hash(const Person* a) { + return cstr_hash(&a->name) ^ cstr_hash(&a->last); +} + +int Person_cmp(const Person* a, const Person* b) { + int c = cstr_cmp(&a->name, &b->name); + return c ? c : cstr_cmp(&a->last, &b->last); +} + +Person Person_clone(Person p) { + p.name = cstr_clone(p.name); + p.last = cstr_clone(p.last); + return p; +} + +void Person_drop(Person* p) { + printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); + c_drop(cstr, &p->name, &p->last); +} + +#define i_type PBox +#define i_val_bind Person // binds Person_cmp, ... +#include <stc/cbox.h> + +#define i_type Persons +#define i_val_arcbox PBox // informs that PBox is a smart pointer. +#include <stc/cvec.h> + +int main() +{ + c_auto (Persons, vec) + c_auto (PBox, p, q) + { + p = PBox_make(Person_new("Laura", "Palmer")); + + q = PBox_clone(p); + cstr_assign(&q.get->name, "Leland"); + + printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last)); + printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last)); + + Persons_push_back(&vec, PBox_make(Person_new("Dale", "Cooper"))); + Persons_push_back(&vec, PBox_make(Person_new("Audrey", "Home"))); + + // NB! Clone p and q to the vector using emplace_back() + c_apply(v, Persons_push_back(&vec, PBox_clone(*v)), PBox, {p, q}); + + c_foreach (i, Persons, vec) + printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last)); + puts(""); + + // Look-up Audrey! Use a (fake) temporary PBox for lookup. + c_autovar (Person a = Person_new("Audrey", "Home"), Person_drop(&a)) { + const PBox *v = Persons_get(&vec, a); + if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last)); + } + puts(""); + + // Alternative to use cbox (when not placed in container). + Person *she = c_new(Person, Person_new("Shelly", "Johnson")); + printf("%s %s\n", cstr_str(&she->name), cstr_str(&she->last)); + c_delete(Person, she); // drop and free + puts(""); + } +} diff --git a/examples/box2.c b/examples/box2.c index 2d1b82fc..c44802d3 100644 --- a/examples/box2.c +++ b/examples/box2.c @@ -1,88 +1,88 @@ -// https://doc.rust-lang.org/rust-by-example/std/box.html
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stc/ccommon.h>
-
-struct {
- double x;
- double y;
-} typedef Point;
-
-// A Rectangle can be specified by where its top left and bottom right
-// corners are in space
-struct {
- Point top_left;
- Point bottom_right;
-} typedef Rectangle;
-
-#define i_val Point
-#define i_opt c_no_cmp
-#include <stc/cbox.h> // cbox_Point
-
-#define i_val Rectangle
-#define i_opt c_no_cmp
-#include <stc/cbox.h> // cbox_Rectangle
-
-// Box in box:
-#define i_val_arcbox cbox_Point // NB: use i_val_arcbox when value is a cbox or carc!
- // it will auto-set i_valdrop, i_valfrom, i_cmp for you.
-#define i_opt c_no_cmp
-#define i_tag BoxPoint
-#include <stc/cbox.h> // cbox_BoxPoint
-
-Point origin(void) {
- return (Point){ .x=0.0, .y=0.0 };
-}
-
-cbox_Point boxed_origin(void) {
- // Allocate this point on the heap, and return a pointer to it
- return cbox_Point_make((Point){ .x=0.0, .y=0.0 });
-}
-
-
-int main(void) {
- // (all the type annotations are superfluous)
- // Stack allocated variables
- Point point = origin();
- Rectangle rectangle = (Rectangle){
- .top_left = origin(),
- .bottom_right = (Point){ .x=3.0, .y=-4.0 }
- };
-
- // Heap allocated rectangle
- c_auto (cbox_Rectangle, boxed_rectangle)
- c_auto (cbox_Point, boxed_point)
- c_auto (cbox_BoxPoint, box_in_a_box)
- {
- boxed_rectangle = cbox_Rectangle_make((Rectangle){
- .top_left = origin(),
- .bottom_right = (Point){ .x=3.0, .y=-4.0 }
- });
-
- // The output of functions can be boxed
- boxed_point = cbox_Point_make(origin());
-
- // Double indirection
- box_in_a_box = cbox_BoxPoint_make(boxed_origin());
-
- printf("Point occupies %" PRIuMAX " bytes on the stack\n",
- sizeof(point));
- printf("Rectangle occupies %" PRIuMAX " bytes on the stack\n",
- sizeof(rectangle));
-
- // box size == pointer size
- printf("Boxed point occupies %" PRIuMAX " bytes on the stack\n",
- sizeof(boxed_point));
- printf("Boxed rectangle occupies %" PRIuMAX " bytes on the stack\n",
- sizeof(boxed_rectangle));
- printf("Boxed box occupies %" PRIuMAX " bytes on the stack\n",
- sizeof(box_in_a_box));
-
- // Copy the data contained in `boxed_point` into `unboxed_point`
- Point unboxed_point = *boxed_point.get;
- printf("Unboxed point occupies %" PRIuMAX " bytes on the stack\n",
- sizeof(unboxed_point));
- }
-}
+// https://doc.rust-lang.org/rust-by-example/std/box.html + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stc/ccommon.h> + +struct { + double x; + double y; +} typedef Point; + +// A Rectangle can be specified by where its top left and bottom right +// corners are in space +struct { + Point top_left; + Point bottom_right; +} typedef Rectangle; + +#define i_val Point +#define i_opt c_no_cmp +#include <stc/cbox.h> // cbox_Point + +#define i_val Rectangle +#define i_opt c_no_cmp +#include <stc/cbox.h> // cbox_Rectangle + +// Box in box: +#define i_val_arcbox cbox_Point // NB: use i_val_arcbox when value is a cbox or carc! + // it will auto-set i_valdrop, i_valfrom, i_cmp for you. +#define i_opt c_no_cmp +#define i_tag BoxPoint +#include <stc/cbox.h> // cbox_BoxPoint + +Point origin(void) { + return (Point){ .x=0.0, .y=0.0 }; +} + +cbox_Point boxed_origin(void) { + // Allocate this point on the heap, and return a pointer to it + return cbox_Point_make((Point){ .x=0.0, .y=0.0 }); +} + + +int main(void) { + // (all the type annotations are superfluous) + // Stack allocated variables + Point point = origin(); + Rectangle rectangle = (Rectangle){ + .top_left = origin(), + .bottom_right = (Point){ .x=3.0, .y=-4.0 } + }; + + // Heap allocated rectangle + c_auto (cbox_Rectangle, boxed_rectangle) + c_auto (cbox_Point, boxed_point) + c_auto (cbox_BoxPoint, box_in_a_box) + { + boxed_rectangle = cbox_Rectangle_make((Rectangle){ + .top_left = origin(), + .bottom_right = (Point){ .x=3.0, .y=-4.0 } + }); + + // The output of functions can be boxed + boxed_point = cbox_Point_make(origin()); + + // Double indirection + box_in_a_box = cbox_BoxPoint_make(boxed_origin()); + + printf("Point occupies %" PRIuMAX " bytes on the stack\n", + sizeof(point)); + printf("Rectangle occupies %" PRIuMAX " bytes on the stack\n", + sizeof(rectangle)); + + // box size == pointer size + printf("Boxed point occupies %" PRIuMAX " bytes on the stack\n", + sizeof(boxed_point)); + printf("Boxed rectangle occupies %" PRIuMAX " bytes on the stack\n", + sizeof(boxed_rectangle)); + printf("Boxed box occupies %" PRIuMAX " bytes on the stack\n", + sizeof(box_in_a_box)); + + // Copy the data contained in `boxed_point` into `unboxed_point` + Point unboxed_point = *boxed_point.get; + printf("Unboxed point occupies %" PRIuMAX " bytes on the stack\n", + sizeof(unboxed_point)); + } +} diff --git a/examples/city.c b/examples/city.c index 8ee1576f..c359ebdf 100644 --- a/examples/city.c +++ b/examples/city.c @@ -1,83 +1,83 @@ -#define i_implement
-#include <stc/cstr.h>
-
-typedef struct {
- cstr name;
- cstr country;
- float lat, lon;
- int population;
-} City;
-
-static inline int City_cmp(const City* a, const City* b) {
- int c = cstr_cmp(&a->name, &b->name);
- return c ? c : cstr_cmp(&a->country, &b->country);
-}
-
-static inline uint64_t City_hash(const City* a) {
- printf("hash %s\n", cstr_str(&a->name));
- return cstr_hash(&a->name) ^ cstr_hash(&a->country);
-}
-
-static inline City City_clone(City c) {
- printf("clone %s\n", cstr_str(&c.name));
- c.name = cstr_clone(c.name);
- c.country = cstr_clone(c.country);
- return c;
-}
-
-static inline void City_drop(City* c) {
- printf("drop %s\n", cstr_str(&c->name));
- c_drop(cstr, &c->name, &c->country);
-}
-
-
-#define i_type CityArc
-#define i_key_bind City
-#include <stc/cbox.h>
-//#include <stc/carc.h> // try instead of cbox.h
-
-#define i_type Cities
-#define i_key_arcbox CityArc
-#include <stc/cvec.h>
-
-#define i_type CityMap
-#define i_key int
-#define i_val_arcbox CityArc
-#include <stc/csmap.h>
-
-
-int main(void)
-{
- c_auto (Cities, cities, copy)
- c_auto (CityMap, map)
- {
- struct City_s { const char *name, *country; float lat, lon; int pop; };
-
- c_apply(c, Cities_push(&cities, CityArc_make((City){cstr_from(c->name), cstr_from(c->country),
- c->lat, c->lon, c->pop})), struct City_s, {
- {"New York", "US", 4.3, 23.2, 9000000},
- {"Paris", "France", 4.3, 23.2, 9000000},
- {"Berlin", "Germany", 4.3, 23.2, 9000000},
- {"London", "UK", 4.3, 23.2, 9000000},
- });
-
- copy = Cities_clone(cities); // share each element!
-
- int k = 0, id[] = {8, 4, 3, 9, 2, 5};
- c_foreach (i, Cities, cities)
- CityMap_insert(&map, id[k++], CityArc_clone(*i.ref));
-
- Cities_pop(&cities);
- Cities_pop(&cities);
-
- printf("Vec:\n");
- c_foreach (c, Cities, cities)
- printf("city:%s, %d, use:%ld\n", cstr_str(&c.ref->get->name), c.ref->get->population, CityArc_use_count(*c.ref));
-
- printf("\nMap:\n");
- c_forpair (id, city, CityMap, map)
- printf("id:%d, city:%s, %d, use:%ld\n", *_.id, cstr_str(&_.city->get->name),
- _.city->get->population, CityArc_use_count(*_.city));
- puts("");
- }
-}
+#define i_implement +#include <stc/cstr.h> + +typedef struct { + cstr name; + cstr country; + float lat, lon; + int population; +} City; + +static inline int City_cmp(const City* a, const City* b) { + int c = cstr_cmp(&a->name, &b->name); + return c ? c : cstr_cmp(&a->country, &b->country); +} + +static inline uint64_t City_hash(const City* a) { + printf("hash %s\n", cstr_str(&a->name)); + return cstr_hash(&a->name) ^ cstr_hash(&a->country); +} + +static inline City City_clone(City c) { + printf("clone %s\n", cstr_str(&c.name)); + c.name = cstr_clone(c.name); + c.country = cstr_clone(c.country); + return c; +} + +static inline void City_drop(City* c) { + printf("drop %s\n", cstr_str(&c->name)); + c_drop(cstr, &c->name, &c->country); +} + + +#define i_type CityArc +#define i_key_bind City +#include <stc/cbox.h> +//#include <stc/carc.h> // try instead of cbox.h + +#define i_type Cities +#define i_key_arcbox CityArc +#include <stc/cvec.h> + +#define i_type CityMap +#define i_key int +#define i_val_arcbox CityArc +#include <stc/csmap.h> + + +int main(void) +{ + c_auto (Cities, cities, copy) + c_auto (CityMap, map) + { + struct City_s { const char *name, *country; float lat, lon; int pop; }; + + c_apply(c, Cities_push(&cities, CityArc_make((City){cstr_from(c->name), cstr_from(c->country), + c->lat, c->lon, c->pop})), struct City_s, { + {"New York", "US", 4.3, 23.2, 9000000}, + {"Paris", "France", 4.3, 23.2, 9000000}, + {"Berlin", "Germany", 4.3, 23.2, 9000000}, + {"London", "UK", 4.3, 23.2, 9000000}, + }); + + copy = Cities_clone(cities); // share each element! + + int k = 0, id[] = {8, 4, 3, 9, 2, 5}; + c_foreach (i, Cities, cities) + CityMap_insert(&map, id[k++], CityArc_clone(*i.ref)); + + Cities_pop(&cities); + Cities_pop(&cities); + + printf("Vec:\n"); + c_foreach (c, Cities, cities) + printf("city:%s, %d, use:%ld\n", cstr_str(&c.ref->get->name), c.ref->get->population, CityArc_use_count(*c.ref)); + + printf("\nMap:\n"); + c_forpair (id, city, CityMap, map) + printf("id:%d, city:%s, %d, use:%ld\n", *_.id, cstr_str(&_.city->get->name), + _.city->get->population, CityArc_use_count(*_.city)); + puts(""); + } +} diff --git a/examples/complex.c b/examples/complex.c index c5ac9882..8db85bbd 100644 --- a/examples/complex.c +++ b/examples/complex.c @@ -1,63 +1,63 @@ -#define i_implement
-#include <stc/cstr.h>
-
-void check_drop(float* v) {printf("destroy %g\n", *v);}
-
-#define i_type FloatStack
-#define i_val float
-#define i_valdrop check_drop
-#define i_valclone(x) x // required to allow cloning when i_valdrop is defined
- // (not for carc as it does not use i_valclone to clone).
-#include <stc/cstack.h>
-
-#define i_type StackList
-#define i_val_bind FloatStack
-#define i_opt c_no_cmp
-#include <stc/clist.h>
-
-#define i_type ListMap
-#define i_key int
-#define i_val_bind StackList
-#include <stc/cmap.h>
-
-#define i_type MapMap
-#define i_key_str
-#define i_val_bind ListMap
-#include <stc/cmap.h>
-
-// c++:
-// using FloatStack = std::stack<float>;
-// using map_lst = std::unordered_map<int, std::forward_list<array2f>>;
-// using map_map = std::unordered_map<std::string, map_lst>;
-
-int main() {
- int xdim = 4, ydim = 6;
- int x = 1, tableKey = 42;
- const char* strKey = "first";
-
- c_auto (MapMap, mmap)
- {
- FloatStack stack = FloatStack_with_capacity(xdim * ydim);
- memset(stack.data, 0, xdim*ydim*sizeof *stack.data);
- stack.size = stack.capacity;
-
- // Put in some data in stack array
- stack.data[x] = 3.1415927f;
- printf("stack size: %" PRIuMAX "\n", FloatStack_size(stack));
-
- StackList list = StackList_init();
- StackList_push_back(&list, stack);
-
- ListMap lmap = ListMap_init();
- ListMap_insert(&lmap, tableKey, list);
- MapMap_insert(&mmap, cstr_from(strKey), lmap);
-
- // Access the data entry
- const ListMap* lmap_p = MapMap_at(&mmap, strKey);
- const StackList* list_p = ListMap_at(lmap_p, tableKey);
- const FloatStack* stack_p = StackList_back(list_p);
- printf("value (%d) is: %f\n", x, *FloatStack_at(stack_p, x));
-
- stack.data[x] = 1.41421356f; // change the value in array
- }
-}
+#define i_implement +#include <stc/cstr.h> + +void check_drop(float* v) {printf("destroy %g\n", *v);} + +#define i_type FloatStack +#define i_val float +#define i_valdrop check_drop +#define i_valclone(x) x // required to allow cloning when i_valdrop is defined + // (not for carc as it does not use i_valclone to clone). +#include <stc/cstack.h> + +#define i_type StackList +#define i_val_bind FloatStack +#define i_opt c_no_cmp +#include <stc/clist.h> + +#define i_type ListMap +#define i_key int +#define i_val_bind StackList +#include <stc/cmap.h> + +#define i_type MapMap +#define i_key_str +#define i_val_bind ListMap +#include <stc/cmap.h> + +// c++: +// using FloatStack = std::stack<float>; +// using map_lst = std::unordered_map<int, std::forward_list<array2f>>; +// using map_map = std::unordered_map<std::string, map_lst>; + +int main() { + int xdim = 4, ydim = 6; + int x = 1, tableKey = 42; + const char* strKey = "first"; + + c_auto (MapMap, mmap) + { + FloatStack stack = FloatStack_with_capacity(xdim * ydim); + memset(stack.data, 0, xdim*ydim*sizeof *stack.data); + stack.size = stack.capacity; + + // Put in some data in stack array + stack.data[x] = 3.1415927f; + printf("stack size: %" PRIuMAX "\n", FloatStack_size(stack)); + + StackList list = StackList_init(); + StackList_push_back(&list, stack); + + ListMap lmap = ListMap_init(); + ListMap_insert(&lmap, tableKey, list); + MapMap_insert(&mmap, cstr_from(strKey), lmap); + + // Access the data entry + const ListMap* lmap_p = MapMap_at(&mmap, strKey); + const StackList* list_p = ListMap_at(lmap_p, tableKey); + const FloatStack* stack_p = StackList_back(list_p); + printf("value (%d) is: %f\n", x, *FloatStack_at(stack_p, x)); + + stack.data[x] = 1.41421356f; // change the value in array + } +} diff --git a/examples/csmap_insert.c b/examples/csmap_insert.c index 24f536e9..3d235877 100644 --- a/examples/csmap_insert.c +++ b/examples/csmap_insert.c @@ -1,112 +1,112 @@ -#define i_implement
-#include <stc/cstr.h>
-
-// This implements the std::map insert c++ example at:
-// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-19
-
-#define i_key int
-#define i_val int
-#define i_tag ii // Map of int => int
-#include <stc/csmap.h>
-
-#define i_key int
-#define i_val_str
-#define i_tag istr // Map of int => cstr
-#include <stc/csmap.h>
-
-#define i_val csmap_ii_raw
-#define i_opt c_no_cmp
-#define i_tag ii
-#include <stc/cvec.h>
-
-void print_ii(csmap_ii map) {
- c_foreach (e, csmap_ii, map)
- printf("(%d, %d) ", e.ref->first, e.ref->second);
- puts("");
-}
-
-void print_istr(csmap_istr map) {
- c_foreach (e, csmap_istr, map)
- printf("(%d, %s) ", e.ref->first, cstr_str(&e.ref->second));
- puts("");
-}
-
-int main()
-{
- // insert single values
- c_auto (csmap_ii, m1) {
- csmap_ii_insert(&m1, 1, 10);
- csmap_ii_insert(&m1, 2, 20);
-
- puts("The original key and mapped values of m1 are:");
- print_ii(m1);
-
- // intentionally attempt a duplicate, single element
- csmap_ii_result ret = csmap_ii_insert(&m1, 1, 111);
- if (!ret.inserted) {
- csmap_ii_value pr = *ret.ref;
- puts("Insert failed, element with key value 1 already exists.");
- printf(" The existing element is (%d, %d)\n", pr.first, pr.second);
- }
- else {
- puts("The modified key and mapped values of m1 are:");
- print_ii(m1);
- }
- puts("");
-
- csmap_ii_insert(&m1, 3, 30);
- puts("The modified key and mapped values of m1 are:");
- print_ii(m1);
- puts("");
- }
-
- // The templatized version inserting a jumbled range
- c_auto (csmap_ii, m2)
- c_auto (cvec_ii, v) {
- typedef cvec_ii_value ipair;
- cvec_ii_push_back(&v, (ipair){43, 294});
- cvec_ii_push_back(&v, (ipair){41, 262});
- cvec_ii_push_back(&v, (ipair){45, 330});
- cvec_ii_push_back(&v, (ipair){42, 277});
- cvec_ii_push_back(&v, (ipair){44, 311});
-
- puts("Inserting the following vector data into m2:");
- c_foreach (e, cvec_ii, v)
- printf("(%d, %d) ", e.ref->first, e.ref->second);
- puts("");
-
- c_foreach (e, cvec_ii, v)
- csmap_ii_insert_or_assign(&m2, e.ref->first, e.ref->second);
-
- puts("The modified key and mapped values of m2 are:");
- c_foreach (e, csmap_ii, m2)
- printf("(%d, %d) ", e.ref->first, e.ref->second);
- puts("\n");
- }
-
- // The templatized versions move-constructing elements
- c_auto (csmap_istr, m3) {
- csmap_istr_value ip1 = {475, cstr_new("blue")}, ip2 = {510, cstr_new("green")};
-
- // single element
- csmap_istr_insert(&m3, ip1.first, cstr_move(&ip1.second));
- puts("After the first move insertion, m3 contains:");
- print_istr(m3);
-
- // single element
- csmap_istr_insert(&m3, ip2.first, cstr_move(&ip2.second));
- puts("After the second move insertion, m3 contains:");
- print_istr(m3);
- puts("");
- }
-
- c_auto (csmap_ii, m4) {
- // Insert the elements from an initializer_list
- c_apply(v, csmap_ii_insert(&m4, c_pair(v)), csmap_ii_raw, {
- { 4, 44 }, { 2, 22 }, { 3, 33 }, { 1, 11 }, { 5, 55 }
- });
- puts("After initializer_list insertion, m4 contains:");
- print_ii(m4);
- puts("");
- }
-}
+#define i_implement +#include <stc/cstr.h> + +// This implements the std::map insert c++ example at: +// https://docs.microsoft.com/en-us/cpp/standard-library/map-class?view=msvc-160#example-19 + +#define i_key int +#define i_val int +#define i_tag ii // Map of int => int +#include <stc/csmap.h> + +#define i_key int +#define i_val_str +#define i_tag istr // Map of int => cstr +#include <stc/csmap.h> + +#define i_val csmap_ii_raw +#define i_opt c_no_cmp +#define i_tag ii +#include <stc/cvec.h> + +void print_ii(csmap_ii map) { + c_foreach (e, csmap_ii, map) + printf("(%d, %d) ", e.ref->first, e.ref->second); + puts(""); +} + +void print_istr(csmap_istr map) { + c_foreach (e, csmap_istr, map) + printf("(%d, %s) ", e.ref->first, cstr_str(&e.ref->second)); + puts(""); +} + +int main() +{ + // insert single values + c_auto (csmap_ii, m1) { + csmap_ii_insert(&m1, 1, 10); + csmap_ii_insert(&m1, 2, 20); + + puts("The original key and mapped values of m1 are:"); + print_ii(m1); + + // intentionally attempt a duplicate, single element + csmap_ii_result ret = csmap_ii_insert(&m1, 1, 111); + if (!ret.inserted) { + csmap_ii_value pr = *ret.ref; + puts("Insert failed, element with key value 1 already exists."); + printf(" The existing element is (%d, %d)\n", pr.first, pr.second); + } + else { + puts("The modified key and mapped values of m1 are:"); + print_ii(m1); + } + puts(""); + + csmap_ii_insert(&m1, 3, 30); + puts("The modified key and mapped values of m1 are:"); + print_ii(m1); + puts(""); + } + + // The templatized version inserting a jumbled range + c_auto (csmap_ii, m2) + c_auto (cvec_ii, v) { + typedef cvec_ii_value ipair; + cvec_ii_push_back(&v, (ipair){43, 294}); + cvec_ii_push_back(&v, (ipair){41, 262}); + cvec_ii_push_back(&v, (ipair){45, 330}); + cvec_ii_push_back(&v, (ipair){42, 277}); + cvec_ii_push_back(&v, (ipair){44, 311}); + + puts("Inserting the following vector data into m2:"); + c_foreach (e, cvec_ii, v) + printf("(%d, %d) ", e.ref->first, e.ref->second); + puts(""); + + c_foreach (e, cvec_ii, v) + csmap_ii_insert_or_assign(&m2, e.ref->first, e.ref->second); + + puts("The modified key and mapped values of m2 are:"); + c_foreach (e, csmap_ii, m2) + printf("(%d, %d) ", e.ref->first, e.ref->second); + puts("\n"); + } + + // The templatized versions move-constructing elements + c_auto (csmap_istr, m3) { + csmap_istr_value ip1 = {475, cstr_new("blue")}, ip2 = {510, cstr_new("green")}; + + // single element + csmap_istr_insert(&m3, ip1.first, cstr_move(&ip1.second)); + puts("After the first move insertion, m3 contains:"); + print_istr(m3); + + // single element + csmap_istr_insert(&m3, ip2.first, cstr_move(&ip2.second)); + puts("After the second move insertion, m3 contains:"); + print_istr(m3); + puts(""); + } + + c_auto (csmap_ii, m4) { + // Insert the elements from an initializer_list + c_apply(v, csmap_ii_insert(&m4, c_pair(v)), csmap_ii_raw, { + { 4, 44 }, { 2, 22 }, { 3, 33 }, { 1, 11 }, { 5, 55 } + }); + puts("After initializer_list insertion, m4 contains:"); + print_ii(m4); + puts(""); + } +} diff --git a/examples/csset_erase.c b/examples/csset_erase.c index 3cfaa7f1..7c8c1d97 100644 --- a/examples/csset_erase.c +++ b/examples/csset_erase.c @@ -1,42 +1,42 @@ -#include <stdio.h>
-
-#define i_key int
-#include <stc/csset.h>
-
-int main()
-{
- c_auto (csset_int, set)
- {
- c_apply(v, csset_int_insert(&set, *v),
- int, {30, 20, 80, 40, 60, 90, 10, 70, 50});
- c_foreach (k, csset_int, set)
- printf(" %d", *k.ref);
- puts("");
-
- int val = 64;
- csset_int_iter it;
- printf("Show values >= %d:\n", val);
- it = csset_int_lower_bound(&set, val);
-
- c_foreach (k, csset_int, it, csset_int_end(&set))
- printf(" %d", *k.ref);
- puts("");
-
- printf("Erase values >= %d:\n", val);
- while (it.ref != csset_int_end(&set).ref)
- it = csset_int_erase_at(&set, it);
-
- c_foreach (k, csset_int, set)
- printf(" %d", *k.ref);
- puts("");
-
- val = 40;
- printf("Erase values < %d:\n", val);
- it = csset_int_lower_bound(&set, val);
- csset_int_erase_range(&set, csset_int_begin(&set), it);
-
- c_foreach (k, csset_int, set)
- printf(" %d", *k.ref);
- puts("");
- }
-}
+#include <stdio.h> + +#define i_key int +#include <stc/csset.h> + +int main() +{ + c_auto (csset_int, set) + { + c_apply(v, csset_int_insert(&set, *v), + int, {30, 20, 80, 40, 60, 90, 10, 70, 50}); + c_foreach (k, csset_int, set) + printf(" %d", *k.ref); + puts(""); + + int val = 64; + csset_int_iter it; + printf("Show values >= %d:\n", val); + it = csset_int_lower_bound(&set, val); + + c_foreach (k, csset_int, it, csset_int_end(&set)) + printf(" %d", *k.ref); + puts(""); + + printf("Erase values >= %d:\n", val); + while (it.ref != csset_int_end(&set).ref) + it = csset_int_erase_at(&set, it); + + c_foreach (k, csset_int, set) + printf(" %d", *k.ref); + puts(""); + + val = 40; + printf("Erase values < %d:\n", val); + it = csset_int_lower_bound(&set, val); + csset_int_erase_range(&set, csset_int_begin(&set), it); + + c_foreach (k, csset_int, set) + printf(" %d", *k.ref); + puts(""); + } +} diff --git a/examples/cstr_match.c b/examples/cstr_match.c index a110e49a..69c12ef2 100644 --- a/examples/cstr_match.c +++ b/examples/cstr_match.c @@ -1,23 +1,23 @@ -#define i_implement
-#include <stc/cstr.h>
-#include <stc/csview.h>
-#include <stdio.h>
-
-int main()
-{
- c_autovar (cstr ss = cstr_new("The quick brown fox jumps over the lazy dog.JPG"), cstr_drop(&ss)) {
- size_t pos = cstr_find_from(ss, 0, "brown");
- printf("%" PRIuMAX " [%s]\n", pos, pos == cstr_npos ? "<NULL>" : cstr_str(&ss) + pos);
- printf("equals: %d\n", cstr_equals(ss, "The quick brown fox jumps over the lazy dog.JPG"));
- printf("contains: %d\n", cstr_contains(ss, "umps ove"));
- printf("starts_with: %d\n", cstr_starts_with(ss, "The quick brown"));
- printf("ends_with: %d\n", cstr_ends_with(ss, ".jpg"));
- printf("ends_with: %d\n", cstr_ends_with(ss, ".JPG"));
-
- cstr s1 = cstr_new("hell😀 w😀rl🐨");
- csview ch1 = cstr_at(&s1, 10);
- csview ch2 = cstr_at_u8(&s1, 10);
- printf("ch1: %" c_PRIsv "\n", c_ARGsv(ch1));
- printf("ch2: %" c_PRIsv "\n", c_ARGsv(ch2));
- }
-}
+#define i_implement +#include <stc/cstr.h> +#include <stc/csview.h> +#include <stdio.h> + +int main() +{ + c_autovar (cstr ss = cstr_new("The quick brown fox jumps over the lazy dog.JPG"), cstr_drop(&ss)) { + size_t pos = cstr_find_from(ss, 0, "brown"); + printf("%" PRIuMAX " [%s]\n", pos, pos == cstr_npos ? "<NULL>" : cstr_str(&ss) + pos); + printf("equals: %d\n", cstr_equals(ss, "The quick brown fox jumps over the lazy dog.JPG")); + printf("contains: %d\n", cstr_contains(ss, "umps ove")); + printf("starts_with: %d\n", cstr_starts_with(ss, "The quick brown")); + printf("ends_with: %d\n", cstr_ends_with(ss, ".jpg")); + printf("ends_with: %d\n", cstr_ends_with(ss, ".JPG")); + + cstr s1 = cstr_new("hell😀 w😀rl🐨"); + csview ch1 = cstr_at(&s1, 10); + csview ch2 = cstr_at_u8(&s1, 10); + printf("ch1: %" c_PRIsv "\n", c_ARGsv(ch1)); + printf("ch2: %" c_PRIsv "\n", c_ARGsv(ch2)); + } +} diff --git a/examples/demos.c b/examples/demos.c index 62df82a4..780a4bff 100644 --- a/examples/demos.c +++ b/examples/demos.c @@ -1,229 +1,229 @@ -#define i_implement
-#include <stc/cstr.h>
-
-void stringdemo1()
-{
- printf("\nSTRINGDEMO1\n");
- c_autovar (cstr cs = cstr_new("one-nine-three-seven-five"), cstr_drop(&cs))
- {
- printf("%s.\n", cstr_str(&cs));
-
- cstr_insert(&cs, 3, "-two");
- printf("%s.\n", cstr_str(&cs));
-
- cstr_erase_n(&cs, 7, 5); // -nine
- printf("%s.\n", cstr_str(&cs));
-
- cstr_replace_one(&cs, 0, "seven", "four");
- printf("%s.\n", cstr_str(&cs));
-
- cstr_take(&cs, cstr_from_fmt("%s *** %s", cstr_str(&cs), cstr_str(&cs)));
- printf("%s.\n", cstr_str(&cs));
-
- printf("find \"four\": %s\n", cstr_str(&cs) + cstr_find(cs, "four"));
-
- // reassign:
- cstr_assign(&cs, "one two three four five six seven");
- cstr_append(&cs, " eight");
- printf("append: %s\n", cstr_str(&cs));
- }
-}
-
-#define i_val int64_t
-#define i_tag ix
-#include <stc/cvec.h>
-
-void vectordemo1()
-{
- printf("\nVECTORDEMO1\n");
- c_autovar (cvec_ix bignums = cvec_ix_with_capacity(100), cvec_ix_drop(&bignums))
- {
- cvec_ix_reserve(&bignums, 100);
- for (size_t i = 10; i <= 100; i += 10)
- cvec_ix_push_back(&bignums, i * i);
-
- printf("erase - %d: %" PRIuMAX "\n", 3, bignums.data[3]);
- cvec_ix_erase_n(&bignums, 3, 1); // erase index 3
-
- cvec_ix_pop_back(&bignums); // erase the last
- cvec_ix_erase_n(&bignums, 0, 1); // erase the first
-
- for (size_t i = 0; i < cvec_ix_size(bignums); ++i) {
- printf("%" PRIuMAX ": %" PRIuMAX "\n", i, bignums.data[i]);
- }
- }
-}
-
-#define i_val_str
-#include <stc/cvec.h>
-
-void vectordemo2()
-{
- printf("\nVECTORDEMO2\n");
- c_auto (cvec_str, names) {
- cvec_str_emplace_back(&names, "Mary");
- cvec_str_emplace_back(&names, "Joe");
- cvec_str_emplace_back(&names, "Chris");
- cstr_assign(&names.data[1], "Jane"); // replace Joe
- printf("names[1]: %s\n", cstr_str(&names.data[1]));
-
- cvec_str_sort(&names); // Sort the array
- c_foreach (i, cvec_str, names)
- printf("sorted: %s\n", cstr_str(i.ref));
- }
-}
-
-#define i_val int
-#define i_tag ix
-#define i_extern // define _clist_mergesort() once
-#include <stc/clist.h>
-
-void listdemo1()
-{
- printf("\nLISTDEMO1\n");
- c_auto (clist_ix, nums, nums2)
- {
- for (int i = 0; i < 10; ++i)
- clist_ix_push_back(&nums, i);
- for (int i = 100; i < 110; ++i)
- clist_ix_push_back(&nums2, i);
-
- /* splice nums2 to front of nums */
- clist_ix_splice(&nums, clist_ix_begin(&nums), &nums2);
- c_foreach (i, clist_ix, nums)
- printf("spliced: %d\n", *i.ref);
- puts("");
-
- *clist_ix_find(&nums, 104).ref += 50;
- clist_ix_remove(&nums, 103);
- clist_ix_iter it = clist_ix_begin(&nums);
- clist_ix_erase_range(&nums, clist_ix_advance(it, 5), clist_ix_advance(it, 15));
- clist_ix_pop_front(&nums);
- clist_ix_push_back(&nums, -99);
- clist_ix_sort(&nums);
-
- c_foreach (i, clist_ix, nums)
- printf("sorted: %d\n", *i.ref);
- }
-}
-
-#define i_key int
-#define i_tag i
-#include <stc/cset.h>
-
-void setdemo1()
-{
- printf("\nSETDEMO1\n");
- cset_i nums = cset_i_init();
- cset_i_insert(&nums, 8);
- cset_i_insert(&nums, 11);
-
- c_foreach (i, cset_i, nums)
- printf("set: %d\n", *i.ref);
- cset_i_drop(&nums);
-}
-
-#define i_key int
-#define i_val int
-#define i_tag ii
-#include <stc/cmap.h>
-
-void mapdemo1()
-{
- printf("\nMAPDEMO1\n");
- cmap_ii nums = cmap_ii_init();
- cmap_ii_insert(&nums, 8, 64);
- cmap_ii_insert(&nums, 11, 121);
- printf("val 8: %d\n", *cmap_ii_at(&nums, 8));
- cmap_ii_drop(&nums);
-}
-
-#define i_key_str
-#define i_val int
-#define i_tag si
-#include <stc/cmap.h>
-
-void mapdemo2()
-{
- printf("\nMAPDEMO2\n");
- c_auto (cmap_si, nums)
- {
- cmap_si_emplace_or_assign(&nums, "Hello", 64);
- cmap_si_emplace_or_assign(&nums, "Groovy", 121);
- cmap_si_emplace_or_assign(&nums, "Groovy", 200); // overwrite previous
-
- // iterate the map:
- for (cmap_si_iter i = cmap_si_begin(&nums); i.ref != cmap_si_end(&nums).ref; cmap_si_next(&i))
- printf("long: %s: %d\n", cstr_str(&i.ref->first), i.ref->second);
-
- // or rather use the short form:
- c_foreach (i, cmap_si, nums)
- printf("short: %s: %d\n", cstr_str(&i.ref->first), i.ref->second);
- }
-}
-
-#define i_key_str
-#define i_val_str
-#include <stc/cmap.h>
-
-void mapdemo3()
-{
- printf("\nMAPDEMO3\n");
- cmap_str table = cmap_str_init();
- cmap_str_emplace(&table, "Map", "test");
- cmap_str_emplace(&table, "Make", "my");
- cmap_str_emplace(&table, "Sunny", "day");
- cmap_str_iter it = cmap_str_find(&table, "Make");
- c_foreach (i, cmap_str, table)
- printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
- printf("size %" PRIuMAX ": remove: Make: %s\n", cmap_str_size(table), cstr_str(&it.ref->second));
- //cmap_str_erase(&table, "Make");
- cmap_str_erase_at(&table, it);
-
- printf("size %" PRIuMAX "\n", cmap_str_size(table));
- c_foreach (i, cmap_str, table)
- printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
- cmap_str_drop(&table); // frees key and value cstrs, and hash table.
-}
-
-#define i_val float
-#define i_tag f
-#include <stc/carr3.h>
-
-void arraydemo1()
-{
- printf("\nARRAYDEMO1\n");
- c_autovar (carr3_f arr3 = carr3_f_with_size(30, 20, 10, 0.0f),
- carr3_f_drop(&arr3))
- {
- arr3.data[5][4][3] = 10.2f;
- float **arr2 = arr3.data[5];
- float *arr1 = arr3.data[5][4];
-
- printf("arr3: %" PRIuMAX ": (%" PRIuMAX ", %" PRIuMAX ", %" PRIuMAX ") = %" PRIuMAX "\n", sizeof(arr3),
- arr3.xdim, arr3.ydim, arr3.zdim, carr3_f_size(arr3));
-
- printf("%g\n", arr1[3]); // = 10.2
- printf("%g\n", arr2[4][3]); // = 10.2
- printf("%g\n", arr3.data[5][4][3]); // = 10.2
-
- float x = 0.0;
- c_foreach (i, carr3_f, arr3)
- *i.ref = ++x;
- printf("%g\n", arr3.data[29][19][9]); // = 6000
- }
-}
-
-
-int main()
-{
- stringdemo1();
- vectordemo1();
- vectordemo2();
- listdemo1();
- setdemo1();
- mapdemo1();
- mapdemo2();
- mapdemo3();
- arraydemo1();
-}
+#define i_implement +#include <stc/cstr.h> + +void stringdemo1() +{ + printf("\nSTRINGDEMO1\n"); + c_autovar (cstr cs = cstr_new("one-nine-three-seven-five"), cstr_drop(&cs)) + { + printf("%s.\n", cstr_str(&cs)); + + cstr_insert(&cs, 3, "-two"); + printf("%s.\n", cstr_str(&cs)); + + cstr_erase_n(&cs, 7, 5); // -nine + printf("%s.\n", cstr_str(&cs)); + + cstr_replace_one(&cs, 0, "seven", "four"); + printf("%s.\n", cstr_str(&cs)); + + cstr_take(&cs, cstr_from_fmt("%s *** %s", cstr_str(&cs), cstr_str(&cs))); + printf("%s.\n", cstr_str(&cs)); + + printf("find \"four\": %s\n", cstr_str(&cs) + cstr_find(cs, "four")); + + // reassign: + cstr_assign(&cs, "one two three four five six seven"); + cstr_append(&cs, " eight"); + printf("append: %s\n", cstr_str(&cs)); + } +} + +#define i_val int64_t +#define i_tag ix +#include <stc/cvec.h> + +void vectordemo1() +{ + printf("\nVECTORDEMO1\n"); + c_autovar (cvec_ix bignums = cvec_ix_with_capacity(100), cvec_ix_drop(&bignums)) + { + cvec_ix_reserve(&bignums, 100); + for (size_t i = 10; i <= 100; i += 10) + cvec_ix_push_back(&bignums, i * i); + + printf("erase - %d: %" PRIuMAX "\n", 3, bignums.data[3]); + cvec_ix_erase_n(&bignums, 3, 1); // erase index 3 + + cvec_ix_pop_back(&bignums); // erase the last + cvec_ix_erase_n(&bignums, 0, 1); // erase the first + + for (size_t i = 0; i < cvec_ix_size(bignums); ++i) { + printf("%" PRIuMAX ": %" PRIuMAX "\n", i, bignums.data[i]); + } + } +} + +#define i_val_str +#include <stc/cvec.h> + +void vectordemo2() +{ + printf("\nVECTORDEMO2\n"); + c_auto (cvec_str, names) { + cvec_str_emplace_back(&names, "Mary"); + cvec_str_emplace_back(&names, "Joe"); + cvec_str_emplace_back(&names, "Chris"); + cstr_assign(&names.data[1], "Jane"); // replace Joe + printf("names[1]: %s\n", cstr_str(&names.data[1])); + + cvec_str_sort(&names); // Sort the array + c_foreach (i, cvec_str, names) + printf("sorted: %s\n", cstr_str(i.ref)); + } +} + +#define i_val int +#define i_tag ix +#define i_extern // define _clist_mergesort() once +#include <stc/clist.h> + +void listdemo1() +{ + printf("\nLISTDEMO1\n"); + c_auto (clist_ix, nums, nums2) + { + for (int i = 0; i < 10; ++i) + clist_ix_push_back(&nums, i); + for (int i = 100; i < 110; ++i) + clist_ix_push_back(&nums2, i); + + /* splice nums2 to front of nums */ + clist_ix_splice(&nums, clist_ix_begin(&nums), &nums2); + c_foreach (i, clist_ix, nums) + printf("spliced: %d\n", *i.ref); + puts(""); + + *clist_ix_find(&nums, 104).ref += 50; + clist_ix_remove(&nums, 103); + clist_ix_iter it = clist_ix_begin(&nums); + clist_ix_erase_range(&nums, clist_ix_advance(it, 5), clist_ix_advance(it, 15)); + clist_ix_pop_front(&nums); + clist_ix_push_back(&nums, -99); + clist_ix_sort(&nums); + + c_foreach (i, clist_ix, nums) + printf("sorted: %d\n", *i.ref); + } +} + +#define i_key int +#define i_tag i +#include <stc/cset.h> + +void setdemo1() +{ + printf("\nSETDEMO1\n"); + cset_i nums = cset_i_init(); + cset_i_insert(&nums, 8); + cset_i_insert(&nums, 11); + + c_foreach (i, cset_i, nums) + printf("set: %d\n", *i.ref); + cset_i_drop(&nums); +} + +#define i_key int +#define i_val int +#define i_tag ii +#include <stc/cmap.h> + +void mapdemo1() +{ + printf("\nMAPDEMO1\n"); + cmap_ii nums = cmap_ii_init(); + cmap_ii_insert(&nums, 8, 64); + cmap_ii_insert(&nums, 11, 121); + printf("val 8: %d\n", *cmap_ii_at(&nums, 8)); + cmap_ii_drop(&nums); +} + +#define i_key_str +#define i_val int +#define i_tag si +#include <stc/cmap.h> + +void mapdemo2() +{ + printf("\nMAPDEMO2\n"); + c_auto (cmap_si, nums) + { + cmap_si_emplace_or_assign(&nums, "Hello", 64); + cmap_si_emplace_or_assign(&nums, "Groovy", 121); + cmap_si_emplace_or_assign(&nums, "Groovy", 200); // overwrite previous + + // iterate the map: + for (cmap_si_iter i = cmap_si_begin(&nums); i.ref != cmap_si_end(&nums).ref; cmap_si_next(&i)) + printf("long: %s: %d\n", cstr_str(&i.ref->first), i.ref->second); + + // or rather use the short form: + c_foreach (i, cmap_si, nums) + printf("short: %s: %d\n", cstr_str(&i.ref->first), i.ref->second); + } +} + +#define i_key_str +#define i_val_str +#include <stc/cmap.h> + +void mapdemo3() +{ + printf("\nMAPDEMO3\n"); + cmap_str table = cmap_str_init(); + cmap_str_emplace(&table, "Map", "test"); + cmap_str_emplace(&table, "Make", "my"); + cmap_str_emplace(&table, "Sunny", "day"); + cmap_str_iter it = cmap_str_find(&table, "Make"); + c_foreach (i, cmap_str, table) + printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); + printf("size %" PRIuMAX ": remove: Make: %s\n", cmap_str_size(table), cstr_str(&it.ref->second)); + //cmap_str_erase(&table, "Make"); + cmap_str_erase_at(&table, it); + + printf("size %" PRIuMAX "\n", cmap_str_size(table)); + c_foreach (i, cmap_str, table) + printf("entry: %s: %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); + cmap_str_drop(&table); // frees key and value cstrs, and hash table. +} + +#define i_val float +#define i_tag f +#include <stc/carr3.h> + +void arraydemo1() +{ + printf("\nARRAYDEMO1\n"); + c_autovar (carr3_f arr3 = carr3_f_with_size(30, 20, 10, 0.0f), + carr3_f_drop(&arr3)) + { + arr3.data[5][4][3] = 10.2f; + float **arr2 = arr3.data[5]; + float *arr1 = arr3.data[5][4]; + + printf("arr3: %" PRIuMAX ": (%" PRIuMAX ", %" PRIuMAX ", %" PRIuMAX ") = %" PRIuMAX "\n", sizeof(arr3), + arr3.xdim, arr3.ydim, arr3.zdim, carr3_f_size(arr3)); + + printf("%g\n", arr1[3]); // = 10.2 + printf("%g\n", arr2[4][3]); // = 10.2 + printf("%g\n", arr3.data[5][4][3]); // = 10.2 + + float x = 0.0; + c_foreach (i, carr3_f, arr3) + *i.ref = ++x; + printf("%g\n", arr3.data[29][19][9]); // = 6000 + } +} + + +int main() +{ + stringdemo1(); + vectordemo1(); + vectordemo2(); + listdemo1(); + setdemo1(); + mapdemo1(); + mapdemo2(); + mapdemo3(); + arraydemo1(); +} diff --git a/examples/gauss1.c b/examples/gauss1.c index cca38953..75d5567e 100644 --- a/examples/gauss1.c +++ b/examples/gauss1.c @@ -1,57 +1,57 @@ -#include <time.h>
-#include <math.h>
-
-#define STC_IMPLEMENT
-#include <stc/crandom.h>
-#include <stc/cstr.h>
-
-// Declare int -> int hashmap. Uses typetag 'ii' for ints.
-#define i_key int
-#define i_val int
-#define i_tag ii
-#include <stc/cmap.h>
-
-// Declare int vector with entries from the cmap.
-#define i_val cmap_ii_raw
-#define i_less(x, y) x->first < y->first
-#define i_tag ii
-#include <stc/cvec.h>
-
-int main()
-{
- enum {N = 10000000};
- const double Mean = -12.0, StdDev = 6.0, Scale = 74;
-
- printf("Demo of gaussian / normal distribution of %d random samples\n", N);
-
- // Setup random engine with normal distribution.
- uint64_t seed = time(NULL);
- stc64_t rng = stc64_new(seed);
- stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev);
-
- // Create and init histogram vec and map with defered destructors:
- c_auto (cvec_ii, histvec)
- c_auto (cmap_ii, histmap)
- {
- c_forrange (N) {
- int index = (int) round( stc64_normalf(&rng, &dist) );
- cmap_ii_insert(&histmap, index, 0).ref->second += 1;
- }
-
- // Transfer map to vec and sort it by map keys.
- c_foreach (i, cmap_ii, histmap)
- cvec_ii_push_back(&histvec, (cmap_ii_raw){i.ref->first, i.ref->second});
-
- cvec_ii_sort(&histvec);
-
- // Print the gaussian bar chart
- c_auto (cstr, bar)
- c_foreach (i, cvec_ii, histvec) {
- size_t n = (size_t) (i.ref->second * StdDev * Scale * 2.5 / (float)N);
- if (n > 0) {
- cstr_resize(&bar, n, '*');
- printf("%4d %s\n", i.ref->first, cstr_str(&bar));
- }
- }
- }
-}
+#include <time.h> +#include <math.h> + +#define STC_IMPLEMENT +#include <stc/crandom.h> +#include <stc/cstr.h> + +// Declare int -> int hashmap. Uses typetag 'ii' for ints. +#define i_key int +#define i_val int +#define i_tag ii +#include <stc/cmap.h> + +// Declare int vector with entries from the cmap. +#define i_val cmap_ii_raw +#define i_less(x, y) x->first < y->first +#define i_tag ii +#include <stc/cvec.h> + +int main() +{ + enum {N = 10000000}; + const double Mean = -12.0, StdDev = 6.0, Scale = 74; + + printf("Demo of gaussian / normal distribution of %d random samples\n", N); + + // Setup random engine with normal distribution. + uint64_t seed = time(NULL); + stc64_t rng = stc64_new(seed); + stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev); + + // Create and init histogram vec and map with defered destructors: + c_auto (cvec_ii, histvec) + c_auto (cmap_ii, histmap) + { + c_forrange (N) { + int index = (int) round( stc64_normalf(&rng, &dist) ); + cmap_ii_insert(&histmap, index, 0).ref->second += 1; + } + + // Transfer map to vec and sort it by map keys. + c_foreach (i, cmap_ii, histmap) + cvec_ii_push_back(&histvec, (cmap_ii_raw){i.ref->first, i.ref->second}); + + cvec_ii_sort(&histvec); + + // Print the gaussian bar chart + c_auto (cstr, bar) + c_foreach (i, cvec_ii, histvec) { + size_t n = (size_t) (i.ref->second * StdDev * Scale * 2.5 / (float)N); + if (n > 0) { + cstr_resize(&bar, n, '*'); + printf("%4d %s\n", i.ref->first, cstr_str(&bar)); + } + } + } +} diff --git a/examples/gauss2.c b/examples/gauss2.c index 297b8616..2e07c5a5 100644 --- a/examples/gauss2.c +++ b/examples/gauss2.c @@ -1,43 +1,43 @@ -#include <stdio.h>
-#include <time.h>
-
-#define STC_IMPLEMENT
-#include <stc/crandom.h>
-#include <stc/cstr.h>
-
-// Declare int -> int sorted map.
-#define i_key int
-#define i_val size_t
-#include <stc/csmap.h>
-
-int main()
-{
- enum {N = 10000000};
- const double Mean = -12.0, StdDev = 6.0, Scale = 74;
-
- printf("Demo of gaussian / normal distribution of %d random samples\n", N);
-
- // Setup random engine with normal distribution.
- uint64_t seed = time(NULL);
- stc64_t rng = stc64_new(seed);
- stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev);
-
- // Create and init histogram map with defered destruct
- c_auto (csmap_int, mhist)
- {
- c_forrange (N) {
- int index = (int) round( stc64_normalf(&rng, &dist) );
- csmap_int_insert(&mhist, index, 0).ref->second += 1;
- }
-
- // Print the gaussian bar chart
- c_auto (cstr, bar)
- c_forpair (index, count, csmap_int, mhist) {
- size_t n = (size_t) (*_.count * StdDev * Scale * 2.5 / (float)N);
- if (n > 0) {
- cstr_resize(&bar, n, '*');
- printf("%4d %s\n", *_.index, cstr_str(&bar));
- }
- }
- }
-}
+#include <stdio.h> +#include <time.h> + +#define STC_IMPLEMENT +#include <stc/crandom.h> +#include <stc/cstr.h> + +// Declare int -> int sorted map. +#define i_key int +#define i_val size_t +#include <stc/csmap.h> + +int main() +{ + enum {N = 10000000}; + const double Mean = -12.0, StdDev = 6.0, Scale = 74; + + printf("Demo of gaussian / normal distribution of %d random samples\n", N); + + // Setup random engine with normal distribution. + uint64_t seed = time(NULL); + stc64_t rng = stc64_new(seed); + stc64_normalf_t dist = stc64_normalf_new(Mean, StdDev); + + // Create and init histogram map with defered destruct + c_auto (csmap_int, mhist) + { + c_forrange (N) { + int index = (int) round( stc64_normalf(&rng, &dist) ); + csmap_int_insert(&mhist, index, 0).ref->second += 1; + } + + // Print the gaussian bar chart + c_auto (cstr, bar) + c_forpair (index, count, csmap_int, mhist) { + size_t n = (size_t) (*_.count * StdDev * Scale * 2.5 / (float)N); + if (n > 0) { + cstr_resize(&bar, n, '*'); + printf("%4d %s\n", *_.index, cstr_str(&bar)); + } + } + } +} diff --git a/examples/hashmap.c b/examples/hashmap.c index 62f20079..ab980045 100644 --- a/examples/hashmap.c +++ b/examples/hashmap.c @@ -1,49 +1,49 @@ -// https://doc.rust-lang.org/rust-by-example/std/hash.html
-#define i_implement
-#include <stc/cstr.h>
-#define i_key_str
-#define i_val_str
-#include <stdio.h>
-#include <stc/cmap.h>
-
-const char* call(const char* number) {
- if (!strcmp(number, "798-1364"))
- return "We're sorry, the call cannot be completed as dialed."
- " Please hang up and try again.";
- else if (!strcmp(number, "645-7689"))
- return "Hello, this is Mr. Awesome's Pizza. My name is Fred."
- " What can I get for you today?";
- else
- return "Hi! Who is this again?";
-}
-
-int main(void) {
- c_auto (cmap_str, contacts)
- {
- cmap_str_emplace(&contacts, "Daniel", "798-1364");
- cmap_str_emplace(&contacts, "Ashley", "645-7689");
- cmap_str_emplace(&contacts, "Katie", "435-8291");
- cmap_str_emplace(&contacts, "Robert", "956-1745");
-
- const cmap_str_value* v;
- if ((v = cmap_str_get(&contacts, "Daniel")))
- printf("Calling Daniel: %s\n", call(cstr_str(&v->second)));
- else
- printf("Don't have Daniel's number.");
-
- cmap_str_emplace(&contacts, "Daniel", "164-6743");
-
- if ((v = cmap_str_get(&contacts, "Ashley")))
- printf("Calling Ashley: %s\n", call(cstr_str(&v->second)));
- else
- printf("Don't have Ashley's number.");
-
- cmap_str_erase(&contacts, "Ashley");
-
- puts("");
- c_forpair (contact, number, cmap_str, contacts) {
- printf("Calling %s: %s\n", cstr_str(_.contact), call(cstr_str(_.number)));
- }
- puts("");
- }
-}
+// https://doc.rust-lang.org/rust-by-example/std/hash.html +#define i_implement +#include <stc/cstr.h> +#define i_key_str +#define i_val_str +#include <stdio.h> +#include <stc/cmap.h> + +const char* call(const char* number) { + if (!strcmp(number, "798-1364")) + return "We're sorry, the call cannot be completed as dialed." + " Please hang up and try again."; + else if (!strcmp(number, "645-7689")) + return "Hello, this is Mr. Awesome's Pizza. My name is Fred." + " What can I get for you today?"; + else + return "Hi! Who is this again?"; +} + +int main(void) { + c_auto (cmap_str, contacts) + { + cmap_str_emplace(&contacts, "Daniel", "798-1364"); + cmap_str_emplace(&contacts, "Ashley", "645-7689"); + cmap_str_emplace(&contacts, "Katie", "435-8291"); + cmap_str_emplace(&contacts, "Robert", "956-1745"); + + const cmap_str_value* v; + if ((v = cmap_str_get(&contacts, "Daniel"))) + printf("Calling Daniel: %s\n", call(cstr_str(&v->second))); + else + printf("Don't have Daniel's number."); + + cmap_str_emplace(&contacts, "Daniel", "164-6743"); + + if ((v = cmap_str_get(&contacts, "Ashley"))) + printf("Calling Ashley: %s\n", call(cstr_str(&v->second))); + else + printf("Don't have Ashley's number."); + + cmap_str_erase(&contacts, "Ashley"); + + puts(""); + c_forpair (contact, number, cmap_str, contacts) { + printf("Calling %s: %s\n", cstr_str(_.contact), call(cstr_str(_.number))); + } + puts(""); + } +} diff --git a/examples/inits.c b/examples/inits.c index 26f4b286..1013da36 100644 --- a/examples/inits.c +++ b/examples/inits.c @@ -1,114 +1,114 @@ -#define i_implement
-#include <stc/cstr.h>
-
-#define i_key int
-#define i_val_str
-#define i_tag id // Map of int => cstr
-#include <stc/cmap.h>
-
-#define i_key_str
-#define i_val int
-#define i_tag cnt // Map of cstr => int
-#include <stc/cmap.h>
-
-typedef struct {int x, y;} ipair_t;
-inline static int ipair_cmp(const ipair_t* a, const ipair_t* b) {
- int c = c_default_cmp(&a->x, &b->x);
- return c ? c : c_default_cmp(&a->y, &b->y);
-}
-
-
-#define i_val ipair_t
-#define i_cmp ipair_cmp
-#define i_tag ip
-#include <stc/cvec.h>
-
-#define i_val ipair_t
-#define i_cmp ipair_cmp
-#define i_tag ip
-#define i_extern // define _clist_mergesort() once
-#include <stc/clist.h>
-
-#define i_val float
-#define i_tag f
-#include <stc/cpque.h>
-
-int main(void)
-{
- // CVEC FLOAT / PRIORITY QUEUE
-
- c_auto (cpque_f, floats) {
- const float nums[] = {4.0f, 2.0f, 5.0f, 3.0f, 1.0f};
-
- // PRIORITY QUEUE
-
- c_apply_arr(v, cpque_f_push(&floats, *v), const float, nums, c_arraylen(nums));
-
- puts("\npop and show high priorites first:");
- while (! cpque_f_empty(floats)) {
- printf("%.1f ", *cpque_f_top(&floats));
- cpque_f_pop(&floats);
- }
- puts("\n");
- }
-
- // CMAP ID
-
- int year = 2020;
- c_auto (cmap_id, idnames) {
- cmap_id_emplace(&idnames, 100, "Hello");
- cmap_id_insert(&idnames, 110, cstr_new("World"));
- cmap_id_insert(&idnames, 120, cstr_from_fmt("Howdy, -%d-", year));
-
- c_foreach (i, cmap_id, idnames)
- printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second));
- puts("");
- }
-
- // CMAP CNT
-
- c_auto (cmap_cnt, countries) {
- c_apply(v, cmap_cnt_emplace(&countries, c_pair(v)), cmap_cnt_raw, {
- {"Norway", 100},
- {"Denmark", 50},
- {"Iceland", 10},
- {"Belgium", 10},
- {"Italy", 10},
- {"Germany", 10},
- {"Spain", 10},
- {"France", 10},
- });
- cmap_cnt_emplace(&countries, "Greenland", 0).ref->second += 20;
- cmap_cnt_emplace(&countries, "Sweden", 0).ref->second += 20;
- cmap_cnt_emplace(&countries, "Norway", 0).ref->second += 20;
- cmap_cnt_emplace(&countries, "Finland", 0).ref->second += 20;
-
- c_forpair (country, health, cmap_cnt, countries)
- printf("%s: %d\n", cstr_str(_.country), *_.health);
- puts("");
- }
-
- // CVEC PAIR
-
- c_auto (cvec_ip, pairs1) {
- c_apply(p, cvec_ip_push_back(&pairs1, *p), ipair_t,
- {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
- cvec_ip_sort(&pairs1);
-
- c_foreach (i, cvec_ip, pairs1)
- printf("(%d %d) ", i.ref->x, i.ref->y);
- puts("");
- }
-
- // CLIST PAIR
-
- c_auto (clist_ip, pairs2) {
- c_apply(p, clist_ip_push_back(&pairs2, *p), ipair_t,
- {{5, 6}, {3, 4}, {1, 2}, {7, 8}});
- clist_ip_sort(&pairs2);
-
- c_foreach (i, clist_ip, pairs2)
- printf("(%d %d) ", i.ref->x, i.ref->y);
- puts("");
- }
-}
+#define i_implement +#include <stc/cstr.h> + +#define i_key int +#define i_val_str +#define i_tag id // Map of int => cstr +#include <stc/cmap.h> + +#define i_key_str +#define i_val int +#define i_tag cnt // Map of cstr => int +#include <stc/cmap.h> + +typedef struct {int x, y;} ipair_t; +inline static int ipair_cmp(const ipair_t* a, const ipair_t* b) { + int c = c_default_cmp(&a->x, &b->x); + return c ? c : c_default_cmp(&a->y, &b->y); +} + + +#define i_val ipair_t +#define i_cmp ipair_cmp +#define i_tag ip +#include <stc/cvec.h> + +#define i_val ipair_t +#define i_cmp ipair_cmp +#define i_tag ip +#define i_extern // define _clist_mergesort() once +#include <stc/clist.h> + +#define i_val float +#define i_tag f +#include <stc/cpque.h> + +int main(void) +{ + // CVEC FLOAT / PRIORITY QUEUE + + c_auto (cpque_f, floats) { + const float nums[] = {4.0f, 2.0f, 5.0f, 3.0f, 1.0f}; + + // PRIORITY QUEUE + + c_apply_arr(v, cpque_f_push(&floats, *v), const float, nums, c_arraylen(nums)); + + puts("\npop and show high priorites first:"); + while (! cpque_f_empty(floats)) { + printf("%.1f ", *cpque_f_top(&floats)); + cpque_f_pop(&floats); + } + puts("\n"); + } + + // CMAP ID + + int year = 2020; + c_auto (cmap_id, idnames) { + cmap_id_emplace(&idnames, 100, "Hello"); + cmap_id_insert(&idnames, 110, cstr_new("World")); + cmap_id_insert(&idnames, 120, cstr_from_fmt("Howdy, -%d-", year)); + + c_foreach (i, cmap_id, idnames) + printf("%d: %s\n", i.ref->first, cstr_str(&i.ref->second)); + puts(""); + } + + // CMAP CNT + + c_auto (cmap_cnt, countries) { + c_apply(v, cmap_cnt_emplace(&countries, c_pair(v)), cmap_cnt_raw, { + {"Norway", 100}, + {"Denmark", 50}, + {"Iceland", 10}, + {"Belgium", 10}, + {"Italy", 10}, + {"Germany", 10}, + {"Spain", 10}, + {"France", 10}, + }); + cmap_cnt_emplace(&countries, "Greenland", 0).ref->second += 20; + cmap_cnt_emplace(&countries, "Sweden", 0).ref->second += 20; + cmap_cnt_emplace(&countries, "Norway", 0).ref->second += 20; + cmap_cnt_emplace(&countries, "Finland", 0).ref->second += 20; + + c_forpair (country, health, cmap_cnt, countries) + printf("%s: %d\n", cstr_str(_.country), *_.health); + puts(""); + } + + // CVEC PAIR + + c_auto (cvec_ip, pairs1) { + c_apply(p, cvec_ip_push_back(&pairs1, *p), ipair_t, + {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); + cvec_ip_sort(&pairs1); + + c_foreach (i, cvec_ip, pairs1) + printf("(%d %d) ", i.ref->x, i.ref->y); + puts(""); + } + + // CLIST PAIR + + c_auto (clist_ip, pairs2) { + c_apply(p, clist_ip_push_back(&pairs2, *p), ipair_t, + {{5, 6}, {3, 4}, {1, 2}, {7, 8}}); + clist_ip_sort(&pairs2); + + c_foreach (i, clist_ip, pairs2) + printf("(%d %d) ", i.ref->x, i.ref->y); + puts(""); + } +} diff --git a/examples/list.c b/examples/list.c index 7d6d1a50..17ed048d 100644 --- a/examples/list.c +++ b/examples/list.c @@ -1,61 +1,61 @@ -#include <stdio.h>
-#include <time.h>
-
-#define STC_IMPLEMENT
-#define STC_EXTERN
-
-#define i_val double
-#define i_tag fx
-#include <stc/clist.h>
-#include <stc/crandom.h>
-
-int main() {
- int k;
- const int n = 2000000;
-
- c_auto (clist_fx, list)
- {
- stc64_t rng = stc64_new(1234);
- stc64_uniformf_t dist = stc64_uniformf_new(100.0f, n);
- int m = 0;
- c_forrange (i, int, n)
- clist_fx_push_back(&list, stc64_uniformf(&rng, &dist)), ++m;
- double sum = 0.0;
- printf("sumarize %d:\n", m);
- c_foreach (i, clist_fx, list)
- sum += *i.ref;
- printf("sum %f\n\n", sum);
-
- k = 0;
- c_foreach (i, clist_fx, list)
- if (++k <= 10) printf("%8d: %10f\n", k, *i.ref); else break;
- puts("sort");
- clist_fx_sort(&list); // mergesort O(n*log n)
- puts("sorted");
-
- k = 0;
- c_foreach (i, clist_fx, list)
- if (++k <= 10) printf("%8d: %10f\n", k, *i.ref); else break;
- puts("");
-
- clist_fx_clear(&list);
- c_apply(v, clist_fx_push_back(&list, *v), int, {10, 20, 30, 40, 30, 50});
- const double* v = clist_fx_get(&list, 30);
- printf("found: %f\n", *v);
- c_foreach (i, clist_fx, list) printf(" %g", *i.ref);
- puts("");
-
- clist_fx_remove(&list, 30);
- clist_fx_insert_at(&list, clist_fx_begin(&list), 5); // same as push_front()
- clist_fx_push_back(&list, 500);
- clist_fx_push_front(&list, 1964);
- clist_fx_iter it = clist_fx_begin(&list);
- printf("Full: ");
- c_foreach (i, clist_fx, list)
- printf(" %g", *i.ref);
- printf("\nSubs: ");
- c_foreach (i, clist_fx, clist_fx_advance(it, 4), clist_fx_end(&list))
- printf(" %g", *i.ref);
- puts("");
- }
-}
+#include <stdio.h> +#include <time.h> + +#define STC_IMPLEMENT +#define STC_EXTERN + +#define i_val double +#define i_tag fx +#include <stc/clist.h> +#include <stc/crandom.h> + +int main() { + int k; + const int n = 2000000; + + c_auto (clist_fx, list) + { + stc64_t rng = stc64_new(1234); + stc64_uniformf_t dist = stc64_uniformf_new(100.0f, n); + int m = 0; + c_forrange (i, int, n) + clist_fx_push_back(&list, stc64_uniformf(&rng, &dist)), ++m; + double sum = 0.0; + printf("sumarize %d:\n", m); + c_foreach (i, clist_fx, list) + sum += *i.ref; + printf("sum %f\n\n", sum); + + k = 0; + c_foreach (i, clist_fx, list) + if (++k <= 10) printf("%8d: %10f\n", k, *i.ref); else break; + puts("sort"); + clist_fx_sort(&list); // mergesort O(n*log n) + puts("sorted"); + + k = 0; + c_foreach (i, clist_fx, list) + if (++k <= 10) printf("%8d: %10f\n", k, *i.ref); else break; + puts(""); + + clist_fx_clear(&list); + c_apply(v, clist_fx_push_back(&list, *v), int, {10, 20, 30, 40, 30, 50}); + const double* v = clist_fx_get(&list, 30); + printf("found: %f\n", *v); + c_foreach (i, clist_fx, list) printf(" %g", *i.ref); + puts(""); + + clist_fx_remove(&list, 30); + clist_fx_insert_at(&list, clist_fx_begin(&list), 5); // same as push_front() + clist_fx_push_back(&list, 500); + clist_fx_push_front(&list, 1964); + clist_fx_iter it = clist_fx_begin(&list); + printf("Full: "); + c_foreach (i, clist_fx, list) + printf(" %g", *i.ref); + printf("\nSubs: "); + c_foreach (i, clist_fx, clist_fx_advance(it, 4), clist_fx_end(&list)) + printf(" %g", *i.ref); + puts(""); + } +} diff --git a/examples/list_erase.c b/examples/list_erase.c index 19a00299..ad062131 100644 --- a/examples/list_erase.c +++ b/examples/list_erase.c @@ -1,29 +1,29 @@ -// erasing from clist
-#include <stdio.h>
-
-#define i_val int
-#include <stc/clist.h>
-
-int main ()
-{
- c_auto (clist_int, L)
- {
- c_apply(i, clist_int_push_back(&L, *i), int, {10, 20, 30, 40, 50});
- c_foreach (x, clist_int, L)
- printf("%d ", *x.ref);
- puts("");
- // 10 20 30 40 50
- clist_int_iter it = clist_int_begin(&L); // ^
- clist_int_next(&it);
- it = clist_int_erase_at(&L, it); // 10 30 40 50
- // ^
- clist_int_iter end = clist_int_end(&L); //
- clist_int_next(&it);
- it = clist_int_erase_range(&L, it, end); // 10 30
- // ^
- printf("list contains:");
- c_foreach (x, clist_int, L)
- printf(" %d", *x.ref);
- puts("");
- }
-}
+// erasing from clist +#include <stdio.h> + +#define i_val int +#include <stc/clist.h> + +int main () +{ + c_auto (clist_int, L) + { + c_apply(i, clist_int_push_back(&L, *i), int, {10, 20, 30, 40, 50}); + c_foreach (x, clist_int, L) + printf("%d ", *x.ref); + puts(""); + // 10 20 30 40 50 + clist_int_iter it = clist_int_begin(&L); // ^ + clist_int_next(&it); + it = clist_int_erase_at(&L, it); // 10 30 40 50 + // ^ + clist_int_iter end = clist_int_end(&L); // + clist_int_next(&it); + it = clist_int_erase_range(&L, it, end); // 10 30 + // ^ + printf("list contains:"); + c_foreach (x, clist_int, L) + printf(" %d", *x.ref); + puts(""); + } +} diff --git a/examples/lower_bound.c b/examples/lower_bound.c index 6039dd48..a1de1cfd 100644 --- a/examples/lower_bound.c +++ b/examples/lower_bound.c @@ -1,64 +1,64 @@ -#include <stdio.h>
-
-#define i_val int
-#include <stc/cvec.h>
-
-#define i_val int
-#include <stc/csset.h>
-
-int main()
-{
- // TEST SORTED VECTOR
- c_auto (cvec_int, vec)
- {
- int key, *res;
-
- c_apply(t, cvec_int_push(&vec, *t), int, {
- 40, 600, 1, 7000, 2, 500, 30,
- });
-
- cvec_int_sort(&vec);
-
- key = 500;
- res = cvec_int_lower_bound(&vec, key).ref;
- if (res != cvec_int_end(&vec).ref)
- printf("Sorted Vec %d: lower bound: %d\n", key, *res); // 600
-
- key = 550;
- res = cvec_int_lower_bound(&vec, key).ref;
- if (res != cvec_int_end(&vec).ref)
- printf("Sorted Vec %d: lower_bound: %d\n", key, *res); // 500
-
- key = 500;
- res = cvec_int_binary_search(&vec, key).ref;
- if (res != cvec_int_end(&vec).ref)
- printf("Sorted Vec %d: bin. search: %d\n", key, *res); // 500
- puts("");
- }
-
- // TEST SORTED SET
- c_auto (csset_int, set)
- {
- int key, *res;
-
- c_apply(t, csset_int_push(&set, *t), int, {
- 40, 600, 1, 7000, 2, 500, 30,
- });
-
- key = 500;
- res = csset_int_lower_bound(&set, key).ref;
- if (res != csset_int_end(&set).ref)
- printf("Sorted Set %d: lower bound: %d\n", key, *res); // 600
-
- key = 550;
- res = csset_int_lower_bound(&set, key).ref;
- if (res != csset_int_end(&set).ref)
- printf("Sorted Set %d: lower bound: %d\n", key, *res); // 600
-
- key = 500;
- res = csset_int_find(&set, key).ref;
- if (res != csset_int_end(&set).ref)
- printf("Sorted Set %d: find : %d\n", key, *res); // 600
- }
- return 0;
-}
+#include <stdio.h> + +#define i_val int +#include <stc/cvec.h> + +#define i_val int +#include <stc/csset.h> + +int main() +{ + // TEST SORTED VECTOR + c_auto (cvec_int, vec) + { + int key, *res; + + c_apply(t, cvec_int_push(&vec, *t), int, { + 40, 600, 1, 7000, 2, 500, 30, + }); + + cvec_int_sort(&vec); + + key = 500; + res = cvec_int_lower_bound(&vec, key).ref; + if (res != cvec_int_end(&vec).ref) + printf("Sorted Vec %d: lower bound: %d\n", key, *res); // 600 + + key = 550; + res = cvec_int_lower_bound(&vec, key).ref; + if (res != cvec_int_end(&vec).ref) + printf("Sorted Vec %d: lower_bound: %d\n", key, *res); // 500 + + key = 500; + res = cvec_int_binary_search(&vec, key).ref; + if (res != cvec_int_end(&vec).ref) + printf("Sorted Vec %d: bin. search: %d\n", key, *res); // 500 + puts(""); + } + + // TEST SORTED SET + c_auto (csset_int, set) + { + int key, *res; + + c_apply(t, csset_int_push(&set, *t), int, { + 40, 600, 1, 7000, 2, 500, 30, + }); + + key = 500; + res = csset_int_lower_bound(&set, key).ref; + if (res != csset_int_end(&set).ref) + printf("Sorted Set %d: lower bound: %d\n", key, *res); // 600 + + key = 550; + res = csset_int_lower_bound(&set, key).ref; + if (res != csset_int_end(&set).ref) + printf("Sorted Set %d: lower bound: %d\n", key, *res); // 600 + + key = 500; + res = csset_int_find(&set, key).ref; + if (res != csset_int_end(&set).ref) + printf("Sorted Set %d: find : %d\n", key, *res); // 600 + } + return 0; +} diff --git a/examples/mapmap.c b/examples/mapmap.c index 9ac22371..ab48ecc6 100644 --- a/examples/mapmap.c +++ b/examples/mapmap.c @@ -1,73 +1,73 @@ -// unordered_map<string, unordered_map<string, string>>:
-#define i_implement
-#include <stc/cstr.h>
-#define i_type People
-#define i_key_str
-#define i_val_str
-#define i_keydrop(p) (printf("kdrop: %s\n", cstr_str(p)), cstr_drop(p)) // override
-#include <stc/csmap.h>
-
-#define i_type Departments
-#define i_key_str
-#define i_val_bind People
-// Shorthand for:
-// #define i_val People
-// #define i_cmp People_cmp
-// #define i_valclone People_clone
-// #define i_valdrop People_drop
-#include <stc/csmap.h>
-
-#define i_type Stack
-#define i_val_bind People_value
-// Shorthand for:
-// #define i_val People_value (pair of cstr)
-// #define i_cmp People_value_cmp
-// #define i_valclone People_value_clone
-// #define i_valdrop People_value_drop
-#include <stc/cvec.h>
-
-void add(Departments* deps, const char* name, const char* email, const char* dep)
-{
- People *people = &Departments_insert(deps, cstr_from(dep), People_init()).ref->second;
- People_emplace_or_assign(people, name, email);
-}
-
-int contains(Departments* map, const char* name)
-{
- int count = 0;
- c_foreach (i, Departments, *map)
- if (People_contains(&i.ref->second, name))
- ++count;
- return count;
-}
-
-int main(void)
-{
- c_auto (Departments, map)
- {
- add(&map, "Anna Kendro", "[email protected]", "Support");
- add(&map, "Terry Dane", "[email protected]", "Development");
- add(&map, "Kik Winston", "[email protected]", "Finance");
- add(&map, "Nancy Drew", "[email protected]", "Development");
- add(&map, "Nick Denton", "[email protected]", "Finance");
- add(&map, "Stan Whiteword", "[email protected]", "Marketing");
- add(&map, "Serena Bath", "[email protected]", "Support");
- add(&map, "Patrick Dust", "[email protected]", "Finance");
- add(&map, "Red Winger", "[email protected]", "Marketing");
- add(&map, "Nick Denton", "[email protected]", "Support");
- add(&map, "Colin Turth", "[email protected]", "Support");
- add(&map, "Dennis Kay", "[email protected]", "Marketing");
- add(&map, "Anne Dickens", "[email protected]", "Development");
-
- c_foreach (i, Departments, map)
- c_forpair (name, email, People, i.ref->second)
- printf("%s: %s - %s\n", cstr_str(&i.ref->first), cstr_str(_.name), cstr_str(_.email));
- puts("");
-
- printf("found: %d\n", contains(&map, "Nick Denton"));
- printf("found: %d\n", contains(&map, "Patrick Dust"));
- printf("found: %d\n", contains(&map, "Dennis Kay"));
- printf("found: %d\n", contains(&map, "Serena Bath"));
- puts("Done");
- }
-}
+// unordered_map<string, unordered_map<string, string>>: +#define i_implement +#include <stc/cstr.h> +#define i_type People +#define i_key_str +#define i_val_str +#define i_keydrop(p) (printf("kdrop: %s\n", cstr_str(p)), cstr_drop(p)) // override +#include <stc/csmap.h> + +#define i_type Departments +#define i_key_str +#define i_val_bind People +// Shorthand for: +// #define i_val People +// #define i_cmp People_cmp +// #define i_valclone People_clone +// #define i_valdrop People_drop +#include <stc/csmap.h> + +#define i_type Stack +#define i_val_bind People_value +// Shorthand for: +// #define i_val People_value (pair of cstr) +// #define i_cmp People_value_cmp +// #define i_valclone People_value_clone +// #define i_valdrop People_value_drop +#include <stc/cvec.h> + +void add(Departments* deps, const char* name, const char* email, const char* dep) +{ + People *people = &Departments_insert(deps, cstr_from(dep), People_init()).ref->second; + People_emplace_or_assign(people, name, email); +} + +int contains(Departments* map, const char* name) +{ + int count = 0; + c_foreach (i, Departments, *map) + if (People_contains(&i.ref->second, name)) + ++count; + return count; +} + +int main(void) +{ + c_auto (Departments, map) + { + add(&map, "Anna Kendro", "[email protected]", "Support"); + add(&map, "Terry Dane", "[email protected]", "Development"); + add(&map, "Kik Winston", "[email protected]", "Finance"); + add(&map, "Nancy Drew", "[email protected]", "Development"); + add(&map, "Nick Denton", "[email protected]", "Finance"); + add(&map, "Stan Whiteword", "[email protected]", "Marketing"); + add(&map, "Serena Bath", "[email protected]", "Support"); + add(&map, "Patrick Dust", "[email protected]", "Finance"); + add(&map, "Red Winger", "[email protected]", "Marketing"); + add(&map, "Nick Denton", "[email protected]", "Support"); + add(&map, "Colin Turth", "[email protected]", "Support"); + add(&map, "Dennis Kay", "[email protected]", "Marketing"); + add(&map, "Anne Dickens", "[email protected]", "Development"); + + c_foreach (i, Departments, map) + c_forpair (name, email, People, i.ref->second) + printf("%s: %s - %s\n", cstr_str(&i.ref->first), cstr_str(_.name), cstr_str(_.email)); + puts(""); + + printf("found: %d\n", contains(&map, "Nick Denton")); + printf("found: %d\n", contains(&map, "Patrick Dust")); + printf("found: %d\n", contains(&map, "Dennis Kay")); + printf("found: %d\n", contains(&map, "Serena Bath")); + puts("Done"); + } +} diff --git a/examples/mmap.c b/examples/mmap.c index cfb7470e..5e3eda00 100644 --- a/examples/mmap.c +++ b/examples/mmap.c @@ -1,76 +1,76 @@ -// This implements the multimap c++ example found at:
-// https://en.cppreference.com/w/cpp/container/multimap/insert
-
-// Multimap entries
-#define i_implement
-#include <stc/cstr.h>
-#define i_val_str
-#define i_extern // define _clist_mergesort() once
-#include <stc/clist.h>
-
-// Map of int => clist_str.
-#define i_type Multimap
-#define i_key int
-#define i_val_bind clist_str // uses clist_str as i_val and binds clist_str_clone, clist_str_drop
-#define i_cmp -c_default_cmp // like std::greater<int>
-#include <stc/csmap.h>
-
-void print(const char* lbl, const Multimap mmap)
-{
- printf("%s ", lbl);
- c_foreach (e, Multimap, mmap) {
- c_foreach (s, clist_str, e.ref->second)
- printf("{%d,%s} ", e.ref->first, cstr_str(s.ref));
- }
- puts("");
-}
-
-void insert(Multimap* mmap, int key, const char* str)
-{
- clist_str *list = &Multimap_insert(mmap, key, clist_str_init()).ref->second;
- clist_str_emplace_back(list, str);
-}
-
-int main()
-{
- c_auto (Multimap, mmap)
- {
- // list-initialize
- struct { int first; const char* second; } vals[] =
- {{2, "foo"}, {2, "bar"}, {3, "baz"}, {1, "abc"}, {5, "def"}};
- c_forrange (i, c_arraylen(vals)) insert(&mmap, c_pair(&vals[i]));
- print("#1", mmap);
-
- // insert using value_type
- insert(&mmap, 5, "pqr");
- print("#2", mmap);
-
- // insert using make_pair
- insert(&mmap, 6, "uvw");
- print("#3", mmap);
-
- insert(&mmap, 7, "xyz");
- print("#4", mmap);
-
- // insert using initialization_list
- insert(&mmap, 5, "one");
- insert(&mmap, 5, "two");
- print("#5", mmap);
-
- // FOLLOWING NOT IN ORIGINAL EXAMPLE:
-
- // erase all entries with key 5
- Multimap_erase(&mmap, 5);
- print("+6", mmap);
-
- // find and erase first entry containing "bar"
- clist_str_iter pos;
- c_foreach (e, Multimap, mmap) {
- if ((pos = clist_str_find(&e.ref->second, "bar")).ref != clist_str_end(&e.ref->second).ref) {
- clist_str_erase_at(&e.ref->second, pos);
- break;
- }
- }
- print("+7", mmap);
- }
-}
+// This implements the multimap c++ example found at: +// https://en.cppreference.com/w/cpp/container/multimap/insert + +// Multimap entries +#define i_implement +#include <stc/cstr.h> +#define i_val_str +#define i_extern // define _clist_mergesort() once +#include <stc/clist.h> + +// Map of int => clist_str. +#define i_type Multimap +#define i_key int +#define i_val_bind clist_str // uses clist_str as i_val and binds clist_str_clone, clist_str_drop +#define i_cmp -c_default_cmp // like std::greater<int> +#include <stc/csmap.h> + +void print(const char* lbl, const Multimap mmap) +{ + printf("%s ", lbl); + c_foreach (e, Multimap, mmap) { + c_foreach (s, clist_str, e.ref->second) + printf("{%d,%s} ", e.ref->first, cstr_str(s.ref)); + } + puts(""); +} + +void insert(Multimap* mmap, int key, const char* str) +{ + clist_str *list = &Multimap_insert(mmap, key, clist_str_init()).ref->second; + clist_str_emplace_back(list, str); +} + +int main() +{ + c_auto (Multimap, mmap) + { + // list-initialize + struct { int first; const char* second; } vals[] = + {{2, "foo"}, {2, "bar"}, {3, "baz"}, {1, "abc"}, {5, "def"}}; + c_forrange (i, c_arraylen(vals)) insert(&mmap, c_pair(&vals[i])); + print("#1", mmap); + + // insert using value_type + insert(&mmap, 5, "pqr"); + print("#2", mmap); + + // insert using make_pair + insert(&mmap, 6, "uvw"); + print("#3", mmap); + + insert(&mmap, 7, "xyz"); + print("#4", mmap); + + // insert using initialization_list + insert(&mmap, 5, "one"); + insert(&mmap, 5, "two"); + print("#5", mmap); + + // FOLLOWING NOT IN ORIGINAL EXAMPLE: + + // erase all entries with key 5 + Multimap_erase(&mmap, 5); + print("+6", mmap); + + // find and erase first entry containing "bar" + clist_str_iter pos; + c_foreach (e, Multimap, mmap) { + if ((pos = clist_str_find(&e.ref->second, "bar")).ref != clist_str_end(&e.ref->second).ref) { + clist_str_erase_at(&e.ref->second, pos); + break; + } + } + print("+7", mmap); + } +} diff --git a/examples/multimap.c b/examples/multimap.c index c2920ef4..a2d06a06 100644 --- a/examples/multimap.c +++ b/examples/multimap.c @@ -1,100 +1,100 @@ -#define i_implement
-#include <stc/cstr.h>
-
-// Olympics multimap example
-
-struct OlympicsData { int year; const char *city, *country, *date; } ol_data[] = {
- {2026, "Milan and Cortina d'Ampezzo", "Italy", "February 6-22"},
- {2022, "Beijing", "China", "February 4-20"},
- {2018, "PyeongChang", "South Korea", "February 9-25"},
- {2014, "Sochi", "Russia", "February 7-23"},
- {2010, "Vancouver", "Canada", "February 12-28"},
- {2006, "Torino", "Italy", "February 10-26"},
- {2002, "Salt Lake City", "United States", "February 8-24"},
- {1998, "Nagano", "Japan", "February 7-22"},
- {1994, "Lillehammer", "Norway", "February 12-27"},
- {1992, "Albertville", "France", "February 8-23"},
- {1988, "Calgary", "Canada", "February 13-28"},
- {1984, "Sarajevo", "Yugoslavia", "February 8-19"},
- {1980, "Lake Placid", "United States", "February 13-24"},
- {1976, "Innsbruck", "Austria", "February 4-15"},
- {1972, "Sapporo", "Japan", "February 3-13"},
- {1968, "Grenoble", "France", "February 6-18"},
- {1964, "Innsbruck", "Austria", "January 29-February 9"},
- {1960, "Squaw Valley", "United States", "February 18-28"},
- {1956, "Cortina d'Ampezzo", "Italy", "January 26 - February 5"},
- {1952, "Oslo", "Norway", "February 14 - 25"},
- {1948, "St. Moritz", "Switzerland", "January 30 - February 8"},
- {1944, "canceled", "canceled", "canceled"},
- {1940, "canceled", "canceled", "canceled"},
- {1936, "Garmisch-Partenkirchen", "Germany", "February 6 - 16"},
- {1932, "Lake Placid", "United States", "February 4 - 15"},
- {1928, "St. Moritz", "Switzerland", "February 11 - 19"},
- {1924, "Chamonix", "France", "January 25 - February 5"},
-};
-
-typedef struct { int year; cstr city, date; } OlympicLocation;
-
-int OlympicLocation_cmp(const OlympicLocation* a, const OlympicLocation* b);
-OlympicLocation OlympicLocation_clone(OlympicLocation loc);
-void OlympicLocation_drop(OlympicLocation* self);
-
-// Create a clist<OlympicLocation>, can be sorted by year.
-#define i_val_bind OlympicLocation // binds _cmp, _clone and _drop.
-#define i_tag OL
-#define i_extern // define _clist_mergesort()
-#include <stc/clist.h>
-
-// Create a csmap<cstr, clist_OL> where key is country name
-#define i_key_str // binds cstr_equ, cstr_hash, cstr_clone, ++
-#define i_val_bind clist_OL // binds clist_OL_clone, clist_OL_drop
-#define i_tag OL
-#include <stc/csmap.h>
-
-int OlympicLocation_cmp(const OlympicLocation* a, const OlympicLocation* b) {
- return a->year - b->year;
-}
-
-OlympicLocation OlympicLocation_clone(OlympicLocation loc) {
- loc.city = cstr_clone(loc.city);
- loc.date = cstr_clone(loc.date);
- return loc;
-}
-void OlympicLocation_drop(OlympicLocation* self) {
- c_drop(cstr, &self->city, &self->date);
-}
-
-int main()
-{
- // Define the multimap with destructor defered to when block is completed.
- c_auto (csmap_OL, multimap)
- {
- const clist_OL empty = clist_OL_init();
-
- for (size_t i = 0; i < c_arraylen(ol_data); ++i)
- {
- struct OlympicsData* d = &ol_data[i];
- OlympicLocation loc = {.year = d->year,
- .city = cstr_from(d->city),
- .date = cstr_from(d->date)};
- // Insert an empty list for each new country, and append the entry to the list.
- // If country already exist in map, its list is returned from the insert function.
- clist_OL* list = &csmap_OL_insert(&multimap, cstr_from(d->country), empty).ref->second;
- clist_OL_push_back(list, loc);
- }
- // Sort locations by year for each country.
- c_foreach (country, csmap_OL, multimap)
- clist_OL_sort(&country.ref->second);
-
- // Print the multimap:
- c_foreach (country, csmap_OL, multimap)
- {
- // Loop the locations for a country sorted by year
- c_foreach (loc, clist_OL, country.ref->second)
- printf("%s: %d, %s, %s\n", cstr_str(&country.ref->first),
- loc.ref->year,
- cstr_str(&loc.ref->city),
- cstr_str(&loc.ref->date));
- }
- }
-}
+#define i_implement +#include <stc/cstr.h> + +// Olympics multimap example + +struct OlympicsData { int year; const char *city, *country, *date; } ol_data[] = { + {2026, "Milan and Cortina d'Ampezzo", "Italy", "February 6-22"}, + {2022, "Beijing", "China", "February 4-20"}, + {2018, "PyeongChang", "South Korea", "February 9-25"}, + {2014, "Sochi", "Russia", "February 7-23"}, + {2010, "Vancouver", "Canada", "February 12-28"}, + {2006, "Torino", "Italy", "February 10-26"}, + {2002, "Salt Lake City", "United States", "February 8-24"}, + {1998, "Nagano", "Japan", "February 7-22"}, + {1994, "Lillehammer", "Norway", "February 12-27"}, + {1992, "Albertville", "France", "February 8-23"}, + {1988, "Calgary", "Canada", "February 13-28"}, + {1984, "Sarajevo", "Yugoslavia", "February 8-19"}, + {1980, "Lake Placid", "United States", "February 13-24"}, + {1976, "Innsbruck", "Austria", "February 4-15"}, + {1972, "Sapporo", "Japan", "February 3-13"}, + {1968, "Grenoble", "France", "February 6-18"}, + {1964, "Innsbruck", "Austria", "January 29-February 9"}, + {1960, "Squaw Valley", "United States", "February 18-28"}, + {1956, "Cortina d'Ampezzo", "Italy", "January 26 - February 5"}, + {1952, "Oslo", "Norway", "February 14 - 25"}, + {1948, "St. Moritz", "Switzerland", "January 30 - February 8"}, + {1944, "canceled", "canceled", "canceled"}, + {1940, "canceled", "canceled", "canceled"}, + {1936, "Garmisch-Partenkirchen", "Germany", "February 6 - 16"}, + {1932, "Lake Placid", "United States", "February 4 - 15"}, + {1928, "St. Moritz", "Switzerland", "February 11 - 19"}, + {1924, "Chamonix", "France", "January 25 - February 5"}, +}; + +typedef struct { int year; cstr city, date; } OlympicLocation; + +int OlympicLocation_cmp(const OlympicLocation* a, const OlympicLocation* b); +OlympicLocation OlympicLocation_clone(OlympicLocation loc); +void OlympicLocation_drop(OlympicLocation* self); + +// Create a clist<OlympicLocation>, can be sorted by year. +#define i_val_bind OlympicLocation // binds _cmp, _clone and _drop. +#define i_tag OL +#define i_extern // define _clist_mergesort() +#include <stc/clist.h> + +// Create a csmap<cstr, clist_OL> where key is country name +#define i_key_str // binds cstr_equ, cstr_hash, cstr_clone, ++ +#define i_val_bind clist_OL // binds clist_OL_clone, clist_OL_drop +#define i_tag OL +#include <stc/csmap.h> + +int OlympicLocation_cmp(const OlympicLocation* a, const OlympicLocation* b) { + return a->year - b->year; +} + +OlympicLocation OlympicLocation_clone(OlympicLocation loc) { + loc.city = cstr_clone(loc.city); + loc.date = cstr_clone(loc.date); + return loc; +} +void OlympicLocation_drop(OlympicLocation* self) { + c_drop(cstr, &self->city, &self->date); +} + +int main() +{ + // Define the multimap with destructor defered to when block is completed. + c_auto (csmap_OL, multimap) + { + const clist_OL empty = clist_OL_init(); + + for (size_t i = 0; i < c_arraylen(ol_data); ++i) + { + struct OlympicsData* d = &ol_data[i]; + OlympicLocation loc = {.year = d->year, + .city = cstr_from(d->city), + .date = cstr_from(d->date)}; + // Insert an empty list for each new country, and append the entry to the list. + // If country already exist in map, its list is returned from the insert function. + clist_OL* list = &csmap_OL_insert(&multimap, cstr_from(d->country), empty).ref->second; + clist_OL_push_back(list, loc); + } + // Sort locations by year for each country. + c_foreach (country, csmap_OL, multimap) + clist_OL_sort(&country.ref->second); + + // Print the multimap: + c_foreach (country, csmap_OL, multimap) + { + // Loop the locations for a country sorted by year + c_foreach (loc, clist_OL, country.ref->second) + printf("%s: %d, %s, %s\n", cstr_str(&country.ref->first), + loc.ref->year, + cstr_str(&loc.ref->city), + cstr_str(&loc.ref->date)); + } + } +} diff --git a/examples/music_arc.c b/examples/music_arc.c index b6b59489..13075741 100644 --- a/examples/music_arc.c +++ b/examples/music_arc.c @@ -1,59 +1,59 @@ -// shared_ptr-examples.cpp
-// based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160
-#define i_implement
-#include <stc/cstr.h>
-
-struct Song
-{
- cstr artist;
- cstr title;
-} typedef Song;
-
-Song Song_new(const char* artist, const char* title)
- { return (Song){cstr_from(artist), cstr_from(title)}; }
-
-void Song_drop(Song* s) {
- printf("drop: %s\n", cstr_str(&s->title));
- c_drop(cstr, &s->artist, &s->title);
-}
-
-#define i_type SongPtr
-#define i_val Song
-#define i_valdrop Song_drop
-#define i_opt c_no_cmp
-#include <stc/carc.h>
-
-#define i_type SongVec
-#define i_val_arcbox SongPtr
-#include <stc/cvec.h>
-
-void example3()
-{
- c_auto (SongVec, vec, vec2)
- {
- c_apply(v, SongVec_push_back(&vec, *v), SongPtr, {
- SongPtr_make(Song_new("Bob Dylan", "The Times They Are A Changing")),
- SongPtr_make(Song_new("Aretha Franklin", "Bridge Over Troubled Water")),
- SongPtr_make(Song_new("Thalia", "Entre El Mar y Una Estrella"))
- });
-
- c_foreach (s, SongVec, vec)
- if (!cstr_equals(s.ref->get->artist, "Bob Dylan"))
- SongVec_push_back(&vec2, SongPtr_clone(*s.ref));
-
- c_apply(v, SongVec_push_back(&vec2, *v), SongPtr, {
- SongPtr_make(Song_new("Michael Jackson", "Billie Jean")),
- SongPtr_make(Song_new("Rihanna", "Stay")),
- });
-
- c_foreach (s, SongVec, vec2)
- printf("%s - %s: refs %lu\n", cstr_str(&s.ref->get->artist),
- cstr_str(&s.ref->get->title),
- *s.ref->use_count);
- }
-}
-
-int main()
-{
- example3();
-}
+// shared_ptr-examples.cpp +// based on https://docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-shared-ptr-instances?view=msvc-160 +#define i_implement +#include <stc/cstr.h> + +struct Song +{ + cstr artist; + cstr title; +} typedef Song; + +Song Song_new(const char* artist, const char* title) + { return (Song){cstr_from(artist), cstr_from(title)}; } + +void Song_drop(Song* s) { + printf("drop: %s\n", cstr_str(&s->title)); + c_drop(cstr, &s->artist, &s->title); +} + +#define i_type SongPtr +#define i_val Song +#define i_valdrop Song_drop +#define i_opt c_no_cmp +#include <stc/carc.h> + +#define i_type SongVec +#define i_val_arcbox SongPtr +#include <stc/cvec.h> + +void example3() +{ + c_auto (SongVec, vec, vec2) + { + c_apply(v, SongVec_push_back(&vec, *v), SongPtr, { + SongPtr_make(Song_new("Bob Dylan", "The Times They Are A Changing")), + SongPtr_make(Song_new("Aretha Franklin", "Bridge Over Troubled Water")), + SongPtr_make(Song_new("Thalia", "Entre El Mar y Una Estrella")) + }); + + c_foreach (s, SongVec, vec) + if (!cstr_equals(s.ref->get->artist, "Bob Dylan")) + SongVec_push_back(&vec2, SongPtr_clone(*s.ref)); + + c_apply(v, SongVec_push_back(&vec2, *v), SongPtr, { + SongPtr_make(Song_new("Michael Jackson", "Billie Jean")), + SongPtr_make(Song_new("Rihanna", "Stay")), + }); + + c_foreach (s, SongVec, vec2) + printf("%s - %s: refs %lu\n", cstr_str(&s.ref->get->artist), + cstr_str(&s.ref->get->title), + *s.ref->use_count); + } +} + +int main() +{ + example3(); +} diff --git a/examples/new_deq.c b/examples/new_deq.c index f1e872f0..5fe2403a 100644 --- a/examples/new_deq.c +++ b/examples/new_deq.c @@ -1,62 +1,62 @@ -#define i_implement
-#include <stc/cstr.h>
-#include <stc/forward.h>
-
-forward_cdeq(cdeq_i32, int);
-forward_cdeq(cdeq_pnt, struct Point);
-
-struct MyStruct {
- cdeq_i32 intvec;
- cdeq_pnt pntvec;
-} typedef MyStruct;
-
-
-#define i_val int
-#define i_opt c_is_fwd
-#define i_tag i32
-#include <stc/cdeq.h>
-
-struct Point { int x, y; } typedef Point;
-int point_cmp(const Point* a, const Point* b) {
- int c = a->x - b->x;
- return c ? c : a->y - b->y;
-}
-
-#define i_val Point
-#define i_cmp point_cmp
-#define i_opt c_is_fwd
-#define i_tag pnt
-#include <stc/cdeq.h>
-
-#define i_val float
-#include <stc/cdeq.h>
-
-#define i_val_str
-#include <stc/cdeq.h>
-
-
-int main()
-{
- c_auto (cdeq_i32, vec)
- {
- cdeq_i32_push_back(&vec, 123);
- }
- c_auto (cdeq_float, fvec)
- {
- cdeq_float_push_back(&fvec, 123.3);
- }
- c_auto (cdeq_pnt, pvec)
- {
- cdeq_pnt_push_back(&pvec, (Point){42, 14});
- cdeq_pnt_push_back(&pvec, (Point){32, 94});
- cdeq_pnt_push_front(&pvec, (Point){62, 81});
- cdeq_pnt_sort(&pvec);
- c_foreach (i, cdeq_pnt, pvec)
- printf(" (%d %d)", i.ref->x, i.ref->y);
- puts("");
- }
- c_auto (cdeq_str, svec)
- {
- cdeq_str_emplace_back(&svec, "Hello, friend");
- }
-}
+#define i_implement +#include <stc/cstr.h> +#include <stc/forward.h> + +forward_cdeq(cdeq_i32, int); +forward_cdeq(cdeq_pnt, struct Point); + +struct MyStruct { + cdeq_i32 intvec; + cdeq_pnt pntvec; +} typedef MyStruct; + + +#define i_val int +#define i_opt c_is_fwd +#define i_tag i32 +#include <stc/cdeq.h> + +struct Point { int x, y; } typedef Point; +int point_cmp(const Point* a, const Point* b) { + int c = a->x - b->x; + return c ? c : a->y - b->y; +} + +#define i_val Point +#define i_cmp point_cmp +#define i_opt c_is_fwd +#define i_tag pnt +#include <stc/cdeq.h> + +#define i_val float +#include <stc/cdeq.h> + +#define i_val_str +#include <stc/cdeq.h> + + +int main() +{ + c_auto (cdeq_i32, vec) + { + cdeq_i32_push_back(&vec, 123); + } + c_auto (cdeq_float, fvec) + { + cdeq_float_push_back(&fvec, 123.3); + } + c_auto (cdeq_pnt, pvec) + { + cdeq_pnt_push_back(&pvec, (Point){42, 14}); + cdeq_pnt_push_back(&pvec, (Point){32, 94}); + cdeq_pnt_push_front(&pvec, (Point){62, 81}); + cdeq_pnt_sort(&pvec); + c_foreach (i, cdeq_pnt, pvec) + printf(" (%d %d)", i.ref->x, i.ref->y); + puts(""); + } + c_auto (cdeq_str, svec) + { + cdeq_str_emplace_back(&svec, "Hello, friend"); + } +} diff --git a/examples/new_map.c b/examples/new_map.c index 0882d02f..78c1a44d 100644 --- a/examples/new_map.c +++ b/examples/new_map.c @@ -1,73 +1,73 @@ -#define i_implement
-#include <stc/cstr.h>
-#include <stc/forward.h>
-
-forward_cmap(cmap_pnt, struct Point, int);
-
-struct MyStruct {
- cmap_pnt pntmap;
- cstr name;
-} typedef MyStruct;
-
-// int => int map
-#define i_key int
-#define i_val int
-#include <stc/cmap.h>
-
-// Point => int map
-struct Point { int x, y; } typedef Point;
-
-int point_cmp(const Point* a, const Point* b) {
- int c = a->x - b->x;
- return c ? c : a->y - b->y;
-}
-
-// Point => int map
-#define i_key Point
-#define i_val int
-#define i_cmp point_cmp
-#define i_hash c_default_hash
-#define i_opt c_is_fwd
-#define i_tag pnt
-#include <stc/cmap.h>
-
-// cstr => cstr map
-#define i_key_str
-#define i_val_str
-#include <stc/cmap.h>
-
-// string set
-#define i_key_str
-#include <stc/cset.h>
-
-
-int main()
-{
- c_auto (cmap_int, map)
- c_auto (cmap_pnt, pmap)
- c_auto (cmap_str, smap)
- c_auto (cset_str, sset)
- {
- cmap_int_insert(&map, 123, 321);
-
- c_apply(v, cmap_pnt_insert(&pmap, c_pair(v)), cmap_pnt_raw, {
- {{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3}
- });
- c_foreach (i, cmap_pnt, pmap)
- printf(" (%d, %d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second);
- puts("");
-
- c_apply(v, cmap_str_emplace(&smap, c_pair(v)), cmap_str_raw, {
- {"Hello, friend", "long time no see"},
- {"So long, friend", "see you around"},
- });
-
- c_apply(v, cset_str_emplace(&sset, *v), const char*, {
- "Hello, friend",
- "Nice to see you again",
- "So long, friend",
- });
- c_foreach (i, cset_str, sset)
- printf(" %s\n", cstr_str(i.ref));
- }
-}
+#define i_implement +#include <stc/cstr.h> +#include <stc/forward.h> + +forward_cmap(cmap_pnt, struct Point, int); + +struct MyStruct { + cmap_pnt pntmap; + cstr name; +} typedef MyStruct; + +// int => int map +#define i_key int +#define i_val int +#include <stc/cmap.h> + +// Point => int map +struct Point { int x, y; } typedef Point; + +int point_cmp(const Point* a, const Point* b) { + int c = a->x - b->x; + return c ? c : a->y - b->y; +} + +// Point => int map +#define i_key Point +#define i_val int +#define i_cmp point_cmp +#define i_hash c_default_hash +#define i_opt c_is_fwd +#define i_tag pnt +#include <stc/cmap.h> + +// cstr => cstr map +#define i_key_str +#define i_val_str +#include <stc/cmap.h> + +// string set +#define i_key_str +#include <stc/cset.h> + + +int main() +{ + c_auto (cmap_int, map) + c_auto (cmap_pnt, pmap) + c_auto (cmap_str, smap) + c_auto (cset_str, sset) + { + cmap_int_insert(&map, 123, 321); + + c_apply(v, cmap_pnt_insert(&pmap, c_pair(v)), cmap_pnt_raw, { + {{42, 14}, 1}, {{32, 94}, 2}, {{62, 81}, 3} + }); + c_foreach (i, cmap_pnt, pmap) + printf(" (%d, %d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second); + puts(""); + + c_apply(v, cmap_str_emplace(&smap, c_pair(v)), cmap_str_raw, { + {"Hello, friend", "long time no see"}, + {"So long, friend", "see you around"}, + }); + + c_apply(v, cset_str_emplace(&sset, *v), const char*, { + "Hello, friend", + "Nice to see you again", + "So long, friend", + }); + c_foreach (i, cset_str, sset) + printf(" %s\n", cstr_str(i.ref)); + } +} diff --git a/examples/new_pque.c b/examples/new_pque.c index 79e895d8..2e5cf9ca 100644 --- a/examples/new_pque.c +++ b/examples/new_pque.c @@ -1,65 +1,65 @@ -#include <stc/forward.h>
-
-forward_cpque(cpque_pnt, struct Point);
-
-struct MyStruct {
- cpque_pnt priority_queue;
- int id;
-};
-
-#define i_val int
-#include <stc/cstack.h>
-
-#define i_val int
-#include <stc/cpque.h>
-
-struct Point { int x, y; } typedef Point;
-
-int Point_cmp(const Point* a, const Point* b) {
- int c = a->x - b->x;
- return c ? c : a->y - b->y;
-}
-
-#define i_val Point
-#define i_cmp Point_cmp
-#define i_opt c_is_fwd
-#define i_tag pnt
-#include <stc/cpque.h>
-
-#include <stdio.h>
-
-int main()
-{
- c_auto (cstack_int, istk)
- {
- cstack_int_push(&istk, 123);
- cstack_int_push(&istk, 321);
- // print
- c_foreach (i, cstack_int, istk)
- printf(" %d", *i.ref);
- puts("");
- }
- c_auto (cpque_pnt, pque)
- {
- cpque_pnt_push(&pque, (Point){23, 80});
- cpque_pnt_push(&pque, (Point){12, 32});
- cpque_pnt_push(&pque, (Point){54, 74});
- cpque_pnt_push(&pque, (Point){12, 62});
- // print
- while (!cpque_pnt_empty(pque)) {
- cpque_pnt_value *v = cpque_pnt_top(&pque);
- printf(" (%d,%d)", v->x, v->y);
- cpque_pnt_pop(&pque);
- }
- puts("");
- }
- c_auto (cpque_int, ique)
- {
- cpque_int_push(&ique, 123);
- cpque_int_push(&ique, 321);
- // print
- for (size_t i=0; i<cpque_int_size(ique); ++i)
- printf(" %d", ique.data[i]);
- puts("");
- }
-}
+#include <stc/forward.h> + +forward_cpque(cpque_pnt, struct Point); + +struct MyStruct { + cpque_pnt priority_queue; + int id; +}; + +#define i_val int +#include <stc/cstack.h> + +#define i_val int +#include <stc/cpque.h> + +struct Point { int x, y; } typedef Point; + +int Point_cmp(const Point* a, const Point* b) { + int c = a->x - b->x; + return c ? c : a->y - b->y; +} + +#define i_val Point +#define i_cmp Point_cmp +#define i_opt c_is_fwd +#define i_tag pnt +#include <stc/cpque.h> + +#include <stdio.h> + +int main() +{ + c_auto (cstack_int, istk) + { + cstack_int_push(&istk, 123); + cstack_int_push(&istk, 321); + // print + c_foreach (i, cstack_int, istk) + printf(" %d", *i.ref); + puts(""); + } + c_auto (cpque_pnt, pque) + { + cpque_pnt_push(&pque, (Point){23, 80}); + cpque_pnt_push(&pque, (Point){12, 32}); + cpque_pnt_push(&pque, (Point){54, 74}); + cpque_pnt_push(&pque, (Point){12, 62}); + // print + while (!cpque_pnt_empty(pque)) { + cpque_pnt_value *v = cpque_pnt_top(&pque); + printf(" (%d,%d)", v->x, v->y); + cpque_pnt_pop(&pque); + } + puts(""); + } + c_auto (cpque_int, ique) + { + cpque_int_push(&ique, 123); + cpque_int_push(&ique, 321); + // print + for (size_t i=0; i<cpque_int_size(ique); ++i) + printf(" %d", ique.data[i]); + puts(""); + } +} diff --git a/examples/new_queue.c b/examples/new_queue.c index 86f4227c..f0d8120f 100644 --- a/examples/new_queue.c +++ b/examples/new_queue.c @@ -1,45 +1,45 @@ -#define i_implement
-#include <stc/crandom.h>
-#include <stc/forward.h>
-#include <stdio.h>
-#include <time.h>
-
-forward_cqueue(cqueue_pnt, struct Point);
-
-struct Point { int x, y; } typedef Point;
-int point_cmp(const Point* a, const Point* b) {
- int c = c_default_cmp(&a->x, &b->x);
- return c ? c : c_default_cmp(&a->y, &b->y);
-}
-#define i_val Point
-#define i_cmp point_cmp
-#define i_opt c_is_fwd
-#define i_tag pnt
-#include <stc/cqueue.h>
-
-#define i_val int
-#include <stc/cqueue.h>
-
-int main() {
- int n = 60000000;
- stc64_t rng = stc64_new(time(NULL));
- stc64_uniform_t dist = stc64_uniform_new(0, n);
-
- c_auto (cqueue_int, Q)
- {
- // Push eight million random numbers onto the queue.
- for (int i=0; i<n; ++i)
- cqueue_int_push(&Q, stc64_uniform(&rng, &dist));
-
- // Push or pop on the queue ten million times
- printf("befor: size %" PRIuMAX ", capacity %" PRIuMAX "\n", cqueue_int_size(Q), cqueue_int_capacity(Q));
- for (int i=n; i>0; --i) {
- int r = stc64_uniform(&rng, &dist);
- if (r & 1)
- cqueue_int_push(&Q, r);
- else
- cqueue_int_pop(&Q);
- }
- printf("after: size %" PRIuMAX ", capacity %" PRIuMAX "\n", cqueue_int_size(Q), cqueue_int_capacity(Q));
- }
-}
+#define i_implement +#include <stc/crandom.h> +#include <stc/forward.h> +#include <stdio.h> +#include <time.h> + +forward_cqueue(cqueue_pnt, struct Point); + +struct Point { int x, y; } typedef Point; +int point_cmp(const Point* a, const Point* b) { + int c = c_default_cmp(&a->x, &b->x); + return c ? c : c_default_cmp(&a->y, &b->y); +} +#define i_val Point +#define i_cmp point_cmp +#define i_opt c_is_fwd +#define i_tag pnt +#include <stc/cqueue.h> + +#define i_val int +#include <stc/cqueue.h> + +int main() { + int n = 60000000; + stc64_t rng = stc64_new(time(NULL)); + stc64_uniform_t dist = stc64_uniform_new(0, n); + + c_auto (cqueue_int, Q) + { + // Push eight million random numbers onto the queue. + for (int i=0; i<n; ++i) + cqueue_int_push(&Q, stc64_uniform(&rng, &dist)); + + // Push or pop on the queue ten million times + printf("befor: size %" PRIuMAX ", capacity %" PRIuMAX "\n", cqueue_int_size(Q), cqueue_int_capacity(Q)); + for (int i=n; i>0; --i) { + int r = stc64_uniform(&rng, &dist); + if (r & 1) + cqueue_int_push(&Q, r); + else + cqueue_int_pop(&Q); + } + printf("after: size %" PRIuMAX ", capacity %" PRIuMAX "\n", cqueue_int_size(Q), cqueue_int_capacity(Q)); + } +} diff --git a/examples/new_smap.c b/examples/new_smap.c index 2a885d03..141934d3 100644 --- a/examples/new_smap.c +++ b/examples/new_smap.c @@ -1,76 +1,76 @@ -#define i_implement
-#include <stc/cstr.h>
-#include <stc/forward.h>
-
-forward_csmap(PMap, struct Point, int);
-
-// Use forward declared PMap in struct
-struct MyStruct {
- PMap pntmap;
- cstr name;
-} typedef MyStruct;
-
-// int => int map
-#define i_key int
-#define i_val int
-#include <stc/csmap.h>
-
-// Point => int map
-struct Point { int x, y; } typedef Point;
-int point_cmp(const Point* a, const Point* b) {
- int c = a->x - b->x;
- return c ? c : a->y - b->y;
-}
-
-#define i_type PMap
-#define i_key Point
-#define i_val int
-#define i_cmp point_cmp
-#define i_opt c_is_fwd
-#include <stc/csmap.h>
-
-// cstr => cstr map
-#define i_type SMap
-#define i_key_str
-#define i_val_str
-#include <stc/csmap.h>
-
-// cstr set
-#define i_type SSet
-#define i_key_str
-#include <stc/csset.h>
-
-
-int main()
-{
- c_auto (csmap_int, imap) {
- csmap_int_insert(&imap, 123, 321);
- }
-
- c_auto (PMap, pmap) {
- c_apply(v, PMap_insert(&pmap, c_pair(v)), PMap_value, {
- {{42, 14}, 1},
- {{32, 94}, 2},
- {{62, 81}, 3},
- });
- c_forpair (p, i, PMap, pmap)
- printf(" (%d,%d: %d)", _.p->x, _.p->y, *_.i);
- puts("");
- }
-
- c_auto (SMap, smap) {
- c_apply(v, SMap_emplace(&smap, c_pair(v)), SMap_raw, {
- {"Hello, friend", "this is the mapped value"},
- {"The brown fox", "jumped"},
- {"This is the time", "for all good things"},
- });
- c_forpair (i, j, SMap, smap)
- printf(" (%s: %s)\n", cstr_str(_.i), cstr_str(_.j));
- }
-
- c_auto (SSet, sset) {
- SSet_emplace(&sset, "Hello, friend");
- SSet_emplace(&sset, "Goodbye, foe");
- printf("Found? %s\n", SSet_contains(&sset, "Hello, friend") ? "true" : "false");
- }
-}
+#define i_implement +#include <stc/cstr.h> +#include <stc/forward.h> + +forward_csmap(PMap, struct Point, int); + +// Use forward declared PMap in struct +struct MyStruct { + PMap pntmap; + cstr name; +} typedef MyStruct; + +// int => int map +#define i_key int +#define i_val int +#include <stc/csmap.h> + +// Point => int map +struct Point { int x, y; } typedef Point; +int point_cmp(const Point* a, const Point* b) { + int c = a->x - b->x; + return c ? c : a->y - b->y; +} + +#define i_type PMap +#define i_key Point +#define i_val int +#define i_cmp point_cmp +#define i_opt c_is_fwd +#include <stc/csmap.h> + +// cstr => cstr map +#define i_type SMap +#define i_key_str +#define i_val_str +#include <stc/csmap.h> + +// cstr set +#define i_type SSet +#define i_key_str +#include <stc/csset.h> + + +int main() +{ + c_auto (csmap_int, imap) { + csmap_int_insert(&imap, 123, 321); + } + + c_auto (PMap, pmap) { + c_apply(v, PMap_insert(&pmap, c_pair(v)), PMap_value, { + {{42, 14}, 1}, + {{32, 94}, 2}, + {{62, 81}, 3}, + }); + c_forpair (p, i, PMap, pmap) + printf(" (%d,%d: %d)", _.p->x, _.p->y, *_.i); + puts(""); + } + + c_auto (SMap, smap) { + c_apply(v, SMap_emplace(&smap, c_pair(v)), SMap_raw, { + {"Hello, friend", "this is the mapped value"}, + {"The brown fox", "jumped"}, + {"This is the time", "for all good things"}, + }); + c_forpair (i, j, SMap, smap) + printf(" (%s: %s)\n", cstr_str(_.i), cstr_str(_.j)); + } + + c_auto (SSet, sset) { + SSet_emplace(&sset, "Hello, friend"); + SSet_emplace(&sset, "Goodbye, foe"); + printf("Found? %s\n", SSet_contains(&sset, "Hello, friend") ? "true" : "false"); + } +} diff --git a/examples/new_sptr.c b/examples/new_sptr.c index 58f68dae..e2d4da85 100644 --- a/examples/new_sptr.c +++ b/examples/new_sptr.c @@ -1,56 +1,56 @@ -#define i_implement
-#include <stc/cstr.h>
-
-struct Person { cstr name, last; } typedef Person;
-
-Person Person_new(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
-}
-Person Person_clone(Person p) {
- p.name = cstr_clone(p.name), p.last = cstr_clone(p.last);
- return p;
-}
-void Person_drop(Person* p) {
- printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
- c_drop(cstr, &p->name, &p->last);
-}
-
-#define i_val_bind Person
-#define i_opt c_no_cmp // makes cmp and hash not required when using _bind
-#define i_tag person
-#include <stc/carc.h>
-
-// ...
-#define i_type SPtr
-#define i_val int
-#define i_valdrop(x) printf("drop: %d\n", *x)
-#include <stc/carc.h>
-
-#define i_val_arcbox SPtr
-#define i_tag iptr
-#include <stc/cstack.h>
-
-int main(void) {
- c_auto (carc_person, p, q, r, s)
- {
- puts("Ex1");
- p = carc_person_make(Person_new("John", "Smiths"));
- q = carc_person_clone(p);
- r = carc_person_clone(p);
- s = carc_person_make(Person_clone(*p.get)); // deep copy
- printf("%s %s. uses: %lu\n", cstr_str(&r.get->name), cstr_str(&s.get->last), *p.use_count);
- }
-
- c_auto (cstack_iptr, stk) {
- puts("Ex2");
- cstack_iptr_push(&stk, SPtr_make(10));
- cstack_iptr_push(&stk, SPtr_make(20));
- cstack_iptr_push(&stk, SPtr_make(30));
- cstack_iptr_push(&stk, SPtr_clone(*cstack_iptr_top(&stk)));
- cstack_iptr_push(&stk, SPtr_clone(*cstack_iptr_begin(&stk).ref));
-
- c_foreach (i, cstack_iptr, stk)
- printf(" (%d, uses %ld)", *i.ref->get, *i.ref->use_count);
- puts("");
- }
-}
+#define i_implement +#include <stc/cstr.h> + +struct Person { cstr name, last; } typedef Person; + +Person Person_new(const char* name, const char* last) { + return (Person){.name = cstr_from(name), .last = cstr_from(last)}; +} +Person Person_clone(Person p) { + p.name = cstr_clone(p.name), p.last = cstr_clone(p.last); + return p; +} +void Person_drop(Person* p) { + printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); + c_drop(cstr, &p->name, &p->last); +} + +#define i_val_bind Person +#define i_opt c_no_cmp // makes cmp and hash not required when using _bind +#define i_tag person +#include <stc/carc.h> + +// ... +#define i_type SPtr +#define i_val int +#define i_valdrop(x) printf("drop: %d\n", *x) +#include <stc/carc.h> + +#define i_val_arcbox SPtr +#define i_tag iptr +#include <stc/cstack.h> + +int main(void) { + c_auto (carc_person, p, q, r, s) + { + puts("Ex1"); + p = carc_person_make(Person_new("John", "Smiths")); + q = carc_person_clone(p); + r = carc_person_clone(p); + s = carc_person_make(Person_clone(*p.get)); // deep copy + printf("%s %s. uses: %lu\n", cstr_str(&r.get->name), cstr_str(&s.get->last), *p.use_count); + } + + c_auto (cstack_iptr, stk) { + puts("Ex2"); + cstack_iptr_push(&stk, SPtr_make(10)); + cstack_iptr_push(&stk, SPtr_make(20)); + cstack_iptr_push(&stk, SPtr_make(30)); + cstack_iptr_push(&stk, SPtr_clone(*cstack_iptr_top(&stk))); + cstack_iptr_push(&stk, SPtr_clone(*cstack_iptr_begin(&stk).ref)); + + c_foreach (i, cstack_iptr, stk) + printf(" (%d, uses %ld)", *i.ref->get, *i.ref->use_count); + puts(""); + } +} diff --git a/examples/new_vec.c b/examples/new_vec.c index 3f3d5de8..73e4987f 100644 --- a/examples/new_vec.c +++ b/examples/new_vec.c @@ -1,57 +1,57 @@ -#define i_implement
-#include <stc/cstr.h>
-#include <stc/forward.h>
-
-forward_cvec(cvec_i32, int);
-forward_cvec(cvec_pnt, struct Point);
-
-struct MyStruct {
- cvec_i32 intvec;
- cvec_pnt pntvec;
-} typedef MyStruct;
-
-#define i_val int
-#define i_opt c_is_fwd
-#define i_tag i32
-#include <stc/cvec.h>
-
-struct Point { int x, y; } typedef Point;
-int point_cmp(const Point* a, const Point* b) {
- int c = c_default_cmp(&a->x, &b->x);
- return c ? c : c_default_cmp(&a->y, &b->y);
-}
-
-#define i_val Point
-#define i_cmp point_cmp
-#define i_opt c_is_fwd
-#define i_tag pnt
-#include <stc/cvec.h>
-
-#define i_val float
-#include <stc/cvec.h>
-
-#define i_val_str
-#include <stc/cvec.h>
-
-
-int main()
-{
- c_auto (cvec_i32, vec)
- c_auto (cvec_float, fvec)
- c_auto (cvec_pnt, pvec)
- c_auto (cvec_str, svec)
- {
- cvec_i32_push_back(&vec, 123);
- cvec_float_push_back(&fvec, 123.3);
-
- cvec_pnt_push_back(&pvec, (Point){42, 14});
- cvec_pnt_push_back(&pvec, (Point){32, 94});
- cvec_pnt_push_back(&pvec, (Point){62, 81});
- cvec_pnt_sort(&pvec);
- c_foreach (i, cvec_pnt, pvec)
- printf(" (%d %d)", i.ref->x, i.ref->y);
- puts("");
-
- cvec_str_emplace_back(&svec, "Hello, friend");
- }
-}
+#define i_implement +#include <stc/cstr.h> +#include <stc/forward.h> + +forward_cvec(cvec_i32, int); +forward_cvec(cvec_pnt, struct Point); + +struct MyStruct { + cvec_i32 intvec; + cvec_pnt pntvec; +} typedef MyStruct; + +#define i_val int +#define i_opt c_is_fwd +#define i_tag i32 +#include <stc/cvec.h> + +struct Point { int x, y; } typedef Point; +int point_cmp(const Point* a, const Point* b) { + int c = c_default_cmp(&a->x, &b->x); + return c ? c : c_default_cmp(&a->y, &b->y); +} + +#define i_val Point +#define i_cmp point_cmp +#define i_opt c_is_fwd +#define i_tag pnt +#include <stc/cvec.h> + +#define i_val float +#include <stc/cvec.h> + +#define i_val_str +#include <stc/cvec.h> + + +int main() +{ + c_auto (cvec_i32, vec) + c_auto (cvec_float, fvec) + c_auto (cvec_pnt, pvec) + c_auto (cvec_str, svec) + { + cvec_i32_push_back(&vec, 123); + cvec_float_push_back(&fvec, 123.3); + + cvec_pnt_push_back(&pvec, (Point){42, 14}); + cvec_pnt_push_back(&pvec, (Point){32, 94}); + cvec_pnt_push_back(&pvec, (Point){62, 81}); + cvec_pnt_sort(&pvec); + c_foreach (i, cvec_pnt, pvec) + printf(" (%d %d)", i.ref->x, i.ref->y); + puts(""); + + cvec_str_emplace_back(&svec, "Hello, friend"); + } +} diff --git a/examples/person_arc.c b/examples/person_arc.c index 5ac1e9c2..685d1b3c 100644 --- a/examples/person_arc.c +++ b/examples/person_arc.c @@ -1,72 +1,72 @@ -/* cbox: heap allocated boxed type */
-#define i_implement
-#include <stc/cstr.h>
-
-typedef struct { cstr name, last; } Person;
-
-Person Person_new(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
-}
-
-int Person_cmp(const Person* a, const Person* b) {
- int c = cstr_cmp(&a->name, &b->name);
- return c ? c : cstr_cmp(&a->last, &b->last);
-}
-
-uint64_t Person_hash(const Person* a) {
- return cstr_hash(&a->name) ^ cstr_hash(&a->last);
-}
-
-Person Person_clone(Person p) {
- p.name = cstr_clone(p.name);
- p.last = cstr_clone(p.last);
- return p;
-}
-
-void Person_drop(Person* p) {
- printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
- c_drop(cstr, &p->name, &p->last);
-}
-
-#define i_type PSPtr
-#define i_val_bind Person // binds Person_cmp, ...
-#include <stc/carc.h>
-
-#define i_type Persons
-#define i_val_arcbox PSPtr // binds PSPtr_cmp, ...
-#include <stc/cvec.h>
-
-
-int main()
-{
- c_auto (Persons, vec)
- c_auto (PSPtr, p, q)
- {
- p = PSPtr_make(Person_new("Laura", "Palmer"));
-
- // We want a deep copy -- PSPtr_clone(p) only shares!
- q = PSPtr_make(Person_clone(*p.get));
- cstr_assign(&q.get->name, "Leland");
-
- printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last));
- printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last));
-
- Persons_push_back(&vec, PSPtr_make(Person_new("Dale", "Cooper")));
- Persons_push_back(&vec, PSPtr_make(Person_new("Audrey", "Home")));
-
- // Clone/share p and q to the vector
- c_apply(v, Persons_push_back(&vec, PSPtr_clone(*v)), PSPtr, {p, q});
-
- c_foreach (i, Persons, vec)
- printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last));
- puts("");
-
- // Look-up Audrey!
- c_autovar (Person a = Person_new("Audrey", "Home"), Person_drop(&a)) {
- const PSPtr *v = Persons_get(&vec, a);
- if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last));
- }
-
- puts("");
- }
-}
+/* cbox: heap allocated boxed type */ +#define i_implement +#include <stc/cstr.h> + +typedef struct { cstr name, last; } Person; + +Person Person_new(const char* name, const char* last) { + return (Person){.name = cstr_from(name), .last = cstr_from(last)}; +} + +int Person_cmp(const Person* a, const Person* b) { + int c = cstr_cmp(&a->name, &b->name); + return c ? c : cstr_cmp(&a->last, &b->last); +} + +uint64_t Person_hash(const Person* a) { + return cstr_hash(&a->name) ^ cstr_hash(&a->last); +} + +Person Person_clone(Person p) { + p.name = cstr_clone(p.name); + p.last = cstr_clone(p.last); + return p; +} + +void Person_drop(Person* p) { + printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); + c_drop(cstr, &p->name, &p->last); +} + +#define i_type PSPtr +#define i_val_bind Person // binds Person_cmp, ... +#include <stc/carc.h> + +#define i_type Persons +#define i_val_arcbox PSPtr // binds PSPtr_cmp, ... +#include <stc/cvec.h> + + +int main() +{ + c_auto (Persons, vec) + c_auto (PSPtr, p, q) + { + p = PSPtr_make(Person_new("Laura", "Palmer")); + + // We want a deep copy -- PSPtr_clone(p) only shares! + q = PSPtr_make(Person_clone(*p.get)); + cstr_assign(&q.get->name, "Leland"); + + printf("orig: %s %s\n", cstr_str(&p.get->name), cstr_str(&p.get->last)); + printf("copy: %s %s\n", cstr_str(&q.get->name), cstr_str(&q.get->last)); + + Persons_push_back(&vec, PSPtr_make(Person_new("Dale", "Cooper"))); + Persons_push_back(&vec, PSPtr_make(Person_new("Audrey", "Home"))); + + // Clone/share p and q to the vector + c_apply(v, Persons_push_back(&vec, PSPtr_clone(*v)), PSPtr, {p, q}); + + c_foreach (i, Persons, vec) + printf("%s %s\n", cstr_str(&i.ref->get->name), cstr_str(&i.ref->get->last)); + puts(""); + + // Look-up Audrey! + c_autovar (Person a = Person_new("Audrey", "Home"), Person_drop(&a)) { + const PSPtr *v = Persons_get(&vec, a); + if (v) printf("found: %s %s\n", cstr_str(&v->get->name), cstr_str(&v->get->last)); + } + + puts(""); + } +} diff --git a/examples/phonebook.c b/examples/phonebook.c index ab782653..2368480c 100644 --- a/examples/phonebook.c +++ b/examples/phonebook.c @@ -1,81 +1,81 @@ -// The MIT License (MIT)
-// Copyright (c) 2018 Maksim Andrianov
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-// IN THE SOFTWARE.
-
-// Program to emulates the phone book.
-
-#define i_implement
-#include <stc/cstr.h>
-
-#define i_key_str
-#define i_val_str
-#include <stc/cmap.h>
-
-#define i_key_str
-#include <stc/cset.h>
-
-void print_phone_book(cmap_str phone_book)
-{
- c_foreach (i, cmap_str, phone_book)
- printf("%s\t- %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second));
-}
-
-int main(int argc, char **argv)
-{
- c_auto (cset_str, names) {
- c_apply(v, cset_str_emplace(&names, *v), const char*,
- {"Hello", "Cool", "True"});
- c_foreach (i, cset_str, names) printf("%s ", cstr_str(i.ref));
- puts("");
- }
-
- c_auto (cmap_str, phone_book) {
- c_apply(v, cmap_str_emplace(&phone_book, c_pair(v)), cmap_str_raw, {
- {"Lilia Friedman", "(892) 670-4739"},
- {"Tariq Beltran", "(489) 600-7575"},
- {"Laiba Juarez", "(303) 885-5692"},
- {"Elliott Mooney", "(945) 616-4482"},
- });
-
- printf("Phone book:\n");
- print_phone_book(phone_book);
-
- cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1880");
- cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1990");
-
- printf("\nPhone book after adding Zak Byers:\n");
- print_phone_book(phone_book);
-
- if (cmap_str_contains(&phone_book, "Tariq Beltran"))
- printf("\nTariq Beltran is in phone book\n");
-
- cmap_str_erase(&phone_book, "Tariq Beltran");
- cmap_str_erase(&phone_book, "Elliott Mooney");
-
- printf("\nPhone book after erasing Tariq and Elliott:\n");
- print_phone_book(phone_book);
-
- cmap_str_emplace_or_assign(&phone_book, "Zak Byers", "(555) 396-188");
-
- printf("\nPhone book after update phone of Zak Byers:\n");
- print_phone_book(phone_book);
- }
- puts("done");
-}
+// The MIT License (MIT) +// Copyright (c) 2018 Maksim Andrianov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +// Program to emulates the phone book. + +#define i_implement +#include <stc/cstr.h> + +#define i_key_str +#define i_val_str +#include <stc/cmap.h> + +#define i_key_str +#include <stc/cset.h> + +void print_phone_book(cmap_str phone_book) +{ + c_foreach (i, cmap_str, phone_book) + printf("%s\t- %s\n", cstr_str(&i.ref->first), cstr_str(&i.ref->second)); +} + +int main(int argc, char **argv) +{ + c_auto (cset_str, names) { + c_apply(v, cset_str_emplace(&names, *v), const char*, + {"Hello", "Cool", "True"}); + c_foreach (i, cset_str, names) printf("%s ", cstr_str(i.ref)); + puts(""); + } + + c_auto (cmap_str, phone_book) { + c_apply(v, cmap_str_emplace(&phone_book, c_pair(v)), cmap_str_raw, { + {"Lilia Friedman", "(892) 670-4739"}, + {"Tariq Beltran", "(489) 600-7575"}, + {"Laiba Juarez", "(303) 885-5692"}, + {"Elliott Mooney", "(945) 616-4482"}, + }); + + printf("Phone book:\n"); + print_phone_book(phone_book); + + cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1880"); + cmap_str_emplace(&phone_book, "Zak Byers", "(551) 396-1990"); + + printf("\nPhone book after adding Zak Byers:\n"); + print_phone_book(phone_book); + + if (cmap_str_contains(&phone_book, "Tariq Beltran")) + printf("\nTariq Beltran is in phone book\n"); + + cmap_str_erase(&phone_book, "Tariq Beltran"); + cmap_str_erase(&phone_book, "Elliott Mooney"); + + printf("\nPhone book after erasing Tariq and Elliott:\n"); + print_phone_book(phone_book); + + cmap_str_emplace_or_assign(&phone_book, "Zak Byers", "(555) 396-188"); + + printf("\nPhone book after update phone of Zak Byers:\n"); + print_phone_book(phone_book); + } + puts("done"); +} diff --git a/examples/prime.c b/examples/prime.c index 92fafde4..f235f845 100644 --- a/examples/prime.c +++ b/examples/prime.c @@ -1,42 +1,42 @@ -#include <stdio.h>
-#include <math.h>
-#include <time.h>
-#define i_implement
-#include <stc/cbits.h>
-
-cbits sieveOfEratosthenes(size_t n)
-{
- cbits bits = cbits_with_size(n/2 + 1, true);
- size_t q = (size_t) sqrt((double) n) + 1;
- for (size_t i = 3; i < q; i += 2) {
- size_t j = i;
- for (; j < n; j += 2) {
- if (cbits_test(&bits, j>>1)) {
- i = j;
- break;
- }
- }
- for (size_t j = i*i; j < n; j += i*2)
- cbits_reset(&bits, j>>1);
- }
- return bits;
-}
-
-int main(void)
-{
- size_t n = 1000000000;
- printf("computing prime numbers up to %" PRIuMAX "\n", n);
-
- clock_t t1 = clock();
- c_autovar (cbits primes = sieveOfEratosthenes(n + 1), cbits_drop(&primes)) {
- puts("done");
- size_t np = cbits_count(&primes);
- clock_t t2 = clock();
-
- printf("number of primes: %" PRIuMAX ", time: %f\n", np, (t2 - t1) / (float)CLOCKS_PER_SEC);
- printf("2");
- for (size_t i = 3; i < 1000; i += 2)
- if (cbits_test(&primes, i>>1)) printf(" %" PRIuMAX "", i);
- puts("");
- }
-}
+#include <stdio.h> +#include <math.h> +#include <time.h> +#define i_implement +#include <stc/cbits.h> + +cbits sieveOfEratosthenes(size_t n) +{ + cbits bits = cbits_with_size(n/2 + 1, true); + size_t q = (size_t) sqrt((double) n) + 1; + for (size_t i = 3; i < q; i += 2) { + size_t j = i; + for (; j < n; j += 2) { + if (cbits_test(&bits, j>>1)) { + i = j; + break; + } + } + for (size_t j = i*i; j < n; j += i*2) + cbits_reset(&bits, j>>1); + } + return bits; +} + +int main(void) +{ + size_t n = 1000000000; + printf("computing prime numbers up to %" PRIuMAX "\n", n); + + clock_t t1 = clock(); + c_autovar (cbits primes = sieveOfEratosthenes(n + 1), cbits_drop(&primes)) { + puts("done"); + size_t np = cbits_count(&primes); + clock_t t2 = clock(); + + printf("number of primes: %" PRIuMAX ", time: %f\n", np, (t2 - t1) / (float)CLOCKS_PER_SEC); + printf("2"); + for (size_t i = 3; i < 1000; i += 2) + if (cbits_test(&primes, i>>1)) printf(" %" PRIuMAX "", i); + puts(""); + } +} diff --git a/examples/priority.c b/examples/priority.c index 65543590..f4c45d76 100644 --- a/examples/priority.c +++ b/examples/priority.c @@ -1,35 +1,35 @@ -
-#include <stdio.h>
-#include <time.h>
-#define i_implement
-#include <stc/crandom.h>
-
-#define i_val int64_t
-#define i_cmp -c_default_cmp // min-heap (increasing values)
-#define i_tag i
-#include <stc/cpque.h>
-
-int main() {
- size_t N = 10000000;
- stc64_t rng = stc64_new(time(NULL));
- stc64_uniform_t dist = stc64_uniform_new(0, N * 10);
- c_auto (cpque_i, heap)
- {
- // Push ten million random numbers to priority queue
- printf("Push %" PRIuMAX " numbers\n", N);
- c_forrange (N)
- cpque_i_push(&heap, stc64_uniform(&rng, &dist));
-
- // push some negative numbers too.
- c_apply(v, cpque_i_push(&heap, *v), int, {-231, -32, -873, -4, -343});
-
- c_forrange (N)
- cpque_i_push(&heap, stc64_uniform(&rng, &dist));
-
- puts("Extract the hundred smallest.");
- c_forrange (100) {
- printf("%" PRIdMAX " ", *cpque_i_top(&heap));
- cpque_i_pop(&heap);
- }
- }
-}
+ +#include <stdio.h> +#include <time.h> +#define i_implement +#include <stc/crandom.h> + +#define i_val int64_t +#define i_cmp -c_default_cmp // min-heap (increasing values) +#define i_tag i +#include <stc/cpque.h> + +int main() { + size_t N = 10000000; + stc64_t rng = stc64_new(time(NULL)); + stc64_uniform_t dist = stc64_uniform_new(0, N * 10); + c_auto (cpque_i, heap) + { + // Push ten million random numbers to priority queue + printf("Push %" PRIuMAX " numbers\n", N); + c_forrange (N) + cpque_i_push(&heap, stc64_uniform(&rng, &dist)); + + // push some negative numbers too. + c_apply(v, cpque_i_push(&heap, *v), int, {-231, -32, -873, -4, -343}); + + c_forrange (N) + cpque_i_push(&heap, stc64_uniform(&rng, &dist)); + + puts("Extract the hundred smallest."); + c_forrange (100) { + printf("%" PRIdMAX " ", *cpque_i_top(&heap)); + cpque_i_pop(&heap); + } + } +} diff --git a/examples/queue.c b/examples/queue.c index 1b56d96a..57e24fe6 100644 --- a/examples/queue.c +++ b/examples/queue.c @@ -1,32 +1,32 @@ -#define i_implement
-#include <stc/crandom.h>
-#include <stdio.h>
-
-#define i_val int
-#define i_tag i
-#include <stc/cqueue.h>
-
-int main() {
- int n = 100000000;
- stc64_uniform_t dist;
- stc64_t rng = stc64_new(1234);
- dist = stc64_uniform_new(0, n);
-
- c_auto (cqueue_i, queue)
- {
- // Push ten million random numbers onto the queue.
- c_forrange (n)
- cqueue_i_push(&queue, stc64_uniform(&rng, &dist));
-
- // Push or pop on the queue ten million times
- printf("%d\n", n);
- c_forrange (n) { // forrange uses initial n only.
- int r = stc64_uniform(&rng, &dist);
- if (r & 1)
- ++n, cqueue_i_push(&queue, r);
- else
- --n, cqueue_i_pop(&queue);
- }
- printf("%d, %" PRIuMAX "\n", n, cqueue_i_size(queue));
- }
-}
+#define i_implement +#include <stc/crandom.h> +#include <stdio.h> + +#define i_val int +#define i_tag i +#include <stc/cqueue.h> + +int main() { + int n = 100000000; + stc64_uniform_t dist; + stc64_t rng = stc64_new(1234); + dist = stc64_uniform_new(0, n); + + c_auto (cqueue_i, queue) + { + // Push ten million random numbers onto the queue. + c_forrange (n) + cqueue_i_push(&queue, stc64_uniform(&rng, &dist)); + + // Push or pop on the queue ten million times + printf("%d\n", n); + c_forrange (n) { // forrange uses initial n only. + int r = stc64_uniform(&rng, &dist); + if (r & 1) + ++n, cqueue_i_push(&queue, r); + else + --n, cqueue_i_pop(&queue); + } + printf("%d, %" PRIuMAX "\n", n, cqueue_i_size(queue)); + } +} diff --git a/examples/random.c b/examples/random.c index 39fd7fa1..fc7745e5 100644 --- a/examples/random.c +++ b/examples/random.c @@ -1,43 +1,43 @@ -#include <stdio.h>
-#include <time.h>
-#define i_implement
-#include <stc/crandom.h>
-
-int main()
-{
- const size_t N = 1000000000;
- const uint64_t seed = time(NULL), range = 1000000;
- stc64_t rng = stc64_new(seed);
-
- uint64_t sum;
- clock_t diff, before;
-
- printf("Compare speed of full and unbiased ranged random numbers...\n");
- sum = 0;
- before = clock();
- c_forrange (N) {
- sum += (uint32_t) stc64_rand(&rng);
- }
- diff = clock() - before;
- printf("full range\t\t: %f secs, %" PRIuMAX ", avg: %f\n", (float) diff / CLOCKS_PER_SEC, N, (double) sum / N);
-
- stc64_uniform_t dist1 = stc64_uniform_new(0, range);
- rng = stc64_new(seed);
- sum = 0;
- before = clock();
- c_forrange (N) {
- sum += stc64_uniform(&rng, &dist1); // unbiased
- }
- diff = clock() - before;
- printf("unbiased 0-%" PRIuMAX "\t: %f secs, %" PRIuMAX ", avg: %f\n", range, (float) diff / CLOCKS_PER_SEC, N, (double) sum / N);
-
- sum = 0;
- rng = stc64_new(seed);
- before = clock();
- c_forrange (N) {
- sum += stc64_rand(&rng) % (range + 1); // biased
- }
- diff = clock() - before;
- printf("biased 0-%" PRIuMAX " \t: %f secs, %" PRIuMAX ", avg: %f\n", range, (float) diff / CLOCKS_PER_SEC, N, (double) sum / N);
-
-}
+#include <stdio.h> +#include <time.h> +#define i_implement +#include <stc/crandom.h> + +int main() +{ + const size_t N = 1000000000; + const uint64_t seed = time(NULL), range = 1000000; + stc64_t rng = stc64_new(seed); + + uint64_t sum; + clock_t diff, before; + + printf("Compare speed of full and unbiased ranged random numbers...\n"); + sum = 0; + before = clock(); + c_forrange (N) { + sum += (uint32_t) stc64_rand(&rng); + } + diff = clock() - before; + printf("full range\t\t: %f secs, %" PRIuMAX ", avg: %f\n", (float) diff / CLOCKS_PER_SEC, N, (double) sum / N); + + stc64_uniform_t dist1 = stc64_uniform_new(0, range); + rng = stc64_new(seed); + sum = 0; + before = clock(); + c_forrange (N) { + sum += stc64_uniform(&rng, &dist1); // unbiased + } + diff = clock() - before; + printf("unbiased 0-%" PRIuMAX "\t: %f secs, %" PRIuMAX ", avg: %f\n", range, (float) diff / CLOCKS_PER_SEC, N, (double) sum / N); + + sum = 0; + rng = stc64_new(seed); + before = clock(); + c_forrange (N) { + sum += stc64_rand(&rng) % (range + 1); // biased + } + diff = clock() - before; + printf("biased 0-%" PRIuMAX " \t: %f secs, %" PRIuMAX ", avg: %f\n", range, (float) diff / CLOCKS_PER_SEC, N, (double) sum / N); + +} diff --git a/examples/rawptr_elements.c b/examples/rawptr_elements.c index 64d73843..cfeb459d 100644 --- a/examples/rawptr_elements.c +++ b/examples/rawptr_elements.c @@ -1,68 +1,68 @@ -#include <stc/ccommon.h>
-#include <stdio.h>
-
-struct { double x, y; } typedef Point;
-
-// Set of Point pointers: define all template parameters "in-line"
-// Note it may be simpler to use a cbox for this.
-#define i_key Point*
-#define i_keydrop(x) c_free(*(x))
-#define i_keyclone(x) c_new(Point, *(x))
-#define i_hash(x) c_default_hash(*(x))
-#define i_cmp(x, y) memcmp(*(x), *(y), sizeof **(x)) // not good!
-#define i_tag pnt
-#include <stc/cset.h>
-
-#define i_implement
-#include <stc/cstr.h>
-// Map of int64 pointers: Define i_valraw as int64_t for easy emplace calls!
-typedef int64_t inttype;
-#define i_key_str
-#define i_val inttype*
-#define i_valraw inttype
-#define i_valfrom(raw) (puts("from"), c_new(inttype, raw))
-#define i_valto(x) (puts("to"), **(x))
-#define i_valclone c_derived_valclone // enables clone via valto+valfrom
-#define i_valdrop(x) c_free(*(x))
-#include <stc/cmap.h>
-
-int main()
-{
- c_auto (cset_pnt, set, cpy)
- {
- printf("Set with pointer elements:\n");
- // c++: set.insert(new Point{1.2, 3.4});
- cset_pnt_insert(&set, c_new(Point, {1.2, 3.4}));
- Point* q = *cset_pnt_insert(&set, c_new(Point, {6.1, 4.7})).ref;
- cset_pnt_insert(&set, c_new(Point, {5.7, 2.3}));
-
- cpy = cset_pnt_clone(set);
- cset_pnt_erase(&cpy, q);
-
- printf("set:");
- c_foreach (i, cset_pnt, set)
- printf(" (%g %g)", i.ref[0]->x, i.ref[0]->y);
-
- printf("\ncpy:");
- c_foreach (i, cset_pnt, cpy)
- printf(" (%g %g)", i.ref[0]->x, i.ref[0]->y);
- puts("");
- }
-
- c_auto (cmap_str, map, m2)
- {
- printf("\nMap with pointer elements:\n");
- cmap_str_insert(&map, cstr_new("testing"), c_new(inttype, 999));
- cmap_str_insert(&map, cstr_new("done"), c_new(inttype, 111));
-
- // Emplace: implicit key, val construction using i_keyfrom/i_valfrom:
- cmap_str_emplace(&map, "hello", 200);
- cmap_str_emplace(&map, "goodbye", 400);
-
- // default uses i_valfrom+i_valto when no i_valclone defined:
- m2 = cmap_str_clone(map);
-
- c_forpair (name, number, cmap_str, m2)
- printf("%s: %" PRIdMAX "\n", cstr_str(_.name), **_.number);
- }
-}
+#include <stc/ccommon.h> +#include <stdio.h> + +struct { double x, y; } typedef Point; + +// Set of Point pointers: define all template parameters "in-line" +// Note it may be simpler to use a cbox for this. +#define i_key Point* +#define i_keydrop(x) c_free(*(x)) +#define i_keyclone(x) c_new(Point, *(x)) +#define i_hash(x) c_default_hash(*(x)) +#define i_cmp(x, y) memcmp(*(x), *(y), sizeof **(x)) // not good! +#define i_tag pnt +#include <stc/cset.h> + +#define i_implement +#include <stc/cstr.h> +// Map of int64 pointers: Define i_valraw as int64_t for easy emplace calls! +typedef int64_t inttype; +#define i_key_str +#define i_val inttype* +#define i_valraw inttype +#define i_valfrom(raw) (puts("from"), c_new(inttype, raw)) +#define i_valto(x) (puts("to"), **(x)) +#define i_valclone c_derived_valclone // enables clone via valto+valfrom +#define i_valdrop(x) c_free(*(x)) +#include <stc/cmap.h> + +int main() +{ + c_auto (cset_pnt, set, cpy) + { + printf("Set with pointer elements:\n"); + // c++: set.insert(new Point{1.2, 3.4}); + cset_pnt_insert(&set, c_new(Point, {1.2, 3.4})); + Point* q = *cset_pnt_insert(&set, c_new(Point, {6.1, 4.7})).ref; + cset_pnt_insert(&set, c_new(Point, {5.7, 2.3})); + + cpy = cset_pnt_clone(set); + cset_pnt_erase(&cpy, q); + + printf("set:"); + c_foreach (i, cset_pnt, set) + printf(" (%g %g)", i.ref[0]->x, i.ref[0]->y); + + printf("\ncpy:"); + c_foreach (i, cset_pnt, cpy) + printf(" (%g %g)", i.ref[0]->x, i.ref[0]->y); + puts(""); + } + + c_auto (cmap_str, map, m2) + { + printf("\nMap with pointer elements:\n"); + cmap_str_insert(&map, cstr_new("testing"), c_new(inttype, 999)); + cmap_str_insert(&map, cstr_new("done"), c_new(inttype, 111)); + + // Emplace: implicit key, val construction using i_keyfrom/i_valfrom: + cmap_str_emplace(&map, "hello", 200); + cmap_str_emplace(&map, "goodbye", 400); + + // default uses i_valfrom+i_valto when no i_valclone defined: + m2 = cmap_str_clone(map); + + c_forpair (name, number, cmap_str, m2) + printf("%s: %" PRIdMAX "\n", cstr_str(_.name), **_.number); + } +} diff --git a/examples/read.c b/examples/read.c index 67b7e67e..74375a4f 100644 --- a/examples/read.c +++ b/examples/read.c @@ -1,26 +1,26 @@ -#define i_implement
-#include <stc/cstr.h>
-#define i_val_str
-#include <stc/cvec.h>
-#include <errno.h>
-
-cvec_str read_file(const char* name)
-{
- cvec_str vec = cvec_str_init();
- c_autovar (FILE* f = fopen(name, "r"), fclose(f))
- c_autovar (cstr line = cstr_init(), cstr_drop(&line))
- while (cstr_getline(&line, f))
- cvec_str_emplace_back(&vec, cstr_str(&line));
- return vec;
-}
-
-int main()
-{
- int n = 0;
- c_autovar (cvec_str vec = read_file(__FILE__), cvec_str_drop(&vec))
- c_foreach (i, cvec_str, vec)
- printf("%5d: %s\n", ++n, cstr_str(i.ref));
-
- if (errno)
- printf("error: read_file(" __FILE__ "). errno: %d\n", errno);
-}
+#define i_implement +#include <stc/cstr.h> +#define i_val_str +#include <stc/cvec.h> +#include <errno.h> + +cvec_str read_file(const char* name) +{ + cvec_str vec = cvec_str_init(); + c_autovar (FILE* f = fopen(name, "r"), fclose(f)) + c_autovar (cstr line = cstr_init(), cstr_drop(&line)) + while (cstr_getline(&line, f)) + cvec_str_emplace_back(&vec, cstr_str(&line)); + return vec; +} + +int main() +{ + int n = 0; + c_autovar (cvec_str vec = read_file(__FILE__), cvec_str_drop(&vec)) + c_foreach (i, cvec_str, vec) + printf("%5d: %s\n", ++n, cstr_str(i.ref)); + + if (errno) + printf("error: read_file(" __FILE__ "). errno: %d\n", errno); +} diff --git a/examples/replace.c b/examples/replace.c index 57018618..6084ede0 100644 --- a/examples/replace.c +++ b/examples/replace.c @@ -1,31 +1,31 @@ -#define i_implement
-#include <stc/cstr.h>
-
-int main ()
-{
- const char *base = "this is a test string.";
- const char *s2 = "n example";
- const char *s3 = "sample phrase";
-
- // replace signatures used in the same order as described above:
-
- // Ustring positions: 0123456789*123456789*12345
- cstr s = cstr_from(base); // "this is a test string."
- cstr m = cstr_clone(s);
- c_autodefer (cstr_drop(&s), cstr_drop(&m)) {
- cstr_append(&m, cstr_str(&m));
- cstr_append(&m, cstr_str(&m));
- printf("%s\n", cstr_str(&m));
-
- cstr_replace(&s, 9, 5, s2); // "this is an example string." (1)
- printf("(1) %s\n", cstr_str(&s));
- cstr_replace_n(&s, 19, 6, s3+7, 6); // "this is an example phrase." (2)
- printf("(2) %s\n", cstr_str(&s));
- cstr_replace(&s, 8, 10, "just a"); // "this is just a phrase." (3)
- printf("(3) %s\n", cstr_str(&s));
- cstr_replace_n(&s, 8, 6,"a shorty", 7); // "this is a short phrase." (4)
- printf("(4) %s\n", cstr_str(&s));
- cstr_replace(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5)
- printf("(5) %s\n", cstr_str(&s));
- }
-}
+#define i_implement +#include <stc/cstr.h> + +int main () +{ + const char *base = "this is a test string."; + const char *s2 = "n example"; + const char *s3 = "sample phrase"; + + // replace signatures used in the same order as described above: + + // Ustring positions: 0123456789*123456789*12345 + cstr s = cstr_from(base); // "this is a test string." + cstr m = cstr_clone(s); + c_autodefer (cstr_drop(&s), cstr_drop(&m)) { + cstr_append(&m, cstr_str(&m)); + cstr_append(&m, cstr_str(&m)); + printf("%s\n", cstr_str(&m)); + + cstr_replace(&s, 9, 5, s2); // "this is an example string." (1) + printf("(1) %s\n", cstr_str(&s)); + cstr_replace_n(&s, 19, 6, s3+7, 6); // "this is an example phrase." (2) + printf("(2) %s\n", cstr_str(&s)); + cstr_replace(&s, 8, 10, "just a"); // "this is just a phrase." (3) + printf("(3) %s\n", cstr_str(&s)); + cstr_replace_n(&s, 8, 6,"a shorty", 7); // "this is a short phrase." (4) + printf("(4) %s\n", cstr_str(&s)); + cstr_replace(&s, 22, 1, "!!!"); // "this is a short phrase!!!" (5) + printf("(5) %s\n", cstr_str(&s)); + } +} diff --git a/examples/shape.c b/examples/shape.c index d3534021..051e1c63 100644 --- a/examples/shape.c +++ b/examples/shape.c @@ -1,161 +1,161 @@ -// Demo of typesafe polymorphism in C99, using STC.
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stc/ccommon.h>
-
-#define c_dyn_ptr(T, s) \
- (&T##_api == (s)->api ? (T*)(s) : (T*)0)
-
-#define c_vtable(Api, T) \
- c_static_assert(offsetof(T, base) == 0); \
- static Api T##_api
-
-// Shape definition
-// ============================================================
-
-typedef struct {
- float x, y;
-} Point;
-
-typedef struct Shape Shape;
-
-struct ShapeAPI {
- void (*drop)(Shape*);
- void (*draw)(const Shape*);
-};
-
-struct Shape {
- struct ShapeAPI* api;
- uint32_t color;
- uint16_t style;
- uint8_t thickness;
- uint8_t hardness;
-};
-
-void Shape_drop(Shape* shape)
-{
- printf("base destructed\n");
-}
-
-void Shape_delete(Shape* shape)
-{
- if (shape) {
- shape->api->drop(shape);
- c_free(shape);
- }
-}
-
-// Triangle implementation
-// ============================================================
-
-typedef struct {
- Shape base;
- Point p[3];
-} Triangle;
-
-c_vtable(struct ShapeAPI, Triangle);
-
-
-Triangle* Triangle_new(Point a, Point b, Point c)
-{
- return c_new(Triangle, {{.api=&Triangle_api}, .p={a, b, c}});
-}
-
-static void Triangle_draw(const Shape* shape)
-{
- const Triangle* self = c_dyn_ptr(Triangle, shape);
- printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n",
- self->p[0].x, self->p[0].y,
- self->p[1].x, self->p[1].y,
- self->p[2].x, self->p[2].y);
-}
-
-static struct ShapeAPI Triangle_api = {
- .drop = Shape_drop,
- .draw = Triangle_draw,
-};
-
-// Polygon implementation
-// ============================================================
-
-#define i_type PointVec
-#define i_val Point
-#include <stc/cstack.h>
-
-typedef struct {
- Shape base;
- PointVec points;
-} Polygon;
-
-c_vtable(struct ShapeAPI, Polygon);
-
-
-Polygon* Polygon_new(void)
-{
- return c_new(Polygon, {{.api=&Polygon_api}, .points=PointVec_init()});
-}
-
-void Polygon_addPoint(Polygon* self, Point p)
-{
- PointVec_push(&self->points, p);
-}
-
-static void Polygon_drop(Shape* shape)
-{
- Polygon* self = c_dyn_ptr(Polygon, shape);
- printf("poly destructed\n");
- PointVec_drop(&self->points);
- Shape_drop(shape);
-}
-
-static void Polygon_draw(const Shape* shape)
-{
- const Polygon* self = c_dyn_ptr(Polygon, shape);
- printf("Polygon :");
- c_foreach (i, PointVec, self->points)
- printf(" (%g,%g)", i.ref->x, i.ref->y);
- puts("");
-}
-
-static struct ShapeAPI Polygon_api = {
- .drop = Polygon_drop,
- .draw = Polygon_draw,
-};
-
-// Test
-// ============================================================
-
-#define i_type Shapes
-#define i_val Shape*
-#define i_valdrop(x) Shape_delete(*x)
-#include <stc/cstack.h>
-
-void testShape(const Shape* shape)
-{
- shape->api->draw(shape);
-}
-
-
-int main(void)
-{
- c_auto (Shapes, shapes)
- {
- Triangle* tri1 = Triangle_new((Point){5, 7}, (Point){12, 7}, (Point){12, 20});
- Polygon* pol1 = Polygon_new();
- Polygon* pol2 = Polygon_new();
-
- c_apply(p, Polygon_addPoint(pol1, *p), Point,
- {{50, 72}, {123, 73}, {127, 201}, {828, 333}});
-
- c_apply(p, Polygon_addPoint(pol2, *p), Point,
- {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}});
-
- Shapes_push(&shapes, &tri1->base);
- Shapes_push(&shapes, &pol1->base);
- Shapes_push(&shapes, &pol2->base);
-
- c_foreach (i, Shapes, shapes)
- testShape(*i.ref);
- }
-}
+// Demo of typesafe polymorphism in C99, using STC. + +#include <stdlib.h> +#include <stdio.h> +#include <stc/ccommon.h> + +#define c_dyn_ptr(T, s) \ + (&T##_api == (s)->api ? (T*)(s) : (T*)0) + +#define c_vtable(Api, T) \ + c_static_assert(offsetof(T, base) == 0); \ + static Api T##_api + +// Shape definition +// ============================================================ + +typedef struct { + float x, y; +} Point; + +typedef struct Shape Shape; + +struct ShapeAPI { + void (*drop)(Shape*); + void (*draw)(const Shape*); +}; + +struct Shape { + struct ShapeAPI* api; + uint32_t color; + uint16_t style; + uint8_t thickness; + uint8_t hardness; +}; + +void Shape_drop(Shape* shape) +{ + printf("base destructed\n"); +} + +void Shape_delete(Shape* shape) +{ + if (shape) { + shape->api->drop(shape); + c_free(shape); + } +} + +// Triangle implementation +// ============================================================ + +typedef struct { + Shape base; + Point p[3]; +} Triangle; + +c_vtable(struct ShapeAPI, Triangle); + + +Triangle* Triangle_new(Point a, Point b, Point c) +{ + return c_new(Triangle, {{.api=&Triangle_api}, .p={a, b, c}}); +} + +static void Triangle_draw(const Shape* shape) +{ + const Triangle* self = c_dyn_ptr(Triangle, shape); + printf("Triangle : (%g,%g), (%g,%g), (%g,%g)\n", + self->p[0].x, self->p[0].y, + self->p[1].x, self->p[1].y, + self->p[2].x, self->p[2].y); +} + +static struct ShapeAPI Triangle_api = { + .drop = Shape_drop, + .draw = Triangle_draw, +}; + +// Polygon implementation +// ============================================================ + +#define i_type PointVec +#define i_val Point +#include <stc/cstack.h> + +typedef struct { + Shape base; + PointVec points; +} Polygon; + +c_vtable(struct ShapeAPI, Polygon); + + +Polygon* Polygon_new(void) +{ + return c_new(Polygon, {{.api=&Polygon_api}, .points=PointVec_init()}); +} + +void Polygon_addPoint(Polygon* self, Point p) +{ + PointVec_push(&self->points, p); +} + +static void Polygon_drop(Shape* shape) +{ + Polygon* self = c_dyn_ptr(Polygon, shape); + printf("poly destructed\n"); + PointVec_drop(&self->points); + Shape_drop(shape); +} + +static void Polygon_draw(const Shape* shape) +{ + const Polygon* self = c_dyn_ptr(Polygon, shape); + printf("Polygon :"); + c_foreach (i, PointVec, self->points) + printf(" (%g,%g)", i.ref->x, i.ref->y); + puts(""); +} + +static struct ShapeAPI Polygon_api = { + .drop = Polygon_drop, + .draw = Polygon_draw, +}; + +// Test +// ============================================================ + +#define i_type Shapes +#define i_val Shape* +#define i_valdrop(x) Shape_delete(*x) +#include <stc/cstack.h> + +void testShape(const Shape* shape) +{ + shape->api->draw(shape); +} + + +int main(void) +{ + c_auto (Shapes, shapes) + { + Triangle* tri1 = Triangle_new((Point){5, 7}, (Point){12, 7}, (Point){12, 20}); + Polygon* pol1 = Polygon_new(); + Polygon* pol2 = Polygon_new(); + + c_apply(p, Polygon_addPoint(pol1, *p), Point, + {{50, 72}, {123, 73}, {127, 201}, {828, 333}}); + + c_apply(p, Polygon_addPoint(pol2, *p), Point, + {{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}); + + Shapes_push(&shapes, &tri1->base); + Shapes_push(&shapes, &pol1->base); + Shapes_push(&shapes, &pol2->base); + + c_foreach (i, Shapes, shapes) + testShape(*i.ref); + } +} diff --git a/examples/shape.cpp b/examples/shape.cpp index b451b5ba..ea1f53d2 100644 --- a/examples/shape.cpp +++ b/examples/shape.cpp @@ -1,122 +1,122 @@ -// Demo of polymorphism in C++
-
-#include <iostream>
-#include <memory>
-#include <vector>
-
-// Shape definition
-// ============================================================
-
-struct Point {
- float x, y;
-};
-
-std::ostream& operator<<(std::ostream& os, const Point& p) {
- os << " (" << p.x << "," << p.y << ")";
- return os;
-}
-
-struct Shape {
- virtual ~Shape();
- virtual void draw() const = 0;
-
- uint32_t color;
- uint16_t style;
- uint8_t thickness;
- uint8_t hardness;
-};
-
-Shape::~Shape()
-{
- std::cout << "base destructed" << std::endl;
-}
-
-// Triangle implementation
-// ============================================================
-
-struct Triangle : public Shape
-{
- Triangle(Point a, Point b, Point c);
- void draw() const override;
-
- private: Point p[3];
-};
-
-
-Triangle::Triangle(Point a, Point b, Point c)
- : p{a, b, c} {}
-
-void Triangle::draw() const
-{
- std::cout << "Triangle :"
- << p[0] << p[1] << p[2]
- << std::endl;
-}
-
-
-// Polygon implementation
-// ============================================================
-
-
-struct Polygon : public Shape
-{
- ~Polygon();
- void draw() const override;
- void addPoint(const Point& p);
-
- private: std::vector<Point> points;
-};
-
-
-void Polygon::addPoint(const Point& p)
-{
- points.push_back(p);
-}
-
-Polygon::~Polygon()
-{
- std::cout << "poly destructed" << std::endl;
-}
-
-void Polygon::draw() const
-{
- std::cout << "Polygon :";
- for (auto& p : points)
- std::cout << p ;
- std::cout << std::endl;
-}
-
-
-// Test
-// ============================================================
-
-void testShape(const Shape* shape)
-{
- shape->draw();
-}
-
-#include <array>
-
-int main(void)
-{
- std::vector<std::unique_ptr<Shape>> shapes;
-
- auto tri1 = std::make_unique<Triangle>(Point{5, 7}, Point{12, 7}, Point{12, 20});
- auto pol1 = std::make_unique<Polygon>();
- auto pol2 = std::make_unique<Polygon>();
-
- for (auto& p: std::array<Point, 4>
- {{{50, 72}, {123, 73}, {127, 201}, {828, 333}}})
- pol1->addPoint(p);
-
- for (auto& p: std::array<Point, 5>
- {{{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}})
- pol2->addPoint(p);
-
- shapes.push_back(std::move(tri1));
- shapes.push_back(std::move(pol1));
- shapes.push_back(std::move(pol2));
-
- for (auto& shape: shapes)
- testShape(shape.get());
-}
+// Demo of polymorphism in C++ + +#include <iostream> +#include <memory> +#include <vector> + +// Shape definition +// ============================================================ + +struct Point { + float x, y; +}; + +std::ostream& operator<<(std::ostream& os, const Point& p) { + os << " (" << p.x << "," << p.y << ")"; + return os; +} + +struct Shape { + virtual ~Shape(); + virtual void draw() const = 0; + + uint32_t color; + uint16_t style; + uint8_t thickness; + uint8_t hardness; +}; + +Shape::~Shape() +{ + std::cout << "base destructed" << std::endl; +} + +// Triangle implementation +// ============================================================ + +struct Triangle : public Shape +{ + Triangle(Point a, Point b, Point c); + void draw() const override; + + private: Point p[3]; +}; + + +Triangle::Triangle(Point a, Point b, Point c) + : p{a, b, c} {} + +void Triangle::draw() const +{ + std::cout << "Triangle :" + << p[0] << p[1] << p[2] + << std::endl; +} + + +// Polygon implementation +// ============================================================ + + +struct Polygon : public Shape +{ + ~Polygon(); + void draw() const override; + void addPoint(const Point& p); + + private: std::vector<Point> points; +}; + + +void Polygon::addPoint(const Point& p) +{ + points.push_back(p); +} + +Polygon::~Polygon() +{ + std::cout << "poly destructed" << std::endl; +} + +void Polygon::draw() const +{ + std::cout << "Polygon :"; + for (auto& p : points) + std::cout << p ; + std::cout << std::endl; +} + + +// Test +// ============================================================ + +void testShape(const Shape* shape) +{ + shape->draw(); +} + +#include <array> + +int main(void) +{ + std::vector<std::unique_ptr<Shape>> shapes; + + auto tri1 = std::make_unique<Triangle>(Point{5, 7}, Point{12, 7}, Point{12, 20}); + auto pol1 = std::make_unique<Polygon>(); + auto pol2 = std::make_unique<Polygon>(); + + for (auto& p: std::array<Point, 4> + {{{50, 72}, {123, 73}, {127, 201}, {828, 333}}}) + pol1->addPoint(p); + + for (auto& p: std::array<Point, 5> + {{{5, 7}, {12, 7}, {12, 20}, {82, 33}, {17, 56}}}) + pol2->addPoint(p); + + shapes.push_back(std::move(tri1)); + shapes.push_back(std::move(pol1)); + shapes.push_back(std::move(pol2)); + + for (auto& shape: shapes) + testShape(shape.get()); +} diff --git a/examples/sidebyside.cpp b/examples/sidebyside.cpp index 89446b23..4d63496b 100644 --- a/examples/sidebyside.cpp +++ b/examples/sidebyside.cpp @@ -1,54 +1,54 @@ -#include <iostream>
-#include <map>
-#include <string>
-
-#define i_key_str
-#define i_val int
-#define i_tag si
-#include <stc/cmap.h>
-
-#define i_key int
-#define i_val int
-#define i_tag ii
-#include <stc/csmap.h>
-
-int main() {
- {
- std::map<std::string, int> food =
- {{"burger", 5}, {"pizza", 12}, {"steak", 15}};
-
- for (auto i: food)
- std::cout << i.first << ", " << i.second << std::endl;
- std::cout << std::endl;
- }
- c_auto (cmap_si, food)
- {
- c_apply(v, cmap_si_emplace(&food, c_pair(v)), cmap_si_raw,
- {{"burger", 5}, {"pizza", 12}, {"steak", 15}});
-
- c_foreach (i, cmap_si, food)
- printf("%s, %d\n", i.ref->first.str, i.ref->second);
- puts("");
- }
-
- {
- std::map<int, int> hist;
- ++ hist.emplace(12, 100).first->second;
- ++ hist.emplace(13, 100).first->second;
- ++ hist.emplace(12, 100).first->second;
-
- for (auto i: hist)
- std::cout << i.first << ", " << i.second << std::endl;
- std::cout << std::endl;
- }
- c_auto (csmap_ii, hist)
- {
- ++ csmap_ii_insert(&hist, 12, 100).ref->second;
- ++ csmap_ii_insert(&hist, 13, 100).ref->second;
- ++ csmap_ii_insert(&hist, 12, 100).ref->second;
-
- c_foreach (i, csmap_ii, hist)
- printf("%d, %d\n", i.ref->first, i.ref->second);
- puts("");
- }
-}
+#include <iostream> +#include <map> +#include <string> + +#define i_key_str +#define i_val int +#define i_tag si +#include <stc/cmap.h> + +#define i_key int +#define i_val int +#define i_tag ii +#include <stc/csmap.h> + +int main() { + { + std::map<std::string, int> food = + {{"burger", 5}, {"pizza", 12}, {"steak", 15}}; + + for (auto i: food) + std::cout << i.first << ", " << i.second << std::endl; + std::cout << std::endl; + } + c_auto (cmap_si, food) + { + c_apply(v, cmap_si_emplace(&food, c_pair(v)), cmap_si_raw, + {{"burger", 5}, {"pizza", 12}, {"steak", 15}}); + + c_foreach (i, cmap_si, food) + printf("%s, %d\n", i.ref->first.str, i.ref->second); + puts(""); + } + + { + std::map<int, int> hist; + ++ hist.emplace(12, 100).first->second; + ++ hist.emplace(13, 100).first->second; + ++ hist.emplace(12, 100).first->second; + + for (auto i: hist) + std::cout << i.first << ", " << i.second << std::endl; + std::cout << std::endl; + } + c_auto (csmap_ii, hist) + { + ++ csmap_ii_insert(&hist, 12, 100).ref->second; + ++ csmap_ii_insert(&hist, 13, 100).ref->second; + ++ csmap_ii_insert(&hist, 12, 100).ref->second; + + c_foreach (i, csmap_ii, hist) + printf("%d, %d\n", i.ref->first, i.ref->second); + puts(""); + } +} diff --git a/examples/splitstr.c b/examples/splitstr.c index 0cd48067..a155830c 100644 --- a/examples/splitstr.c +++ b/examples/splitstr.c @@ -1,39 +1,39 @@ -#define i_implement
-#include <stc/cstr.h>
-#define i_implement
-#include <stc/csview.h>
-#define i_val_str
-#include <stc/cvec.h>
-
-void print_split(csview str, csview sep)
-{
- size_t pos = 0;
- while (pos != str.size) {
- csview tok = csview_token(str, sep, &pos);
- // print non-null-terminated csview
- printf("[%" c_PRIsv "]\n", c_ARGsv(tok));
- }
-}
-
-cvec_str string_split(csview str, csview sep)
-{
- cvec_str vec = cvec_str_init();
- size_t pos = 0;
- while (pos != str.size) {
- csview tok = csview_token(str, sep, &pos);
- cvec_str_push_back(&vec, cstr_from_sv(tok));
- }
- return vec;
-}
-
-int main()
-{
- print_split(c_sv("//This is a//double-slash//separated//string"), c_sv("//"));
- puts("");
- print_split(c_sv("This has no matching separator"), c_sv("xx"));
- puts("");
-
- c_autovar (cvec_str v = string_split(c_sv("Split,this,,string,now,"), c_sv(",")), cvec_str_drop(&v))
- c_foreach (i, cvec_str, v)
- printf("[%s]\n", cstr_str(i.ref));
-}
+#define i_implement +#include <stc/cstr.h> +#define i_implement +#include <stc/csview.h> +#define i_val_str +#include <stc/cvec.h> + +void print_split(csview str, csview sep) +{ + size_t pos = 0; + while (pos != str.size) { + csview tok = csview_token(str, sep, &pos); + // print non-null-terminated csview + printf("[%" c_PRIsv "]\n", c_ARGsv(tok)); + } +} + +cvec_str string_split(csview str, csview sep) +{ + cvec_str vec = cvec_str_init(); + size_t pos = 0; + while (pos != str.size) { + csview tok = csview_token(str, sep, &pos); + cvec_str_push_back(&vec, cstr_from_sv(tok)); + } + return vec; +} + +int main() +{ + print_split(c_sv("//This is a//double-slash//separated//string"), c_sv("//")); + puts(""); + print_split(c_sv("This has no matching separator"), c_sv("xx")); + puts(""); + + c_autovar (cvec_str v = string_split(c_sv("Split,this,,string,now,"), c_sv(",")), cvec_str_drop(&v)) + c_foreach (i, cvec_str, v) + printf("[%s]\n", cstr_str(i.ref)); +} diff --git a/examples/sso_map.c b/examples/sso_map.c index 53fac3e3..823398e1 100644 --- a/examples/sso_map.c +++ b/examples/sso_map.c @@ -1,18 +1,18 @@ -#define i_implement
-#include <stc/cstr.h>
-#define i_key_str
-#define i_val_str
-#include <stc/cmap.h>
-
-int main()
-{
- c_auto (cmap_str, m) {
- cmap_str_emplace(&m, "Test short", "This is a short string.");
- cmap_str_emplace(&m, "Test long ", "This is a longer string.");
-
- c_forpair (k, v, cmap_str, m)
- printf("%s: '%s' Len=%" PRIuMAX ", Is long: %s\n",
- cstr_str(_.k), cstr_str(_.v), cstr_size(*_.v),
- cstr_is_long(_.v)?"true":"false");
- }
-}
+#define i_implement +#include <stc/cstr.h> +#define i_key_str +#define i_val_str +#include <stc/cmap.h> + +int main() +{ + c_auto (cmap_str, m) { + cmap_str_emplace(&m, "Test short", "This is a short string."); + cmap_str_emplace(&m, "Test long ", "This is a longer string."); + + c_forpair (k, v, cmap_str, m) + printf("%s: '%s' Len=%" PRIuMAX ", Is long: %s\n", + cstr_str(_.k), cstr_str(_.v), cstr_size(*_.v), + cstr_is_long(_.v)?"true":"false"); + } +} diff --git a/examples/stack.c b/examples/stack.c index 29b39aef..ca809c97 100644 --- a/examples/stack.c +++ b/examples/stack.c @@ -1,29 +1,29 @@ -
-#include <stdio.h>
-
-#define i_tag i
-#define i_val int
-#include <stc/cstack.h>
-
-#define i_tag c
-#define i_val char
-#include <stc/cstack.h>
-
-int main() {
- c_auto (cstack_i, stack)
- c_auto (cstack_c, chars)
- {
- c_forrange (i, int, 101)
- cstack_i_push(&stack, i*i);
-
- printf("%d\n", *cstack_i_top(&stack));
-
- c_forrange (i, int, 90)
- cstack_i_pop(&stack);
-
- c_foreach (i, cstack_i, stack)
- printf(" %d", *i.ref);
- puts("");
- printf("top: %d\n", *cstack_i_top(&stack));
- }
-}
+ +#include <stdio.h> + +#define i_tag i +#define i_val int +#include <stc/cstack.h> + +#define i_tag c +#define i_val char +#include <stc/cstack.h> + +int main() { + c_auto (cstack_i, stack) + c_auto (cstack_c, chars) + { + c_forrange (i, int, 101) + cstack_i_push(&stack, i*i); + + printf("%d\n", *cstack_i_top(&stack)); + + c_forrange (i, int, 90) + cstack_i_pop(&stack); + + c_foreach (i, cstack_i, stack) + printf(" %d", *i.ref); + puts(""); + printf("top: %d\n", *cstack_i_top(&stack)); + } +} diff --git a/examples/sview_split.c b/examples/sview_split.c index 8c3d7120..2c7ce395 100644 --- a/examples/sview_split.c +++ b/examples/sview_split.c @@ -1,21 +1,21 @@ -#define STC_IMPLEMENT
-#include <stc/cstr.h>
-#include <stc/csview.h>
-
-int main()
-{
- // No memory allocations or string length calculations!
- const csview date = c_sv("2021/03/12");
- size_t pos = 0;
- const csview year = csview_token(date, c_sv("/"), &pos);
- const csview month = csview_token(date, c_sv("/"), &pos);
- const csview day = csview_token(date, c_sv("/"), &pos);
-
- printf("%" c_PRIsv ", %" c_PRIsv ", %" c_PRIsv "\n",
- c_ARGsv(year), c_ARGsv(month), c_ARGsv(day));
-
- c_auto (cstr, y, m, d) {
- y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day);
- printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d));
- }
-}
+#define STC_IMPLEMENT +#include <stc/cstr.h> +#include <stc/csview.h> + +int main() +{ + // No memory allocations or string length calculations! + const csview date = c_sv("2021/03/12"); + size_t pos = 0; + const csview year = csview_token(date, c_sv("/"), &pos); + const csview month = csview_token(date, c_sv("/"), &pos); + const csview day = csview_token(date, c_sv("/"), &pos); + + printf("%" c_PRIsv ", %" c_PRIsv ", %" c_PRIsv "\n", + c_ARGsv(year), c_ARGsv(month), c_ARGsv(day)); + + c_auto (cstr, y, m, d) { + y = cstr_from_sv(year), m = cstr_from_sv(month), d = cstr_from_sv(day); + printf("%s, %s, %s\n", cstr_str(&y), cstr_str(&m), cstr_str(&d)); + } +} diff --git a/examples/unordered_map.c b/examples/unordered_map.c index 7af6fa0a..c4a05c76 100644 --- a/examples/unordered_map.c +++ b/examples/unordered_map.c @@ -1,64 +1,64 @@ -// https://iq.opengenus.org/containers-cpp-stl/
-
-#define i_key int
-#define i_val int
-#include <stc/csmap.h>
-#include <stdio.h>
-
-int main()
-{
-
- // empty map containers
- c_auto (csmap_int, gquiz1, gquiz2)
- {
- // insert elements in random order
- csmap_int_insert(&gquiz1, 2, 30);
- csmap_int_insert(&gquiz1, 4, 20);
- csmap_int_insert(&gquiz1, 7, 10);
- csmap_int_insert(&gquiz1, 5, 50);
- csmap_int_insert(&gquiz1, 3, 60);
- csmap_int_insert(&gquiz1, 1, 40);
- csmap_int_insert(&gquiz1, 6, 50);
-
- // printing map gquiz1
- printf("\nThe map gquiz1 is :\n\tKEY\tELEMENT\n");
- c_foreach (itr, csmap_int, gquiz1)
- printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
- printf("\n");
-
- // assigning the elements from gquiz1 to gquiz2
- c_foreach (i, csmap_int, gquiz1)
- csmap_int_insert(&gquiz2, i.ref->first, i.ref->second);
-
- // print all elements of the map gquiz2
- printf("\nThe map gquiz2 is :\n\tKEY\tELEMENT\n");
- c_foreach (itr, csmap_int, gquiz2)
- printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
- printf("\n");
-
- // remove all elements up to element with key=3 in gquiz2
- printf("\ngquiz2 after removal of elements less than key=3 :\n");
- printf("\tKEY\tELEMENT\n");
- csmap_int_erase_range(&gquiz2, csmap_int_begin(&gquiz2),
- csmap_int_find(&gquiz2, 3));
- c_foreach (itr, csmap_int, gquiz2)
- printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
- printf("\n");
-
- // remove all elements with key = 4
- int num = csmap_int_erase(&gquiz2, 4);
- printf("\ngquiz2.erase(4) : %d removed\n", num);
- printf("\tKEY\tELEMENT\n");
- c_foreach (itr, csmap_int, gquiz2)
- printf("\t%d\t%d\n", itr.ref->first, itr.ref->second);
- printf("\n");
-
- // lower bound and upper bound for map gquiz1 key = 5
- printf("gquiz1.lower_bound(5) : ");
- printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5).ref->first);
- printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5).ref->second);
- printf("gquiz1.upper_bound(5) : ");
- printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5+1).ref->first);
- printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5+1).ref->second);
- }
-}
+// https://iq.opengenus.org/containers-cpp-stl/ + +#define i_key int +#define i_val int +#include <stc/csmap.h> +#include <stdio.h> + +int main() +{ + + // empty map containers + c_auto (csmap_int, gquiz1, gquiz2) + { + // insert elements in random order + csmap_int_insert(&gquiz1, 2, 30); + csmap_int_insert(&gquiz1, 4, 20); + csmap_int_insert(&gquiz1, 7, 10); + csmap_int_insert(&gquiz1, 5, 50); + csmap_int_insert(&gquiz1, 3, 60); + csmap_int_insert(&gquiz1, 1, 40); + csmap_int_insert(&gquiz1, 6, 50); + + // printing map gquiz1 + printf("\nThe map gquiz1 is :\n\tKEY\tELEMENT\n"); + c_foreach (itr, csmap_int, gquiz1) + printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); + printf("\n"); + + // assigning the elements from gquiz1 to gquiz2 + c_foreach (i, csmap_int, gquiz1) + csmap_int_insert(&gquiz2, i.ref->first, i.ref->second); + + // print all elements of the map gquiz2 + printf("\nThe map gquiz2 is :\n\tKEY\tELEMENT\n"); + c_foreach (itr, csmap_int, gquiz2) + printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); + printf("\n"); + + // remove all elements up to element with key=3 in gquiz2 + printf("\ngquiz2 after removal of elements less than key=3 :\n"); + printf("\tKEY\tELEMENT\n"); + csmap_int_erase_range(&gquiz2, csmap_int_begin(&gquiz2), + csmap_int_find(&gquiz2, 3)); + c_foreach (itr, csmap_int, gquiz2) + printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); + printf("\n"); + + // remove all elements with key = 4 + int num = csmap_int_erase(&gquiz2, 4); + printf("\ngquiz2.erase(4) : %d removed\n", num); + printf("\tKEY\tELEMENT\n"); + c_foreach (itr, csmap_int, gquiz2) + printf("\t%d\t%d\n", itr.ref->first, itr.ref->second); + printf("\n"); + + // lower bound and upper bound for map gquiz1 key = 5 + printf("gquiz1.lower_bound(5) : "); + printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5).ref->first); + printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5).ref->second); + printf("gquiz1.upper_bound(5) : "); + printf("\tKEY = %d\t", csmap_int_lower_bound(&gquiz1, 5+1).ref->first); + printf("\tELEMENT = %d\n", csmap_int_lower_bound(&gquiz1, 5+1).ref->second); + } +} diff --git a/examples/unordered_set.c b/examples/unordered_set.c index 9ecd59fe..99a9da49 100644 --- a/examples/unordered_set.c +++ b/examples/unordered_set.c @@ -1,43 +1,43 @@ -// https://iq.opengenus.org/containers-cpp-stl/
-// C program to demonstrate various function of stc cset
-#define i_implement
-#include <stc/cstr.h>
-#define i_key_str
-#include <stc/cset.h>
-
-int main()
-{
- // declaring set for storing string data-type
- c_auto (cset_str, stringSet)
- {
- // inserting various string, same string will be stored
- // once in set
- cset_str_emplace(&stringSet, "code");
- cset_str_emplace(&stringSet, "in");
- cset_str_emplace(&stringSet, "C");
- cset_str_emplace(&stringSet, "is");
- cset_str_emplace(&stringSet, "fast");
-
- const char* key = "slow";
-
- // find returns end iterator if key is not found,
- // else it returns iterator to that key
-
- if (cset_str_find(&stringSet, key).ref == cset_str_end(&stringSet).ref)
- printf("\"%s\" not found\n", key);
- else
- printf("Found \"%s\"\n", key);
-
- key = "C";
- if (!cset_str_contains(&stringSet, key))
- printf("\"%s\" not found\n", key);
- else
- printf("Found \"%s\"\n", key);
-
- // now iterating over whole set and printing its
- // content
- printf("All elements :\n");
- c_foreach (itr, cset_str, stringSet)
- printf("%s\n", cstr_str(itr.ref));
- }
-}
+// https://iq.opengenus.org/containers-cpp-stl/ +// C program to demonstrate various function of stc cset +#define i_implement +#include <stc/cstr.h> +#define i_key_str +#include <stc/cset.h> + +int main() +{ + // declaring set for storing string data-type + c_auto (cset_str, stringSet) + { + // inserting various string, same string will be stored + // once in set + cset_str_emplace(&stringSet, "code"); + cset_str_emplace(&stringSet, "in"); + cset_str_emplace(&stringSet, "C"); + cset_str_emplace(&stringSet, "is"); + cset_str_emplace(&stringSet, "fast"); + + const char* key = "slow"; + + // find returns end iterator if key is not found, + // else it returns iterator to that key + + if (cset_str_find(&stringSet, key).ref == cset_str_end(&stringSet).ref) + printf("\"%s\" not found\n", key); + else + printf("Found \"%s\"\n", key); + + key = "C"; + if (!cset_str_contains(&stringSet, key)) + printf("\"%s\" not found\n", key); + else + printf("Found \"%s\"\n", key); + + // now iterating over whole set and printing its + // content + printf("All elements :\n"); + c_foreach (itr, cset_str, stringSet) + printf("%s\n", cstr_str(itr.ref)); + } +} diff --git a/include/stc/alt/csmap.h b/include/stc/alt/csmap.h index 1e6f1836..168cf480 100644 --- a/include/stc/alt/csmap.h +++ b/include/stc/alt/csmap.h @@ -1,512 +1,512 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-// Sorted/Ordered set and map - implemented as an AA-tree.
-/*
-#include <stdio.h>
-#include <stc/cstr.h>
-
-#define i_tag sx // Sorted map<cstr, double>
-#define i_key_str
-#define i_val double
-#include <stc/csmap.h>
-
-int main(void) {
- c_autovar (csmap_sx m = csmap_sx_init(), csmap_sx_drop(&m))
- {
- csmap_sx_emplace(&m, "Testing one", 1.234);
- csmap_sx_emplace(&m, "Testing two", 12.34);
- csmap_sx_emplace(&m, "Testing three", 123.4);
-
- csmap_sx_value *v = csmap_sx_get(&m, "Testing five"); // NULL
- double num = *csmap_sx_at(&m, "Testing one");
- csmap_sx_emplace_or_assign(&m, "Testing three", 1000.0); // update
- csmap_sx_erase(&m, "Testing two");
-
- c_foreach (i, csmap_sx, m)
- printf("map %s: %g\n", cstr_str(&i.ref->first), i.ref->second);
- }
-}
-*/
-#include <stc/ccommon.h>
-
-#ifndef CSMAP_H_INCLUDED
-#define STC_CSMAP_V1 1
-#include <stc/forward.h>
-#include <stdlib.h>
-#include <string.h>
-#endif // CSMAP_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix csmap_
-#endif
-#ifdef _i_isset
- #define _i_MAP_ONLY c_false
- #define _i_SET_ONLY c_true
- #define _i_keyref(vp) (vp)
-#else
- #define _i_ismap
- #define _i_MAP_ONLY c_true
- #define _i_SET_ONLY c_false
- #define _i_keyref(vp) (&(vp)->first)
-#endif
-#include <stc/template.h>
-
-#if !c_option(c_is_fwd)
-_cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_size, _i_MAP_ONLY, _i_SET_ONLY);
-#endif
-
-_i_MAP_ONLY( struct _cx_value {
- _cx_key first;
- _cx_mapped second;
-}; )
-struct _cx_node {
- struct _cx_node *link[2];
- uint8_t level;
- _cx_value value;
-};
-
-typedef i_keyraw _cx_rawkey;
-typedef i_valraw _cx_memb(_rawmapped);
-typedef _i_SET_ONLY( i_keyraw )
- _i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } )
- _cx_raw;
-
-#if !defined _i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
-#if !defined _i_no_emplace
-STC_API _cx_result _cx_memb(_emplace)(_cx_self* self, i_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped));
-#endif // !_i_no_emplace
-#endif // !_i_no_clone
-STC_API _cx_self _cx_memb(_init)(void);
-STC_API _cx_result _cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped));
-STC_API _cx_result _cx_memb(_push)(_cx_self* self, _cx_value _val);
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API _cx_value* _cx_memb(_find_it)(const _cx_self* self, i_keyraw rkey, _cx_iter* out);
-STC_API _cx_iter _cx_memb(_lower_bound)(const _cx_self* self, i_keyraw rkey);
-STC_API _cx_value* _cx_memb(_front)(const _cx_self* self);
-STC_API _cx_value* _cx_memb(_back)(const _cx_self* self);
-STC_API int _cx_memb(_erase)(_cx_self* self, i_keyraw rkey);
-STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it);
-STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2);
-STC_API void _cx_memb(_next)(_cx_iter* it);
-
-STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return cx.size == 0; }
-STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return cx.size; }
-STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); }
-STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, i_keyraw rkey)
- { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); return it; }
-STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, i_keyraw rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it) != NULL; }
-STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, i_keyraw rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
-STC_INLINE _cx_value* _cx_memb(_get_mut)(_cx_self* self, i_keyraw rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
-
-STC_INLINE void
-_cx_memb(_clear)(_cx_self* self)
- { _cx_memb(_drop)(self); *self = _cx_memb(_init)(); }
-
-STC_INLINE _cx_raw
-_cx_memb(_value_toraw)(_cx_value* val) {
- return _i_SET_ONLY( i_keyto(val) )
- _i_MAP_ONLY( c_make(_cx_raw){i_keyto((&val->first)),
- i_valto((&val->second))} );
-}
-
-STC_INLINE int
-_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- _cx_rawkey rx = i_keyto(_i_keyref(x)), ry = i_keyto(_i_keyref(y));
- return i_cmp((&rx), (&ry));
-}
-
-STC_INLINE void
-_cx_memb(_value_drop)(_cx_value* val) {
- i_keydrop(_i_keyref(val));
- _i_MAP_ONLY( i_valdrop((&val->second)); )
-}
-
-#if !defined _i_no_clone
-STC_INLINE _cx_value
-_cx_memb(_value_clone)(_cx_value _val) {
- *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val)));
- _i_MAP_ONLY( _val.second = i_valclone(_val.second); )
- return _val;
-}
-
-STC_INLINE void
-_cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->root == other.root)
- return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(other);
-}
-#endif // !_i_no_clone
-
-#ifndef _i_isset
- #if !defined _i_no_clone && !defined _i_no_emplace
- STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, i_keyraw rkey, i_valraw rmapped);
- #endif
- STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped);
-
- STC_INLINE const _cx_mapped*
- _cx_memb(_at)(const _cx_self* self, i_keyraw rkey)
- { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
- STC_INLINE _cx_mapped*
- _cx_memb(_at_mut)(_cx_self* self, i_keyraw rkey)
- { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
-#endif // !_i_isset
-
-STC_INLINE _cx_iter
-_cx_memb(_begin)(const _cx_self* self) {
- _cx_iter it;
- it.ref = NULL, it._top = 0, it._tn = self->root;
- _cx_memb(_next)(&it);
- return it;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_end)(const _cx_self* self) {
- (void)self;
- _cx_iter it; it.ref = NULL, it._top = 0, it._tn = NULL;
- return it;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_advance)(_cx_iter it, size_t n) {
- while (n-- && it.ref)
- _cx_memb(_next)(&it);
- return it;
-}
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-#ifndef CSMAP_H_INCLUDED
-static struct { void *link[2]; uint8_t level; }
-_csmap_sentinel = {{&_csmap_sentinel, &_csmap_sentinel}, 0};
-#endif
-
-static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, i_keyraw rkey);
-
-STC_DEF _cx_self
-_cx_memb(_init)(void) {
- _cx_self cx = {(_cx_node *)&_csmap_sentinel, 0};
- return cx;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_front)(const _cx_self* self) {
- _cx_node *tn = self->root;
- while (tn->link[0]->level)
- tn = tn->link[0];
- return &tn->value;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_back)(const _cx_self* self) {
- _cx_node *tn = self->root;
- while (tn->link[1]->level)
- tn = tn->link[1];
- return &tn->value;
-}
-
-STC_DEF _cx_result
-_cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped)) {
- _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key)));
- if (res.inserted)
- { *_i_keyref(res.ref) = key; _i_MAP_ONLY( res.ref->second = mapped; )}
- else
- { i_keydrop((&key)); _i_MAP_ONLY( i_valdrop((&mapped)); )}
- return res;
-}
-
-STC_DEF _cx_result
-_cx_memb(_push)(_cx_self* self, _cx_value _val) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
- if (_res.inserted)
- *_res.ref = _val;
- else
- _cx_memb(_value_drop)(&_val);
- return _res;
-}
-
-#ifndef _i_isset
- STC_DEF _cx_result
- _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped) {
- _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key)));
- if (res.inserted)
- res.ref->first = key;
- else
- { i_keydrop((&key)); i_valdrop((&res.ref->second)); }
- res.ref->second = mapped;
- return res;
- }
- #if !defined _i_no_clone && !defined _i_no_emplace
- STC_DEF _cx_result
- _cx_memb(_emplace_or_assign)(_cx_self* self, i_keyraw rkey, i_valraw rmapped) {
- _cx_result res = _cx_memb(_insert_entry_)(self, rkey);
- if (res.inserted)
- res.ref->first = i_keyfrom(rkey);
- else
- { i_valdrop((&res.ref->second)); }
- res.ref->second = i_valfrom(rmapped);
- return res;
- }
- #endif // !_i_no_clone && !_i_no_emplace
-#endif // !_i_isset
-
-STC_DEF _cx_value*
-_cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out) {
- _cx_node *tn = self->root;
- out->_top = 0;
- while (tn->level) {
- int c; _cx_rawkey raw = i_keyto(_i_keyref(&tn->value));
- if ((c = i_cmp((&raw), (&rkey))) < 0)
- tn = tn->link[1];
- else if (c > 0)
- { out->_st[out->_top++] = tn; tn = tn->link[0]; }
- else
- { out->_tn = tn->link[1]; return (out->ref = &tn->value); }
- }
- return (out->ref = NULL);
-}
-
-STC_DEF _cx_iter
-_cx_memb(_lower_bound)(const _cx_self* self, i_keyraw rkey) {
- _cx_iter it;
- _cx_memb(_find_it)(self, rkey, &it);
- if (!it.ref && it._top) {
- _cx_node *tn = it._st[--it._top];
- it._tn = tn->link[1];
- it.ref = &tn->value;
- }
- return it;
-}
-
-STC_DEF void
-_cx_memb(_next)(_cx_iter *it) {
- _cx_node *tn = it->_tn;
- if (it->_top || tn->level) {
- while (tn->level) {
- it->_st[it->_top++] = tn;
- tn = tn->link[0];
- }
- tn = it->_st[--it->_top];
- it->_tn = tn->link[1];
- it->ref = &tn->value;
- } else
- it->ref = NULL;
-}
-
-static _cx_node *
-_cx_memb(_skew_)(_cx_node *tn) {
- if (tn && tn->link[0]->level == tn->level && tn->level) {
- _cx_node *tmp = tn->link[0];
- tn->link[0] = tmp->link[1];
- tmp->link[1] = tn;
- tn = tmp;
- }
- return tn;
-}
-
-static _cx_node *
-_cx_memb(_split_)(_cx_node *tn) {
- if (tn->link[1]->link[1]->level == tn->level && tn->level) {
- _cx_node *tmp = tn->link[1];
- tn->link[1] = tmp->link[0];
- tmp->link[0] = tn;
- tn = tmp;
- ++tn->level;
- }
- return tn;
-}
-
-static _cx_node*
-_cx_memb(_insert_entry_i_)(_cx_node* tn, const _cx_rawkey* rkey, _cx_result* res) {
- _cx_node *up[64], *tx = tn;
- int c, top = 0, dir = 0;
- while (tx->level) {
- up[top++] = tx;
- _cx_rawkey r = i_keyto(_i_keyref(&tx->value));
- if (!(c = (i_cmp((&r), rkey))))
- { res->ref = &tx->value; return tn; }
- dir = (c < 0);
- tx = tx->link[dir];
- }
- tn = c_alloc(_cx_node);
- tn->link[0] = tn->link[1] = (_cx_node*)&_csmap_sentinel;
- tn->level = 1;
- res->ref = &tn->value, res->inserted = true;
- if (top == 0)
- return tn;
- up[top - 1]->link[dir] = tn;
- while (top--) {
- if (top)
- dir = (up[top - 1]->link[1] == up[top]);
- up[top] = _cx_memb(_skew_)(up[top]);
- up[top] = _cx_memb(_split_)(up[top]);
- if (top)
- up[top - 1]->link[dir] = up[top];
- }
- return up[0];
-}
-
-STC_DEF _cx_result
-_cx_memb(_insert_entry_)(_cx_self* self, i_keyraw rkey) {
- _cx_result res = {NULL};
- self->root = _cx_memb(_insert_entry_i_)(self->root, &rkey, &res);
- self->size += res.inserted;
- return res;
-}
-
-static _cx_node*
-_cx_memb(_erase_r_)(_cx_node *tn, const _cx_rawkey* rkey, int *erased) {
- if (tn->level == 0)
- return tn;
- _cx_rawkey raw = i_keyto(_i_keyref(&tn->value));
- _cx_node *tx; int c = (i_cmp((&raw), rkey));
- if (c != 0)
- tn->link[c < 0] = _cx_memb(_erase_r_)(tn->link[c < 0], rkey, erased);
- else {
- if (!*erased)
- { _cx_memb(_value_drop)(&tn->value); *erased = 1; }
- if (tn->link[0]->level && tn->link[1]->level) {
- tx = tn->link[0];
- while (tx->link[1]->level)
- tx = tx->link[1];
- tn->value = tx->value;
- raw = i_keyto(_i_keyref(&tn->value));
- tn->link[0] = _cx_memb(_erase_r_)(tn->link[0], &raw, erased);
- } else { /* unlink node */
- tx = tn;
- tn = tn->link[tn->link[0]->level == 0];
- c_free(tx);
- }
- }
- if (tn->link[0]->level < tn->level - 1 || tn->link[1]->level < tn->level - 1) {
- if (tn->link[1]->level > --tn->level)
- tn->link[1]->level = tn->level;
- tn = _cx_memb(_skew_)(tn);
- tx = tn->link[0] = _cx_memb(_skew_)(tn->link[0]);
- tx->link[0] = _cx_memb(_skew_)(tx->link[0]);
- tn = _cx_memb(_split_)(tn);
- tn->link[0] = _cx_memb(_split_)(tn->link[0]);
- }
- return tn;
-}
-
-STC_DEF int
-_cx_memb(_erase)(_cx_self* self, i_keyraw rkey) {
- int erased = 0;
- self->root = _cx_memb(_erase_r_)(self->root, &rkey, &erased);
- self->size -= erased;
- return erased;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- _cx_rawkey raw = i_keyto(_i_keyref(it.ref)), nxt;
- _cx_memb(_next)(&it);
- if (it.ref)
- nxt = i_keyto(_i_keyref(it.ref));
- _cx_memb(_erase)(self, raw);
- if (it.ref)
- _cx_memb(_find_it)(self, nxt, &it);
- return it;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
- if (!it2.ref) {
- while (it1.ref)
- it1 = _cx_memb(_erase_at)(self, it1);
- return it1;
- }
- _cx_key k1 = *_i_keyref(it1.ref), k2 = *_i_keyref(it2.ref);
- _cx_rawkey r1 = i_keyto((&k1));
- for (;;) {
- if (memcmp(&k1, &k2, sizeof k1) == 0)
- return it1;
- _cx_memb(_next)(&it1);
- k1 = *_i_keyref(it1.ref);
- _cx_memb(_erase)(self, r1);
- r1 = i_keyto((&k1));
- _cx_memb(_find_it)(self, r1, &it1);
- }
-}
-
-#if !defined _i_no_clone
-static _cx_node*
-_cx_memb(_clone_r_)(_cx_node *tn) {
- if (! tn->level)
- return tn;
- _cx_node *cn = c_alloc(_cx_node);
- cn->level = tn->level;
- cn->value = _cx_memb(_value_clone)(tn->value);
- cn->link[0] = _cx_memb(_clone_r_)(tn->link[0]);
- cn->link[1] = _cx_memb(_clone_r_)(tn->link[1]);
- return cn;
-}
-
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self cx) {
- return c_make(_cx_self){_cx_memb(_clone_r_)(cx.root), cx.size};
-}
-
-#if !defined _i_no_emplace
-STC_DEF _cx_result
-_cx_memb(_emplace)(_cx_self* self, i_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) {
- _cx_result res = _cx_memb(_insert_entry_)(self, rkey);
- if (res.inserted) {
- *_i_keyref(res.ref) = i_keyfrom(rkey);
- _i_MAP_ONLY(res.ref->second = i_valfrom(rmapped);)
- }
- return res;
-}
-#endif // _i_no_emplace
-#endif // !_i_no_clone
-
-static void
-_cx_memb(_drop_r_)(_cx_node* tn) {
- if (tn->level != 0) {
- _cx_memb(_drop_r_)(tn->link[0]);
- _cx_memb(_drop_r_)(tn->link[1]);
- _cx_memb(_value_drop)(&tn->value);
- c_free(tn);
- }
-}
-
-STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
- _cx_memb(_drop_r_)(self->root);
-}
-
-#endif // i_implement
-#undef _i_isset
-#undef _i_ismap
-#undef _i_keyref
-#undef _i_MAP_ONLY
-#undef _i_SET_ONLY
-#define CSMAP_H_INCLUDED
-#include <stc/template.h>
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// Sorted/Ordered set and map - implemented as an AA-tree. +/* +#include <stdio.h> +#include <stc/cstr.h> + +#define i_tag sx // Sorted map<cstr, double> +#define i_key_str +#define i_val double +#include <stc/csmap.h> + +int main(void) { + c_autovar (csmap_sx m = csmap_sx_init(), csmap_sx_drop(&m)) + { + csmap_sx_emplace(&m, "Testing one", 1.234); + csmap_sx_emplace(&m, "Testing two", 12.34); + csmap_sx_emplace(&m, "Testing three", 123.4); + + csmap_sx_value *v = csmap_sx_get(&m, "Testing five"); // NULL + double num = *csmap_sx_at(&m, "Testing one"); + csmap_sx_emplace_or_assign(&m, "Testing three", 1000.0); // update + csmap_sx_erase(&m, "Testing two"); + + c_foreach (i, csmap_sx, m) + printf("map %s: %g\n", cstr_str(&i.ref->first), i.ref->second); + } +} +*/ +#include <stc/ccommon.h> + +#ifndef CSMAP_H_INCLUDED +#define STC_CSMAP_V1 1 +#include <stc/forward.h> +#include <stdlib.h> +#include <string.h> +#endif // CSMAP_H_INCLUDED + +#ifndef _i_prefix +#define _i_prefix csmap_ +#endif +#ifdef _i_isset + #define _i_MAP_ONLY c_false + #define _i_SET_ONLY c_true + #define _i_keyref(vp) (vp) +#else + #define _i_ismap + #define _i_MAP_ONLY c_true + #define _i_SET_ONLY c_false + #define _i_keyref(vp) (&(vp)->first) +#endif +#include <stc/template.h> + +#if !c_option(c_is_fwd) +_cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_size, _i_MAP_ONLY, _i_SET_ONLY); +#endif + +_i_MAP_ONLY( struct _cx_value { + _cx_key first; + _cx_mapped second; +}; ) +struct _cx_node { + struct _cx_node *link[2]; + uint8_t level; + _cx_value value; +}; + +typedef i_keyraw _cx_rawkey; +typedef i_valraw _cx_memb(_rawmapped); +typedef _i_SET_ONLY( i_keyraw ) + _i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } ) + _cx_raw; + +#if !defined _i_no_clone +STC_API _cx_self _cx_memb(_clone)(_cx_self cx); +#if !defined _i_no_emplace +STC_API _cx_result _cx_memb(_emplace)(_cx_self* self, i_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)); +#endif // !_i_no_emplace +#endif // !_i_no_clone +STC_API _cx_self _cx_memb(_init)(void); +STC_API _cx_result _cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped)); +STC_API _cx_result _cx_memb(_push)(_cx_self* self, _cx_value _val); +STC_API void _cx_memb(_drop)(_cx_self* self); +STC_API _cx_value* _cx_memb(_find_it)(const _cx_self* self, i_keyraw rkey, _cx_iter* out); +STC_API _cx_iter _cx_memb(_lower_bound)(const _cx_self* self, i_keyraw rkey); +STC_API _cx_value* _cx_memb(_front)(const _cx_self* self); +STC_API _cx_value* _cx_memb(_back)(const _cx_self* self); +STC_API int _cx_memb(_erase)(_cx_self* self, i_keyraw rkey); +STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it); +STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2); +STC_API void _cx_memb(_next)(_cx_iter* it); + +STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return cx.size == 0; } +STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return cx.size; } +STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); } +STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, i_keyraw rkey) + { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); return it; } +STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, i_keyraw rkey) + { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it) != NULL; } +STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, i_keyraw rkey) + { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); } +STC_INLINE _cx_value* _cx_memb(_get_mut)(_cx_self* self, i_keyraw rkey) + { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); } + +STC_INLINE void +_cx_memb(_clear)(_cx_self* self) + { _cx_memb(_drop)(self); *self = _cx_memb(_init)(); } + +STC_INLINE _cx_raw +_cx_memb(_value_toraw)(_cx_value* val) { + return _i_SET_ONLY( i_keyto(val) ) + _i_MAP_ONLY( c_make(_cx_raw){i_keyto((&val->first)), + i_valto((&val->second))} ); +} + +STC_INLINE int +_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { + _cx_rawkey rx = i_keyto(_i_keyref(x)), ry = i_keyto(_i_keyref(y)); + return i_cmp((&rx), (&ry)); +} + +STC_INLINE void +_cx_memb(_value_drop)(_cx_value* val) { + i_keydrop(_i_keyref(val)); + _i_MAP_ONLY( i_valdrop((&val->second)); ) +} + +#if !defined _i_no_clone +STC_INLINE _cx_value +_cx_memb(_value_clone)(_cx_value _val) { + *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val))); + _i_MAP_ONLY( _val.second = i_valclone(_val.second); ) + return _val; +} + +STC_INLINE void +_cx_memb(_copy)(_cx_self *self, _cx_self other) { + if (self->root == other.root) + return; + _cx_memb(_drop)(self); + *self = _cx_memb(_clone)(other); +} +#endif // !_i_no_clone + +#ifndef _i_isset + #if !defined _i_no_clone && !defined _i_no_emplace + STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, i_keyraw rkey, i_valraw rmapped); + #endif + STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped); + + STC_INLINE const _cx_mapped* + _cx_memb(_at)(const _cx_self* self, i_keyraw rkey) + { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; } + STC_INLINE _cx_mapped* + _cx_memb(_at_mut)(_cx_self* self, i_keyraw rkey) + { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; } +#endif // !_i_isset + +STC_INLINE _cx_iter +_cx_memb(_begin)(const _cx_self* self) { + _cx_iter it; + it.ref = NULL, it._top = 0, it._tn = self->root; + _cx_memb(_next)(&it); + return it; +} + +STC_INLINE _cx_iter +_cx_memb(_end)(const _cx_self* self) { + (void)self; + _cx_iter it; it.ref = NULL, it._top = 0, it._tn = NULL; + return it; +} + +STC_INLINE _cx_iter +_cx_memb(_advance)(_cx_iter it, size_t n) { + while (n-- && it.ref) + _cx_memb(_next)(&it); + return it; +} + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) + +#ifndef CSMAP_H_INCLUDED +static struct { void *link[2]; uint8_t level; } +_csmap_sentinel = {{&_csmap_sentinel, &_csmap_sentinel}, 0}; +#endif + +static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, i_keyraw rkey); + +STC_DEF _cx_self +_cx_memb(_init)(void) { + _cx_self cx = {(_cx_node *)&_csmap_sentinel, 0}; + return cx; +} + +STC_DEF _cx_value* +_cx_memb(_front)(const _cx_self* self) { + _cx_node *tn = self->root; + while (tn->link[0]->level) + tn = tn->link[0]; + return &tn->value; +} + +STC_DEF _cx_value* +_cx_memb(_back)(const _cx_self* self) { + _cx_node *tn = self->root; + while (tn->link[1]->level) + tn = tn->link[1]; + return &tn->value; +} + +STC_DEF _cx_result +_cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped)) { + _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key))); + if (res.inserted) + { *_i_keyref(res.ref) = key; _i_MAP_ONLY( res.ref->second = mapped; )} + else + { i_keydrop((&key)); _i_MAP_ONLY( i_valdrop((&mapped)); )} + return res; +} + +STC_DEF _cx_result +_cx_memb(_push)(_cx_self* self, _cx_value _val) { + _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); + if (_res.inserted) + *_res.ref = _val; + else + _cx_memb(_value_drop)(&_val); + return _res; +} + +#ifndef _i_isset + STC_DEF _cx_result + _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped) { + _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key))); + if (res.inserted) + res.ref->first = key; + else + { i_keydrop((&key)); i_valdrop((&res.ref->second)); } + res.ref->second = mapped; + return res; + } + #if !defined _i_no_clone && !defined _i_no_emplace + STC_DEF _cx_result + _cx_memb(_emplace_or_assign)(_cx_self* self, i_keyraw rkey, i_valraw rmapped) { + _cx_result res = _cx_memb(_insert_entry_)(self, rkey); + if (res.inserted) + res.ref->first = i_keyfrom(rkey); + else + { i_valdrop((&res.ref->second)); } + res.ref->second = i_valfrom(rmapped); + return res; + } + #endif // !_i_no_clone && !_i_no_emplace +#endif // !_i_isset + +STC_DEF _cx_value* +_cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out) { + _cx_node *tn = self->root; + out->_top = 0; + while (tn->level) { + int c; _cx_rawkey raw = i_keyto(_i_keyref(&tn->value)); + if ((c = i_cmp((&raw), (&rkey))) < 0) + tn = tn->link[1]; + else if (c > 0) + { out->_st[out->_top++] = tn; tn = tn->link[0]; } + else + { out->_tn = tn->link[1]; return (out->ref = &tn->value); } + } + return (out->ref = NULL); +} + +STC_DEF _cx_iter +_cx_memb(_lower_bound)(const _cx_self* self, i_keyraw rkey) { + _cx_iter it; + _cx_memb(_find_it)(self, rkey, &it); + if (!it.ref && it._top) { + _cx_node *tn = it._st[--it._top]; + it._tn = tn->link[1]; + it.ref = &tn->value; + } + return it; +} + +STC_DEF void +_cx_memb(_next)(_cx_iter *it) { + _cx_node *tn = it->_tn; + if (it->_top || tn->level) { + while (tn->level) { + it->_st[it->_top++] = tn; + tn = tn->link[0]; + } + tn = it->_st[--it->_top]; + it->_tn = tn->link[1]; + it->ref = &tn->value; + } else + it->ref = NULL; +} + +static _cx_node * +_cx_memb(_skew_)(_cx_node *tn) { + if (tn && tn->link[0]->level == tn->level && tn->level) { + _cx_node *tmp = tn->link[0]; + tn->link[0] = tmp->link[1]; + tmp->link[1] = tn; + tn = tmp; + } + return tn; +} + +static _cx_node * +_cx_memb(_split_)(_cx_node *tn) { + if (tn->link[1]->link[1]->level == tn->level && tn->level) { + _cx_node *tmp = tn->link[1]; + tn->link[1] = tmp->link[0]; + tmp->link[0] = tn; + tn = tmp; + ++tn->level; + } + return tn; +} + +static _cx_node* +_cx_memb(_insert_entry_i_)(_cx_node* tn, const _cx_rawkey* rkey, _cx_result* res) { + _cx_node *up[64], *tx = tn; + int c, top = 0, dir = 0; + while (tx->level) { + up[top++] = tx; + _cx_rawkey r = i_keyto(_i_keyref(&tx->value)); + if (!(c = (i_cmp((&r), rkey)))) + { res->ref = &tx->value; return tn; } + dir = (c < 0); + tx = tx->link[dir]; + } + tn = c_alloc(_cx_node); + tn->link[0] = tn->link[1] = (_cx_node*)&_csmap_sentinel; + tn->level = 1; + res->ref = &tn->value, res->inserted = true; + if (top == 0) + return tn; + up[top - 1]->link[dir] = tn; + while (top--) { + if (top) + dir = (up[top - 1]->link[1] == up[top]); + up[top] = _cx_memb(_skew_)(up[top]); + up[top] = _cx_memb(_split_)(up[top]); + if (top) + up[top - 1]->link[dir] = up[top]; + } + return up[0]; +} + +STC_DEF _cx_result +_cx_memb(_insert_entry_)(_cx_self* self, i_keyraw rkey) { + _cx_result res = {NULL}; + self->root = _cx_memb(_insert_entry_i_)(self->root, &rkey, &res); + self->size += res.inserted; + return res; +} + +static _cx_node* +_cx_memb(_erase_r_)(_cx_node *tn, const _cx_rawkey* rkey, int *erased) { + if (tn->level == 0) + return tn; + _cx_rawkey raw = i_keyto(_i_keyref(&tn->value)); + _cx_node *tx; int c = (i_cmp((&raw), rkey)); + if (c != 0) + tn->link[c < 0] = _cx_memb(_erase_r_)(tn->link[c < 0], rkey, erased); + else { + if (!*erased) + { _cx_memb(_value_drop)(&tn->value); *erased = 1; } + if (tn->link[0]->level && tn->link[1]->level) { + tx = tn->link[0]; + while (tx->link[1]->level) + tx = tx->link[1]; + tn->value = tx->value; + raw = i_keyto(_i_keyref(&tn->value)); + tn->link[0] = _cx_memb(_erase_r_)(tn->link[0], &raw, erased); + } else { /* unlink node */ + tx = tn; + tn = tn->link[tn->link[0]->level == 0]; + c_free(tx); + } + } + if (tn->link[0]->level < tn->level - 1 || tn->link[1]->level < tn->level - 1) { + if (tn->link[1]->level > --tn->level) + tn->link[1]->level = tn->level; + tn = _cx_memb(_skew_)(tn); + tx = tn->link[0] = _cx_memb(_skew_)(tn->link[0]); + tx->link[0] = _cx_memb(_skew_)(tx->link[0]); + tn = _cx_memb(_split_)(tn); + tn->link[0] = _cx_memb(_split_)(tn->link[0]); + } + return tn; +} + +STC_DEF int +_cx_memb(_erase)(_cx_self* self, i_keyraw rkey) { + int erased = 0; + self->root = _cx_memb(_erase_r_)(self->root, &rkey, &erased); + self->size -= erased; + return erased; +} + +STC_DEF _cx_iter +_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { + _cx_rawkey raw = i_keyto(_i_keyref(it.ref)), nxt; + _cx_memb(_next)(&it); + if (it.ref) + nxt = i_keyto(_i_keyref(it.ref)); + _cx_memb(_erase)(self, raw); + if (it.ref) + _cx_memb(_find_it)(self, nxt, &it); + return it; +} + +STC_DEF _cx_iter +_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { + if (!it2.ref) { + while (it1.ref) + it1 = _cx_memb(_erase_at)(self, it1); + return it1; + } + _cx_key k1 = *_i_keyref(it1.ref), k2 = *_i_keyref(it2.ref); + _cx_rawkey r1 = i_keyto((&k1)); + for (;;) { + if (memcmp(&k1, &k2, sizeof k1) == 0) + return it1; + _cx_memb(_next)(&it1); + k1 = *_i_keyref(it1.ref); + _cx_memb(_erase)(self, r1); + r1 = i_keyto((&k1)); + _cx_memb(_find_it)(self, r1, &it1); + } +} + +#if !defined _i_no_clone +static _cx_node* +_cx_memb(_clone_r_)(_cx_node *tn) { + if (! tn->level) + return tn; + _cx_node *cn = c_alloc(_cx_node); + cn->level = tn->level; + cn->value = _cx_memb(_value_clone)(tn->value); + cn->link[0] = _cx_memb(_clone_r_)(tn->link[0]); + cn->link[1] = _cx_memb(_clone_r_)(tn->link[1]); + return cn; +} + +STC_DEF _cx_self +_cx_memb(_clone)(_cx_self cx) { + return c_make(_cx_self){_cx_memb(_clone_r_)(cx.root), cx.size}; +} + +#if !defined _i_no_emplace +STC_DEF _cx_result +_cx_memb(_emplace)(_cx_self* self, i_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) { + _cx_result res = _cx_memb(_insert_entry_)(self, rkey); + if (res.inserted) { + *_i_keyref(res.ref) = i_keyfrom(rkey); + _i_MAP_ONLY(res.ref->second = i_valfrom(rmapped);) + } + return res; +} +#endif // _i_no_emplace +#endif // !_i_no_clone + +static void +_cx_memb(_drop_r_)(_cx_node* tn) { + if (tn->level != 0) { + _cx_memb(_drop_r_)(tn->link[0]); + _cx_memb(_drop_r_)(tn->link[1]); + _cx_memb(_value_drop)(&tn->value); + c_free(tn); + } +} + +STC_DEF void +_cx_memb(_drop)(_cx_self* self) { + _cx_memb(_drop_r_)(self->root); +} + +#endif // i_implement +#undef _i_isset +#undef _i_ismap +#undef _i_keyref +#undef _i_MAP_ONLY +#undef _i_SET_ONLY +#define CSMAP_H_INCLUDED +#include <stc/template.h> diff --git a/include/stc/alt/cstr.h b/include/stc/alt/cstr.h index 0012d364..32dec09d 100644 --- a/include/stc/alt/cstr.h +++ b/include/stc/alt/cstr.h @@ -1,389 +1,389 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef CSTR_H_INCLUDED
-#define CSTR_H_INCLUDED
-#define STC_CSTR_V1 1
-
-#include <stc/ccommon.h>
-#include <stc/forward.h>
-#include <stdlib.h> /* malloc */
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h> /* vsnprintf */
-#include <ctype.h>
-
-#define cstr_npos (SIZE_MAX >> 1)
-typedef struct { size_t size, cap; char chr[1]; } cstr_priv;
-#define _cstr_p(self) c_unchecked_container_of((self)->str, cstr_priv, chr)
-#ifdef i_static
- static cstr_priv _cstr_nullrep = {0, 0, {0}};
- static const cstr cstr_null = {_cstr_nullrep.chr};
-#else
- extern const cstr cstr_null;
-#endif
-/* optimal memory: based on malloc_usable_size() sequence: 24, 40, 56, ... */
-#define _cstr_opt_mem(cap) ((((offsetof(cstr_priv, chr) + (cap) + 8)>>4)<<4) + 8)
-/* optimal string capacity: 7, 23, 39, ... */
-#define _cstr_opt_cap(cap) (_cstr_opt_mem(cap) - offsetof(cstr_priv, chr) - 1)
-
-STC_API cstr cstr_from_n(const char* str, size_t n);
-STC_API cstr cstr_from_fmt(const char* fmt, ...);
-STC_API cstr cstr_from_replace_all(const char* str, size_t str_len,
- const char* find, size_t find_len,
- const char* repl, size_t repl_len);
-STC_API char* cstr_reserve(cstr* self, size_t cap);
-STC_API void cstr_resize(cstr* self, size_t len, char fill);
-STC_API cstr* cstr_assign_n(cstr* self, const char* str, size_t n);
-STC_API int cstr_printf(cstr* self, const char* fmt, ...);
-STC_API cstr* cstr_append_n(cstr* self, const char* str, size_t n);
-STC_API void cstr_replace_n(cstr* self, size_t pos, size_t len, const char* str, size_t n);
-STC_API void cstr_replace_all(cstr* self, const char* find, const char* replace);
-STC_API void cstr_erase_n(cstr* self, size_t pos, size_t n);
-STC_API size_t cstr_find(cstr s, const char* needle);
-STC_API size_t cstr_find_from(cstr s, size_t pos, const char* needle);
-STC_API bool cstr_getdelim(cstr *self, int delim, FILE *stream);
-STC_API void cstr_replace_all(cstr* self, const char* find, const char* repl);
-
-STC_INLINE cstr cstr_init() { return cstr_null; }
-STC_INLINE const char* cstr_str(const cstr* self) { return self->str; }
-#define cstr_toraw(self) (self)->str
-STC_INLINE csview cstr_sv(const cstr* self)
- { return c_make(csview){self->str, _cstr_p(self)->size}; }
-#define cstr_new(literal) \
- cstr_from_n(literal, c_strlen_lit(literal))
-STC_INLINE cstr cstr_from(const char* str)
- { return cstr_from_n(str, strlen(str)); }
-STC_INLINE char* cstr_data(cstr* self) { return self->str; }
-STC_INLINE size_t cstr_size(cstr s) { return _cstr_p(&s)->size; }
-STC_INLINE size_t cstr_length(cstr s) { return _cstr_p(&s)->size; }
-STC_INLINE size_t cstr_capacity(cstr s) { return _cstr_p(&s)->cap; }
-STC_INLINE bool cstr_empty(cstr s) { return _cstr_p(&s)->size == 0; }
-STC_INLINE void cstr_drop(cstr* self)
- { if (_cstr_p(self)->cap) c_free(_cstr_p(self)); }
-STC_INLINE cstr cstr_clone(cstr s)
- { return cstr_from_n(s.str, _cstr_p(&s)->size); }
-STC_INLINE void cstr_clear(cstr* self)
- { self->str[_cstr_p(self)->size = 0] = '\0'; }
-STC_INLINE cstr* cstr_assign(cstr* self, const char* str)
- { return cstr_assign_n(self, str, strlen(str)); }
-STC_INLINE cstr* cstr_copy(cstr* self, cstr s)
- { return cstr_assign_n(self, s.str, _cstr_p(&s)->size); }
-STC_INLINE cstr* cstr_append(cstr* self, const char* str)
- { return cstr_append_n(self, str, strlen(str)); }
-STC_INLINE cstr* cstr_append_s(cstr* self, cstr s)
- { return cstr_append_n(self, s.str, _cstr_p(&s)->size); }
-STC_INLINE void cstr_push_back(cstr* self, char value)
- { cstr_append_n(self, &value, 1); }
-STC_INLINE void cstr_pop_back(cstr* self)
- { self->str[ --_cstr_p(self)->size ] = '\0'; }
-STC_INLINE void cstr_insert_n(cstr* self, const size_t pos, const char* str, const size_t n)
- { cstr_replace_n(self, pos, 0, str, n); }
-STC_INLINE void cstr_insert(cstr* self, const size_t pos, const char* str)
- { cstr_replace_n(self, pos, 0, str, strlen(str)); }
-STC_INLINE void cstr_insert_s(cstr* self, const size_t pos, cstr s)
- { cstr_replace_n(self, pos, 0, s.str, _cstr_p(&s)->size); }
-STC_INLINE void cstr_replace(cstr* self, const size_t pos, const size_t len, const char* str)
- { cstr_replace_n(self, pos, len, str, strlen(str)); }
-STC_INLINE void cstr_replace_s(cstr* self, const size_t pos, const size_t len, cstr s)
- { cstr_replace_n(self, pos, len, s.str, _cstr_p(&s)->size); }
-STC_INLINE void cstr_erase(cstr* self, const size_t pos)
- { cstr_erase_n(self, pos, 1); }
-STC_INLINE char* cstr_front(cstr* self) { return self->str; }
-STC_INLINE char* cstr_back(cstr* self)
- { return self->str + _cstr_p(self)->size - 1; }
-STC_INLINE bool cstr_equals(cstr s, const char* str)
- { return strcmp(s.str, str) == 0; }
-STC_INLINE bool cstr_equals_s(cstr s1, cstr s2)
- { return strcmp(s1.str, s2.str) == 0; }
-STC_INLINE bool cstr_contains(cstr s, const char* needle)
- { return strstr(s.str, needle) != NULL; }
-STC_INLINE bool cstr_getline(cstr *self, FILE *stream)
- { return cstr_getdelim(self, '\n', stream); }
-
-STC_INLINE cstr_buf cstr_buffer(cstr* s) {
- cstr_priv* p = _cstr_p(s);
- return c_make(cstr_buf){s->str, p->size, p->cap};
-}
-
-STC_INLINE cstr cstr_with_capacity(const size_t cap) {
- cstr s = cstr_null;
- cstr_reserve(&s, cap);
- return s;
-}
-
-STC_INLINE cstr cstr_with_size(const size_t len, const char fill) {
- cstr s = cstr_null;
- cstr_resize(&s, len, fill);
- return s;
-}
-
-STC_INLINE char* cstr_expand_uninit(cstr *self, size_t n) {
- size_t len = cstr_size(*self); char* d;
- if (!(d = cstr_reserve(self, len + n))) return NULL;
- _cstr_p(self)->size += n;
- return d + len;
-}
-
-STC_INLINE cstr* cstr_take(cstr* self, cstr s) {
- if (self->str != s.str && _cstr_p(self)->cap)
- c_free(_cstr_p(self));
- self->str = s.str;
- return self;
-}
-
-STC_INLINE cstr cstr_move(cstr* self) {
- cstr tmp = *self;
- *self = cstr_null;
- return tmp;
-}
-
-STC_INLINE bool cstr_starts_with(cstr s, const char* sub) {
- while (*sub && *s.str == *sub) ++s.str, ++sub;
- return *sub == 0;
-}
-
-STC_INLINE bool cstr_ends_with(cstr s, const char* sub) {
- const size_t n = strlen(sub), sz = _cstr_p(&s)->size;
- return n <= sz && !memcmp(s.str + sz - n, sub, n);
-}
-
-STC_INLINE int c_strncasecmp(const char* s1, const char* s2, size_t nmax) {
- int ret = 0;
- while (nmax-- && (ret = tolower(*s1++) - tolower(*s2)) == 0 && *s2++)
- ;
- return ret;
-}
-
-/* container adaptor functions: */
-#define cstr_cmp(xp, yp) strcmp((xp)->str, (yp)->str)
-
-STC_INLINE bool cstr_eq(const cstr* x, const cstr* y) {
- size_t xs = _cstr_p(x)->size, ys = _cstr_p(y)->size;
- return xs == ys && !memcmp(x->str, y->str, xs);
-}
-STC_INLINE uint64_t cstr_hash(const cstr *self) {
- return c_fasthash(self->str, _cstr_p(self)->size);
-}
-
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-#ifndef i_static
-static cstr_priv _cstr_nullrep = {0, 0, {0}};
-const cstr cstr_null = {_cstr_nullrep.chr};
-#endif
-
-STC_DEF char*
-cstr_reserve(cstr* self, const size_t cap) {
- cstr_priv *p = _cstr_p(self);
- const size_t oldcap = p->cap;
- if (cap > oldcap) {
- p = (cstr_priv*) c_realloc(((oldcap != 0) & (p != &_cstr_nullrep)) ? p : NULL, _cstr_opt_mem(cap));
- if (!p) return NULL;
- self->str = p->chr;
- if (oldcap == 0) self->str[p->size = 0] = '\0';
- p->cap = _cstr_opt_cap(cap);
- }
- return self->str;
-}
-
-STC_DEF void
-cstr_resize(cstr* self, const size_t len, const char fill) {
- const size_t n = _cstr_p(self)->size;
- cstr_reserve(self, len);
- if (len > n) memset(self->str + n, fill, len - n);
- if (len | n) self->str[_cstr_p(self)->size = len] = '\0';
-}
-
-STC_DEF cstr
-cstr_from_n(const char* str, const size_t n) {
- if (n == 0) return cstr_null;
- cstr_priv* prv = (cstr_priv*) c_malloc(_cstr_opt_mem(n));
- cstr s = {(char *) memcpy(prv->chr, str, n)};
- s.str[prv->size = n] = '\0';
- prv->cap = _cstr_opt_cap(n);
- return s;
-}
-
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wdeprecated-declarations"
-#elif defined(_MSC_VER)
-# pragma warning(push)
-# pragma warning(disable: 4996)
-#endif
-
-STC_DEF int
-cstr_vfmt(cstr* self, const char* fmt, va_list args) {
- va_list args2;
- va_copy(args2, args);
- int len = vsnprintf(NULL, (size_t)0, fmt, args);
- cstr_reserve(self, len);
- vsprintf(self->str, fmt, args2);
- va_end(args2);
- return _cstr_p(self)->size = len;
-}
-
-#if defined(__clang__)
-# pragma clang diagnostic pop
-#elif defined(_MSC_VER)
-# pragma warning(pop)
-#endif
-
-STC_DEF cstr
-cstr_from_fmt(const char* fmt, ...) {
- cstr ret = cstr_null;
- va_list args; va_start(args, fmt);
- cstr_vfmt(&ret, fmt, args);
- va_end(args);
- return ret;
-}
-
-STC_DEF int
-cstr_printf(cstr* self, const char* fmt, ...) {
- cstr ret = cstr_null;
- va_list args;
- va_start(args, fmt);
- int n = cstr_vfmt(&ret, fmt, args);
- va_end(args);
- cstr_drop(self);
- *self = ret;
- return n;
-}
-
-STC_DEF cstr*
-cstr_assign_n(cstr* self, const char* str, const size_t n) {
- if (n || _cstr_p(self)->cap) {
- cstr_reserve(self, n);
- memmove(self->str, str, n);
- self->str[_cstr_p(self)->size = n] = '\0';
- }
- return self;
-}
-
-STC_DEF cstr*
-cstr_append_n(cstr* self, const char* str, const size_t n) {
- if (n == 0) return self;
- const size_t oldlen = _cstr_p(self)->size, newlen = oldlen + n;
- if (newlen > _cstr_p(self)->cap) {
- const size_t off = (size_t) (str - self->str); /* handle self append */
- cstr_reserve(self, (oldlen*3 >> 1) + n);
- if (off <= oldlen) str = self->str + off;
- }
- memcpy(&self->str[oldlen], str, n);
- self->str[_cstr_p(self)->size = newlen] = '\0';
- return self;
-}
-
-STC_INLINE void _cstr_internal_move(cstr* self, const size_t pos1, const size_t pos2) {
- if (pos1 == pos2)
- return;
- const size_t len = _cstr_p(self)->size, newlen = len + pos2 - pos1;
- if (newlen > _cstr_p(self)->cap)
- cstr_reserve(self, (len*3 >> 1) + pos2 - pos1);
- memmove(&self->str[pos2], &self->str[pos1], len - pos1);
- self->str[_cstr_p(self)->size = newlen] = '\0';
-}
-
-STC_DEF void
-cstr_replace_n(cstr* self, const size_t pos, size_t len, const char* str, const size_t n) {
- const size_t sz = cstr_size(*self);
- if (len > sz - pos) len = sz - pos;
- c_autobuf (xstr, char, n) {
- memcpy(xstr, str, n);
- _cstr_internal_move(self, pos + len, pos + n);
- memcpy(&self->str[pos], xstr, n);
- }
-}
-
-STC_DEF cstr
-cstr_from_replace_all(const char* str, const size_t str_len,
- const char* find, const size_t find_len,
- const char* repl, const size_t repl_len) {
- cstr out = cstr_null;
- size_t from = 0; char* res;
- if (find_len)
- while ((res = c_strnstrn(str + from, find, str_len - from, find_len))) {
- const size_t pos = res - str;
- cstr_append_n(&out, str + from, pos - from);
- cstr_append_n(&out, repl, repl_len);
- from = pos + find_len;
- }
- cstr_append_n(&out, str + from, str_len - from);
- return out;
-}
-
-STC_DEF void
-cstr_replace_all(cstr* self, const char* find, const char* repl) {
- cstr_take(self, cstr_from_replace_all(self->str, _cstr_p(self)->size,
- find, strlen(find), repl, strlen(repl)));
-}
-
-STC_DEF void
-cstr_erase_n(cstr* self, const size_t pos, size_t n) {
- const size_t len = _cstr_p(self)->size;
- if (n > len - pos) n = len - pos;
- if (len) {
- memmove(&self->str[pos], &self->str[pos + n], len - (pos + n));
- self->str[_cstr_p(self)->size -= n] = '\0';
- }
-}
-
-STC_DEF bool
-cstr_getdelim(cstr *self, const int delim, FILE *fp) {
- size_t pos = 0, cap = _cstr_p(self)->cap;
- char* d = self->str;
- int c = fgetc(fp);
- if (c == EOF)
- return false;
- for (;;) {
- if (c == delim || c == EOF) {
- if (cap) d[_cstr_p(self)->size = pos] = '\0';
- return true;
- }
- if (pos == cap) {
- d = cstr_reserve(self, (cap*3 >> 1) + 16);
- cap = cstr_capacity(*self);
- }
- d[pos++] = (char) c;
- c = fgetc(fp);
- }
-}
-
-STC_DEF size_t
-cstr_find(cstr s, const char* needle) {
- char* res = strstr(s.str, needle);
- return res ? res - s.str : cstr_npos;
-}
-
-STC_DEF size_t
-cstr_find_from(cstr s, const size_t pos, const char* needle) {
- if (pos > _cstr_p(&s)->size) return cstr_npos;
- char* res = strstr(s.str + pos, needle);
- return res ? res - s.str : cstr_npos;
-}
-
-#endif
-#endif // CSTR_H_INCLUDED
-#undef i_opt
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef CSTR_H_INCLUDED +#define CSTR_H_INCLUDED +#define STC_CSTR_V1 1 + +#include <stc/ccommon.h> +#include <stc/forward.h> +#include <stdlib.h> /* malloc */ +#include <string.h> +#include <stdarg.h> +#include <stdio.h> /* vsnprintf */ +#include <ctype.h> + +#define cstr_npos (SIZE_MAX >> 1) +typedef struct { size_t size, cap; char chr[1]; } cstr_priv; +#define _cstr_p(self) c_unchecked_container_of((self)->str, cstr_priv, chr) +#ifdef i_static + static cstr_priv _cstr_nullrep = {0, 0, {0}}; + static const cstr cstr_null = {_cstr_nullrep.chr}; +#else + extern const cstr cstr_null; +#endif +/* optimal memory: based on malloc_usable_size() sequence: 24, 40, 56, ... */ +#define _cstr_opt_mem(cap) ((((offsetof(cstr_priv, chr) + (cap) + 8)>>4)<<4) + 8) +/* optimal string capacity: 7, 23, 39, ... */ +#define _cstr_opt_cap(cap) (_cstr_opt_mem(cap) - offsetof(cstr_priv, chr) - 1) + +STC_API cstr cstr_from_n(const char* str, size_t n); +STC_API cstr cstr_from_fmt(const char* fmt, ...); +STC_API cstr cstr_from_replace_all(const char* str, size_t str_len, + const char* find, size_t find_len, + const char* repl, size_t repl_len); +STC_API char* cstr_reserve(cstr* self, size_t cap); +STC_API void cstr_resize(cstr* self, size_t len, char fill); +STC_API cstr* cstr_assign_n(cstr* self, const char* str, size_t n); +STC_API int cstr_printf(cstr* self, const char* fmt, ...); +STC_API cstr* cstr_append_n(cstr* self, const char* str, size_t n); +STC_API void cstr_replace_n(cstr* self, size_t pos, size_t len, const char* str, size_t n); +STC_API void cstr_replace_all(cstr* self, const char* find, const char* replace); +STC_API void cstr_erase_n(cstr* self, size_t pos, size_t n); +STC_API size_t cstr_find(cstr s, const char* needle); +STC_API size_t cstr_find_from(cstr s, size_t pos, const char* needle); +STC_API bool cstr_getdelim(cstr *self, int delim, FILE *stream); +STC_API void cstr_replace_all(cstr* self, const char* find, const char* repl); + +STC_INLINE cstr cstr_init() { return cstr_null; } +STC_INLINE const char* cstr_str(const cstr* self) { return self->str; } +#define cstr_toraw(self) (self)->str +STC_INLINE csview cstr_sv(const cstr* self) + { return c_make(csview){self->str, _cstr_p(self)->size}; } +#define cstr_new(literal) \ + cstr_from_n(literal, c_strlen_lit(literal)) +STC_INLINE cstr cstr_from(const char* str) + { return cstr_from_n(str, strlen(str)); } +STC_INLINE char* cstr_data(cstr* self) { return self->str; } +STC_INLINE size_t cstr_size(cstr s) { return _cstr_p(&s)->size; } +STC_INLINE size_t cstr_length(cstr s) { return _cstr_p(&s)->size; } +STC_INLINE size_t cstr_capacity(cstr s) { return _cstr_p(&s)->cap; } +STC_INLINE bool cstr_empty(cstr s) { return _cstr_p(&s)->size == 0; } +STC_INLINE void cstr_drop(cstr* self) + { if (_cstr_p(self)->cap) c_free(_cstr_p(self)); } +STC_INLINE cstr cstr_clone(cstr s) + { return cstr_from_n(s.str, _cstr_p(&s)->size); } +STC_INLINE void cstr_clear(cstr* self) + { self->str[_cstr_p(self)->size = 0] = '\0'; } +STC_INLINE cstr* cstr_assign(cstr* self, const char* str) + { return cstr_assign_n(self, str, strlen(str)); } +STC_INLINE cstr* cstr_copy(cstr* self, cstr s) + { return cstr_assign_n(self, s.str, _cstr_p(&s)->size); } +STC_INLINE cstr* cstr_append(cstr* self, const char* str) + { return cstr_append_n(self, str, strlen(str)); } +STC_INLINE cstr* cstr_append_s(cstr* self, cstr s) + { return cstr_append_n(self, s.str, _cstr_p(&s)->size); } +STC_INLINE void cstr_push_back(cstr* self, char value) + { cstr_append_n(self, &value, 1); } +STC_INLINE void cstr_pop_back(cstr* self) + { self->str[ --_cstr_p(self)->size ] = '\0'; } +STC_INLINE void cstr_insert_n(cstr* self, const size_t pos, const char* str, const size_t n) + { cstr_replace_n(self, pos, 0, str, n); } +STC_INLINE void cstr_insert(cstr* self, const size_t pos, const char* str) + { cstr_replace_n(self, pos, 0, str, strlen(str)); } +STC_INLINE void cstr_insert_s(cstr* self, const size_t pos, cstr s) + { cstr_replace_n(self, pos, 0, s.str, _cstr_p(&s)->size); } +STC_INLINE void cstr_replace(cstr* self, const size_t pos, const size_t len, const char* str) + { cstr_replace_n(self, pos, len, str, strlen(str)); } +STC_INLINE void cstr_replace_s(cstr* self, const size_t pos, const size_t len, cstr s) + { cstr_replace_n(self, pos, len, s.str, _cstr_p(&s)->size); } +STC_INLINE void cstr_erase(cstr* self, const size_t pos) + { cstr_erase_n(self, pos, 1); } +STC_INLINE char* cstr_front(cstr* self) { return self->str; } +STC_INLINE char* cstr_back(cstr* self) + { return self->str + _cstr_p(self)->size - 1; } +STC_INLINE bool cstr_equals(cstr s, const char* str) + { return strcmp(s.str, str) == 0; } +STC_INLINE bool cstr_equals_s(cstr s1, cstr s2) + { return strcmp(s1.str, s2.str) == 0; } +STC_INLINE bool cstr_contains(cstr s, const char* needle) + { return strstr(s.str, needle) != NULL; } +STC_INLINE bool cstr_getline(cstr *self, FILE *stream) + { return cstr_getdelim(self, '\n', stream); } + +STC_INLINE cstr_buf cstr_buffer(cstr* s) { + cstr_priv* p = _cstr_p(s); + return c_make(cstr_buf){s->str, p->size, p->cap}; +} + +STC_INLINE cstr cstr_with_capacity(const size_t cap) { + cstr s = cstr_null; + cstr_reserve(&s, cap); + return s; +} + +STC_INLINE cstr cstr_with_size(const size_t len, const char fill) { + cstr s = cstr_null; + cstr_resize(&s, len, fill); + return s; +} + +STC_INLINE char* cstr_expand_uninit(cstr *self, size_t n) { + size_t len = cstr_size(*self); char* d; + if (!(d = cstr_reserve(self, len + n))) return NULL; + _cstr_p(self)->size += n; + return d + len; +} + +STC_INLINE cstr* cstr_take(cstr* self, cstr s) { + if (self->str != s.str && _cstr_p(self)->cap) + c_free(_cstr_p(self)); + self->str = s.str; + return self; +} + +STC_INLINE cstr cstr_move(cstr* self) { + cstr tmp = *self; + *self = cstr_null; + return tmp; +} + +STC_INLINE bool cstr_starts_with(cstr s, const char* sub) { + while (*sub && *s.str == *sub) ++s.str, ++sub; + return *sub == 0; +} + +STC_INLINE bool cstr_ends_with(cstr s, const char* sub) { + const size_t n = strlen(sub), sz = _cstr_p(&s)->size; + return n <= sz && !memcmp(s.str + sz - n, sub, n); +} + +STC_INLINE int c_strncasecmp(const char* s1, const char* s2, size_t nmax) { + int ret = 0; + while (nmax-- && (ret = tolower(*s1++) - tolower(*s2)) == 0 && *s2++) + ; + return ret; +} + +/* container adaptor functions: */ +#define cstr_cmp(xp, yp) strcmp((xp)->str, (yp)->str) + +STC_INLINE bool cstr_eq(const cstr* x, const cstr* y) { + size_t xs = _cstr_p(x)->size, ys = _cstr_p(y)->size; + return xs == ys && !memcmp(x->str, y->str, xs); +} +STC_INLINE uint64_t cstr_hash(const cstr *self) { + return c_fasthash(self->str, _cstr_p(self)->size); +} + + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) + +#ifndef i_static +static cstr_priv _cstr_nullrep = {0, 0, {0}}; +const cstr cstr_null = {_cstr_nullrep.chr}; +#endif + +STC_DEF char* +cstr_reserve(cstr* self, const size_t cap) { + cstr_priv *p = _cstr_p(self); + const size_t oldcap = p->cap; + if (cap > oldcap) { + p = (cstr_priv*) c_realloc(((oldcap != 0) & (p != &_cstr_nullrep)) ? p : NULL, _cstr_opt_mem(cap)); + if (!p) return NULL; + self->str = p->chr; + if (oldcap == 0) self->str[p->size = 0] = '\0'; + p->cap = _cstr_opt_cap(cap); + } + return self->str; +} + +STC_DEF void +cstr_resize(cstr* self, const size_t len, const char fill) { + const size_t n = _cstr_p(self)->size; + cstr_reserve(self, len); + if (len > n) memset(self->str + n, fill, len - n); + if (len | n) self->str[_cstr_p(self)->size = len] = '\0'; +} + +STC_DEF cstr +cstr_from_n(const char* str, const size_t n) { + if (n == 0) return cstr_null; + cstr_priv* prv = (cstr_priv*) c_malloc(_cstr_opt_mem(n)); + cstr s = {(char *) memcpy(prv->chr, str, n)}; + s.str[prv->size = n] = '\0'; + prv->cap = _cstr_opt_cap(n); + return s; +} + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4996) +#endif + +STC_DEF int +cstr_vfmt(cstr* self, const char* fmt, va_list args) { + va_list args2; + va_copy(args2, args); + int len = vsnprintf(NULL, (size_t)0, fmt, args); + cstr_reserve(self, len); + vsprintf(self->str, fmt, args2); + va_end(args2); + return _cstr_p(self)->size = len; +} + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif + +STC_DEF cstr +cstr_from_fmt(const char* fmt, ...) { + cstr ret = cstr_null; + va_list args; va_start(args, fmt); + cstr_vfmt(&ret, fmt, args); + va_end(args); + return ret; +} + +STC_DEF int +cstr_printf(cstr* self, const char* fmt, ...) { + cstr ret = cstr_null; + va_list args; + va_start(args, fmt); + int n = cstr_vfmt(&ret, fmt, args); + va_end(args); + cstr_drop(self); + *self = ret; + return n; +} + +STC_DEF cstr* +cstr_assign_n(cstr* self, const char* str, const size_t n) { + if (n || _cstr_p(self)->cap) { + cstr_reserve(self, n); + memmove(self->str, str, n); + self->str[_cstr_p(self)->size = n] = '\0'; + } + return self; +} + +STC_DEF cstr* +cstr_append_n(cstr* self, const char* str, const size_t n) { + if (n == 0) return self; + const size_t oldlen = _cstr_p(self)->size, newlen = oldlen + n; + if (newlen > _cstr_p(self)->cap) { + const size_t off = (size_t) (str - self->str); /* handle self append */ + cstr_reserve(self, (oldlen*3 >> 1) + n); + if (off <= oldlen) str = self->str + off; + } + memcpy(&self->str[oldlen], str, n); + self->str[_cstr_p(self)->size = newlen] = '\0'; + return self; +} + +STC_INLINE void _cstr_internal_move(cstr* self, const size_t pos1, const size_t pos2) { + if (pos1 == pos2) + return; + const size_t len = _cstr_p(self)->size, newlen = len + pos2 - pos1; + if (newlen > _cstr_p(self)->cap) + cstr_reserve(self, (len*3 >> 1) + pos2 - pos1); + memmove(&self->str[pos2], &self->str[pos1], len - pos1); + self->str[_cstr_p(self)->size = newlen] = '\0'; +} + +STC_DEF void +cstr_replace_n(cstr* self, const size_t pos, size_t len, const char* str, const size_t n) { + const size_t sz = cstr_size(*self); + if (len > sz - pos) len = sz - pos; + c_autobuf (xstr, char, n) { + memcpy(xstr, str, n); + _cstr_internal_move(self, pos + len, pos + n); + memcpy(&self->str[pos], xstr, n); + } +} + +STC_DEF cstr +cstr_from_replace_all(const char* str, const size_t str_len, + const char* find, const size_t find_len, + const char* repl, const size_t repl_len) { + cstr out = cstr_null; + size_t from = 0; char* res; + if (find_len) + while ((res = c_strnstrn(str + from, find, str_len - from, find_len))) { + const size_t pos = res - str; + cstr_append_n(&out, str + from, pos - from); + cstr_append_n(&out, repl, repl_len); + from = pos + find_len; + } + cstr_append_n(&out, str + from, str_len - from); + return out; +} + +STC_DEF void +cstr_replace_all(cstr* self, const char* find, const char* repl) { + cstr_take(self, cstr_from_replace_all(self->str, _cstr_p(self)->size, + find, strlen(find), repl, strlen(repl))); +} + +STC_DEF void +cstr_erase_n(cstr* self, const size_t pos, size_t n) { + const size_t len = _cstr_p(self)->size; + if (n > len - pos) n = len - pos; + if (len) { + memmove(&self->str[pos], &self->str[pos + n], len - (pos + n)); + self->str[_cstr_p(self)->size -= n] = '\0'; + } +} + +STC_DEF bool +cstr_getdelim(cstr *self, const int delim, FILE *fp) { + size_t pos = 0, cap = _cstr_p(self)->cap; + char* d = self->str; + int c = fgetc(fp); + if (c == EOF) + return false; + for (;;) { + if (c == delim || c == EOF) { + if (cap) d[_cstr_p(self)->size = pos] = '\0'; + return true; + } + if (pos == cap) { + d = cstr_reserve(self, (cap*3 >> 1) + 16); + cap = cstr_capacity(*self); + } + d[pos++] = (char) c; + c = fgetc(fp); + } +} + +STC_DEF size_t +cstr_find(cstr s, const char* needle) { + char* res = strstr(s.str, needle); + return res ? res - s.str : cstr_npos; +} + +STC_DEF size_t +cstr_find_from(cstr s, const size_t pos, const char* needle) { + if (pos > _cstr_p(&s)->size) return cstr_npos; + char* res = strstr(s.str + pos, needle); + return res ? res - s.str : cstr_npos; +} + +#endif +#endif // CSTR_H_INCLUDED +#undef i_opt diff --git a/include/stc/carc.h b/include/stc/carc.h index e4a69e80..73ccc5bf 100644 --- a/include/stc/carc.h +++ b/include/stc/carc.h @@ -1,199 +1,199 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/* carc: atomic reference counted shared_ptr
-#include <stc/cstr.h>
-
-typedef struct { cstr name, last; } Person;
-
-Person Person_new(const char* name, const char* last) {
- return (Person){.name = cstr_from(name), .last = cstr_from(last)};
-}
-void Person_drop(Person* p) {
- printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
- c_drop(cstr, &p->name, &p->last);
-}
-
-#define i_tag person
-#define i_key Person
-#define i_keydrop Person_drop
-#define i_opt c_no_cmp
-#include <stc/carc.h>
-
-int main() {
- carc_person p = carc_person_make(Person_new("John", "Smiths"));
- carc_person q = carc_person_clone(p); // share the pointer
-
- printf("%s %s. uses: %" PRIuMAX "\n", cstr_str(&q.get->name), cstr_str(&q.get->last), *q.use_count);
- c_drop(carc_person, &p, &q);
-}
-*/
-#include "ccommon.h"
-
-#ifndef CARC_H_INCLUDED
-#define CARC_H_INCLUDED
-#include "forward.h"
-#include <stdlib.h>
-
-#if defined(__GNUC__) || defined(__clang__)
- #define c_atomic_inc(v) (void)__atomic_add_fetch(v, 1, __ATOMIC_SEQ_CST)
- #define c_atomic_dec_and_test(v) !__atomic_sub_fetch(v, 1, __ATOMIC_SEQ_CST)
-#elif defined(_MSC_VER)
- #include <intrin.h>
- #define c_atomic_inc(v) (void)_InterlockedIncrement(v)
- #define c_atomic_dec_and_test(v) !_InterlockedDecrement(v)
-#else
- #include <stdatomic.h>
- #define c_atomic_inc(v) (void)atomic_fetch_add(v, 1)
- #define c_atomic_dec_and_test(v) (atomic_fetch_sub(v, 1) == 1)
-#endif
-
-#define carc_null {NULL, NULL}
-#define _cx_carc_rep struct _cx_memb(_rep_)
-#endif // CARC_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix carc_
-#endif
-#include "template.h"
-typedef i_keyraw _cx_raw;
-
-#if !c_option(c_no_atomic)
- #define _i_atomic_inc(v) c_atomic_inc(v)
- #define _i_atomic_dec_and_test(v) c_atomic_dec_and_test(v)
-#else
- #define _i_atomic_inc(v) (void)(++*(v))
- #define _i_atomic_dec_and_test(v) !(--*(v))
-#endif
-#if !c_option(c_is_fwd)
-_cx_deftypes(_c_carc_types, _cx_self, i_key);
-#endif
-_cx_carc_rep { long counter; i_key value; };
-
-STC_INLINE _cx_self _cx_memb(_init)(void)
- { return c_make(_cx_self){NULL, NULL}; }
-
-STC_INLINE long _cx_memb(_use_count)(_cx_self ptr)
- { return ptr.use_count ? *ptr.use_count : 0; }
-
-STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p) {
- _cx_self ptr = {p};
- if (p)
- *(ptr.use_count = c_alloc(long)) = 1;
- return ptr;
-}
-
-// c++: std::make_shared<_cx_value>(val)
-STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) {
- _cx_self ptr;
- _cx_carc_rep *rep = c_alloc(_cx_carc_rep);
- *(ptr.use_count = &rep->counter) = 1;
- *(ptr.get = &rep->value) = val;
- return ptr;
-}
-
-STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self)
- { return i_keyto(self->get); }
-
-STC_INLINE _cx_value _cx_memb(_toval)(const _cx_self* self)
- { return *self->get; }
-
-STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) {
- _cx_self ptr = *self;
- self->get = NULL, self->use_count = NULL;
- return ptr;
-}
-
-STC_INLINE void _cx_memb(_drop)(_cx_self* self) {
- if (self->use_count && _i_atomic_dec_and_test(self->use_count)) {
- i_keydrop(self->get);
- if ((char *)self->get != (char *)self->use_count + offsetof(_cx_carc_rep, value))
- c_free(self->get);
- c_free(self->use_count);
- }
-}
-
-STC_INLINE void _cx_memb(_reset)(_cx_self* self) {
- _cx_memb(_drop)(self);
- self->use_count = NULL, self->get = NULL;
-}
-
-STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) {
- _cx_memb(_drop)(self);
- *self = _cx_memb(_from_ptr)(p);
-}
-
-#if !defined _i_no_clone && !defined _i_no_emplace
- STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw)
- { return _cx_memb(_make)(i_keyfrom(raw)); }
-#endif // !_i_no_clone
-
-// does not use i_keyclone, so OK to always define.
-STC_INLINE _cx_self _cx_memb(_clone)(_cx_self ptr) {
- if (ptr.use_count)
- _i_atomic_inc(ptr.use_count);
- return ptr;
-}
-
-STC_INLINE void _cx_memb(_copy)(_cx_self* self, _cx_self ptr) {
- if (ptr.use_count)
- _i_atomic_inc(ptr.use_count);
- _cx_memb(_drop)(self);
- *self = ptr;
-}
-
-STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self ptr) {
- if (self->get != ptr.get)
- _cx_memb(_drop)(self);
- *self = ptr;
-}
-
-STC_INLINE uint64_t _cx_memb(_value_hash)(const _cx_value* x) {
- #if c_option(c_no_cmp)
- return c_default_hash(&x);
- #else
- _cx_raw rx = i_keyto(x);
- return i_hash((&rx));
- #endif
-}
-
-STC_INLINE int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- #if c_option(c_no_cmp)
- return c_default_cmp(&x, &y);
- #else
- _cx_raw rx = i_keyto(x), ry = i_keyto(y);
- return i_cmp((&rx), (&ry));
- #endif
-}
-
-STC_INLINE bool _cx_memb(_value_eq)(const _cx_value* x, const _cx_value* y) {
- #if c_option(c_no_cmp)
- return x == y;
- #else
- _cx_raw rx = i_keyto(x), ry = i_keyto(y);
- return i_eq((&rx), (&ry));
- #endif
-}
-#undef _i_atomic_inc
-#undef _i_atomic_dec_and_test
-#include "template.h"
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* carc: atomic reference counted shared_ptr +#include <stc/cstr.h> + +typedef struct { cstr name, last; } Person; + +Person Person_new(const char* name, const char* last) { + return (Person){.name = cstr_from(name), .last = cstr_from(last)}; +} +void Person_drop(Person* p) { + printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last)); + c_drop(cstr, &p->name, &p->last); +} + +#define i_tag person +#define i_key Person +#define i_keydrop Person_drop +#define i_opt c_no_cmp +#include <stc/carc.h> + +int main() { + carc_person p = carc_person_make(Person_new("John", "Smiths")); + carc_person q = carc_person_clone(p); // share the pointer + + printf("%s %s. uses: %" PRIuMAX "\n", cstr_str(&q.get->name), cstr_str(&q.get->last), *q.use_count); + c_drop(carc_person, &p, &q); +} +*/ +#include "ccommon.h" + +#ifndef CARC_H_INCLUDED +#define CARC_H_INCLUDED +#include "forward.h" +#include <stdlib.h> + +#if defined(__GNUC__) || defined(__clang__) + #define c_atomic_inc(v) (void)__atomic_add_fetch(v, 1, __ATOMIC_SEQ_CST) + #define c_atomic_dec_and_test(v) !__atomic_sub_fetch(v, 1, __ATOMIC_SEQ_CST) +#elif defined(_MSC_VER) + #include <intrin.h> + #define c_atomic_inc(v) (void)_InterlockedIncrement(v) + #define c_atomic_dec_and_test(v) !_InterlockedDecrement(v) +#else + #include <stdatomic.h> + #define c_atomic_inc(v) (void)atomic_fetch_add(v, 1) + #define c_atomic_dec_and_test(v) (atomic_fetch_sub(v, 1) == 1) +#endif + +#define carc_null {NULL, NULL} +#define _cx_carc_rep struct _cx_memb(_rep_) +#endif // CARC_H_INCLUDED + +#ifndef _i_prefix +#define _i_prefix carc_ +#endif +#include "template.h" +typedef i_keyraw _cx_raw; + +#if !c_option(c_no_atomic) + #define _i_atomic_inc(v) c_atomic_inc(v) + #define _i_atomic_dec_and_test(v) c_atomic_dec_and_test(v) +#else + #define _i_atomic_inc(v) (void)(++*(v)) + #define _i_atomic_dec_and_test(v) !(--*(v)) +#endif +#if !c_option(c_is_fwd) +_cx_deftypes(_c_carc_types, _cx_self, i_key); +#endif +_cx_carc_rep { long counter; i_key value; }; + +STC_INLINE _cx_self _cx_memb(_init)(void) + { return c_make(_cx_self){NULL, NULL}; } + +STC_INLINE long _cx_memb(_use_count)(_cx_self ptr) + { return ptr.use_count ? *ptr.use_count : 0; } + +STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p) { + _cx_self ptr = {p}; + if (p) + *(ptr.use_count = c_alloc(long)) = 1; + return ptr; +} + +// c++: std::make_shared<_cx_value>(val) +STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) { + _cx_self ptr; + _cx_carc_rep *rep = c_alloc(_cx_carc_rep); + *(ptr.use_count = &rep->counter) = 1; + *(ptr.get = &rep->value) = val; + return ptr; +} + +STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self) + { return i_keyto(self->get); } + +STC_INLINE _cx_value _cx_memb(_toval)(const _cx_self* self) + { return *self->get; } + +STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) { + _cx_self ptr = *self; + self->get = NULL, self->use_count = NULL; + return ptr; +} + +STC_INLINE void _cx_memb(_drop)(_cx_self* self) { + if (self->use_count && _i_atomic_dec_and_test(self->use_count)) { + i_keydrop(self->get); + if ((char *)self->get != (char *)self->use_count + offsetof(_cx_carc_rep, value)) + c_free(self->get); + c_free(self->use_count); + } +} + +STC_INLINE void _cx_memb(_reset)(_cx_self* self) { + _cx_memb(_drop)(self); + self->use_count = NULL, self->get = NULL; +} + +STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) { + _cx_memb(_drop)(self); + *self = _cx_memb(_from_ptr)(p); +} + +#if !defined _i_no_clone && !defined _i_no_emplace + STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw) + { return _cx_memb(_make)(i_keyfrom(raw)); } +#endif // !_i_no_clone + +// does not use i_keyclone, so OK to always define. +STC_INLINE _cx_self _cx_memb(_clone)(_cx_self ptr) { + if (ptr.use_count) + _i_atomic_inc(ptr.use_count); + return ptr; +} + +STC_INLINE void _cx_memb(_copy)(_cx_self* self, _cx_self ptr) { + if (ptr.use_count) + _i_atomic_inc(ptr.use_count); + _cx_memb(_drop)(self); + *self = ptr; +} + +STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self ptr) { + if (self->get != ptr.get) + _cx_memb(_drop)(self); + *self = ptr; +} + +STC_INLINE uint64_t _cx_memb(_value_hash)(const _cx_value* x) { + #if c_option(c_no_cmp) + return c_default_hash(&x); + #else + _cx_raw rx = i_keyto(x); + return i_hash((&rx)); + #endif +} + +STC_INLINE int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { + #if c_option(c_no_cmp) + return c_default_cmp(&x, &y); + #else + _cx_raw rx = i_keyto(x), ry = i_keyto(y); + return i_cmp((&rx), (&ry)); + #endif +} + +STC_INLINE bool _cx_memb(_value_eq)(const _cx_value* x, const _cx_value* y) { + #if c_option(c_no_cmp) + return x == y; + #else + _cx_raw rx = i_keyto(x), ry = i_keyto(y); + return i_eq((&rx), (&ry)); + #endif +} +#undef _i_atomic_inc +#undef _i_atomic_dec_and_test +#include "template.h" diff --git a/include/stc/cbits.h b/include/stc/cbits.h index b3f5ac4d..bf5d5406 100644 --- a/include/stc/cbits.h +++ b/include/stc/cbits.h @@ -1,328 +1,328 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-/*
-Similar to boost::dynamic_bitset / std::bitset
-
-#include <stdio.h>
-#include "cbits.h"
-
-int main() {
- c_autovar (cbits bset = cbits_with_size(23, true), cbits_drop(&bset))
- {
- cbits_reset(&bset, 9);
- cbits_resize(&bset, 43, false);
-
- printf("%4zu: ", cbits_size(&bset));
- c_forrange (i, cbits_size(&bset))
- printf("%d", cbits_at(&bset, i));
- puts("");
- cbits_set(&bset, 28);
- cbits_resize(&bset, 77, true);
- cbits_resize(&bset, 93, false);
- cbits_resize(&bset, 102, true);
- cbits_set_value(&bset, 99, false);
-
- printf("%4zu: ", cbits_size(&bset));
- c_forrange (i, cbits_size(&bset))
- printf("%d", cbits_at(&bset, i));
- puts("");
- }
-}
-*/
-
-#ifndef CBITS_H_INCLUDED
-#define i_header
-#include "ccommon.h"
-#include <stdlib.h>
-#include <string.h>
-
-#define _cbits_bit(i) ((uint64_t)1 << ((i) & 63))
-#define _cbits_words(n) (((n) + 63)>>6)
-#define _cbits_bytes(n) (_cbits_words(n) * sizeof(uint64_t))
-
-STC_API bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, size_t sz);
-STC_API bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, size_t sz);
-STC_API size_t _cbits_count(const uint64_t* set, const size_t sz);
-STC_API char* _cbits_to_str(const uint64_t* set, const size_t sz,
- char* out, size_t start, intptr_t stop);
-
-#if defined(__GNUC__) || defined(__clang__)
- STC_INLINE uint64_t cpopcount64(uint64_t x) {return __builtin_popcountll(x);}
-#elif defined(_MSC_VER) && defined(_WIN64)
- #include <intrin.h>
- STC_INLINE uint64_t cpopcount64(uint64_t x) {return __popcnt64(x);}
-#else
- STC_INLINE uint64_t cpopcount64(uint64_t x) { /* http://en.wikipedia.org/wiki/Hamming_weight */
- x -= (x >> 1) & 0x5555555555555555;
- x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333);
- x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;
- return (x * 0x0101010101010101) >> 56;
- }
-#endif
-#endif // CBITS_H_INCLUDED
-
-#define _i_memb(name) c_paste(i_type, name)
-
-#if !defined i_len
-
-#define _i_assert(x) assert(x)
-#define i_type cbits
-
-struct { uint64_t *data64; size_t _size; } typedef i_type;
-
-STC_INLINE cbits cbits_init(void) { return c_make(cbits){NULL}; }
-STC_INLINE void cbits_drop(cbits* self) { c_free(self->data64); }
-STC_INLINE size_t cbits_size(const cbits* self) { return self->_size; }
-STC_API void cbits_resize(cbits* self, size_t size, bool value);
-STC_API cbits* cbits_copy(cbits* self, const cbits* other);
-
-// predecl;
-STC_INLINE void cbits_set_all(cbits *self, const bool value);
-STC_INLINE void cbits_set_pattern(cbits *self, const uint64_t pattern);
-
-STC_INLINE cbits cbits_move(cbits* self) {
- cbits tmp = *self;
- self->data64 = NULL, self->_size = 0;
- return tmp;
-}
-
-STC_INLINE cbits* cbits_take(cbits* self, cbits other) {
- if (self->data64 != other.data64) {
- cbits_drop(self);
- *self = other;
- }
- return self;
-}
-
-STC_INLINE cbits cbits_clone(cbits other) {
- const size_t bytes = _cbits_bytes(other._size);
- cbits set = {(uint64_t *)memcpy(c_malloc(bytes), other.data64, bytes), other._size};
- return set;
-}
-
-STC_INLINE cbits cbits_with_size(const size_t size, const bool value) {
- cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size};
- cbits_set_all(&set, value);
- return set;
-}
-
-STC_INLINE cbits cbits_with_pattern(const size_t size, const uint64_t pattern) {
- cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size};
- cbits_set_pattern(&set, pattern);
- return set;
-}
-
-#else // i_len
-
-#define _i_assert(x) (void)0
-#if !defined i_type
- #define i_type c_paste(cbits, i_len)
-#endif
-
-struct { uint64_t data64[(i_len - 1)/64 + 1]; } typedef i_type;
-
-STC_INLINE i_type _i_memb(_init)(void) { return c_make(i_type){0}; }
-STC_INLINE void _i_memb(_drop)(i_type* self) {}
-STC_INLINE size_t _i_memb(_size)(const i_type* self) { return i_len; }
-STC_INLINE i_type _i_memb(_move)(i_type* self) { return *self; }
-
-STC_INLINE i_type* _i_memb(_take)(i_type* self, i_type other)
- { *self = other; return self; }
-
-STC_INLINE i_type _i_memb(_clone)(i_type other)
- { return other; }
-
-STC_INLINE i_type* _i_memb(_copy)(i_type* self, i_type other)
- { *self = other; return self; }
-
-STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value);
-STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern);
-
-STC_INLINE i_type _i_memb(_with_size)(const size_t size, const bool value) {
- assert(size <= i_len);
- i_type set; _i_memb(_set_all)(&set, value);
- return set;
-}
-
-STC_INLINE i_type _i_memb(_with_pattern)(const size_t size, const uint64_t pattern) {
- assert(size <= i_len);
- i_type set; _i_memb(_set_pattern)(&set, pattern);
- return set;
-}
-#endif // i_len
-
-
-STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value)
- { memset(self->data64, value? ~0 : 0, _cbits_bytes(_i_memb(_size)(self))); }
-
-STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern) {
- size_t n = _cbits_words(_i_memb(_size)(self));
- while (n--) self->data64[n] = pattern;
-}
-
-STC_INLINE bool _i_memb(_test)(const i_type* self, const size_t i)
- { return (self->data64[i>>6] & _cbits_bit(i)) != 0; }
-
-STC_INLINE bool _i_memb(_at)(const i_type* self, const size_t i)
- { return (self->data64[i>>6] & _cbits_bit(i)) != 0; }
-
-STC_INLINE void _i_memb(_set)(i_type *self, const size_t i)
- { self->data64[i>>6] |= _cbits_bit(i); }
-
-STC_INLINE void _i_memb(_reset)(i_type *self, const size_t i)
- { self->data64[i>>6] &= ~_cbits_bit(i); }
-
-STC_INLINE void _i_memb(_set_value)(i_type *self, const size_t i, const bool b) {
- self->data64[i>>6] ^= ((uint64_t)-(int)b ^ self->data64[i>>6]) & _cbits_bit(i);
-}
-
-STC_INLINE void _i_memb(_flip)(i_type *self, const size_t i)
- { self->data64[i>>6] ^= _cbits_bit(i); }
-
-STC_INLINE void _i_memb(_flip_all)(i_type *self) {
- size_t n = _cbits_words(_i_memb(_size)(self));
- while (n--) self->data64[n] ^= ~(uint64_t)0;
-}
-
-STC_INLINE i_type _i_memb(_from)(const char* str) {
- size_t n = strlen(str);
- i_type set = _i_memb(_with_size)(n, false);
- while (n--) if (str[n] == '1') _i_memb(_set)(&set, n);
- return set;
-}
-
-/* Intersection */
-STC_INLINE void _i_memb(_intersect)(i_type *self, const i_type* other) {
- _i_assert(self->_size == other->_size);
- size_t n = _cbits_words(_i_memb(_size)(self));
- while (n--) self->data64[n] &= other->data64[n];
-}
-/* Union */
-STC_INLINE void _i_memb(_union)(i_type *self, const i_type* other) {
- _i_assert(self->_size == other->_size);
- size_t n = _cbits_words(_i_memb(_size)(self));
- while (n--) self->data64[n] |= other->data64[n];
-}
-/* Exclusive disjunction */
-STC_INLINE void _i_memb(_xor)(i_type *self, const i_type* other) {
- _i_assert(self->_size == other->_size);
- size_t n = _cbits_words(_i_memb(_size)(self));
- while (n--) self->data64[n] ^= other->data64[n];
-}
-
-STC_INLINE size_t _i_memb(_count)(const i_type* self)
- { return _cbits_count(self->data64, _i_memb(_size)(self)); }
-
-STC_INLINE char* _i_memb(_to_str)(const i_type* self, char* out, size_t start, intptr_t stop)
- { return _cbits_to_str(self->data64, _i_memb(_size)(self), out, start, stop); }
-
-STC_INLINE bool _i_memb(_subset_of)(const i_type* self, const i_type* other) {
- _i_assert(self->_size == other->_size);
- return _cbits_subset_of(self->data64, other->data64, _i_memb(_size)(self));
-}
-
-STC_INLINE bool _i_memb(_disjoint)(const i_type* self, const i_type* other) {
- _i_assert(self->_size == other->_size);
- return _cbits_disjoint(self->data64, other->data64, _i_memb(_size)(self));
-}
-
-
-#if defined(i_implement)
-
-#if !defined i_len
-STC_DEF cbits* cbits_copy(cbits* self, const cbits* other) {
- if (self->data64 == other->data64)
- return self;
- if (self->_size != other->_size)
- return cbits_take(self, cbits_clone(*other));
- memcpy(self->data64, other->data64, _cbits_bytes(other->_size));
- return self;
-}
-
-STC_DEF void cbits_resize(cbits* self, const size_t size, const bool value) {
- const size_t new_n = _cbits_words(size), osize = self->_size, old_n = _cbits_words(osize);
- self->data64 = (uint64_t *)c_realloc(self->data64, new_n*8);
- self->_size = size;
- if (new_n >= old_n) {
- memset(self->data64 + old_n, -(int)value, (new_n - old_n)*8);
- if (old_n > 0) {
- uint64_t m = _cbits_bit(osize) - 1; /* mask */
- value ? (self->data64[old_n - 1] |= ~m)
- : (self->data64[old_n - 1] &= m);
- }
- }
-}
-#endif
-#ifndef CBITS_H_INCLUDED
-
-STC_DEF size_t _cbits_count(const uint64_t* set, const size_t sz) {
- const size_t n = sz>>6;
- size_t count = 0;
- for (size_t i = 0; i < n; ++i)
- count += cpopcount64(set[i]);
- if (sz & 63)
- count += cpopcount64(set[n] & (_cbits_bit(sz) - 1));
- return count;
-}
-
-STC_DEF char* _cbits_to_str(const uint64_t* set, const size_t sz,
- char* out, size_t start, intptr_t stop) {
- if (stop < 0)
- stop = sz;
- memset(out, '0', stop - start);
- for (intptr_t i = start; i < stop; ++i)
- if ((set[i>>6] & _cbits_bit(i)) != 0)
- out[i - start] = '1';
- out[stop - start] = '\0';
- return out;
-}
-
-#define _cbits_OPR(OPR, VAL) \
- const size_t n = sz>>6; \
- for (size_t i = 0; i < n; ++i) \
- if ((set[i] OPR other[i]) != VAL) \
- return false; \
- if (!(sz & 63)) \
- return true; \
- const uint64_t i = n, m = _cbits_bit(sz) - 1; \
- return ((set[i] OPR other[i]) & m) == (VAL & m)
-
-STC_DEF bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, const size_t sz)
- { _cbits_OPR(|, set[i]); }
-
-STC_DEF bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, const size_t sz)
- { _cbits_OPR(&, 0); }
-
-#endif // !CBITS_H_INCLUDED
-#endif // i_implement
-
-#define CBITS_H_INCLUDED
-#undef _i_memb
-#undef _i_assert
-#undef i_len
-#undef i_type
-#undef i_opt
-#undef i_header
-#undef i_implement
-#undef i_static
-#undef i_exterm
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/* +Similar to boost::dynamic_bitset / std::bitset + +#include <stdio.h> +#include "cbits.h" + +int main() { + c_autovar (cbits bset = cbits_with_size(23, true), cbits_drop(&bset)) + { + cbits_reset(&bset, 9); + cbits_resize(&bset, 43, false); + + printf("%4zu: ", cbits_size(&bset)); + c_forrange (i, cbits_size(&bset)) + printf("%d", cbits_at(&bset, i)); + puts(""); + cbits_set(&bset, 28); + cbits_resize(&bset, 77, true); + cbits_resize(&bset, 93, false); + cbits_resize(&bset, 102, true); + cbits_set_value(&bset, 99, false); + + printf("%4zu: ", cbits_size(&bset)); + c_forrange (i, cbits_size(&bset)) + printf("%d", cbits_at(&bset, i)); + puts(""); + } +} +*/ + +#ifndef CBITS_H_INCLUDED +#define i_header +#include "ccommon.h" +#include <stdlib.h> +#include <string.h> + +#define _cbits_bit(i) ((uint64_t)1 << ((i) & 63)) +#define _cbits_words(n) (((n) + 63)>>6) +#define _cbits_bytes(n) (_cbits_words(n) * sizeof(uint64_t)) + +STC_API bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, size_t sz); +STC_API bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, size_t sz); +STC_API size_t _cbits_count(const uint64_t* set, const size_t sz); +STC_API char* _cbits_to_str(const uint64_t* set, const size_t sz, + char* out, size_t start, intptr_t stop); + +#if defined(__GNUC__) || defined(__clang__) + STC_INLINE uint64_t cpopcount64(uint64_t x) {return __builtin_popcountll(x);} +#elif defined(_MSC_VER) && defined(_WIN64) + #include <intrin.h> + STC_INLINE uint64_t cpopcount64(uint64_t x) {return __popcnt64(x);} +#else + STC_INLINE uint64_t cpopcount64(uint64_t x) { /* http://en.wikipedia.org/wiki/Hamming_weight */ + x -= (x >> 1) & 0x5555555555555555; + x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333); + x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f; + return (x * 0x0101010101010101) >> 56; + } +#endif +#endif // CBITS_H_INCLUDED + +#define _i_memb(name) c_paste(i_type, name) + +#if !defined i_len + +#define _i_assert(x) assert(x) +#define i_type cbits + +struct { uint64_t *data64; size_t _size; } typedef i_type; + +STC_INLINE cbits cbits_init(void) { return c_make(cbits){NULL}; } +STC_INLINE void cbits_drop(cbits* self) { c_free(self->data64); } +STC_INLINE size_t cbits_size(const cbits* self) { return self->_size; } +STC_API void cbits_resize(cbits* self, size_t size, bool value); +STC_API cbits* cbits_copy(cbits* self, const cbits* other); + +// predecl; +STC_INLINE void cbits_set_all(cbits *self, const bool value); +STC_INLINE void cbits_set_pattern(cbits *self, const uint64_t pattern); + +STC_INLINE cbits cbits_move(cbits* self) { + cbits tmp = *self; + self->data64 = NULL, self->_size = 0; + return tmp; +} + +STC_INLINE cbits* cbits_take(cbits* self, cbits other) { + if (self->data64 != other.data64) { + cbits_drop(self); + *self = other; + } + return self; +} + +STC_INLINE cbits cbits_clone(cbits other) { + const size_t bytes = _cbits_bytes(other._size); + cbits set = {(uint64_t *)memcpy(c_malloc(bytes), other.data64, bytes), other._size}; + return set; +} + +STC_INLINE cbits cbits_with_size(const size_t size, const bool value) { + cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size}; + cbits_set_all(&set, value); + return set; +} + +STC_INLINE cbits cbits_with_pattern(const size_t size, const uint64_t pattern) { + cbits set = {(uint64_t *)c_malloc(_cbits_bytes(size)), size}; + cbits_set_pattern(&set, pattern); + return set; +} + +#else // i_len + +#define _i_assert(x) (void)0 +#if !defined i_type + #define i_type c_paste(cbits, i_len) +#endif + +struct { uint64_t data64[(i_len - 1)/64 + 1]; } typedef i_type; + +STC_INLINE i_type _i_memb(_init)(void) { return c_make(i_type){0}; } +STC_INLINE void _i_memb(_drop)(i_type* self) {} +STC_INLINE size_t _i_memb(_size)(const i_type* self) { return i_len; } +STC_INLINE i_type _i_memb(_move)(i_type* self) { return *self; } + +STC_INLINE i_type* _i_memb(_take)(i_type* self, i_type other) + { *self = other; return self; } + +STC_INLINE i_type _i_memb(_clone)(i_type other) + { return other; } + +STC_INLINE i_type* _i_memb(_copy)(i_type* self, i_type other) + { *self = other; return self; } + +STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value); +STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern); + +STC_INLINE i_type _i_memb(_with_size)(const size_t size, const bool value) { + assert(size <= i_len); + i_type set; _i_memb(_set_all)(&set, value); + return set; +} + +STC_INLINE i_type _i_memb(_with_pattern)(const size_t size, const uint64_t pattern) { + assert(size <= i_len); + i_type set; _i_memb(_set_pattern)(&set, pattern); + return set; +} +#endif // i_len + + +STC_INLINE void _i_memb(_set_all)(i_type *self, const bool value) + { memset(self->data64, value? ~0 : 0, _cbits_bytes(_i_memb(_size)(self))); } + +STC_INLINE void _i_memb(_set_pattern)(i_type *self, const uint64_t pattern) { + size_t n = _cbits_words(_i_memb(_size)(self)); + while (n--) self->data64[n] = pattern; +} + +STC_INLINE bool _i_memb(_test)(const i_type* self, const size_t i) + { return (self->data64[i>>6] & _cbits_bit(i)) != 0; } + +STC_INLINE bool _i_memb(_at)(const i_type* self, const size_t i) + { return (self->data64[i>>6] & _cbits_bit(i)) != 0; } + +STC_INLINE void _i_memb(_set)(i_type *self, const size_t i) + { self->data64[i>>6] |= _cbits_bit(i); } + +STC_INLINE void _i_memb(_reset)(i_type *self, const size_t i) + { self->data64[i>>6] &= ~_cbits_bit(i); } + +STC_INLINE void _i_memb(_set_value)(i_type *self, const size_t i, const bool b) { + self->data64[i>>6] ^= ((uint64_t)-(int)b ^ self->data64[i>>6]) & _cbits_bit(i); +} + +STC_INLINE void _i_memb(_flip)(i_type *self, const size_t i) + { self->data64[i>>6] ^= _cbits_bit(i); } + +STC_INLINE void _i_memb(_flip_all)(i_type *self) { + size_t n = _cbits_words(_i_memb(_size)(self)); + while (n--) self->data64[n] ^= ~(uint64_t)0; +} + +STC_INLINE i_type _i_memb(_from)(const char* str) { + size_t n = strlen(str); + i_type set = _i_memb(_with_size)(n, false); + while (n--) if (str[n] == '1') _i_memb(_set)(&set, n); + return set; +} + +/* Intersection */ +STC_INLINE void _i_memb(_intersect)(i_type *self, const i_type* other) { + _i_assert(self->_size == other->_size); + size_t n = _cbits_words(_i_memb(_size)(self)); + while (n--) self->data64[n] &= other->data64[n]; +} +/* Union */ +STC_INLINE void _i_memb(_union)(i_type *self, const i_type* other) { + _i_assert(self->_size == other->_size); + size_t n = _cbits_words(_i_memb(_size)(self)); + while (n--) self->data64[n] |= other->data64[n]; +} +/* Exclusive disjunction */ +STC_INLINE void _i_memb(_xor)(i_type *self, const i_type* other) { + _i_assert(self->_size == other->_size); + size_t n = _cbits_words(_i_memb(_size)(self)); + while (n--) self->data64[n] ^= other->data64[n]; +} + +STC_INLINE size_t _i_memb(_count)(const i_type* self) + { return _cbits_count(self->data64, _i_memb(_size)(self)); } + +STC_INLINE char* _i_memb(_to_str)(const i_type* self, char* out, size_t start, intptr_t stop) + { return _cbits_to_str(self->data64, _i_memb(_size)(self), out, start, stop); } + +STC_INLINE bool _i_memb(_subset_of)(const i_type* self, const i_type* other) { + _i_assert(self->_size == other->_size); + return _cbits_subset_of(self->data64, other->data64, _i_memb(_size)(self)); +} + +STC_INLINE bool _i_memb(_disjoint)(const i_type* self, const i_type* other) { + _i_assert(self->_size == other->_size); + return _cbits_disjoint(self->data64, other->data64, _i_memb(_size)(self)); +} + + +#if defined(i_implement) + +#if !defined i_len +STC_DEF cbits* cbits_copy(cbits* self, const cbits* other) { + if (self->data64 == other->data64) + return self; + if (self->_size != other->_size) + return cbits_take(self, cbits_clone(*other)); + memcpy(self->data64, other->data64, _cbits_bytes(other->_size)); + return self; +} + +STC_DEF void cbits_resize(cbits* self, const size_t size, const bool value) { + const size_t new_n = _cbits_words(size), osize = self->_size, old_n = _cbits_words(osize); + self->data64 = (uint64_t *)c_realloc(self->data64, new_n*8); + self->_size = size; + if (new_n >= old_n) { + memset(self->data64 + old_n, -(int)value, (new_n - old_n)*8); + if (old_n > 0) { + uint64_t m = _cbits_bit(osize) - 1; /* mask */ + value ? (self->data64[old_n - 1] |= ~m) + : (self->data64[old_n - 1] &= m); + } + } +} +#endif +#ifndef CBITS_H_INCLUDED + +STC_DEF size_t _cbits_count(const uint64_t* set, const size_t sz) { + const size_t n = sz>>6; + size_t count = 0; + for (size_t i = 0; i < n; ++i) + count += cpopcount64(set[i]); + if (sz & 63) + count += cpopcount64(set[n] & (_cbits_bit(sz) - 1)); + return count; +} + +STC_DEF char* _cbits_to_str(const uint64_t* set, const size_t sz, + char* out, size_t start, intptr_t stop) { + if (stop < 0) + stop = sz; + memset(out, '0', stop - start); + for (intptr_t i = start; i < stop; ++i) + if ((set[i>>6] & _cbits_bit(i)) != 0) + out[i - start] = '1'; + out[stop - start] = '\0'; + return out; +} + +#define _cbits_OPR(OPR, VAL) \ + const size_t n = sz>>6; \ + for (size_t i = 0; i < n; ++i) \ + if ((set[i] OPR other[i]) != VAL) \ + return false; \ + if (!(sz & 63)) \ + return true; \ + const uint64_t i = n, m = _cbits_bit(sz) - 1; \ + return ((set[i] OPR other[i]) & m) == (VAL & m) + +STC_DEF bool _cbits_subset_of(const uint64_t* set, const uint64_t* other, const size_t sz) + { _cbits_OPR(|, set[i]); } + +STC_DEF bool _cbits_disjoint(const uint64_t* set, const uint64_t* other, const size_t sz) + { _cbits_OPR(&, 0); } + +#endif // !CBITS_H_INCLUDED +#endif // i_implement + +#define CBITS_H_INCLUDED +#undef _i_memb +#undef _i_assert +#undef i_len +#undef i_type +#undef i_opt +#undef i_header +#undef i_implement +#undef i_static +#undef i_exterm diff --git a/include/stc/cbox.h b/include/stc/cbox.h index 73b437d4..f1e410b1 100644 --- a/include/stc/cbox.h +++ b/include/stc/cbox.h @@ -1,182 +1,182 @@ -
-/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/* cbox: heap allocated boxed type
-#include <stc/cstr.h>
-
-typedef struct { cstr name, email; } Person;
-
-Person Person_from(const char* name, const char* email) {
- return (Person){.name = cstr_from(name), .email = cstr_from(email)};
-}
-Person Person_clone(Person p) {
- p.name = cstr_clone(p.name);
- p.email = cstr_clone(p.email);
- return p;
-}
-void Person_drop(Person* p) {
- printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->email));
- c_drop(cstr, &p->name, &p->email);
-}
-
-#define i_key_bind Person // bind Person clone+drop fn's
-#define i_opt c_no_cmp // compare by .get addresses only
-#define i_type PBox
-#include <stc/cbox.h>
-
-int main() {
- c_auto (PBox, p, q)
- {
- p = PBox_make(Person_from("John Smiths", "[email protected]"));
- q = PBox_clone(p);
- cstr_assign(&q.get->name, "Joe Smiths");
-
- printf("%s %s.\n", cstr_str(&p.get->name), cstr_str(&p.get->email));
- printf("%s %s.\n", cstr_str(&q.get->name), cstr_str(&q.get->email));
- }
-}
-*/
-#include "ccommon.h"
-
-#ifndef CBOX_H_INCLUDED
-#define CBOX_H_INCLUDED
-#include "forward.h"
-#include <stdlib.h>
-#include <string.h>
-
-#define cbox_null {NULL}
-#endif // CBOX_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix cbox_
-#endif
-#include "template.h"
-typedef i_keyraw _cx_raw;
-
-#if !c_option(c_is_fwd)
-_cx_deftypes(_c_cbox_types, _cx_self, i_key);
-#endif
-
-// constructors (takes ownsership)
-STC_INLINE _cx_self _cx_memb(_init)(void)
- { return c_make(_cx_self){NULL}; }
-
-STC_INLINE long _cx_memb(_use_count)(_cx_self box)
- { return (long)(box.get != NULL); }
-
-STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p)
- { return c_make(_cx_self){p}; }
-
-// c++: std::make_unique<i_key>(val)
-STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) {
- _cx_self ptr = {c_alloc(_cx_value)};
- *ptr.get = val; return ptr;
-}
-
-STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self)
- { return i_keyto(self->get); }
-
-STC_INLINE _cx_value _cx_memb(_toval)(const _cx_self* self)
- { return *self->get; }
-
-// destructor
-STC_INLINE void _cx_memb(_drop)(_cx_self* self) {
- if (self->get) {
- i_keydrop(self->get);
- c_free(self->get);
- }
-}
-
-STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) {
- _cx_self ptr = *self;
- self->get = NULL;
- return ptr;
-}
-
-STC_INLINE void _cx_memb(_reset)(_cx_self* self) {
- _cx_memb(_drop)(self);
- self->get = NULL;
-}
-
-// take ownership of p
-STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) {
- if (self->get)
- i_keydrop(self->get);
- self->get = p;
-}
-
-#if !defined _i_no_clone
-#if !defined _i_no_emplace
- STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw)
- { return _cx_memb(_make)(i_keyfrom(raw)); }
-#endif
- STC_INLINE _cx_self _cx_memb(_clone)(_cx_self other) {
- if (!other.get)
- return other;
- _cx_self out = {c_alloc(i_key)};
- *out.get = i_keyclone(*other.get);
- return out;
- }
-
- STC_INLINE void _cx_memb(_copy)(_cx_self* self, _cx_self other) {
- if (self->get == other.get)
- return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(other);
- }
-#endif // !_i_no_clone
-
-STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self other) {
- if (other.get != self->get)
- _cx_memb(_drop)(self);
- *self = other;
-}
-
-STC_INLINE uint64_t _cx_memb(_value_hash)(const _cx_value* x) {
- #if c_option(c_no_cmp)
- return c_default_hash(&x);
- #else
- _cx_raw rx = i_keyto(x);
- return i_hash((&rx));
- #endif
-}
-
-STC_INLINE int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- #if c_option(c_no_cmp)
- return c_default_cmp(&x, &y);
- #else
- _cx_raw rx = i_keyto(x), ry = i_keyto(y);
- return i_cmp((&rx), (&ry));
- #endif
-}
-
-STC_INLINE bool _cx_memb(_value_eq)(const _cx_value* x, const _cx_value* y) {
- #if c_option(c_no_cmp)
- return x == y;
- #else
- _cx_raw rx = i_keyto(x), ry = i_keyto(y);
- return i_eq((&rx), (&ry));
- #endif
-}
-#include "template.h"
+ +/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* cbox: heap allocated boxed type +#include <stc/cstr.h> + +typedef struct { cstr name, email; } Person; + +Person Person_from(const char* name, const char* email) { + return (Person){.name = cstr_from(name), .email = cstr_from(email)}; +} +Person Person_clone(Person p) { + p.name = cstr_clone(p.name); + p.email = cstr_clone(p.email); + return p; +} +void Person_drop(Person* p) { + printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->email)); + c_drop(cstr, &p->name, &p->email); +} + +#define i_key_bind Person // bind Person clone+drop fn's +#define i_opt c_no_cmp // compare by .get addresses only +#define i_type PBox +#include <stc/cbox.h> + +int main() { + c_auto (PBox, p, q) + { + p = PBox_make(Person_from("John Smiths", "[email protected]")); + q = PBox_clone(p); + cstr_assign(&q.get->name, "Joe Smiths"); + + printf("%s %s.\n", cstr_str(&p.get->name), cstr_str(&p.get->email)); + printf("%s %s.\n", cstr_str(&q.get->name), cstr_str(&q.get->email)); + } +} +*/ +#include "ccommon.h" + +#ifndef CBOX_H_INCLUDED +#define CBOX_H_INCLUDED +#include "forward.h" +#include <stdlib.h> +#include <string.h> + +#define cbox_null {NULL} +#endif // CBOX_H_INCLUDED + +#ifndef _i_prefix +#define _i_prefix cbox_ +#endif +#include "template.h" +typedef i_keyraw _cx_raw; + +#if !c_option(c_is_fwd) +_cx_deftypes(_c_cbox_types, _cx_self, i_key); +#endif + +// constructors (takes ownsership) +STC_INLINE _cx_self _cx_memb(_init)(void) + { return c_make(_cx_self){NULL}; } + +STC_INLINE long _cx_memb(_use_count)(_cx_self box) + { return (long)(box.get != NULL); } + +STC_INLINE _cx_self _cx_memb(_from_ptr)(_cx_value* p) + { return c_make(_cx_self){p}; } + +// c++: std::make_unique<i_key>(val) +STC_INLINE _cx_self _cx_memb(_make)(_cx_value val) { + _cx_self ptr = {c_alloc(_cx_value)}; + *ptr.get = val; return ptr; +} + +STC_INLINE _cx_raw _cx_memb(_toraw)(const _cx_self* self) + { return i_keyto(self->get); } + +STC_INLINE _cx_value _cx_memb(_toval)(const _cx_self* self) + { return *self->get; } + +// destructor +STC_INLINE void _cx_memb(_drop)(_cx_self* self) { + if (self->get) { + i_keydrop(self->get); + c_free(self->get); + } +} + +STC_INLINE _cx_self _cx_memb(_move)(_cx_self* self) { + _cx_self ptr = *self; + self->get = NULL; + return ptr; +} + +STC_INLINE void _cx_memb(_reset)(_cx_self* self) { + _cx_memb(_drop)(self); + self->get = NULL; +} + +// take ownership of p +STC_INLINE void _cx_memb(_reset_to)(_cx_self* self, _cx_value* p) { + if (self->get) + i_keydrop(self->get); + self->get = p; +} + +#if !defined _i_no_clone +#if !defined _i_no_emplace + STC_INLINE _cx_self _cx_memb(_from)(_cx_raw raw) + { return _cx_memb(_make)(i_keyfrom(raw)); } +#endif + STC_INLINE _cx_self _cx_memb(_clone)(_cx_self other) { + if (!other.get) + return other; + _cx_self out = {c_alloc(i_key)}; + *out.get = i_keyclone(*other.get); + return out; + } + + STC_INLINE void _cx_memb(_copy)(_cx_self* self, _cx_self other) { + if (self->get == other.get) + return; + _cx_memb(_drop)(self); + *self = _cx_memb(_clone)(other); + } +#endif // !_i_no_clone + +STC_INLINE void _cx_memb(_take)(_cx_self* self, _cx_self other) { + if (other.get != self->get) + _cx_memb(_drop)(self); + *self = other; +} + +STC_INLINE uint64_t _cx_memb(_value_hash)(const _cx_value* x) { + #if c_option(c_no_cmp) + return c_default_hash(&x); + #else + _cx_raw rx = i_keyto(x); + return i_hash((&rx)); + #endif +} + +STC_INLINE int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { + #if c_option(c_no_cmp) + return c_default_cmp(&x, &y); + #else + _cx_raw rx = i_keyto(x), ry = i_keyto(y); + return i_cmp((&rx), (&ry)); + #endif +} + +STC_INLINE bool _cx_memb(_value_eq)(const _cx_value* x, const _cx_value* y) { + #if c_option(c_no_cmp) + return x == y; + #else + _cx_raw rx = i_keyto(x), ry = i_keyto(y); + return i_eq((&rx), (&ry)); + #endif +} +#include "template.h" diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index b67fb598..110114a0 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -1,269 +1,269 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef CCOMMON_H_INCLUDED
-#define CCOMMON_H_INCLUDED
-
-#define _CRT_SECURE_NO_WARNINGS
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <string.h>
-#include <assert.h>
-
-#if defined(_MSC_VER)
-# pragma warning(disable: 4116 4996) // unnamed type definition in parentheses
-# define STC_FORCE_INLINE static __forceinline
-#elif defined(__GNUC__) || defined(__clang__)
-# define STC_FORCE_INLINE static inline __attribute((always_inline))
-#else
-# define STC_FORCE_INLINE static inline
-#endif
-#define STC_INLINE static inline
-
-/* Macro overloading feature support based on: https://rextester.com/ONP80107 */
-#define c_MACRO_OVERLOAD(name, ...) \
- c_paste(name, c_numargs(__VA_ARGS__))(__VA_ARGS__)
-#define c_concat(a, b) a ## b
-#define c_paste(a, b) c_concat(a, b)
-#define c_expand(...) __VA_ARGS__
-#define c_numargs(...) _c_APPLY_ARG_N((__VA_ARGS__, _c_RSEQ_N))
-
-#define _c_APPLY_ARG_N(args) c_expand(_c_ARG_N args)
-#define _c_RSEQ_N 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
-#define _c_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
- _14, _15, _16, N, ...) N
-
-#define c_static_assert(cond) \
- typedef char c_paste(_static_assert_line_, __LINE__)[(cond) ? 1 : -1]
-#define c_unchecked_container_of(ptr, type, member) \
- ((type *)((char *)(ptr) - offsetof(type, member)))
-#if __STDC_VERSION__ >= 202300L || defined STC_CHECKED_CONTAINER_OF
-# define c_container_of(ptr, type, member) \
- (((type *)((char *)(ptr) - offsetof(type, member))) + \
- ((typeof(ptr))0 != (typeof(&((type *)0)->member))0))
-#else
-# define c_container_of(p,t,m) c_unchecked_container_of(p,t,m)
-#endif
-#ifndef __cplusplus
-# define c_alloc(T) c_malloc(sizeof(T))
-# define c_alloc_n(T, n) c_malloc(sizeof(T)*(n))
-# define c_make(T) (T)
-# define c_new(T, ...) (T*)memcpy(c_alloc(T), (T[]){__VA_ARGS__}, sizeof(T))
-#else
-# include <new>
-# define c_alloc(T) static_cast<T*>(c_malloc(sizeof(T)))
-# define c_alloc_n(T, n) static_cast<T*>(c_malloc(sizeof(T)*(n)))
-# define c_make(T) T
-# define c_new(T, ...) new (c_alloc(T)) T(__VA_ARGS__)
-#endif
-#ifndef c_malloc
-# define c_malloc(sz) malloc(sz)
-# define c_calloc(n, sz) calloc(n, sz)
-# define c_realloc(p, sz) realloc(p, sz)
-# define c_free(p) free(p)
-#endif
-
-#define c_delete(T, ptr) do { T *_c_p = ptr; T##_drop(_c_p); c_free(_c_p); } while (0)
-#define c_swap(T, x, y) do { T _c_t = x; x = y; y = _c_t; } while (0)
-#define c_arraylen(a) (sizeof (a)/sizeof *(a))
-
-// x and y are i_keyraw* type, defaults to i_key*:
-#define c_less_cmp(less, x, y) ((less((y), (x))) - (less((x), (y))))
-#define c_default_cmp(x, y) c_less_cmp(c_default_less, x, y)
-#define c_default_less(x, y) (*(x) < *(y))
-#define c_default_eq(x, y) (*(x) == *(y))
-#define c_memcmp_eq(x, y) (memcmp(x, y, sizeof *(x)) == 0)
-#define c_default_hash(x) c_fasthash(x, sizeof *(x))
-
-#define c_default_clone(v) (v)
-#define c_default_toraw(vp) (*(vp))
-#define c_default_drop(vp) ((void) (vp))
-#define c_derived_keyclone(v) i_keyfrom((i_keyto((&(v)))))
-#define c_derived_valclone(v) i_valfrom((i_valto((&(v)))))
-
-#define c_option(flag) ((i_opt) & (flag))
-#define c_is_fwd (1<<0)
-#define c_no_atomic (1<<1)
-#define c_no_clone (1<<2)
-#define c_no_cmp (1<<3)
-
-/* Generic algorithms */
-
-typedef const char* crawstr;
-#define crawstr_cmp(xp, yp) strcmp(*(xp), *(yp))
-#define crawstr_hash(p) c_strhash(*(p))
-#define c_strlen_lit(literal) (sizeof "" literal - 1U)
-#define c_sv(lit) c_make(csview){lit, c_strlen_lit(lit)}
-#define c_PRIsv ".*s"
-#define c_ARGsv(sv) (int)(sv).size, (sv).str
-
-#define _c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k)))
-
-STC_INLINE uint64_t c_fasthash(const void* key, size_t len) {
- const uint8_t *x = (const uint8_t*) key;
- uint64_t u8, h = 1; size_t n = len >> 3;
- uint32_t u4;
- while (n--) {
- memcpy(&u8, x, 8), x += 8;
- h += (_c_ROTL(u8, 26) ^ u8)*0xc6a4a7935bd1e99d;
- }
- switch (len &= 7) {
- case 0: return h;
- case 4: memcpy(&u4, x, 4);
- return h + u4*0xc6a4a7935bd1e99d;
- }
- h += *x++;
- while (--len) h = (h << 10) - h + *x++;
- return _c_ROTL(h, 26) ^ h;
-}
-
-STC_INLINE uint64_t c_strhash(const char *str)
- { return c_fasthash(str, strlen(str)); }
-
-STC_INLINE char* c_strnstrn(const char *s, const char *needle,
- size_t slen, const size_t nlen) {
- if (!nlen) return (char *)s;
- if (nlen > slen) return NULL;
- slen -= nlen;
- do {
- if (*s == *needle && !memcmp(s, needle, nlen))
- return (char *)s;
- ++s;
- } while (slen--);
- return NULL;
-}
-
-#define c_foreach(...) c_MACRO_OVERLOAD(c_foreach, __VA_ARGS__)
-#define c_foreach3(it, C, cnt) \
- for (C##_iter it = C##_begin(&cnt), it##_end_ = C##_end(&cnt) \
- ; it.ref != it##_end_.ref; C##_next(&it))
-#define c_foreach4(it, C, start, finish) \
- for (C##_iter it = start, it##_end_ = finish \
- ; it.ref != it##_end_.ref; C##_next(&it))
-
-#define c_forpair(key, val, C, cnt) /* structured binding */ \
- for (struct {C##_iter _it; C##_value* _endref; const C##_key* key; C##_mapped* val;} \
- _ = {C##_begin(&cnt), C##_end(&cnt).ref} \
- ; _._it.ref != _._endref && (_.key = &_._it.ref->first, _.val = &_._it.ref->second) \
- ; C##_next(&_._it))
-
-#define c_forrange(...) c_MACRO_OVERLOAD(c_forrange, __VA_ARGS__)
-#define c_forrange1(stop) for (size_t _c_ii=0, _c_end=stop; _c_ii < _c_end; ++_c_ii)
-#define c_forrange2(i, stop) for (size_t i=0, _c_end=stop; i < _c_end; ++i)
-#define c_forrange3(i, type, stop) for (type i=0, _c_end=stop; i < _c_end; ++i)
-#define c_forrange4(i, type, start, stop) for (type i=start, _c_end=stop; i < _c_end; ++i)
-#define c_forrange5(i, type, start, stop, step) \
- for (type i=start, _c_inc=step, _c_end=(stop) - (0 < _c_inc) \
- ; (i <= _c_end) == (0 < _c_inc); i += _c_inc)
-
-#define c_autovar(...) c_MACRO_OVERLOAD(c_autovar, __VA_ARGS__)
-#define c_autovar2(declvar, drop) for (declvar, **_c_ii = NULL; !_c_ii; ++_c_ii, drop)
-#define c_autovar3(declvar, pred, drop) for (declvar, **_c_ii = NULL; !_c_ii && (pred); ++_c_ii, drop)
-#define c_autoscope(init, drop) for (int _c_ii = (init, 0); !_c_ii; ++_c_ii, drop)
-#define c_autodefer(...) for (int _c_ii = 0; !_c_ii; ++_c_ii, __VA_ARGS__)
-#define c_breakauto continue
-
-#define c_auto(...) c_MACRO_OVERLOAD(c_auto, __VA_ARGS__)
-#define c_auto2(C, a) \
- c_autovar2(C a = C##_init(), C##_drop(&a))
-#define c_auto3(C, a, b) \
- c_autovar2(c_expand(C a = C##_init(), b = C##_init()), \
- (C##_drop(&b), C##_drop(&a)))
-#define c_auto4(C, a, b, c) \
- c_autovar2(c_expand(C a = C##_init(), b = C##_init(), c = C##_init()), \
- (C##_drop(&c), C##_drop(&b), C##_drop(&a)))
-#define c_auto5(C, a, b, c, d) \
- c_autovar2(c_expand(C a = C##_init(), b = C##_init(), c = C##_init(), d = C##_init()), \
- (C##_drop(&d), C##_drop(&c), C##_drop(&b), C##_drop(&a)))
-
-#define c_autobuf(b, type, n) c_autobuf_N(b, type, n, 256)
-#define c_autobuf_N(b, type, n, BYTES) \
- for (type _c_b[((BYTES) - 1) / sizeof(type) + 1], \
- *b = (n)*sizeof *b > (BYTES) ? c_alloc_n(type, n) : _c_b \
- ; b; b != _c_b ? c_free(b) : (void)0, b = NULL)
-
-#define c_apply(v, action, T, ...) do { \
- typedef T _c_T; \
- const _c_T _c_arr[] = __VA_ARGS__, *v = _c_arr, \
- *_c_end = v + c_arraylen(_c_arr); \
- while (v != _c_end) { action; ++v; } \
-} while (0)
-
-#define c_apply_arr(v, action, T, arr, n) do { \
- typedef T _c_T; \
- _c_T *v = arr, *_c_end = v + (n); \
- while (v != _c_end) { action; ++v; } \
-} while (0)
-
-#define c_pair(v) (v)->first, (v)->second
-
-#define c_find_if(C, cnt, it, pred) \
- c_find_in(C, C##_begin(&cnt), C##_end(&cnt), it, pred)
-#define c_find_from(C, cnt, it, pred) \
- c_find_in(C, it, C##_end(&cnt), it, pred)
-// NB: it.ref == NULL when not found, not end.ref:
-#define c_find_in(C, start, end, it, pred) do { \
- size_t index = 0; \
- C##_iter _end = end; \
- for (it = start; it.ref != _end.ref && !(pred); C##_next(&it)) \
- ++index; \
- if (it.ref == _end.ref) it.ref = NULL; \
-} while (0)
-
-#define c_drop(C, ...) do { \
- C* _c_arr[] = {__VA_ARGS__}; \
- for (size_t _c_i = 0; _c_i < c_arraylen(_c_arr); ++_c_i) \
- C##_drop(_c_arr[_c_i]); \
-} while (0)
-
-#if defined(__SIZEOF_INT128__)
- #define c_umul128(a, b, lo, hi) \
- do { __uint128_t _z = (__uint128_t)(a)*(b); \
- *(lo) = (uint64_t)_z, *(hi) = _z >> 64; } while(0)
-#elif defined(_MSC_VER) && defined(_WIN64)
- #include <intrin.h>
- #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi)))
-#elif defined(__x86_64__)
- #define c_umul128(a, b, lo, hi) \
- asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b))
-#endif
-#endif // CCOMMON_H_INCLUDED
-
-#undef STC_API
-#undef STC_DEF
-
-#if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \
- defined(i_implement) || defined(STC_IMPLEMENT))
-# define STC_API extern
-# define STC_DEF
-#else
-# define i_static
-# define STC_API static inline
-# define STC_DEF static inline
-#endif
-#if defined(STC_EXTERN)
-# define i_extern
-#endif
-#if defined(i_static) || defined(STC_IMPLEMENT)
-# define i_implement
-#endif
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef CCOMMON_H_INCLUDED +#define CCOMMON_H_INCLUDED + +#define _CRT_SECURE_NO_WARNINGS +#include <inttypes.h> +#include <stddef.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> + +#if defined(_MSC_VER) +# pragma warning(disable: 4116 4996) // unnamed type definition in parentheses +# define STC_FORCE_INLINE static __forceinline +#elif defined(__GNUC__) || defined(__clang__) +# define STC_FORCE_INLINE static inline __attribute((always_inline)) +#else +# define STC_FORCE_INLINE static inline +#endif +#define STC_INLINE static inline + +/* Macro overloading feature support based on: https://rextester.com/ONP80107 */ +#define c_MACRO_OVERLOAD(name, ...) \ + c_paste(name, c_numargs(__VA_ARGS__))(__VA_ARGS__) +#define c_concat(a, b) a ## b +#define c_paste(a, b) c_concat(a, b) +#define c_expand(...) __VA_ARGS__ +#define c_numargs(...) _c_APPLY_ARG_N((__VA_ARGS__, _c_RSEQ_N)) + +#define _c_APPLY_ARG_N(args) c_expand(_c_ARG_N args) +#define _c_RSEQ_N 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +#define _c_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \ + _14, _15, _16, N, ...) N + +#define c_static_assert(cond) \ + typedef char c_paste(_static_assert_line_, __LINE__)[(cond) ? 1 : -1] +#define c_unchecked_container_of(ptr, type, member) \ + ((type *)((char *)(ptr) - offsetof(type, member))) +#if __STDC_VERSION__ >= 202300L || defined STC_CHECKED_CONTAINER_OF +# define c_container_of(ptr, type, member) \ + (((type *)((char *)(ptr) - offsetof(type, member))) + \ + ((typeof(ptr))0 != (typeof(&((type *)0)->member))0)) +#else +# define c_container_of(p,t,m) c_unchecked_container_of(p,t,m) +#endif +#ifndef __cplusplus +# define c_alloc(T) c_malloc(sizeof(T)) +# define c_alloc_n(T, n) c_malloc(sizeof(T)*(n)) +# define c_make(T) (T) +# define c_new(T, ...) (T*)memcpy(c_alloc(T), (T[]){__VA_ARGS__}, sizeof(T)) +#else +# include <new> +# define c_alloc(T) static_cast<T*>(c_malloc(sizeof(T))) +# define c_alloc_n(T, n) static_cast<T*>(c_malloc(sizeof(T)*(n))) +# define c_make(T) T +# define c_new(T, ...) new (c_alloc(T)) T(__VA_ARGS__) +#endif +#ifndef c_malloc +# define c_malloc(sz) malloc(sz) +# define c_calloc(n, sz) calloc(n, sz) +# define c_realloc(p, sz) realloc(p, sz) +# define c_free(p) free(p) +#endif + +#define c_delete(T, ptr) do { T *_c_p = ptr; T##_drop(_c_p); c_free(_c_p); } while (0) +#define c_swap(T, x, y) do { T _c_t = x; x = y; y = _c_t; } while (0) +#define c_arraylen(a) (sizeof (a)/sizeof *(a)) + +// x and y are i_keyraw* type, defaults to i_key*: +#define c_less_cmp(less, x, y) ((less((y), (x))) - (less((x), (y)))) +#define c_default_cmp(x, y) c_less_cmp(c_default_less, x, y) +#define c_default_less(x, y) (*(x) < *(y)) +#define c_default_eq(x, y) (*(x) == *(y)) +#define c_memcmp_eq(x, y) (memcmp(x, y, sizeof *(x)) == 0) +#define c_default_hash(x) c_fasthash(x, sizeof *(x)) + +#define c_default_clone(v) (v) +#define c_default_toraw(vp) (*(vp)) +#define c_default_drop(vp) ((void) (vp)) +#define c_derived_keyclone(v) i_keyfrom((i_keyto((&(v))))) +#define c_derived_valclone(v) i_valfrom((i_valto((&(v))))) + +#define c_option(flag) ((i_opt) & (flag)) +#define c_is_fwd (1<<0) +#define c_no_atomic (1<<1) +#define c_no_clone (1<<2) +#define c_no_cmp (1<<3) + +/* Generic algorithms */ + +typedef const char* crawstr; +#define crawstr_cmp(xp, yp) strcmp(*(xp), *(yp)) +#define crawstr_hash(p) c_strhash(*(p)) +#define c_strlen_lit(literal) (sizeof "" literal - 1U) +#define c_sv(lit) c_make(csview){lit, c_strlen_lit(lit)} +#define c_PRIsv ".*s" +#define c_ARGsv(sv) (int)(sv).size, (sv).str + +#define _c_ROTL(x, k) (x << (k) | x >> (8*sizeof(x) - (k))) + +STC_INLINE uint64_t c_fasthash(const void* key, size_t len) { + const uint8_t *x = (const uint8_t*) key; + uint64_t u8, h = 1; size_t n = len >> 3; + uint32_t u4; + while (n--) { + memcpy(&u8, x, 8), x += 8; + h += (_c_ROTL(u8, 26) ^ u8)*0xc6a4a7935bd1e99d; + } + switch (len &= 7) { + case 0: return h; + case 4: memcpy(&u4, x, 4); + return h + u4*0xc6a4a7935bd1e99d; + } + h += *x++; + while (--len) h = (h << 10) - h + *x++; + return _c_ROTL(h, 26) ^ h; +} + +STC_INLINE uint64_t c_strhash(const char *str) + { return c_fasthash(str, strlen(str)); } + +STC_INLINE char* c_strnstrn(const char *s, const char *needle, + size_t slen, const size_t nlen) { + if (!nlen) return (char *)s; + if (nlen > slen) return NULL; + slen -= nlen; + do { + if (*s == *needle && !memcmp(s, needle, nlen)) + return (char *)s; + ++s; + } while (slen--); + return NULL; +} + +#define c_foreach(...) c_MACRO_OVERLOAD(c_foreach, __VA_ARGS__) +#define c_foreach3(it, C, cnt) \ + for (C##_iter it = C##_begin(&cnt), it##_end_ = C##_end(&cnt) \ + ; it.ref != it##_end_.ref; C##_next(&it)) +#define c_foreach4(it, C, start, finish) \ + for (C##_iter it = start, it##_end_ = finish \ + ; it.ref != it##_end_.ref; C##_next(&it)) + +#define c_forpair(key, val, C, cnt) /* structured binding */ \ + for (struct {C##_iter _it; C##_value* _endref; const C##_key* key; C##_mapped* val;} \ + _ = {C##_begin(&cnt), C##_end(&cnt).ref} \ + ; _._it.ref != _._endref && (_.key = &_._it.ref->first, _.val = &_._it.ref->second) \ + ; C##_next(&_._it)) + +#define c_forrange(...) c_MACRO_OVERLOAD(c_forrange, __VA_ARGS__) +#define c_forrange1(stop) for (size_t _c_ii=0, _c_end=stop; _c_ii < _c_end; ++_c_ii) +#define c_forrange2(i, stop) for (size_t i=0, _c_end=stop; i < _c_end; ++i) +#define c_forrange3(i, type, stop) for (type i=0, _c_end=stop; i < _c_end; ++i) +#define c_forrange4(i, type, start, stop) for (type i=start, _c_end=stop; i < _c_end; ++i) +#define c_forrange5(i, type, start, stop, step) \ + for (type i=start, _c_inc=step, _c_end=(stop) - (0 < _c_inc) \ + ; (i <= _c_end) == (0 < _c_inc); i += _c_inc) + +#define c_autovar(...) c_MACRO_OVERLOAD(c_autovar, __VA_ARGS__) +#define c_autovar2(declvar, drop) for (declvar, **_c_ii = NULL; !_c_ii; ++_c_ii, drop) +#define c_autovar3(declvar, pred, drop) for (declvar, **_c_ii = NULL; !_c_ii && (pred); ++_c_ii, drop) +#define c_autoscope(init, drop) for (int _c_ii = (init, 0); !_c_ii; ++_c_ii, drop) +#define c_autodefer(...) for (int _c_ii = 0; !_c_ii; ++_c_ii, __VA_ARGS__) +#define c_breakauto continue + +#define c_auto(...) c_MACRO_OVERLOAD(c_auto, __VA_ARGS__) +#define c_auto2(C, a) \ + c_autovar2(C a = C##_init(), C##_drop(&a)) +#define c_auto3(C, a, b) \ + c_autovar2(c_expand(C a = C##_init(), b = C##_init()), \ + (C##_drop(&b), C##_drop(&a))) +#define c_auto4(C, a, b, c) \ + c_autovar2(c_expand(C a = C##_init(), b = C##_init(), c = C##_init()), \ + (C##_drop(&c), C##_drop(&b), C##_drop(&a))) +#define c_auto5(C, a, b, c, d) \ + c_autovar2(c_expand(C a = C##_init(), b = C##_init(), c = C##_init(), d = C##_init()), \ + (C##_drop(&d), C##_drop(&c), C##_drop(&b), C##_drop(&a))) + +#define c_autobuf(b, type, n) c_autobuf_N(b, type, n, 256) +#define c_autobuf_N(b, type, n, BYTES) \ + for (type _c_b[((BYTES) - 1) / sizeof(type) + 1], \ + *b = (n)*sizeof *b > (BYTES) ? c_alloc_n(type, n) : _c_b \ + ; b; b != _c_b ? c_free(b) : (void)0, b = NULL) + +#define c_apply(v, action, T, ...) do { \ + typedef T _c_T; \ + const _c_T _c_arr[] = __VA_ARGS__, *v = _c_arr, \ + *_c_end = v + c_arraylen(_c_arr); \ + while (v != _c_end) { action; ++v; } \ +} while (0) + +#define c_apply_arr(v, action, T, arr, n) do { \ + typedef T _c_T; \ + _c_T *v = arr, *_c_end = v + (n); \ + while (v != _c_end) { action; ++v; } \ +} while (0) + +#define c_pair(v) (v)->first, (v)->second + +#define c_find_if(C, cnt, it, pred) \ + c_find_in(C, C##_begin(&cnt), C##_end(&cnt), it, pred) +#define c_find_from(C, cnt, it, pred) \ + c_find_in(C, it, C##_end(&cnt), it, pred) +// NB: it.ref == NULL when not found, not end.ref: +#define c_find_in(C, start, end, it, pred) do { \ + size_t index = 0; \ + C##_iter _end = end; \ + for (it = start; it.ref != _end.ref && !(pred); C##_next(&it)) \ + ++index; \ + if (it.ref == _end.ref) it.ref = NULL; \ +} while (0) + +#define c_drop(C, ...) do { \ + C* _c_arr[] = {__VA_ARGS__}; \ + for (size_t _c_i = 0; _c_i < c_arraylen(_c_arr); ++_c_i) \ + C##_drop(_c_arr[_c_i]); \ +} while (0) + +#if defined(__SIZEOF_INT128__) + #define c_umul128(a, b, lo, hi) \ + do { __uint128_t _z = (__uint128_t)(a)*(b); \ + *(lo) = (uint64_t)_z, *(hi) = _z >> 64; } while(0) +#elif defined(_MSC_VER) && defined(_WIN64) + #include <intrin.h> + #define c_umul128(a, b, lo, hi) ((void)(*(lo) = _umul128(a, b, hi))) +#elif defined(__x86_64__) + #define c_umul128(a, b, lo, hi) \ + asm("mulq %3" : "=a"(*(lo)), "=d"(*(hi)) : "a"(a), "rm"(b)) +#endif +#endif // CCOMMON_H_INCLUDED + +#undef STC_API +#undef STC_DEF + +#if !defined(i_static) && !defined(STC_STATIC) && (defined(i_header) || defined(STC_HEADER) || \ + defined(i_implement) || defined(STC_IMPLEMENT)) +# define STC_API extern +# define STC_DEF +#else +# define i_static +# define STC_API static inline +# define STC_DEF static inline +#endif +#if defined(STC_EXTERN) +# define i_extern +#endif +#if defined(i_static) || defined(STC_IMPLEMENT) +# define i_implement +#endif diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index b0198678..afe01165 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -1,437 +1,437 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include "ccommon.h"
-
-#ifndef CDEQ_H_INCLUDED
-#include "forward.h"
-#include <stdlib.h>
-#include <string.h>
-
-struct cdeq_rep { size_t size, cap; unsigned base[1]; };
-#define cdeq_rep_(self) c_unchecked_container_of((self)->_base, struct cdeq_rep, base)
-#endif // CDEQ_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix cdeq_
-#endif
-#include "template.h"
-
-#if !c_option(c_is_fwd)
-_cx_deftypes(_c_cdeq_types, _cx_self, i_key);
-#endif
-typedef i_keyraw _cx_raw;
-
-STC_API _cx_self _cx_memb(_init)(void);
-STC_API _cx_self _cx_memb(_with_capacity)(const size_t n);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, const size_t n);
-STC_API void _cx_memb(_clear)(_cx_self* self);
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value);
-STC_API void _cx_memb(_shrink_to_fit)(_cx_self *self);
-#if !defined _i_queue
-#if !defined _i_no_clone
-STC_API _cx_value* _cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
-#if !defined _i_no_emplace
-STC_API _cx_value* _cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_raw* p1, const _cx_raw* p2);
-#endif // _i_no_emplace
-#endif // !_i_no_clone
-
-#if !c_option(c_no_cmp)
-STC_API _cx_iter _cx_memb(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw);
-STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y);
-#endif
-STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value);
-STC_API _cx_iter _cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2);
-STC_API _cx_value* _cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
-#endif // !_i_queue
-
-#if !defined _i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
-#if !defined _i_no_emplace
-STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-#endif
-STC_INLINE i_key _cx_memb(_value_clone)(i_key val)
- { return i_keyclone(val); }
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->data == other.data) return;
- _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other);
- }
-#endif // !_i_no_clone
-STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return cdeq_rep_(&cx)->size; }
-STC_INLINE size_t _cx_memb(_capacity)(_cx_self cx) { return cdeq_rep_(&cx)->cap; }
-STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return !cdeq_rep_(&cx)->size; }
-STC_INLINE _cx_raw _cx_memb(_value_toraw)(_cx_value* pval) { return i_keyto(pval); }
-STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); }
-STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->data; }
-STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self)
- { return self->data + cdeq_rep_(self)->size - 1; }
-STC_INLINE void _cx_memb(_pop_front)(_cx_self* self) // == _pop() when _i_queue
- { i_keydrop(self->data); ++self->data; --cdeq_rep_(self)->size; }
-STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self)
- { return c_make(_cx_iter){self->data}; }
-STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
- { return c_make(_cx_iter){self->data + cdeq_rep_(self)->size}; }
-STC_INLINE void _cx_memb(_next)(_cx_iter* it) { ++it->ref; }
-STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t offs)
- { it.ref += offs; return it; }
-
-#if !defined _i_queue
-
-STC_INLINE size_t _cx_memb(_index)(_cx_self cx, _cx_iter it)
- { return it.ref - cx.data; }
-STC_INLINE void _cx_memb(_pop_back)(_cx_self* self)
- { _cx_value* p = &self->data[--cdeq_rep_(self)->size]; i_keydrop(p); }
-
-STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, const size_t idx) {
- assert(idx < cdeq_rep_(self)->size); return self->data + idx;
-}
-STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, const size_t idx) {
- assert(idx < cdeq_rep_(self)->size); return self->data + idx;
-}
-
-STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value) {
- return _cx_memb(_push)(self, value);
-}
-STC_INLINE _cx_value*
-_cx_memb(_insert)(_cx_self* self, const size_t idx, i_key value) {
- return _cx_memb(_insert_range_p)(self, self->data + idx, &value, &value + 1);
-}
-STC_INLINE _cx_value*
-_cx_memb(_insert_n)(_cx_self* self, const size_t idx, const _cx_value arr[], const size_t n) {
- return _cx_memb(_insert_range_p)(self, self->data + idx, arr, arr + n);
-}
-STC_INLINE _cx_value*
-_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
- return _cx_memb(_insert_range_p)(self, it.ref, &value, &value + 1);
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_erase_n)(_cx_self* self, const size_t idx, const size_t n) {
- return _cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n);
-}
-STC_INLINE _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- return _cx_memb(_erase_range_p)(self, it.ref, it.ref + 1);
-}
-STC_INLINE _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
- return _cx_memb(_erase_range_p)(self, it1.ref, it2.ref);
-}
-
-#if !defined _i_no_clone && !defined _i_no_emplace
-STC_INLINE _cx_value*
-_cx_memb(_emplace_range)(_cx_self* self, _cx_iter it, _cx_iter it1, _cx_iter it2) {
- return _cx_memb(_clone_range_p)(self, it.ref, it1.ref, it2.ref);
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw) {
- return _cx_memb(_push_front)(self, i_keyfrom(raw));
-}
-
-STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) {
- return _cx_memb(_push)(self, i_keyfrom(raw));
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_emplace_n)(_cx_self* self, const size_t idx, const _cx_raw arr[], const size_t n) {
- return _cx_memb(_emplace_range_p)(self, self->data + idx, arr, arr + n);
-}
-STC_INLINE _cx_value*
-_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) {
- return _cx_memb(_emplace_range_p)(self, it.ref, &raw, &raw + 1);
-}
-#endif // !_i_no_clone && !_i_no_emplace
-
-#if !c_option(c_no_cmp)
-
-STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_raw raw) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw);
-}
-
-STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_raw raw) {
- _cx_iter end = _cx_memb(_end)(self);
- _cx_value* val = _cx_memb(_find_in)(_cx_memb(_begin)(self), end, raw).ref;
- return val == end.ref ? NULL : val;
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_get_mut)(_cx_self* self, _cx_raw raw)
- { return (_cx_value *) _cx_memb(_get)(self, raw); }
-
-STC_INLINE void
-_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2,
- int(*_cmp_)(const _cx_value*, const _cx_value*)) {
- qsort(i1.ref, i2.ref - i1.ref, sizeof *i1.ref, (int(*)(const void*, const void*)) _cmp_);
-}
-
-STC_INLINE void
-_cx_memb(_sort)(_cx_self* self) {
- _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp));
-}
-#endif // !c_no_cmp
-#endif // _i_queue
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-#ifndef CDEQ_H_INCLUDED
-static struct cdeq_rep _cdeq_sentinel = {0, 0};
-#define _cdeq_nfront(self) ((self)->data - (self)->_base)
-#endif
-
-STC_DEF _cx_self
-_cx_memb(_init)(void) {
- _cx_value *b = (_cx_value *) _cdeq_sentinel.base;
- return c_make(_cx_self){b, b};
-}
-
-STC_DEF void
-_cx_memb(_clear)(_cx_self* self) {
- struct cdeq_rep* rep = cdeq_rep_(self);
- if (rep->cap) {
- for (_cx_value *p = self->data, *q = p + rep->size; p != q; ) {
- --q; i_keydrop(q);
- }
- rep->size = 0;
- }
-}
-
-STC_DEF void
-_cx_memb(_shrink_to_fit)(_cx_self *self) {
- if (_cx_memb(_size)(*self) != _cx_memb(_capacity)(*self)) {
- struct cdeq_rep* rep = cdeq_rep_(self);
- const size_t sz = rep->size;
- memmove(self->_base, self->data, sz*sizeof(i_key));
- rep = (struct cdeq_rep*) c_realloc(rep, offsetof(struct cdeq_rep, base) + sz*sizeof(i_key));
- if (rep) {
- self->_base = self->data = (_cx_value*)rep->base;
- rep->cap = sz;
- }
- }
-}
-
-STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
- struct cdeq_rep* rep = cdeq_rep_(self);
- // second test to supress gcc -O2 warn: -Wfree-nonheap-object
- if (rep->cap == 0 || rep == &_cdeq_sentinel)
- return;
- _cx_memb(_clear)(self);
- c_free(rep);
-}
-
-static size_t
-_cx_memb(_realloc_)(_cx_self* self, const size_t n) {
- struct cdeq_rep* rep = cdeq_rep_(self);
- const size_t sz = rep->size, cap = (size_t) (sz*1.7) + n + 7;
- const size_t nfront = _cdeq_nfront(self);
- rep = (struct cdeq_rep*) c_realloc(rep->cap ? rep : NULL,
- offsetof(struct cdeq_rep, base) + cap*sizeof(i_key));
- if (!rep)
- return 0;
- rep->size = sz, rep->cap = cap;
- self->_base = (_cx_value *) rep->base;
- self->data = self->_base + nfront;
- return cap;
-}
-
-static bool
-_cx_memb(_expand_right_half_)(_cx_self* self, const size_t idx, const size_t n) {
- struct cdeq_rep* rep = cdeq_rep_(self);
- const size_t sz = rep->size, cap = rep->cap;
- const size_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront;
- if (nback >= n || sz*1.3 + n > cap) {
- if (!_cx_memb(_realloc_)(self, n))
- return false;
- memmove(self->data + idx + n, self->data + idx, (sz - idx)*sizeof(i_key));
- } else {
-#if !defined _i_queue
- const size_t unused = cap - (sz + n);
- const size_t pos = (nfront*2 < unused) ? nfront : unused/2;
-#else
- const size_t pos = 0;
-#endif
- memmove(self->_base + pos, self->data, idx*sizeof(i_key));
- memmove(self->data + pos + idx + n, self->data + idx, (sz - idx)*sizeof(i_key));
- self->data = self->_base + pos;
- }
- return true;
-}
-
-STC_DEF _cx_self
-_cx_memb(_with_capacity)(const size_t n) {
- _cx_self cx = _cx_memb(_init)();
- _cx_memb(_expand_right_half_)(&cx, 0, n);
- return cx;
-}
-
-STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const size_t n) {
- const size_t sz = cdeq_rep_(self)->size;
- return n <= sz || _cx_memb(_expand_right_half_)(self, sz, n - sz);
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push)(_cx_self* self, i_key value) {
- struct cdeq_rep* r = cdeq_rep_(self);
- if (_cdeq_nfront(self) + r->size == r->cap) {
- _cx_memb(_expand_right_half_)(self, r->size, 1);
- r = cdeq_rep_(self);
- }
- _cx_value *v = self->data + r->size++;
- *v = value; return v;
-}
-
-#if !c_option(c_no_clone)
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self cx) {
- const size_t sz = cdeq_rep_(&cx)->size;
- _cx_self out = _cx_memb(_with_capacity)(sz);
- if (cdeq_rep_(&out)->cap) {
- cdeq_rep_(&out)->size = sz;
- for (size_t i = 0; i < sz; ++i)
- out.data[i] = i_keyclone(cx.data[i]);
- }
- return out;
-}
-#endif
-
-#if !defined _i_queue
-
-static void
-_cx_memb(_expand_left_half_)(_cx_self* self, const size_t idx, const size_t n) {
- struct cdeq_rep* rep = cdeq_rep_(self);
- size_t cap = rep->cap;
- const size_t sz = rep->size;
- const size_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront;
- if (nfront >= n) {
- self->data = (_cx_value *)memmove(self->data - n, self->data, idx*sizeof(i_key));
- } else {
- if (sz*1.3 + n > cap)
- cap = _cx_memb(_realloc_)(self, n);
- const size_t unused = cap - (sz + n);
- const size_t pos = (nback*2 < unused) ? unused - nback : unused/2;
- memmove(self->_base + pos + idx + n, self->data + idx, (sz - idx)*sizeof(i_key));
- self->data = (_cx_value *)memmove(self->_base + pos, self->data, idx*sizeof(i_key));
- }
-}
-
-static _cx_value*
-_cx_memb(_expand_uninit_p)(_cx_self* self, const _cx_value* pos, const size_t n) {
- const size_t idx = pos - self->data;
- if (idx*2 < cdeq_rep_(self)->size)
- _cx_memb(_expand_left_half_)(self, idx, n);
- else
- _cx_memb(_expand_right_half_)(self, idx, n);
- if (n)
- cdeq_rep_(self)->size += n; /* do only if size > 0 */
- return self->data + idx;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push_front)(_cx_self* self, i_key value) {
- if (self->data == self->_base)
- _cx_memb(_expand_left_half_)(self, 0, 1);
- else
- --self->data;
- ++cdeq_rep_(self)->size;
- *self->data = value;
- return self->data;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
- if (pos)
- memcpy(pos, p1, (p2 - p1)*sizeof *p1);
- return pos;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2) {
- const size_t n = p2 - p1;
- if (n > 0) {
- _cx_value* p = p1, *end = self->data + cdeq_rep_(self)->size;
- for (; p != p2; ++p) { i_keydrop(p); }
- if (p1 == self->data)
- self->data += n;
- else memmove(p1, p2, (end - p2) * sizeof(i_key));
- cdeq_rep_(self)->size -= n;
- }
- return c_make(_cx_iter){p1};
-}
-
-#if !defined _i_no_clone
-#if !defined _i_no_emplace
-STC_DEF _cx_value*
-_cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos, const _cx_raw* p1, const _cx_raw* p2) {
- pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
- _cx_value* it = pos;
- if (pos) for (; p1 != p2; ++p1)
- *pos++ = i_keyfrom((*p1));
- return it;
-}
-#endif // !_i_no_emplace
-
-STC_DEF _cx_value*
-_cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
- _cx_value* it = pos;
- if (pos) for (; p1 != p2; ++p1)
- *pos++ = i_keyclone((*p1));
- return it;
-}
-#endif // !_i_no_clone
-
-#if !c_option(c_no_cmp)
-
-STC_DEF _cx_iter
-_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
- for (; i1.ref != i2.ref; ++i1.ref) {
- _cx_raw r = i_keyto(i1.ref);
- if (i_eq((&raw), (&r)))
- return i1;
- }
- return i2;
-}
-
-STC_DEF int
-_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- const _cx_raw rx = i_keyto(x);
- const _cx_raw ry = i_keyto(y);
- return i_cmp((&rx), (&ry));
-}
-#endif // !c_no_cmp
-#endif // !_i_queue
-#endif // IMPLEMENTATION
-#include "template.h"
-#define CDEQ_H_INCLUDED
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "ccommon.h" + +#ifndef CDEQ_H_INCLUDED +#include "forward.h" +#include <stdlib.h> +#include <string.h> + +struct cdeq_rep { size_t size, cap; unsigned base[1]; }; +#define cdeq_rep_(self) c_unchecked_container_of((self)->_base, struct cdeq_rep, base) +#endif // CDEQ_H_INCLUDED + +#ifndef _i_prefix +#define _i_prefix cdeq_ +#endif +#include "template.h" + +#if !c_option(c_is_fwd) +_cx_deftypes(_c_cdeq_types, _cx_self, i_key); +#endif +typedef i_keyraw _cx_raw; + +STC_API _cx_self _cx_memb(_init)(void); +STC_API _cx_self _cx_memb(_with_capacity)(const size_t n); +STC_API bool _cx_memb(_reserve)(_cx_self* self, const size_t n); +STC_API void _cx_memb(_clear)(_cx_self* self); +STC_API void _cx_memb(_drop)(_cx_self* self); +STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value); +STC_API void _cx_memb(_shrink_to_fit)(_cx_self *self); +#if !defined _i_queue +#if !defined _i_no_clone +STC_API _cx_value* _cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos, + const _cx_value* p1, const _cx_value* p2); +#if !defined _i_no_emplace +STC_API _cx_value* _cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos, + const _cx_raw* p1, const _cx_raw* p2); +#endif // _i_no_emplace +#endif // !_i_no_clone + +#if !c_option(c_no_cmp) +STC_API _cx_iter _cx_memb(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw); +STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y); +#endif +STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value); +STC_API _cx_iter _cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2); +STC_API _cx_value* _cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos, + const _cx_value* p1, const _cx_value* p2); +#endif // !_i_queue + +#if !defined _i_no_clone +STC_API _cx_self _cx_memb(_clone)(_cx_self cx); +#if !defined _i_no_emplace +STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) + { return _cx_memb(_push)(self, i_keyfrom(raw)); } +#endif +STC_INLINE i_key _cx_memb(_value_clone)(i_key val) + { return i_keyclone(val); } +STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) { + if (self->data == other.data) return; + _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other); + } +#endif // !_i_no_clone +STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return cdeq_rep_(&cx)->size; } +STC_INLINE size_t _cx_memb(_capacity)(_cx_self cx) { return cdeq_rep_(&cx)->cap; } +STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return !cdeq_rep_(&cx)->size; } +STC_INLINE _cx_raw _cx_memb(_value_toraw)(_cx_value* pval) { return i_keyto(pval); } +STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); } +STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->data; } +STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) + { return self->data + cdeq_rep_(self)->size - 1; } +STC_INLINE void _cx_memb(_pop_front)(_cx_self* self) // == _pop() when _i_queue + { i_keydrop(self->data); ++self->data; --cdeq_rep_(self)->size; } +STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) + { return c_make(_cx_iter){self->data}; } +STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) + { return c_make(_cx_iter){self->data + cdeq_rep_(self)->size}; } +STC_INLINE void _cx_memb(_next)(_cx_iter* it) { ++it->ref; } +STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t offs) + { it.ref += offs; return it; } + +#if !defined _i_queue + +STC_INLINE size_t _cx_memb(_index)(_cx_self cx, _cx_iter it) + { return it.ref - cx.data; } +STC_INLINE void _cx_memb(_pop_back)(_cx_self* self) + { _cx_value* p = &self->data[--cdeq_rep_(self)->size]; i_keydrop(p); } + +STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, const size_t idx) { + assert(idx < cdeq_rep_(self)->size); return self->data + idx; +} +STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, const size_t idx) { + assert(idx < cdeq_rep_(self)->size); return self->data + idx; +} + +STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value) { + return _cx_memb(_push)(self, value); +} +STC_INLINE _cx_value* +_cx_memb(_insert)(_cx_self* self, const size_t idx, i_key value) { + return _cx_memb(_insert_range_p)(self, self->data + idx, &value, &value + 1); +} +STC_INLINE _cx_value* +_cx_memb(_insert_n)(_cx_self* self, const size_t idx, const _cx_value arr[], const size_t n) { + return _cx_memb(_insert_range_p)(self, self->data + idx, arr, arr + n); +} +STC_INLINE _cx_value* +_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) { + return _cx_memb(_insert_range_p)(self, it.ref, &value, &value + 1); +} + +STC_INLINE _cx_iter +_cx_memb(_erase_n)(_cx_self* self, const size_t idx, const size_t n) { + return _cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n); +} +STC_INLINE _cx_iter +_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { + return _cx_memb(_erase_range_p)(self, it.ref, it.ref + 1); +} +STC_INLINE _cx_iter +_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { + return _cx_memb(_erase_range_p)(self, it1.ref, it2.ref); +} + +#if !defined _i_no_clone && !defined _i_no_emplace +STC_INLINE _cx_value* +_cx_memb(_emplace_range)(_cx_self* self, _cx_iter it, _cx_iter it1, _cx_iter it2) { + return _cx_memb(_clone_range_p)(self, it.ref, it1.ref, it2.ref); +} + +STC_INLINE _cx_value* +_cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw) { + return _cx_memb(_push_front)(self, i_keyfrom(raw)); +} + +STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) { + return _cx_memb(_push)(self, i_keyfrom(raw)); +} + +STC_INLINE _cx_value* +_cx_memb(_emplace_n)(_cx_self* self, const size_t idx, const _cx_raw arr[], const size_t n) { + return _cx_memb(_emplace_range_p)(self, self->data + idx, arr, arr + n); +} +STC_INLINE _cx_value* +_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) { + return _cx_memb(_emplace_range_p)(self, it.ref, &raw, &raw + 1); +} +#endif // !_i_no_clone && !_i_no_emplace + +#if !c_option(c_no_cmp) + +STC_INLINE _cx_iter +_cx_memb(_find)(const _cx_self* self, _cx_raw raw) { + return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw); +} + +STC_INLINE const _cx_value* +_cx_memb(_get)(const _cx_self* self, _cx_raw raw) { + _cx_iter end = _cx_memb(_end)(self); + _cx_value* val = _cx_memb(_find_in)(_cx_memb(_begin)(self), end, raw).ref; + return val == end.ref ? NULL : val; +} + +STC_INLINE _cx_value* +_cx_memb(_get_mut)(_cx_self* self, _cx_raw raw) + { return (_cx_value *) _cx_memb(_get)(self, raw); } + +STC_INLINE void +_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2, + int(*_cmp_)(const _cx_value*, const _cx_value*)) { + qsort(i1.ref, i2.ref - i1.ref, sizeof *i1.ref, (int(*)(const void*, const void*)) _cmp_); +} + +STC_INLINE void +_cx_memb(_sort)(_cx_self* self) { + _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp)); +} +#endif // !c_no_cmp +#endif // _i_queue + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) + +#ifndef CDEQ_H_INCLUDED +static struct cdeq_rep _cdeq_sentinel = {0, 0}; +#define _cdeq_nfront(self) ((self)->data - (self)->_base) +#endif + +STC_DEF _cx_self +_cx_memb(_init)(void) { + _cx_value *b = (_cx_value *) _cdeq_sentinel.base; + return c_make(_cx_self){b, b}; +} + +STC_DEF void +_cx_memb(_clear)(_cx_self* self) { + struct cdeq_rep* rep = cdeq_rep_(self); + if (rep->cap) { + for (_cx_value *p = self->data, *q = p + rep->size; p != q; ) { + --q; i_keydrop(q); + } + rep->size = 0; + } +} + +STC_DEF void +_cx_memb(_shrink_to_fit)(_cx_self *self) { + if (_cx_memb(_size)(*self) != _cx_memb(_capacity)(*self)) { + struct cdeq_rep* rep = cdeq_rep_(self); + const size_t sz = rep->size; + memmove(self->_base, self->data, sz*sizeof(i_key)); + rep = (struct cdeq_rep*) c_realloc(rep, offsetof(struct cdeq_rep, base) + sz*sizeof(i_key)); + if (rep) { + self->_base = self->data = (_cx_value*)rep->base; + rep->cap = sz; + } + } +} + +STC_DEF void +_cx_memb(_drop)(_cx_self* self) { + struct cdeq_rep* rep = cdeq_rep_(self); + // second test to supress gcc -O2 warn: -Wfree-nonheap-object + if (rep->cap == 0 || rep == &_cdeq_sentinel) + return; + _cx_memb(_clear)(self); + c_free(rep); +} + +static size_t +_cx_memb(_realloc_)(_cx_self* self, const size_t n) { + struct cdeq_rep* rep = cdeq_rep_(self); + const size_t sz = rep->size, cap = (size_t) (sz*1.7) + n + 7; + const size_t nfront = _cdeq_nfront(self); + rep = (struct cdeq_rep*) c_realloc(rep->cap ? rep : NULL, + offsetof(struct cdeq_rep, base) + cap*sizeof(i_key)); + if (!rep) + return 0; + rep->size = sz, rep->cap = cap; + self->_base = (_cx_value *) rep->base; + self->data = self->_base + nfront; + return cap; +} + +static bool +_cx_memb(_expand_right_half_)(_cx_self* self, const size_t idx, const size_t n) { + struct cdeq_rep* rep = cdeq_rep_(self); + const size_t sz = rep->size, cap = rep->cap; + const size_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront; + if (nback >= n || sz*1.3 + n > cap) { + if (!_cx_memb(_realloc_)(self, n)) + return false; + memmove(self->data + idx + n, self->data + idx, (sz - idx)*sizeof(i_key)); + } else { +#if !defined _i_queue + const size_t unused = cap - (sz + n); + const size_t pos = (nfront*2 < unused) ? nfront : unused/2; +#else + const size_t pos = 0; +#endif + memmove(self->_base + pos, self->data, idx*sizeof(i_key)); + memmove(self->data + pos + idx + n, self->data + idx, (sz - idx)*sizeof(i_key)); + self->data = self->_base + pos; + } + return true; +} + +STC_DEF _cx_self +_cx_memb(_with_capacity)(const size_t n) { + _cx_self cx = _cx_memb(_init)(); + _cx_memb(_expand_right_half_)(&cx, 0, n); + return cx; +} + +STC_DEF bool +_cx_memb(_reserve)(_cx_self* self, const size_t n) { + const size_t sz = cdeq_rep_(self)->size; + return n <= sz || _cx_memb(_expand_right_half_)(self, sz, n - sz); +} + +STC_DEF _cx_value* +_cx_memb(_push)(_cx_self* self, i_key value) { + struct cdeq_rep* r = cdeq_rep_(self); + if (_cdeq_nfront(self) + r->size == r->cap) { + _cx_memb(_expand_right_half_)(self, r->size, 1); + r = cdeq_rep_(self); + } + _cx_value *v = self->data + r->size++; + *v = value; return v; +} + +#if !c_option(c_no_clone) +STC_DEF _cx_self +_cx_memb(_clone)(_cx_self cx) { + const size_t sz = cdeq_rep_(&cx)->size; + _cx_self out = _cx_memb(_with_capacity)(sz); + if (cdeq_rep_(&out)->cap) { + cdeq_rep_(&out)->size = sz; + for (size_t i = 0; i < sz; ++i) + out.data[i] = i_keyclone(cx.data[i]); + } + return out; +} +#endif + +#if !defined _i_queue + +static void +_cx_memb(_expand_left_half_)(_cx_self* self, const size_t idx, const size_t n) { + struct cdeq_rep* rep = cdeq_rep_(self); + size_t cap = rep->cap; + const size_t sz = rep->size; + const size_t nfront = _cdeq_nfront(self), nback = cap - sz - nfront; + if (nfront >= n) { + self->data = (_cx_value *)memmove(self->data - n, self->data, idx*sizeof(i_key)); + } else { + if (sz*1.3 + n > cap) + cap = _cx_memb(_realloc_)(self, n); + const size_t unused = cap - (sz + n); + const size_t pos = (nback*2 < unused) ? unused - nback : unused/2; + memmove(self->_base + pos + idx + n, self->data + idx, (sz - idx)*sizeof(i_key)); + self->data = (_cx_value *)memmove(self->_base + pos, self->data, idx*sizeof(i_key)); + } +} + +static _cx_value* +_cx_memb(_expand_uninit_p)(_cx_self* self, const _cx_value* pos, const size_t n) { + const size_t idx = pos - self->data; + if (idx*2 < cdeq_rep_(self)->size) + _cx_memb(_expand_left_half_)(self, idx, n); + else + _cx_memb(_expand_right_half_)(self, idx, n); + if (n) + cdeq_rep_(self)->size += n; /* do only if size > 0 */ + return self->data + idx; +} + +STC_DEF _cx_value* +_cx_memb(_push_front)(_cx_self* self, i_key value) { + if (self->data == self->_base) + _cx_memb(_expand_left_half_)(self, 0, 1); + else + --self->data; + ++cdeq_rep_(self)->size; + *self->data = value; + return self->data; +} + +STC_DEF _cx_value* +_cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos, + const _cx_value* p1, const _cx_value* p2) { + pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1); + if (pos) + memcpy(pos, p1, (p2 - p1)*sizeof *p1); + return pos; +} + +STC_DEF _cx_iter +_cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2) { + const size_t n = p2 - p1; + if (n > 0) { + _cx_value* p = p1, *end = self->data + cdeq_rep_(self)->size; + for (; p != p2; ++p) { i_keydrop(p); } + if (p1 == self->data) + self->data += n; + else memmove(p1, p2, (end - p2) * sizeof(i_key)); + cdeq_rep_(self)->size -= n; + } + return c_make(_cx_iter){p1}; +} + +#if !defined _i_no_clone +#if !defined _i_no_emplace +STC_DEF _cx_value* +_cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos, const _cx_raw* p1, const _cx_raw* p2) { + pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1); + _cx_value* it = pos; + if (pos) for (; p1 != p2; ++p1) + *pos++ = i_keyfrom((*p1)); + return it; +} +#endif // !_i_no_emplace + +STC_DEF _cx_value* +_cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos, + const _cx_value* p1, const _cx_value* p2) { + pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1); + _cx_value* it = pos; + if (pos) for (; p1 != p2; ++p1) + *pos++ = i_keyclone((*p1)); + return it; +} +#endif // !_i_no_clone + +#if !c_option(c_no_cmp) + +STC_DEF _cx_iter +_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { + for (; i1.ref != i2.ref; ++i1.ref) { + _cx_raw r = i_keyto(i1.ref); + if (i_eq((&raw), (&r))) + return i1; + } + return i2; +} + +STC_DEF int +_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { + const _cx_raw rx = i_keyto(x); + const _cx_raw ry = i_keyto(y); + return i_cmp((&rx), (&ry)); +} +#endif // !c_no_cmp +#endif // !_i_queue +#endif // IMPLEMENTATION +#include "template.h" +#define CDEQ_H_INCLUDED diff --git a/include/stc/clist.h b/include/stc/clist.h index 9380dc11..29bf56f3 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -1,424 +1,424 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/* Circular Singly-linked Lists.
- This implements a std::forward_list-like class in C. Because it is circular,
- it also support both push_back() and push_front(), unlike std::forward_list:
-
- #include <stdio.h>
- #include <stc/crandom.h>
-
- #define i_key int64_t
- #define i_tag ix
- #include <stc/clist.h>
-
- int main()
- {
- c_auto (clist_ix, list)
- {
- int n;
- for (int i = 0; i < 1000000; ++i) // one million
- clist_ix_push_back(&list, crandom() >> 32);
- n = 0;
- c_foreach (i, clist_ix, list)
- if (++n % 10000 == 0) printf("%8d: %10zu\n", n, *i.ref);
- // Sort them...
- clist_ix_sort(&list); // mergesort O(n*log n)
- n = 0;
- puts("sorted");
- c_foreach (i, clist_ix, list)
- if (++n % 10000 == 0) printf("%8d: %10zu\n", n, *i.ref);
- }
- }
-*/
-#include "ccommon.h"
-
-#ifndef CLIST_H_INCLUDED
-#include "forward.h"
-#include <stdlib.h>
-#include <string.h>
-
-#define _c_clist_complete_types(SELF, dummy) \
- struct SELF##_node { \
- struct SELF##_node *next; \
- SELF##_value value; \
- }
-
-#define clist_node_(vp) c_unchecked_container_of(vp, _cx_node, value)
-
-_c_clist_types(clist_VOID, int);
-_c_clist_complete_types(clist_VOID, dummy);
-
-#define _c_clist_insert_after(self, _cx_self, node, val) \
- _cx_node *entry = c_alloc(_cx_node); \
- if (node) entry->next = node->next, node->next = entry; \
- else entry->next = entry; \
- entry->value = val
- // +: set self->last based on node
-
-#define _c_clist_insert_node_after(self, _cx_self, node, entry) \
- if (node) entry->next = node->next, node->next = entry; \
- else entry->next = entry
-
-#endif // CLIST_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix clist_
-#endif
-#include "template.h"
-
-#if !c_option(c_is_fwd)
- _cx_deftypes(_c_clist_types, _cx_self, i_key);
-#endif
-_cx_deftypes(_c_clist_complete_types, _cx_self, dummy);
-typedef i_keyraw _cx_raw;
-
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value);
-STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value);
-STC_API _cx_value* _cx_memb(_push_node_back)(_cx_self* self, _cx_node* node);
-STC_API _cx_value* _cx_memb(_push_node_front)(_cx_self* self, _cx_node* node);
-STC_API _cx_iter _cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value);
-STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it);
-STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2);
-#if !c_option(c_no_cmp)
-STC_API size_t _cx_memb(_remove)(_cx_self* self, _cx_raw val);
-STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val);
-STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y);
-STC_API int _cx_memb(_sort_cmp_)(const clist_VOID_node* x, const clist_VOID_node* y);
-#endif
-STC_API _cx_iter _cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other);
-STC_API _cx_self _cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2);
-STC_API _cx_node* _cx_memb(_erase_after_)(_cx_self* self, _cx_node* node);
-
-#if !defined _i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
-STC_INLINE i_key _cx_memb(_value_clone)(i_key val)
- { return i_keyclone(val); }
-STC_INLINE void
-_cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->last == other.last) return;
- _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other);
-}
-#if !defined _i_no_emplace
-STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push_back)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push_front)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_iter _cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw)
- { return _cx_memb(_insert_at)(self, it, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push_back)(self, i_keyfrom(raw)); }
-#endif // !_i_no_emplace
-#endif // !_i_no_clone
-
-STC_INLINE _cx_self _cx_memb(_init)(void) { return c_make(_cx_self){NULL}; }
-STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, size_t n) { return true; }
-STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return cx.last == NULL; }
-STC_INLINE void _cx_memb(_clear)(_cx_self* self) { _cx_memb(_drop)(self); }
-STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, i_key value)
- { return _cx_memb(_push_back)(self, value); }
-STC_INLINE void _cx_memb(_pop_front)(_cx_self* self)
- { _cx_memb(_erase_after_)(self, self->last); }
-STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return &self->last->next->value; }
-STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) { return &self->last->value; }
-
-STC_INLINE size_t
-_cx_memb(_count)(_cx_self cx) {
- size_t n = 1; const _cx_node *node = cx.last;
- if (!node) return 0;
- while ((node = node->next) != cx.last) ++n;
- return n;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_begin)(const _cx_self* self) {
- _cx_value* head = self->last ? &self->last->next->value : NULL;
- return c_make(_cx_iter){head, &self->last, self->last};
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_end)(const _cx_self* self) {
- return c_make(_cx_iter){NULL};
-}
-
-STC_INLINE void
-_cx_memb(_next)(_cx_iter* it) {
- _cx_node* node = it->prev = clist_node_(it->ref);
- it->ref = (node == *it->_last ? NULL : &node->next->value);
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_advance)(_cx_iter it, size_t n) {
- while (n-- && it.ref) _cx_memb(_next)(&it);
- return it;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_splice_range)(_cx_self* self, _cx_iter it,
- _cx_self* other, _cx_iter it1, _cx_iter it2) {
- _cx_self tmp = _cx_memb(_split_off)(other, it1, it2);
- return _cx_memb(_splice)(self, it, &tmp);
-}
-
-#if !c_option(c_no_cmp)
-STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_raw val) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val);
-}
-
-STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_raw val) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref;
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_get_mut)(_cx_self* self, _cx_raw val) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref;
-}
-
-STC_INLINE void
-_cx_memb(_sort)(_cx_self* self) {
- extern clist_VOID_node*
- _clist_mergesort(clist_VOID_node *list, int (*cmp)(const clist_VOID_node*, const clist_VOID_node*));
-
- if (self->last)
- self->last = (_cx_node *)_clist_mergesort((clist_VOID_node *)self->last->next, _cx_memb(_sort_cmp_));
-}
-#endif
-
-#if defined(i_extern)
-/* Implement non-templated extern functions */
-// Singly linked list Mergesort implementation by Simon Tatham. O(n*log n).
-// https://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
-clist_VOID_node *
-_clist_mergesort(clist_VOID_node *list, int (*cmp)(const clist_VOID_node*, const clist_VOID_node*)) {
- clist_VOID_node *p, *q, *e, *tail, *oldhead;
- int insize = 1, nmerges, psize, qsize, i;
-
- while (1) {
- p = oldhead = list;
- list = tail = NULL;
- nmerges = 0;
-
- while (p) {
- ++nmerges;
- q = p, psize = 0;
- for (i = 0; i < insize; ++i) {
- ++psize;
- q = (q->next == oldhead ? NULL : q->next);
- if (!q) break;
- }
- qsize = insize;
-
- while (psize > 0 || (qsize > 0 && q)) {
- if (psize == 0) {
- e = q, q = q->next, --qsize;
- if (q == oldhead) q = NULL;
- } else if (qsize == 0 || !q) {
- e = p, p = p->next, --psize;
- if (p == oldhead) p = NULL;
- } else if (cmp(p, q) <= 0) {
- e = p, p = p->next, --psize;
- if (p == oldhead) p = NULL;
- } else {
- e = q, q = q->next, --qsize;
- if (q == oldhead) q = NULL;
- }
- if (tail) tail->next = e; else list = e;
- tail = e;
- }
- p = q;
- }
- tail->next = list;
-
- if (nmerges <= 1)
- return tail;
-
- insize *= 2;
- }
-}
-#endif // i_extern
-
-// -------------------------- IMPLEMENTATION -------------------------
-#if defined(i_implement)
-
-#if !defined _i_no_clone
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self cx) {
- _cx_self out = _cx_memb(_init)();
- c_foreach (it, _cx_self, cx)
- _cx_memb(_push_back)(&out, i_keyclone((*it.ref)));
- return out;
-}
-#endif
-
-STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
- while (self->last) _cx_memb(_erase_after_)(self, self->last);
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push_back)(_cx_self* self, i_key value) {
- _c_clist_insert_after(self, _cx_self, self->last, value);
- self->last = entry;
- return &entry->value;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push_node_back)(_cx_self* self, _cx_node* entry) {
- _c_clist_insert_node_after(self, _cx_self, self->last, entry);
- self->last = entry;
- return &entry->value;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push_front)(_cx_self* self, i_key value) {
- _c_clist_insert_after(self, _cx_self, self->last, value);
- if (!self->last)
- self->last = entry;
- return &entry->value;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push_node_front)(_cx_self* self, _cx_node* entry) {
- _c_clist_insert_node_after(self, _cx_self, self->last, entry);
- if (!self->last)
- self->last = entry;
- return &entry->value;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
- _cx_node* node = it.ref ? it.prev : self->last;
- _c_clist_insert_after(self, _cx_self, node, value);
- if (!self->last || !it.ref) {
- it.prev = self->last ? self->last : entry;
- self->last = entry;
- }
- it.ref = &entry->value;
- return it;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- _cx_node *node = clist_node_(it.ref);
- it.ref = (node == self->last) ? NULL : &node->next->value;
- _cx_memb(_erase_after_)(self, it.prev);
- return it;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
- _cx_node *node = it1.ref ? it1.prev : NULL,
- *done = it2.ref ? clist_node_(it2.ref) : NULL;
- while (node && node->next != done)
- node = _cx_memb(_erase_after_)(self, node);
- return it2;
-}
-
-STC_DEF _cx_node*
-_cx_memb(_erase_after_)(_cx_self* self, _cx_node* node) {
- _cx_node* del = node->next, *next = del->next;
- node->next = next;
- if (del == next)
- self->last = node = NULL;
- else if (self->last == del)
- self->last = node, node = NULL;
- i_keydrop((&del->value)); c_free(del);
- return node;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other) {
- if (!self->last)
- self->last = other->last;
- else if (other->last) {
- _cx_node *p = it.ref ? it.prev : self->last, *next = p->next;
- it.prev = other->last;
- p->next = it.prev->next;
- it.prev->next = next;
- if (!it.ref) self->last = it.prev;
- }
- other->last = NULL; return it;
-}
-
-STC_DEF _cx_self
-_cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
- _cx_self cx = {NULL};
- if (it1.ref == it2.ref)
- return cx;
- _cx_node *p1 = it1.prev,
- *p2 = it2.ref ? it2.prev : self->last;
- p1->next = p2->next;
- p2->next = clist_node_(it1.ref);
- if (self->last == p2)
- self->last = (p1 == p2) ? NULL : p1;
- cx.last = p2;
- return cx;
-}
-
-#if !c_option(c_no_cmp)
-
-STC_DEF _cx_iter
-_cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) {
- c_foreach (it, _cx_self, it1, it2) {
- _cx_raw r = i_keyto(it.ref);
- if (i_eq((&r), (&val)))
- return it;
- }
- it2.ref = NULL; return it2;
-}
-
-STC_DEF size_t
-_cx_memb(_remove)(_cx_self* self, _cx_raw val) {
- size_t n = 0;
- _cx_node* prev = self->last, *node;
- while (prev) {
- node = prev->next;
- _cx_raw r = i_keyto((&node->value));
- if (i_eq((&r), (&val)))
- prev = _cx_memb(_erase_after_)(self, prev), ++n;
- else
- prev = (node == self->last ? NULL : node);
- }
- return n;
-}
-
-STC_DEF int
-_cx_memb(_sort_cmp_)(const clist_VOID_node* x, const clist_VOID_node* y) {
- const _cx_raw a = i_keyto((&((const _cx_node *) x)->value));
- const _cx_raw b = i_keyto((&((const _cx_node *) y)->value));
- return i_cmp((&a), (&b));
-}
-
-STC_DEF int
-_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- const _cx_raw rx = i_keyto(x);
- const _cx_raw ry = i_keyto(y);
- return i_cmp((&rx), (&ry));
-}
-#endif // !c_no_cmp
-#endif // i_implement
-#define CLIST_H_INCLUDED
-#include "template.h"
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* Circular Singly-linked Lists. + This implements a std::forward_list-like class in C. Because it is circular, + it also support both push_back() and push_front(), unlike std::forward_list: + + #include <stdio.h> + #include <stc/crandom.h> + + #define i_key int64_t + #define i_tag ix + #include <stc/clist.h> + + int main() + { + c_auto (clist_ix, list) + { + int n; + for (int i = 0; i < 1000000; ++i) // one million + clist_ix_push_back(&list, crandom() >> 32); + n = 0; + c_foreach (i, clist_ix, list) + if (++n % 10000 == 0) printf("%8d: %10zu\n", n, *i.ref); + // Sort them... + clist_ix_sort(&list); // mergesort O(n*log n) + n = 0; + puts("sorted"); + c_foreach (i, clist_ix, list) + if (++n % 10000 == 0) printf("%8d: %10zu\n", n, *i.ref); + } + } +*/ +#include "ccommon.h" + +#ifndef CLIST_H_INCLUDED +#include "forward.h" +#include <stdlib.h> +#include <string.h> + +#define _c_clist_complete_types(SELF, dummy) \ + struct SELF##_node { \ + struct SELF##_node *next; \ + SELF##_value value; \ + } + +#define clist_node_(vp) c_unchecked_container_of(vp, _cx_node, value) + +_c_clist_types(clist_VOID, int); +_c_clist_complete_types(clist_VOID, dummy); + +#define _c_clist_insert_after(self, _cx_self, node, val) \ + _cx_node *entry = c_alloc(_cx_node); \ + if (node) entry->next = node->next, node->next = entry; \ + else entry->next = entry; \ + entry->value = val + // +: set self->last based on node + +#define _c_clist_insert_node_after(self, _cx_self, node, entry) \ + if (node) entry->next = node->next, node->next = entry; \ + else entry->next = entry + +#endif // CLIST_H_INCLUDED + +#ifndef _i_prefix +#define _i_prefix clist_ +#endif +#include "template.h" + +#if !c_option(c_is_fwd) + _cx_deftypes(_c_clist_types, _cx_self, i_key); +#endif +_cx_deftypes(_c_clist_complete_types, _cx_self, dummy); +typedef i_keyraw _cx_raw; + +STC_API void _cx_memb(_drop)(_cx_self* self); +STC_API _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value); +STC_API _cx_value* _cx_memb(_push_front)(_cx_self* self, i_key value); +STC_API _cx_value* _cx_memb(_push_node_back)(_cx_self* self, _cx_node* node); +STC_API _cx_value* _cx_memb(_push_node_front)(_cx_self* self, _cx_node* node); +STC_API _cx_iter _cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value); +STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it); +STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2); +#if !c_option(c_no_cmp) +STC_API size_t _cx_memb(_remove)(_cx_self* self, _cx_raw val); +STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val); +STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y); +STC_API int _cx_memb(_sort_cmp_)(const clist_VOID_node* x, const clist_VOID_node* y); +#endif +STC_API _cx_iter _cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other); +STC_API _cx_self _cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2); +STC_API _cx_node* _cx_memb(_erase_after_)(_cx_self* self, _cx_node* node); + +#if !defined _i_no_clone +STC_API _cx_self _cx_memb(_clone)(_cx_self cx); +STC_INLINE i_key _cx_memb(_value_clone)(i_key val) + { return i_keyclone(val); } +STC_INLINE void +_cx_memb(_copy)(_cx_self *self, _cx_self other) { + if (self->last == other.last) return; + _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other); +} +#if !defined _i_no_emplace +STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) + { return _cx_memb(_push_back)(self, i_keyfrom(raw)); } +STC_INLINE _cx_value* _cx_memb(_emplace_front)(_cx_self* self, _cx_raw raw) + { return _cx_memb(_push_front)(self, i_keyfrom(raw)); } +STC_INLINE _cx_iter _cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) + { return _cx_memb(_insert_at)(self, it, i_keyfrom(raw)); } +STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) + { return _cx_memb(_push_back)(self, i_keyfrom(raw)); } +#endif // !_i_no_emplace +#endif // !_i_no_clone + +STC_INLINE _cx_self _cx_memb(_init)(void) { return c_make(_cx_self){NULL}; } +STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, size_t n) { return true; } +STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return cx.last == NULL; } +STC_INLINE void _cx_memb(_clear)(_cx_self* self) { _cx_memb(_drop)(self); } +STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, i_key value) + { return _cx_memb(_push_back)(self, value); } +STC_INLINE void _cx_memb(_pop_front)(_cx_self* self) + { _cx_memb(_erase_after_)(self, self->last); } +STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return &self->last->next->value; } +STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) { return &self->last->value; } + +STC_INLINE size_t +_cx_memb(_count)(_cx_self cx) { + size_t n = 1; const _cx_node *node = cx.last; + if (!node) return 0; + while ((node = node->next) != cx.last) ++n; + return n; +} + +STC_INLINE _cx_iter +_cx_memb(_begin)(const _cx_self* self) { + _cx_value* head = self->last ? &self->last->next->value : NULL; + return c_make(_cx_iter){head, &self->last, self->last}; +} + +STC_INLINE _cx_iter +_cx_memb(_end)(const _cx_self* self) { + return c_make(_cx_iter){NULL}; +} + +STC_INLINE void +_cx_memb(_next)(_cx_iter* it) { + _cx_node* node = it->prev = clist_node_(it->ref); + it->ref = (node == *it->_last ? NULL : &node->next->value); +} + +STC_INLINE _cx_iter +_cx_memb(_advance)(_cx_iter it, size_t n) { + while (n-- && it.ref) _cx_memb(_next)(&it); + return it; +} + +STC_INLINE _cx_iter +_cx_memb(_splice_range)(_cx_self* self, _cx_iter it, + _cx_self* other, _cx_iter it1, _cx_iter it2) { + _cx_self tmp = _cx_memb(_split_off)(other, it1, it2); + return _cx_memb(_splice)(self, it, &tmp); +} + +#if !c_option(c_no_cmp) +STC_INLINE _cx_iter +_cx_memb(_find)(const _cx_self* self, _cx_raw val) { + return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val); +} + +STC_INLINE const _cx_value* +_cx_memb(_get)(const _cx_self* self, _cx_raw val) { + return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref; +} + +STC_INLINE _cx_value* +_cx_memb(_get_mut)(_cx_self* self, _cx_raw val) { + return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), val).ref; +} + +STC_INLINE void +_cx_memb(_sort)(_cx_self* self) { + extern clist_VOID_node* + _clist_mergesort(clist_VOID_node *list, int (*cmp)(const clist_VOID_node*, const clist_VOID_node*)); + + if (self->last) + self->last = (_cx_node *)_clist_mergesort((clist_VOID_node *)self->last->next, _cx_memb(_sort_cmp_)); +} +#endif + +#if defined(i_extern) +/* Implement non-templated extern functions */ +// Singly linked list Mergesort implementation by Simon Tatham. O(n*log n). +// https://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html +clist_VOID_node * +_clist_mergesort(clist_VOID_node *list, int (*cmp)(const clist_VOID_node*, const clist_VOID_node*)) { + clist_VOID_node *p, *q, *e, *tail, *oldhead; + int insize = 1, nmerges, psize, qsize, i; + + while (1) { + p = oldhead = list; + list = tail = NULL; + nmerges = 0; + + while (p) { + ++nmerges; + q = p, psize = 0; + for (i = 0; i < insize; ++i) { + ++psize; + q = (q->next == oldhead ? NULL : q->next); + if (!q) break; + } + qsize = insize; + + while (psize > 0 || (qsize > 0 && q)) { + if (psize == 0) { + e = q, q = q->next, --qsize; + if (q == oldhead) q = NULL; + } else if (qsize == 0 || !q) { + e = p, p = p->next, --psize; + if (p == oldhead) p = NULL; + } else if (cmp(p, q) <= 0) { + e = p, p = p->next, --psize; + if (p == oldhead) p = NULL; + } else { + e = q, q = q->next, --qsize; + if (q == oldhead) q = NULL; + } + if (tail) tail->next = e; else list = e; + tail = e; + } + p = q; + } + tail->next = list; + + if (nmerges <= 1) + return tail; + + insize *= 2; + } +} +#endif // i_extern + +// -------------------------- IMPLEMENTATION ------------------------- +#if defined(i_implement) + +#if !defined _i_no_clone +STC_DEF _cx_self +_cx_memb(_clone)(_cx_self cx) { + _cx_self out = _cx_memb(_init)(); + c_foreach (it, _cx_self, cx) + _cx_memb(_push_back)(&out, i_keyclone((*it.ref))); + return out; +} +#endif + +STC_DEF void +_cx_memb(_drop)(_cx_self* self) { + while (self->last) _cx_memb(_erase_after_)(self, self->last); +} + +STC_DEF _cx_value* +_cx_memb(_push_back)(_cx_self* self, i_key value) { + _c_clist_insert_after(self, _cx_self, self->last, value); + self->last = entry; + return &entry->value; +} + +STC_DEF _cx_value* +_cx_memb(_push_node_back)(_cx_self* self, _cx_node* entry) { + _c_clist_insert_node_after(self, _cx_self, self->last, entry); + self->last = entry; + return &entry->value; +} + +STC_DEF _cx_value* +_cx_memb(_push_front)(_cx_self* self, i_key value) { + _c_clist_insert_after(self, _cx_self, self->last, value); + if (!self->last) + self->last = entry; + return &entry->value; +} + +STC_DEF _cx_value* +_cx_memb(_push_node_front)(_cx_self* self, _cx_node* entry) { + _c_clist_insert_node_after(self, _cx_self, self->last, entry); + if (!self->last) + self->last = entry; + return &entry->value; +} + +STC_DEF _cx_iter +_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) { + _cx_node* node = it.ref ? it.prev : self->last; + _c_clist_insert_after(self, _cx_self, node, value); + if (!self->last || !it.ref) { + it.prev = self->last ? self->last : entry; + self->last = entry; + } + it.ref = &entry->value; + return it; +} + +STC_DEF _cx_iter +_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { + _cx_node *node = clist_node_(it.ref); + it.ref = (node == self->last) ? NULL : &node->next->value; + _cx_memb(_erase_after_)(self, it.prev); + return it; +} + +STC_DEF _cx_iter +_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { + _cx_node *node = it1.ref ? it1.prev : NULL, + *done = it2.ref ? clist_node_(it2.ref) : NULL; + while (node && node->next != done) + node = _cx_memb(_erase_after_)(self, node); + return it2; +} + +STC_DEF _cx_node* +_cx_memb(_erase_after_)(_cx_self* self, _cx_node* node) { + _cx_node* del = node->next, *next = del->next; + node->next = next; + if (del == next) + self->last = node = NULL; + else if (self->last == del) + self->last = node, node = NULL; + i_keydrop((&del->value)); c_free(del); + return node; +} + +STC_DEF _cx_iter +_cx_memb(_splice)(_cx_self* self, _cx_iter it, _cx_self* other) { + if (!self->last) + self->last = other->last; + else if (other->last) { + _cx_node *p = it.ref ? it.prev : self->last, *next = p->next; + it.prev = other->last; + p->next = it.prev->next; + it.prev->next = next; + if (!it.ref) self->last = it.prev; + } + other->last = NULL; return it; +} + +STC_DEF _cx_self +_cx_memb(_split_off)(_cx_self* self, _cx_iter it1, _cx_iter it2) { + _cx_self cx = {NULL}; + if (it1.ref == it2.ref) + return cx; + _cx_node *p1 = it1.prev, + *p2 = it2.ref ? it2.prev : self->last; + p1->next = p2->next; + p2->next = clist_node_(it1.ref); + if (self->last == p2) + self->last = (p1 == p2) ? NULL : p1; + cx.last = p2; + return cx; +} + +#if !c_option(c_no_cmp) + +STC_DEF _cx_iter +_cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) { + c_foreach (it, _cx_self, it1, it2) { + _cx_raw r = i_keyto(it.ref); + if (i_eq((&r), (&val))) + return it; + } + it2.ref = NULL; return it2; +} + +STC_DEF size_t +_cx_memb(_remove)(_cx_self* self, _cx_raw val) { + size_t n = 0; + _cx_node* prev = self->last, *node; + while (prev) { + node = prev->next; + _cx_raw r = i_keyto((&node->value)); + if (i_eq((&r), (&val))) + prev = _cx_memb(_erase_after_)(self, prev), ++n; + else + prev = (node == self->last ? NULL : node); + } + return n; +} + +STC_DEF int +_cx_memb(_sort_cmp_)(const clist_VOID_node* x, const clist_VOID_node* y) { + const _cx_raw a = i_keyto((&((const _cx_node *) x)->value)); + const _cx_raw b = i_keyto((&((const _cx_node *) y)->value)); + return i_cmp((&a), (&b)); +} + +STC_DEF int +_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { + const _cx_raw rx = i_keyto(x); + const _cx_raw ry = i_keyto(y); + return i_cmp((&rx), (&ry)); +} +#endif // !c_no_cmp +#endif // i_implement +#define CLIST_H_INCLUDED +#include "template.h" diff --git a/include/stc/cmap.h b/include/stc/cmap.h index eabd5f1c..e193a8d0 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -1,423 +1,423 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-// Unordered set/map - implemented as closed hashing with linear probing and no tombstones.
-/*
-#include <stdio.h>
-
-#define i_tag ichar // Map int => char
-#define i_key int
-#define i_val char
-#include <stc/cmap.h>
-
-int main(void) {
- c_autovar (cmap_ichar m = cmap_ichar_init(), cmap_ichar_drop(&m))
- {
- cmap_ichar_emplace(&m, 5, 'a');
- cmap_ichar_emplace(&m, 8, 'b');
- cmap_ichar_emplace(&m, 12, 'c');
-
- cmap_ichar_value* v = cmap_ichar_get(&m, 10); // NULL
- char val = *cmap_ichar_at(&m, 5); // 'a'
- cmap_ichar_emplace_or_assign(&m, 5, 'd'); // update
- cmap_ichar_erase(&m, 8);
-
- c_foreach (i, cmap_ichar, m)
- printf("map %d: %c\n", i.ref->first, i.ref->second);
- }
-}
-*/
-#include "ccommon.h"
-
-#ifndef CMAP_H_INCLUDED
-#include "forward.h"
-#include <stdlib.h>
-#include <string.h>
-#define _cmap_inits {NULL, NULL, 0, 0, 0.85f}
-typedef struct { size_t idx; uint8_t hx; } chash_bucket_t;
-#endif // CMAP_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix cmap_
-#endif
-#ifdef _i_isset
- #define _i_MAP_ONLY c_false
- #define _i_SET_ONLY c_true
- #define _i_keyref(vp) (vp)
-#else
- #define _i_ismap
- #define _i_MAP_ONLY c_true
- #define _i_SET_ONLY c_false
- #define _i_keyref(vp) (&(vp)->first)
-#endif
-#define _i_ishash
-#include "template.h"
-#if !c_option(c_is_fwd)
- _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_size, _i_MAP_ONLY, _i_SET_ONLY);
-#endif
-
-_i_MAP_ONLY( struct _cx_value {
- _cx_key first;
- _cx_mapped second;
-}; )
-
-typedef i_keyraw _cx_rawkey;
-typedef i_valraw _cx_memb(_rawmapped);
-typedef _i_SET_ONLY( i_keyraw )
- _i_MAP_ONLY( struct { i_keyraw first;
- i_valraw second; } )
-_cx_raw;
-
-STC_API _cx_self _cx_memb(_with_capacity)(size_t cap);
-#if !defined _i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self map);
-#endif
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API void _cx_memb(_clear)(_cx_self* self);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, size_t capacity);
-STC_API chash_bucket_t _cx_memb(_bucket_)(const _cx_self* self, const _cx_rawkey* rkeyptr);
-STC_API _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey);
-STC_API void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* val);
-
-STC_INLINE _cx_self _cx_memb(_init)(void) { return c_make(_cx_self)_cmap_inits; }
-STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) { _cx_memb(_reserve)(self, self->size); }
-STC_INLINE void _cx_memb(_max_load_factor)(_cx_self* self, float ml) {self->max_load_factor = ml; }
-STC_INLINE bool _cx_memb(_empty)(_cx_self m) { return m.size == 0; }
-STC_INLINE size_t _cx_memb(_size)(_cx_self m) { return m.size; }
-STC_INLINE size_t _cx_memb(_bucket_count)(_cx_self map) { return map.bucket_count; }
-STC_INLINE size_t _cx_memb(_capacity)(_cx_self map)
- { return map.bucket_count ? (size_t)((map.bucket_count - 2)*map.max_load_factor) : 0u; }
-STC_INLINE void _cx_memb(_swap)(_cx_self *map1, _cx_self *map2) {c_swap(_cx_self, *map1, *map2); }
-STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_rawkey rkey)
- { return self->size && self->_hashx[_cx_memb(_bucket_)(self, &rkey).idx]; }
-
-#ifndef _i_isset
- STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped);
- #if !defined _i_no_clone && !defined _i_no_emplace
- STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped);
- #endif
-
- STC_INLINE const _cx_mapped*
- _cx_memb(_at)(const _cx_self* self, _cx_rawkey rkey) {
- chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey);
- assert(self->_hashx[b.idx]);
- return &self->table[b.idx].second;
- }
- STC_INLINE _cx_mapped*
- _cx_memb(_at_mut)(_cx_self* self, _cx_rawkey rkey)
- { return (_cx_mapped*)_cx_memb(_at)(self, rkey); }
-#endif // !_i_isset
-
-#if !defined _i_no_clone
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->table == other.table)
- return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(other);
-}
-
-STC_INLINE _cx_value
-_cx_memb(_value_clone)(_cx_value _val) {
- *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val)));
- _i_MAP_ONLY( _val.second = i_valclone(_val.second); )
- return _val;
-}
-
-#if !defined _i_no_emplace
-STC_INLINE _cx_result
-_cx_memb(_emplace)(_cx_self* self, _cx_rawkey rkey _i_MAP_ONLY(, i_valraw rmapped)) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, rkey);
- if (_res.inserted) {
- *_i_keyref(_res.ref) = i_keyfrom(rkey);
- _i_MAP_ONLY( _res.ref->second = i_valfrom(rmapped); )
- }
- return _res;
-}
-#endif // !_i_no_emplace
-#endif // !_i_no_clone
-
-STC_INLINE _cx_raw
-_cx_memb(_value_toraw)(_cx_value* val) {
- return _i_SET_ONLY( i_keyto(val) )
- _i_MAP_ONLY( c_make(_cx_raw){i_keyto((&val->first)), i_valto((&val->second))} );
-}
-
-STC_INLINE void
-_cx_memb(_value_drop)(_cx_value* _val) {
- i_keydrop(_i_keyref(_val));
- _i_MAP_ONLY( i_valdrop((&_val->second)); )
-}
-
-STC_INLINE _cx_result
-_cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key)));
- if (_res.inserted)
- { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )}
- else
- { i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )}
- return _res;
-}
-
-STC_INLINE _cx_result
-_cx_memb(_push)(_cx_self* self, _cx_value _val) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
- if (_res.inserted)
- *_res.ref = _val;
- else
- _cx_memb(_value_drop)(&_val);
- return _res;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_rawkey rkey) {
- i_size idx;
- if (!(self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx]))
- idx = self->bucket_count;
- return c_make(_cx_iter){self->table+idx, self->_hashx+idx};
-}
-
-STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_rawkey rkey) {
- i_size idx;
- if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx])
- return self->table + idx;
- return NULL;
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_get_mut)(const _cx_self* self, _cx_rawkey rkey)
- { return (_cx_value*)_cx_memb(_get)(self, rkey); }
-
-STC_INLINE _cx_iter
-_cx_memb(_begin)(const _cx_self* self) {
- _cx_iter it = {self->table, self->_hashx};
- if (it._hx)
- while (*it._hx == 0)
- ++it.ref, ++it._hx;
- return it;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_end)(const _cx_self* self)
- { return c_make(_cx_iter){self->table + self->bucket_count}; }
-
-STC_INLINE void
-_cx_memb(_next)(_cx_iter* it)
- { while ((++it->ref, *++it->_hx == 0)) ; }
-
-STC_INLINE _cx_iter
-_cx_memb(_advance)(_cx_iter it, size_t n) {
- // UB if n > elements left
- while (n--) _cx_memb(_next)(&it);
- return it;
-}
-
-STC_INLINE size_t
-_cx_memb(_erase)(_cx_self* self, _cx_rawkey rkey) {
- if (self->size == 0)
- return 0;
- chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey);
- return self->_hashx[b.idx] ? _cx_memb(_erase_entry)(self, self->table + b.idx), 1 : 0;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- _cx_memb(_erase_entry)(self, it.ref);
- if (*it._hx == 0)
- _cx_memb(_next)(&it);
- return it;
-}
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-#ifndef CMAP_H_INCLUDED
-STC_INLINE size_t fastrange_size_t(uint64_t x, uint64_t n)
- { uint64_t lo, hi; c_umul128(x, n, &lo, &hi); return (size_t)hi; }
-STC_INLINE size_t fastrange_uint32_t(uint64_t x, uint64_t n)
- { return (size_t)((uint32_t)x*n >> 32); }
-#endif // CMAP_H_INCLUDED
-
-STC_DEF _cx_self
-_cx_memb(_with_capacity)(const size_t cap) {
- _cx_self h = _cmap_inits;
- _cx_memb(_reserve)(&h, cap);
- return h;
-}
-
-STC_INLINE void _cx_memb(_wipe_)(_cx_self* self) {
- if (self->size == 0)
- return;
- _cx_value* e = self->table, *end = e + self->bucket_count;
- uint8_t *hx = self->_hashx;
- for (; e != end; ++e)
- if (*hx++)
- _cx_memb(_value_drop)(e);
-}
-
-STC_DEF void _cx_memb(_drop)(_cx_self* self) {
- _cx_memb(_wipe_)(self);
- c_free(self->_hashx);
- c_free((void *) self->table);
-}
-
-STC_DEF void _cx_memb(_clear)(_cx_self* self) {
- _cx_memb(_wipe_)(self);
- self->size = 0;
- memset(self->_hashx, 0, self->bucket_count);
-}
-
-#ifndef _i_isset
- STC_DEF _cx_result
- _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key)));
- if (_res.inserted)
- _res.ref->first = _key;
- else
- { i_keydrop((&_key)); i_valdrop((&_res.ref->second)); }
- _res.ref->second = _mapped;
- return _res;
- }
-
- #if !defined _i_no_clone && !defined _i_no_emplace
- STC_DEF _cx_result
- _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, rkey);
- if (_res.inserted)
- _res.ref->first = i_keyfrom(rkey);
- else
- { i_valdrop((&_res.ref->second)); }
- _res.ref->second = i_valfrom(rmapped);
- return _res;
- }
- #endif // !_i_no_clone && !_i_no_emplace
-#endif // !_i_isset
-
-STC_DEF chash_bucket_t
-_cx_memb(_bucket_)(const _cx_self* self, const _cx_rawkey* rkeyptr) {
- const uint64_t _hash = i_hash(rkeyptr);
- i_size _cap = self->bucket_count;
- chash_bucket_t b = {c_paste(fastrange_,i_size)(_hash, _cap), (uint8_t)(_hash | 0x80)};
- const uint8_t* _hx = self->_hashx;
- while (_hx[b.idx]) {
- if (_hx[b.idx] == b.hx) {
- const _cx_rawkey _raw = i_keyto(_i_keyref(self->table + b.idx));
- if (i_eq((&_raw), rkeyptr))
- break;
- }
- if (++b.idx == _cap)
- b.idx = 0;
- }
- return b;
-}
-
-STC_DEF _cx_result
-_cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey) {
- bool nomem = false;
- if (self->size + 1 >= (i_size)(self->bucket_count*self->max_load_factor))
- nomem = !_cx_memb(_reserve)(self, ((size_t)self->size*3 >> 1) + 4);
- chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey);
- _cx_result res = {&self->table[b.idx], !self->_hashx[b.idx], nomem};
- if (res.inserted) {
- self->_hashx[b.idx] = b.hx;
- ++self->size;
- }
- return res;
-}
-
-#if !defined _i_no_clone
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self m) {
- _cx_value *t = c_alloc_n(_cx_value, m.bucket_count), *dst = t, *m_end = m.table + m.bucket_count;
- uint8_t *h = (uint8_t *)memcpy(c_malloc(m.bucket_count + 1), m._hashx, m.bucket_count + 1);
- if (!(t && h))
- { c_free(t), c_free(h), t = 0, h = 0, m.bucket_count = 0; }
- else
- for (; m.table != m_end; ++m.table, ++m._hashx, ++dst)
- if (*m._hashx)
- *dst = _cx_memb(_value_clone)(*m.table);
- m.table = t, m._hashx = h;
- return m;
-}
-#endif
-
-STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const size_t _newcap) {
- const i_size _oldbuckets = self->bucket_count;
- const i_size _nbuckets = ((i_size)(_newcap/self->max_load_factor) + 2) | 1;
- if (_newcap != self->size && _newcap <= _oldbuckets)
- return true;
- _cx_self m = {
- c_alloc_n(_cx_value, _nbuckets),
- (uint8_t *) c_calloc(_nbuckets + 1, 1),
- self->size, (i_size)_nbuckets,
- self->max_load_factor
- };
- bool ok = m.table && m._hashx;
- if (ok) { /* Rehash: */
- m._hashx[_nbuckets] = 0xff;
- const _cx_value* e = self->table;
- const uint8_t* h = self->_hashx;
- for (size_t i = 0; i < _oldbuckets; ++i, ++e) if (*h++) {
- _cx_rawkey r = i_keyto(_i_keyref(e));
- chash_bucket_t b = _cx_memb(_bucket_)(&m, &r);
- m.table[b.idx] = *e;
- m._hashx[b.idx] = (uint8_t)b.hx;
- }
- c_swap(_cx_self, *self, m);
- }
- c_free(m._hashx);
- c_free(m.table);
- return ok;
-}
-
-STC_DEF void
-_cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) {
- i_size i = _val - self->table, j = i, k;
- const i_size _cap = self->bucket_count;
- _cx_value* _slot = self->table;
- uint8_t* _hashx = self->_hashx;
- _cx_memb(_value_drop)(_val);
- for (;;) { /* delete without leaving tombstone */
- if (++j == _cap)
- j = 0;
- if (! _hashx[j])
- break;
- const _cx_rawkey _raw = i_keyto(_i_keyref(_slot + j));
- k = c_paste(fastrange_,i_size)(i_hash((&_raw)), _cap);
- if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */
- _slot[i] = _slot[j], _hashx[i] = _hashx[j], i = j;
- }
- _hashx[i] = 0;
- --self->size;
-}
-
-#endif // i_implement
-#undef _i_isset
-#undef _i_ismap
-#undef _i_ishash
-#undef _i_keyref
-#undef _i_MAP_ONLY
-#undef _i_SET_ONLY
-#define CMAP_H_INCLUDED
-#include "template.h"
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// Unordered set/map - implemented as closed hashing with linear probing and no tombstones. +/* +#include <stdio.h> + +#define i_tag ichar // Map int => char +#define i_key int +#define i_val char +#include <stc/cmap.h> + +int main(void) { + c_autovar (cmap_ichar m = cmap_ichar_init(), cmap_ichar_drop(&m)) + { + cmap_ichar_emplace(&m, 5, 'a'); + cmap_ichar_emplace(&m, 8, 'b'); + cmap_ichar_emplace(&m, 12, 'c'); + + cmap_ichar_value* v = cmap_ichar_get(&m, 10); // NULL + char val = *cmap_ichar_at(&m, 5); // 'a' + cmap_ichar_emplace_or_assign(&m, 5, 'd'); // update + cmap_ichar_erase(&m, 8); + + c_foreach (i, cmap_ichar, m) + printf("map %d: %c\n", i.ref->first, i.ref->second); + } +} +*/ +#include "ccommon.h" + +#ifndef CMAP_H_INCLUDED +#include "forward.h" +#include <stdlib.h> +#include <string.h> +#define _cmap_inits {NULL, NULL, 0, 0, 0.85f} +typedef struct { size_t idx; uint8_t hx; } chash_bucket_t; +#endif // CMAP_H_INCLUDED + +#ifndef _i_prefix +#define _i_prefix cmap_ +#endif +#ifdef _i_isset + #define _i_MAP_ONLY c_false + #define _i_SET_ONLY c_true + #define _i_keyref(vp) (vp) +#else + #define _i_ismap + #define _i_MAP_ONLY c_true + #define _i_SET_ONLY c_false + #define _i_keyref(vp) (&(vp)->first) +#endif +#define _i_ishash +#include "template.h" +#if !c_option(c_is_fwd) + _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_size, _i_MAP_ONLY, _i_SET_ONLY); +#endif + +_i_MAP_ONLY( struct _cx_value { + _cx_key first; + _cx_mapped second; +}; ) + +typedef i_keyraw _cx_rawkey; +typedef i_valraw _cx_memb(_rawmapped); +typedef _i_SET_ONLY( i_keyraw ) + _i_MAP_ONLY( struct { i_keyraw first; + i_valraw second; } ) +_cx_raw; + +STC_API _cx_self _cx_memb(_with_capacity)(size_t cap); +#if !defined _i_no_clone +STC_API _cx_self _cx_memb(_clone)(_cx_self map); +#endif +STC_API void _cx_memb(_drop)(_cx_self* self); +STC_API void _cx_memb(_clear)(_cx_self* self); +STC_API bool _cx_memb(_reserve)(_cx_self* self, size_t capacity); +STC_API chash_bucket_t _cx_memb(_bucket_)(const _cx_self* self, const _cx_rawkey* rkeyptr); +STC_API _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey); +STC_API void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* val); + +STC_INLINE _cx_self _cx_memb(_init)(void) { return c_make(_cx_self)_cmap_inits; } +STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) { _cx_memb(_reserve)(self, self->size); } +STC_INLINE void _cx_memb(_max_load_factor)(_cx_self* self, float ml) {self->max_load_factor = ml; } +STC_INLINE bool _cx_memb(_empty)(_cx_self m) { return m.size == 0; } +STC_INLINE size_t _cx_memb(_size)(_cx_self m) { return m.size; } +STC_INLINE size_t _cx_memb(_bucket_count)(_cx_self map) { return map.bucket_count; } +STC_INLINE size_t _cx_memb(_capacity)(_cx_self map) + { return map.bucket_count ? (size_t)((map.bucket_count - 2)*map.max_load_factor) : 0u; } +STC_INLINE void _cx_memb(_swap)(_cx_self *map1, _cx_self *map2) {c_swap(_cx_self, *map1, *map2); } +STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_rawkey rkey) + { return self->size && self->_hashx[_cx_memb(_bucket_)(self, &rkey).idx]; } + +#ifndef _i_isset + STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped); + #if !defined _i_no_clone && !defined _i_no_emplace + STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped); + #endif + + STC_INLINE const _cx_mapped* + _cx_memb(_at)(const _cx_self* self, _cx_rawkey rkey) { + chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey); + assert(self->_hashx[b.idx]); + return &self->table[b.idx].second; + } + STC_INLINE _cx_mapped* + _cx_memb(_at_mut)(_cx_self* self, _cx_rawkey rkey) + { return (_cx_mapped*)_cx_memb(_at)(self, rkey); } +#endif // !_i_isset + +#if !defined _i_no_clone +STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) { + if (self->table == other.table) + return; + _cx_memb(_drop)(self); + *self = _cx_memb(_clone)(other); +} + +STC_INLINE _cx_value +_cx_memb(_value_clone)(_cx_value _val) { + *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val))); + _i_MAP_ONLY( _val.second = i_valclone(_val.second); ) + return _val; +} + +#if !defined _i_no_emplace +STC_INLINE _cx_result +_cx_memb(_emplace)(_cx_self* self, _cx_rawkey rkey _i_MAP_ONLY(, i_valraw rmapped)) { + _cx_result _res = _cx_memb(_insert_entry_)(self, rkey); + if (_res.inserted) { + *_i_keyref(_res.ref) = i_keyfrom(rkey); + _i_MAP_ONLY( _res.ref->second = i_valfrom(rmapped); ) + } + return _res; +} +#endif // !_i_no_emplace +#endif // !_i_no_clone + +STC_INLINE _cx_raw +_cx_memb(_value_toraw)(_cx_value* val) { + return _i_SET_ONLY( i_keyto(val) ) + _i_MAP_ONLY( c_make(_cx_raw){i_keyto((&val->first)), i_valto((&val->second))} ); +} + +STC_INLINE void +_cx_memb(_value_drop)(_cx_value* _val) { + i_keydrop(_i_keyref(_val)); + _i_MAP_ONLY( i_valdrop((&_val->second)); ) +} + +STC_INLINE _cx_result +_cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { + _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key))); + if (_res.inserted) + { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )} + else + { i_keydrop((&_key)); _i_MAP_ONLY( i_valdrop((&_mapped)); )} + return _res; +} + +STC_INLINE _cx_result +_cx_memb(_push)(_cx_self* self, _cx_value _val) { + _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); + if (_res.inserted) + *_res.ref = _val; + else + _cx_memb(_value_drop)(&_val); + return _res; +} + +STC_INLINE _cx_iter +_cx_memb(_find)(const _cx_self* self, _cx_rawkey rkey) { + i_size idx; + if (!(self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx])) + idx = self->bucket_count; + return c_make(_cx_iter){self->table+idx, self->_hashx+idx}; +} + +STC_INLINE const _cx_value* +_cx_memb(_get)(const _cx_self* self, _cx_rawkey rkey) { + i_size idx; + if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx]) + return self->table + idx; + return NULL; +} + +STC_INLINE _cx_value* +_cx_memb(_get_mut)(const _cx_self* self, _cx_rawkey rkey) + { return (_cx_value*)_cx_memb(_get)(self, rkey); } + +STC_INLINE _cx_iter +_cx_memb(_begin)(const _cx_self* self) { + _cx_iter it = {self->table, self->_hashx}; + if (it._hx) + while (*it._hx == 0) + ++it.ref, ++it._hx; + return it; +} + +STC_INLINE _cx_iter +_cx_memb(_end)(const _cx_self* self) + { return c_make(_cx_iter){self->table + self->bucket_count}; } + +STC_INLINE void +_cx_memb(_next)(_cx_iter* it) + { while ((++it->ref, *++it->_hx == 0)) ; } + +STC_INLINE _cx_iter +_cx_memb(_advance)(_cx_iter it, size_t n) { + // UB if n > elements left + while (n--) _cx_memb(_next)(&it); + return it; +} + +STC_INLINE size_t +_cx_memb(_erase)(_cx_self* self, _cx_rawkey rkey) { + if (self->size == 0) + return 0; + chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey); + return self->_hashx[b.idx] ? _cx_memb(_erase_entry)(self, self->table + b.idx), 1 : 0; +} + +STC_INLINE _cx_iter +_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { + _cx_memb(_erase_entry)(self, it.ref); + if (*it._hx == 0) + _cx_memb(_next)(&it); + return it; +} + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) + +#ifndef CMAP_H_INCLUDED +STC_INLINE size_t fastrange_size_t(uint64_t x, uint64_t n) + { uint64_t lo, hi; c_umul128(x, n, &lo, &hi); return (size_t)hi; } +STC_INLINE size_t fastrange_uint32_t(uint64_t x, uint64_t n) + { return (size_t)((uint32_t)x*n >> 32); } +#endif // CMAP_H_INCLUDED + +STC_DEF _cx_self +_cx_memb(_with_capacity)(const size_t cap) { + _cx_self h = _cmap_inits; + _cx_memb(_reserve)(&h, cap); + return h; +} + +STC_INLINE void _cx_memb(_wipe_)(_cx_self* self) { + if (self->size == 0) + return; + _cx_value* e = self->table, *end = e + self->bucket_count; + uint8_t *hx = self->_hashx; + for (; e != end; ++e) + if (*hx++) + _cx_memb(_value_drop)(e); +} + +STC_DEF void _cx_memb(_drop)(_cx_self* self) { + _cx_memb(_wipe_)(self); + c_free(self->_hashx); + c_free((void *) self->table); +} + +STC_DEF void _cx_memb(_clear)(_cx_self* self) { + _cx_memb(_wipe_)(self); + self->size = 0; + memset(self->_hashx, 0, self->bucket_count); +} + +#ifndef _i_isset + STC_DEF _cx_result + _cx_memb(_insert_or_assign)(_cx_self* self, i_key _key, i_val _mapped) { + _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto((&_key))); + if (_res.inserted) + _res.ref->first = _key; + else + { i_keydrop((&_key)); i_valdrop((&_res.ref->second)); } + _res.ref->second = _mapped; + return _res; + } + + #if !defined _i_no_clone && !defined _i_no_emplace + STC_DEF _cx_result + _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped) { + _cx_result _res = _cx_memb(_insert_entry_)(self, rkey); + if (_res.inserted) + _res.ref->first = i_keyfrom(rkey); + else + { i_valdrop((&_res.ref->second)); } + _res.ref->second = i_valfrom(rmapped); + return _res; + } + #endif // !_i_no_clone && !_i_no_emplace +#endif // !_i_isset + +STC_DEF chash_bucket_t +_cx_memb(_bucket_)(const _cx_self* self, const _cx_rawkey* rkeyptr) { + const uint64_t _hash = i_hash(rkeyptr); + i_size _cap = self->bucket_count; + chash_bucket_t b = {c_paste(fastrange_,i_size)(_hash, _cap), (uint8_t)(_hash | 0x80)}; + const uint8_t* _hx = self->_hashx; + while (_hx[b.idx]) { + if (_hx[b.idx] == b.hx) { + const _cx_rawkey _raw = i_keyto(_i_keyref(self->table + b.idx)); + if (i_eq((&_raw), rkeyptr)) + break; + } + if (++b.idx == _cap) + b.idx = 0; + } + return b; +} + +STC_DEF _cx_result +_cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey) { + bool nomem = false; + if (self->size + 1 >= (i_size)(self->bucket_count*self->max_load_factor)) + nomem = !_cx_memb(_reserve)(self, ((size_t)self->size*3 >> 1) + 4); + chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey); + _cx_result res = {&self->table[b.idx], !self->_hashx[b.idx], nomem}; + if (res.inserted) { + self->_hashx[b.idx] = b.hx; + ++self->size; + } + return res; +} + +#if !defined _i_no_clone +STC_DEF _cx_self +_cx_memb(_clone)(_cx_self m) { + _cx_value *t = c_alloc_n(_cx_value, m.bucket_count), *dst = t, *m_end = m.table + m.bucket_count; + uint8_t *h = (uint8_t *)memcpy(c_malloc(m.bucket_count + 1), m._hashx, m.bucket_count + 1); + if (!(t && h)) + { c_free(t), c_free(h), t = 0, h = 0, m.bucket_count = 0; } + else + for (; m.table != m_end; ++m.table, ++m._hashx, ++dst) + if (*m._hashx) + *dst = _cx_memb(_value_clone)(*m.table); + m.table = t, m._hashx = h; + return m; +} +#endif + +STC_DEF bool +_cx_memb(_reserve)(_cx_self* self, const size_t _newcap) { + const i_size _oldbuckets = self->bucket_count; + const i_size _nbuckets = ((i_size)(_newcap/self->max_load_factor) + 2) | 1; + if (_newcap != self->size && _newcap <= _oldbuckets) + return true; + _cx_self m = { + c_alloc_n(_cx_value, _nbuckets), + (uint8_t *) c_calloc(_nbuckets + 1, 1), + self->size, (i_size)_nbuckets, + self->max_load_factor + }; + bool ok = m.table && m._hashx; + if (ok) { /* Rehash: */ + m._hashx[_nbuckets] = 0xff; + const _cx_value* e = self->table; + const uint8_t* h = self->_hashx; + for (size_t i = 0; i < _oldbuckets; ++i, ++e) if (*h++) { + _cx_rawkey r = i_keyto(_i_keyref(e)); + chash_bucket_t b = _cx_memb(_bucket_)(&m, &r); + m.table[b.idx] = *e; + m._hashx[b.idx] = (uint8_t)b.hx; + } + c_swap(_cx_self, *self, m); + } + c_free(m._hashx); + c_free(m.table); + return ok; +} + +STC_DEF void +_cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { + i_size i = _val - self->table, j = i, k; + const i_size _cap = self->bucket_count; + _cx_value* _slot = self->table; + uint8_t* _hashx = self->_hashx; + _cx_memb(_value_drop)(_val); + for (;;) { /* delete without leaving tombstone */ + if (++j == _cap) + j = 0; + if (! _hashx[j]) + break; + const _cx_rawkey _raw = i_keyto(_i_keyref(_slot + j)); + k = c_paste(fastrange_,i_size)(i_hash((&_raw)), _cap); + if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */ + _slot[i] = _slot[j], _hashx[i] = _hashx[j], i = j; + } + _hashx[i] = 0; + --self->size; +} + +#endif // i_implement +#undef _i_isset +#undef _i_ismap +#undef _i_ishash +#undef _i_keyref +#undef _i_MAP_ONLY +#undef _i_SET_ONLY +#define CMAP_H_INCLUDED +#include "template.h" diff --git a/include/stc/cpque.h b/include/stc/cpque.h index cb4b6e70..3a7cc0a1 100644 --- a/include/stc/cpque.h +++ b/include/stc/cpque.h @@ -1,157 +1,157 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include "ccommon.h"
-
-#ifndef CPQUE_H_INCLUDED
-#include <stdlib.h>
-#include "forward.h"
-#endif
-
-#ifndef _i_prefix
-#define _i_prefix cpque_
-#endif
-
-#include "template.h"
-
-#if !c_option(c_is_fwd)
- _cx_deftypes(_c_cpque_types, _cx_self, i_key);
-#endif
-typedef i_keyraw _cx_raw;
-
-STC_API void _cx_memb(_make_heap)(_cx_self* self);
-STC_API void _cx_memb(_erase_at)(_cx_self* self, size_t idx);
-STC_API void _cx_memb(_push)(_cx_self* self, _cx_value value);
-
-STC_INLINE _cx_self _cx_memb(_init)(void)
- { return c_make(_cx_self){NULL}; }
-
-STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, const size_t cap) {
- if (cap != self->size && cap <= self->capacity) return true;
- _cx_value *d = (_cx_value *)c_realloc(self->data, cap*sizeof *d);
- return d ? (self->data = d, self->capacity = cap, true) : false;
-}
-
-STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self)
- { _cx_memb(_reserve)(self, self->size); }
-
-STC_INLINE _cx_self _cx_memb(_with_capacity)(const size_t cap) {
- _cx_self out = {NULL}; _cx_memb(_reserve)(&out, cap);
- return out;
-}
-
-STC_INLINE _cx_self _cx_memb(_with_size)(const size_t size, i_key null) {
- _cx_self out = {NULL}; _cx_memb(_reserve)(&out, size);
- while (out.size < size) out.data[out.size++] = null;
- return out;
-}
-
-STC_INLINE void _cx_memb(_clear)(_cx_self* self) {
- size_t i = self->size; self->size = 0;
- while (i--) { i_keydrop((self->data + i)); }
-}
-
-STC_INLINE void _cx_memb(_drop)(_cx_self* self)
- { _cx_memb(_clear)(self); c_free(self->data); }
-
-STC_INLINE size_t _cx_memb(_size)(_cx_self q)
- { return q.size; }
-
-STC_INLINE bool _cx_memb(_empty)(_cx_self q)
- { return !q.size; }
-
-STC_INLINE size_t _cx_memb(_capacity)(_cx_self q)
- { return q.capacity; }
-
-STC_INLINE _cx_value* _cx_memb(_top)(const _cx_self* self)
- { return &self->data[0]; }
-
-STC_INLINE void _cx_memb(_pop)(_cx_self* self)
- { _cx_memb(_erase_at)(self, 0); }
-
-#if !defined _i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self q);
-
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->data == other.data) return;
- _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other);
-}
-STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val)
- { return i_keyclone(val); }
-
-#if !defined _i_no_emplace
-STC_INLINE void _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { _cx_memb(_push)(self, i_keyfrom(raw)); }
-#endif // !_i_no_emplace
-#endif // !_i_no_clone
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-STC_DEF void
-_cx_memb(_sift_down_)(_cx_value* arr, const size_t idx, const size_t n) {
- for (size_t r = idx, c = idx << 1; c <= n; c <<= 1) {
- c += (c < n && (i_cmp((&arr[c]), (&arr[c + 1]))) < 0);
- if ((i_cmp((&arr[r]), (&arr[c]))) >= 0) return;
- _cx_value t = arr[r]; arr[r] = arr[c]; arr[r = c] = t;
- }
-}
-
-STC_DEF void
-_cx_memb(_make_heap)(_cx_self* self) {
- size_t n = _cx_memb(_size)(*self);
- _cx_value *arr = self->data - 1;
- for (size_t k = n >> 1; k != 0; --k)
- _cx_memb(_sift_down_)(arr, k, n);
-}
-
-#if !defined _i_no_clone
-STC_DEF _cx_self _cx_memb(_clone)(_cx_self q) {
- _cx_self out = _cx_memb(_with_capacity)(q.size);
- for (; out.size < out.capacity; ++q.data)
- out.data[out.size++] = i_keyclone((*q.data));
- return out;
-}
-#endif
-
-STC_DEF void
-_cx_memb(_erase_at)(_cx_self* self, const size_t idx) {
- i_keydrop((self->data + idx));
- const size_t n = --self->size;
- self->data[idx] = self->data[n];
- _cx_memb(_sift_down_)(self->data - 1, idx + 1, n);
-}
-
-STC_DEF void
-_cx_memb(_push)(_cx_self* self, _cx_value value) {
- if (self->size == self->capacity)
- _cx_memb(_reserve)(self, self->size*3/2 + 4);
- _cx_value *arr = self->data - 1; /* base 1 */
- size_t c = ++self->size;
- for (; c > 1 && (i_cmp((&arr[c >> 1]), (&value))) < 0; c >>= 1)
- arr[c] = arr[c >> 1];
- arr[c] = value;
-}
-
-#endif
-#define CPQUE_H_INCLUDED
-#include "template.h"
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "ccommon.h" + +#ifndef CPQUE_H_INCLUDED +#include <stdlib.h> +#include "forward.h" +#endif + +#ifndef _i_prefix +#define _i_prefix cpque_ +#endif + +#include "template.h" + +#if !c_option(c_is_fwd) + _cx_deftypes(_c_cpque_types, _cx_self, i_key); +#endif +typedef i_keyraw _cx_raw; + +STC_API void _cx_memb(_make_heap)(_cx_self* self); +STC_API void _cx_memb(_erase_at)(_cx_self* self, size_t idx); +STC_API void _cx_memb(_push)(_cx_self* self, _cx_value value); + +STC_INLINE _cx_self _cx_memb(_init)(void) + { return c_make(_cx_self){NULL}; } + +STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, const size_t cap) { + if (cap != self->size && cap <= self->capacity) return true; + _cx_value *d = (_cx_value *)c_realloc(self->data, cap*sizeof *d); + return d ? (self->data = d, self->capacity = cap, true) : false; +} + +STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) + { _cx_memb(_reserve)(self, self->size); } + +STC_INLINE _cx_self _cx_memb(_with_capacity)(const size_t cap) { + _cx_self out = {NULL}; _cx_memb(_reserve)(&out, cap); + return out; +} + +STC_INLINE _cx_self _cx_memb(_with_size)(const size_t size, i_key null) { + _cx_self out = {NULL}; _cx_memb(_reserve)(&out, size); + while (out.size < size) out.data[out.size++] = null; + return out; +} + +STC_INLINE void _cx_memb(_clear)(_cx_self* self) { + size_t i = self->size; self->size = 0; + while (i--) { i_keydrop((self->data + i)); } +} + +STC_INLINE void _cx_memb(_drop)(_cx_self* self) + { _cx_memb(_clear)(self); c_free(self->data); } + +STC_INLINE size_t _cx_memb(_size)(_cx_self q) + { return q.size; } + +STC_INLINE bool _cx_memb(_empty)(_cx_self q) + { return !q.size; } + +STC_INLINE size_t _cx_memb(_capacity)(_cx_self q) + { return q.capacity; } + +STC_INLINE _cx_value* _cx_memb(_top)(const _cx_self* self) + { return &self->data[0]; } + +STC_INLINE void _cx_memb(_pop)(_cx_self* self) + { _cx_memb(_erase_at)(self, 0); } + +#if !defined _i_no_clone +STC_API _cx_self _cx_memb(_clone)(_cx_self q); + +STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) { + if (self->data == other.data) return; + _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other); +} +STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val) + { return i_keyclone(val); } + +#if !defined _i_no_emplace +STC_INLINE void _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) + { _cx_memb(_push)(self, i_keyfrom(raw)); } +#endif // !_i_no_emplace +#endif // !_i_no_clone + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) + +STC_DEF void +_cx_memb(_sift_down_)(_cx_value* arr, const size_t idx, const size_t n) { + for (size_t r = idx, c = idx << 1; c <= n; c <<= 1) { + c += (c < n && (i_cmp((&arr[c]), (&arr[c + 1]))) < 0); + if ((i_cmp((&arr[r]), (&arr[c]))) >= 0) return; + _cx_value t = arr[r]; arr[r] = arr[c]; arr[r = c] = t; + } +} + +STC_DEF void +_cx_memb(_make_heap)(_cx_self* self) { + size_t n = _cx_memb(_size)(*self); + _cx_value *arr = self->data - 1; + for (size_t k = n >> 1; k != 0; --k) + _cx_memb(_sift_down_)(arr, k, n); +} + +#if !defined _i_no_clone +STC_DEF _cx_self _cx_memb(_clone)(_cx_self q) { + _cx_self out = _cx_memb(_with_capacity)(q.size); + for (; out.size < out.capacity; ++q.data) + out.data[out.size++] = i_keyclone((*q.data)); + return out; +} +#endif + +STC_DEF void +_cx_memb(_erase_at)(_cx_self* self, const size_t idx) { + i_keydrop((self->data + idx)); + const size_t n = --self->size; + self->data[idx] = self->data[n]; + _cx_memb(_sift_down_)(self->data - 1, idx + 1, n); +} + +STC_DEF void +_cx_memb(_push)(_cx_self* self, _cx_value value) { + if (self->size == self->capacity) + _cx_memb(_reserve)(self, self->size*3/2 + 4); + _cx_value *arr = self->data - 1; /* base 1 */ + size_t c = ++self->size; + for (; c > 1 && (i_cmp((&arr[c >> 1]), (&value))) < 0; c >>= 1) + arr[c] = arr[c >> 1]; + arr[c] = value; +} + +#endif +#define CPQUE_H_INCLUDED +#include "template.h" diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h index 920f8eac..00874f35 100644 --- a/include/stc/cqueue.h +++ b/include/stc/cqueue.h @@ -1,65 +1,65 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-// STC queue
-/*
-#include <stc/crandom.h>
-#include <stdio.h>
-
-#define i_key int
-#include <stc/cqueue.h>
-
-int main() {
- int n = 10000000;
- stc64_t rng = stc64_new(1234);
- stc64_uniform_t dist = stc64_uniform_new(0, n);
-
- c_auto (cqueue_int, Q)
- {
- // Push ten million random numbers onto the queue.
- for (int i=0; i<n; ++i)
- cqueue_int_push(&Q, stc64_uniform(&rng, &dist));
-
- // Push or pop on the queue ten million times
- printf("before: size, capacity: %d, %d\n", n, cqueue_int_size(Q), cqueue_int_capacity(Q));
- for (int i=n; i>0; --i) {
- int r = stc64_uniform(&rng, &dist);
- if (r & 1)
- ++n, cqueue_int_push(&Q, r);
- else
- --n, cqueue_int_pop(&Q);
- }
- printf("after: size, capacity: %d, %d\n", n, cqueue_int_size(Q), cqueue_int_capacity(Q));
- }
-}
-*/
-
-#ifndef _i_prefix
-#define _i_prefix cqueue_
-#endif
-#define _i_queue
-#define _pop_front _pop
-
-#include "cdeq.h"
-
-#undef _pop_front
-#undef _i_queue
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +// STC queue +/* +#include <stc/crandom.h> +#include <stdio.h> + +#define i_key int +#include <stc/cqueue.h> + +int main() { + int n = 10000000; + stc64_t rng = stc64_new(1234); + stc64_uniform_t dist = stc64_uniform_new(0, n); + + c_auto (cqueue_int, Q) + { + // Push ten million random numbers onto the queue. + for (int i=0; i<n; ++i) + cqueue_int_push(&Q, stc64_uniform(&rng, &dist)); + + // Push or pop on the queue ten million times + printf("before: size, capacity: %d, %d\n", n, cqueue_int_size(Q), cqueue_int_capacity(Q)); + for (int i=n; i>0; --i) { + int r = stc64_uniform(&rng, &dist); + if (r & 1) + ++n, cqueue_int_push(&Q, r); + else + --n, cqueue_int_pop(&Q); + } + printf("after: size, capacity: %d, %d\n", n, cqueue_int_size(Q), cqueue_int_capacity(Q)); + } +} +*/ + +#ifndef _i_prefix +#define _i_prefix cqueue_ +#endif +#define _i_queue +#define _pop_front _pop + +#include "cdeq.h" + +#undef _pop_front +#undef _i_queue diff --git a/include/stc/crandom.h b/include/stc/crandom.h index 88ac3af6..ea26eba3 100644 --- a/include/stc/crandom.h +++ b/include/stc/crandom.h @@ -1,195 +1,195 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#define i_header
-#include "ccommon.h"
-
-#ifndef CRANDOM_H_INCLUDED
-#define CRANDOM_H_INCLUDED
-/*
-// crandom: Pseudo-random number generator
-#include "stc/crandom.h"
-int main() {
- uint64_t seed = 123456789;
- stc64_t rng = stc64_new(seed);
- stc64_uniform_t dist1 = stc64_uniform_new(1, 6);
- stc64_uniformf_t dist2 = stc64_uniformf_new(1.0, 10.0);
- stc64_normalf_t dist3 = stc64_normalf_new(1.0, 10.0);
-
- uint64_t i = stc64_rand(&rng);
- int64_t iu = stc64_uniform(&rng, &dist1);
- double xu = stc64_uniformf(&rng, &dist2);
- double xn = stc64_normalf(&rng, &dist3);
-}
-*/
-#include <string.h>
-#include <math.h>
-
-typedef struct stc64 { uint64_t state[5]; } stc64_t;
-typedef struct stc64_uniform { int64_t lower; uint64_t range, threshold; } stc64_uniform_t;
-typedef struct stc64_uniformf { double lower, range; } stc64_uniformf_t;
-typedef struct stc64_normalf { double mean, stddev, next; unsigned has_next; } stc64_normalf_t;
-
-/* PRNG stc64.
- * Very fast PRNG suited for parallel usage with Weyl-sequence parameter.
- * 320-bit state, 256 bit is mutable.
- * Noticable faster than xoshiro and pcg, slighly slower than wyrand64 and
- * Romu, but these have restricted capacity for larger parallel jobs or unknown minimum periods.
- * stc64 supports 2^63 unique threads with a minimum 2^64 period lengths each.
- * Passes all statistical tests, e.g PractRand and correlation tests, i.e. interleaved
- * streams with one-bit diff state. Even the 16-bit version (LR=6, RS=5, LS=3) passes
- * PractRand to multiple TB input.
- */
-
-/* Global stc64 PRNGs */
-STC_API void csrandom(uint64_t seed);
-STC_API uint64_t crandom(void);
-STC_API double crandomf(void);
-
-/* Init stc64 prng with and without sequence number */
-STC_API stc64_t stc64_with_seq(uint64_t seed, uint64_t seq);
-STC_INLINE stc64_t stc64_new(uint64_t seed)
- { return stc64_with_seq(seed, seed + 0x3504f333d3aa0b37); }
-
-/* Unbiased bounded uniform distribution. range [low, high] */
-STC_API stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high);
-STC_API int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* dist);
-
-/* Normal distribution PRNG */
-STC_API double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist);
-
-
-/* Main stc64 prng */
-STC_INLINE uint64_t stc64_rand(stc64_t* rng) {
- uint64_t *s = rng->state; enum {LR=24, RS=11, LS=3};
- const uint64_t result = (s[0] ^ (s[3] += s[4])) + s[1];
- s[0] = s[1] ^ (s[1] >> RS);
- s[1] = s[2] + (s[2] << LS);
- s[2] = ((s[2] << LR) | (s[2] >> (64 - LR))) + result;
- return result;
-}
-
-/* Float64 random number in range [0.0, 1.0). */
-STC_INLINE double stc64_randf(stc64_t* rng) {
- union {uint64_t i; double f;} u = {0x3FF0000000000000ull | (stc64_rand(rng) >> 12)};
- return u.f - 1.0;
-}
-
-/* Float64 uniform distributed RNG, range [low, high). */
-STC_INLINE double stc64_uniformf(stc64_t* rng, stc64_uniformf_t* dist) {
- return stc64_randf(rng)*dist->range + dist->lower;
-}
-
-/* Init uniform distributed float64 RNG, range [low, high). */
-STC_INLINE stc64_uniformf_t stc64_uniformf_new(double low, double high) {
- return c_make(stc64_uniformf_t){low, high - low};
-}
-
-/* Marsaglia polar method for gaussian/normal distribution, float64. */
-STC_INLINE stc64_normalf_t stc64_normalf_new(double mean, double stddev) {
- return c_make(stc64_normalf_t){mean, stddev, 0.0, 0};
-}
-
-/* Following functions are deprecated (will be removed in the future): */
-STC_INLINE void stc64_srandom(uint64_t seed) { csrandom(seed); }
-STC_INLINE uint64_t stc64_random() { return crandom(); }
-STC_INLINE stc64_t stc64_init(uint64_t seed) { return stc64_new(seed); }
-STC_INLINE stc64_uniformf_t stc64_uniformf_init(double low, double high)
- { return stc64_uniformf_new(low, high); }
-STC_INLINE stc64_normalf_t stc64_normalf_init(double mean, double stddev)
- { return stc64_normalf_new(mean, stddev); }
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-/* Global random() */
-static stc64_t stc64_global = {{
- 0x26aa069ea2fb1a4d, 0x70c72c95cd592d04,
- 0x504f333d3aa0b359, 0x9e3779b97f4a7c15,
- 0x6a09e667a754166b
-}};
-
-STC_DEF void csrandom(uint64_t seed) {
- stc64_global = stc64_new(seed);
-}
-
-STC_DEF uint64_t crandom(void) {
- return stc64_rand(&stc64_global);
-}
-
-STC_DEF double crandomf(void) {
- return stc64_randf(&stc64_global);
-}
-
-/* rng.state[4] must be odd */
-STC_DEF stc64_t stc64_with_seq(uint64_t seed, uint64_t seq) {
- stc64_t rng = {{seed+0x26aa069ea2fb1a4d, seed+0x70c72c95cd592d04,
- seed+0x504f333d3aa0b359, seed, seed<<1 | 1}};
- for (int i = 0; i < 6; ++i) stc64_rand(&rng);
- return rng;
-}
-
-/* Init unbiased uniform uint RNG with bounds [low, high] */
-STC_DEF stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high) {
- stc64_uniform_t dist = {low, (uint64_t) (high - low + 1)};
- dist.threshold = (uint64_t)-(int64_t)dist.range % dist.range;
- return dist;
-}
-
-/* Int uniform distributed RNG, range [low, high]. */
-STC_DEF int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* d) {
-#ifdef c_umul128
- uint64_t lo, hi;
- do { c_umul128(stc64_rand(rng), d->range, &lo, &hi); } while (lo < d->threshold);
- return d->lower + hi;
-#else
- uint64_t x, r;
- do {
- x = stc64_rand(rng);
- r = x % d->range;
- } while (x - r > -d->range);
- return d->lower + r;
-#endif
-}
-
-/* Normal distribution PRNG */
-STC_DEF double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist) {
- double u1, u2, s, m;
- if (dist->has_next++ & 1)
- return dist->next * dist->stddev + dist->mean;
- do {
- u1 = 2.0 * stc64_randf(rng) - 1.0;
- u2 = 2.0 * stc64_randf(rng) - 1.0;
- s = u1*u1 + u2*u2;
- } while (s >= 1.0 || s == 0.0);
- m = sqrt(-2.0 * log(s) / s);
- dist->next = u2 * m;
- return (u1 * m) * dist->stddev + dist->mean;
-}
-
-#endif
-#endif
-#undef i_opt
-#undef i_static
-#undef i_header
-#undef i_implement
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#define i_header +#include "ccommon.h" + +#ifndef CRANDOM_H_INCLUDED +#define CRANDOM_H_INCLUDED +/* +// crandom: Pseudo-random number generator +#include "stc/crandom.h" +int main() { + uint64_t seed = 123456789; + stc64_t rng = stc64_new(seed); + stc64_uniform_t dist1 = stc64_uniform_new(1, 6); + stc64_uniformf_t dist2 = stc64_uniformf_new(1.0, 10.0); + stc64_normalf_t dist3 = stc64_normalf_new(1.0, 10.0); + + uint64_t i = stc64_rand(&rng); + int64_t iu = stc64_uniform(&rng, &dist1); + double xu = stc64_uniformf(&rng, &dist2); + double xn = stc64_normalf(&rng, &dist3); +} +*/ +#include <string.h> +#include <math.h> + +typedef struct stc64 { uint64_t state[5]; } stc64_t; +typedef struct stc64_uniform { int64_t lower; uint64_t range, threshold; } stc64_uniform_t; +typedef struct stc64_uniformf { double lower, range; } stc64_uniformf_t; +typedef struct stc64_normalf { double mean, stddev, next; unsigned has_next; } stc64_normalf_t; + +/* PRNG stc64. + * Very fast PRNG suited for parallel usage with Weyl-sequence parameter. + * 320-bit state, 256 bit is mutable. + * Noticable faster than xoshiro and pcg, slighly slower than wyrand64 and + * Romu, but these have restricted capacity for larger parallel jobs or unknown minimum periods. + * stc64 supports 2^63 unique threads with a minimum 2^64 period lengths each. + * Passes all statistical tests, e.g PractRand and correlation tests, i.e. interleaved + * streams with one-bit diff state. Even the 16-bit version (LR=6, RS=5, LS=3) passes + * PractRand to multiple TB input. + */ + +/* Global stc64 PRNGs */ +STC_API void csrandom(uint64_t seed); +STC_API uint64_t crandom(void); +STC_API double crandomf(void); + +/* Init stc64 prng with and without sequence number */ +STC_API stc64_t stc64_with_seq(uint64_t seed, uint64_t seq); +STC_INLINE stc64_t stc64_new(uint64_t seed) + { return stc64_with_seq(seed, seed + 0x3504f333d3aa0b37); } + +/* Unbiased bounded uniform distribution. range [low, high] */ +STC_API stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high); +STC_API int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* dist); + +/* Normal distribution PRNG */ +STC_API double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist); + + +/* Main stc64 prng */ +STC_INLINE uint64_t stc64_rand(stc64_t* rng) { + uint64_t *s = rng->state; enum {LR=24, RS=11, LS=3}; + const uint64_t result = (s[0] ^ (s[3] += s[4])) + s[1]; + s[0] = s[1] ^ (s[1] >> RS); + s[1] = s[2] + (s[2] << LS); + s[2] = ((s[2] << LR) | (s[2] >> (64 - LR))) + result; + return result; +} + +/* Float64 random number in range [0.0, 1.0). */ +STC_INLINE double stc64_randf(stc64_t* rng) { + union {uint64_t i; double f;} u = {0x3FF0000000000000ull | (stc64_rand(rng) >> 12)}; + return u.f - 1.0; +} + +/* Float64 uniform distributed RNG, range [low, high). */ +STC_INLINE double stc64_uniformf(stc64_t* rng, stc64_uniformf_t* dist) { + return stc64_randf(rng)*dist->range + dist->lower; +} + +/* Init uniform distributed float64 RNG, range [low, high). */ +STC_INLINE stc64_uniformf_t stc64_uniformf_new(double low, double high) { + return c_make(stc64_uniformf_t){low, high - low}; +} + +/* Marsaglia polar method for gaussian/normal distribution, float64. */ +STC_INLINE stc64_normalf_t stc64_normalf_new(double mean, double stddev) { + return c_make(stc64_normalf_t){mean, stddev, 0.0, 0}; +} + +/* Following functions are deprecated (will be removed in the future): */ +STC_INLINE void stc64_srandom(uint64_t seed) { csrandom(seed); } +STC_INLINE uint64_t stc64_random() { return crandom(); } +STC_INLINE stc64_t stc64_init(uint64_t seed) { return stc64_new(seed); } +STC_INLINE stc64_uniformf_t stc64_uniformf_init(double low, double high) + { return stc64_uniformf_new(low, high); } +STC_INLINE stc64_normalf_t stc64_normalf_init(double mean, double stddev) + { return stc64_normalf_new(mean, stddev); } + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) + +/* Global random() */ +static stc64_t stc64_global = {{ + 0x26aa069ea2fb1a4d, 0x70c72c95cd592d04, + 0x504f333d3aa0b359, 0x9e3779b97f4a7c15, + 0x6a09e667a754166b +}}; + +STC_DEF void csrandom(uint64_t seed) { + stc64_global = stc64_new(seed); +} + +STC_DEF uint64_t crandom(void) { + return stc64_rand(&stc64_global); +} + +STC_DEF double crandomf(void) { + return stc64_randf(&stc64_global); +} + +/* rng.state[4] must be odd */ +STC_DEF stc64_t stc64_with_seq(uint64_t seed, uint64_t seq) { + stc64_t rng = {{seed+0x26aa069ea2fb1a4d, seed+0x70c72c95cd592d04, + seed+0x504f333d3aa0b359, seed, seed<<1 | 1}}; + for (int i = 0; i < 6; ++i) stc64_rand(&rng); + return rng; +} + +/* Init unbiased uniform uint RNG with bounds [low, high] */ +STC_DEF stc64_uniform_t stc64_uniform_new(int64_t low, int64_t high) { + stc64_uniform_t dist = {low, (uint64_t) (high - low + 1)}; + dist.threshold = (uint64_t)-(int64_t)dist.range % dist.range; + return dist; +} + +/* Int uniform distributed RNG, range [low, high]. */ +STC_DEF int64_t stc64_uniform(stc64_t* rng, stc64_uniform_t* d) { +#ifdef c_umul128 + uint64_t lo, hi; + do { c_umul128(stc64_rand(rng), d->range, &lo, &hi); } while (lo < d->threshold); + return d->lower + hi; +#else + uint64_t x, r; + do { + x = stc64_rand(rng); + r = x % d->range; + } while (x - r > -d->range); + return d->lower + r; +#endif +} + +/* Normal distribution PRNG */ +STC_DEF double stc64_normalf(stc64_t* rng, stc64_normalf_t* dist) { + double u1, u2, s, m; + if (dist->has_next++ & 1) + return dist->next * dist->stddev + dist->mean; + do { + u1 = 2.0 * stc64_randf(rng) - 1.0; + u2 = 2.0 * stc64_randf(rng) - 1.0; + s = u1*u1 + u2*u2; + } while (s >= 1.0 || s == 0.0); + m = sqrt(-2.0 * log(s) / s); + dist->next = u2 * m; + return (u1 * m) * dist->stddev + dist->mean; +} + +#endif +#endif +#undef i_opt +#undef i_static +#undef i_header +#undef i_implement #undef i_extern
\ No newline at end of file diff --git a/include/stc/cregex.h b/include/stc/cregex.h index 0a4508b7..1afe484f 100644 --- a/include/stc/cregex.h +++ b/include/stc/cregex.h @@ -1,90 +1,90 @@ -/*
-This is a Unix port of the Plan 9 regular expression library, by Rob Pike.
-Please send comments about the packaging to Russ Cox <[email protected]>.
-
-Copyright © 2021 Plan 9 Foundation
-Copyright © 2022 Tyge Løvset, for additions made in 2022.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-#ifndef CREGEX9_H_
-#define CREGEX9_H_
-/*
- * cregex9.h
- *
- * This is a extended version of regexp9, supporting UTF8 input, common
- * shorthand character classes, ++.
- */
-#include "forward.h" // csview
-
-typedef enum {
- creg_nomatch = -1,
- creg_matcherror = -2,
- creg_outofmemory = -3,
- creg_unmatchedleftparenthesis = -4,
- creg_unmatchedrightparenthesis = -5,
- creg_toomanysubexpressions = -6,
- creg_toomanycharacterclasses = -7,
- creg_malformedcharacterclass = -8,
- creg_missingoperand = -9,
- creg_unknownoperator = -10,
- creg_operandstackoverflow = -11,
- creg_operatorstackoverflow = -12,
- creg_operatorstackunderflow = -13,
-} cregex_error_t;
-
-enum {
- /* compile flags */
- creg_dotall = 1<<0,
- creg_caseless = 1<<1,
- /* execution flags */
- creg_fullmatch = 1<<2,
- creg_next = 1<<3,
- creg_startend = 1<<4,
- /* limits */
- creg_max_classes = 16,
- creg_max_captures = 32,
-};
-
-typedef struct {
- struct Reprog* prog;
-} cregex;
-
-typedef csview cregmatch;
-
-static inline cregex cregex_init(void) {
- cregex rx = {NULL}; return rx;
-}
-
-/* return number of capture groups on success, or (negative) error code on failure. */
-int cregex_compile(cregex *self, const char* pattern, int cflags);
-
-/* number of capture groups in a regex pattern */
-int cregex_captures(cregex rx);
-
-/* return number of capture groups on success, or (negative) error code on failure. */
-int cregex_find(const cregex *self, const char* string,
- size_t nmatch, cregmatch match[], int mflags);
-
-void cregex_replace(const char* src, char* dst, int dsize,
- int nmatch, const cregmatch match[]);
-
-void cregex_drop(cregex* self);
-
-#endif
+/* +This is a Unix port of the Plan 9 regular expression library, by Rob Pike. +Please send comments about the packaging to Russ Cox <[email protected]>. + +Copyright © 2021 Plan 9 Foundation +Copyright © 2022 Tyge Løvset, for additions made in 2022. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#ifndef CREGEX9_H_ +#define CREGEX9_H_ +/* + * cregex9.h + * + * This is a extended version of regexp9, supporting UTF8 input, common + * shorthand character classes, ++. + */ +#include "forward.h" // csview + +typedef enum { + creg_nomatch = -1, + creg_matcherror = -2, + creg_outofmemory = -3, + creg_unmatchedleftparenthesis = -4, + creg_unmatchedrightparenthesis = -5, + creg_toomanysubexpressions = -6, + creg_toomanycharacterclasses = -7, + creg_malformedcharacterclass = -8, + creg_missingoperand = -9, + creg_unknownoperator = -10, + creg_operandstackoverflow = -11, + creg_operatorstackoverflow = -12, + creg_operatorstackunderflow = -13, +} cregex_error_t; + +enum { + /* compile flags */ + creg_dotall = 1<<0, + creg_caseless = 1<<1, + /* execution flags */ + creg_fullmatch = 1<<2, + creg_next = 1<<3, + creg_startend = 1<<4, + /* limits */ + creg_max_classes = 16, + creg_max_captures = 32, +}; + +typedef struct { + struct Reprog* prog; +} cregex; + +typedef csview cregmatch; + +static inline cregex cregex_init(void) { + cregex rx = {NULL}; return rx; +} + +/* return number of capture groups on success, or (negative) error code on failure. */ +int cregex_compile(cregex *self, const char* pattern, int cflags); + +/* number of capture groups in a regex pattern */ +int cregex_captures(cregex rx); + +/* return number of capture groups on success, or (negative) error code on failure. */ +int cregex_find(const cregex *self, const char* string, + size_t nmatch, cregmatch match[], int mflags); + +void cregex_replace(const char* src, char* dst, int dsize, + int nmatch, const cregmatch match[]); + +void cregex_drop(cregex* self); + +#endif diff --git a/include/stc/cset.h b/include/stc/cset.h index 335ce753..0dddc02f 100644 --- a/include/stc/cset.h +++ b/include/stc/cset.h @@ -1,46 +1,46 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-// Unordered set - implemented as closed hashing with linear probing and no tombstones.
-/*
-#define i_tag sx
-#define i_key int
-#include <stc/cset.h>
-#include <stdio.h>
-
-int main(void) {
- cset_sx s = cset_sx_init();
- cset_sx_insert(&s, 5);
- cset_sx_insert(&s, 8);
-
- c_foreach (i, cset_sx, s)
- printf("set %d\n", *i.ref);
- cset_sx_drop(&s);
-}
-*/
-
-#ifndef _i_prefix
-#define _i_prefix cset_
-#endif
-#define _i_isset
-#include "cmap.h"
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// Unordered set - implemented as closed hashing with linear probing and no tombstones. +/* +#define i_tag sx +#define i_key int +#include <stc/cset.h> +#include <stdio.h> + +int main(void) { + cset_sx s = cset_sx_init(); + cset_sx_insert(&s, 5); + cset_sx_insert(&s, 8); + + c_foreach (i, cset_sx, s) + printf("set %d\n", *i.ref); + cset_sx_drop(&s); +} +*/ + +#ifndef _i_prefix +#define _i_prefix cset_ +#endif +#define _i_isset +#include "cmap.h" diff --git a/include/stc/csmap.h b/include/stc/csmap.h index a723185d..a463d381 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -1,594 +1,594 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-// Sorted/Ordered set and map - implemented as an AA-tree.
-/*
-#include <stdio.h>
-#include <stc/cstr.h>
-
-#define i_tag sx // Sorted map<cstr, double>
-#define i_key_str
-#define i_val double
-#include <stc/csmap.h>
-
-int main(void) {
- c_autovar (csmap_sx m = csmap_sx_init(), csmap_sx_drop(&m))
- {
- csmap_sx_emplace(&m, "Testing one", 1.234);
- csmap_sx_emplace(&m, "Testing two", 12.34);
- csmap_sx_emplace(&m, "Testing three", 123.4);
-
- csmap_sx_value *v = csmap_sx_get(&m, "Testing five"); // NULL
- double num = *csmap_sx_at(&m, "Testing one");
- csmap_sx_emplace_or_assign(&m, "Testing three", 1000.0); // update
- csmap_sx_erase(&m, "Testing two");
-
- c_foreach (i, csmap_sx, m)
- printf("map %s: %g\n", cstr_str(&i.ref->first), i.ref->second);
- }
-}
-*/
-#ifdef STC_CSMAP_V1
-#include "alt/csmap.h"
-#else
-#include "ccommon.h"
-
-#ifndef CSMAP_H_INCLUDED
-#include "forward.h"
-#include <stdlib.h>
-#include <string.h>
-
-struct csmap_rep { size_t root, disp, head, size, cap; unsigned nodes[1]; };
-#define _csmap_rep(self) c_unchecked_container_of((self)->nodes, struct csmap_rep, nodes)
-#endif // CSMAP_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix csmap_
-#endif
-#ifdef _i_isset
- #define _i_MAP_ONLY c_false
- #define _i_SET_ONLY c_true
- #define _i_keyref(vp) (vp)
-#else
- #define _i_ismap
- #define _i_MAP_ONLY c_true
- #define _i_SET_ONLY c_false
- #define _i_keyref(vp) (&(vp)->first)
-#endif
-#include "template.h"
-
-#if !c_option(c_is_fwd)
-_cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_size, _i_MAP_ONLY, _i_SET_ONLY);
-#endif
-
-_i_MAP_ONLY( struct _cx_value {
- _cx_key first;
- _cx_mapped second;
-}; )
-struct _cx_node {
- i_size link[2];
- int8_t level;
- _cx_value value;
-};
-
-typedef i_keyraw _cx_rawkey;
-typedef i_valraw _cx_memb(_rawmapped);
-typedef _i_SET_ONLY( i_keyraw )
- _i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } )
- _cx_raw;
-
-#if !defined _i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self tree);
-#if !defined _i_no_emplace
-STC_API _cx_result _cx_memb(_emplace)(_cx_self* self, _cx_rawkey rkey _i_MAP_ONLY(, i_valraw rmapped));
-#endif // !_i_no_emplace
-#endif // !_i_no_clone
-STC_API _cx_self _cx_memb(_init)(void);
-STC_API _cx_result _cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped));
-STC_API _cx_result _cx_memb(_push)(_cx_self* self, _cx_value _val);
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, size_t cap);
-STC_API _cx_value* _cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out);
-STC_API _cx_iter _cx_memb(_lower_bound)(const _cx_self* self, _cx_rawkey rkey);
-STC_API _cx_value* _cx_memb(_front)(const _cx_self* self);
-STC_API _cx_value* _cx_memb(_back)(const _cx_self* self);
-STC_API int _cx_memb(_erase)(_cx_self* self, _cx_rawkey rkey);
-STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it);
-STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2);
-STC_API void _cx_memb(_next)(_cx_iter* it);
-
-STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return _csmap_rep(&cx)->size == 0; }
-STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return _csmap_rep(&cx)->size; }
-STC_INLINE size_t _cx_memb(_capacity)(_cx_self cx) { return _csmap_rep(&cx)->cap; }
-STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); }
-STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, _cx_rawkey rkey)
- { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); return it; }
-STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_rawkey rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it) != NULL; }
-STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, _cx_rawkey rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
-STC_INLINE _cx_value* _cx_memb(_get_mut)(_cx_self* self, _cx_rawkey rkey)
- { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); }
-
-STC_INLINE _cx_self
-_cx_memb(_with_capacity)(const size_t cap) {
- _cx_self tree = _cx_memb(_init)();
- _cx_memb(_reserve)(&tree, cap);
- return tree;
-}
-
-STC_INLINE void
-_cx_memb(_clear)(_cx_self* self)
- { _cx_memb(_drop)(self); *self = _cx_memb(_init)(); }
-
-STC_INLINE _cx_raw
-_cx_memb(_value_toraw)(_cx_value* val) {
- return _i_SET_ONLY( i_keyto(val) )
- _i_MAP_ONLY( c_make(_cx_raw){i_keyto((&val->first)),
- i_valto((&val->second))} );
-}
-
-STC_INLINE int
-_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- const _cx_rawkey rx = i_keyto(_i_keyref(x)), ry = i_keyto(_i_keyref(y));
- return i_cmp((&rx), (&ry));
-}
-
-STC_INLINE void
-_cx_memb(_value_drop)(_cx_value* val) {
- i_keydrop(_i_keyref(val));
- _i_MAP_ONLY( i_valdrop((&val->second)); )
-}
-
-#if !defined _i_no_clone
-STC_INLINE _cx_value
-_cx_memb(_value_clone)(_cx_value _val) {
- *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val)));
- _i_MAP_ONLY( _val.second = i_valclone(_val.second); )
- return _val;
-}
-
-STC_INLINE void
-_cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->nodes == other.nodes)
- return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(other);
-}
-
-STC_INLINE void
-_cx_memb(_shrink_to_fit)(_cx_self *self) {
- _cx_self tmp = _cx_memb(_clone)(*self);
- _cx_memb(_drop)(self); *self = tmp;
-}
-#endif // !_i_no_clone
-
-#ifndef _i_isset
- #if !defined _i_no_clone && !defined _i_no_emplace
- STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped);
- #endif
- STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped);
-
- STC_INLINE const _cx_mapped*
- _cx_memb(_at)(const _cx_self* self, _cx_rawkey rkey)
- { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
- STC_INLINE _cx_mapped*
- _cx_memb(_at_mut)(_cx_self* self, _cx_rawkey rkey)
- { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; }
-#endif // !_i_isset
-
-STC_INLINE _cx_iter
-_cx_memb(_begin)(const _cx_self* self) {
- _cx_iter it;
- it._d = self->nodes, it._top = 0;
- it._tn = (i_size) _csmap_rep(self)->root;
- if (it._tn)
- _cx_memb(_next)(&it);
- return it;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_end)(const _cx_self* self) {
- (void)self;
- _cx_iter it; it.ref = NULL, it._top = 0, it._tn = 0;
- return it;
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_advance)(_cx_iter it, size_t n) {
- while (n-- && it.ref)
- _cx_memb(_next)(&it);
- return it;
-}
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-#ifndef CSMAP_H_INCLUDED
-static struct csmap_rep _csmap_sentinel = {0, 0, 0, 0, 0};
-#endif
-
-STC_DEF _cx_self
-_cx_memb(_init)(void) {
- _cx_self tree = {(_cx_node *)_csmap_sentinel.nodes};
- return tree;
-}
-
-STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const size_t cap) {
- struct csmap_rep* rep = _csmap_rep(self), *oldrep;
- if (cap >= rep->size) {
- // second test is bogus, but supresses gcc warning:
- oldrep = rep->cap && rep != &_csmap_sentinel ? rep : NULL;
- rep = (struct csmap_rep*) c_realloc(oldrep, offsetof(struct csmap_rep, nodes) +
- (cap + 1)*sizeof(_cx_node));
- if (!rep)
- return false;
- if (oldrep == NULL)
- memset(rep, 0, offsetof(struct csmap_rep, nodes) + sizeof(_cx_node));
- rep->cap = cap;
- self->nodes = (_cx_node *) rep->nodes;
- }
- return true;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_front)(const _cx_self* self) {
- _cx_node *d = self->nodes;
- i_size tn = (i_size) _csmap_rep(self)->root;
- while (d[tn].link[0])
- tn = d[tn].link[0];
- return &d[tn].value;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_back)(const _cx_self* self) {
- _cx_node *d = self->nodes;
- i_size tn = (i_size) _csmap_rep(self)->root;
- while (d[tn].link[1])
- tn = d[tn].link[1];
- return &d[tn].value;
-}
-
-static i_size
-_cx_memb(_new_node_)(_cx_self* self, int level) {
- i_size tn; struct csmap_rep *rep = _csmap_rep(self);
- if (rep->disp) {
- tn = rep->disp;
- rep->disp = self->nodes[tn].link[1];
- } else {
- if (rep->head == rep->cap)
- if (!_cx_memb(_reserve)(self, rep->head*3/2 + 4))
- return 0;
- tn = ++_csmap_rep(self)->head; /* start with 1, 0 is nullnode. */
- }
- _cx_node* dn = &self->nodes[tn];
- dn->link[0] = dn->link[1] = 0; dn->level = level;
- return tn;
-}
-
-static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey);
-
-STC_DEF _cx_result
-_cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped)) {
- _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key)));
- if (res.inserted)
- { *_i_keyref(res.ref) = key; _i_MAP_ONLY( res.ref->second = mapped; )}
- else
- { i_keydrop((&key)); _i_MAP_ONLY( i_valdrop((&mapped)); )}
- return res;
-}
-
-STC_DEF _cx_result
-_cx_memb(_push)(_cx_self* self, _cx_value _val) {
- _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val)));
- if (_res.inserted)
- *_res.ref = _val;
- else
- _cx_memb(_value_drop)(&_val);
- return _res;
-}
-
-#ifndef _i_isset
- STC_DEF _cx_result
- _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped) {
- _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key)));
- if (!res.nomem_error) {
- if (res.inserted)
- res.ref->first = key;
- else
- { i_keydrop((&key)); i_valdrop((&res.ref->second)); }
- res.ref->second = mapped;
- }
- return res;
- }
-
- #if !defined _i_no_clone && !defined _i_no_emplace
- STC_DEF _cx_result
- _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped) {
- _cx_result res = _cx_memb(_insert_entry_)(self, rkey);
- if (!res.nomem_error) {
- if (res.inserted)
- res.ref->first = i_keyfrom(rkey);
- else
- { i_valdrop((&res.ref->second)); }
- res.ref->second = i_valfrom(rmapped);
- }
- return res;
- }
- #endif // !_i_no_clone && !_i_no_emplace
-#endif // !_i_isset
-
-STC_DEF _cx_value*
-_cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out) {
- i_size tn = _csmap_rep(self)->root;
- _cx_node *d = out->_d = self->nodes;
- out->_top = 0;
- while (tn) {
- int c; const _cx_rawkey raw = i_keyto(_i_keyref(&d[tn].value));
- if ((c = i_cmp((&raw), (&rkey))) < 0)
- tn = d[tn].link[1];
- else if (c > 0)
- { out->_st[out->_top++] = tn; tn = d[tn].link[0]; }
- else
- { out->_tn = d[tn].link[1]; return (out->ref = &d[tn].value); }
- }
- return (out->ref = NULL);
-}
-
-STC_DEF _cx_iter
-_cx_memb(_lower_bound)(const _cx_self* self, _cx_rawkey rkey) {
- _cx_iter it;
- _cx_memb(_find_it)(self, rkey, &it);
- if (!it.ref && it._top) {
- i_size tn = it._st[--it._top];
- it._tn = it._d[tn].link[1];
- it.ref = &it._d[tn].value;
- }
- return it;
-}
-
-STC_DEF void
-_cx_memb(_next)(_cx_iter *it) {
- i_size tn = it->_tn;
- if (it->_top || tn) {
- while (tn) {
- it->_st[it->_top++] = tn;
- tn = it->_d[tn].link[0];
- }
- tn = it->_st[--it->_top];
- it->_tn = it->_d[tn].link[1];
- it->ref = &it->_d[tn].value;
- } else
- it->ref = NULL;
-}
-
-STC_DEF i_size
-_cx_memb(_skew_)(_cx_node *d, i_size tn) {
- if (tn && d[d[tn].link[0]].level == d[tn].level) {
- i_size tmp = d[tn].link[0];
- d[tn].link[0] = d[tmp].link[1];
- d[tmp].link[1] = tn;
- tn = tmp;
- }
- return tn;
-}
-
-STC_DEF i_size
-_cx_memb(_split_)(_cx_node *d, i_size tn) {
- if (d[d[d[tn].link[1]].link[1]].level == d[tn].level) {
- i_size tmp = d[tn].link[1];
- d[tn].link[1] = d[tmp].link[0];
- d[tmp].link[0] = tn;
- tn = tmp;
- ++d[tn].level;
- }
- return tn;
-}
-
-static i_size
-_cx_memb(_insert_entry_i_)(_cx_self* self, i_size tn, const _cx_rawkey* rkey, _cx_result* res) {
- i_size up[64], tx = tn;
- _cx_node* d = self->nodes;
- int c, top = 0, dir = 0;
- while (tx) {
- up[top++] = tx;
- const _cx_rawkey raw = i_keyto(_i_keyref(&d[tx].value));
- if (!(c = i_cmp((&raw), rkey)))
- { res->ref = &d[tx].value; return tn; }
- dir = (c < 0);
- tx = d[tx].link[dir];
- }
- if ((tx = _cx_memb(_new_node_)(self, 1)) == 0)
- { res->nomem_error = true; return 0; }
- d = self->nodes;
- res->ref = &d[tx].value, res->inserted = true;
- if (top == 0)
- return tx;
- d[up[top - 1]].link[dir] = tx;
- while (top--) {
- if (top)
- dir = (d[up[top - 1]].link[1] == up[top]);
- up[top] = _cx_memb(_skew_)(d, up[top]);
- up[top] = _cx_memb(_split_)(d, up[top]);
- if (top)
- d[up[top - 1]].link[dir] = up[top];
- }
- return up[0];
-}
-
-static _cx_result
-_cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey) {
- _cx_result res = {NULL};
- i_size tn = _cx_memb(_insert_entry_i_)(self, (i_size) _csmap_rep(self)->root, &rkey, &res);
- _csmap_rep(self)->root = tn;
- _csmap_rep(self)->size += res.inserted;
- return res;
-}
-
-static i_size
-_cx_memb(_erase_r_)(_cx_node *d, i_size tn, const _cx_rawkey* rkey, int *erased) {
- if (tn == 0)
- return 0;
- _cx_rawkey raw = i_keyto(_i_keyref(&d[tn].value));
- i_size tx; int c = i_cmp((&raw), rkey);
- if (c != 0)
- d[tn].link[c < 0] = _cx_memb(_erase_r_)(d, d[tn].link[c < 0], rkey, erased);
- else {
- if (!(*erased)++)
- _cx_memb(_value_drop)(&d[tn].value);
- if (d[tn].link[0] && d[tn].link[1]) {
- tx = d[tn].link[0];
- while (d[tx].link[1])
- tx = d[tx].link[1];
- d[tn].value = d[tx].value; /* move */
- raw = i_keyto(_i_keyref(&d[tn].value));
- d[tn].link[0] = _cx_memb(_erase_r_)(d, d[tn].link[0], &raw, erased);
- } else { /* unlink node */
- tx = tn;
- tn = d[tn].link[ d[tn].link[0] == 0 ];
- /* move it to disposed nodes list */
- struct csmap_rep *rep = c_unchecked_container_of(d, struct csmap_rep, nodes);
- d[tx].link[1] = (i_size) rep->disp;
- rep->disp = tx;
- }
- }
- tx = d[tn].link[1];
- if (d[d[tn].link[0]].level < d[tn].level - 1 || d[tx].level < d[tn].level - 1) {
- if (d[tx].level > --d[tn].level)
- d[tx].level = d[tn].level;
- tn = _cx_memb(_skew_)(d, tn);
- tx = d[tn].link[1] = _cx_memb(_skew_)(d, d[tn].link[1]);
- d[tx].link[1] = _cx_memb(_skew_)(d, d[tx].link[1]);
- tn = _cx_memb(_split_)(d, tn);
- d[tn].link[1] = _cx_memb(_split_)(d, d[tn].link[1]);
- }
- return tn;
-}
-
-STC_DEF int
-_cx_memb(_erase)(_cx_self* self, _cx_rawkey rkey) {
- int erased = 0;
- i_size root = _cx_memb(_erase_r_)(self->nodes, (i_size) _csmap_rep(self)->root, &rkey, &erased);
- if (erased) {
- _csmap_rep(self)->root = root;
- --_csmap_rep(self)->size;
- return 1;
- }
- return 0;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- _cx_rawkey raw = i_keyto(_i_keyref(it.ref)), nxt;
- _cx_memb(_next)(&it);
- if (it.ref)
- nxt = i_keyto(_i_keyref(it.ref));
- _cx_memb(_erase)(self, raw);
- if (it.ref)
- _cx_memb(_find_it)(self, nxt, &it);
- return it;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
- if (!it2.ref) {
- while (it1.ref)
- it1 = _cx_memb(_erase_at)(self, it1);
- return it1;
- }
- _cx_key k1 = *_i_keyref(it1.ref), k2 = *_i_keyref(it2.ref);
- _cx_rawkey r1 = i_keyto((&k1));
- for (;;) {
- if (memcmp(&k1, &k2, sizeof k1) == 0)
- return it1;
- _cx_memb(_next)(&it1);
- k1 = *_i_keyref(it1.ref);
- _cx_memb(_erase)(self, r1);
- r1 = i_keyto((&k1));
- _cx_memb(_find_it)(self, r1, &it1);
- }
-}
-
-#if !defined _i_no_clone
-static i_size
-_cx_memb(_clone_r_)(_cx_self* self, _cx_node* src, i_size sn) {
- if (sn == 0)
- return 0;
- i_size tx, tn = _cx_memb(_new_node_)(self, src[sn].level);
- self->nodes[tn].value = _cx_memb(_value_clone)(src[sn].value);
- tx = _cx_memb(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx;
- tx = _cx_memb(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx;
- return tn;
-}
-
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self tree) {
- _cx_self clone = _cx_memb(_with_capacity)(_csmap_rep(&tree)->size);
- i_size root = _cx_memb(_clone_r_)(&clone, tree.nodes, (i_size) _csmap_rep(&tree)->root);
- _csmap_rep(&clone)->root = root;
- _csmap_rep(&clone)->size = _csmap_rep(&tree)->size;
- return clone;
-}
-
-#if !defined _i_no_emplace
-STC_DEF _cx_result
-_cx_memb(_emplace)(_cx_self* self, _cx_rawkey rkey _i_MAP_ONLY(, i_valraw rmapped)) {
- _cx_result res = _cx_memb(_insert_entry_)(self, rkey);
- if (res.inserted) {
- *_i_keyref(res.ref) = i_keyfrom(rkey);
- _i_MAP_ONLY(res.ref->second = i_valfrom(rmapped);)
- }
- return res;
-}
-#endif // _i_no_emplace
-#endif // !_i_no_clone
-
-static void
-_cx_memb(_drop_r_)(_cx_node* d, i_size tn) {
- if (tn) {
- _cx_memb(_drop_r_)(d, d[tn].link[0]);
- _cx_memb(_drop_r_)(d, d[tn].link[1]);
- _cx_memb(_value_drop)(&d[tn].value);
- }
-}
-
-STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
- struct csmap_rep* rep = _csmap_rep(self);
- // second test is bogus, but supresses gcc warning:
- if (rep->cap && rep != &_csmap_sentinel) {
- _cx_memb(_drop_r_)(self->nodes, (i_size) rep->root);
- c_free(rep); // correct, but may give warning
- }
-}
-
-#endif // i_implement
-#undef _i_isset
-#undef _i_ismap
-#undef _i_keyref
-#undef _i_MAP_ONLY
-#undef _i_SET_ONLY
-#define CSMAP_H_INCLUDED
-#include "template.h"
-#endif // !STC_CSMAP_V1
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// Sorted/Ordered set and map - implemented as an AA-tree. +/* +#include <stdio.h> +#include <stc/cstr.h> + +#define i_tag sx // Sorted map<cstr, double> +#define i_key_str +#define i_val double +#include <stc/csmap.h> + +int main(void) { + c_autovar (csmap_sx m = csmap_sx_init(), csmap_sx_drop(&m)) + { + csmap_sx_emplace(&m, "Testing one", 1.234); + csmap_sx_emplace(&m, "Testing two", 12.34); + csmap_sx_emplace(&m, "Testing three", 123.4); + + csmap_sx_value *v = csmap_sx_get(&m, "Testing five"); // NULL + double num = *csmap_sx_at(&m, "Testing one"); + csmap_sx_emplace_or_assign(&m, "Testing three", 1000.0); // update + csmap_sx_erase(&m, "Testing two"); + + c_foreach (i, csmap_sx, m) + printf("map %s: %g\n", cstr_str(&i.ref->first), i.ref->second); + } +} +*/ +#ifdef STC_CSMAP_V1 +#include "alt/csmap.h" +#else +#include "ccommon.h" + +#ifndef CSMAP_H_INCLUDED +#include "forward.h" +#include <stdlib.h> +#include <string.h> + +struct csmap_rep { size_t root, disp, head, size, cap; unsigned nodes[1]; }; +#define _csmap_rep(self) c_unchecked_container_of((self)->nodes, struct csmap_rep, nodes) +#endif // CSMAP_H_INCLUDED + +#ifndef _i_prefix +#define _i_prefix csmap_ +#endif +#ifdef _i_isset + #define _i_MAP_ONLY c_false + #define _i_SET_ONLY c_true + #define _i_keyref(vp) (vp) +#else + #define _i_ismap + #define _i_MAP_ONLY c_true + #define _i_SET_ONLY c_false + #define _i_keyref(vp) (&(vp)->first) +#endif +#include "template.h" + +#if !c_option(c_is_fwd) +_cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_size, _i_MAP_ONLY, _i_SET_ONLY); +#endif + +_i_MAP_ONLY( struct _cx_value { + _cx_key first; + _cx_mapped second; +}; ) +struct _cx_node { + i_size link[2]; + int8_t level; + _cx_value value; +}; + +typedef i_keyraw _cx_rawkey; +typedef i_valraw _cx_memb(_rawmapped); +typedef _i_SET_ONLY( i_keyraw ) + _i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } ) + _cx_raw; + +#if !defined _i_no_clone +STC_API _cx_self _cx_memb(_clone)(_cx_self tree); +#if !defined _i_no_emplace +STC_API _cx_result _cx_memb(_emplace)(_cx_self* self, _cx_rawkey rkey _i_MAP_ONLY(, i_valraw rmapped)); +#endif // !_i_no_emplace +#endif // !_i_no_clone +STC_API _cx_self _cx_memb(_init)(void); +STC_API _cx_result _cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped)); +STC_API _cx_result _cx_memb(_push)(_cx_self* self, _cx_value _val); +STC_API void _cx_memb(_drop)(_cx_self* self); +STC_API bool _cx_memb(_reserve)(_cx_self* self, size_t cap); +STC_API _cx_value* _cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out); +STC_API _cx_iter _cx_memb(_lower_bound)(const _cx_self* self, _cx_rawkey rkey); +STC_API _cx_value* _cx_memb(_front)(const _cx_self* self); +STC_API _cx_value* _cx_memb(_back)(const _cx_self* self); +STC_API int _cx_memb(_erase)(_cx_self* self, _cx_rawkey rkey); +STC_API _cx_iter _cx_memb(_erase_at)(_cx_self* self, _cx_iter it); +STC_API _cx_iter _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2); +STC_API void _cx_memb(_next)(_cx_iter* it); + +STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return _csmap_rep(&cx)->size == 0; } +STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return _csmap_rep(&cx)->size; } +STC_INLINE size_t _cx_memb(_capacity)(_cx_self cx) { return _csmap_rep(&cx)->cap; } +STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); } +STC_INLINE _cx_iter _cx_memb(_find)(const _cx_self* self, _cx_rawkey rkey) + { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); return it; } +STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_rawkey rkey) + { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it) != NULL; } +STC_INLINE const _cx_value* _cx_memb(_get)(const _cx_self* self, _cx_rawkey rkey) + { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); } +STC_INLINE _cx_value* _cx_memb(_get_mut)(_cx_self* self, _cx_rawkey rkey) + { _cx_iter it; return _cx_memb(_find_it)(self, rkey, &it); } + +STC_INLINE _cx_self +_cx_memb(_with_capacity)(const size_t cap) { + _cx_self tree = _cx_memb(_init)(); + _cx_memb(_reserve)(&tree, cap); + return tree; +} + +STC_INLINE void +_cx_memb(_clear)(_cx_self* self) + { _cx_memb(_drop)(self); *self = _cx_memb(_init)(); } + +STC_INLINE _cx_raw +_cx_memb(_value_toraw)(_cx_value* val) { + return _i_SET_ONLY( i_keyto(val) ) + _i_MAP_ONLY( c_make(_cx_raw){i_keyto((&val->first)), + i_valto((&val->second))} ); +} + +STC_INLINE int +_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { + const _cx_rawkey rx = i_keyto(_i_keyref(x)), ry = i_keyto(_i_keyref(y)); + return i_cmp((&rx), (&ry)); +} + +STC_INLINE void +_cx_memb(_value_drop)(_cx_value* val) { + i_keydrop(_i_keyref(val)); + _i_MAP_ONLY( i_valdrop((&val->second)); ) +} + +#if !defined _i_no_clone +STC_INLINE _cx_value +_cx_memb(_value_clone)(_cx_value _val) { + *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val))); + _i_MAP_ONLY( _val.second = i_valclone(_val.second); ) + return _val; +} + +STC_INLINE void +_cx_memb(_copy)(_cx_self *self, _cx_self other) { + if (self->nodes == other.nodes) + return; + _cx_memb(_drop)(self); + *self = _cx_memb(_clone)(other); +} + +STC_INLINE void +_cx_memb(_shrink_to_fit)(_cx_self *self) { + _cx_self tmp = _cx_memb(_clone)(*self); + _cx_memb(_drop)(self); *self = tmp; +} +#endif // !_i_no_clone + +#ifndef _i_isset + #if !defined _i_no_clone && !defined _i_no_emplace + STC_API _cx_result _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped); + #endif + STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped); + + STC_INLINE const _cx_mapped* + _cx_memb(_at)(const _cx_self* self, _cx_rawkey rkey) + { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; } + STC_INLINE _cx_mapped* + _cx_memb(_at_mut)(_cx_self* self, _cx_rawkey rkey) + { _cx_iter it; return &_cx_memb(_find_it)(self, rkey, &it)->second; } +#endif // !_i_isset + +STC_INLINE _cx_iter +_cx_memb(_begin)(const _cx_self* self) { + _cx_iter it; + it._d = self->nodes, it._top = 0; + it._tn = (i_size) _csmap_rep(self)->root; + if (it._tn) + _cx_memb(_next)(&it); + return it; +} + +STC_INLINE _cx_iter +_cx_memb(_end)(const _cx_self* self) { + (void)self; + _cx_iter it; it.ref = NULL, it._top = 0, it._tn = 0; + return it; +} + +STC_INLINE _cx_iter +_cx_memb(_advance)(_cx_iter it, size_t n) { + while (n-- && it.ref) + _cx_memb(_next)(&it); + return it; +} + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) + +#ifndef CSMAP_H_INCLUDED +static struct csmap_rep _csmap_sentinel = {0, 0, 0, 0, 0}; +#endif + +STC_DEF _cx_self +_cx_memb(_init)(void) { + _cx_self tree = {(_cx_node *)_csmap_sentinel.nodes}; + return tree; +} + +STC_DEF bool +_cx_memb(_reserve)(_cx_self* self, const size_t cap) { + struct csmap_rep* rep = _csmap_rep(self), *oldrep; + if (cap >= rep->size) { + // second test is bogus, but supresses gcc warning: + oldrep = rep->cap && rep != &_csmap_sentinel ? rep : NULL; + rep = (struct csmap_rep*) c_realloc(oldrep, offsetof(struct csmap_rep, nodes) + + (cap + 1)*sizeof(_cx_node)); + if (!rep) + return false; + if (oldrep == NULL) + memset(rep, 0, offsetof(struct csmap_rep, nodes) + sizeof(_cx_node)); + rep->cap = cap; + self->nodes = (_cx_node *) rep->nodes; + } + return true; +} + +STC_DEF _cx_value* +_cx_memb(_front)(const _cx_self* self) { + _cx_node *d = self->nodes; + i_size tn = (i_size) _csmap_rep(self)->root; + while (d[tn].link[0]) + tn = d[tn].link[0]; + return &d[tn].value; +} + +STC_DEF _cx_value* +_cx_memb(_back)(const _cx_self* self) { + _cx_node *d = self->nodes; + i_size tn = (i_size) _csmap_rep(self)->root; + while (d[tn].link[1]) + tn = d[tn].link[1]; + return &d[tn].value; +} + +static i_size +_cx_memb(_new_node_)(_cx_self* self, int level) { + i_size tn; struct csmap_rep *rep = _csmap_rep(self); + if (rep->disp) { + tn = rep->disp; + rep->disp = self->nodes[tn].link[1]; + } else { + if (rep->head == rep->cap) + if (!_cx_memb(_reserve)(self, rep->head*3/2 + 4)) + return 0; + tn = ++_csmap_rep(self)->head; /* start with 1, 0 is nullnode. */ + } + _cx_node* dn = &self->nodes[tn]; + dn->link[0] = dn->link[1] = 0; dn->level = level; + return tn; +} + +static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey); + +STC_DEF _cx_result +_cx_memb(_insert)(_cx_self* self, i_key key _i_MAP_ONLY(, i_val mapped)) { + _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key))); + if (res.inserted) + { *_i_keyref(res.ref) = key; _i_MAP_ONLY( res.ref->second = mapped; )} + else + { i_keydrop((&key)); _i_MAP_ONLY( i_valdrop((&mapped)); )} + return res; +} + +STC_DEF _cx_result +_cx_memb(_push)(_cx_self* self, _cx_value _val) { + _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); + if (_res.inserted) + *_res.ref = _val; + else + _cx_memb(_value_drop)(&_val); + return _res; +} + +#ifndef _i_isset + STC_DEF _cx_result + _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped) { + _cx_result res = _cx_memb(_insert_entry_)(self, i_keyto((&key))); + if (!res.nomem_error) { + if (res.inserted) + res.ref->first = key; + else + { i_keydrop((&key)); i_valdrop((&res.ref->second)); } + res.ref->second = mapped; + } + return res; + } + + #if !defined _i_no_clone && !defined _i_no_emplace + STC_DEF _cx_result + _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_rawkey rkey, i_valraw rmapped) { + _cx_result res = _cx_memb(_insert_entry_)(self, rkey); + if (!res.nomem_error) { + if (res.inserted) + res.ref->first = i_keyfrom(rkey); + else + { i_valdrop((&res.ref->second)); } + res.ref->second = i_valfrom(rmapped); + } + return res; + } + #endif // !_i_no_clone && !_i_no_emplace +#endif // !_i_isset + +STC_DEF _cx_value* +_cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out) { + i_size tn = _csmap_rep(self)->root; + _cx_node *d = out->_d = self->nodes; + out->_top = 0; + while (tn) { + int c; const _cx_rawkey raw = i_keyto(_i_keyref(&d[tn].value)); + if ((c = i_cmp((&raw), (&rkey))) < 0) + tn = d[tn].link[1]; + else if (c > 0) + { out->_st[out->_top++] = tn; tn = d[tn].link[0]; } + else + { out->_tn = d[tn].link[1]; return (out->ref = &d[tn].value); } + } + return (out->ref = NULL); +} + +STC_DEF _cx_iter +_cx_memb(_lower_bound)(const _cx_self* self, _cx_rawkey rkey) { + _cx_iter it; + _cx_memb(_find_it)(self, rkey, &it); + if (!it.ref && it._top) { + i_size tn = it._st[--it._top]; + it._tn = it._d[tn].link[1]; + it.ref = &it._d[tn].value; + } + return it; +} + +STC_DEF void +_cx_memb(_next)(_cx_iter *it) { + i_size tn = it->_tn; + if (it->_top || tn) { + while (tn) { + it->_st[it->_top++] = tn; + tn = it->_d[tn].link[0]; + } + tn = it->_st[--it->_top]; + it->_tn = it->_d[tn].link[1]; + it->ref = &it->_d[tn].value; + } else + it->ref = NULL; +} + +STC_DEF i_size +_cx_memb(_skew_)(_cx_node *d, i_size tn) { + if (tn && d[d[tn].link[0]].level == d[tn].level) { + i_size tmp = d[tn].link[0]; + d[tn].link[0] = d[tmp].link[1]; + d[tmp].link[1] = tn; + tn = tmp; + } + return tn; +} + +STC_DEF i_size +_cx_memb(_split_)(_cx_node *d, i_size tn) { + if (d[d[d[tn].link[1]].link[1]].level == d[tn].level) { + i_size tmp = d[tn].link[1]; + d[tn].link[1] = d[tmp].link[0]; + d[tmp].link[0] = tn; + tn = tmp; + ++d[tn].level; + } + return tn; +} + +static i_size +_cx_memb(_insert_entry_i_)(_cx_self* self, i_size tn, const _cx_rawkey* rkey, _cx_result* res) { + i_size up[64], tx = tn; + _cx_node* d = self->nodes; + int c, top = 0, dir = 0; + while (tx) { + up[top++] = tx; + const _cx_rawkey raw = i_keyto(_i_keyref(&d[tx].value)); + if (!(c = i_cmp((&raw), rkey))) + { res->ref = &d[tx].value; return tn; } + dir = (c < 0); + tx = d[tx].link[dir]; + } + if ((tx = _cx_memb(_new_node_)(self, 1)) == 0) + { res->nomem_error = true; return 0; } + d = self->nodes; + res->ref = &d[tx].value, res->inserted = true; + if (top == 0) + return tx; + d[up[top - 1]].link[dir] = tx; + while (top--) { + if (top) + dir = (d[up[top - 1]].link[1] == up[top]); + up[top] = _cx_memb(_skew_)(d, up[top]); + up[top] = _cx_memb(_split_)(d, up[top]); + if (top) + d[up[top - 1]].link[dir] = up[top]; + } + return up[0]; +} + +static _cx_result +_cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey) { + _cx_result res = {NULL}; + i_size tn = _cx_memb(_insert_entry_i_)(self, (i_size) _csmap_rep(self)->root, &rkey, &res); + _csmap_rep(self)->root = tn; + _csmap_rep(self)->size += res.inserted; + return res; +} + +static i_size +_cx_memb(_erase_r_)(_cx_node *d, i_size tn, const _cx_rawkey* rkey, int *erased) { + if (tn == 0) + return 0; + _cx_rawkey raw = i_keyto(_i_keyref(&d[tn].value)); + i_size tx; int c = i_cmp((&raw), rkey); + if (c != 0) + d[tn].link[c < 0] = _cx_memb(_erase_r_)(d, d[tn].link[c < 0], rkey, erased); + else { + if (!(*erased)++) + _cx_memb(_value_drop)(&d[tn].value); + if (d[tn].link[0] && d[tn].link[1]) { + tx = d[tn].link[0]; + while (d[tx].link[1]) + tx = d[tx].link[1]; + d[tn].value = d[tx].value; /* move */ + raw = i_keyto(_i_keyref(&d[tn].value)); + d[tn].link[0] = _cx_memb(_erase_r_)(d, d[tn].link[0], &raw, erased); + } else { /* unlink node */ + tx = tn; + tn = d[tn].link[ d[tn].link[0] == 0 ]; + /* move it to disposed nodes list */ + struct csmap_rep *rep = c_unchecked_container_of(d, struct csmap_rep, nodes); + d[tx].link[1] = (i_size) rep->disp; + rep->disp = tx; + } + } + tx = d[tn].link[1]; + if (d[d[tn].link[0]].level < d[tn].level - 1 || d[tx].level < d[tn].level - 1) { + if (d[tx].level > --d[tn].level) + d[tx].level = d[tn].level; + tn = _cx_memb(_skew_)(d, tn); + tx = d[tn].link[1] = _cx_memb(_skew_)(d, d[tn].link[1]); + d[tx].link[1] = _cx_memb(_skew_)(d, d[tx].link[1]); + tn = _cx_memb(_split_)(d, tn); + d[tn].link[1] = _cx_memb(_split_)(d, d[tn].link[1]); + } + return tn; +} + +STC_DEF int +_cx_memb(_erase)(_cx_self* self, _cx_rawkey rkey) { + int erased = 0; + i_size root = _cx_memb(_erase_r_)(self->nodes, (i_size) _csmap_rep(self)->root, &rkey, &erased); + if (erased) { + _csmap_rep(self)->root = root; + --_csmap_rep(self)->size; + return 1; + } + return 0; +} + +STC_DEF _cx_iter +_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { + _cx_rawkey raw = i_keyto(_i_keyref(it.ref)), nxt; + _cx_memb(_next)(&it); + if (it.ref) + nxt = i_keyto(_i_keyref(it.ref)); + _cx_memb(_erase)(self, raw); + if (it.ref) + _cx_memb(_find_it)(self, nxt, &it); + return it; +} + +STC_DEF _cx_iter +_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { + if (!it2.ref) { + while (it1.ref) + it1 = _cx_memb(_erase_at)(self, it1); + return it1; + } + _cx_key k1 = *_i_keyref(it1.ref), k2 = *_i_keyref(it2.ref); + _cx_rawkey r1 = i_keyto((&k1)); + for (;;) { + if (memcmp(&k1, &k2, sizeof k1) == 0) + return it1; + _cx_memb(_next)(&it1); + k1 = *_i_keyref(it1.ref); + _cx_memb(_erase)(self, r1); + r1 = i_keyto((&k1)); + _cx_memb(_find_it)(self, r1, &it1); + } +} + +#if !defined _i_no_clone +static i_size +_cx_memb(_clone_r_)(_cx_self* self, _cx_node* src, i_size sn) { + if (sn == 0) + return 0; + i_size tx, tn = _cx_memb(_new_node_)(self, src[sn].level); + self->nodes[tn].value = _cx_memb(_value_clone)(src[sn].value); + tx = _cx_memb(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx; + tx = _cx_memb(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx; + return tn; +} + +STC_DEF _cx_self +_cx_memb(_clone)(_cx_self tree) { + _cx_self clone = _cx_memb(_with_capacity)(_csmap_rep(&tree)->size); + i_size root = _cx_memb(_clone_r_)(&clone, tree.nodes, (i_size) _csmap_rep(&tree)->root); + _csmap_rep(&clone)->root = root; + _csmap_rep(&clone)->size = _csmap_rep(&tree)->size; + return clone; +} + +#if !defined _i_no_emplace +STC_DEF _cx_result +_cx_memb(_emplace)(_cx_self* self, _cx_rawkey rkey _i_MAP_ONLY(, i_valraw rmapped)) { + _cx_result res = _cx_memb(_insert_entry_)(self, rkey); + if (res.inserted) { + *_i_keyref(res.ref) = i_keyfrom(rkey); + _i_MAP_ONLY(res.ref->second = i_valfrom(rmapped);) + } + return res; +} +#endif // _i_no_emplace +#endif // !_i_no_clone + +static void +_cx_memb(_drop_r_)(_cx_node* d, i_size tn) { + if (tn) { + _cx_memb(_drop_r_)(d, d[tn].link[0]); + _cx_memb(_drop_r_)(d, d[tn].link[1]); + _cx_memb(_value_drop)(&d[tn].value); + } +} + +STC_DEF void +_cx_memb(_drop)(_cx_self* self) { + struct csmap_rep* rep = _csmap_rep(self); + // second test is bogus, but supresses gcc warning: + if (rep->cap && rep != &_csmap_sentinel) { + _cx_memb(_drop_r_)(self->nodes, (i_size) rep->root); + c_free(rep); // correct, but may give warning + } +} + +#endif // i_implement +#undef _i_isset +#undef _i_ismap +#undef _i_keyref +#undef _i_MAP_ONLY +#undef _i_SET_ONLY +#define CSMAP_H_INCLUDED +#include "template.h" +#endif // !STC_CSMAP_V1 diff --git a/include/stc/csset.h b/include/stc/csset.h index 6fb29845..753ed063 100644 --- a/include/stc/csset.h +++ b/include/stc/csset.h @@ -1,49 +1,49 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-// Sorted set - implemented as an AA-tree (balanced binary tree).
-/*
-#include <stdio.h>
-
-#define i_tag i
-#define i_key int
-#include <stc/csset.h> // sorted set of int
-
-int main(void) {
- csset_i s = csset_i_init();
- csset_i_insert(&s, 5);
- csset_i_insert(&s, 8);
- csset_i_insert(&s, 3);
- csset_i_insert(&s, 5);
-
- c_foreach (k, csset_i, s)
- printf("set %d\n", *k.ref);
- csset_i_drop(&s);
-}
-*/
-
-#ifndef _i_prefix
-#define _i_prefix csset_
-#endif
-#define _i_isset
-#include "csmap.h"
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// Sorted set - implemented as an AA-tree (balanced binary tree). +/* +#include <stdio.h> + +#define i_tag i +#define i_key int +#include <stc/csset.h> // sorted set of int + +int main(void) { + csset_i s = csset_i_init(); + csset_i_insert(&s, 5); + csset_i_insert(&s, 8); + csset_i_insert(&s, 3); + csset_i_insert(&s, 5); + + c_foreach (k, csset_i, s) + printf("set %d\n", *k.ref); + csset_i_drop(&s); +} +*/ + +#ifndef _i_prefix +#define _i_prefix csset_ +#endif +#define _i_isset +#include "csmap.h" diff --git a/include/stc/cstack.h b/include/stc/cstack.h index 61d69f0c..52137d33 100644 --- a/include/stc/cstack.h +++ b/include/stc/cstack.h @@ -1,150 +1,150 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include "ccommon.h"
-
-#ifndef CSTACK_H_INCLUDED
-#define CSTACK_H_INCLUDED
-#include <stdlib.h>
-#include "forward.h"
-#endif // CSTACK_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix cstack_
-#endif
-#include "template.h"
-
-#if !c_option(c_is_fwd)
-_cx_deftypes(_c_cstack_types, _cx_self, i_key);
-#endif
-typedef i_keyraw _cx_raw;
-
-STC_INLINE _cx_self _cx_memb(_init)(void)
- { return c_make(_cx_self){0, 0, 0}; }
-
-STC_INLINE _cx_self _cx_memb(_with_capacity)(size_t cap) {
- _cx_self out = {(_cx_value *) c_malloc(cap*sizeof(i_key)), 0, cap};
- return out;
-}
-
-STC_INLINE _cx_self _cx_memb(_with_size)(size_t size, i_key null) {
- _cx_self out = {(_cx_value *) c_malloc(size*sizeof null), size, size};
- while (size) out.data[--size] = null;
- return out;
-}
-
-STC_INLINE void _cx_memb(_clear)(_cx_self* self) {
- _cx_value *p = self->data + self->size;
- while (p-- != self->data) { i_keydrop(p); }
- self->size = 0;
-}
-
-STC_INLINE void _cx_memb(_drop)(_cx_self* self)
- { _cx_memb(_clear)(self); c_free(self->data); }
-
-STC_INLINE size_t _cx_memb(_size)(_cx_self v)
- { return v.size; }
-
-STC_INLINE bool _cx_memb(_empty)(_cx_self v)
- { return !v.size; }
-
-STC_INLINE size_t _cx_memb(_capacity)(_cx_self v)
- { return v.capacity; }
-
-STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, size_t n) {
- if (n < self->size) return true;
- _cx_value *t = (_cx_value *)c_realloc(self->data, n*sizeof *t);
- if (t) { self->capacity = n, self->data = t; return true; }
- return false;
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_expand_uninit)(_cx_self *self, size_t n) {
- size_t len = self->size;
- if (!_cx_memb(_reserve)(self, len + n)) return NULL;
- self->size += n;
- return self->data + len;
-}
-
-STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self)
- { _cx_memb(_reserve)(self, self->size); }
-
-STC_INLINE _cx_value* _cx_memb(_top)(const _cx_self* self)
- { return &self->data[self->size - 1]; }
-
-STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value val) {
- if (self->size == self->capacity)
- if (!_cx_memb(_reserve)(self, self->size*3/2 + 4))
- return NULL;
- _cx_value* vp = self->data + self->size++;
- *vp = val; return vp;
-}
-STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, _cx_value val)
- { return _cx_memb(_push)(self, val); }
-
-STC_INLINE void _cx_memb(_pop)(_cx_self* self)
- { _cx_value* p = &self->data[--self->size]; i_keydrop(p); }
-STC_INLINE void _cx_memb(_pop_back)(_cx_self* self)
- { _cx_memb(_pop)(self); }
-
-STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, size_t idx)
- { assert(idx < self->size); return self->data + idx; }
-STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, size_t idx)
- { assert(idx < self->size); return self->data + idx; }
-
-#if !defined _i_no_clone
-#if !defined _i_no_emplace
-STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-#endif // !_i_no_emplace
-
-STC_INLINE _cx_self _cx_memb(_clone)(_cx_self v) {
- _cx_self out = {(_cx_value *) c_malloc(v.size*sizeof(_cx_value)), v.size, v.size};
- if (!out.data) out.capacity = 0;
- else for (size_t i = 0; i < v.size; ++v.data)
- out.data[i++] = i_keyclone((*v.data));
- return out;
-}
-
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->data == other.data) return;
- _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other);
-}
-
-STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val)
- { return i_keyclone(val); }
-
-STC_INLINE i_keyraw _cx_memb(_value_toraw)(_cx_value* val)
- { return i_keyto(val); }
-#endif // !_i_no_clone
-
-STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self)
- { return c_make(_cx_iter){self->data}; }
-STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
- { return c_make(_cx_iter){self->data + self->size}; }
-STC_INLINE void _cx_memb(_next)(_cx_iter* it) { ++it->ref; }
-STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t offs)
- { it.ref += offs; return it; }
-
-#include "template.h"
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "ccommon.h" + +#ifndef CSTACK_H_INCLUDED +#define CSTACK_H_INCLUDED +#include <stdlib.h> +#include "forward.h" +#endif // CSTACK_H_INCLUDED + +#ifndef _i_prefix +#define _i_prefix cstack_ +#endif +#include "template.h" + +#if !c_option(c_is_fwd) +_cx_deftypes(_c_cstack_types, _cx_self, i_key); +#endif +typedef i_keyraw _cx_raw; + +STC_INLINE _cx_self _cx_memb(_init)(void) + { return c_make(_cx_self){0, 0, 0}; } + +STC_INLINE _cx_self _cx_memb(_with_capacity)(size_t cap) { + _cx_self out = {(_cx_value *) c_malloc(cap*sizeof(i_key)), 0, cap}; + return out; +} + +STC_INLINE _cx_self _cx_memb(_with_size)(size_t size, i_key null) { + _cx_self out = {(_cx_value *) c_malloc(size*sizeof null), size, size}; + while (size) out.data[--size] = null; + return out; +} + +STC_INLINE void _cx_memb(_clear)(_cx_self* self) { + _cx_value *p = self->data + self->size; + while (p-- != self->data) { i_keydrop(p); } + self->size = 0; +} + +STC_INLINE void _cx_memb(_drop)(_cx_self* self) + { _cx_memb(_clear)(self); c_free(self->data); } + +STC_INLINE size_t _cx_memb(_size)(_cx_self v) + { return v.size; } + +STC_INLINE bool _cx_memb(_empty)(_cx_self v) + { return !v.size; } + +STC_INLINE size_t _cx_memb(_capacity)(_cx_self v) + { return v.capacity; } + +STC_INLINE bool _cx_memb(_reserve)(_cx_self* self, size_t n) { + if (n < self->size) return true; + _cx_value *t = (_cx_value *)c_realloc(self->data, n*sizeof *t); + if (t) { self->capacity = n, self->data = t; return true; } + return false; +} + +STC_INLINE _cx_value* +_cx_memb(_expand_uninit)(_cx_self *self, size_t n) { + size_t len = self->size; + if (!_cx_memb(_reserve)(self, len + n)) return NULL; + self->size += n; + return self->data + len; +} + +STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) + { _cx_memb(_reserve)(self, self->size); } + +STC_INLINE _cx_value* _cx_memb(_top)(const _cx_self* self) + { return &self->data[self->size - 1]; } + +STC_INLINE _cx_value* _cx_memb(_push)(_cx_self* self, _cx_value val) { + if (self->size == self->capacity) + if (!_cx_memb(_reserve)(self, self->size*3/2 + 4)) + return NULL; + _cx_value* vp = self->data + self->size++; + *vp = val; return vp; +} +STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, _cx_value val) + { return _cx_memb(_push)(self, val); } + +STC_INLINE void _cx_memb(_pop)(_cx_self* self) + { _cx_value* p = &self->data[--self->size]; i_keydrop(p); } +STC_INLINE void _cx_memb(_pop_back)(_cx_self* self) + { _cx_memb(_pop)(self); } + +STC_INLINE const _cx_value* _cx_memb(_at)(const _cx_self* self, size_t idx) + { assert(idx < self->size); return self->data + idx; } +STC_INLINE _cx_value* _cx_memb(_at_mut)(_cx_self* self, size_t idx) + { assert(idx < self->size); return self->data + idx; } + +#if !defined _i_no_clone +#if !defined _i_no_emplace +STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) + { return _cx_memb(_push)(self, i_keyfrom(raw)); } +STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) + { return _cx_memb(_push)(self, i_keyfrom(raw)); } +#endif // !_i_no_emplace + +STC_INLINE _cx_self _cx_memb(_clone)(_cx_self v) { + _cx_self out = {(_cx_value *) c_malloc(v.size*sizeof(_cx_value)), v.size, v.size}; + if (!out.data) out.capacity = 0; + else for (size_t i = 0; i < v.size; ++v.data) + out.data[i++] = i_keyclone((*v.data)); + return out; +} + +STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) { + if (self->data == other.data) return; + _cx_memb(_drop)(self); *self = _cx_memb(_clone)(other); +} + +STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val) + { return i_keyclone(val); } + +STC_INLINE i_keyraw _cx_memb(_value_toraw)(_cx_value* val) + { return i_keyto(val); } +#endif // !_i_no_clone + +STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) + { return c_make(_cx_iter){self->data}; } +STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) + { return c_make(_cx_iter){self->data + self->size}; } +STC_INLINE void _cx_memb(_next)(_cx_iter* it) { ++it->ref; } +STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t offs) + { it.ref += offs; return it; } + +#include "template.h" diff --git a/include/stc/cstr.h b/include/stc/cstr.h index 7dabd0c0..b33faf43 100644 --- a/include/stc/cstr.h +++ b/include/stc/cstr.h @@ -1,555 +1,555 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/* A string type with short string optimization in C99 with optimal short string
- * utilization (23 characters with 24 bytes string representation).
- */
-#ifdef STC_CSTR_V1
-#include "alt/cstr.h"
-#else
-#ifndef CSTR_H_INCLUDED
-#define CSTR_H_INCLUDED
-
-#define i_header
-#include "ccommon.h"
-#include "forward.h"
-#include "utf8.h"
-#include <stdlib.h> /* malloc */
-#include <stdarg.h>
-#include <stdio.h> /* vsnprintf */
-#include <ctype.h>
-
-/**************************** PRIVATE API **********************************/
-
-#if defined __GNUC__ && !defined __clang__
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Warray-bounds"
-# pragma GCC diagnostic ignored "-Wstringop-overflow="
-#endif
-
-enum { cstr_s_cap = sizeof(cstr_buf) - 1 };
-#define cstr_s_size(s) ((size_t)(cstr_s_cap - (s)->sml.last))
-#define cstr_s_set_size(s, len) ((s)->sml.last = cstr_s_cap - (len), (s)->sml.data[len] = 0)
-#define cstr_s_data(s) (s)->sml.data
-#define cstr_s_end(s) ((s)->sml.data + cstr_s_size(s))
-
-#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
- #define byte_rotl_(x, b) ((x) << (b)*8 | (x) >> (sizeof(x) - (b))*8)
- #define cstr_l_cap(s) (~byte_rotl_((s)->lon.ncap, sizeof((s)->lon.ncap) - 1))
- #define cstr_l_set_cap(s, cap) ((s)->lon.ncap = ~byte_rotl_(cap, 1))
-#else
- #define cstr_l_cap(s) (~(s)->lon.ncap)
- #define cstr_l_set_cap(s, cap) ((s)->lon.ncap = ~(cap))
-#endif
-#define cstr_l_size(s) ((s)->lon.size)
-#define cstr_l_set_size(s, len) ((s)->lon.data[(s)->lon.size = (len)] = 0)
-#define cstr_l_data(s) (s)->lon.data
-#define cstr_l_end(s) ((s)->lon.data + cstr_l_size(s))
-#define cstr_l_drop(s) c_free((s)->lon.data)
-
-#define cstr_is_long(s) ((s)->sml.last > 127)
-STC_API char* _cstr_init(cstr* self, size_t len, size_t cap);
-STC_API char* _cstr_internal_move(cstr* self, size_t pos1, size_t pos2);
-
-/**************************** PUBLIC API **********************************/
-
-#define cstr_new(literal) cstr_from_n(literal, c_strlen_lit(literal))
-#define cstr_npos (SIZE_MAX >> 1)
-#define cstr_null (c_make(cstr){.sml = {.last = cstr_s_cap}})
-#define cstr_toraw(self) cstr_str(self)
-
-STC_API char* cstr_reserve(cstr* self, size_t cap);
-STC_API void cstr_shrink_to_fit(cstr* self);
-STC_API void cstr_resize(cstr* self, size_t size, char value);
-STC_API size_t cstr_find_from(cstr s, size_t pos, const char* search);
-STC_API char* cstr_assign_n(cstr* self, const char* str, size_t n);
-STC_API char* cstr_append_n(cstr* self, const char* str, size_t n);
-STC_API bool cstr_getdelim(cstr *self, int delim, FILE *fp);
-STC_API void cstr_erase_n(cstr* self, size_t pos, size_t n);
-STC_API cstr cstr_from_fmt(const char* fmt, ...);
-STC_API int cstr_printf(cstr* self, const char* fmt, ...);
-STC_API void cstr_replace_all(cstr* self, const char* search, const char* repl);
-
-STC_INLINE cstr_buf cstr_buffer(cstr* s) {
- return cstr_is_long(s)
- ? c_make(cstr_buf){s->lon.data, cstr_l_size(s), cstr_l_cap(s)}
- : c_make(cstr_buf){s->sml.data, cstr_s_size(s), cstr_s_cap};
-}
-STC_INLINE csview cstr_sv(const cstr* s) {
- return cstr_is_long(s) ? c_make(csview){s->lon.data, cstr_l_size(s)}
- : c_make(csview){s->sml.data, cstr_s_size(s)};
-}
-
-STC_INLINE cstr cstr_init(void)
- { return cstr_null; }
-
-STC_INLINE cstr cstr_from_n(const char* str, const size_t n) {
- cstr s;
- memcpy(_cstr_init(&s, n, n), str, n);
- return s;
-}
-
-STC_INLINE cstr cstr_from(const char* str)
- { return cstr_from_n(str, strlen(str)); }
-
-STC_INLINE cstr cstr_with_size(const size_t size, const char value) {
- cstr s;
- memset(_cstr_init(&s, size, size), value, size);
- return s;
-}
-
-STC_INLINE cstr cstr_with_capacity(const size_t cap) {
- cstr s;
- _cstr_init(&s, 0, cap);
- return s;
-}
-
-STC_INLINE cstr* cstr_take(cstr* self, const cstr s) {
- if (cstr_is_long(self) && self->lon.data != s.lon.data)
- cstr_l_drop(self);
- *self = s;
- return self;
-}
-
-STC_INLINE cstr cstr_move(cstr* self) {
- cstr tmp = *self;
- *self = cstr_null;
- return tmp;
-}
-
-STC_INLINE cstr cstr_clone(cstr s) {
- csview sv = cstr_sv(&s);
- return cstr_from_n(sv.str, sv.size);
-}
-
-STC_INLINE void cstr_drop(cstr* self) {
- if (cstr_is_long(self))
- cstr_l_drop(self);
-}
-
-#define SSO_CALL(s, call) (cstr_is_long(s) ? cstr_l_##call : cstr_s_##call)
-
-STC_INLINE void _cstr_set_size(cstr* self, size_t len)
- { SSO_CALL(self, set_size(self, len)); }
-
-STC_INLINE char* cstr_data(cstr* self)
- { return SSO_CALL(self, data(self)); }
-
-STC_INLINE const char* cstr_str(const cstr* self)
- { return SSO_CALL(self, data(self)); }
-
-STC_INLINE bool cstr_empty(cstr s)
- { return s.sml.last == cstr_s_cap; }
-
-STC_INLINE size_t cstr_size(cstr s)
- { return SSO_CALL(&s, size(&s)); }
-
-STC_INLINE size_t cstr_length(cstr s)
- { return SSO_CALL(&s, size(&s)); }
-
-STC_INLINE size_t cstr_capacity(cstr s)
- { return cstr_is_long(&s) ? cstr_l_cap(&s) : cstr_s_cap; }
-
-// utf8 methods defined in/depending on src/utf8code.c:
-
-extern cstr cstr_tolower(const cstr* self);
-extern cstr cstr_toupper(const cstr* self);
-extern void cstr_lowercase(cstr* self);
-extern void cstr_uppercase(cstr* self);
-
-STC_INLINE bool cstr_valid_u8(const cstr* self)
- { return utf8_valid(cstr_str(self)); }
-
-// other utf8
-
-STC_INLINE size_t cstr_size_u8(cstr s)
- { return utf8_size(cstr_str(&s)); }
-
-STC_INLINE size_t cstr_size_n_u8(cstr s, size_t nbytes)
- { return utf8_size_n(cstr_str(&s), nbytes); }
-
-STC_INLINE csview cstr_at(const cstr* self, size_t bytepos) {
- csview sv = cstr_sv(self);
- sv.str += bytepos;
- sv.size = utf8_codep_size(sv.str);
- return sv;
-}
-
-STC_INLINE csview cstr_at_u8(const cstr* self, size_t u8idx) {
- csview sv = cstr_sv(self);
- sv.str = utf8_at(sv.str, u8idx);
- sv.size = utf8_codep_size(sv.str);
- return sv;
-}
-
-STC_INLINE size_t cstr_pos_u8(const cstr* self, size_t u8idx)
- { return utf8_pos(cstr_str(self), u8idx); }
-
-// utf8 iterator
-
-STC_INLINE cstr_iter cstr_begin(const cstr* self) {
- const char* str = cstr_str(self);
- return c_make(cstr_iter){.chr = {str, utf8_codep_size(str)}};
-}
-STC_INLINE cstr_iter cstr_end(const cstr* self) {
- csview sv = cstr_sv(self);
- return c_make(cstr_iter){sv.str + sv.size};
-}
-STC_INLINE void cstr_next(cstr_iter* it) {
- it->ref += it->chr.size;
- it->chr.size = utf8_codep_size(it->ref);
-}
-
-
-STC_INLINE void cstr_clear(cstr* self)
- { _cstr_set_size(self, 0); }
-
-STC_INLINE char* cstr_expand_uninit(cstr *self, size_t n) {
- size_t len = cstr_size(*self); char* d;
- if (!(d = cstr_reserve(self, len + n))) return NULL;
- _cstr_set_size(self, len + n);
- return d + len;
-}
-
-STC_INLINE int cstr_cmp(const cstr* s1, const cstr* s2)
- { return strcmp(cstr_str(s1), cstr_str(s2)); }
-
-STC_INLINE int cstr_icmp(const cstr* s1, const cstr* s2)
- { return utf8_icmp(cstr_str(s1), cstr_str(s2)); }
-
-STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) {
- csview x = cstr_sv(s1), y = cstr_sv(s2);
- return x.size == y.size && !memcmp(x.str, y.str, x.size);
-}
-
-STC_INLINE bool cstr_equals(cstr s1, const char* str)
- { return !strcmp(cstr_str(&s1), str); }
-
-STC_INLINE bool cstr_iequals(cstr s1, const char* str)
- { return !utf8_icmp(cstr_str(&s1), str); }
-
-STC_INLINE bool cstr_equals_s(cstr s1, cstr s2)
- { return !cstr_cmp(&s1, &s2); }
-
-STC_INLINE size_t cstr_find(cstr s, const char* search) {
- const char *str = cstr_str(&s), *res = strstr((char*)str, search);
- return res ? res - str : cstr_npos;
-}
-
-STC_INLINE size_t cstr_find_s(cstr s, cstr search)
- { return cstr_find(s, cstr_str(&search)); }
-
-STC_INLINE bool cstr_contains(cstr s, const char* search)
- { return strstr(cstr_data(&s), search) != NULL; }
-
-STC_INLINE bool cstr_contains_s(cstr s, cstr search)
- { return strstr(cstr_data(&s), cstr_str(&search)) != NULL; }
-
-STC_INLINE bool cstr_starts_with(cstr s, const char* sub) {
- const char* str = cstr_str(&s);
- while (*sub && *str == *sub) ++str, ++sub;
- return !*sub;
-}
-STC_INLINE bool cstr_istarts_with(cstr s, const char* sub) {
- csview sv = cstr_sv(&s);
- size_t n = strlen(sub);
- return n <= sv.size && !utf8_icmp_n(cstr_npos, sv.str, sv.size, sub, n);
-}
-
-STC_INLINE bool cstr_starts_with_s(cstr s, cstr sub)
- { return cstr_starts_with(s, cstr_str(&sub)); }
-
-STC_INLINE bool cstr_ends_with(cstr s, const char* sub) {
- csview sv = cstr_sv(&s);
- size_t n = strlen(sub);
- return n <= sv.size && !memcmp(sv.str + sv.size - n, sub, n);
-}
-
-STC_INLINE bool cstr_iends_with(cstr s, const char* sub) {
- csview sv = cstr_sv(&s);
- size_t n = strlen(sub);
- return n <= sv.size && !utf8_icmp(sv.str + sv.size - n, sub);
-}
-
-STC_INLINE bool cstr_ends_with_s(cstr s, cstr sub)
- { return cstr_ends_with(s, cstr_str(&sub)); }
-
-STC_INLINE char* cstr_assign(cstr* self, const char* str)
- { return cstr_assign_n(self, str, strlen(str)); }
-
-STC_INLINE char* cstr_assign_s(cstr* self, cstr s) {
- csview sv = cstr_sv(&s);
- return cstr_assign_n(self, sv.str, sv.size);
-}
-
-STC_INLINE void cstr_copy(cstr* self, cstr s)
- { cstr_assign_s(self, s); }
-
-STC_INLINE char* cstr_append(cstr* self, const char* str)
- { return cstr_append_n(self, str, strlen(str)); }
-
-STC_INLINE char* cstr_append_s(cstr* self, cstr s) {
- csview sv = cstr_sv(&s);
- return cstr_append_n(self, sv.str, sv.size);
-}
-
-STC_INLINE void cstr_replace_n(cstr* self, size_t pos, size_t len, const char* repl, size_t n) {
- char* d = _cstr_internal_move(self, pos + len, pos + n);
- memcpy(d + pos, repl, n);
-}
-
-STC_INLINE void cstr_replace(cstr* self, size_t pos, size_t len, const char* repl)
- { cstr_replace_n(self, pos, len, repl, strlen(repl)); }
-
-STC_INLINE size_t cstr_replace_one(cstr* self, size_t pos, const char* search, const char* repl) {
- pos = cstr_find_from(*self, pos, search);
- if (pos == cstr_npos)
- return pos;
- const size_t rlen = strlen(repl);
- cstr_replace_n(self, pos, strlen(search), repl, rlen);
- return pos + rlen;
-}
-
-STC_INLINE void cstr_replace_s(cstr* self, size_t pos, size_t len, cstr s) {
- csview sv = cstr_sv(&s);
- cstr_replace_n(self, pos, len, sv.str, sv.size);
-}
-
-STC_INLINE void cstr_insert_n(cstr* self, size_t pos, const char* str, size_t n)
- { cstr_replace_n(self, pos, 0, str, n); }
-
-STC_INLINE void cstr_insert(cstr* self, size_t pos, const char* str)
- { cstr_replace_n(self, pos, 0, str, strlen(str)); }
-
-STC_INLINE void cstr_insert_s(cstr* self, size_t pos, cstr s) {
- csview sv = cstr_sv(&s);
- cstr_replace_n(self, pos, 0, sv.str, sv.size);
-}
-
-STC_INLINE bool cstr_getline(cstr *self, FILE *fp)
- { return cstr_getdelim(self, '\n', fp); }
-
-STC_INLINE uint64_t cstr_hash(const cstr *self) {
- csview sv = cstr_sv(self);
- return c_fasthash(sv.str, sv.size);
-}
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-STC_DEF char* _cstr_internal_move(cstr* self, const size_t pos1, const size_t pos2) {
- cstr_buf r = cstr_buffer(self);
- if (pos1 != pos2) {
- const size_t newlen = r.size + pos2 - pos1;
- if (newlen > r.cap)
- r.data = cstr_reserve(self, (r.size*3 >> 1) + pos2 - pos1);
- memmove(&r.data[pos2], &r.data[pos1], r.size - pos1);
- _cstr_set_size(self, newlen);
- }
- return r.data;
-}
-
-STC_DEF char* _cstr_init(cstr* self, const size_t len, const size_t cap) {
- if (cap > cstr_s_cap) {
- self->lon.data = (char *)c_malloc(cap + 1);
- cstr_l_set_size(self, len);
- cstr_l_set_cap(self, cap);
- return self->lon.data;
- }
- cstr_s_set_size(self, len);
- return self->sml.data;
-}
-
-STC_DEF void cstr_shrink_to_fit(cstr* self) {
- cstr_buf r = cstr_buffer(self);
- if (r.size == r.cap)
- return;
- if (r.size > cstr_s_cap) {
- self->lon.data = (char *)c_realloc(self->lon.data, r.size + 1);
- cstr_l_set_cap(self, r.size);
- } else if (r.cap > cstr_s_cap) {
- memcpy(self->sml.data, r.data, r.size + 1);
- cstr_s_set_size(self, r.size);
- c_free(r.data);
- }
-}
-
-STC_DEF char* cstr_reserve(cstr* self, const size_t cap) {
- if (cstr_is_long(self)) {
- if (cap > cstr_l_cap(self)) {
- self->lon.data = (char *)c_realloc(self->lon.data, cap + 1);
- cstr_l_set_cap(self, cap);
- }
- return self->lon.data;
- }
- /* from short to long: */
- if (cap > cstr_s_cap) {
- char* data = (char *)c_malloc(cap + 1);
- const size_t len = cstr_s_size(self);
- memcpy(data, self->sml.data, len);
- self->lon.data = data;
- cstr_l_set_size(self, len);
- cstr_l_set_cap(self, cap);
- return data;
- }
- return self->sml.data;
-}
-
-STC_DEF void cstr_resize(cstr* self, const size_t size, const char value) {
- cstr_buf r = cstr_buffer(self);
- if (size > r.size) {
- if (size > r.cap) r.data = cstr_reserve(self, size);
- memset(r.data + r.size, value, size - r.size);
- }
- _cstr_set_size(self, size);
-}
-
-STC_DEF size_t cstr_find_from(cstr s, const size_t pos, const char* search) {
- csview sv = cstr_sv(&s);
- if (pos > sv.size) return cstr_npos;
- const char* res = strstr((char*)sv.str + pos, search);
- return res ? res - sv.str : cstr_npos;
-}
-
-STC_DEF char* cstr_assign_n(cstr* self, const char* str, const size_t n) {
- char* d = cstr_reserve(self, n);
- memmove(d, str, n);
- _cstr_set_size(self, n);
- return d;
-}
-
-STC_DEF char* cstr_append_n(cstr* self, const char* str, const size_t n) {
- cstr_buf r = cstr_buffer(self);
- if (r.size + n > r.cap) {
- const size_t off = (size_t)(str - r.data);
- r.data = cstr_reserve(self, (r.size*3 >> 1) + n);
- if (off <= r.size) str = r.data + off; /* handle self append */
- }
- memcpy(r.data + r.size, str, n);
- _cstr_set_size(self, r.size + n);
- return r.data;
-}
-
-STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) {
- int c = fgetc(fp);
- if (c == EOF)
- return false;
- size_t pos = 0;
- cstr_buf r = cstr_buffer(self);
- for (;;) {
- if (c == delim || c == EOF) {
- _cstr_set_size(self, pos);
- return true;
- }
- if (pos == r.cap) {
- _cstr_set_size(self, pos);
- r.data = cstr_reserve(self, (r.cap = (r.cap*3 >> 1) + 16));
- }
- r.data[pos++] = (char) c;
- c = fgetc(fp);
- }
-}
-
-STC_DEF cstr
-cstr_from_replace_all(const char* str, const size_t str_len,
- const char* search, const size_t search_len,
- const char* repl, const size_t repl_len) {
- cstr out = cstr_null;
- size_t from = 0; char* res;
- if (search_len)
- while ((res = c_strnstrn(str + from, search, str_len - from, search_len))) {
- const size_t pos = res - str;
- cstr_append_n(&out, str + from, pos - from);
- cstr_append_n(&out, repl, repl_len);
- from = pos + search_len;
- }
- cstr_append_n(&out, str + from, str_len - from);
- return out;
-}
-
-STC_DEF void
-cstr_replace_all(cstr* self, const char* search, const char* repl) {
- csview sv = cstr_sv(self);
- cstr_take(self, cstr_from_replace_all(sv.str, sv.size, search, strlen(search),
- repl, strlen(repl)));
-}
-
-STC_DEF void cstr_erase_n(cstr* self, const size_t pos, size_t n) {
- cstr_buf r = cstr_buffer(self);
- if (n > r.size - pos) n = r.size - pos;
- memmove(&r.data[pos], &r.data[pos + n], r.size - (pos + n));
- _cstr_set_size(self, r.size - n);
-}
-
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wdeprecated-declarations"
-#elif defined(_MSC_VER)
-# pragma warning(push)
-# pragma warning(disable: 4996)
-#endif
-
-STC_DEF int cstr_vfmt(cstr* self, const char* fmt, va_list args) {
- va_list args2;
- va_copy(args2, args);
- const int n = vsnprintf(NULL, (size_t)0, fmt, args);
- cstr_reserve(self, n);
- vsprintf(cstr_data(self), fmt, args2);
- va_end(args2);
- _cstr_set_size(self, n);
- return n;
-}
-#if defined(__clang__)
-# pragma clang diagnostic pop
-#elif defined(_MSC_VER)
-# pragma warning(pop)
-#endif
-
-STC_DEF cstr cstr_from_fmt(const char* fmt, ...) {
- cstr s = cstr_null;
- va_list args; va_start(args, fmt);
- cstr_vfmt(&s, fmt, args);
- va_end(args);
- return s;
-}
-
-STC_DEF int cstr_printf(cstr* self, const char* fmt, ...) {
- cstr s = cstr_null;
- va_list args; va_start(args, fmt);
- const int n = cstr_vfmt(&s, fmt, args);
- va_end(args);
- cstr_drop(self); *self = s;
- return n;
-}
-
-#endif // i_implement
-#if defined __GNUC__ && !defined __clang__
-# pragma GCC diagnostic pop
-#endif
-#endif // CSTR_H_INCLUDED
-#undef i_opt
-#undef i_header
-#undef i_static
-#undef i_implement
-#undef i_extern
-#endif // !STC_CSTR_V1
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* A string type with short string optimization in C99 with optimal short string + * utilization (23 characters with 24 bytes string representation). + */ +#ifdef STC_CSTR_V1 +#include "alt/cstr.h" +#else +#ifndef CSTR_H_INCLUDED +#define CSTR_H_INCLUDED + +#define i_header +#include "ccommon.h" +#include "forward.h" +#include "utf8.h" +#include <stdlib.h> /* malloc */ +#include <stdarg.h> +#include <stdio.h> /* vsnprintf */ +#include <ctype.h> + +/**************************** PRIVATE API **********************************/ + +#if defined __GNUC__ && !defined __clang__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Warray-bounds" +# pragma GCC diagnostic ignored "-Wstringop-overflow=" +#endif + +enum { cstr_s_cap = sizeof(cstr_buf) - 1 }; +#define cstr_s_size(s) ((size_t)(cstr_s_cap - (s)->sml.last)) +#define cstr_s_set_size(s, len) ((s)->sml.last = cstr_s_cap - (len), (s)->sml.data[len] = 0) +#define cstr_s_data(s) (s)->sml.data +#define cstr_s_end(s) ((s)->sml.data + cstr_s_size(s)) + +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + #define byte_rotl_(x, b) ((x) << (b)*8 | (x) >> (sizeof(x) - (b))*8) + #define cstr_l_cap(s) (~byte_rotl_((s)->lon.ncap, sizeof((s)->lon.ncap) - 1)) + #define cstr_l_set_cap(s, cap) ((s)->lon.ncap = ~byte_rotl_(cap, 1)) +#else + #define cstr_l_cap(s) (~(s)->lon.ncap) + #define cstr_l_set_cap(s, cap) ((s)->lon.ncap = ~(cap)) +#endif +#define cstr_l_size(s) ((s)->lon.size) +#define cstr_l_set_size(s, len) ((s)->lon.data[(s)->lon.size = (len)] = 0) +#define cstr_l_data(s) (s)->lon.data +#define cstr_l_end(s) ((s)->lon.data + cstr_l_size(s)) +#define cstr_l_drop(s) c_free((s)->lon.data) + +#define cstr_is_long(s) ((s)->sml.last > 127) +STC_API char* _cstr_init(cstr* self, size_t len, size_t cap); +STC_API char* _cstr_internal_move(cstr* self, size_t pos1, size_t pos2); + +/**************************** PUBLIC API **********************************/ + +#define cstr_new(literal) cstr_from_n(literal, c_strlen_lit(literal)) +#define cstr_npos (SIZE_MAX >> 1) +#define cstr_null (c_make(cstr){.sml = {.last = cstr_s_cap}}) +#define cstr_toraw(self) cstr_str(self) + +STC_API char* cstr_reserve(cstr* self, size_t cap); +STC_API void cstr_shrink_to_fit(cstr* self); +STC_API void cstr_resize(cstr* self, size_t size, char value); +STC_API size_t cstr_find_from(cstr s, size_t pos, const char* search); +STC_API char* cstr_assign_n(cstr* self, const char* str, size_t n); +STC_API char* cstr_append_n(cstr* self, const char* str, size_t n); +STC_API bool cstr_getdelim(cstr *self, int delim, FILE *fp); +STC_API void cstr_erase_n(cstr* self, size_t pos, size_t n); +STC_API cstr cstr_from_fmt(const char* fmt, ...); +STC_API int cstr_printf(cstr* self, const char* fmt, ...); +STC_API void cstr_replace_all(cstr* self, const char* search, const char* repl); + +STC_INLINE cstr_buf cstr_buffer(cstr* s) { + return cstr_is_long(s) + ? c_make(cstr_buf){s->lon.data, cstr_l_size(s), cstr_l_cap(s)} + : c_make(cstr_buf){s->sml.data, cstr_s_size(s), cstr_s_cap}; +} +STC_INLINE csview cstr_sv(const cstr* s) { + return cstr_is_long(s) ? c_make(csview){s->lon.data, cstr_l_size(s)} + : c_make(csview){s->sml.data, cstr_s_size(s)}; +} + +STC_INLINE cstr cstr_init(void) + { return cstr_null; } + +STC_INLINE cstr cstr_from_n(const char* str, const size_t n) { + cstr s; + memcpy(_cstr_init(&s, n, n), str, n); + return s; +} + +STC_INLINE cstr cstr_from(const char* str) + { return cstr_from_n(str, strlen(str)); } + +STC_INLINE cstr cstr_with_size(const size_t size, const char value) { + cstr s; + memset(_cstr_init(&s, size, size), value, size); + return s; +} + +STC_INLINE cstr cstr_with_capacity(const size_t cap) { + cstr s; + _cstr_init(&s, 0, cap); + return s; +} + +STC_INLINE cstr* cstr_take(cstr* self, const cstr s) { + if (cstr_is_long(self) && self->lon.data != s.lon.data) + cstr_l_drop(self); + *self = s; + return self; +} + +STC_INLINE cstr cstr_move(cstr* self) { + cstr tmp = *self; + *self = cstr_null; + return tmp; +} + +STC_INLINE cstr cstr_clone(cstr s) { + csview sv = cstr_sv(&s); + return cstr_from_n(sv.str, sv.size); +} + +STC_INLINE void cstr_drop(cstr* self) { + if (cstr_is_long(self)) + cstr_l_drop(self); +} + +#define SSO_CALL(s, call) (cstr_is_long(s) ? cstr_l_##call : cstr_s_##call) + +STC_INLINE void _cstr_set_size(cstr* self, size_t len) + { SSO_CALL(self, set_size(self, len)); } + +STC_INLINE char* cstr_data(cstr* self) + { return SSO_CALL(self, data(self)); } + +STC_INLINE const char* cstr_str(const cstr* self) + { return SSO_CALL(self, data(self)); } + +STC_INLINE bool cstr_empty(cstr s) + { return s.sml.last == cstr_s_cap; } + +STC_INLINE size_t cstr_size(cstr s) + { return SSO_CALL(&s, size(&s)); } + +STC_INLINE size_t cstr_length(cstr s) + { return SSO_CALL(&s, size(&s)); } + +STC_INLINE size_t cstr_capacity(cstr s) + { return cstr_is_long(&s) ? cstr_l_cap(&s) : cstr_s_cap; } + +// utf8 methods defined in/depending on src/utf8code.c: + +extern cstr cstr_tolower(const cstr* self); +extern cstr cstr_toupper(const cstr* self); +extern void cstr_lowercase(cstr* self); +extern void cstr_uppercase(cstr* self); + +STC_INLINE bool cstr_valid_u8(const cstr* self) + { return utf8_valid(cstr_str(self)); } + +// other utf8 + +STC_INLINE size_t cstr_size_u8(cstr s) + { return utf8_size(cstr_str(&s)); } + +STC_INLINE size_t cstr_size_n_u8(cstr s, size_t nbytes) + { return utf8_size_n(cstr_str(&s), nbytes); } + +STC_INLINE csview cstr_at(const cstr* self, size_t bytepos) { + csview sv = cstr_sv(self); + sv.str += bytepos; + sv.size = utf8_codep_size(sv.str); + return sv; +} + +STC_INLINE csview cstr_at_u8(const cstr* self, size_t u8idx) { + csview sv = cstr_sv(self); + sv.str = utf8_at(sv.str, u8idx); + sv.size = utf8_codep_size(sv.str); + return sv; +} + +STC_INLINE size_t cstr_pos_u8(const cstr* self, size_t u8idx) + { return utf8_pos(cstr_str(self), u8idx); } + +// utf8 iterator + +STC_INLINE cstr_iter cstr_begin(const cstr* self) { + const char* str = cstr_str(self); + return c_make(cstr_iter){.chr = {str, utf8_codep_size(str)}}; +} +STC_INLINE cstr_iter cstr_end(const cstr* self) { + csview sv = cstr_sv(self); + return c_make(cstr_iter){sv.str + sv.size}; +} +STC_INLINE void cstr_next(cstr_iter* it) { + it->ref += it->chr.size; + it->chr.size = utf8_codep_size(it->ref); +} + + +STC_INLINE void cstr_clear(cstr* self) + { _cstr_set_size(self, 0); } + +STC_INLINE char* cstr_expand_uninit(cstr *self, size_t n) { + size_t len = cstr_size(*self); char* d; + if (!(d = cstr_reserve(self, len + n))) return NULL; + _cstr_set_size(self, len + n); + return d + len; +} + +STC_INLINE int cstr_cmp(const cstr* s1, const cstr* s2) + { return strcmp(cstr_str(s1), cstr_str(s2)); } + +STC_INLINE int cstr_icmp(const cstr* s1, const cstr* s2) + { return utf8_icmp(cstr_str(s1), cstr_str(s2)); } + +STC_INLINE bool cstr_eq(const cstr* s1, const cstr* s2) { + csview x = cstr_sv(s1), y = cstr_sv(s2); + return x.size == y.size && !memcmp(x.str, y.str, x.size); +} + +STC_INLINE bool cstr_equals(cstr s1, const char* str) + { return !strcmp(cstr_str(&s1), str); } + +STC_INLINE bool cstr_iequals(cstr s1, const char* str) + { return !utf8_icmp(cstr_str(&s1), str); } + +STC_INLINE bool cstr_equals_s(cstr s1, cstr s2) + { return !cstr_cmp(&s1, &s2); } + +STC_INLINE size_t cstr_find(cstr s, const char* search) { + const char *str = cstr_str(&s), *res = strstr((char*)str, search); + return res ? res - str : cstr_npos; +} + +STC_INLINE size_t cstr_find_s(cstr s, cstr search) + { return cstr_find(s, cstr_str(&search)); } + +STC_INLINE bool cstr_contains(cstr s, const char* search) + { return strstr(cstr_data(&s), search) != NULL; } + +STC_INLINE bool cstr_contains_s(cstr s, cstr search) + { return strstr(cstr_data(&s), cstr_str(&search)) != NULL; } + +STC_INLINE bool cstr_starts_with(cstr s, const char* sub) { + const char* str = cstr_str(&s); + while (*sub && *str == *sub) ++str, ++sub; + return !*sub; +} +STC_INLINE bool cstr_istarts_with(cstr s, const char* sub) { + csview sv = cstr_sv(&s); + size_t n = strlen(sub); + return n <= sv.size && !utf8_icmp_n(cstr_npos, sv.str, sv.size, sub, n); +} + +STC_INLINE bool cstr_starts_with_s(cstr s, cstr sub) + { return cstr_starts_with(s, cstr_str(&sub)); } + +STC_INLINE bool cstr_ends_with(cstr s, const char* sub) { + csview sv = cstr_sv(&s); + size_t n = strlen(sub); + return n <= sv.size && !memcmp(sv.str + sv.size - n, sub, n); +} + +STC_INLINE bool cstr_iends_with(cstr s, const char* sub) { + csview sv = cstr_sv(&s); + size_t n = strlen(sub); + return n <= sv.size && !utf8_icmp(sv.str + sv.size - n, sub); +} + +STC_INLINE bool cstr_ends_with_s(cstr s, cstr sub) + { return cstr_ends_with(s, cstr_str(&sub)); } + +STC_INLINE char* cstr_assign(cstr* self, const char* str) + { return cstr_assign_n(self, str, strlen(str)); } + +STC_INLINE char* cstr_assign_s(cstr* self, cstr s) { + csview sv = cstr_sv(&s); + return cstr_assign_n(self, sv.str, sv.size); +} + +STC_INLINE void cstr_copy(cstr* self, cstr s) + { cstr_assign_s(self, s); } + +STC_INLINE char* cstr_append(cstr* self, const char* str) + { return cstr_append_n(self, str, strlen(str)); } + +STC_INLINE char* cstr_append_s(cstr* self, cstr s) { + csview sv = cstr_sv(&s); + return cstr_append_n(self, sv.str, sv.size); +} + +STC_INLINE void cstr_replace_n(cstr* self, size_t pos, size_t len, const char* repl, size_t n) { + char* d = _cstr_internal_move(self, pos + len, pos + n); + memcpy(d + pos, repl, n); +} + +STC_INLINE void cstr_replace(cstr* self, size_t pos, size_t len, const char* repl) + { cstr_replace_n(self, pos, len, repl, strlen(repl)); } + +STC_INLINE size_t cstr_replace_one(cstr* self, size_t pos, const char* search, const char* repl) { + pos = cstr_find_from(*self, pos, search); + if (pos == cstr_npos) + return pos; + const size_t rlen = strlen(repl); + cstr_replace_n(self, pos, strlen(search), repl, rlen); + return pos + rlen; +} + +STC_INLINE void cstr_replace_s(cstr* self, size_t pos, size_t len, cstr s) { + csview sv = cstr_sv(&s); + cstr_replace_n(self, pos, len, sv.str, sv.size); +} + +STC_INLINE void cstr_insert_n(cstr* self, size_t pos, const char* str, size_t n) + { cstr_replace_n(self, pos, 0, str, n); } + +STC_INLINE void cstr_insert(cstr* self, size_t pos, const char* str) + { cstr_replace_n(self, pos, 0, str, strlen(str)); } + +STC_INLINE void cstr_insert_s(cstr* self, size_t pos, cstr s) { + csview sv = cstr_sv(&s); + cstr_replace_n(self, pos, 0, sv.str, sv.size); +} + +STC_INLINE bool cstr_getline(cstr *self, FILE *fp) + { return cstr_getdelim(self, '\n', fp); } + +STC_INLINE uint64_t cstr_hash(const cstr *self) { + csview sv = cstr_sv(self); + return c_fasthash(sv.str, sv.size); +} + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) + +STC_DEF char* _cstr_internal_move(cstr* self, const size_t pos1, const size_t pos2) { + cstr_buf r = cstr_buffer(self); + if (pos1 != pos2) { + const size_t newlen = r.size + pos2 - pos1; + if (newlen > r.cap) + r.data = cstr_reserve(self, (r.size*3 >> 1) + pos2 - pos1); + memmove(&r.data[pos2], &r.data[pos1], r.size - pos1); + _cstr_set_size(self, newlen); + } + return r.data; +} + +STC_DEF char* _cstr_init(cstr* self, const size_t len, const size_t cap) { + if (cap > cstr_s_cap) { + self->lon.data = (char *)c_malloc(cap + 1); + cstr_l_set_size(self, len); + cstr_l_set_cap(self, cap); + return self->lon.data; + } + cstr_s_set_size(self, len); + return self->sml.data; +} + +STC_DEF void cstr_shrink_to_fit(cstr* self) { + cstr_buf r = cstr_buffer(self); + if (r.size == r.cap) + return; + if (r.size > cstr_s_cap) { + self->lon.data = (char *)c_realloc(self->lon.data, r.size + 1); + cstr_l_set_cap(self, r.size); + } else if (r.cap > cstr_s_cap) { + memcpy(self->sml.data, r.data, r.size + 1); + cstr_s_set_size(self, r.size); + c_free(r.data); + } +} + +STC_DEF char* cstr_reserve(cstr* self, const size_t cap) { + if (cstr_is_long(self)) { + if (cap > cstr_l_cap(self)) { + self->lon.data = (char *)c_realloc(self->lon.data, cap + 1); + cstr_l_set_cap(self, cap); + } + return self->lon.data; + } + /* from short to long: */ + if (cap > cstr_s_cap) { + char* data = (char *)c_malloc(cap + 1); + const size_t len = cstr_s_size(self); + memcpy(data, self->sml.data, len); + self->lon.data = data; + cstr_l_set_size(self, len); + cstr_l_set_cap(self, cap); + return data; + } + return self->sml.data; +} + +STC_DEF void cstr_resize(cstr* self, const size_t size, const char value) { + cstr_buf r = cstr_buffer(self); + if (size > r.size) { + if (size > r.cap) r.data = cstr_reserve(self, size); + memset(r.data + r.size, value, size - r.size); + } + _cstr_set_size(self, size); +} + +STC_DEF size_t cstr_find_from(cstr s, const size_t pos, const char* search) { + csview sv = cstr_sv(&s); + if (pos > sv.size) return cstr_npos; + const char* res = strstr((char*)sv.str + pos, search); + return res ? res - sv.str : cstr_npos; +} + +STC_DEF char* cstr_assign_n(cstr* self, const char* str, const size_t n) { + char* d = cstr_reserve(self, n); + memmove(d, str, n); + _cstr_set_size(self, n); + return d; +} + +STC_DEF char* cstr_append_n(cstr* self, const char* str, const size_t n) { + cstr_buf r = cstr_buffer(self); + if (r.size + n > r.cap) { + const size_t off = (size_t)(str - r.data); + r.data = cstr_reserve(self, (r.size*3 >> 1) + n); + if (off <= r.size) str = r.data + off; /* handle self append */ + } + memcpy(r.data + r.size, str, n); + _cstr_set_size(self, r.size + n); + return r.data; +} + +STC_DEF bool cstr_getdelim(cstr *self, const int delim, FILE *fp) { + int c = fgetc(fp); + if (c == EOF) + return false; + size_t pos = 0; + cstr_buf r = cstr_buffer(self); + for (;;) { + if (c == delim || c == EOF) { + _cstr_set_size(self, pos); + return true; + } + if (pos == r.cap) { + _cstr_set_size(self, pos); + r.data = cstr_reserve(self, (r.cap = (r.cap*3 >> 1) + 16)); + } + r.data[pos++] = (char) c; + c = fgetc(fp); + } +} + +STC_DEF cstr +cstr_from_replace_all(const char* str, const size_t str_len, + const char* search, const size_t search_len, + const char* repl, const size_t repl_len) { + cstr out = cstr_null; + size_t from = 0; char* res; + if (search_len) + while ((res = c_strnstrn(str + from, search, str_len - from, search_len))) { + const size_t pos = res - str; + cstr_append_n(&out, str + from, pos - from); + cstr_append_n(&out, repl, repl_len); + from = pos + search_len; + } + cstr_append_n(&out, str + from, str_len - from); + return out; +} + +STC_DEF void +cstr_replace_all(cstr* self, const char* search, const char* repl) { + csview sv = cstr_sv(self); + cstr_take(self, cstr_from_replace_all(sv.str, sv.size, search, strlen(search), + repl, strlen(repl))); +} + +STC_DEF void cstr_erase_n(cstr* self, const size_t pos, size_t n) { + cstr_buf r = cstr_buffer(self); + if (n > r.size - pos) n = r.size - pos; + memmove(&r.data[pos], &r.data[pos + n], r.size - (pos + n)); + _cstr_set_size(self, r.size - n); +} + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4996) +#endif + +STC_DEF int cstr_vfmt(cstr* self, const char* fmt, va_list args) { + va_list args2; + va_copy(args2, args); + const int n = vsnprintf(NULL, (size_t)0, fmt, args); + cstr_reserve(self, n); + vsprintf(cstr_data(self), fmt, args2); + va_end(args2); + _cstr_set_size(self, n); + return n; +} +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif + +STC_DEF cstr cstr_from_fmt(const char* fmt, ...) { + cstr s = cstr_null; + va_list args; va_start(args, fmt); + cstr_vfmt(&s, fmt, args); + va_end(args); + return s; +} + +STC_DEF int cstr_printf(cstr* self, const char* fmt, ...) { + cstr s = cstr_null; + va_list args; va_start(args, fmt); + const int n = cstr_vfmt(&s, fmt, args); + va_end(args); + cstr_drop(self); *self = s; + return n; +} + +#endif // i_implement +#if defined __GNUC__ && !defined __clang__ +# pragma GCC diagnostic pop +#endif +#endif // CSTR_H_INCLUDED +#undef i_opt +#undef i_header +#undef i_static +#undef i_implement +#undef i_extern +#endif // !STC_CSTR_V1 diff --git a/include/stc/csview.h b/include/stc/csview.h index 36e6ad7b..90e1b10b 100644 --- a/include/stc/csview.h +++ b/include/stc/csview.h @@ -1,219 +1,219 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef CSVIEW_H_INCLUDED
-#define CSVIEW_H_INCLUDED
-
-#define i_header
-#include "ccommon.h"
-#include "forward.h"
-#include "utf8.h"
-
-#define csview_null c_sv("")
-#define csview_new(literal) c_sv(literal)
-#define csview_npos (SIZE_MAX >> 1)
-
-STC_API csview csview_substr_ex(csview sv, intptr_t pos, size_t n);
-STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2);
-STC_API csview csview_token(csview sv, csview sep, size_t* start);
-
-STC_INLINE csview csview_init() { return csview_null; }
-STC_INLINE csview csview_from(const char* str)
- { return c_make(csview){str, strlen(str)}; }
-STC_INLINE csview csview_from_n(const char* str, size_t n)
- { return c_make(csview){str, n}; }
-STC_INLINE void csview_clear(csview* self) { *self = csview_null; }
-
-STC_INLINE size_t csview_size(csview sv) { return sv.size; }
-STC_INLINE size_t csview_length(csview sv) { return sv.size; }
-STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; }
-STC_INLINE char csview_front(csview sv) { return sv.str[0]; }
-STC_INLINE char csview_back(csview sv) { return sv.str[sv.size - 1]; }
-
-STC_INLINE bool csview_equals(csview sv, csview sv2)
- { return sv.size == sv2.size && !memcmp(sv.str, sv2.str, sv.size); }
-
-STC_INLINE size_t csview_find(csview sv, csview needle) {
- char* res = c_strnstrn(sv.str, needle.str, sv.size, needle.size);
- return res ? res - sv.str : csview_npos;
-}
-
-STC_INLINE bool csview_contains(csview sv, csview needle)
- { return c_strnstrn(sv.str, needle.str, sv.size, needle.size) != NULL; }
-
-STC_INLINE bool csview_starts_with(csview sv, csview sub) {
- if (sub.size > sv.size) return false;
- return !memcmp(sv.str, sub.str, sub.size);
-}
-
-STC_INLINE bool csview_ends_with(csview sv, csview sub) {
- if (sub.size > sv.size) return false;
- return !memcmp(sv.str + sv.size - sub.size, sub.str, sub.size);
-}
-
-STC_INLINE csview csview_substr(csview sv, size_t pos, size_t n) {
- if (pos + n > sv.size) n = sv.size - pos;
- sv.str += pos, sv.size = n;
- return sv;
-}
-
-STC_INLINE csview csview_slice(csview sv, size_t p1, size_t p2) {
- if (p2 > sv.size) p2 = sv.size;
- sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0;
- return sv;
-}
-
-/* iterator */
-STC_INLINE csview_iter csview_begin(const csview* self)
- { return c_make(csview_iter){.chr = {self->str, utf8_codep_size(self->str)}}; }
-
-STC_INLINE csview_iter csview_end(const csview* self)
- { return c_make(csview_iter){self->str + self->size}; }
-
-STC_INLINE void csview_next(csview_iter* it)
- { it->ref += it->chr.size; it->chr.size = utf8_codep_size(it->ref); }
-
-/* utf8 */
-STC_INLINE size_t csview_size_u8(csview sv)
- { return utf8_size_n(sv.str, sv.size); }
-
-STC_INLINE csview csview_substr_u8(csview sv, size_t u8pos, size_t u8len) {
- sv.str = utf8_at(sv.str, u8pos);
- sv.size = utf8_pos(sv.str, u8len);
- return sv;
-}
-
-STC_INLINE bool csview_valid_u8(csview sv) // depends on src/utf8code.c
- { return utf8_valid_n(sv.str, sv.size); }
-
-
-/* csview interaction with cstr: */
-#ifdef CSTR_H_INCLUDED
-
-STC_INLINE csview csview_from_s(const cstr* self)
- { return c_make(csview){cstr_str(self), cstr_size(*self)}; }
-
-STC_INLINE cstr cstr_from_sv(csview sv)
- { return cstr_from_n(sv.str, sv.size); }
-
-STC_INLINE csview cstr_substr(const cstr* self, size_t pos, size_t n)
- { return csview_substr(csview_from_s(self), pos, n); }
-
-STC_INLINE csview cstr_slice(const cstr* self, size_t p1, size_t p2)
- { return csview_slice(csview_from_s(self), p1, p2); }
-
-STC_INLINE csview cstr_substr_ex(const cstr* self, intptr_t pos, size_t n)
- { return csview_substr_ex(csview_from_s(self), pos, n); }
-
-STC_INLINE csview cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2)
- { return csview_slice_ex(csview_from_s(self), p1, p2); }
-
-STC_INLINE csview cstr_assign_sv(cstr* self, csview sv)
- { return c_make(csview){cstr_assign_n(self, sv.str, sv.size), sv.size}; }
-
-STC_INLINE void cstr_append_sv(cstr* self, csview sv)
- { cstr_append_n(self, sv.str, sv.size); }
-
-STC_INLINE void cstr_insert_sv(cstr* self, size_t pos, csview sv)
- { cstr_replace_n(self, pos, 0, sv.str, sv.size); }
-
-STC_INLINE void cstr_replace_sv(cstr* self, csview sub, csview with)
- { cstr_replace_n(self, sub.str - cstr_str(self), sub.size, with.str, with.size); }
-
-STC_INLINE bool cstr_equals_sv(cstr s, csview sv)
- { return sv.size == cstr_size(s) && !memcmp(cstr_str(&s), sv.str, sv.size); }
-
-STC_INLINE size_t cstr_find_sv(cstr s, csview needle) {
- char* res = c_strnstrn(cstr_str(&s), needle.str, cstr_size(s), needle.size);
- return res ? res - cstr_str(&s) : cstr_npos;
-}
-
-STC_INLINE bool cstr_contains_sv(cstr s, csview needle)
- { return c_strnstrn(cstr_str(&s), needle.str, cstr_size(s), needle.size) != NULL; }
-
-STC_INLINE bool cstr_starts_with_sv(cstr s, csview sub) {
- if (sub.size > cstr_size(s)) return false;
- return !memcmp(cstr_str(&s), sub.str, sub.size);
-}
-
-STC_INLINE bool cstr_ends_with_sv(cstr s, csview sub) {
- if (sub.size > cstr_size(s)) return false;
- return !memcmp(cstr_str(&s) + cstr_size(s) - sub.size, sub.str, sub.size);
-}
-#endif
-/* ---- Container helper functions ---- */
-
-STC_INLINE int csview_cmp(const csview* x, const csview* y)
- { return strcmp(x->str, y->str); }
-
-STC_INLINE int csview_icmp(const csview* x, const csview* y)
- { return utf8_icmp_n(~(size_t)0, x->str, x->size, y->str, y->size); }
-
-STC_INLINE bool csview_eq(const csview* x, const csview* y)
- { return x->size == y->size && !memcmp(x->str, y->str, x->size); }
-
-STC_INLINE uint64_t csview_hash(const csview *self)
- { return c_fasthash(self->str, self->size); }
-
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-STC_DEF csview
-csview_substr_ex(csview sv, intptr_t pos, size_t n) {
- if (pos < 0) {
- pos += sv.size;
- if (pos < 0) pos = 0;
- }
- if (pos > (intptr_t)sv.size) pos = sv.size;
- if (pos + n > sv.size) n = sv.size - pos;
- sv.str += pos, sv.size = n;
- return sv;
-}
-
-STC_DEF csview
-csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) {
- if (p1 < 0) {
- p1 += sv.size;
- if (p1 < 0) p1 = 0;
- }
- if (p2 < 0) p2 += sv.size;
- if (p2 > (intptr_t)sv.size) p2 = sv.size;
- sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0;
- return sv;
-}
-
-STC_DEF csview
-csview_token(csview sv, csview sep, size_t* start) {
- csview slice = {sv.str + *start, sv.size - *start};
- const char* res = c_strnstrn(slice.str, sep.str, slice.size, sep.size);
- csview tok = {slice.str, res ? res - slice.str : (sep.size = 0, slice.size)};
- *start += tok.size + sep.size;
- return tok;
-}
-
-#endif
-#endif
-#undef i_opt
-#undef i_header
-#undef i_implement
-#undef i_static
-#undef i_extern
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef CSVIEW_H_INCLUDED +#define CSVIEW_H_INCLUDED + +#define i_header +#include "ccommon.h" +#include "forward.h" +#include "utf8.h" + +#define csview_null c_sv("") +#define csview_new(literal) c_sv(literal) +#define csview_npos (SIZE_MAX >> 1) + +STC_API csview csview_substr_ex(csview sv, intptr_t pos, size_t n); +STC_API csview csview_slice_ex(csview sv, intptr_t p1, intptr_t p2); +STC_API csview csview_token(csview sv, csview sep, size_t* start); + +STC_INLINE csview csview_init() { return csview_null; } +STC_INLINE csview csview_from(const char* str) + { return c_make(csview){str, strlen(str)}; } +STC_INLINE csview csview_from_n(const char* str, size_t n) + { return c_make(csview){str, n}; } +STC_INLINE void csview_clear(csview* self) { *self = csview_null; } + +STC_INLINE size_t csview_size(csview sv) { return sv.size; } +STC_INLINE size_t csview_length(csview sv) { return sv.size; } +STC_INLINE bool csview_empty(csview sv) { return sv.size == 0; } +STC_INLINE char csview_front(csview sv) { return sv.str[0]; } +STC_INLINE char csview_back(csview sv) { return sv.str[sv.size - 1]; } + +STC_INLINE bool csview_equals(csview sv, csview sv2) + { return sv.size == sv2.size && !memcmp(sv.str, sv2.str, sv.size); } + +STC_INLINE size_t csview_find(csview sv, csview needle) { + char* res = c_strnstrn(sv.str, needle.str, sv.size, needle.size); + return res ? res - sv.str : csview_npos; +} + +STC_INLINE bool csview_contains(csview sv, csview needle) + { return c_strnstrn(sv.str, needle.str, sv.size, needle.size) != NULL; } + +STC_INLINE bool csview_starts_with(csview sv, csview sub) { + if (sub.size > sv.size) return false; + return !memcmp(sv.str, sub.str, sub.size); +} + +STC_INLINE bool csview_ends_with(csview sv, csview sub) { + if (sub.size > sv.size) return false; + return !memcmp(sv.str + sv.size - sub.size, sub.str, sub.size); +} + +STC_INLINE csview csview_substr(csview sv, size_t pos, size_t n) { + if (pos + n > sv.size) n = sv.size - pos; + sv.str += pos, sv.size = n; + return sv; +} + +STC_INLINE csview csview_slice(csview sv, size_t p1, size_t p2) { + if (p2 > sv.size) p2 = sv.size; + sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0; + return sv; +} + +/* iterator */ +STC_INLINE csview_iter csview_begin(const csview* self) + { return c_make(csview_iter){.chr = {self->str, utf8_codep_size(self->str)}}; } + +STC_INLINE csview_iter csview_end(const csview* self) + { return c_make(csview_iter){self->str + self->size}; } + +STC_INLINE void csview_next(csview_iter* it) + { it->ref += it->chr.size; it->chr.size = utf8_codep_size(it->ref); } + +/* utf8 */ +STC_INLINE size_t csview_size_u8(csview sv) + { return utf8_size_n(sv.str, sv.size); } + +STC_INLINE csview csview_substr_u8(csview sv, size_t u8pos, size_t u8len) { + sv.str = utf8_at(sv.str, u8pos); + sv.size = utf8_pos(sv.str, u8len); + return sv; +} + +STC_INLINE bool csview_valid_u8(csview sv) // depends on src/utf8code.c + { return utf8_valid_n(sv.str, sv.size); } + + +/* csview interaction with cstr: */ +#ifdef CSTR_H_INCLUDED + +STC_INLINE csview csview_from_s(const cstr* self) + { return c_make(csview){cstr_str(self), cstr_size(*self)}; } + +STC_INLINE cstr cstr_from_sv(csview sv) + { return cstr_from_n(sv.str, sv.size); } + +STC_INLINE csview cstr_substr(const cstr* self, size_t pos, size_t n) + { return csview_substr(csview_from_s(self), pos, n); } + +STC_INLINE csview cstr_slice(const cstr* self, size_t p1, size_t p2) + { return csview_slice(csview_from_s(self), p1, p2); } + +STC_INLINE csview cstr_substr_ex(const cstr* self, intptr_t pos, size_t n) + { return csview_substr_ex(csview_from_s(self), pos, n); } + +STC_INLINE csview cstr_slice_ex(const cstr* self, intptr_t p1, intptr_t p2) + { return csview_slice_ex(csview_from_s(self), p1, p2); } + +STC_INLINE csview cstr_assign_sv(cstr* self, csview sv) + { return c_make(csview){cstr_assign_n(self, sv.str, sv.size), sv.size}; } + +STC_INLINE void cstr_append_sv(cstr* self, csview sv) + { cstr_append_n(self, sv.str, sv.size); } + +STC_INLINE void cstr_insert_sv(cstr* self, size_t pos, csview sv) + { cstr_replace_n(self, pos, 0, sv.str, sv.size); } + +STC_INLINE void cstr_replace_sv(cstr* self, csview sub, csview with) + { cstr_replace_n(self, sub.str - cstr_str(self), sub.size, with.str, with.size); } + +STC_INLINE bool cstr_equals_sv(cstr s, csview sv) + { return sv.size == cstr_size(s) && !memcmp(cstr_str(&s), sv.str, sv.size); } + +STC_INLINE size_t cstr_find_sv(cstr s, csview needle) { + char* res = c_strnstrn(cstr_str(&s), needle.str, cstr_size(s), needle.size); + return res ? res - cstr_str(&s) : cstr_npos; +} + +STC_INLINE bool cstr_contains_sv(cstr s, csview needle) + { return c_strnstrn(cstr_str(&s), needle.str, cstr_size(s), needle.size) != NULL; } + +STC_INLINE bool cstr_starts_with_sv(cstr s, csview sub) { + if (sub.size > cstr_size(s)) return false; + return !memcmp(cstr_str(&s), sub.str, sub.size); +} + +STC_INLINE bool cstr_ends_with_sv(cstr s, csview sub) { + if (sub.size > cstr_size(s)) return false; + return !memcmp(cstr_str(&s) + cstr_size(s) - sub.size, sub.str, sub.size); +} +#endif +/* ---- Container helper functions ---- */ + +STC_INLINE int csview_cmp(const csview* x, const csview* y) + { return strcmp(x->str, y->str); } + +STC_INLINE int csview_icmp(const csview* x, const csview* y) + { return utf8_icmp_n(~(size_t)0, x->str, x->size, y->str, y->size); } + +STC_INLINE bool csview_eq(const csview* x, const csview* y) + { return x->size == y->size && !memcmp(x->str, y->str, x->size); } + +STC_INLINE uint64_t csview_hash(const csview *self) + { return c_fasthash(self->str, self->size); } + +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) + +STC_DEF csview +csview_substr_ex(csview sv, intptr_t pos, size_t n) { + if (pos < 0) { + pos += sv.size; + if (pos < 0) pos = 0; + } + if (pos > (intptr_t)sv.size) pos = sv.size; + if (pos + n > sv.size) n = sv.size - pos; + sv.str += pos, sv.size = n; + return sv; +} + +STC_DEF csview +csview_slice_ex(csview sv, intptr_t p1, intptr_t p2) { + if (p1 < 0) { + p1 += sv.size; + if (p1 < 0) p1 = 0; + } + if (p2 < 0) p2 += sv.size; + if (p2 > (intptr_t)sv.size) p2 = sv.size; + sv.str += p1, sv.size = p2 > p1 ? p2 - p1 : 0; + return sv; +} + +STC_DEF csview +csview_token(csview sv, csview sep, size_t* start) { + csview slice = {sv.str + *start, sv.size - *start}; + const char* res = c_strnstrn(slice.str, sep.str, slice.size, sep.size); + csview tok = {slice.str, res ? res - slice.str : (sep.size = 0, slice.size)}; + *start += tok.size + sep.size; + return tok; +} + +#endif +#endif +#undef i_opt +#undef i_header +#undef i_implement +#undef i_static +#undef i_extern diff --git a/include/stc/cvec.h b/include/stc/cvec.h index f4fc0fb6..cd9c8f9e 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -1,436 +1,436 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
-#include <stc/cstr.h>
-#include <stc/forward.h>
-
-forward_cvec(cvec_i32, int);
-
-struct MyStruct {
- cvec_i32 int_vec;
- cstr name;
-} typedef MyStruct;
-
-#define i_key float
-#include <stc/cvec.h>
-
-#define i_key_str // special for cstr
-#include <stc/cvec.h>
-
-#define i_key int
-#define i_opt c_is_fwd // forward declared
-#define i_tag i32
-#include <stc/cvec.h>
-
-int main() {
- cvec_i32 vec = cvec_i32_init();
- cvec_i32_push_back(&vec, 123);
- cvec_i32_drop(&vec);
-
- cvec_float fvec = cvec_float_init();
- cvec_float_push_back(&fvec, 123.3);
- cvec_float_drop(&fvec);
-
- cvec_str svec = cvec_str_init();
- cvec_str_emplace_back(&svec, "Hello, friend");
- cvec_str_drop(&svec);
-}
-*/
-#include "ccommon.h"
-
-#ifndef CVEC_H_INCLUDED
-#include "forward.h"
-#include <stdlib.h>
-#include <string.h>
-
-struct cvec_rep { size_t size, cap; unsigned data[1]; };
-#define cvec_rep_(self) c_unchecked_container_of((self)->data, struct cvec_rep, data)
-#endif // CVEC_H_INCLUDED
-
-#ifndef _i_prefix
-#define _i_prefix cvec_
-#endif
-#include "template.h"
-
-#if !c_option(c_is_fwd)
- _cx_deftypes(_c_cvec_types, _cx_self, i_key);
-#endif
-typedef i_keyraw _cx_raw;
-STC_API _cx_self _cx_memb(_init)(void);
-STC_API void _cx_memb(_drop)(_cx_self* self);
-STC_API void _cx_memb(_clear)(_cx_self* self);
-STC_API bool _cx_memb(_reserve)(_cx_self* self, size_t cap);
-STC_API bool _cx_memb(_resize)(_cx_self* self, size_t size, i_key null);
-STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value);
-STC_API _cx_iter _cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2);
-STC_API _cx_value* _cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
-STC_API _cx_value* _cx_memb(_expand_uninit_p)(_cx_self* self, _cx_value* pos, const size_t n);
-#if !c_option(c_no_cmp)
-STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y);
-STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw);
-STC_API _cx_iter _cx_memb(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound);
-#endif
-
-#if !defined _i_no_clone
-STC_API _cx_self _cx_memb(_clone)(_cx_self cx);
-STC_API _cx_value* _cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2);
-STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val)
- { return i_keyclone(val); }
-STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) {
- if (self->data == other.data) return;
- _cx_memb(_drop)(self);
- *self = _cx_memb(_clone)(other);
- }
-#if !defined _i_no_emplace
-STC_API _cx_value* _cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_raw* p1, const _cx_raw* p2);
-STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw)
- { return _cx_memb(_push)(self, i_keyfrom(raw)); }
-STC_INLINE _cx_value*
-_cx_memb(_emplace_n)(_cx_self* self, const size_t idx, const _cx_raw arr[], const size_t n) {
- return _cx_memb(_emplace_range_p)(self, self->data + idx, arr, arr + n);
-}
-STC_INLINE _cx_value*
-_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) {
- return _cx_memb(_emplace_range_p)(self, it.ref, &raw, &raw + 1);
-}
-STC_INLINE _cx_value*
-_cx_memb(_emplace_range)(_cx_self* self, _cx_iter it, _cx_iter it1, _cx_iter it2) {
- return _cx_memb(_clone_range_p)(self, it.ref, it1.ref, it2.ref);
-}
-#endif // !_i_no_emplace
-#endif // !_i_no_clone
-
-STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return cvec_rep_(&cx)->size; }
-STC_INLINE size_t _cx_memb(_capacity)(_cx_self cx) { return cvec_rep_(&cx)->cap; }
-STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return !cvec_rep_(&cx)->size; }
-STC_INLINE _cx_raw _cx_memb(_value_toraw)(_cx_value* val) { return i_keyto(val); }
-STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); }
-STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->data; }
-STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self)
- { return self->data + cvec_rep_(self)->size - 1; }
-STC_INLINE void _cx_memb(_pop)(_cx_self* self)
- { _cx_value* p = &self->data[--cvec_rep_(self)->size]; i_keydrop(p); }
-STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value)
- { return _cx_memb(_push)(self, value); }
-STC_INLINE void _cx_memb(_pop_back)(_cx_self* self) { _cx_memb(_pop)(self); }
-STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self)
- { return c_make(_cx_iter){self->data}; }
-STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self)
- { return c_make(_cx_iter){self->data + cvec_rep_(self)->size}; }
-STC_INLINE void _cx_memb(_next)(_cx_iter* it) { ++it->ref; }
-STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t offs)
- { it.ref += offs; return it; }
-STC_INLINE size_t _cx_memb(_index)(_cx_self cx, _cx_iter it) { return it.ref - cx.data; }
-
-STC_INLINE _cx_self
-_cx_memb(_with_size)(const size_t size, i_key null) {
- _cx_self cx = _cx_memb(_init)();
- _cx_memb(_resize)(&cx, size, null);
- return cx;
-}
-
-STC_INLINE _cx_self
-_cx_memb(_with_capacity)(const size_t cap) {
- _cx_self cx = _cx_memb(_init)();
- _cx_memb(_reserve)(&cx, cap);
- return cx;
-}
-
-STC_INLINE void
-_cx_memb(_shrink_to_fit)(_cx_self *self) {
- _cx_memb(_reserve)(self, _cx_memb(_size)(*self));
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_expand_uninit)(_cx_self *self, const size_t n) {
- return _cx_memb(_expand_uninit_p)(self, self->data + _cx_memb(_size)(*self), n);
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_insert)(_cx_self* self, const size_t idx, i_key value) {
- return _cx_memb(_insert_range_p)(self, self->data + idx, &value, &value + 1);
-}
-STC_INLINE _cx_value*
-_cx_memb(_insert_n)(_cx_self* self, const size_t idx, const _cx_value arr[], const size_t n) {
- return _cx_memb(_insert_range_p)(self, self->data + idx, arr, arr + n);
-}
-STC_INLINE _cx_value*
-_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) {
- return _cx_memb(_insert_range_p)(self, it.ref, &value, &value + 1);
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_erase_n)(_cx_self* self, const size_t idx, const size_t n) {
- return _cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n);
-}
-STC_INLINE _cx_iter
-_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) {
- return _cx_memb(_erase_range_p)(self, it.ref, it.ref + 1);
-}
-STC_INLINE _cx_iter
-_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) {
- return _cx_memb(_erase_range_p)(self, it1.ref, it2.ref);
-}
-
-STC_INLINE const _cx_value*
-_cx_memb(_at)(const _cx_self* self, const size_t idx) {
- assert(idx < cvec_rep_(self)->size); return self->data + idx;
-}
-STC_INLINE _cx_value*
-_cx_memb(_at_mut)(_cx_self* self, const size_t idx) {
- assert(idx < cvec_rep_(self)->size); return self->data + idx;
-}
-
-#if !c_option(c_no_cmp)
-
-STC_INLINE _cx_iter
-_cx_memb(_find)(const _cx_self* self, _cx_raw raw) {
- return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw);
-}
-
-STC_INLINE const _cx_value*
-_cx_memb(_get)(const _cx_self* self, _cx_raw raw) {
- _cx_iter end = _cx_memb(_end)(self);
- _cx_value* val = _cx_memb(_find)(self, raw).ref;
- return val == end.ref ? NULL : val;
-}
-
-STC_INLINE _cx_value*
-_cx_memb(_get_mut)(const _cx_self* self, _cx_raw raw)
- { return (_cx_value*) _cx_memb(_get)(self, raw); }
-
-STC_INLINE _cx_iter
-_cx_memb(_binary_search)(const _cx_self* self, _cx_raw raw) {
- _cx_iter lower;
- return _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower);
-}
-
-STC_INLINE _cx_iter
-_cx_memb(_lower_bound)(const _cx_self* self, _cx_raw raw) {
- _cx_iter lower;
- _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower);
- return lower;
-}
-
-STC_INLINE void
-_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2,
- int(*_cmp_)(const _cx_value*, const _cx_value*)) {
- qsort(i1.ref, i2.ref - i1.ref, sizeof(_cx_value), (int(*)(const void*, const void*)) _cmp_);
-}
-STC_INLINE void
-_cx_memb(_sort)(_cx_self* self) {
- _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp));
-}
-#endif // !c_no_cmp
-/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined(i_implement)
-
-#ifndef CVEC_H_INCLUDED
-static struct cvec_rep _cvec_sentinel = {0, 0};
-#endif
-
-STC_DEF _cx_self
-_cx_memb(_init)(void) {
- _cx_self cx = {(_cx_value *) _cvec_sentinel.data};
- return cx;
-}
-
-STC_DEF void
-_cx_memb(_clear)(_cx_self* self) {
- struct cvec_rep* rep = cvec_rep_(self);
- if (rep->cap) {
- for (_cx_value *p = self->data, *q = p + rep->size; p != q; ) {
- --q; i_keydrop(q);
- }
- rep->size = 0;
- }
-}
-
-STC_DEF void
-_cx_memb(_drop)(_cx_self* self) {
- struct cvec_rep* rep = cvec_rep_(self);
- // second test to supress gcc -O2 warn: -Wfree-nonheap-object
- if (rep->cap == 0 || rep == &_cvec_sentinel)
- return;
- _cx_memb(_clear)(self);
- c_free(rep);
-}
-
-STC_DEF bool
-_cx_memb(_reserve)(_cx_self* self, const size_t cap) {
- struct cvec_rep* rep = cvec_rep_(self);
- const size_t len = rep->size;
- if (cap > rep->cap || (cap && cap == len)) {
- rep = (struct cvec_rep*) c_realloc(rep->cap ? rep : NULL,
- offsetof(struct cvec_rep, data) + cap*sizeof(i_key));
- if (!rep)
- return false;
- self->data = (_cx_value*) rep->data;
- rep->size = len;
- rep->cap = cap;
- }
- return true;
-}
-
-STC_DEF bool
-_cx_memb(_resize)(_cx_self* self, const size_t len, i_key null) {
- if (!_cx_memb(_reserve)(self, len)) return false;
- struct cvec_rep *rep = cvec_rep_(self);
- const size_t n = rep->size;
- for (size_t i = len; i < n; ++i)
- { i_keydrop((self->data + i)); }
- for (size_t i = n; i < len; ++i)
- self->data[i] = null;
- if (rep->cap)
- rep->size = len;
- return true;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_push)(_cx_self* self, i_key value) {
- struct cvec_rep *r = cvec_rep_(self);
- if (r->size == r->cap) {
- if (!_cx_memb(_reserve)(self, (r->size*3 >> 1) + 4))
- return NULL;
- r = cvec_rep_(self);
- }
- _cx_value *v = self->data + r->size++;
- *v = value; return v;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_expand_uninit_p)(_cx_self* self, _cx_value* pos, const size_t n) {
- const size_t idx = pos - self->data;
- struct cvec_rep* r = cvec_rep_(self);
- if (!n)
- return pos;
- if (r->size + n > r->cap) {
- if (!_cx_memb(_reserve)(self, r->size*3/2 + n))
- return NULL;
- r = cvec_rep_(self);
- pos = self->data + idx;
- }
- memmove(pos + n, pos, (r->size - idx)*sizeof *pos);
- r->size += n;
- return pos;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
- if (pos)
- memcpy(pos, p1, (p2 - p1)*sizeof *p1);
- return pos;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2) {
- intptr_t len = p2 - p1;
- if (len > 0) {
- _cx_value* p = p1, *end = self->data + cvec_rep_(self)->size;
- for (; p != p2; ++p)
- { i_keydrop(p); }
- memmove(p1, p2, (end - p2) * sizeof(i_key));
- cvec_rep_(self)->size -= len;
- }
- return c_make(_cx_iter){.ref = p1};
-}
-
-#if !defined _i_no_clone
-STC_DEF _cx_self
-_cx_memb(_clone)(_cx_self cx) {
- const size_t len = cvec_rep_(&cx)->size;
- _cx_self out = _cx_memb(_with_capacity)(len);
- if (cvec_rep_(&out)->cap)
- _cx_memb(_clone_range_p)(&out, out.data, cx.data, cx.data + len);
- return out;
-}
-
-STC_DEF _cx_value*
-_cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_value* p1, const _cx_value* p2) {
- pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
- _cx_value* it = pos;
- if (pos) for (; p1 != p2; ++p1)
- *pos++ = i_keyclone((*p1));
- return it;
-}
-
-#if !defined _i_no_emplace
-STC_DEF _cx_value*
-_cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos,
- const _cx_raw* p1, const _cx_raw* p2) {
- pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1);
- _cx_value* it = pos;
- if (pos) for (; p1 != p2; ++p1)
- *pos++ = i_keyfrom((*p1));
- return it;
-}
-#endif // !_i_no_emplace
-#endif // !_i_no_clone
-
-#if !c_option(c_no_cmp)
-STC_DEF _cx_iter
-_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
- for (; i1.ref != i2.ref; ++i1.ref) {
- const _cx_raw r = i_keyto(i1.ref);
- if (i_eq((&raw), (&r)))
- return i1;
- }
- return i2;
-}
-
-STC_DEF _cx_iter
-_cx_memb(_binary_search_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw, _cx_iter* lower_bound) {
- _cx_iter mid, last = i2;
- while (i1.ref != i2.ref) {
- mid.ref = i1.ref + ((i2.ref - i1.ref) >> 1);
- int c; const _cx_raw m = i_keyto(mid.ref);
- if (!(c = i_cmp((&raw), (&m))))
- return *lower_bound = mid;
- else if (c < 0)
- i2.ref = mid.ref;
- else
- i1.ref = mid.ref + 1;
- }
- *lower_bound = i1;
- return last;
-}
-
-STC_DEF int
-_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
- const _cx_raw rx = i_keyto(x);
- const _cx_raw ry = i_keyto(y);
- return i_cmp((&rx), (&ry));
-}
-#endif // !c_no_cmp
-#endif // i_implement
-#define CVEC_H_INCLUDED
-#include "template.h"
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* +#include <stc/cstr.h> +#include <stc/forward.h> + +forward_cvec(cvec_i32, int); + +struct MyStruct { + cvec_i32 int_vec; + cstr name; +} typedef MyStruct; + +#define i_key float +#include <stc/cvec.h> + +#define i_key_str // special for cstr +#include <stc/cvec.h> + +#define i_key int +#define i_opt c_is_fwd // forward declared +#define i_tag i32 +#include <stc/cvec.h> + +int main() { + cvec_i32 vec = cvec_i32_init(); + cvec_i32_push_back(&vec, 123); + cvec_i32_drop(&vec); + + cvec_float fvec = cvec_float_init(); + cvec_float_push_back(&fvec, 123.3); + cvec_float_drop(&fvec); + + cvec_str svec = cvec_str_init(); + cvec_str_emplace_back(&svec, "Hello, friend"); + cvec_str_drop(&svec); +} +*/ +#include "ccommon.h" + +#ifndef CVEC_H_INCLUDED +#include "forward.h" +#include <stdlib.h> +#include <string.h> + +struct cvec_rep { size_t size, cap; unsigned data[1]; }; +#define cvec_rep_(self) c_unchecked_container_of((self)->data, struct cvec_rep, data) +#endif // CVEC_H_INCLUDED + +#ifndef _i_prefix +#define _i_prefix cvec_ +#endif +#include "template.h" + +#if !c_option(c_is_fwd) + _cx_deftypes(_c_cvec_types, _cx_self, i_key); +#endif +typedef i_keyraw _cx_raw; +STC_API _cx_self _cx_memb(_init)(void); +STC_API void _cx_memb(_drop)(_cx_self* self); +STC_API void _cx_memb(_clear)(_cx_self* self); +STC_API bool _cx_memb(_reserve)(_cx_self* self, size_t cap); +STC_API bool _cx_memb(_resize)(_cx_self* self, size_t size, i_key null); +STC_API _cx_value* _cx_memb(_push)(_cx_self* self, i_key value); +STC_API _cx_iter _cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2); +STC_API _cx_value* _cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos, + const _cx_value* p1, const _cx_value* p2); +STC_API _cx_value* _cx_memb(_expand_uninit_p)(_cx_self* self, _cx_value* pos, const size_t n); +#if !c_option(c_no_cmp) +STC_API int _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y); +STC_API _cx_iter _cx_memb(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw); +STC_API _cx_iter _cx_memb(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound); +#endif + +#if !defined _i_no_clone +STC_API _cx_self _cx_memb(_clone)(_cx_self cx); +STC_API _cx_value* _cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos, + const _cx_value* p1, const _cx_value* p2); +STC_INLINE i_key _cx_memb(_value_clone)(_cx_value val) + { return i_keyclone(val); } +STC_INLINE void _cx_memb(_copy)(_cx_self *self, _cx_self other) { + if (self->data == other.data) return; + _cx_memb(_drop)(self); + *self = _cx_memb(_clone)(other); + } +#if !defined _i_no_emplace +STC_API _cx_value* _cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos, + const _cx_raw* p1, const _cx_raw* p2); +STC_INLINE _cx_value* _cx_memb(_emplace)(_cx_self* self, _cx_raw raw) + { return _cx_memb(_push)(self, i_keyfrom(raw)); } +STC_INLINE _cx_value* _cx_memb(_emplace_back)(_cx_self* self, _cx_raw raw) + { return _cx_memb(_push)(self, i_keyfrom(raw)); } +STC_INLINE _cx_value* +_cx_memb(_emplace_n)(_cx_self* self, const size_t idx, const _cx_raw arr[], const size_t n) { + return _cx_memb(_emplace_range_p)(self, self->data + idx, arr, arr + n); +} +STC_INLINE _cx_value* +_cx_memb(_emplace_at)(_cx_self* self, _cx_iter it, _cx_raw raw) { + return _cx_memb(_emplace_range_p)(self, it.ref, &raw, &raw + 1); +} +STC_INLINE _cx_value* +_cx_memb(_emplace_range)(_cx_self* self, _cx_iter it, _cx_iter it1, _cx_iter it2) { + return _cx_memb(_clone_range_p)(self, it.ref, it1.ref, it2.ref); +} +#endif // !_i_no_emplace +#endif // !_i_no_clone + +STC_INLINE size_t _cx_memb(_size)(_cx_self cx) { return cvec_rep_(&cx)->size; } +STC_INLINE size_t _cx_memb(_capacity)(_cx_self cx) { return cvec_rep_(&cx)->cap; } +STC_INLINE bool _cx_memb(_empty)(_cx_self cx) { return !cvec_rep_(&cx)->size; } +STC_INLINE _cx_raw _cx_memb(_value_toraw)(_cx_value* val) { return i_keyto(val); } +STC_INLINE void _cx_memb(_swap)(_cx_self* a, _cx_self* b) { c_swap(_cx_self, *a, *b); } +STC_INLINE _cx_value* _cx_memb(_front)(const _cx_self* self) { return self->data; } +STC_INLINE _cx_value* _cx_memb(_back)(const _cx_self* self) + { return self->data + cvec_rep_(self)->size - 1; } +STC_INLINE void _cx_memb(_pop)(_cx_self* self) + { _cx_value* p = &self->data[--cvec_rep_(self)->size]; i_keydrop(p); } +STC_INLINE _cx_value* _cx_memb(_push_back)(_cx_self* self, i_key value) + { return _cx_memb(_push)(self, value); } +STC_INLINE void _cx_memb(_pop_back)(_cx_self* self) { _cx_memb(_pop)(self); } +STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) + { return c_make(_cx_iter){self->data}; } +STC_INLINE _cx_iter _cx_memb(_end)(const _cx_self* self) + { return c_make(_cx_iter){self->data + cvec_rep_(self)->size}; } +STC_INLINE void _cx_memb(_next)(_cx_iter* it) { ++it->ref; } +STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t offs) + { it.ref += offs; return it; } +STC_INLINE size_t _cx_memb(_index)(_cx_self cx, _cx_iter it) { return it.ref - cx.data; } + +STC_INLINE _cx_self +_cx_memb(_with_size)(const size_t size, i_key null) { + _cx_self cx = _cx_memb(_init)(); + _cx_memb(_resize)(&cx, size, null); + return cx; +} + +STC_INLINE _cx_self +_cx_memb(_with_capacity)(const size_t cap) { + _cx_self cx = _cx_memb(_init)(); + _cx_memb(_reserve)(&cx, cap); + return cx; +} + +STC_INLINE void +_cx_memb(_shrink_to_fit)(_cx_self *self) { + _cx_memb(_reserve)(self, _cx_memb(_size)(*self)); +} + +STC_INLINE _cx_value* +_cx_memb(_expand_uninit)(_cx_self *self, const size_t n) { + return _cx_memb(_expand_uninit_p)(self, self->data + _cx_memb(_size)(*self), n); +} + +STC_INLINE _cx_value* +_cx_memb(_insert)(_cx_self* self, const size_t idx, i_key value) { + return _cx_memb(_insert_range_p)(self, self->data + idx, &value, &value + 1); +} +STC_INLINE _cx_value* +_cx_memb(_insert_n)(_cx_self* self, const size_t idx, const _cx_value arr[], const size_t n) { + return _cx_memb(_insert_range_p)(self, self->data + idx, arr, arr + n); +} +STC_INLINE _cx_value* +_cx_memb(_insert_at)(_cx_self* self, _cx_iter it, i_key value) { + return _cx_memb(_insert_range_p)(self, it.ref, &value, &value + 1); +} + +STC_INLINE _cx_iter +_cx_memb(_erase_n)(_cx_self* self, const size_t idx, const size_t n) { + return _cx_memb(_erase_range_p)(self, self->data + idx, self->data + idx + n); +} +STC_INLINE _cx_iter +_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { + return _cx_memb(_erase_range_p)(self, it.ref, it.ref + 1); +} +STC_INLINE _cx_iter +_cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { + return _cx_memb(_erase_range_p)(self, it1.ref, it2.ref); +} + +STC_INLINE const _cx_value* +_cx_memb(_at)(const _cx_self* self, const size_t idx) { + assert(idx < cvec_rep_(self)->size); return self->data + idx; +} +STC_INLINE _cx_value* +_cx_memb(_at_mut)(_cx_self* self, const size_t idx) { + assert(idx < cvec_rep_(self)->size); return self->data + idx; +} + +#if !c_option(c_no_cmp) + +STC_INLINE _cx_iter +_cx_memb(_find)(const _cx_self* self, _cx_raw raw) { + return _cx_memb(_find_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw); +} + +STC_INLINE const _cx_value* +_cx_memb(_get)(const _cx_self* self, _cx_raw raw) { + _cx_iter end = _cx_memb(_end)(self); + _cx_value* val = _cx_memb(_find)(self, raw).ref; + return val == end.ref ? NULL : val; +} + +STC_INLINE _cx_value* +_cx_memb(_get_mut)(const _cx_self* self, _cx_raw raw) + { return (_cx_value*) _cx_memb(_get)(self, raw); } + +STC_INLINE _cx_iter +_cx_memb(_binary_search)(const _cx_self* self, _cx_raw raw) { + _cx_iter lower; + return _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower); +} + +STC_INLINE _cx_iter +_cx_memb(_lower_bound)(const _cx_self* self, _cx_raw raw) { + _cx_iter lower; + _cx_memb(_binary_search_in)(_cx_memb(_begin)(self), _cx_memb(_end)(self), raw, &lower); + return lower; +} + +STC_INLINE void +_cx_memb(_sort_range)(_cx_iter i1, _cx_iter i2, + int(*_cmp_)(const _cx_value*, const _cx_value*)) { + qsort(i1.ref, i2.ref - i1.ref, sizeof(_cx_value), (int(*)(const void*, const void*)) _cmp_); +} +STC_INLINE void +_cx_memb(_sort)(_cx_self* self) { + _cx_memb(_sort_range)(_cx_memb(_begin)(self), _cx_memb(_end)(self), _cx_memb(_value_cmp)); +} +#endif // !c_no_cmp +/* -------------------------- IMPLEMENTATION ------------------------- */ +#if defined(i_implement) + +#ifndef CVEC_H_INCLUDED +static struct cvec_rep _cvec_sentinel = {0, 0}; +#endif + +STC_DEF _cx_self +_cx_memb(_init)(void) { + _cx_self cx = {(_cx_value *) _cvec_sentinel.data}; + return cx; +} + +STC_DEF void +_cx_memb(_clear)(_cx_self* self) { + struct cvec_rep* rep = cvec_rep_(self); + if (rep->cap) { + for (_cx_value *p = self->data, *q = p + rep->size; p != q; ) { + --q; i_keydrop(q); + } + rep->size = 0; + } +} + +STC_DEF void +_cx_memb(_drop)(_cx_self* self) { + struct cvec_rep* rep = cvec_rep_(self); + // second test to supress gcc -O2 warn: -Wfree-nonheap-object + if (rep->cap == 0 || rep == &_cvec_sentinel) + return; + _cx_memb(_clear)(self); + c_free(rep); +} + +STC_DEF bool +_cx_memb(_reserve)(_cx_self* self, const size_t cap) { + struct cvec_rep* rep = cvec_rep_(self); + const size_t len = rep->size; + if (cap > rep->cap || (cap && cap == len)) { + rep = (struct cvec_rep*) c_realloc(rep->cap ? rep : NULL, + offsetof(struct cvec_rep, data) + cap*sizeof(i_key)); + if (!rep) + return false; + self->data = (_cx_value*) rep->data; + rep->size = len; + rep->cap = cap; + } + return true; +} + +STC_DEF bool +_cx_memb(_resize)(_cx_self* self, const size_t len, i_key null) { + if (!_cx_memb(_reserve)(self, len)) return false; + struct cvec_rep *rep = cvec_rep_(self); + const size_t n = rep->size; + for (size_t i = len; i < n; ++i) + { i_keydrop((self->data + i)); } + for (size_t i = n; i < len; ++i) + self->data[i] = null; + if (rep->cap) + rep->size = len; + return true; +} + +STC_DEF _cx_value* +_cx_memb(_push)(_cx_self* self, i_key value) { + struct cvec_rep *r = cvec_rep_(self); + if (r->size == r->cap) { + if (!_cx_memb(_reserve)(self, (r->size*3 >> 1) + 4)) + return NULL; + r = cvec_rep_(self); + } + _cx_value *v = self->data + r->size++; + *v = value; return v; +} + +STC_DEF _cx_value* +_cx_memb(_expand_uninit_p)(_cx_self* self, _cx_value* pos, const size_t n) { + const size_t idx = pos - self->data; + struct cvec_rep* r = cvec_rep_(self); + if (!n) + return pos; + if (r->size + n > r->cap) { + if (!_cx_memb(_reserve)(self, r->size*3/2 + n)) + return NULL; + r = cvec_rep_(self); + pos = self->data + idx; + } + memmove(pos + n, pos, (r->size - idx)*sizeof *pos); + r->size += n; + return pos; +} + +STC_DEF _cx_value* +_cx_memb(_insert_range_p)(_cx_self* self, _cx_value* pos, + const _cx_value* p1, const _cx_value* p2) { + pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1); + if (pos) + memcpy(pos, p1, (p2 - p1)*sizeof *p1); + return pos; +} + +STC_DEF _cx_iter +_cx_memb(_erase_range_p)(_cx_self* self, _cx_value* p1, _cx_value* p2) { + intptr_t len = p2 - p1; + if (len > 0) { + _cx_value* p = p1, *end = self->data + cvec_rep_(self)->size; + for (; p != p2; ++p) + { i_keydrop(p); } + memmove(p1, p2, (end - p2) * sizeof(i_key)); + cvec_rep_(self)->size -= len; + } + return c_make(_cx_iter){.ref = p1}; +} + +#if !defined _i_no_clone +STC_DEF _cx_self +_cx_memb(_clone)(_cx_self cx) { + const size_t len = cvec_rep_(&cx)->size; + _cx_self out = _cx_memb(_with_capacity)(len); + if (cvec_rep_(&out)->cap) + _cx_memb(_clone_range_p)(&out, out.data, cx.data, cx.data + len); + return out; +} + +STC_DEF _cx_value* +_cx_memb(_clone_range_p)(_cx_self* self, _cx_value* pos, + const _cx_value* p1, const _cx_value* p2) { + pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1); + _cx_value* it = pos; + if (pos) for (; p1 != p2; ++p1) + *pos++ = i_keyclone((*p1)); + return it; +} + +#if !defined _i_no_emplace +STC_DEF _cx_value* +_cx_memb(_emplace_range_p)(_cx_self* self, _cx_value* pos, + const _cx_raw* p1, const _cx_raw* p2) { + pos = _cx_memb(_expand_uninit_p)(self, pos, p2 - p1); + _cx_value* it = pos; + if (pos) for (; p1 != p2; ++p1) + *pos++ = i_keyfrom((*p1)); + return it; +} +#endif // !_i_no_emplace +#endif // !_i_no_clone + +#if !c_option(c_no_cmp) +STC_DEF _cx_iter +_cx_memb(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) { + for (; i1.ref != i2.ref; ++i1.ref) { + const _cx_raw r = i_keyto(i1.ref); + if (i_eq((&raw), (&r))) + return i1; + } + return i2; +} + +STC_DEF _cx_iter +_cx_memb(_binary_search_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw, _cx_iter* lower_bound) { + _cx_iter mid, last = i2; + while (i1.ref != i2.ref) { + mid.ref = i1.ref + ((i2.ref - i1.ref) >> 1); + int c; const _cx_raw m = i_keyto(mid.ref); + if (!(c = i_cmp((&raw), (&m)))) + return *lower_bound = mid; + else if (c < 0) + i2.ref = mid.ref; + else + i1.ref = mid.ref + 1; + } + *lower_bound = i1; + return last; +} + +STC_DEF int +_cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) { + const _cx_raw rx = i_keyto(x); + const _cx_raw ry = i_keyto(y); + return i_cmp((&rx), (&ry)); +} +#endif // !c_no_cmp +#endif // i_implement +#define CVEC_H_INCLUDED +#include "template.h" diff --git a/include/stc/forward.h b/include/stc/forward.h index 67f5f0f2..18c3d7b0 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -1,207 +1,207 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef STC_FORWARD_H_INCLUDED
-#define STC_FORWARD_H_INCLUDED
-
-#include <stddef.h>
-
-#define forward_carc(CX, VAL) _c_carc_types(CX, VAL)
-#define forward_carr2(CX, VAL) _c_carr2_types(CX, VAL)
-#define forward_carr3(CX, VAL) _c_carr3_types(CX, VAL)
-#define forward_cbox(CX, VAL) _c_cbox_types(CX, VAL)
-#define forward_cdeq(CX, VAL) _c_cdeq_types(CX, VAL)
-#define forward_clist(CX, VAL) _c_clist_types(CX, VAL)
-#define forward_cmap(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, uint32_t, c_true, c_false)
-#define forward_cmap_huge(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, size_t, c_true, c_false)
-#define forward_cset(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, uint32_t, c_false, c_true)
-#define forward_cset_huge(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, size_t, c_false, c_true)
-#define forward_csmap(CX, KEY, VAL) _c_aatree_types(CX, KEY, VAL, uint32_t, c_true, c_false)
-#define forward_csset(CX, KEY) _c_aatree_types(CX, KEY, KEY, uint32_t, c_false, c_true)
-#define forward_cstack(CX, VAL) _c_cstack_types(CX, VAL)
-#define forward_cpque(CX, VAL) _c_cpque_types(CX, VAL)
-#define forward_cqueue(CX, VAL) _c_cdeq_types(CX, VAL)
-#define forward_cvec(CX, VAL) _c_cvec_types(CX, VAL)
-
-typedef struct { char* data; size_t size, cap; } cstr_buf;
-typedef char cstr_value;
-#if defined STC_CSTR_V1
- typedef struct { char* str; } cstr;
-#else
- typedef union {
- struct { char data[sizeof(cstr_buf) - 1]; unsigned char last; } sml;
- struct { char* data; size_t size, ncap; } lon;
- } cstr;
-#endif
-
-typedef struct { const char* str; size_t size; } csview;
-typedef char csview_value;
-typedef union {
- const char *ref;
- csview chr;
-} csview_iter, cstr_iter;
-
-#define c_true(...) __VA_ARGS__
-#define c_false(...)
-
-#define _c_carc_types(SELF, VAL) \
- typedef VAL SELF##_value; \
-\
- typedef struct { \
- SELF##_value* get; \
- long* use_count; \
- } SELF
-
-#define _c_carr2_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct { SELF##_value *ref; } SELF##_iter; \
- typedef struct { SELF##_value **data; size_t xdim, ydim; } SELF
-
-#define _c_carr3_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct { SELF##_value *ref; } SELF##_iter; \
- typedef struct { SELF##_value ***data; size_t xdim, ydim, zdim; } SELF
-
-#define _c_cbox_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct { \
- SELF##_value* get; \
- } SELF
-
-#define _c_cdeq_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct {SELF##_value *ref; } SELF##_iter; \
- typedef struct {SELF##_value *_base, *data;} SELF
-
-#define _c_clist_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct SELF##_node SELF##_node; \
-\
- typedef struct { \
- SELF##_value *ref; \
- SELF##_node *const *_last, *prev; \
- } SELF##_iter; \
-\
- typedef struct { \
- SELF##_node *last; \
- } SELF
-
-#define _c_chash_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \
- typedef KEY SELF##_key; \
- typedef VAL SELF##_mapped; \
- typedef SZ SELF##_size_t; \
-\
- typedef SET_ONLY( SELF##_key ) \
- MAP_ONLY( struct SELF##_value ) \
- SELF##_value; \
-\
- typedef struct { \
- SELF##_value *ref; \
- bool inserted, nomem_error; \
- } SELF##_result; \
-\
- typedef struct { \
- SELF##_value *ref; \
- uint8_t* _hx; \
- } SELF##_iter; \
-\
- typedef struct { \
- SELF##_value* table; \
- uint8_t* _hashx; \
- SELF##_size_t size, bucket_count; \
- float max_load_factor; \
- } SELF
-
-#if defined STC_CSMAP_V1
-#define _c_aatree_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \
- typedef KEY SELF##_key; \
- typedef VAL SELF##_mapped; \
- typedef SZ SELF##_size_t; \
- typedef struct SELF##_node SELF##_node; \
-\
- typedef SET_ONLY( SELF##_key ) \
- MAP_ONLY( struct SELF##_value ) \
- SELF##_value; \
-\
- typedef struct { \
- SELF##_value *ref; \
- bool inserted, nomem_error; \
- } SELF##_result; \
-\
- typedef struct { \
- SELF##_value *ref; \
- int _top; \
- SELF##_node *_tn, *_st[36]; \
- } SELF##_iter; \
-\
- typedef struct { \
- SELF##_node *root; \
- SELF##_size_t size; \
- } SELF
-#else
-#define _c_aatree_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \
- typedef KEY SELF##_key; \
- typedef VAL SELF##_mapped; \
- typedef SZ SELF##_size_t; \
- typedef struct SELF##_node SELF##_node; \
-\
- typedef SET_ONLY( SELF##_key ) \
- MAP_ONLY( struct SELF##_value ) \
- SELF##_value; \
-\
- typedef struct { \
- SELF##_value *ref; \
- bool inserted, nomem_error; \
- } SELF##_result; \
-\
- typedef struct { \
- SELF##_value *ref; \
- SELF##_node *_d; \
- int _top; \
- SELF##_size_t _tn, _st[36]; \
- } SELF##_iter; \
-\
- typedef struct { \
- SELF##_node *nodes; \
- } SELF
-#endif
-#define _c_cstack_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct { SELF##_value *ref; } SELF##_iter; \
- typedef struct SELF { \
- SELF##_value* data; \
- size_t size, capacity; \
- } SELF
-
-#define _c_cpque_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct SELF { \
- SELF##_value* data; \
- size_t size, capacity; \
- } SELF
-
-#define _c_cvec_types(SELF, VAL) \
- typedef VAL SELF##_value; \
- typedef struct { SELF##_value *ref; } SELF##_iter; \
- typedef struct { SELF##_value *data; } SELF
-
-#endif // STC_FORWARD_H_INCLUDED
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef STC_FORWARD_H_INCLUDED +#define STC_FORWARD_H_INCLUDED + +#include <stddef.h> + +#define forward_carc(CX, VAL) _c_carc_types(CX, VAL) +#define forward_carr2(CX, VAL) _c_carr2_types(CX, VAL) +#define forward_carr3(CX, VAL) _c_carr3_types(CX, VAL) +#define forward_cbox(CX, VAL) _c_cbox_types(CX, VAL) +#define forward_cdeq(CX, VAL) _c_cdeq_types(CX, VAL) +#define forward_clist(CX, VAL) _c_clist_types(CX, VAL) +#define forward_cmap(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, uint32_t, c_true, c_false) +#define forward_cmap_huge(CX, KEY, VAL) _c_chash_types(CX, KEY, VAL, size_t, c_true, c_false) +#define forward_cset(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, uint32_t, c_false, c_true) +#define forward_cset_huge(CX, KEY) _c_chash_types(CX, cset, KEY, KEY, size_t, c_false, c_true) +#define forward_csmap(CX, KEY, VAL) _c_aatree_types(CX, KEY, VAL, uint32_t, c_true, c_false) +#define forward_csset(CX, KEY) _c_aatree_types(CX, KEY, KEY, uint32_t, c_false, c_true) +#define forward_cstack(CX, VAL) _c_cstack_types(CX, VAL) +#define forward_cpque(CX, VAL) _c_cpque_types(CX, VAL) +#define forward_cqueue(CX, VAL) _c_cdeq_types(CX, VAL) +#define forward_cvec(CX, VAL) _c_cvec_types(CX, VAL) + +typedef struct { char* data; size_t size, cap; } cstr_buf; +typedef char cstr_value; +#if defined STC_CSTR_V1 + typedef struct { char* str; } cstr; +#else + typedef union { + struct { char data[sizeof(cstr_buf) - 1]; unsigned char last; } sml; + struct { char* data; size_t size, ncap; } lon; + } cstr; +#endif + +typedef struct { const char* str; size_t size; } csview; +typedef char csview_value; +typedef union { + const char *ref; + csview chr; +} csview_iter, cstr_iter; + +#define c_true(...) __VA_ARGS__ +#define c_false(...) + +#define _c_carc_types(SELF, VAL) \ + typedef VAL SELF##_value; \ +\ + typedef struct { \ + SELF##_value* get; \ + long* use_count; \ + } SELF + +#define _c_carr2_types(SELF, VAL) \ + typedef VAL SELF##_value; \ + typedef struct { SELF##_value *ref; } SELF##_iter; \ + typedef struct { SELF##_value **data; size_t xdim, ydim; } SELF + +#define _c_carr3_types(SELF, VAL) \ + typedef VAL SELF##_value; \ + typedef struct { SELF##_value *ref; } SELF##_iter; \ + typedef struct { SELF##_value ***data; size_t xdim, ydim, zdim; } SELF + +#define _c_cbox_types(SELF, VAL) \ + typedef VAL SELF##_value; \ + typedef struct { \ + SELF##_value* get; \ + } SELF + +#define _c_cdeq_types(SELF, VAL) \ + typedef VAL SELF##_value; \ + typedef struct {SELF##_value *ref; } SELF##_iter; \ + typedef struct {SELF##_value *_base, *data;} SELF + +#define _c_clist_types(SELF, VAL) \ + typedef VAL SELF##_value; \ + typedef struct SELF##_node SELF##_node; \ +\ + typedef struct { \ + SELF##_value *ref; \ + SELF##_node *const *_last, *prev; \ + } SELF##_iter; \ +\ + typedef struct { \ + SELF##_node *last; \ + } SELF + +#define _c_chash_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \ + typedef KEY SELF##_key; \ + typedef VAL SELF##_mapped; \ + typedef SZ SELF##_size_t; \ +\ + typedef SET_ONLY( SELF##_key ) \ + MAP_ONLY( struct SELF##_value ) \ + SELF##_value; \ +\ + typedef struct { \ + SELF##_value *ref; \ + bool inserted, nomem_error; \ + } SELF##_result; \ +\ + typedef struct { \ + SELF##_value *ref; \ + uint8_t* _hx; \ + } SELF##_iter; \ +\ + typedef struct { \ + SELF##_value* table; \ + uint8_t* _hashx; \ + SELF##_size_t size, bucket_count; \ + float max_load_factor; \ + } SELF + +#if defined STC_CSMAP_V1 +#define _c_aatree_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \ + typedef KEY SELF##_key; \ + typedef VAL SELF##_mapped; \ + typedef SZ SELF##_size_t; \ + typedef struct SELF##_node SELF##_node; \ +\ + typedef SET_ONLY( SELF##_key ) \ + MAP_ONLY( struct SELF##_value ) \ + SELF##_value; \ +\ + typedef struct { \ + SELF##_value *ref; \ + bool inserted, nomem_error; \ + } SELF##_result; \ +\ + typedef struct { \ + SELF##_value *ref; \ + int _top; \ + SELF##_node *_tn, *_st[36]; \ + } SELF##_iter; \ +\ + typedef struct { \ + SELF##_node *root; \ + SELF##_size_t size; \ + } SELF +#else +#define _c_aatree_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \ + typedef KEY SELF##_key; \ + typedef VAL SELF##_mapped; \ + typedef SZ SELF##_size_t; \ + typedef struct SELF##_node SELF##_node; \ +\ + typedef SET_ONLY( SELF##_key ) \ + MAP_ONLY( struct SELF##_value ) \ + SELF##_value; \ +\ + typedef struct { \ + SELF##_value *ref; \ + bool inserted, nomem_error; \ + } SELF##_result; \ +\ + typedef struct { \ + SELF##_value *ref; \ + SELF##_node *_d; \ + int _top; \ + SELF##_size_t _tn, _st[36]; \ + } SELF##_iter; \ +\ + typedef struct { \ + SELF##_node *nodes; \ + } SELF +#endif +#define _c_cstack_types(SELF, VAL) \ + typedef VAL SELF##_value; \ + typedef struct { SELF##_value *ref; } SELF##_iter; \ + typedef struct SELF { \ + SELF##_value* data; \ + size_t size, capacity; \ + } SELF + +#define _c_cpque_types(SELF, VAL) \ + typedef VAL SELF##_value; \ + typedef struct SELF { \ + SELF##_value* data; \ + size_t size, capacity; \ + } SELF + +#define _c_cvec_types(SELF, VAL) \ + typedef VAL SELF##_value; \ + typedef struct { SELF##_value *ref; } SELF##_iter; \ + typedef struct { SELF##_value *data; } SELF + +#endif // STC_FORWARD_H_INCLUDED diff --git a/include/stc/template.h b/include/stc/template.h index 9bf7e378..5de248e7 100644 --- a/include/stc/template.h +++ b/include/stc/template.h @@ -1,296 +1,296 @@ -/* MIT License
- *
- * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef _i_template
-#define _i_template
-
-#ifndef STC_TEMPLATE_H_INCLUDED
-#define STC_TEMPLATE_H_INCLUDED
- #define _cx_self c_paste(_i_prefix, i_tag)
- #define _cx_memb(name) c_paste(_cx_self, name)
- #define _cx_deftypes(macro, SELF, ...) c_expand(macro(SELF, __VA_ARGS__))
- #define _cx_value _cx_memb(_value)
- #define _cx_key _cx_memb(_key)
- #define _cx_mapped _cx_memb(_mapped)
- #define _cx_raw _cx_memb(_raw)
- #define _cx_rawkey _cx_memb(_rawkey)
- #define _cx_rawmapped _cx_memb(_rawmapped)
- #define _cx_iter _cx_memb(_iter)
- #define _cx_result _cx_memb(_result)
- #define _cx_node _cx_memb(_node)
-#endif
-
-#ifdef i_type
- #define i_tag i_type
- #undef _i_prefix
- #define _i_prefix
-#endif
-
-#ifndef i_size
- #define i_size uint32_t
-#endif
-
-#if !(defined i_key || defined i_key_str || defined i_key_ssv || \
- defined i_key_bind || defined i_key_arcbox)
- #define _i_key_from_val
- #if defined _i_ismap
- #error "i_key* must be defined for maps."
- #endif
-
- #if defined i_val_str
- #define i_key_str i_val_str
- #endif
- #if defined i_val_ssv
- #define i_key_ssv i_val_ssv
- #endif
- #if defined i_val_arcbox
- #define i_key_arcbox i_val_arcbox
- #endif
- #if defined i_val_bind
- #define i_key_bind i_val_bind
- #endif
- #if defined i_val
- #define i_key i_val
- #endif
- #if defined i_valraw
- #define i_keyraw i_valraw
- #endif
- #if defined i_valclone
- #define i_keyclone i_valclone
- #endif
- #if defined i_valfrom
- #define i_keyfrom i_valfrom
- #endif
- #if defined i_valto
- #define i_keyto i_valto
- #endif
- #if defined i_valdrop
- #define i_keydrop i_valdrop
- #endif
-#endif
-
-#if defined i_key_str
- #define i_key_bind cstr
- #define i_keyraw crawstr
- #define i_keyfrom cstr_from
- #ifndef i_tag
- #define i_tag str
- #endif
-#elif defined i_key_ssv
- #define i_key_bind cstr
- #define i_keyraw csview
- #define i_keyfrom cstr_from_sv
- #define i_keyto cstr_sv
- #define i_eq csview_eq
- #ifndef i_tag
- #define i_tag ssv
- #endif
-#elif defined i_key_arcbox
- #define i_key_bind i_key_arcbox
- #define i_keyraw c_paste(i_key_arcbox, _value)
- #define i_keyto c_paste(i_key, _toval)
- #define i_eq c_paste(i_key_arcbox, _value_eq)
-#endif
-
-#ifdef i_key_bind
- #define i_key i_key_bind
- #ifndef i_keyclone
- #define i_keyclone c_paste(i_key, _clone)
- #endif
- #if !defined i_keyto && defined i_keyraw
- #define i_keyto c_paste(i_key, _toraw)
- #endif
- #ifndef i_keydrop
- #define i_keydrop c_paste(i_key, _drop)
- #endif
- #ifndef i_cmp
- #define i_cmp c_paste(i_keyraw, _cmp)
- #endif
- #if !defined i_hash
- #define i_hash c_paste(i_keyraw, _hash)
- #endif
-#endif
-
-#if !defined i_key
- #error "no i_key or i_val defined"
-#elif defined i_keyraw ^ defined i_keyto
- #error "both i_keyraw and i_keyto must be defined, if any"
-#elif defined i_keyfrom && !defined i_keyraw
- #error "i_keyfrom defined without i_keyraw"
-#elif defined i_from || defined i_drop
- #error "i_from / i_drop not supported. Define i_keyfrom/i_valfrom and/or i_keydrop/i_valdrop instead"
-#endif
-
-#ifndef i_tag
- #define i_tag i_key
-#endif
-#if c_option(c_no_clone) || (!defined i_keyclone && (defined i_keydrop || defined i_keyraw))
- #define _i_no_clone
-#endif
-#ifndef i_keyraw
- #define i_keyraw i_key
-#endif
-#ifndef i_keyfrom
- #define i_keyfrom c_default_clone
-#else
- #define _i_has_from
-#endif
-#ifndef i_keyto
- #define i_keyto c_default_toraw
-#endif
-#ifndef i_keyclone
- #define i_keyclone c_default_clone
-#endif
-#ifndef i_keydrop
- #define i_keydrop c_default_drop
-#endif
-#ifdef i_less
- #define i_cmp(x, y) c_less_cmp(i_less, x, y)
-#endif
-#if !defined i_eq && defined i_cmp
- #define i_eq(x, y) !(i_cmp(x, y))
-#elif !defined i_eq
- #define i_eq c_default_eq
-#endif
-#ifndef i_cmp
- #define i_cmp c_default_cmp
-#endif
-#ifndef i_hash
- #define i_hash c_default_hash
-#endif
-
-#if defined _i_ismap // ---- process cmap/csmap value i_val, ... ----
-
-#ifdef i_val_str
- #define i_val_bind cstr
- #define i_valraw crawstr
- #define i_valfrom cstr_from
-#elif defined i_val_ssv
- #define i_val_bind cstr
- #define i_valraw csview
- #define i_valfrom cstr_from_sv
- #define i_valto cstr_sv
-#elif defined i_val_arcbox
- #define i_val_bind i_val_arcbox
- #define i_valraw c_paste(i_val_arcbox, _value)
- #define i_valto c_paste(i_val, _toval)
-#endif
-
-#ifdef i_val_bind
- #define i_val i_val_bind
- #ifndef i_valclone
- #define i_valclone c_paste(i_val, _clone)
- #endif
- #if !defined i_valto && defined i_valraw
- #define i_valto c_paste(i_val, _toraw)
- #endif
- #ifndef i_valdrop
- #define i_valdrop c_paste(i_val, _drop)
- #endif
-#endif
-
-#if defined i_valraw ^ defined i_valto
- #error "both i_valto and i_valraw must be defined, if any"
-#elif defined i_valfrom && !defined i_valraw
- #error "i_valfrom defined without i_valraw"
-#endif
-
-#if !defined i_valclone && (defined i_valdrop || defined i_valraw)
- #define _i_no_clone
-#endif
-#ifndef i_valraw
- #define i_valraw i_val
-#endif
-#ifndef i_valfrom
- #define i_valfrom c_default_clone
-#else
- #define _i_has_from
-#endif
-#ifndef i_valto
- #define i_valto c_default_toraw
-#endif
-#ifndef i_valclone
- #define i_valclone c_default_clone
-#endif
-#ifndef i_valdrop
- #define i_valdrop c_default_drop
-#endif
-
-#endif // !_i_ismap
-
-#ifndef i_val
- #define i_val i_key
-#endif
-#ifndef i_valraw
- #define i_valraw i_keyraw
-#endif
-#ifndef _i_has_from
- #define _i_no_emplace
-#endif
-
-#else // ============================================================
-
-#undef i_type
-#undef i_tag
-#undef i_imp
-#undef i_opt
-#undef i_less
-#undef i_cmp
-#undef i_eq
-#undef i_hash
-#undef i_size
-
-#undef i_val
-#undef i_val_str
-#undef i_val_ssv
-#undef i_val_arcbox
-#undef i_val_bind
-#undef i_valraw
-#undef i_valclone
-#undef i_valfrom
-#undef i_valto
-#undef i_valdrop
-
-#undef i_key
-#undef i_key_str
-#undef i_key_ssv
-#undef i_key_arcbox
-#undef i_key_bind
-#undef i_keyraw
-#undef i_keyclone
-#undef i_keyfrom
-#undef i_keyto
-#undef i_keydrop
-
-#undef i_header
-#undef i_implement
-#undef i_static
-#undef i_extern
-
-#undef _i_prefix
-#undef _i_has_from
-#undef _i_key_from_val
-#undef _i_no_clone
-#undef _i_no_emplace
-#undef _i_no_hash
-#undef _i_template
-#endif
+/* MIT License + * + * Copyright (c) 2022 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _i_template +#define _i_template + +#ifndef STC_TEMPLATE_H_INCLUDED +#define STC_TEMPLATE_H_INCLUDED + #define _cx_self c_paste(_i_prefix, i_tag) + #define _cx_memb(name) c_paste(_cx_self, name) + #define _cx_deftypes(macro, SELF, ...) c_expand(macro(SELF, __VA_ARGS__)) + #define _cx_value _cx_memb(_value) + #define _cx_key _cx_memb(_key) + #define _cx_mapped _cx_memb(_mapped) + #define _cx_raw _cx_memb(_raw) + #define _cx_rawkey _cx_memb(_rawkey) + #define _cx_rawmapped _cx_memb(_rawmapped) + #define _cx_iter _cx_memb(_iter) + #define _cx_result _cx_memb(_result) + #define _cx_node _cx_memb(_node) +#endif + +#ifdef i_type + #define i_tag i_type + #undef _i_prefix + #define _i_prefix +#endif + +#ifndef i_size + #define i_size uint32_t +#endif + +#if !(defined i_key || defined i_key_str || defined i_key_ssv || \ + defined i_key_bind || defined i_key_arcbox) + #define _i_key_from_val + #if defined _i_ismap + #error "i_key* must be defined for maps." + #endif + + #if defined i_val_str + #define i_key_str i_val_str + #endif + #if defined i_val_ssv + #define i_key_ssv i_val_ssv + #endif + #if defined i_val_arcbox + #define i_key_arcbox i_val_arcbox + #endif + #if defined i_val_bind + #define i_key_bind i_val_bind + #endif + #if defined i_val + #define i_key i_val + #endif + #if defined i_valraw + #define i_keyraw i_valraw + #endif + #if defined i_valclone + #define i_keyclone i_valclone + #endif + #if defined i_valfrom + #define i_keyfrom i_valfrom + #endif + #if defined i_valto + #define i_keyto i_valto + #endif + #if defined i_valdrop + #define i_keydrop i_valdrop + #endif +#endif + +#if defined i_key_str + #define i_key_bind cstr + #define i_keyraw crawstr + #define i_keyfrom cstr_from + #ifndef i_tag + #define i_tag str + #endif +#elif defined i_key_ssv + #define i_key_bind cstr + #define i_keyraw csview + #define i_keyfrom cstr_from_sv + #define i_keyto cstr_sv + #define i_eq csview_eq + #ifndef i_tag + #define i_tag ssv + #endif +#elif defined i_key_arcbox + #define i_key_bind i_key_arcbox + #define i_keyraw c_paste(i_key_arcbox, _value) + #define i_keyto c_paste(i_key, _toval) + #define i_eq c_paste(i_key_arcbox, _value_eq) +#endif + +#ifdef i_key_bind + #define i_key i_key_bind + #ifndef i_keyclone + #define i_keyclone c_paste(i_key, _clone) + #endif + #if !defined i_keyto && defined i_keyraw + #define i_keyto c_paste(i_key, _toraw) + #endif + #ifndef i_keydrop + #define i_keydrop c_paste(i_key, _drop) + #endif + #ifndef i_cmp + #define i_cmp c_paste(i_keyraw, _cmp) + #endif + #if !defined i_hash + #define i_hash c_paste(i_keyraw, _hash) + #endif +#endif + +#if !defined i_key + #error "no i_key or i_val defined" +#elif defined i_keyraw ^ defined i_keyto + #error "both i_keyraw and i_keyto must be defined, if any" +#elif defined i_keyfrom && !defined i_keyraw + #error "i_keyfrom defined without i_keyraw" +#elif defined i_from || defined i_drop + #error "i_from / i_drop not supported. Define i_keyfrom/i_valfrom and/or i_keydrop/i_valdrop instead" +#endif + +#ifndef i_tag + #define i_tag i_key +#endif +#if c_option(c_no_clone) || (!defined i_keyclone && (defined i_keydrop || defined i_keyraw)) + #define _i_no_clone +#endif +#ifndef i_keyraw + #define i_keyraw i_key +#endif +#ifndef i_keyfrom + #define i_keyfrom c_default_clone +#else + #define _i_has_from +#endif +#ifndef i_keyto + #define i_keyto c_default_toraw +#endif +#ifndef i_keyclone + #define i_keyclone c_default_clone +#endif +#ifndef i_keydrop + #define i_keydrop c_default_drop +#endif +#ifdef i_less + #define i_cmp(x, y) c_less_cmp(i_less, x, y) +#endif +#if !defined i_eq && defined i_cmp + #define i_eq(x, y) !(i_cmp(x, y)) +#elif !defined i_eq + #define i_eq c_default_eq +#endif +#ifndef i_cmp + #define i_cmp c_default_cmp +#endif +#ifndef i_hash + #define i_hash c_default_hash +#endif + +#if defined _i_ismap // ---- process cmap/csmap value i_val, ... ---- + +#ifdef i_val_str + #define i_val_bind cstr + #define i_valraw crawstr + #define i_valfrom cstr_from +#elif defined i_val_ssv + #define i_val_bind cstr + #define i_valraw csview + #define i_valfrom cstr_from_sv + #define i_valto cstr_sv +#elif defined i_val_arcbox + #define i_val_bind i_val_arcbox + #define i_valraw c_paste(i_val_arcbox, _value) + #define i_valto c_paste(i_val, _toval) +#endif + +#ifdef i_val_bind + #define i_val i_val_bind + #ifndef i_valclone + #define i_valclone c_paste(i_val, _clone) + #endif + #if !defined i_valto && defined i_valraw + #define i_valto c_paste(i_val, _toraw) + #endif + #ifndef i_valdrop + #define i_valdrop c_paste(i_val, _drop) + #endif +#endif + +#if defined i_valraw ^ defined i_valto + #error "both i_valto and i_valraw must be defined, if any" +#elif defined i_valfrom && !defined i_valraw + #error "i_valfrom defined without i_valraw" +#endif + +#if !defined i_valclone && (defined i_valdrop || defined i_valraw) + #define _i_no_clone +#endif +#ifndef i_valraw + #define i_valraw i_val +#endif +#ifndef i_valfrom + #define i_valfrom c_default_clone +#else + #define _i_has_from +#endif +#ifndef i_valto + #define i_valto c_default_toraw +#endif +#ifndef i_valclone + #define i_valclone c_default_clone +#endif +#ifndef i_valdrop + #define i_valdrop c_default_drop +#endif + +#endif // !_i_ismap + +#ifndef i_val + #define i_val i_key +#endif +#ifndef i_valraw + #define i_valraw i_keyraw +#endif +#ifndef _i_has_from + #define _i_no_emplace +#endif + +#else // ============================================================ + +#undef i_type +#undef i_tag +#undef i_imp +#undef i_opt +#undef i_less +#undef i_cmp +#undef i_eq +#undef i_hash +#undef i_size + +#undef i_val +#undef i_val_str +#undef i_val_ssv +#undef i_val_arcbox +#undef i_val_bind +#undef i_valraw +#undef i_valclone +#undef i_valfrom +#undef i_valto +#undef i_valdrop + +#undef i_key +#undef i_key_str +#undef i_key_ssv +#undef i_key_arcbox +#undef i_key_bind +#undef i_keyraw +#undef i_keyclone +#undef i_keyfrom +#undef i_keyto +#undef i_keydrop + +#undef i_header +#undef i_implement +#undef i_static +#undef i_extern + +#undef _i_prefix +#undef _i_has_from +#undef _i_key_from_val +#undef _i_no_clone +#undef _i_no_emplace +#undef _i_no_hash +#undef _i_template +#endif diff --git a/include/stc/utf8.h b/include/stc/utf8.h index 4910900c..b80d8594 100644 --- a/include/stc/utf8.h +++ b/include/stc/utf8.h @@ -1,95 +1,95 @@ -#ifndef UTF8_H_INCLUDED
-#define UTF8_H_INCLUDED
-/*
-// Example:
-#include <stc/cstr.h>
-#include <stc/csview.h>
-
-int main()
-{
- c_auto (cstr, s1) {
- s1 = cstr_new("hell😀 w😀rld");
- printf("%s\n", cstr_str(&s1));
- cstr_replace_sv(&s1, utf8_substr(cstr_str(&s1), 7, 1), c_sv("🐨"));
- printf("%s\n", cstr_str(&s1));
-
- c_foreach (i, cstr, s1)
- printf("%" c_PRIsv ",", c_ARGsv(i.chr));
- }
-}
-// Output:
-// hell😀 w😀rld
-// hell😀 w🐨rld
-// h,e,l,l,😀, ,w,🐨,r,l,d,
-*/
-#include "ccommon.h"
-#include <ctype.h>
-
-// utf8 methods defined in src/utf8code.c:
-bool utf8_islower(uint32_t c);
-bool utf8_isupper(uint32_t c);
-bool utf8_isspace(uint32_t c);
-bool utf8_isdigit(uint32_t c);
-bool utf8_isxdigit(uint32_t c);
-bool utf8_isalpha(uint32_t c);
-bool utf8_isalnum(uint32_t c);
-uint32_t utf8_tolower(uint32_t c);
-uint32_t utf8_toupper(uint32_t c);
-bool utf8_valid(const char* s);
-bool utf8_valid_n(const char* s, size_t n);
-int utf8_icmp_n(size_t u8max, const char* s1, size_t n1,
- const char* s2, size_t n2);
-unsigned utf8_encode(char *out, uint32_t c);
-
-/* decode next utf8 codepoint. https://bjoern.hoehrmann.de/utf-8/decoder/dfa */
-typedef struct { uint32_t state, codep; } utf8_decode_t;
-
-STC_INLINE uint32_t utf8_decode(utf8_decode_t* d, const uint32_t byte) {
- extern const uint8_t utf8_dtab[]; /* utf8code.c */
- const uint32_t type = utf8_dtab[byte];
- d->codep = d->state ? (byte & 0x3fu) | (d->codep << 6)
- : (0xff >> type) & byte;
- return d->state = utf8_dtab[256 + d->state + type];
-}
-
-/* case-insensitive utf8 string comparison */
-STC_INLINE int utf8_icmp(const char* s1, const char* s2) {
- return utf8_icmp_n(~(size_t)0, s1, ~(size_t)0, s2, ~(size_t)0);
-}
-
-/* number of characters in the utf8 codepoint from s */
-STC_INLINE unsigned utf8_codep_size(const char *s) {
- unsigned b = (uint8_t)*s;
- if (b < 0x80) return 1;
- if (b < 0xC2) return 0;
- if (b < 0xE0) return 2;
- if (b < 0xF0) return 3;
- if (b < 0xF5) return 4;
- return 0;
-}
-
-/* number of codepoints in the utf8 string s */
-STC_INLINE size_t utf8_size(const char *s) {
- size_t size = 0;
- while (*s)
- size += (*s++ & 0xC0) != 0x80;
- return size;
-}
-
-STC_INLINE size_t utf8_size_n(const char *s, size_t n) {
- size_t size = 0;
- while ((n-- != 0) & (*s != 0))
- size += (*s++ & 0xC0) != 0x80;
- return size;
-}
-
-STC_INLINE const char* utf8_at(const char *s, size_t index) {
- while ((index > 0) & (*s != 0))
- index -= (*++s & 0xC0) != 0x80;
- return s;
-}
-
-STC_INLINE size_t utf8_pos(const char* s, size_t index)
- { return utf8_at(s, index) - s; }
-
-#endif
+#ifndef UTF8_H_INCLUDED +#define UTF8_H_INCLUDED +/* +// Example: +#include <stc/cstr.h> +#include <stc/csview.h> + +int main() +{ + c_auto (cstr, s1) { + s1 = cstr_new("hell😀 w😀rld"); + printf("%s\n", cstr_str(&s1)); + cstr_replace_sv(&s1, utf8_substr(cstr_str(&s1), 7, 1), c_sv("🐨")); + printf("%s\n", cstr_str(&s1)); + + c_foreach (i, cstr, s1) + printf("%" c_PRIsv ",", c_ARGsv(i.chr)); + } +} +// Output: +// hell😀 w😀rld +// hell😀 w🐨rld +// h,e,l,l,😀, ,w,🐨,r,l,d, +*/ +#include "ccommon.h" +#include <ctype.h> + +// utf8 methods defined in src/utf8code.c: +bool utf8_islower(uint32_t c); +bool utf8_isupper(uint32_t c); +bool utf8_isspace(uint32_t c); +bool utf8_isdigit(uint32_t c); +bool utf8_isxdigit(uint32_t c); +bool utf8_isalpha(uint32_t c); +bool utf8_isalnum(uint32_t c); +uint32_t utf8_tolower(uint32_t c); +uint32_t utf8_toupper(uint32_t c); +bool utf8_valid(const char* s); +bool utf8_valid_n(const char* s, size_t n); +int utf8_icmp_n(size_t u8max, const char* s1, size_t n1, + const char* s2, size_t n2); +unsigned utf8_encode(char *out, uint32_t c); + +/* decode next utf8 codepoint. https://bjoern.hoehrmann.de/utf-8/decoder/dfa */ +typedef struct { uint32_t state, codep; } utf8_decode_t; + +STC_INLINE uint32_t utf8_decode(utf8_decode_t* d, const uint32_t byte) { + extern const uint8_t utf8_dtab[]; /* utf8code.c */ + const uint32_t type = utf8_dtab[byte]; + d->codep = d->state ? (byte & 0x3fu) | (d->codep << 6) + : (0xff >> type) & byte; + return d->state = utf8_dtab[256 + d->state + type]; +} + +/* case-insensitive utf8 string comparison */ +STC_INLINE int utf8_icmp(const char* s1, const char* s2) { + return utf8_icmp_n(~(size_t)0, s1, ~(size_t)0, s2, ~(size_t)0); +} + +/* number of characters in the utf8 codepoint from s */ +STC_INLINE unsigned utf8_codep_size(const char *s) { + unsigned b = (uint8_t)*s; + if (b < 0x80) return 1; + if (b < 0xC2) return 0; + if (b < 0xE0) return 2; + if (b < 0xF0) return 3; + if (b < 0xF5) return 4; + return 0; +} + +/* number of codepoints in the utf8 string s */ +STC_INLINE size_t utf8_size(const char *s) { + size_t size = 0; + while (*s) + size += (*s++ & 0xC0) != 0x80; + return size; +} + +STC_INLINE size_t utf8_size_n(const char *s, size_t n) { + size_t size = 0; + while ((n-- != 0) & (*s != 0)) + size += (*s++ & 0xC0) != 0x80; + return size; +} + +STC_INLINE const char* utf8_at(const char *s, size_t index) { + while ((index > 0) & (*s != 0)) + index -= (*++s & 0xC0) != 0x80; + return s; +} + +STC_INLINE size_t utf8_pos(const char* s, size_t index) + { return utf8_at(s, index) - s; } + +#endif diff --git a/src/cregex.c b/src/cregex.c index 7ca9a336..712056c4 100644 --- a/src/cregex.c +++ b/src/cregex.c @@ -1,1186 +1,1186 @@ -/*
-This is a Unix port of the Plan 9 regular expression library, by Rob Pike.
-Please send comments about the packaging to Russ Cox <[email protected]>.
-
-Copyright © 2021 Plan 9 Foundation
-Copyright © 2022 Tyge Løvset, for additions made in 2022.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <setjmp.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stc/cregex.h>
-#include <stc/utf8.h>
-
-typedef uint32_t Rune; /* Utf8 code point */
-typedef int32_t Token;
-/* max character classes per program */
-#define NCLASS creg_max_classes
-/* max subexpressions */
-#define NSUBEXP creg_max_captures
-/* max rune ranges per character class */
-#define NCCRUNE (NSUBEXP * 2)
-
-/*
- * character class, each pair of rune's defines a range
- */
-typedef struct
-{
- Rune *end;
- Rune spans[NCCRUNE];
-} Reclass;
-
-/*
- * Machine instructions
- */
-typedef struct Reinst
-{
- Token type;
- union {
- Reclass *classp; /* class pointer */
- Rune rune; /* character */
- int subid; /* sub-expression id for RBRA and LBRA */
- struct Reinst *right; /* right child of OR */
- } r;
- union { /* regexp relies on these two being in the same union */
- struct Reinst *left; /* left child of OR */
- struct Reinst *next; /* next instruction for CAT & LBRA */
- } l;
-} Reinst;
-
-typedef struct {
- bool caseless;
- bool dotall;
-} Reflags;
-
-/*
- * Reprogram definition
- */
-typedef struct Reprog
-{
- Reinst *startinst; /* start pc */
- Reflags flags;
- int nsubids;
- Reclass cclass[NCLASS]; /* .data */
- Reinst firstinst[]; /* .text : originally 5 elements? */
-} Reprog;
-
-/*
- * Sub expression matches
- */
-typedef cregmatch Resub;
-
-/*
- * substitution list
- */
-typedef struct Resublist
-{
- Resub m[NSUBEXP];
-} Resublist;
-
-/*
- * Actions and Tokens (Reinst types)
- *
- * 0x800000-0x80FFFF: operators, value => precedence
- * 0x810000-0x81FFFF: RUNE and char classes.
- * 0x820000-0x82FFFF: tokens, i.e. operands for operators
- */
-enum {
- MASK = 0xFF00000,
- OPERATOR = 0x8000000, /* Bitmask of all operators */
- START = 0x8000001, /* Start, used for marker on stack */
- RBRA , /* Right bracket, ) */
- LBRA , /* Left bracket, ( */
- OR , /* Alternation, | */
- CAT , /* Concatentation, implicit operator */
- STAR , /* Closure, * */
- PLUS , /* a+ == aa* */
- QUEST , /* a? == a|nothing, i.e. 0 or 1 a's */
- RUNE = 0x8100000,
- IRUNE,
- ASC_bl , ASC_BL, /* blank */
- ASC_ct , ASC_CT, /* ctrl */
- ASC_gr , ASC_GR, /* graphic */
- ASC_pr , ASC_PR, /* print */
- ASC_pt , ASC_PT, /* punct */
- U8_Nd , U8N_Nd, /* dec digit, non-digit */
- U8_LC , U8N_LC, /* utf8 letter cased */
- U8_Ll , U8N_Ll, /* utf8 letter lower */
- U8_Lu , U8N_Lu, /* utf8 letter upper */
- U8_Zs , U8N_Zs, /* utf8 white space */
- U8_Xnx , U8N_Xnx, /* utf8 hex digit */
- U8_Xan , U8N_Xan, /* utf8 alphanumeric */
- U8_Xw , U8N_Xw, /* utf8 word */
- ANY = 0x8200000, /* Any character except newline, . */
- ANYNL , /* Any character including newline, . */
- NOP , /* No operation, internal use only */
- BOL , BOS, /* Beginning of line, string, ^ */
- EOL , EOS, EOZ, /* End of line, string, $ */
- CCLASS , /* Character class, [] */
- NCCLASS , /* Negated character class, [] */
- WBOUND , /* Non-word boundary, not consuming meta char */
- NWBOUND , /* Word boundary, not consuming meta char */
- END = 0x82FFFFF, /* Terminate: match found */
-};
-
-/*
- * regexec execution lists
- */
-#define LISTSIZE 10
-#define BIGLISTSIZE (10*LISTSIZE)
-
-typedef struct Relist
-{
- Reinst* inst; /* Reinstruction of the thread */
- Resublist se; /* matched subexpressions in this thread */
-} Relist;
-
-typedef struct Reljunk
-{
- Relist* relist[2];
- Relist* reliste[2];
- int starttype;
- Rune startchar;
- const char* starts;
- const char* eol;
-} Reljunk;
-
-/*
- * utf8 and Rune code
- */
-
-static int
-chartorune(Rune *rune, const char *s)
-{
- utf8_decode_t ctx = {.state=0};
- const uint8_t *b = (const uint8_t*)s;
- do { utf8_decode(&ctx, *b++); } while (ctx.state);
- *rune = ctx.codep;
- return (const char*)b - s;
-}
-
-static const char*
-utfrune(const char *s, Rune c)
-{
- Rune r;
-
- if (c < 128) /* ascii */
- return strchr((char *)s, c);
-
- for (;;) {
- int n = chartorune(&r, s);
- if (r == c) return s;
- if ((r == 0) | (n == 0)) return NULL;
- s += n;
- }
-}
-
-static const char*
-utfruneicase(const char *s, Rune c)
-{
- Rune r;
- c = utf8_tolower(c);
- for (;;) {
- int n = chartorune(&r, s);
- if (utf8_tolower(r) == c) return s;
- if ((r == 0) | (n == 0)) return NULL;
- s += n;
- }
-}
-
-/************
- * regaux.c *
- ************/
-
-/*
- * save a new match in mp
- */
-static void
-_renewmatch(Resub *mp, int ms, Resublist *sp, int nsubids)
-{
- int i;
-
- if (mp==NULL || ms<=0)
- return;
- if (mp[0].str == NULL || sp->m[0].str < mp[0].str ||
- (sp->m[0].str == mp[0].str && sp->m[0].size > mp[0].size)) {
- for (i=0; i<ms && i<=nsubids; i++)
- mp[i] = sp->m[i];
- }
-}
-
-/*
- * Note optimization in _renewthread:
- * *lp must be pending when _renewthread called; if *l has been looked
- * at already, the optimization is a bug.
- */
-static Relist*
-_renewthread(Relist *lp, /* _relist to add to */
- Reinst *ip, /* instruction to add */
- int ms,
- Resublist *sep) /* pointers to subexpressions */
-{
- Relist *p;
-
- for (p=lp; p->inst; p++) {
- if (p->inst == ip) {
- if (sep->m[0].str < p->se.m[0].str) {
- if (ms > 1)
- p->se = *sep;
- else
- p->se.m[0] = sep->m[0];
- }
- return 0;
- }
- }
- p->inst = ip;
- if (ms > 1)
- p->se = *sep;
- else
- p->se.m[0] = sep->m[0];
- (++p)->inst = NULL;
- return p;
-}
-
-/*
- * same as renewthread, but called with
- * initial empty start pointer.
- */
-static Relist*
-_renewemptythread(Relist *lp, /* _relist to add to */
- Reinst *ip, /* instruction to add */
- int ms,
- const char *sp) /* pointers to subexpressions */
-{
- Relist *p;
-
- for (p=lp; p->inst; p++) {
- if (p->inst == ip) {
- if (sp < p->se.m[0].str) {
- if (ms > 1)
- memset(&p->se, 0, sizeof(p->se));
- p->se.m[0].str = sp;
- }
- return 0;
- }
- }
- p->inst = ip;
- if (ms > 1)
- memset(&p->se, 0, sizeof(p->se));
- p->se.m[0].str = sp;
- (++p)->inst = NULL;
- return p;
-}
-
-/*
- * Parser Information
- */
-typedef struct Node
-{
- Reinst* first;
- Reinst* last;
-} Node;
-
-#define NSTACK 20
-typedef struct Parser
-{
- const char* exprp; /* pointer to next character in source expression */
- Node andstack[NSTACK];
- Node* andp;
- Token atorstack[NSTACK];
- Token* atorp;
- short subidstack[NSTACK]; /* parallel to atorstack */
- short* subidp;
- short cursubid; /* id of current subexpression */
- int errors;
- Reflags flags;
- int dot_type;
- int rune_type;
- bool litmode;
- bool lastwasand; /* Last token was operand */
- bool lexdone;
- short nbra;
- short nclass;
- Rune yyrune; /* last lex'd rune */
- Reclass *yyclassp; /* last lex'd class */
- Reclass* classp;
- Reinst* freep;
- jmp_buf regkaboom;
-} Parser;
-
-/* predeclared crap */
-static void _operator(Parser *par, Token type);
-static void pushand(Parser *par, Reinst *first, Reinst *last);
-static void pushator(Parser *par, Token type);
-static void evaluntil(Parser *par, Token type);
-static int bldcclass(Parser *par);
-
-static void
-rcerror(Parser *par, cregex_error_t err)
-{
- par->errors = err;
- longjmp(par->regkaboom, 1);
-}
-
-static Reinst*
-newinst(Parser *par, Token t)
-{
- par->freep->type = t;
- par->freep->l.left = 0;
- par->freep->r.right = 0;
- return par->freep++;
-}
-
-static void
-operand(Parser *par, Token t)
-{
- Reinst *i;
-
- if (par->lastwasand)
- _operator(par, CAT); /* catenate is implicit */
- i = newinst(par, t);
-
- if ((t == CCLASS) | (t == NCCLASS))
- i->r.classp = par->yyclassp;
- if ((t == RUNE) | (t == IRUNE))
- i->r.rune = par->yyrune;
-
- pushand(par, i, i);
- par->lastwasand = true;
-}
-
-static void
-_operator(Parser *par, Token t)
-{
- if (t==RBRA && --par->nbra<0)
- rcerror(par, creg_unmatchedrightparenthesis);
- if (t==LBRA) {
- if (++par->cursubid >= NSUBEXP)
- rcerror(par, creg_toomanysubexpressions);
- par->nbra++;
- if (par->lastwasand)
- _operator(par, CAT);
- } else
- evaluntil(par, t);
- if (t != RBRA)
- pushator(par, t);
- par->lastwasand = 0;
- if (t==STAR || t==QUEST || t==PLUS || t==RBRA)
- par->lastwasand = true; /* these look like operands */
-}
-
-static void
-pushand(Parser *par, Reinst *f, Reinst *l)
-{
- if (par->andp >= &par->andstack[NSTACK])
- rcerror(par, creg_operandstackoverflow);
- par->andp->first = f;
- par->andp->last = l;
- par->andp++;
-}
-
-static void
-pushator(Parser *par, Token t)
-{
- if (par->atorp >= &par->atorstack[NSTACK])
- rcerror(par, creg_operatorstackoverflow);
- *par->atorp++ = t;
- *par->subidp++ = par->cursubid;
-}
-
-static Node*
-popand(Parser *par, Token op)
-{
- Reinst *inst;
-
- if (par->andp <= &par->andstack[0]) {
- rcerror(par, creg_missingoperand);
- inst = newinst(par, NOP);
- pushand(par, inst, inst);
- }
- return --par->andp;
-}
-
-static Token
-popator(Parser *par)
-{
- if (par->atorp <= &par->atorstack[0])
- rcerror(par, creg_operatorstackunderflow);
- --par->subidp;
- return *--par->atorp;
-}
-
-static void
-evaluntil(Parser *par, Token pri)
-{
- Node *op1, *op2;
- Reinst *inst1, *inst2;
-
- while (pri==RBRA || par->atorp[-1]>=pri) {
- switch (popator(par)) {
- default:
- rcerror(par, creg_unknownoperator);
- break;
- case LBRA: /* must have been RBRA */
- op1 = popand(par, '(');
- inst2 = newinst(par, RBRA);
- inst2->r.subid = *par->subidp;
- op1->last->l.next = inst2;
- inst1 = newinst(par, LBRA);
- inst1->r.subid = *par->subidp;
- inst1->l.next = op1->first;
- pushand(par, inst1, inst2);
- return;
- case OR:
- op2 = popand(par, '|');
- op1 = popand(par, '|');
- inst2 = newinst(par, NOP);
- op2->last->l.next = inst2;
- op1->last->l.next = inst2;
- inst1 = newinst(par, OR);
- inst1->r.right = op1->first;
- inst1->l.left = op2->first;
- pushand(par, inst1, inst2);
- break;
- case CAT:
- op2 = popand(par, 0);
- op1 = popand(par, 0);
- op1->last->l.next = op2->first;
- pushand(par, op1->first, op2->last);
- break;
- case STAR:
- op2 = popand(par, '*');
- inst1 = newinst(par, OR);
- op2->last->l.next = inst1;
- inst1->r.right = op2->first;
- pushand(par, inst1, inst1);
- break;
- case PLUS:
- op2 = popand(par, '+');
- inst1 = newinst(par, OR);
- op2->last->l.next = inst1;
- inst1->r.right = op2->first;
- pushand(par, op2->first, inst1);
- break;
- case QUEST:
- op2 = popand(par, '?');
- inst1 = newinst(par, OR);
- inst2 = newinst(par, NOP);
- inst1->l.left = inst2;
- inst1->r.right = op2->first;
- op2->last->l.next = inst2;
- pushand(par, inst1, inst2);
- break;
- }
- }
-}
-
-static Reprog*
-optimize(Parser *par, Reprog *pp)
-{
- Reinst *inst, *target;
- size_t size;
- Reprog *npp;
- Reclass *cl;
- ptrdiff_t diff;
-
- /*
- * get rid of NOOP chains
- */
- for (inst = pp->firstinst; inst->type != END; inst++) {
- target = inst->l.next;
- while (target->type == NOP)
- target = target->l.next;
- inst->l.next = target;
- }
-
- /*
- * The original allocation is for an area larger than
- * necessary. Reallocate to the actual space used
- * and then relocate the code.
- */
- size = sizeof(Reprog) + (par->freep - pp->firstinst)*sizeof(Reinst);
- npp = (Reprog *)realloc(pp, size);
- if (npp==NULL || npp==pp)
- return pp;
- diff = (char *)npp - (char *)pp;
- par->freep = (Reinst *)((char *)par->freep + diff);
- for (inst = npp->firstinst; inst < par->freep; inst++) {
- switch (inst->type) {
- case OR:
- case STAR:
- case PLUS:
- case QUEST:
- inst->r.right = (Reinst *)((char*)inst->r.right + diff);
- break;
- case CCLASS:
- case NCCLASS:
- inst->r.right = (Reinst *)((char*)inst->r.right + diff);
- cl = inst->r.classp;
- cl->end = (Rune *)((char*)cl->end + diff);
- break;
- }
- inst->l.left = (Reinst *)((char*)inst->l.left + diff);
- }
- npp->startinst = (Reinst *)((char*)npp->startinst + diff);
- return npp;
-}
-
-static Reclass*
-newclass(Parser *par)
-{
- if (par->nclass >= NCLASS)
- rcerror(par, creg_toomanycharacterclasses);
- return &(par->classp[par->nclass++]);
-}
-
-static int
-nextc(Parser *par, Rune *rp)
-{
- if (par->lexdone) {
- *rp = 0;
- return 1;
- }
- par->exprp += chartorune(rp, par->exprp);
- if (*rp == '\\') {
- if (par->litmode && *par->exprp != 'E')
- return 1;
- par->exprp += chartorune(rp, par->exprp);
- switch (*rp) {
- case 'E': return par->litmode + 1;
- case 't': *rp = '\t'; break;
- case 'n': *rp = '\n'; break;
- case 'r': *rp = '\r'; break;
- case 'v': *rp = '\v'; break;
- case 'f': *rp = '\f'; break;
- case 'd': *rp = U8_Nd; break;
- case 'D': *rp = U8N_Nd; break;
- case 's': *rp = U8_Zs; break;
- case 'S': *rp = U8N_Zs; break;
- case 'w': *rp = U8_Xw; break;
- case 'W': *rp = U8N_Xw; break;
- case 'x': if (*par->exprp != '{') break;
- *rp = 0; sscanf(++par->exprp, "%x", rp);
- while (*par->exprp) if (*(par->exprp++) == '}') break;
- if (par->exprp[-1] != '}')
- rcerror(par, creg_unmatchedrightparenthesis);
- return 2;
- case 'p': case 'P': { /* https://www.regular-expressions.info/unicode.html */
- static struct { const char* c; int n, r; } cls[] = {
- {"{Alpha}", 7, U8_LC}, {"{LC}", 4, U8_LC},
- {"{Alnum}", 7, U8_Xan},
- {"{Digit}", 7, U8_Nd}, {"{Nd}", 4, U8_Nd},
- {"{Lower}", 7, U8_Ll}, {"{Ll}", 4, U8_Ll},
- {"{Space}", 7, U8_Zs}, {"{Zs}", 4, U8_Zs},
- {"{Upper}", 7, U8_Lu}, {"{Lu}", 4, U8_Lu},
- {"{XDigit}", 8, U8_Xnx},
- {"{Blank}", 7, ASC_bl},
- {"{Graph}", 7, ASC_gr},
- {"{Print}", 7, ASC_pr},
- {"{Punct}", 7, ASC_pt},
- };
- int inv = *rp == 'P';
- for (unsigned i = 0; i < (sizeof cls/sizeof *cls); ++i)
- if (!strncmp(par->exprp, cls[i].c, cls[i].n)) {
- if (par->rune_type == IRUNE && (cls[i].r == U8_Ll || cls[i].r == U8_Lu))
- *rp = U8_LC + inv;
- else
- *rp = cls[i].r + inv;
- par->exprp += cls[i].n;
- break;
- }
- if (*rp < OPERATOR) {
- rcerror(par, creg_unknownoperator);
- *rp = 0;
- }
- break;
- }
- }
- return 1;
- }
- if (*rp == 0)
- par->lexdone = true;
- return par->litmode;
-}
-
-static Token
-lex(Parser *par)
-{
- int quoted;
- start:
- quoted = nextc(par, &par->yyrune);
- if (quoted) {
- if (quoted == 2) {
- if (par->litmode && par->yyrune == 'E') {
- par->litmode = false;
- goto start;
- }
- return par->yyrune == 0 ? END : par->rune_type;
- }
- switch (par->yyrune) {
- case 0 : return END;
- case 'b': return WBOUND;
- case 'B': return NWBOUND;
- case 'A': return BOS;
- case 'z': return EOS;
- case 'Z': return EOZ;
- case 'Q': par->litmode = true;
- goto start;
- default : return par->rune_type;
- }
- }
-
- switch (par->yyrune) {
- case 0 : return END;
- case '*': return STAR;
- case '?': return QUEST;
- case '+': return PLUS;
- case '|': return OR;
- case '.': return par->dot_type;
- case '(':
- if (par->exprp[0] == '?') {
- for (int k = 1, enable = 1; ; ++k) switch (par->exprp[k]) {
- case 0 : par->exprp += k; return END;
- case ')': par->exprp += k + 1; goto start;
- case '-': enable = 0; break;
- case 's': if (!par->flags.dotall) par->dot_type = ANY + enable; break;
- case 'i': if (!par->flags.caseless) par->rune_type = RUNE + enable; break;
- default: rcerror(par, creg_unknownoperator); return 0;
- }
- }
- return LBRA;
- case ')': return RBRA;
- case '^': return BOL;
- case '$': return EOL;
- case '[': return bldcclass(par);
- }
- return par->rune_type;
-}
-
-static Token
-bldcclass(Parser *par)
-{
- Token type;
- Rune r[NCCRUNE];
- Rune *p, *ep, *np;
- Rune rune;
- int quoted;
-
- /* we have already seen the '[' */
- type = CCLASS;
- par->yyclassp = newclass(par);
-
- /* look ahead for negation */
- /* SPECIAL CASE!!! negated classes don't match \n */
- ep = r;
- quoted = nextc(par, &rune);
- if (!quoted && rune == '^') {
- type = NCCLASS;
- quoted = nextc(par, &rune);
- *ep++ = '\n';
- *ep++ = '\n';
- }
-
- /* parse class into a set of spans */
- for (; ep < &r[NCCRUNE]; quoted = nextc(par, &rune)) {
- if (rune == 0) {
- rcerror(par, creg_malformedcharacterclass);
- return 0;
- }
- if (!quoted) {
- if (rune == ']')
- break;
- if (rune == '-') {
- if (ep != r && *par->exprp != ']') {
- quoted = nextc(par, &rune);
- if (rune == 0) {
- rcerror(par, creg_malformedcharacterclass);
- return 0;
- }
- ep[-1] = rune;
- continue;
- }
- }
- }
- *ep++ = rune;
- *ep++ = rune;
- }
-
- /* sort on span start */
- for (p = r; p < ep; p += 2) {
- for (np = p; np < ep; np += 2)
- if (*np < *p) {
- rune = np[0];
- np[0] = p[0];
- p[0] = rune;
- rune = np[1];
- np[1] = p[1];
- p[1] = rune;
- }
- }
-
- /* merge spans */
- np = par->yyclassp->spans;
- p = r;
- if (r == ep)
- par->yyclassp->end = np;
- else {
- np[0] = *p++;
- np[1] = *p++;
- for (; p < ep; p += 2)
- if (p[0] <= np[1]) {
- if (p[1] > np[1])
- np[1] = p[1];
- } else {
- np += 2;
- np[0] = p[0];
- np[1] = p[1];
- }
- par->yyclassp->end = np+2;
- }
-
- return type;
-}
-
-static Reprog*
-regcomp1(Parser *par, const char *s, int cflags)
-{
- Token token;
- Reprog *volatile pp;
-
- /* get memory for the program. estimated max usage */
- const int instcap = 5 + 6*strlen(s);
- pp = (Reprog *)malloc(sizeof(Reprog) + instcap*sizeof(Reinst));
- if (pp == NULL) {
- rcerror(par, creg_outofmemory);
- return NULL;
- }
- pp->flags.caseless = (cflags & creg_caseless) != 0;
- pp->flags.dotall = (cflags & creg_dotall) != 0;
- par->freep = pp->firstinst;
- par->classp = pp->cclass;
- par->errors = 0;
-
- if (setjmp(par->regkaboom))
- goto out;
-
- /* go compile the sucker */
- par->lexdone = false;
- par->flags = pp->flags;
- par->rune_type = pp->flags.caseless ? IRUNE : RUNE;
- par->dot_type = pp->flags.dotall ? ANYNL : ANY;
- par->litmode = false;
- par->exprp = s;
- par->nclass = 0;
- par->nbra = 0;
- par->atorp = par->atorstack;
- par->andp = par->andstack;
- par->subidp = par->subidstack;
- par->lastwasand = false;
- par->cursubid = 0;
-
- /* Start with a low priority operator to prime parser */
- pushator(par, START-1);
- while ((token = lex(par)) != END) {
- if ((token & MASK) == OPERATOR)
- _operator(par, token);
- else
- operand(par, token);
- }
-
- /* Close with a low priority operator */
- evaluntil(par, START);
-
- /* Force END */
- operand(par, END);
- evaluntil(par, START);
-#ifdef DEBUG
- dumpstack(par);
-#endif
- if (par->nbra)
- rcerror(par, creg_unmatchedleftparenthesis);
- --par->andp; /* points to first and only operand */
- pp->startinst = par->andp->first;
-#ifdef DEBUG
- dump(pp);
-#endif
- pp = optimize(par, pp);
- pp->nsubids = par->cursubid;
-#ifdef DEBUG
- print("start: %d\n", par->andp->first-pp->firstinst);
- dump(pp);
-#endif
-out:
- if (par->errors) {
- free(pp);
- pp = NULL;
- }
- return pp;
-}
-
-
-static int
-runematch(Rune s, Rune r, bool icase)
-{
- int inv = 0;
- switch (s) {
- case ASC_BL: inv = 1; /* fallthrough */
- case ASC_bl: return inv ^ ((r == ' ') | (r == '\t'));
- case ASC_CT: inv = 1;
- case ASC_ct: return inv ^ (iscntrl(r) != 0);
- case ASC_GR: inv = 1;
- case ASC_gr: return inv ^ (isgraph(r) != 0);
- case ASC_PR: inv = 1;
- case ASC_pr: return inv ^ (isprint(r) != 0);
- case ASC_PT: inv = 1;
- case ASC_pt: return inv ^ (ispunct(r) != 0);
- case U8N_Nd: inv = 1;
- case U8_Nd: return inv ^ (utf8_isdigit(r));
- case U8N_LC: inv = 1;
- case U8_LC: return inv ^ utf8_isalpha(r);
- case U8N_Ll: inv = 1;
- case U8_Ll: return inv ^ utf8_islower(r);
- case U8N_Lu: inv = 1;
- case U8_Lu: return inv ^ utf8_isupper(r);
- case U8N_Zs: inv = 1;
- case U8_Zs: return inv ^ utf8_isspace(r);
- case U8N_Xan: inv = 1;
- case U8_Xan: return inv ^ utf8_isalnum(r);
- case U8N_Xnx: inv = 1;
- case U8_Xnx: return inv ^ utf8_isxdigit(r);
- case U8N_Xw: inv = 1;
- case U8_Xw: return inv ^ (utf8_isalnum(r) | (r == '_'));
- }
- return icase ? utf8_tolower(s) == utf8_tolower(r) : s == r;
-}
-
-/*
- * return 0 if no match
- * >0 if a match
- * <0 if we ran out of _relist space
- */
-static int
-regexec1(const Reprog *progp, /* program to run */
- const char *bol, /* string to run machine on */
- Resub *mp, /* subexpression elements */
- int ms, /* number of elements at mp */
- Reljunk *j,
- int mflags
-)
-{
- int flag=0;
- Reinst *inst;
- Relist *tlp;
- Relist *tl, *nl; /* This list, next list */
- Relist *tle, *nle; /* Ends of this and next list */
- const char *s, *p;
- int i, n, checkstart;
- Rune r, *rp, *ep;
- int match = 0;
-
- bool icase = progp->flags.caseless;
- checkstart = j->starttype;
- if (mp)
- for (i=0; i<ms; i++) {
- mp[i].str = NULL;
- mp[i].size = 0;
- }
- j->relist[0][0].inst = NULL;
- j->relist[1][0].inst = NULL;
-
- /* Execute machine once for each character, including terminal NUL */
- s = j->starts;
- do {
- /* fast check for first char */
- if (checkstart) {
- switch (j->starttype) {
- case IRUNE:
- p = utfruneicase(s, j->startchar);
- goto next1;
- case RUNE:
- p = utfrune(s, j->startchar);
- next1:
- if (p == NULL || s == j->eol)
- return match;
- s = p;
- break;
- case BOL:
- if (s == bol)
- break;
- p = utfrune(s, '\n');
- if (p == NULL || s == j->eol)
- return match;
- s = p+1;
- break;
- }
- }
- n = chartorune(&r, s);
-
- /* switch run lists */
- tl = j->relist[flag];
- tle = j->reliste[flag];
- nl = j->relist[flag^=1];
- nle = j->reliste[flag];
- nl->inst = NULL;
-
- /* Add first instruction to current list */
- if (match == 0)
- _renewemptythread(tl, progp->startinst, ms, s);
-
- /* Execute machine until current list is empty */
- for (tlp=tl; tlp->inst; tlp++) { /* assignment = */
- for (inst = tlp->inst; ; inst = inst->l.next) {
- int ok = false;
-
- switch (inst->type) {
- case RUNE:
- case IRUNE: /* regular character */
- ok = runematch(inst->r.rune, r, (icase = inst->type==IRUNE));
- break;
- case LBRA:
- tlp->se.m[inst->r.subid].str = s;
- continue;
- case RBRA:
- tlp->se.m[inst->r.subid].size = s - tlp->se.m[inst->r.subid].str;
- continue;
- case ANY:
- ok = (r != '\n');
- break;
- case ANYNL:
- ok = true;
- break;
- case BOL:
- if (s == bol || s[-1] == '\n') continue;
- break;
- case BOS:
- if (s == bol) continue;
- break;
- case EOL:
- if (r == '\n') continue;
- case EOS: /* fallthrough */
- if (s == j->eol || r == 0) continue;
- break;
- case EOZ:
- if (s == j->eol || r == 0 || (r == '\n' && s[1] == 0)) continue;
- break;
- case NWBOUND:
- ok = true;
- case WBOUND: /* fallthrough */
- if (ok ^ (s == bol || s == j->eol || ((utf8_isalnum(s[-1]) || s[-1] == '_')
- ^ (utf8_isalnum(s[ 0]) || s[ 0] == '_'))))
- continue;
- break;
- case NCCLASS:
- ok = true;
- case CCLASS: /* fallthrough */
- ep = inst->r.classp->end;
- for (rp = inst->r.classp->spans; rp < ep; rp += 2) {
- if ((r >= rp[0] && r <= rp[1]) || (rp[0] == rp[1] && runematch(rp[0], r, icase)))
- break;
- }
- ok ^= (rp < ep);
- break;
- case OR:
- /* evaluate right choice later */
- if (_renewthread(tlp, inst->r.right, ms, &tlp->se) == tle)
- return -1;
- /* efficiency: advance and re-evaluate */
- continue;
- case END: /* Match! */
- match = !(mflags & creg_fullmatch) ||
- ((s == j->eol || r == 0 || r == '\n') &&
- (tlp->se.m[0].str == bol || tlp->se.m[0].str[-1] == '\n'));
- tlp->se.m[0].size = s - tlp->se.m[0].str;
- if (mp != NULL)
- _renewmatch(mp, ms, &tlp->se, progp->nsubids);
- break;
- }
-
- if (ok && _renewthread(nl, inst->l.next, ms, &tlp->se) == nle)
- return -1;
- break;
- }
- }
- if (s == j->eol)
- break;
- checkstart = j->starttype && nl->inst==NULL;
- s += n;
- } while (r);
- return match;
-}
-
-static int
-regexec2(const Reprog *progp, /* program to run */
- const char *bol, /* string to run machine on */
- Resub *mp, /* subexpression elements */
- int ms, /* number of elements at mp */
- Reljunk *j,
- int mflags
-)
-{
- int rv;
- Relist *relists;
-
- /* mark space */
- relists = (Relist *)malloc(2 * BIGLISTSIZE*sizeof(Relist));
- if (relists == NULL)
- return -1;
-
- j->relist[0] = relists;
- j->relist[1] = relists + BIGLISTSIZE;
- j->reliste[0] = relists + BIGLISTSIZE - 2;
- j->reliste[1] = relists + 2*BIGLISTSIZE - 2;
-
- rv = regexec1(progp, bol, mp, ms, j, mflags);
- free(relists);
- return rv;
-}
-
-static int
-regexec9(const Reprog *progp, /* program to run */
- const char *bol, /* string to run machine on */
- int ms, /* number of elements at mp */
- Resub mp[], /* subexpression elements */
- int mflags)
-{
- Reljunk j;
- Relist relist0[LISTSIZE], relist1[LISTSIZE];
- int rv;
-
- /*
- * use user-specified starting/ending location if specified
- */
- j.starts = bol;
- j.eol = NULL;
-
- if (mp && mp->str && ms>0) {
- if (mflags & creg_startend)
- j.starts = mp->str, j.eol = mp->str + mp->size;
- else if (mflags & creg_next)
- j.starts = mp->str + mp->size;
- }
-
- j.starttype = 0;
- j.startchar = 0;
- int rune_type = progp->flags.caseless ? IRUNE : RUNE;
- if (progp->startinst->type == rune_type && progp->startinst->r.rune < 128) {
- j.starttype = rune_type;
- j.startchar = progp->startinst->r.rune;
- }
- if (progp->startinst->type == BOL)
- j.starttype = BOL;
-
- /* mark space */
- j.relist[0] = relist0;
- j.relist[1] = relist1;
- j.reliste[0] = relist0 + LISTSIZE - 2;
- j.reliste[1] = relist1 + LISTSIZE - 2;
-
- rv = regexec1(progp, bol, mp, ms, &j, mflags);
- if (rv >= 0)
- return rv;
- rv = regexec2(progp, bol, mp, ms, &j, mflags);
- return rv;
-}
-
-/*
- * API functions
- */
-
-/* substitute into one string using the matches from the last regexec() */
-void cregex_replace(
- const char *sp, /* source string */
- char *dp, /* destination string */
- int dlen,
- int ms, /* number of elements pointed to by mp */
- const cregmatch mp[]) /* subexpression elements */
-{
- const char *ssp, *ep;
- int i;
-
- ep = dp+dlen-1;
- while (*sp != '\0') {
- if (*sp == '\\') {
- switch (*++sp) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- i = *sp - '0';
- if (mp[i].str != NULL && mp != NULL && ms > i)
- for (ssp = mp[i].str; ssp < (mp[i].str + mp[i].size); ssp++)
- if (dp < ep)
- *dp++ = *ssp;
- break;
- case '\\':
- if (dp < ep)
- *dp++ = '\\';
- break;
- case '\0':
- sp--;
- break;
- default:
- if (dp < ep)
- *dp++ = *sp;
- break;
- }
- } else if (*sp == '&') {
- if (mp[0].str != NULL && mp != NULL && ms > 0)
- for (ssp = mp[0].str; ssp < (mp[0].str + mp[0].size); ssp++)
- if (dp < ep)
- *dp++ = *ssp;
- } else {
- if (dp < ep)
- *dp++ = *sp;
- }
- sp++;
- }
- *dp = '\0';
-}
-
-int cregex_compile(cregex *rx, const char* pattern, int cflags) {
- Parser par;
- rx->prog = regcomp1(&par, pattern, cflags);
- if (rx->prog)
- return 1 + rx->prog->nsubids;
- return par.errors;
-}
-
-int cregex_captures(cregex rx) {
- return rx.prog ? 1 + rx.prog->nsubids : 0;
-}
-
-int cregex_find(const cregex *rx, const char* string,
- size_t nmatch, cregmatch match[], int mflags) {
- int res = regexec9(rx->prog, string, nmatch, match, mflags);
- switch (res) {
- case 1: return 1 + rx->prog->nsubids;
- case 0: return creg_nomatch;
- default: return creg_matcherror;
- }
-}
-
-void cregex_drop(cregex* self) {
- free(self->prog);
-}
+/* +This is a Unix port of the Plan 9 regular expression library, by Rob Pike. +Please send comments about the packaging to Russ Cox <[email protected]>. + +Copyright © 2021 Plan 9 Foundation +Copyright © 2022 Tyge Løvset, for additions made in 2022. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include <stdlib.h> +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> +#include <setjmp.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> +#include <stc/cregex.h> +#include <stc/utf8.h> + +typedef uint32_t Rune; /* Utf8 code point */ +typedef int32_t Token; +/* max character classes per program */ +#define NCLASS creg_max_classes +/* max subexpressions */ +#define NSUBEXP creg_max_captures +/* max rune ranges per character class */ +#define NCCRUNE (NSUBEXP * 2) + +/* + * character class, each pair of rune's defines a range + */ +typedef struct +{ + Rune *end; + Rune spans[NCCRUNE]; +} Reclass; + +/* + * Machine instructions + */ +typedef struct Reinst +{ + Token type; + union { + Reclass *classp; /* class pointer */ + Rune rune; /* character */ + int subid; /* sub-expression id for RBRA and LBRA */ + struct Reinst *right; /* right child of OR */ + } r; + union { /* regexp relies on these two being in the same union */ + struct Reinst *left; /* left child of OR */ + struct Reinst *next; /* next instruction for CAT & LBRA */ + } l; +} Reinst; + +typedef struct { + bool caseless; + bool dotall; +} Reflags; + +/* + * Reprogram definition + */ +typedef struct Reprog +{ + Reinst *startinst; /* start pc */ + Reflags flags; + int nsubids; + Reclass cclass[NCLASS]; /* .data */ + Reinst firstinst[]; /* .text : originally 5 elements? */ +} Reprog; + +/* + * Sub expression matches + */ +typedef cregmatch Resub; + +/* + * substitution list + */ +typedef struct Resublist +{ + Resub m[NSUBEXP]; +} Resublist; + +/* + * Actions and Tokens (Reinst types) + * + * 0x800000-0x80FFFF: operators, value => precedence + * 0x810000-0x81FFFF: RUNE and char classes. + * 0x820000-0x82FFFF: tokens, i.e. operands for operators + */ +enum { + MASK = 0xFF00000, + OPERATOR = 0x8000000, /* Bitmask of all operators */ + START = 0x8000001, /* Start, used for marker on stack */ + RBRA , /* Right bracket, ) */ + LBRA , /* Left bracket, ( */ + OR , /* Alternation, | */ + CAT , /* Concatentation, implicit operator */ + STAR , /* Closure, * */ + PLUS , /* a+ == aa* */ + QUEST , /* a? == a|nothing, i.e. 0 or 1 a's */ + RUNE = 0x8100000, + IRUNE, + ASC_bl , ASC_BL, /* blank */ + ASC_ct , ASC_CT, /* ctrl */ + ASC_gr , ASC_GR, /* graphic */ + ASC_pr , ASC_PR, /* print */ + ASC_pt , ASC_PT, /* punct */ + U8_Nd , U8N_Nd, /* dec digit, non-digit */ + U8_LC , U8N_LC, /* utf8 letter cased */ + U8_Ll , U8N_Ll, /* utf8 letter lower */ + U8_Lu , U8N_Lu, /* utf8 letter upper */ + U8_Zs , U8N_Zs, /* utf8 white space */ + U8_Xnx , U8N_Xnx, /* utf8 hex digit */ + U8_Xan , U8N_Xan, /* utf8 alphanumeric */ + U8_Xw , U8N_Xw, /* utf8 word */ + ANY = 0x8200000, /* Any character except newline, . */ + ANYNL , /* Any character including newline, . */ + NOP , /* No operation, internal use only */ + BOL , BOS, /* Beginning of line, string, ^ */ + EOL , EOS, EOZ, /* End of line, string, $ */ + CCLASS , /* Character class, [] */ + NCCLASS , /* Negated character class, [] */ + WBOUND , /* Non-word boundary, not consuming meta char */ + NWBOUND , /* Word boundary, not consuming meta char */ + END = 0x82FFFFF, /* Terminate: match found */ +}; + +/* + * regexec execution lists + */ +#define LISTSIZE 10 +#define BIGLISTSIZE (10*LISTSIZE) + +typedef struct Relist +{ + Reinst* inst; /* Reinstruction of the thread */ + Resublist se; /* matched subexpressions in this thread */ +} Relist; + +typedef struct Reljunk +{ + Relist* relist[2]; + Relist* reliste[2]; + int starttype; + Rune startchar; + const char* starts; + const char* eol; +} Reljunk; + +/* + * utf8 and Rune code + */ + +static int +chartorune(Rune *rune, const char *s) +{ + utf8_decode_t ctx = {.state=0}; + const uint8_t *b = (const uint8_t*)s; + do { utf8_decode(&ctx, *b++); } while (ctx.state); + *rune = ctx.codep; + return (const char*)b - s; +} + +static const char* +utfrune(const char *s, Rune c) +{ + Rune r; + + if (c < 128) /* ascii */ + return strchr((char *)s, c); + + for (;;) { + int n = chartorune(&r, s); + if (r == c) return s; + if ((r == 0) | (n == 0)) return NULL; + s += n; + } +} + +static const char* +utfruneicase(const char *s, Rune c) +{ + Rune r; + c = utf8_tolower(c); + for (;;) { + int n = chartorune(&r, s); + if (utf8_tolower(r) == c) return s; + if ((r == 0) | (n == 0)) return NULL; + s += n; + } +} + +/************ + * regaux.c * + ************/ + +/* + * save a new match in mp + */ +static void +_renewmatch(Resub *mp, int ms, Resublist *sp, int nsubids) +{ + int i; + + if (mp==NULL || ms<=0) + return; + if (mp[0].str == NULL || sp->m[0].str < mp[0].str || + (sp->m[0].str == mp[0].str && sp->m[0].size > mp[0].size)) { + for (i=0; i<ms && i<=nsubids; i++) + mp[i] = sp->m[i]; + } +} + +/* + * Note optimization in _renewthread: + * *lp must be pending when _renewthread called; if *l has been looked + * at already, the optimization is a bug. + */ +static Relist* +_renewthread(Relist *lp, /* _relist to add to */ + Reinst *ip, /* instruction to add */ + int ms, + Resublist *sep) /* pointers to subexpressions */ +{ + Relist *p; + + for (p=lp; p->inst; p++) { + if (p->inst == ip) { + if (sep->m[0].str < p->se.m[0].str) { + if (ms > 1) + p->se = *sep; + else + p->se.m[0] = sep->m[0]; + } + return 0; + } + } + p->inst = ip; + if (ms > 1) + p->se = *sep; + else + p->se.m[0] = sep->m[0]; + (++p)->inst = NULL; + return p; +} + +/* + * same as renewthread, but called with + * initial empty start pointer. + */ +static Relist* +_renewemptythread(Relist *lp, /* _relist to add to */ + Reinst *ip, /* instruction to add */ + int ms, + const char *sp) /* pointers to subexpressions */ +{ + Relist *p; + + for (p=lp; p->inst; p++) { + if (p->inst == ip) { + if (sp < p->se.m[0].str) { + if (ms > 1) + memset(&p->se, 0, sizeof(p->se)); + p->se.m[0].str = sp; + } + return 0; + } + } + p->inst = ip; + if (ms > 1) + memset(&p->se, 0, sizeof(p->se)); + p->se.m[0].str = sp; + (++p)->inst = NULL; + return p; +} + +/* + * Parser Information + */ +typedef struct Node +{ + Reinst* first; + Reinst* last; +} Node; + +#define NSTACK 20 +typedef struct Parser +{ + const char* exprp; /* pointer to next character in source expression */ + Node andstack[NSTACK]; + Node* andp; + Token atorstack[NSTACK]; + Token* atorp; + short subidstack[NSTACK]; /* parallel to atorstack */ + short* subidp; + short cursubid; /* id of current subexpression */ + int errors; + Reflags flags; + int dot_type; + int rune_type; + bool litmode; + bool lastwasand; /* Last token was operand */ + bool lexdone; + short nbra; + short nclass; + Rune yyrune; /* last lex'd rune */ + Reclass *yyclassp; /* last lex'd class */ + Reclass* classp; + Reinst* freep; + jmp_buf regkaboom; +} Parser; + +/* predeclared crap */ +static void _operator(Parser *par, Token type); +static void pushand(Parser *par, Reinst *first, Reinst *last); +static void pushator(Parser *par, Token type); +static void evaluntil(Parser *par, Token type); +static int bldcclass(Parser *par); + +static void +rcerror(Parser *par, cregex_error_t err) +{ + par->errors = err; + longjmp(par->regkaboom, 1); +} + +static Reinst* +newinst(Parser *par, Token t) +{ + par->freep->type = t; + par->freep->l.left = 0; + par->freep->r.right = 0; + return par->freep++; +} + +static void +operand(Parser *par, Token t) +{ + Reinst *i; + + if (par->lastwasand) + _operator(par, CAT); /* catenate is implicit */ + i = newinst(par, t); + + if ((t == CCLASS) | (t == NCCLASS)) + i->r.classp = par->yyclassp; + if ((t == RUNE) | (t == IRUNE)) + i->r.rune = par->yyrune; + + pushand(par, i, i); + par->lastwasand = true; +} + +static void +_operator(Parser *par, Token t) +{ + if (t==RBRA && --par->nbra<0) + rcerror(par, creg_unmatchedrightparenthesis); + if (t==LBRA) { + if (++par->cursubid >= NSUBEXP) + rcerror(par, creg_toomanysubexpressions); + par->nbra++; + if (par->lastwasand) + _operator(par, CAT); + } else + evaluntil(par, t); + if (t != RBRA) + pushator(par, t); + par->lastwasand = 0; + if (t==STAR || t==QUEST || t==PLUS || t==RBRA) + par->lastwasand = true; /* these look like operands */ +} + +static void +pushand(Parser *par, Reinst *f, Reinst *l) +{ + if (par->andp >= &par->andstack[NSTACK]) + rcerror(par, creg_operandstackoverflow); + par->andp->first = f; + par->andp->last = l; + par->andp++; +} + +static void +pushator(Parser *par, Token t) +{ + if (par->atorp >= &par->atorstack[NSTACK]) + rcerror(par, creg_operatorstackoverflow); + *par->atorp++ = t; + *par->subidp++ = par->cursubid; +} + +static Node* +popand(Parser *par, Token op) +{ + Reinst *inst; + + if (par->andp <= &par->andstack[0]) { + rcerror(par, creg_missingoperand); + inst = newinst(par, NOP); + pushand(par, inst, inst); + } + return --par->andp; +} + +static Token +popator(Parser *par) +{ + if (par->atorp <= &par->atorstack[0]) + rcerror(par, creg_operatorstackunderflow); + --par->subidp; + return *--par->atorp; +} + +static void +evaluntil(Parser *par, Token pri) +{ + Node *op1, *op2; + Reinst *inst1, *inst2; + + while (pri==RBRA || par->atorp[-1]>=pri) { + switch (popator(par)) { + default: + rcerror(par, creg_unknownoperator); + break; + case LBRA: /* must have been RBRA */ + op1 = popand(par, '('); + inst2 = newinst(par, RBRA); + inst2->r.subid = *par->subidp; + op1->last->l.next = inst2; + inst1 = newinst(par, LBRA); + inst1->r.subid = *par->subidp; + inst1->l.next = op1->first; + pushand(par, inst1, inst2); + return; + case OR: + op2 = popand(par, '|'); + op1 = popand(par, '|'); + inst2 = newinst(par, NOP); + op2->last->l.next = inst2; + op1->last->l.next = inst2; + inst1 = newinst(par, OR); + inst1->r.right = op1->first; + inst1->l.left = op2->first; + pushand(par, inst1, inst2); + break; + case CAT: + op2 = popand(par, 0); + op1 = popand(par, 0); + op1->last->l.next = op2->first; + pushand(par, op1->first, op2->last); + break; + case STAR: + op2 = popand(par, '*'); + inst1 = newinst(par, OR); + op2->last->l.next = inst1; + inst1->r.right = op2->first; + pushand(par, inst1, inst1); + break; + case PLUS: + op2 = popand(par, '+'); + inst1 = newinst(par, OR); + op2->last->l.next = inst1; + inst1->r.right = op2->first; + pushand(par, op2->first, inst1); + break; + case QUEST: + op2 = popand(par, '?'); + inst1 = newinst(par, OR); + inst2 = newinst(par, NOP); + inst1->l.left = inst2; + inst1->r.right = op2->first; + op2->last->l.next = inst2; + pushand(par, inst1, inst2); + break; + } + } +} + +static Reprog* +optimize(Parser *par, Reprog *pp) +{ + Reinst *inst, *target; + size_t size; + Reprog *npp; + Reclass *cl; + ptrdiff_t diff; + + /* + * get rid of NOOP chains + */ + for (inst = pp->firstinst; inst->type != END; inst++) { + target = inst->l.next; + while (target->type == NOP) + target = target->l.next; + inst->l.next = target; + } + + /* + * The original allocation is for an area larger than + * necessary. Reallocate to the actual space used + * and then relocate the code. + */ + size = sizeof(Reprog) + (par->freep - pp->firstinst)*sizeof(Reinst); + npp = (Reprog *)realloc(pp, size); + if (npp==NULL || npp==pp) + return pp; + diff = (char *)npp - (char *)pp; + par->freep = (Reinst *)((char *)par->freep + diff); + for (inst = npp->firstinst; inst < par->freep; inst++) { + switch (inst->type) { + case OR: + case STAR: + case PLUS: + case QUEST: + inst->r.right = (Reinst *)((char*)inst->r.right + diff); + break; + case CCLASS: + case NCCLASS: + inst->r.right = (Reinst *)((char*)inst->r.right + diff); + cl = inst->r.classp; + cl->end = (Rune *)((char*)cl->end + diff); + break; + } + inst->l.left = (Reinst *)((char*)inst->l.left + diff); + } + npp->startinst = (Reinst *)((char*)npp->startinst + diff); + return npp; +} + +static Reclass* +newclass(Parser *par) +{ + if (par->nclass >= NCLASS) + rcerror(par, creg_toomanycharacterclasses); + return &(par->classp[par->nclass++]); +} + +static int +nextc(Parser *par, Rune *rp) +{ + if (par->lexdone) { + *rp = 0; + return 1; + } + par->exprp += chartorune(rp, par->exprp); + if (*rp == '\\') { + if (par->litmode && *par->exprp != 'E') + return 1; + par->exprp += chartorune(rp, par->exprp); + switch (*rp) { + case 'E': return par->litmode + 1; + case 't': *rp = '\t'; break; + case 'n': *rp = '\n'; break; + case 'r': *rp = '\r'; break; + case 'v': *rp = '\v'; break; + case 'f': *rp = '\f'; break; + case 'd': *rp = U8_Nd; break; + case 'D': *rp = U8N_Nd; break; + case 's': *rp = U8_Zs; break; + case 'S': *rp = U8N_Zs; break; + case 'w': *rp = U8_Xw; break; + case 'W': *rp = U8N_Xw; break; + case 'x': if (*par->exprp != '{') break; + *rp = 0; sscanf(++par->exprp, "%x", rp); + while (*par->exprp) if (*(par->exprp++) == '}') break; + if (par->exprp[-1] != '}') + rcerror(par, creg_unmatchedrightparenthesis); + return 2; + case 'p': case 'P': { /* https://www.regular-expressions.info/unicode.html */ + static struct { const char* c; int n, r; } cls[] = { + {"{Alpha}", 7, U8_LC}, {"{LC}", 4, U8_LC}, + {"{Alnum}", 7, U8_Xan}, + {"{Digit}", 7, U8_Nd}, {"{Nd}", 4, U8_Nd}, + {"{Lower}", 7, U8_Ll}, {"{Ll}", 4, U8_Ll}, + {"{Space}", 7, U8_Zs}, {"{Zs}", 4, U8_Zs}, + {"{Upper}", 7, U8_Lu}, {"{Lu}", 4, U8_Lu}, + {"{XDigit}", 8, U8_Xnx}, + {"{Blank}", 7, ASC_bl}, + {"{Graph}", 7, ASC_gr}, + {"{Print}", 7, ASC_pr}, + {"{Punct}", 7, ASC_pt}, + }; + int inv = *rp == 'P'; + for (unsigned i = 0; i < (sizeof cls/sizeof *cls); ++i) + if (!strncmp(par->exprp, cls[i].c, cls[i].n)) { + if (par->rune_type == IRUNE && (cls[i].r == U8_Ll || cls[i].r == U8_Lu)) + *rp = U8_LC + inv; + else + *rp = cls[i].r + inv; + par->exprp += cls[i].n; + break; + } + if (*rp < OPERATOR) { + rcerror(par, creg_unknownoperator); + *rp = 0; + } + break; + } + } + return 1; + } + if (*rp == 0) + par->lexdone = true; + return par->litmode; +} + +static Token +lex(Parser *par) +{ + int quoted; + start: + quoted = nextc(par, &par->yyrune); + if (quoted) { + if (quoted == 2) { + if (par->litmode && par->yyrune == 'E') { + par->litmode = false; + goto start; + } + return par->yyrune == 0 ? END : par->rune_type; + } + switch (par->yyrune) { + case 0 : return END; + case 'b': return WBOUND; + case 'B': return NWBOUND; + case 'A': return BOS; + case 'z': return EOS; + case 'Z': return EOZ; + case 'Q': par->litmode = true; + goto start; + default : return par->rune_type; + } + } + + switch (par->yyrune) { + case 0 : return END; + case '*': return STAR; + case '?': return QUEST; + case '+': return PLUS; + case '|': return OR; + case '.': return par->dot_type; + case '(': + if (par->exprp[0] == '?') { + for (int k = 1, enable = 1; ; ++k) switch (par->exprp[k]) { + case 0 : par->exprp += k; return END; + case ')': par->exprp += k + 1; goto start; + case '-': enable = 0; break; + case 's': if (!par->flags.dotall) par->dot_type = ANY + enable; break; + case 'i': if (!par->flags.caseless) par->rune_type = RUNE + enable; break; + default: rcerror(par, creg_unknownoperator); return 0; + } + } + return LBRA; + case ')': return RBRA; + case '^': return BOL; + case '$': return EOL; + case '[': return bldcclass(par); + } + return par->rune_type; +} + +static Token +bldcclass(Parser *par) +{ + Token type; + Rune r[NCCRUNE]; + Rune *p, *ep, *np; + Rune rune; + int quoted; + + /* we have already seen the '[' */ + type = CCLASS; + par->yyclassp = newclass(par); + + /* look ahead for negation */ + /* SPECIAL CASE!!! negated classes don't match \n */ + ep = r; + quoted = nextc(par, &rune); + if (!quoted && rune == '^') { + type = NCCLASS; + quoted = nextc(par, &rune); + *ep++ = '\n'; + *ep++ = '\n'; + } + + /* parse class into a set of spans */ + for (; ep < &r[NCCRUNE]; quoted = nextc(par, &rune)) { + if (rune == 0) { + rcerror(par, creg_malformedcharacterclass); + return 0; + } + if (!quoted) { + if (rune == ']') + break; + if (rune == '-') { + if (ep != r && *par->exprp != ']') { + quoted = nextc(par, &rune); + if (rune == 0) { + rcerror(par, creg_malformedcharacterclass); + return 0; + } + ep[-1] = rune; + continue; + } + } + } + *ep++ = rune; + *ep++ = rune; + } + + /* sort on span start */ + for (p = r; p < ep; p += 2) { + for (np = p; np < ep; np += 2) + if (*np < *p) { + rune = np[0]; + np[0] = p[0]; + p[0] = rune; + rune = np[1]; + np[1] = p[1]; + p[1] = rune; + } + } + + /* merge spans */ + np = par->yyclassp->spans; + p = r; + if (r == ep) + par->yyclassp->end = np; + else { + np[0] = *p++; + np[1] = *p++; + for (; p < ep; p += 2) + if (p[0] <= np[1]) { + if (p[1] > np[1]) + np[1] = p[1]; + } else { + np += 2; + np[0] = p[0]; + np[1] = p[1]; + } + par->yyclassp->end = np+2; + } + + return type; +} + +static Reprog* +regcomp1(Parser *par, const char *s, int cflags) +{ + Token token; + Reprog *volatile pp; + + /* get memory for the program. estimated max usage */ + const int instcap = 5 + 6*strlen(s); + pp = (Reprog *)malloc(sizeof(Reprog) + instcap*sizeof(Reinst)); + if (pp == NULL) { + rcerror(par, creg_outofmemory); + return NULL; + } + pp->flags.caseless = (cflags & creg_caseless) != 0; + pp->flags.dotall = (cflags & creg_dotall) != 0; + par->freep = pp->firstinst; + par->classp = pp->cclass; + par->errors = 0; + + if (setjmp(par->regkaboom)) + goto out; + + /* go compile the sucker */ + par->lexdone = false; + par->flags = pp->flags; + par->rune_type = pp->flags.caseless ? IRUNE : RUNE; + par->dot_type = pp->flags.dotall ? ANYNL : ANY; + par->litmode = false; + par->exprp = s; + par->nclass = 0; + par->nbra = 0; + par->atorp = par->atorstack; + par->andp = par->andstack; + par->subidp = par->subidstack; + par->lastwasand = false; + par->cursubid = 0; + + /* Start with a low priority operator to prime parser */ + pushator(par, START-1); + while ((token = lex(par)) != END) { + if ((token & MASK) == OPERATOR) + _operator(par, token); + else + operand(par, token); + } + + /* Close with a low priority operator */ + evaluntil(par, START); + + /* Force END */ + operand(par, END); + evaluntil(par, START); +#ifdef DEBUG + dumpstack(par); +#endif + if (par->nbra) + rcerror(par, creg_unmatchedleftparenthesis); + --par->andp; /* points to first and only operand */ + pp->startinst = par->andp->first; +#ifdef DEBUG + dump(pp); +#endif + pp = optimize(par, pp); + pp->nsubids = par->cursubid; +#ifdef DEBUG + print("start: %d\n", par->andp->first-pp->firstinst); + dump(pp); +#endif +out: + if (par->errors) { + free(pp); + pp = NULL; + } + return pp; +} + + +static int +runematch(Rune s, Rune r, bool icase) +{ + int inv = 0; + switch (s) { + case ASC_BL: inv = 1; /* fallthrough */ + case ASC_bl: return inv ^ ((r == ' ') | (r == '\t')); + case ASC_CT: inv = 1; + case ASC_ct: return inv ^ (iscntrl(r) != 0); + case ASC_GR: inv = 1; + case ASC_gr: return inv ^ (isgraph(r) != 0); + case ASC_PR: inv = 1; + case ASC_pr: return inv ^ (isprint(r) != 0); + case ASC_PT: inv = 1; + case ASC_pt: return inv ^ (ispunct(r) != 0); + case U8N_Nd: inv = 1; + case U8_Nd: return inv ^ (utf8_isdigit(r)); + case U8N_LC: inv = 1; + case U8_LC: return inv ^ utf8_isalpha(r); + case U8N_Ll: inv = 1; + case U8_Ll: return inv ^ utf8_islower(r); + case U8N_Lu: inv = 1; + case U8_Lu: return inv ^ utf8_isupper(r); + case U8N_Zs: inv = 1; + case U8_Zs: return inv ^ utf8_isspace(r); + case U8N_Xan: inv = 1; + case U8_Xan: return inv ^ utf8_isalnum(r); + case U8N_Xnx: inv = 1; + case U8_Xnx: return inv ^ utf8_isxdigit(r); + case U8N_Xw: inv = 1; + case U8_Xw: return inv ^ (utf8_isalnum(r) | (r == '_')); + } + return icase ? utf8_tolower(s) == utf8_tolower(r) : s == r; +} + +/* + * return 0 if no match + * >0 if a match + * <0 if we ran out of _relist space + */ +static int +regexec1(const Reprog *progp, /* program to run */ + const char *bol, /* string to run machine on */ + Resub *mp, /* subexpression elements */ + int ms, /* number of elements at mp */ + Reljunk *j, + int mflags +) +{ + int flag=0; + Reinst *inst; + Relist *tlp; + Relist *tl, *nl; /* This list, next list */ + Relist *tle, *nle; /* Ends of this and next list */ + const char *s, *p; + int i, n, checkstart; + Rune r, *rp, *ep; + int match = 0; + + bool icase = progp->flags.caseless; + checkstart = j->starttype; + if (mp) + for (i=0; i<ms; i++) { + mp[i].str = NULL; + mp[i].size = 0; + } + j->relist[0][0].inst = NULL; + j->relist[1][0].inst = NULL; + + /* Execute machine once for each character, including terminal NUL */ + s = j->starts; + do { + /* fast check for first char */ + if (checkstart) { + switch (j->starttype) { + case IRUNE: + p = utfruneicase(s, j->startchar); + goto next1; + case RUNE: + p = utfrune(s, j->startchar); + next1: + if (p == NULL || s == j->eol) + return match; + s = p; + break; + case BOL: + if (s == bol) + break; + p = utfrune(s, '\n'); + if (p == NULL || s == j->eol) + return match; + s = p+1; + break; + } + } + n = chartorune(&r, s); + + /* switch run lists */ + tl = j->relist[flag]; + tle = j->reliste[flag]; + nl = j->relist[flag^=1]; + nle = j->reliste[flag]; + nl->inst = NULL; + + /* Add first instruction to current list */ + if (match == 0) + _renewemptythread(tl, progp->startinst, ms, s); + + /* Execute machine until current list is empty */ + for (tlp=tl; tlp->inst; tlp++) { /* assignment = */ + for (inst = tlp->inst; ; inst = inst->l.next) { + int ok = false; + + switch (inst->type) { + case RUNE: + case IRUNE: /* regular character */ + ok = runematch(inst->r.rune, r, (icase = inst->type==IRUNE)); + break; + case LBRA: + tlp->se.m[inst->r.subid].str = s; + continue; + case RBRA: + tlp->se.m[inst->r.subid].size = s - tlp->se.m[inst->r.subid].str; + continue; + case ANY: + ok = (r != '\n'); + break; + case ANYNL: + ok = true; + break; + case BOL: + if (s == bol || s[-1] == '\n') continue; + break; + case BOS: + if (s == bol) continue; + break; + case EOL: + if (r == '\n') continue; + case EOS: /* fallthrough */ + if (s == j->eol || r == 0) continue; + break; + case EOZ: + if (s == j->eol || r == 0 || (r == '\n' && s[1] == 0)) continue; + break; + case NWBOUND: + ok = true; + case WBOUND: /* fallthrough */ + if (ok ^ (s == bol || s == j->eol || ((utf8_isalnum(s[-1]) || s[-1] == '_') + ^ (utf8_isalnum(s[ 0]) || s[ 0] == '_')))) + continue; + break; + case NCCLASS: + ok = true; + case CCLASS: /* fallthrough */ + ep = inst->r.classp->end; + for (rp = inst->r.classp->spans; rp < ep; rp += 2) { + if ((r >= rp[0] && r <= rp[1]) || (rp[0] == rp[1] && runematch(rp[0], r, icase))) + break; + } + ok ^= (rp < ep); + break; + case OR: + /* evaluate right choice later */ + if (_renewthread(tlp, inst->r.right, ms, &tlp->se) == tle) + return -1; + /* efficiency: advance and re-evaluate */ + continue; + case END: /* Match! */ + match = !(mflags & creg_fullmatch) || + ((s == j->eol || r == 0 || r == '\n') && + (tlp->se.m[0].str == bol || tlp->se.m[0].str[-1] == '\n')); + tlp->se.m[0].size = s - tlp->se.m[0].str; + if (mp != NULL) + _renewmatch(mp, ms, &tlp->se, progp->nsubids); + break; + } + + if (ok && _renewthread(nl, inst->l.next, ms, &tlp->se) == nle) + return -1; + break; + } + } + if (s == j->eol) + break; + checkstart = j->starttype && nl->inst==NULL; + s += n; + } while (r); + return match; +} + +static int +regexec2(const Reprog *progp, /* program to run */ + const char *bol, /* string to run machine on */ + Resub *mp, /* subexpression elements */ + int ms, /* number of elements at mp */ + Reljunk *j, + int mflags +) +{ + int rv; + Relist *relists; + + /* mark space */ + relists = (Relist *)malloc(2 * BIGLISTSIZE*sizeof(Relist)); + if (relists == NULL) + return -1; + + j->relist[0] = relists; + j->relist[1] = relists + BIGLISTSIZE; + j->reliste[0] = relists + BIGLISTSIZE - 2; + j->reliste[1] = relists + 2*BIGLISTSIZE - 2; + + rv = regexec1(progp, bol, mp, ms, j, mflags); + free(relists); + return rv; +} + +static int +regexec9(const Reprog *progp, /* program to run */ + const char *bol, /* string to run machine on */ + int ms, /* number of elements at mp */ + Resub mp[], /* subexpression elements */ + int mflags) +{ + Reljunk j; + Relist relist0[LISTSIZE], relist1[LISTSIZE]; + int rv; + + /* + * use user-specified starting/ending location if specified + */ + j.starts = bol; + j.eol = NULL; + + if (mp && mp->str && ms>0) { + if (mflags & creg_startend) + j.starts = mp->str, j.eol = mp->str + mp->size; + else if (mflags & creg_next) + j.starts = mp->str + mp->size; + } + + j.starttype = 0; + j.startchar = 0; + int rune_type = progp->flags.caseless ? IRUNE : RUNE; + if (progp->startinst->type == rune_type && progp->startinst->r.rune < 128) { + j.starttype = rune_type; + j.startchar = progp->startinst->r.rune; + } + if (progp->startinst->type == BOL) + j.starttype = BOL; + + /* mark space */ + j.relist[0] = relist0; + j.relist[1] = relist1; + j.reliste[0] = relist0 + LISTSIZE - 2; + j.reliste[1] = relist1 + LISTSIZE - 2; + + rv = regexec1(progp, bol, mp, ms, &j, mflags); + if (rv >= 0) + return rv; + rv = regexec2(progp, bol, mp, ms, &j, mflags); + return rv; +} + +/* + * API functions + */ + +/* substitute into one string using the matches from the last regexec() */ +void cregex_replace( + const char *sp, /* source string */ + char *dp, /* destination string */ + int dlen, + int ms, /* number of elements pointed to by mp */ + const cregmatch mp[]) /* subexpression elements */ +{ + const char *ssp, *ep; + int i; + + ep = dp+dlen-1; + while (*sp != '\0') { + if (*sp == '\\') { + switch (*++sp) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + i = *sp - '0'; + if (mp[i].str != NULL && mp != NULL && ms > i) + for (ssp = mp[i].str; ssp < (mp[i].str + mp[i].size); ssp++) + if (dp < ep) + *dp++ = *ssp; + break; + case '\\': + if (dp < ep) + *dp++ = '\\'; + break; + case '\0': + sp--; + break; + default: + if (dp < ep) + *dp++ = *sp; + break; + } + } else if (*sp == '&') { + if (mp[0].str != NULL && mp != NULL && ms > 0) + for (ssp = mp[0].str; ssp < (mp[0].str + mp[0].size); ssp++) + if (dp < ep) + *dp++ = *ssp; + } else { + if (dp < ep) + *dp++ = *sp; + } + sp++; + } + *dp = '\0'; +} + +int cregex_compile(cregex *rx, const char* pattern, int cflags) { + Parser par; + rx->prog = regcomp1(&par, pattern, cflags); + if (rx->prog) + return 1 + rx->prog->nsubids; + return par.errors; +} + +int cregex_captures(cregex rx) { + return rx.prog ? 1 + rx.prog->nsubids : 0; +} + +int cregex_find(const cregex *rx, const char* string, + size_t nmatch, cregmatch match[], int mflags) { + int res = regexec9(rx->prog, string, nmatch, match, mflags); + switch (res) { + case 1: return 1 + rx->prog->nsubids; + case 0: return creg_nomatch; + default: return creg_matcherror; + } +} + +void cregex_drop(cregex* self) { + free(self->prog); +} |
