summaryrefslogtreecommitdiffhomepage
path: root/include
diff options
context:
space:
mode:
authorTyge Løvset <[email protected]>2022-06-01 16:28:07 +0200
committerTyge Løvset <[email protected]>2022-06-01 16:28:07 +0200
commitde629774cb912aa3d563f24d99258142713c3fcd (patch)
treec37e2851d6cb049bc0863a59b6ecf5945fb88619 /include
parent7fb43a24a17da787dd809114ca26c1231b058493 (diff)
downloadSTC-modified-de629774cb912aa3d563f24d99258142713c3fcd.tar.gz
STC-modified-de629774cb912aa3d563f24d99258142713c3fcd.zip
Converted all files with DOS line endings to LINUX.
Diffstat (limited to 'include')
-rw-r--r--include/stc/alt/csmap.h1024
-rw-r--r--include/stc/alt/cstr.h778
-rw-r--r--include/stc/carc.h398
-rw-r--r--include/stc/cbits.h656
-rw-r--r--include/stc/cbox.h364
-rw-r--r--include/stc/ccommon.h538
-rw-r--r--include/stc/cdeq.h874
-rw-r--r--include/stc/clist.h848
-rw-r--r--include/stc/cmap.h846
-rw-r--r--include/stc/cpque.h314
-rw-r--r--include/stc/cqueue.h130
-rw-r--r--include/stc/crandom.h388
-rw-r--r--include/stc/cregex.h180
-rw-r--r--include/stc/cset.h92
-rw-r--r--include/stc/csmap.h1188
-rw-r--r--include/stc/csset.h98
-rw-r--r--include/stc/cstack.h300
-rw-r--r--include/stc/cstr.h1110
-rw-r--r--include/stc/csview.h438
-rw-r--r--include/stc/cvec.h872
-rw-r--r--include/stc/forward.h414
-rw-r--r--include/stc/template.h592
-rw-r--r--include/stc/utf8.h190
23 files changed, 6316 insertions, 6316 deletions
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