summaryrefslogtreecommitdiffhomepage
path: root/include/stc
diff options
context:
space:
mode:
authorTyge Lovset <[email protected]>2022-12-20 23:31:51 +0100
committerTyge Lovset <[email protected]>2022-12-20 23:31:51 +0100
commit5f57d597cd27aef55adbcb3b452973b0c6e33667 (patch)
treedfd59c2fd0e36a6ef37912a9d0cc5a65970f1524 /include/stc
parent1763be8c8cbbc0896477fcf924edd4180d1345a9 (diff)
downloadSTC-modified-5f57d597cd27aef55adbcb3b452973b0c6e33667.tar.gz
STC-modified-5f57d597cd27aef55adbcb3b452973b0c6e33667.zip
Restructured folders: examples, benchmarks, tests into misc folder.
Diffstat (limited to 'include/stc')
-rw-r--r--include/stc/alt/csmap.h512
-rw-r--r--include/stc/alt/cstr.h385
-rw-r--r--include/stc/carc.h4
-rw-r--r--include/stc/carr2.h4
-rw-r--r--include/stc/carr3.h4
-rw-r--r--include/stc/cbox.h4
-rw-r--r--include/stc/cdeq.h4
-rw-r--r--include/stc/clist.h4
-rw-r--r--include/stc/cmap.h4
-rw-r--r--include/stc/cpque.h4
-rw-r--r--include/stc/csmap.h4
-rw-r--r--include/stc/cstack.h4
-rw-r--r--include/stc/cvec.h6
-rw-r--r--include/stc/priv/template.h (renamed from include/stc/template.h)0
-rw-r--r--include/stc/stctest.h203
15 files changed, 23 insertions, 1123 deletions
diff --git a/include/stc/alt/csmap.h b/include/stc/alt/csmap.h
deleted file mode 100644
index 65a9f80b..00000000
--- a/include/stc/alt/csmap.h
+++ /dev/null
@@ -1,512 +0,0 @@
-/* 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_with (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_forward)
-_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_INIT(_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, const _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_INIT(_cx_self){_cx_memb(_clone_r_)(cx.root), cx.size};
-}
-#endif // !i_no_clone
-
-#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
-
-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
deleted file mode 100644
index ecb9c9fb..00000000
--- a/include/stc/alt/cstr.h
+++ /dev/null
@@ -1,385 +0,0 @@
-/* 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
-
-#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 c_unchecked_container_of(ptr, type, member) \
- ((type*)((char*)(ptr) - offsetof(type, member)))
-
-typedef char cstr_value;
-typedef struct { cstr_value* str; } cstr;
-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 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 cstr cstr_replace_sv(csview str, csview find, csview repl, unsigned count);
-STC_DEF void cstr_replace_at_sv(cstr* self, const size_t pos, size_t len, csview repl);
-STC_API void cstr_erase(cstr* self, size_t pos, size_t n);
-STC_API size_t cstr_find(const cstr* self, const char* needle);
-STC_API size_t cstr_find_at(const cstr* self, size_t pos, const char* needle);
-STC_API bool cstr_getdelim(cstr *self, int delim, FILE *stream);
-
-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_INIT(csview){self->str, _cstr_p(self)->size}; }
-#define cstr_lit(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(const cstr* self) { return _cstr_p(self)->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_at_sv(self, pos, 0, c_SV(str, n)); }
-STC_INLINE void cstr_insert(cstr* self, const size_t pos, const char* str)
- { cstr_replace_at_sv(self, pos, 0, c_SV(str, strlen(str))); }
-STC_INLINE void cstr_insert_s(cstr* self, const size_t pos, cstr s)
- { cstr_replace_at_sv(self, pos, 0, c_SV(s.str, _cstr_p(&s)->size)); }
-STC_INLINE void cstr_replace_at(cstr* self, const size_t pos, const size_t len, const char* str)
- { cstr_replace_at_sv(self, pos, len, c_SV(str, strlen(str))); }
-STC_INLINE void cstr_replace_s(cstr* self, const size_t pos, const size_t len, cstr s)
- { cstr_replace_at_sv(self, pos, len, c_SV(s.str, _cstr_p(&s)->size)); }
-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(const cstr* self, const char* str)
- { return strcmp(self->str, str) == 0; }
-STC_INLINE bool cstr_equals_s(const cstr* self, cstr s)
- { return strcmp(self->str, s.str) == 0; }
-STC_INLINE bool cstr_contains(const cstr* self, const char* needle)
- { return strstr(self->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_INIT(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_append_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(const cstr* self, const char* sub) {
- const char* p = self->str;
- while (*sub && *p == *sub) ++p, ++sub;
- return *sub == 0;
-}
-
-STC_INLINE bool cstr_ends_with(const cstr* self, const char* sub) {
- const size_t n = strlen(sub), sz = _cstr_p(self)->size;
- return n <= sz && !memcmp(self->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 cfasthash(self->str, _cstr_p(self)->size);
-}
-
-STC_INLINE void
-cstr_replace(cstr* self, const char* find, const char* repl, unsigned count) {
- csview in = cstr_sv(self);
- cstr_take(self, cstr_replace_sv(in, c_SV(find, strlen(find)),
- c_SV(repl, strlen(repl)), count));
-}
-
-/* -------------------------- 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_at_sv(cstr* self, const size_t pos, size_t len, csview repl) {
- const size_t sz = cstr_size(self);
- if (len > sz - pos) len = sz - pos;
- char buf[256], *xstr = repl.size > 256 ? c_malloc(repl.size) : buf;
- memcpy(xstr, repl.str, repl.size);
- _cstr_internal_move(self, pos + len, pos + repl.size);
- memcpy(&self->str[pos], xstr, repl.size);
- if (repl.size > 256) c_free(xstr);
-}
-
-STC_DEF cstr
-cstr_replace_sv(csview str, csview find, csview repl, unsigned count) {
- cstr out = cstr_NULL;
- size_t from = 0; char* res;
- if (count == 0) count = ~0;
- if (find.size)
- while (count-- && (res = cstrnstrn(str.str + from, find.str, str.size - from, find.size))) {
- const size_t pos = res - str.str;
- cstr_append_n(&out, str.str + from, pos - from);
- cstr_append_n(&out, repl.str, repl.size);
- from = pos + find.size;
- }
- cstr_append_n(&out, str.str + from, str.size - from);
- return out;
-}
-
-STC_DEF void
-cstr_erase(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(const cstr* self, const char* needle) {
- char* res = strstr(self->str, needle);
- return res ? res - self->str : c_NPOS;
-}
-
-STC_DEF size_t
-cstr_find_at(const cstr* self, const size_t pos, const char* needle) {
- if (pos > _cstr_p(self)->size) return c_NPOS;
- char* res = strstr(self->str + pos, needle);
- return res ? res - self->str : c_NPOS;
-}
-
-#endif
-#endif // CSTR_H_INCLUDED
-#undef i_opt
diff --git a/include/stc/carc.h b/include/stc/carc.h
index 509bc595..22453f1d 100644
--- a/include/stc/carc.h
+++ b/include/stc/carc.h
@@ -78,7 +78,7 @@ int main() {
#ifndef _i_prefix
#define _i_prefix carc_
#endif
-#include "template.h"
+#include "priv/template.h"
typedef i_keyraw _cx_raw;
#if !c_option(c_no_atomic)
@@ -201,4 +201,4 @@ STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* x)
#undef _i_atomic_inc
#undef _i_atomic_dec_and_test
-#include "template.h"
+#include "priv/template.h"
diff --git a/include/stc/carr2.h b/include/stc/carr2.h
index 4a12c2e3..89ae9b77 100644
--- a/include/stc/carr2.h
+++ b/include/stc/carr2.h
@@ -56,7 +56,7 @@ int main() {
#ifndef _i_prefix
#define _i_prefix carr2_
#endif
-#include "template.h"
+#include "priv/template.h"
#if !c_option(c_is_forward)
_cx_deftypes(_c_carr2_types, _cx_self, i_key);
#endif
@@ -149,4 +149,4 @@ STC_DEF void _cx_memb(_drop)(_cx_self* self) {
}
#endif
-#include "template.h"
+#include "priv/template.h"
diff --git a/include/stc/carr3.h b/include/stc/carr3.h
index c22536cb..d167dd69 100644
--- a/include/stc/carr3.h
+++ b/include/stc/carr3.h
@@ -57,7 +57,7 @@ int main() {
#ifndef _i_prefix
#define _i_prefix carr3_
#endif
-#include "template.h"
+#include "priv/template.h"
#if !c_option(c_is_forward)
_cx_deftypes(_c_carr3_types, _cx_self, i_key);
@@ -154,4 +154,4 @@ STC_DEF void _cx_memb(_drop)(_cx_self* self) {
}
#endif
-#include "template.h"
+#include "priv/template.h"
diff --git a/include/stc/cbox.h b/include/stc/cbox.h
index 4cbd5f84..bcb1b275 100644
--- a/include/stc/cbox.h
+++ b/include/stc/cbox.h
@@ -70,7 +70,7 @@ int main() {
#ifndef _i_prefix
#define _i_prefix cbox_
#endif
-#include "template.h"
+#include "priv/template.h"
typedef i_keyraw _cx_raw;
#if !c_option(c_is_forward)
@@ -174,4 +174,4 @@ STC_INLINE uint64_t _cx_memb(_hash)(const _cx_self* x)
{ _cx_raw rx = i_keyto(x->get); return i_hash(&rx); }
#endif
-#include "template.h"
+#include "priv/template.h"
diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h
index a8a704b4..9416d5b2 100644
--- a/include/stc/cdeq.h
+++ b/include/stc/cdeq.h
@@ -34,7 +34,7 @@
#ifndef _i_prefix
#define _i_prefix cdeq_
#endif
-#include "template.h"
+#include "priv/template.h"
#if !c_option(c_is_forward)
_cx_deftypes(_c_cdeq_types, _cx_self, i_key);
@@ -425,5 +425,5 @@ _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
#endif // !c_no_cmp
#endif // !_i_queue
#endif // IMPLEMENTATION
-#include "template.h"
+#include "priv/template.h"
#define CDEQ_H_INCLUDED
diff --git a/include/stc/clist.h b/include/stc/clist.h
index 8b96eabf..1ace1dac 100644
--- a/include/stc/clist.h
+++ b/include/stc/clist.h
@@ -83,7 +83,7 @@ _c_clist_complete_types(clist_VOID, dummy);
#ifndef _i_prefix
#define _i_prefix clist_
#endif
-#include "template.h"
+#include "priv/template.h"
#if !c_option(c_is_forward)
_cx_deftypes(_c_clist_types, _cx_self, i_key);
@@ -442,4 +442,4 @@ _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
#endif // !c_no_cmp
#endif // i_implement
#define CLIST_H_INCLUDED
-#include "template.h"
+#include "priv/template.h"
diff --git a/include/stc/cmap.h b/include/stc/cmap.h
index b0793ce5..11edf127 100644
--- a/include/stc/cmap.h
+++ b/include/stc/cmap.h
@@ -73,7 +73,7 @@ typedef struct { size_t idx; uint8_t hx; } chash_bucket_t;
#ifndef i_max_load_factor
#define i_max_load_factor 0.85f
#endif
-#include "template.h"
+#include "priv/template.h"
#ifndef i_hash_functor
#define i_hash_functor(self, x) i_hash(x)
#endif
@@ -450,4 +450,4 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) {
#undef _i_MAP_ONLY
#undef _i_SET_ONLY
#define CMAP_H_INCLUDED
-#include "template.h"
+#include "priv/template.h"
diff --git a/include/stc/cpque.h b/include/stc/cpque.h
index 9cf4b167..c1e7c13b 100644
--- a/include/stc/cpque.h
+++ b/include/stc/cpque.h
@@ -31,7 +31,7 @@
#define _i_prefix cpque_
#endif
-#include "template.h"
+#include "priv/template.h"
#ifndef i_less_functor
#define i_less_functor(self, x, y) i_less(x, y)
#endif
@@ -158,4 +158,4 @@ _cx_memb(_push)(_cx_self* self, _cx_value value) {
#endif
#define CPQUE_H_INCLUDED
#undef i_less_functor
-#include "template.h"
+#include "priv/template.h"
diff --git a/include/stc/csmap.h b/include/stc/csmap.h
index 5c73294e..f651db00 100644
--- a/include/stc/csmap.h
+++ b/include/stc/csmap.h
@@ -73,7 +73,7 @@ int main(void) {
#define _i_SET_ONLY c_false
#define _i_keyref(vp) (&(vp)->first)
#endif
-#include "template.h"
+#include "priv/template.h"
#ifndef i_cmp_functor
#define i_cmp_functor(self, x, y) i_cmp(x, y)
#endif
@@ -575,5 +575,5 @@ _cx_memb(_drop)(_cx_self* self) {
#undef _i_MAP_ONLY
#undef _i_SET_ONLY
#define CSMAP_H_INCLUDED
-#include "template.h"
+#include "priv/template.h"
#endif // !STC_CSMAP_V1
diff --git a/include/stc/cstack.h b/include/stc/cstack.h
index 23778e3c..73d0e2e1 100644
--- a/include/stc/cstack.h
+++ b/include/stc/cstack.h
@@ -31,7 +31,7 @@
#ifndef _i_prefix
#define _i_prefix cstack_
#endif
-#include "template.h"
+#include "priv/template.h"
#if !c_option(c_is_forward)
#ifdef i_capacity
@@ -183,4 +183,4 @@ STC_INLINE void _cx_memb(_next)(_cx_iter* it)
STC_INLINE _cx_iter _cx_memb(_advance)(_cx_iter it, intptr_t n)
{ if ((it.ref += n) >= it.end) it.ref = NULL ; return it; }
-#include "template.h"
+#include "priv/template.h"
diff --git a/include/stc/cvec.h b/include/stc/cvec.h
index ae6e452c..5eaefa04 100644
--- a/include/stc/cvec.h
+++ b/include/stc/cvec.h
@@ -71,7 +71,7 @@ int main() {
#ifndef _i_prefix
#define _i_prefix cvec_
#endif
-#include "template.h"
+#include "priv/template.h"
#if !c_option(c_is_forward)
_cx_deftypes(_c_cvec_types, _cx_self, i_key);
@@ -256,7 +256,7 @@ _cx_memb(_sort)(_cx_self* self) {
STC_DEF _cx_self
_cx_memb(_init)(void) {
- return (_cx_self){NULL};
+ return c_INIT(_cx_self){NULL};
}
STC_DEF void
@@ -420,4 +420,4 @@ _cx_memb(_value_cmp)(const _cx_value* x, const _cx_value* y) {
#endif // !c_no_cmp
#endif // i_implement
#define CVEC_H_INCLUDED
-#include "template.h"
+#include "priv/template.h"
diff --git a/include/stc/template.h b/include/stc/priv/template.h
index b7583e82..b7583e82 100644
--- a/include/stc/template.h
+++ b/include/stc/priv/template.h
diff --git a/include/stc/stctest.h b/include/stc/stctest.h
deleted file mode 100644
index 9718af7f..00000000
--- a/include/stc/stctest.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/* 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.
- */
-
-/* stctest: A small and simple C11 unit-testing framework.
-
- Features:
- - Requires C11. Should work with any C compiler supporting _Generic.
- - No library dependencies. Not even itself. Just a header file.
- - Reports assertion failures, including expressions and line numbers.
- - ANSI color output for maximum visibility.
- - Easy to embed in apps for runtime tests (e.g. environment tests).
-
- Example:
-
- #include "stctest.h"
- #include "mylib.h"
-
- void test_sheep()
- {
- EXPECT_EQ("Sheep are cool", are_sheep_cool());
- EXPECT_EQ(4, sheep.legs);
- }
-
- void test_cheese()
- {
- EXPECT_GT(cheese.tanginess, 0);
- EXPECT_EQ("Wensleydale", cheese.name);
- }
-
- int main()
- {
- RUN_TEST(test_sheep);
- RUN_TEST(test_cheese);
- return REPORT_TESTS();
- }
- */
-
-#ifndef STCTEST_INCLUDED
-#define STCTEST_INCLUDED
-
-#include <stdio.h>
-#include <time.h>
-#include <string.h>
-#include <float.h>
-#include <stdarg.h>
-#include <inttypes.h>
-
-#define STC_FLOAT_EPSILON 1e-6
-#define STC_DOUBLE_EPSILON 1e-13
-
-
-#define EXPECT_TRUE(expr) \
- do { if (!_stctest_assert(__FILE__, __LINE__, #expr, (expr) != 0)) puts(""); } while (0)
-
-#define EXPECT_TRUE1(expr, v) \
- do { if (!_stctest_assert(__FILE__, __LINE__, #expr, (expr) != 0)) { \
- char _fmt[32]; sprintf(_fmt, " ; %%s --> %s\n", _stctest_FMT(v)); \
- printf(_fmt, #v, v); \
- }} while (0)
-
-#define EXPECT_FALSE(expr) EXPECT_TRUE(!(expr))
-#define EXPECT_FALSE1(expr, v) EXPECT_TRUE1(!(expr), v)
-
-/* NB! (char*) are compared as strings. Cast to (void*) to compare pointers only */
-#define EXPECT_EQ(a, b) _stctest_CHECK(a, ==, b, -STC_DOUBLE_EPSILON)
-#define EXPECT_NE(a, b) _stctest_CHECK(a, !=, b, -STC_DOUBLE_EPSILON)
-#define EXPECT_GT(a, b) _stctest_CHECK(a, >, b, -STC_DOUBLE_EPSILON)
-#define EXPECT_LT(a, b) _stctest_CHECK(a, <, b, -STC_DOUBLE_EPSILON)
-#define EXPECT_LE(a, b) _stctest_CHECK(a, <=, b, -STC_DOUBLE_EPSILON)
-#define EXPECT_GE(a, b) _stctest_CHECK(a, >=, b, -STC_DOUBLE_EPSILON)
-#define EXPECT_FLOAT_EQ(a, b) _stctest_CHECK((float)(a), ==, (float)(b), -STC_FLOAT_EPSILON)
-#define EXPECT_DOUBLE_EQ(a, b) _stctest_CHECK((double)(a), ==, (double)(b), -STC_DOUBLE_EPSILON)
-#define EXPECT_NEAR(a, b, abs_error) _stctest_CHECK((double)(a), ==, (double)(b), abs_error)
-
-/* Run a test() function */
-#define RUN_TEST(test, ...) do { \
- puts(#test "(" #__VA_ARGS__ "):"); \
- const int ps = _stctest_s.passes; \
- const int fs = _stctest_s.fails; \
- const clock_t _start = clock(); \
- test(__VA_ARGS__); \
- const int _sum = (clock() - _start)*1000 / CLOCKS_PER_SEC; \
- _stctest_s.total_ms += _sum; \
- printf(" passed: %d/%d. duration: %d ms\n", \
- _stctest_s.passes - ps, _stctest_s.passes + _stctest_s.fails - (ps + fs), _sum); \
-} while (0)
-
-#define REPORT_TESTS() stctest_report()
-
-/* ----------------------------------------------------------------------------- */
-
-#define _stctest_CHECK(a, OP, b, e) \
- do { if (!_stctest_assert(__FILE__, __LINE__, #a " " #OP " " #b, _stctest_CMP(a, OP, b, e))) { \
- char _fmt[32]; sprintf(_fmt, " ; %s %s %s\n", _stctest_FMT(a), #OP, _stctest_FMT(b)); \
- printf(_fmt, a, b); \
- }} while (0)
-
-#define _stctest_CMP(a, OP, b, e) _Generic((a), \
- const char*: _stctest_strcmp, char*: _stctest_strcmp, \
- double: _Generic((b), double: _stctest_dblcmp, float: _stctest_dblcmp, default: _stctest_valcmp), \
- float: _Generic((b), double: _stctest_dblcmp, float: _stctest_dblcmp, default: _stctest_valcmp), \
- default: _stctest_valcmp)((a) OP (b), #OP, a, b, (double)(e))
-
-#define _stctest_FMT(a) _Generic((a), \
- float: "%.8gf", double: "%.15g", \
- int64_t: "%" PRId64, int32_t: "%" PRId32, int16_t: "%" PRId16, int8_t: "%" PRId8, \
- uint64_t: "%" PRIu64 "u", uint32_t: "%" PRIu32 "u", uint16_t: "%" PRIu16 "u", uint8_t: "%" PRIu8 "u", \
- char*: "`%s`", const char*: "`%s`", \
- default: "%p")
-
-static int _stctest_strcmp(int res, const char* OP, ...) {
- va_list ap;
- va_start(ap, OP);
- const char* a = va_arg(ap, const char *);
- const char* b = va_arg(ap, const char *);
- va_end(ap);
- int c = strcmp(a, b);
- if (OP[0] == '<') return OP[1] == '=' ? c <= 0 : c < 0;
- if (OP[0] == '>') return OP[1] == '=' ? c >= 0 : c > 0;
- return (OP[0] == '!') ^ (c == 0);
-}
-
-// Knuth:
-static int approximately_equal(double a, double b, double epsilon) {
- double d = a - b; if (d < 0) d = -d;
- if (a < 0) a = -a; if (b < 0) b = -b;
- return d <= ((a < b ? b : a) * epsilon); // (a > b ? b : a) => essentially_equal:
-}
-
-static int _stctest_dblcmp(int res, const char* OP, ...) {
- va_list ap;
- va_start(ap, OP);
- double a = va_arg(ap, double);
- double b = va_arg(ap, double);
- double e = va_arg(ap, double);
- double c = a - b;
- va_end(ap);
- if (OP[0] == '<') return OP[1] == '=' ? c <= 0 : c < 0;
- if (OP[0] == '>') return OP[1] == '=' ? c >= 0 : c > 0;
- return (OP[0] == '!') ^ (e < 0 ? approximately_equal(a, b, -e) : (c < 0 ? -c : c) <= e);
-}
-
-static int _stctest_valcmp(int res, const char* OP, ...)
- { return res; }
-
-#define _stctest_COLOR_CODE 0x1B
-#define _stctest_COLOR_RED "[1;31m"
-#define _stctest_COLOR_GREEN "[1;32m"
-#define _stctest_COLOR_RESET "[0m"
-
-static struct stctest_s {
- int passes;
- int fails;
- const char* current_file;
- int total_ms;
-} _stctest_s = {0};
-
-static int _stctest_assert(const char* file, int line, const char* expression, int pass) {
- if (pass)
- _stctest_s.passes++;
- else {
- _stctest_s.fails++;
- printf(" failed \"%s:%d\": (%s)", file, line, expression);
- }
- _stctest_s.current_file = file;
- return pass;
-}
-
-static int stctest_report(void) {
- if (_stctest_s.fails) {
- printf("%c%sFAILED%c%s: \"%s\": (failed %d, passed %d, total %d)\n",
- _stctest_COLOR_CODE, _stctest_COLOR_RED, _stctest_COLOR_CODE, _stctest_COLOR_RESET,
- _stctest_s.current_file, _stctest_s.fails, _stctest_s.passes, _stctest_s.passes + _stctest_s.fails);
- } else {
- printf("%c%sPASSED%c%s: \"%s\": (total %d)\n",
- _stctest_COLOR_CODE, _stctest_COLOR_GREEN, _stctest_COLOR_CODE, _stctest_COLOR_RESET,
- _stctest_s.current_file, _stctest_s.passes);
- }
- printf(" duration: %d ms\n", _stctest_s.total_ms); \
- return -_stctest_s.fails;
-}
-
-#endif