diff options
| author | Tyge Løvset <[email protected]> | 2022-06-01 16:28:07 +0200 |
|---|---|---|
| committer | Tyge Løvset <[email protected]> | 2022-06-01 16:28:07 +0200 |
| commit | de629774cb912aa3d563f24d99258142713c3fcd (patch) | |
| tree | c37e2851d6cb049bc0863a59b6ecf5945fb88619 /include | |
| parent | 7fb43a24a17da787dd809114ca26c1231b058493 (diff) | |
| download | STC-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.h | 1024 | ||||
| -rw-r--r-- | include/stc/alt/cstr.h | 778 | ||||
| -rw-r--r-- | include/stc/carc.h | 398 | ||||
| -rw-r--r-- | include/stc/cbits.h | 656 | ||||
| -rw-r--r-- | include/stc/cbox.h | 364 | ||||
| -rw-r--r-- | include/stc/ccommon.h | 538 | ||||
| -rw-r--r-- | include/stc/cdeq.h | 874 | ||||
| -rw-r--r-- | include/stc/clist.h | 848 | ||||
| -rw-r--r-- | include/stc/cmap.h | 846 | ||||
| -rw-r--r-- | include/stc/cpque.h | 314 | ||||
| -rw-r--r-- | include/stc/cqueue.h | 130 | ||||
| -rw-r--r-- | include/stc/crandom.h | 388 | ||||
| -rw-r--r-- | include/stc/cregex.h | 180 | ||||
| -rw-r--r-- | include/stc/cset.h | 92 | ||||
| -rw-r--r-- | include/stc/csmap.h | 1188 | ||||
| -rw-r--r-- | include/stc/csset.h | 98 | ||||
| -rw-r--r-- | include/stc/cstack.h | 300 | ||||
| -rw-r--r-- | include/stc/cstr.h | 1110 | ||||
| -rw-r--r-- | include/stc/csview.h | 438 | ||||
| -rw-r--r-- | include/stc/cvec.h | 872 | ||||
| -rw-r--r-- | include/stc/forward.h | 414 | ||||
| -rw-r--r-- | include/stc/template.h | 592 | ||||
| -rw-r--r-- | include/stc/utf8.h | 190 |
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 |
