From 2b3b428e4257dba3240afdedda8e16a35115d182 Mon Sep 17 00:00:00 2001 From: Tyge Date: Wed, 15 Apr 2020 13:30:35 +0200 Subject: Renamed folder. --- ccl/carray.h | 65 --------------- ccl/cdefs.h | 85 ------------------- ccl/cmap.h | 257 ---------------------------------------------------------- ccl/copt.h | 181 ----------------------------------------- ccl/cstring.h | 246 ------------------------------------------------------- ccl/cvec3.h | 151 ---------------------------------- ccl/cvec4.h | 126 ---------------------------- ccl/cvector.h | 165 ------------------------------------- stc/carray.h | 65 +++++++++++++++ stc/cdefs.h | 85 +++++++++++++++++++ stc/cmap.h | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ stc/copt.h | 181 +++++++++++++++++++++++++++++++++++++++++ stc/cstring.h | 246 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ stc/cvec3.h | 151 ++++++++++++++++++++++++++++++++++ stc/cvec4.h | 126 ++++++++++++++++++++++++++++ stc/cvector.h | 165 +++++++++++++++++++++++++++++++++++++ 16 files changed, 1276 insertions(+), 1276 deletions(-) delete mode 100644 ccl/carray.h delete mode 100644 ccl/cdefs.h delete mode 100644 ccl/cmap.h delete mode 100644 ccl/copt.h delete mode 100644 ccl/cstring.h delete mode 100644 ccl/cvec3.h delete mode 100644 ccl/cvec4.h delete mode 100644 ccl/cvector.h create mode 100644 stc/carray.h create mode 100644 stc/cdefs.h create mode 100644 stc/cmap.h create mode 100644 stc/copt.h create mode 100644 stc/cstring.h create mode 100644 stc/cvec3.h create mode 100644 stc/cvec4.h create mode 100644 stc/cvector.h diff --git a/ccl/carray.h b/ccl/carray.h deleted file mode 100644 index ddb4bd9d..00000000 --- a/ccl/carray.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef CARRAY__H__ -#define CARRAY__H__ - -#include "cdefs.h" - -#define carray_xdim(a) ((a).xdim) -#define carray_ydim(a) ((a)._yxdim / (a).xdim) -#define carray_zdim(a) ((a).zdim) -#define carray_ref(a) (++(a)._refCount, a) -#define carray_unref(a) ({if (--(a)._refCount == 0) free((a).data);0;}) - -/* // demo: -#include "ccl/carray.h" -declare_CArray(f, float); - -int main() -{ - CArray3f a3 = carray3f_make(30, 20, 10); - carray3f_at2(a3, 3, 2).data[1] = 10.2f; - CArray2f a2 = carray3f_at(a3, 3); - printf("%f\n", carray2f_at(a2, 2).data[1]); - carray_unref(a2); - carray_unref(a3); -} -*/ - -#define declare_CArray(tag, T) \ - c_struct (CArray1##tag) { \ - T* data; \ - int _refCount; \ - size_t xdim; \ - }; \ - c_struct (CArray2##tag) { \ - T* data; \ - int _refCount; \ - size_t xdim, _yxdim; \ - }; \ - c_struct (CArray3##tag) { \ - T* data; \ - int _refCount; \ - size_t xdim, _yxdim, zdim; \ - }; \ - \ - static inline CArray1##tag carray1##tag##_make(size_t xdim) { \ - CArray1##tag a = {c_new_2(T, xdim), 1, xdim}; return a; \ - } \ - static inline CArray2##tag carray2##tag##_make(size_t ydim, size_t xdim) { \ - CArray2##tag a = {c_new_2(T, ydim*xdim), 1, xdim, ydim*xdim}; return a; \ - } \ - static inline CArray3##tag carray3##tag##_make(size_t zdim, size_t ydim, size_t xdim) { \ - CArray3##tag a = {c_new_2(T, zdim*ydim*xdim), 1, xdim, ydim*xdim, zdim}; return a; \ - } \ - \ - static inline CArray1##tag carray2##tag##_at(CArray2##tag a, size_t y) { \ - CArray1##tag out = {a.data + y*a.xdim, 1000, a.xdim}; return out; \ - } \ - static inline CArray2##tag carray3##tag##_at(CArray3##tag a, size_t z) { \ - CArray2##tag out = {a.data + z*a._yxdim, 1000, a.xdim, a._yxdim}; return out; \ - } \ - static inline CArray1##tag carray3##tag##_at2(CArray3##tag a, size_t z, size_t y) { \ - CArray1##tag out = {a.data + z*a._yxdim + y*a.xdim, 1000, a.xdim}; return out; \ - } \ - typedef T carray_##tag##_t - -#endif \ No newline at end of file diff --git a/ccl/cdefs.h b/ccl/cdefs.h deleted file mode 100644 index 9a29c36b..00000000 --- a/ccl/cdefs.h +++ /dev/null @@ -1,85 +0,0 @@ -// MIT License -// -// Copyright (c) 2020 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 CDEFS__H__ -#define CDEFS__H__ - -#include -#include - -// Macro overloading feature support: https://rextester.com/ONP80107 -#define c_CAT( A, B ) A ## B -#define c_EXPAND(...) __VA_ARGS__ -#define c_VA_ARG_SIZE(...) c_EXPAND(c_APPLY_ARG_N((__VA_ARGS__, c_RSEQ_N))) -#define c_APPLY_ARG_N(ARGS) c_EXPAND(c_ARG_N ARGS) -#define c_ARG_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N,...) N -#define c_RSEQ_N 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 -#define c_OVERLOAD_SELECT(NAME, NUM) c_CAT( NAME ## _, NUM) - -#define c_MACRO_OVERLOAD(NAME, ...) c_OVERLOAD_SELECT(NAME, c_VA_ARG_SIZE(__VA_ARGS__))(__VA_ARGS__) - - -#define c_new(...) c_MACRO_OVERLOAD(c_new, __VA_ARGS__) -#define c_new_1(T) ((T *) malloc(sizeof(T))) -#define c_new_2(T, n) ((T *) malloc(sizeof(T) * (n))) - -#define c_struct(S) typedef struct S S; struct S -#define c_npos ((size_t) -1) -#define c_max_alloca (1000) -#define c_swap(T, x, y) { T __t = x; x = y; y = __t; } - -#define c_defaultInitRaw(x) (x) -#define c_defaultGetRaw(x) (x) -#define c_defaultCompare(x, y) (*(x) == *(y) ? 0 : *(x) < *(y) ? -1 : 1) -#define c_defaultEquals(x, y) (memcmp(x, y, sizeof(*(y))) == 0) -#define c_defaultDestroy(p) (p) -//static inline void c_defaultDestroy(void* value) {} - -#define c_foreach(it, ctag, con) \ - for (ctag##_iter_t it = ctag##_begin(con); it.item != ctag##_end(con).item; it = ctag##_next(it)) - -// One-byte-at-a-time hash based on Murmur's mix -static inline uint32_t c_defaultHash(const void *data, size_t len) { - const uint8_t *key = (const uint8_t *) data; - uint32_t x = UINT32_C(0xc613fc15); - while (len--) { - x ^= *key++; - x *= UINT32_C(0x5bd1e995); - x ^= x >> 15; - } - return x; -} - -// https://nullprogram.com/blog/2018/07/31/: assume len positive multiple of 4 -static inline uint32_t c_lowbias32Hash(const void *data, size_t len) { - const uint32_t *key = (const uint32_t *) data; uint32_t x = *key; - do { - x ^= *key++ >> 16; - x *= UINT32_C(0x7feb352d); - x ^= x >> 15; - x *= UINT32_C(0x846ca68b); - x ^= x >> 16; - } while (len -= 4); - return x; -} - -#endif diff --git a/ccl/cmap.h b/ccl/cmap.h deleted file mode 100644 index b14f9e3b..00000000 --- a/ccl/cmap.h +++ /dev/null @@ -1,257 +0,0 @@ -// MIT License -// -// Copyright (c) 2020 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 CMAP_H_ -#define CMAP_H_ - -#include "cvector.h" - - -#define cmap_init {cvector_init, 0, 90, 0} -#define cmap_size(map) ((size_t) (map)._size) -#define cmap_bucketCount(map) cvector_capacity((map)._table) - - -// CMapEntry: -#define declare_CMapEntry(tag, Key, Value, valueDestroy, keyDestroy) \ -struct CMapEntry_##tag { \ - Key key; \ - Value value; \ - uint16_t hashx; \ -}; \ - \ -static inline struct CMapEntry_##tag cmapentry_##tag##_make(Key key, Value value) { \ - struct CMapEntry_##tag e = {key, value, 0}; \ - return e; \ -} \ -static inline void cmapentry_##tag##_destroy(struct CMapEntry_##tag* e) { \ - keyDestroy(&e->key); \ - valueDestroy(&e->value); \ - e->hashx = 0; \ -} \ -typedef struct CMapEntry_##tag CMapEntry_##tag - -enum {cmapentry_HASH=0x7fff, cmapentry_USED=0x8000}; -#define cmapentry_noCompare(x, y) (0) - - -// CMap: -#define declare_CMap(...) c_MACRO_OVERLOAD(declare_CMap, __VA_ARGS__) - -#define declare_CMap_3(tag, Key, Value) \ - declare_CMap_4(tag, Key, Value, c_defaultDestroy) - -#define declare_CMap_4(tag, Key, Value, valueDestroy) \ - declare_CMap_5(tag, Key, Value, valueDestroy, c_defaultHash) - -#define declare_CMap_5(tag, Key, Value, valueDestroy, keyHash) \ - declare_CMap_7(tag, Key, Value, valueDestroy, keyHash, c_defaultEquals, c_defaultDestroy) - -#define declare_CMap_7(tag, Key, Value, valueDestroy, keyHash, keyEquals, keyDestroy) \ - declare_CMap_10(tag, Key, Value, valueDestroy, keyHash, keyEquals, keyDestroy, \ - Key, c_defaultGetRaw, c_defaultInitRaw) - - -// CMap: -#define declare_CMap_stringkey(...) c_MACRO_OVERLOAD(declare_CMap_stringkey, __VA_ARGS__) - -#define declare_CMap_stringkey_2(tag, Value) \ - declare_CMap_stringkey_3(tag, Value, c_defaultDestroy) - -#define declare_CMap_stringkey_3(tag, Value, valueDestroy) \ - declare_CMap_10(tag, CString, Value, valueDestroy, cstring_hashRaw, cstring_equalsRaw, cstring_destroy, \ - const char* const, cstring_getRaw, cstring_make) - - -// CMap full: -#define declare_CMap_10(tag, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, keyDestroy, \ - RawKey, keyGetRaw, keyInitRaw) \ - declare_CMapEntry(tag, Key, Value, valueDestroy, keyDestroy); \ - declare_CVector_4(map_##tag, CMapEntry_##tag, cmapentry_##tag##_destroy, cmapentry_noCompare); \ - typedef RawKey cmap_##tag##_rawkey_t; \ - \ -typedef struct CMap_##tag { \ - CVector_map_##tag _table; \ - size_t _size; \ - uint8_t maxLoadPercent; \ - uint8_t shrinkLimitPercent; \ -} CMap_##tag; \ -static const CMap_##tag cmap_##tag##_init = cmap_init; \ - \ -typedef struct cmap_##tag##_iter_t { \ - CMapEntry_##tag *item, *_end; \ -} cmap_##tag##_iter_t; \ - \ -static inline void cmap_##tag##_destroy(CMap_##tag* self) { \ - if (cmap_size(*self)) { \ - size_t cap = _cvector_capacity(self->_table); \ - CMapEntry_##tag* e = self->_table.data, *end = e + cap; \ - for (; e != end; ++e) if (e->hashx) cmapentry_##tag##_destroy(e); \ - } \ - free(_cvector_alloced(self->_table.data)); \ -} \ - \ -static inline size_t cmap_##tag##_reserve(CMap_##tag* self, size_t size); /* predeclared */ \ - \ -static inline void cmap_##tag##_clear(CMap_##tag* self) { \ - memset(self->_table.data, 0, sizeof(CMapEntry_##tag) * _cvector_capacity(self->_table)); \ - self->_size = 0; \ -} \ - \ -static inline void cmap_##tag##_swap(CMap_##tag* a, CMap_##tag* b) { \ - c_swap(CMap_##tag, *a, *b); \ -} \ - \ -static inline void cmap_##tag##_setMaxLoadFactor(CMap_##tag* self, double fac) { \ - self->maxLoadPercent = (uint8_t) (fac * 100); \ - if (cmap_size(*self) >= cmap_bucketCount(*self) * fac) \ - cmap_##tag##_reserve(self, (size_t) (cmap_size(*self) / fac)); \ -} \ - \ -static inline void cmap_##tag##_setShrinkLimitFactor(CMap_##tag* self, double limit) { \ - self->shrinkLimitPercent = (uint8_t) (limit * 100); \ - if (cmap_size(*self) < cmap_bucketCount(*self) * limit) \ - cmap_##tag##_reserve(self, (size_t) (cmap_size(*self) * 1.2 / limit)); \ -} \ - \ -static inline size_t cmap_##tag##_bucket(CMap_##tag* self, cmap_##tag##_rawkey_t* const rawKey, uint32_t* hxPtr) { \ - uint32_t hash = keyHashRaw(rawKey, sizeof(cmap_##tag##_rawkey_t)), hx = (hash & cmapentry_HASH) | cmapentry_USED; \ - size_t cap = cvector_capacity(self->_table); \ - size_t idx = cmap_reduce(hash, cap); \ - CMapEntry_##tag* slot = self->_table.data; \ - while (slot[idx].hashx && (slot[idx].hashx != hx || !keyEqualsRaw((RawKey* const) keyGetRaw(&slot[idx].key), rawKey))) { \ - if (++idx == cap) idx = 0; \ - } \ - *hxPtr = hx; \ - return idx; \ -} \ - \ -static inline CMapEntry_##tag* cmap_##tag##_get(CMap_##tag map, cmap_##tag##_rawkey_t rawKey) { \ - if (cmap_size(map) == 0) return NULL; \ - uint32_t hx; \ - size_t idx = cmap_##tag##_bucket(&map, &rawKey, &hx); \ - return map._table.data[idx].hashx ? &map._table.data[idx] : NULL; \ -} \ - \ -static inline void cmap_##tag##_expand(CMap_##tag* self) { \ - size_t cap = cvector_capacity(self->_table); \ - if (cmap_size(*self) + 1 >= cap * self->maxLoadPercent * 0.01) \ - cmap_##tag##_reserve(self, (size_t) 7 + (1.6 * cap)); \ -} \ - \ -static inline CMapEntry_##tag* cmap_##tag##_put(CMap_##tag* self, cmap_##tag##_rawkey_t rawKey, Value value) { \ - cmap_##tag##_expand(self); \ - uint32_t hx; \ - size_t idx = cmap_##tag##_bucket(self, &rawKey, &hx); \ - CMapEntry_##tag* e = &self->_table.data[idx]; \ - if (! e->hashx) { \ - e->key = keyInitRaw(rawKey); \ - e->hashx = hx; \ - ++self->_size; \ - } \ - e->value = value; \ - return e; \ -} \ - \ -static inline CMapEntry_##tag* cmap_##tag##_insert(CMap_##tag* self, CMapEntry_##tag entry) { \ - cmap_##tag##_expand(self); \ - uint32_t hx; \ - size_t idx = cmap_##tag##_bucket(self, (RawKey* const) keyGetRaw(&entry.key), &hx); \ - CMapEntry_##tag* e = &self->_table.data[idx]; \ - if (! e->hashx) { \ - e->key = entry.key; \ - e->hashx = hx; \ - ++self->_size; \ - } \ - e->value = entry.value; \ - return e; \ -} \ - \ -static inline size_t cmap_##tag##_reserve(CMap_##tag* self, size_t size) { \ - size_t oldcap = cvector_capacity(self->_table), newcap = 1 + (size / 2) * 2; \ - if (cmap_size(*self) >= newcap * self->maxLoadPercent * 0.01) return oldcap; \ - CVector_map_##tag vec = cvector_map_##tag##_init; \ - cvector_map_##tag##_reserve(&vec, newcap); \ - memset(vec.data, 0, sizeof(CMapEntry_##tag) * newcap); \ - cvector_map_##tag##_swap(&self->_table, &vec); \ - \ - CMapEntry_##tag* e = vec.data, *slot = self->_table.data; \ - uint32_t hx; \ - for (size_t i = 0; i < oldcap; ++i, ++e) \ - if (e->hashx) \ - slot[ cmap_##tag##_bucket(self, (RawKey* const) keyGetRaw(&e->key), &hx) ] = *e; \ - free(_cvector_alloced(vec.data)); /* not cvector_destroy() here */ \ - return newcap; \ -} \ - \ -static inline bool cmap_##tag##_erase(CMap_##tag* self, cmap_##tag##_rawkey_t rawKey) { \ - if (cmap_size(*self) == 0) \ - return false; \ - size_t cap = cvector_capacity(self->_table); \ - if (cmap_size(*self) < cap * self->shrinkLimitPercent * 0.01) \ - cap = cmap_##tag##_reserve(self, cmap_size(*self) * 120 / self->maxLoadPercent); \ - uint32_t hx; \ - size_t i = cmap_##tag##_bucket(self, &rawKey, &hx), j = i, k; \ - CMapEntry_##tag* slot = self->_table.data; \ - if (! slot[i].hashx) \ - return false; \ - do { /* deletion from hash table without tombstone */ \ - if (++j == cap) j = 0; /* j %= cap; is slow */ \ - if (! slot[j].hashx) \ - break; \ - k = cmap_reduce(keyHashRaw((RawKey* const) keyGetRaw(&slot[j].key), sizeof(cmap_##tag##_rawkey_t)), cap); \ - if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */ \ - slot[i] = slot[j], i = j; \ - } while (true); \ - cmapentry_##tag##_destroy(&slot[i]); /* sets used=false */ \ - --self->_size; \ - return true; \ -} \ - \ -static inline cmap_##tag##_iter_t cmap_##tag##_begin(CMap_##tag map) { \ - cmap_##tag##_iter_t null = {NULL, NULL}; \ - if (cmap_size(map) == 0) return null; \ - CMapEntry_##tag* e = map._table.data, *end = e + _cvector_capacity(map._table); \ - while (e != end && !e->hashx) ++e; \ - cmap_##tag##_iter_t it = {e, end}; return it; \ -} \ - \ -static inline cmap_##tag##_iter_t cmap_##tag##_next(cmap_##tag##_iter_t it) { \ - do { ++it.item; } while (it.item != it._end && !it.item->hashx); \ - return it; \ -} \ - \ -static inline cmap_##tag##_iter_t cmap_##tag##_end(CMap_##tag map) { \ - CMapEntry_##tag* end = (cmap_size(map) == 0) ? NULL : map._table.data + _cvector_capacity(map._table); \ - cmap_##tag##_iter_t it = {end, end}; \ - return it; \ -} \ -typedef Key cmap_##tag##_key_t; \ -typedef Value cmap_##tag##_value_t - - -// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ -static inline uint32_t cmap_reduce(uint32_t x, uint32_t N) { - return ((uint64_t) x * (uint64_t) N) >> 32 ; -} - -#endif diff --git a/ccl/copt.h b/ccl/copt.h deleted file mode 100644 index fb810e10..00000000 --- a/ccl/copt.h +++ /dev/null @@ -1,181 +0,0 @@ -// MIT License -// -// Copyright (c) 2020 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. - -// Inspired by https://attractivechaos.wordpress.com/2018/08/31/a-survey-of-argument-parsing-libraries-in-c-c -// Fixed major bugs with option arguments (both long and short), and shows a useful demo of the features. -// Has a more consistent API, added arg->bad output field, written in C99. - -#ifndef COPT__H__ -#define COPT__H__ - -#include -#include - -enum { - copt_no_argument = 0, - copt_required_argument = 1, - copt_optional_argument = 2 -}; -typedef struct { - int ind; // equivalent to optind - int opt; // equivalent to optopt - char *arg; // equivalent to optarg - char *bad; // points to the faulty option - int longindex; // idx of long option; or -1 if short - int _i, _pos, _nargs; - char _bad[4]; -} copt_t; - -struct copt_option { - char *name; - int has_arg; - int val; -}; - -static const copt_t copt_init = {1, 0, NULL, NULL, -1, 1, 0, 0, {'-', 0, 0, 0}}; - -static void _copt_permute(char *argv[], int j, int n) { // move argv[j] over n elements to the left - int k; - char *p = argv[j]; - for (k = 0; k < n; ++k) - argv[j - k] = argv[j - k - 1]; - argv[j - k] = p; -} - - -// Parse command-line options and arguments -// -// This fuction has a similar interface to GNU's getopt_long(). Each call -// parses one option and returns the option name. opt->arg points to the option -// argument if present. The function returns -1 when all command-line arguments -// are parsed. In this case, opt->ind is the index of the first non-option -// argument. -// -// @param opt output; must be initialized to copt_init on first call -// @param posixly_correct if true, do not move options ahead of non-option arguments, -// instead stop option processing on first nonoption argument. -// @return ASCII val for a short option; longopt.val for a long option; -// -1 if argv[] is fully processed; '?' for an unknown option or -// an ambiguous long option; ':' if an option argument is missing -// -static int copt_getopt(copt_t *opt, int argc, char *argv[], - const char *shortopts, const struct copt_option *longopts, - bool posixly_correct) { - int optc = -1, i0, j; - if (!posixly_correct) { - while (opt->_i < argc && (argv[opt->_i][0] != '-' || argv[opt->_i][1] == '\0')) - ++opt->_i, ++opt->_nargs; - } - opt->arg = 0, opt->longindex = -1, i0 = opt->_i; - if (opt->_i >= argc || argv[opt->_i][0] != '-' || argv[opt->_i][1] == '\0') { - opt->ind = opt->_i - opt->_nargs; - return -1; - } - if (argv[opt->_i][0] == '-' && argv[opt->_i][1] == '-') { // "--" or a long option - if (argv[opt->_i][2] == '\0') { // a bare "--" - _copt_permute(argv, opt->_i, opt->_nargs); - ++opt->_i, opt->ind = opt->_i - opt->_nargs; - return -1; - } - opt->opt = 0, optc = '?', opt->_pos = -1; - if (longopts) { // parse long options - int k, n_exact = 0, n_partial = 0; - const struct copt_option *o = 0, *o_exact = 0, *o_partial = 0; - for (j = 2; argv[opt->_i][j] != '\0' && argv[opt->_i][j] != '='; ++j) {} // find the end of the option name - for (k = 0; longopts[k].name != 0; ++k) - if (strncmp(&argv[opt->_i][2], longopts[k].name, j - 2) == 0) { - if (longopts[k].name[j - 2] == 0) ++n_exact, o_exact = &longopts[k]; - else ++n_partial, o_partial = &longopts[k]; - } - opt->bad = argv[opt->_i]; - if (n_exact > 1 || (n_exact == 0 && n_partial > 1)) return '?'; - o = n_exact == 1? o_exact : n_partial == 1? o_partial : 0; - if (o) { - opt->opt = optc = o->val, opt->longindex = o - longopts; - if (o->has_arg != copt_no_argument) { - if (argv[opt->_i][j] == '=') - opt->arg = &argv[opt->_i][j + 1]; - else if (argv[opt->_i][j] == '\0' && opt->_i < argc - 1 && (o->has_arg == copt_required_argument || - argv[opt->_i + 1][0] != '-')) - opt->arg = argv[++opt->_i]; - else if (o->has_arg == copt_required_argument) - optc = ':'; // missing option argument - } - } - } - } else { // a short option - const char *p; - if (opt->_pos == 0) opt->_pos = 1; - optc = opt->opt = argv[opt->_i][opt->_pos++]; - opt->_bad[1] = optc, opt->bad = opt->_bad; - p = strchr((char *) shortopts, optc); - if (p == 0) { - optc = '?'; // unknown option - } else if (p[1] == ':') { - if (argv[opt->_i][opt->_pos] != '\0') - opt->arg = &argv[opt->_i][opt->_pos]; - else if (opt->_i < argc - 1 && (p[2] != ':' || argv[opt->_i + 1][0] != '-')) - opt->arg = argv[++opt->_i]; - else if (p[2] != ':') - optc = ':'; - opt->_pos = -1; - } - } - if (opt->_pos < 0 || argv[opt->_i][opt->_pos] == 0) { - ++opt->_i, opt->_pos = 0; - if (opt->_nargs > 0) // permute - for (j = i0; j < opt->_i; ++j) - _copt_permute(argv, j, opt->_nargs); - } - opt->ind = opt->_i - opt->_nargs; - return optc; -} - -/* // demo: - int main(int argc, char *argv[]) - { - static struct copt_option longopts[] = { - {"foo", copt_no_argument, 'f'}, - {"bar", copt_required_argument, 'b'}, - {"opt", copt_optional_argument, 'o'}, - {NULL} - }; - const char* optstr = "xy:z::123"; - printf("program -x -y ARG -z [ARG] -1 -2 -3 --foo --bar ARG --opt [ARG] [ARGUMENTS]\n"); - int c; - copt_t opt = copt_init; - while ((c = copt_getopt(&opt, argc, argv, optstr, longopts, false)) != -1) { - switch (c) { - case '?': printf("error: unknown option: %s\n", opt.bad); break; - case ':': printf("error: missing argument for %s\n", opt.bad); break; - default: printf("option: %c [%s]\n", c, opt.arg ? opt.arg : ""); break; - } - } - printf("\nNon-option arguments:"); - for (int i = opt.ind; i < argc; ++i) - printf(" %s", argv[i]); - putchar('\n'); - return 0; - } -*/ - -#endif diff --git a/ccl/cstring.h b/ccl/cstring.h deleted file mode 100644 index d0719cb6..00000000 --- a/ccl/cstring.h +++ /dev/null @@ -1,246 +0,0 @@ -// MIT License -// -// Copyright (c) 2020 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 CSTRING__H__ -#define CSTRING__H__ - -#include -#include -#include -#include - -#include "cdefs.h" - -typedef struct CString { - char* str; -} CString; - - -static size_t _cstring_null_rep[] = {0, 0, 0}; -#define _cstring_rep(cs) (((size_t *) (cs).str) - 2) - -#define cstring_size(cs) ((size_t) _cstring_rep(cs)[0]) -#define cstring_capacity(cs) ((size_t) _cstring_rep(cs)[1]) -#define cstring_npos c_npos - - -static const CString cstring_init = {(char* ) &_cstring_null_rep[2]}; - -static inline void cstring_reserve(CString* self, size_t cap) { - size_t len = cstring_size(*self), oldcap = cstring_capacity(*self); - if (cap > oldcap) { - size_t* rep = (size_t *) realloc(oldcap ? _cstring_rep(*self) : NULL, sizeof(size_t) * 2 + cap + 1); - self->str = (char* ) (rep + 2); - self->str[ rep[0] = len ] = '\0'; - rep[1] = cap; - } -} - -static inline void cstring_destroy(CString* self) { - if (cstring_capacity(*self)) { - free(_cstring_rep(*self)); - } -} - -static inline CString cstring_makeN(const char* str, size_t len) { - CString cs = cstring_init; - if (len) { - cstring_reserve(&cs, len); - memcpy(cs.str, str, len); - cs.str[ _cstring_rep(cs)[0] = len ] = '\0'; - } - return cs; -} - -static inline CString cstring_make(const char* str) { - return cstring_makeN(str, strlen(str)); -} - -static inline CString cstring_makeCopy(CString cs) { - return cstring_makeN(cs.str, cstring_size(cs)); -} - -static inline void cstring_clear(CString* self) { - CString cs = cstring_init; - cstring_destroy(self); - *self = cs; -} - -static inline CString* cstring_assignN(CString* self, const char* str, size_t len) { - if (len) { - cstring_reserve(self, len); - memmove(self->str, str, len); - self->str[_cstring_rep(*self)[0] = len] = '\0'; - } - return self; -} - -static inline CString* cstring_assign(CString* self, const char* str) { - return cstring_assignN(self, str, strlen(str)); -} - -static inline CString* cstring_copy(CString* self, CString cs2) { - return cstring_assignN(self, cs2.str, cstring_size(cs2)); -} - - -static inline CString* cstring_appendN(CString* self, const char* str, size_t len) { - if (len) { - size_t oldlen = cstring_size(*self), newlen = oldlen + len; - if (newlen > cstring_capacity(*self)) - cstring_reserve(self, newlen * 5 / 3); - memmove(&self->str[oldlen], str, len); - self->str[_cstring_rep(*self)[0] = newlen] = '\0'; - } - return self; -} - -static inline CString* cstring_append(CString* self, const char* str) { - return cstring_appendN(self, str, strlen(str)); -} -static inline CString* cstring_appendS(CString* self, CString cs2) { - return cstring_appendN(self, cs2.str, cstring_size(cs2)); -} - - -static inline void _cstring_internalMove(CString* self, size_t pos1, size_t pos2) { - if (pos1 == pos2) - return; - size_t len = cstring_size(*self), newlen = len + pos2 - pos1; - if (newlen > cstring_capacity(*self)) - cstring_reserve(self, newlen * 5 / 3); - memmove(&self->str[pos2], &self->str[pos1], len - pos1); - self->str[_cstring_rep(*self)[0] = newlen] = '\0'; -} - -static inline void cstring_insertN(CString* self, size_t pos, const char* str, size_t n) { - char* xstr = (char *) memcpy(n > c_max_alloca ? malloc(n) : alloca(n), str, n); - _cstring_internalMove(self, pos, pos + n); - memcpy(&self->str[pos], xstr, n); - if (n > c_max_alloca) free(xstr); -} - -static inline void cstring_insert(CString* self, size_t pos, const char* str) { - cstring_insertN(self, pos, str, strlen(str)); -} - -static inline void cstring_erase(CString* self, size_t pos, size_t n) { - size_t len = cstring_size(*self); - if (len) { - memmove(&self->str[pos], &self->str[pos + n], len - (pos + n)); - self->str[_cstring_rep(*self)[0] -= n] = '\0'; - } -} - -static inline size_t cstring_findN(CString cs, size_t pos, const char* needle, size_t n); - -static inline size_t cstring_replaceN(CString* self, size_t pos, const char* s1, size_t n1, const char* s2, size_t n2) { - size_t pos2 = cstring_findN(*self, pos, s1, n1); - if (pos2 == cstring_npos) return cstring_npos; - char* xs2 = (char *) memcpy(n2 > c_max_alloca ? malloc(n2) : alloca(n2), s2, n2); - _cstring_internalMove(self, pos2 + n1, pos2 + n2); - memcpy(&self->str[pos2], xs2, n2); - if (n2 > c_max_alloca) free(xs2); - return pos2; -} - -static inline size_t cstring_replace(CString* self, size_t pos, const char* s1, const char* s2) { - return cstring_replaceN(self, pos, s1, strlen(s1), s2, strlen(s2)); -} - - -static inline char cstring_back(CString cs) { - return cs.str[cstring_size(cs) - 1]; -} - -static inline CString* cstring_push(CString* self, char value) { - return cstring_appendN(self, &value, 1); -} - - -static inline void cstring_pop(CString* self) { - --_cstring_rep(*self)[0]; -} - -/* readonly */ - -static inline bool cstring_empty(CString cs) { - return cstring_size(cs) == 0; -} - -static inline bool cstring_equals(CString cs1, const char* str) { - return strcmp(cs1.str, str) == 0; -} -static inline bool cstring_equalsS(CString cs1, CString cs2) { - return strcmp(cs1.str, cs2.str) == 0; -} - -static inline char* cstring_strnstr(CString cs, size_t pos, const char* needle, size_t n) { - char *x = cs.str + pos, // haystack - *z = cs.str + cstring_size(cs) - n + 1; - if (x >= z) - return NULL; - ptrdiff_t sum = 0; - const char *y = x, *p = needle, *q = needle + n; - while (p != q) - sum += *y++ - *p++; - while (x != z) { - if (sum == 0 && memcmp(x, needle, n) == 0) - return x; - sum += *y++ - *x++; - } - return NULL; -} - -static inline size_t cstring_findN(CString cs, size_t pos, const char* needle, size_t n) { - char* res = cstring_strnstr(cs, pos, needle, n); - return res ? res - cs.str : cstring_npos; -} - -static inline size_t cstring_find(CString cs, size_t pos, const char* needle) { - char* res = strstr(cs.str + pos, needle); - return res ? res - cs.str : cstring_npos; -} - -static inline char* cstring_splitFirst(const char* delimiters, CString cs) { - return strtok(cs.str, delimiters); -} - -static inline char* cstring_splitNext(const char* delimiters) { - return strtok(NULL, delimiters); -} - -static inline CString cstring_temp(const char* str) { - // May only be used for accessing .str - CString temp = {(char *) str}; - return temp; -} - -// CVector / CMap API functions: - -#define cstring_getRaw(x) (&(x)->str) -#define cstring_compareRaw(x, y) strcmp(*(x), *(y)) -#define cstring_equalsRaw(x, y) (strcmp(*(x), *(y)) == 0) -static inline uint32_t cstring_hashRaw(const char* const* str, size_t ignored) { return c_defaultHash(*str, strlen(*str)); } - - -#endif diff --git a/ccl/cvec3.h b/ccl/cvec3.h deleted file mode 100644 index 3d8d91dc..00000000 --- a/ccl/cvec3.h +++ /dev/null @@ -1,151 +0,0 @@ -// MIT License -// -// Copyright (c) 2020 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 CVEC3__H__ -#define CVEC3__H__ - -#include -#include -#include - -#define cvec3_data(v) (&(v).x) - -#define declare_CVec3(tag, T) \ - typedef struct CVec3##tag { T x, y, z; } CVec3##tag; \ - static CVec3##tag cvec3##tag##_null = {0, 0, 0}; \ - static CVec3##tag cvec3##tag##_axis[3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; \ - \ - static inline CVec3##tag cvec3##tag(T x, T y, T z) { CVec3##tag v = {x, y, z}; return v; } \ - static inline CVec3##tag cvec3##tag##_init(const T* a) { CVec3##tag v = {a[0], a[1], a[2]}; return v; } \ - \ - static inline CVec3##tag cvec3##tag##_set(CVec3##tag* self, T x, T y, T z) { \ - self->x = x, self->y = y, self->z = z; return *self; \ - } \ - static inline CVec3##tag cvec3##tag##_setv(CVec3##tag* self, const T* a) { \ - self->x = a[0], self->y = a[1], self->z = a[2]; return *self; \ - } \ - static inline CVec3##tag cvec3##tag##_add(CVec3##tag* self, CVec3##tag v) { \ - self->x += v.x, self->y += v.y, self->z += v.z; return *self; \ - } \ - static inline CVec3##tag cvec3##tag##_subtract(CVec3##tag* self, CVec3##tag v) { \ - self->x -= v.x, self->y -= v.y, self->z -= v.z; return *self; \ - } \ - static inline CVec3##tag cvec3##tag##_scale(CVec3##tag* self, double s) { \ - self->x = (T)(self->x*s), self->y = (T)(self->y*s), self->z = (T)(self->z*s); \ - return *self; \ - } \ - static inline double cvec3##tag##_length(CVec3##tag v) { \ - return sqrt(_cvec3_DOT(v, v)); \ - } \ - static inline double cvec3##tag##_length2(CVec3##tag v) { \ - return _cvec3_DOT(v, v); \ - } \ - static inline CVec3##tag cvec3##tag##_plus(CVec3##tag u, CVec3##tag v) { \ - u.x += v.x, u.y += v.y, u.z += v.z; return u; \ - } \ - static inline CVec3##tag cvec3##tag##_minus(CVec3##tag u, CVec3##tag v) { \ - u.x -= v.x, u.y -= v.y, u.z -= v.z; return u; \ - } \ - static inline CVec3##tag cvec3##tag##_mult(CVec3##tag v, double s) { \ - v.x = (T)(s*v.x), v.y = (T)(s*v.y), v.z = (T)(s*v.z); return v; \ - } \ - static inline CVec3##tag cvec3##tag##_multInverse(CVec3##tag v, double s) { \ - v.x = (T)(s/v.x), v.y = (T)(s/v.y), v.z = (T)(s/v.z); return v; \ - } \ - static inline CVec3##tag cvec3##tag##_neg(CVec3##tag v) { \ - v.x = -v.x, v.y = -v.y, v.z = -v.z; return v; \ - } \ - static inline CVec3##tag cvec3##tag##_unit(CVec3##tag v) { \ - double s = 1.0 / sqrt(_cvec3_DOT(v, v)); \ - v.x = (T)(s*v.x), v.y = (T)(s*v.y), v.z = (T)(s*v.z); return v; \ - } \ - static inline double cvec3##tag##_dot(CVec3##tag u, CVec3##tag v) { \ - return _cvec3_DOT(u, v); \ - } \ - static inline CVec3##tag cvec3##tag##_cross(CVec3##tag u, CVec3##tag v) { \ - CVec3##tag c = {_cvec3_CROSS(T, u, v)}; \ - return c; \ - } \ - static inline double cvec3##tag##_triple(CVec3##tag u, CVec3##tag v, CVec3##tag w) { \ - CVec3##tag c = {_cvec3_CROSS(T, u, v)}; \ - return _cvec3_DOT(c, w); \ - } \ - /* Reflect u on plane with given normal vector n */ \ - static inline CVec3##tag cvec3##tag##_reflect(CVec3##tag u, CVec3##tag pn) { \ - double dot2 = 2.0 * _cvec3_DOT(u, pn); \ - u.x = (T)(u.x - dot2*pn.x), u.y = (T)(u.y - dot2*pn.y), u.z = (T)(u.z - dot2*pn.z); \ - return u; \ - } \ - /* Signed distance between point u and a plane (pp, pn), pn normalized. */ \ - static inline double cvec3##tag##_distanceToPlane(CVec3##tag u, CVec3##tag pp, CVec3##tag pn) { \ - u.x -= pp.x, u.y -= pp.y, u.z -= pp.z; \ - return _cvec3_DOT(u, pn); \ - } \ - /* Linear interpolation */ \ - static inline CVec3##tag cvec3##tag##_lerp(CVec3##tag u, CVec3##tag v, double t) { \ - double m = 1.0 - t; \ - u.x = (T)(m*u.x + t*v.x), u.y = (T)(m*u.y + t*v.y), u.z = (T)(m*u.z + t*v.z); \ - return u; \ - } \ - static inline bool cvec3##tag##_rayPlaneIntersection(CVec3##tag* out, CVec3##tag u, CVec3##tag dir, \ - CVec3##tag pp, CVec3##tag pn) { \ - double d = _cvec3_DOT(dir, pn); if (d == 0) return false; \ - double t = (_cvec3_DOT(pp, pn) - _cvec3_DOT(u, pn)) / d; \ - if (t < 0) return false; \ - u.x = (T)(u.x + dir.x*t), u.y = (T)(u.y + dir.y*t), u.z = (T)(u.z + dir.z*t); \ - *out = u; return true; \ - } \ - static inline bool cvec3##tag##_equals(CVec3##tag u, CVec3##tag v) { \ - if (u.x != v.x) return false; \ - if (u.y != v.y) return false; \ - return u.z == v.z; \ - } \ - static inline int cvec3##tag##_compare(CVec3##tag* u, CVec3##tag* v) { \ - if (u->x != v->x) return 1 - ((u->x < v->x)<<1); \ - if (u->y != v->y) return 1 - ((u->y < v->y)<<1); \ - return u->z == v->z ? 0 : 1 - ((u->z < v->z)<<1); \ - } \ - typedef T cvec3_##tag##_value_t - -#define _cvec3_DOT(u, v) ((double) u.x*v.x + u.y*v.y + u.z*v.z) -#define _cvec3_SUB(u, v) u.x - v.x, u.y - v.y, u.z - v.z -#define _cvec3_CROSS(T, u, v) (T) (u.y*v.z - v.y*u.z), (T) (u.z*v.x - v.z*u.x), (T) (u.x*v.y - u.y*v.x) - -declare_CVec3(d, double); -declare_CVec3(f, float); -declare_CVec3(i, int32_t); -//declare_CVec3(ui, uint32_t); -//declare_CVec3(s, int16_t); -//declare_CVec3(us, uint16_t); -declare_CVec3(ub, uint8_t); - -static inline CVec3f cvec3d_to3f(CVec3d v) { - CVec3f w = {(float) v.x, (float) v.y, (float) v.z}; return w; -} -static inline CVec3d cvec3f_to3d(CVec3f v) { - CVec3d w = {v.x, v.y, v.z}; return w; -} -static inline CVec3d cvec3i_to3d(CVec3i v) { - CVec3d w = {(double) v.x, (double) v.y, (double) v.z}; return w; -} - -#endif diff --git a/ccl/cvec4.h b/ccl/cvec4.h deleted file mode 100644 index abc5f3dd..00000000 --- a/ccl/cvec4.h +++ /dev/null @@ -1,126 +0,0 @@ -// MIT License -// -// Copyright (c) 2020 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 CVEC4__H__ -#define CVEC4__H__ - -#include "cvec3.h" - -#define cvec4_data(v) (&(v).x) - -#define declare_CVec4(tag, T) \ - typedef struct CVec4##tag { T x, y, z, w; } CVec4##tag; \ - static CVec4##tag cvec4##tag##_null = {0, 0, 0, 0}; \ - static CVec4##tag cvec4##tag##_axis[4] = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}; \ - \ - static inline CVec4##tag cvec4##tag(T x, T y, T z, T w) { CVec4##tag v = {x, y, z, w}; return v; } \ - static inline CVec4##tag cvec4##tag##_init(const T* a) { CVec4##tag v = {a[0], a[1], a[2], a[3]}; return v; } \ - \ - static inline CVec4##tag cvec4##tag##_set(CVec4##tag* self, T x, T y, T z, T w) { \ - self->x = x, self->y = y, self->z = z, self->z = z, self->w = w; return *self; \ - } \ - static inline CVec4##tag cvec4##tag##_setv(CVec4##tag* self, const T* a) { \ - self->x = a[0], self->y = a[1], self->z = a[2], self->w = a[3]; return *self; \ - } \ - static inline CVec4##tag cvec4##tag##_add(CVec4##tag* self, CVec4##tag v) { \ - self->x += v.x, self->y += v.y, self->z += v.z, self->w += v.w; return *self; \ - } \ - static inline CVec4##tag cvec4##tag##_subtract(CVec4##tag* self, CVec4##tag v) { \ - self->x -= v.x, self->y -= v.y, self->z -= v.z, self->w -= v.w; return *self; \ - } \ - static inline CVec4##tag cvec4##tag##_scale(CVec4##tag* self, double s) { \ - self->x = (T)(self->x*s), self->y = (T)(self->y*s), self->z = (T)(self->z*s), self->w = (T)(self->w*s); \ - return *self; \ - } \ - static inline double cvec4##tag##_length(CVec4##tag v) { \ - return sqrt(_cvec4_DOT(v, v)); \ - } \ - static inline double cvec4##tag##_length2(CVec4##tag v) { \ - return _cvec4_DOT(v, v); \ - } \ - static inline CVec4##tag cvec4##tag##_plus(CVec4##tag u, CVec4##tag v) { \ - u.x += v.x, u.y += v.y, u.z += v.z, u.w += v.w; return u; \ - } \ - static inline CVec4##tag cvec4##tag##_minus(CVec4##tag u, CVec4##tag v) { \ - u.x -= v.x, u.y -= v.y, u.z -= v.z, u.w -= v.w; return u; \ - } \ - static inline CVec4##tag cvec4##tag##_mult(CVec4##tag v, double s) { \ - v.x = (T)(s*v.x), v.y = (T)(s*v.y), v.z = (T)(s*v.z), v.w = (T)(s*v.w); return v; \ - } \ - static inline CVec4##tag cvec4##tag##_multInverse(CVec4##tag v, double s) { \ - v.x = (T)(s/v.x), v.y = (T)(s/v.y), v.z = (T)(s/v.z), v.w = (T)(s/v.w); return v; \ - } \ - static inline CVec4##tag cvec4##tag##_neg(CVec4##tag v) { \ - v.x = -v.x, v.y = -v.y, v.z = -v.z, v.w = -v.w; return v; \ - } \ - static inline CVec4##tag cvec4##tag##_unit(CVec4##tag v) { \ - double s = 1.0 / sqrt(_cvec4_DOT(v, v)); \ - v.x = (T)(s*v.x), v.y = (T)(s*v.y), v.z = (T)(s*v.z), v.w = (T)(s*v.w); return v; \ - } \ - static inline double cvec4##tag##_dot(CVec4##tag u, CVec4##tag v) { \ - return _cvec4_DOT(u, v); \ - } \ - /* Linear interpolation */ \ - static inline CVec4##tag cvec4##tag##_lerp(CVec4##tag u, CVec4##tag v, double t) { \ - double m = 1.0 - t; \ - u.x = (T)(m*u.x + t*v.x), u.y = (T)(m*u.y + t*v.y), u.z = (T)(m*u.z + t*v.z), u.w = (T)(m*u.w + t*v.w); \ - return u; \ - } \ - static inline bool cvec4##tag##_equals(CVec4##tag u, CVec4##tag v) { \ - if (u.x != v.x) return false; \ - if (u.y != v.y) return false; \ - if (u.z != v.z) return false; \ - return u.w == v.w; \ - } \ - static inline int cvec4##tag##_compare(CVec4##tag* u, CVec4##tag* v) { \ - if (u->x != v->x) return 1 - ((u->x < v->x)<<1); \ - if (u->y != v->y) return 1 - ((u->y < v->y)<<1); \ - if (u->z != v->z) return 1 - ((u->z < v->z)<<1); \ - return u->w == v->w ? 0 : 1 - ((u->w < v->w)<<1); \ - } \ - typedef T cvec4_##tag##_value_t - -#define _cvec4_DOT(u, v) ((double) u.x*v.x + u.y*v.y + u.z*v.z + u.w*v.w) -#define _cvec4_SUB(u, v) u.x - v.x, u.y - v.y, u.z - v.z, u.w - v.w - -declare_CVec4(d, double); -declare_CVec4(f, float); -declare_CVec4(i, int32_t); -//declare_CVec4(ui, uint32_t); -//declare_CVec4(s, int16_t); -//declare_CVec4(us, uint16_t); -declare_CVec4(ub, uint8_t); - -static inline CVec4d cvec4f_to4d(CVec4f v) { - CVec4d u = {v.x, v.y, v.z, v.w}; return u; -} -static inline CVec4f cvec4d_to4f(CVec4d v) { - CVec4f u = {(float) v.x, (float) v.y, (float) v.z, (float) v.w}; return u; -} -static inline CVec3d cvec4d_to3d(CVec4d v) { - CVec3d u = {v.x, v.y, v.z}; return u; -} -static inline CVec3f cvec4d_to3f(CVec4d v) { - CVec3f u = {(float) v.x, (float) v.y, (float) v.z}; return u; -} - -#endif diff --git a/ccl/cvector.h b/ccl/cvector.h deleted file mode 100644 index 93aaa550..00000000 --- a/ccl/cvector.h +++ /dev/null @@ -1,165 +0,0 @@ -// MIT License -// -// Copyright (c) 2020 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 CVECTOR__H__ -#define CVECTOR__H__ - -#include -#include -#include "cdefs.h" - -#define cvector_init {NULL} -#define cvector_size(cv) _cvector_safe_size((cv).data) -#define cvector_capacity(cv) _cvector_safe_capacity((cv).data) -#define cvector_empty(cv) (_cvector_safe_size((cv).data) == 0) - -#define declare_CVector(...) c_MACRO_OVERLOAD(declare_CVector, __VA_ARGS__) -#define declare_CVector_2(tag, Value) \ - declare_CVector_3(tag, Value, c_defaultDestroy) -#define declare_CVector_3(tag, Value, valueDestroy) \ - declare_CVector_4(tag, Value, valueDestroy, c_defaultCompare) -#define declare_CVector_4(tag, Value, valueDestroy, valueCompare) \ - declare_CVector_6(tag, Value, valueDestroy, valueCompare, Value, c_defaultGetRaw) -#define declare_CVector_string(tag) \ - declare_CVector_6(tag, CString, cstring_destroy, cstring_compareRaw, const char*, cstring_getRaw) - -#define declare_CVector_6(tag, Value, valueDestroy, valueCompare, ValueRaw, valueGetRaw) \ -typedef struct CVector_##tag { \ - Value* data; \ -} CVector_##tag; \ -static const CVector_##tag cvector_##tag##_init = cvector_init; \ - \ -typedef struct cvector_##tag##_iter_t { \ - Value* item; \ -} cvector_##tag##_iter_t; \ - \ -static inline void cvector_##tag##_swap(CVector_##tag* a, CVector_##tag* b) { \ - Value* data = a->data; a->data = b->data; b->data = data; \ -} \ - \ -static inline void cvector_##tag##_destroy(CVector_##tag* self) { \ - Value* p = self->data; \ - size_t i = 0, n = cvector_size(*self); \ - for (; i < n; ++p, ++i) valueDestroy(p); \ - free(_cvector_alloced(self->data)); \ -} \ - \ -static inline void cvector_##tag##_reserve(CVector_##tag* self, size_t cap) { \ - size_t len = cvector_size(*self); \ - if (cap >= len) { \ - size_t* rep = (size_t *) realloc(_cvector_alloced(self->data), 2 * sizeof(size_t) + cap * sizeof(Value)); \ - self->data = (Value *) (rep + 2); \ - rep[0] = len; \ - rep[1] = cap; \ - } \ -} \ - \ -static inline void cvector_##tag##_clear(CVector_##tag* self) { \ - CVector_##tag cv = cvector_##tag##_init; \ - cvector_##tag##_destroy(self); \ - *self = cv; \ -} \ - \ - \ -static inline void cvector_##tag##_push(CVector_##tag* self, Value value) { \ - size_t newsize = cvector_size(*self) + 1; \ - if (newsize > cvector_capacity(*self)) \ - cvector_##tag##_reserve(self, 7 + newsize * 5 / 3); \ - self->data[cvector_size(*self)] = value; \ - _cvector_size(*self) = newsize; \ -} \ - \ -static inline void cvector_##tag##_insert(CVector_##tag* self, size_t pos, Value value) { \ - cvector_##tag##_push(self, value); \ - size_t len = cvector_size(*self); \ - memmove(&self->data[pos + 1], &self->data[pos], (len - pos - 1) * sizeof(Value)); \ - self->data[pos] = value; \ -} \ - \ -static inline void cvector_##tag##_erase(CVector_##tag* self, size_t pos, size_t size) { \ - size_t len = cvector_size(*self); \ - if (len) { \ - Value* p = &self->data[pos], *start = p, *end = p + size; \ - while (p != end) valueDestroy(p++); \ - memmove(start, end, (len - pos - size) * sizeof(Value)); \ - _cvector_size(*self) -= size; \ - } \ -} \ - \ -static inline int cvector_##tag##_sortCompare(const void* x, const void* y) { \ - return valueCompare(valueGetRaw((const Value *) x), valueGetRaw((const Value *) y)); \ -} \ - \ -static inline void cvector_##tag##_sort(CVector_##tag* self) { \ - size_t len = cvector_size(*self); \ - if (len) qsort(self->data, len, sizeof(Value), cvector_##tag##_sortCompare); \ -} \ - \ -static inline size_t cvector_##tag##_find(CVector_##tag cv, ValueRaw rawValue) { \ - size_t n = cvector_size(cv); \ - for (size_t i = 0; i < n; ++i) { \ - if (valueCompare(valueGetRaw(&cv.data[i]), &rawValue) == 0) return i; \ - } \ - return c_npos; \ -} \ - \ - \ -static inline Value cvector_##tag##_back(CVector_##tag cv) { \ - return cv.data[_cvector_size(cv) - 1]; \ -} \ - \ -static inline void cvector_##tag##_pop(CVector_##tag* self) { \ - valueDestroy(&self->data[_cvector_size(*self) - 1]); \ - --_cvector_size(*self); \ -} \ - \ -static inline cvector_##tag##_iter_t cvector_##tag##_begin(CVector_##tag vec) { \ - cvector_##tag##_iter_t it = {vec.data}; \ - return it; \ -} \ - \ -static inline cvector_##tag##_iter_t cvector_##tag##_next(cvector_##tag##_iter_t it) { \ - ++it.item; \ - return it; \ -} \ - \ -static inline cvector_##tag##_iter_t cvector_##tag##_end(CVector_##tag vec) { \ - cvector_##tag##_iter_t it = {vec.data + cvector_size(vec)}; \ - return it; \ -} \ -typedef Value cvector_##tag##_value_t - - -#define _cvector_size(cv) ((size_t *)(cv).data)[-2] -#define _cvector_capacity(cv) ((size_t *)(cv).data)[-1] - -static inline size_t* _cvector_alloced(void* data) { - return data ? ((size_t *) data) - 2 : NULL; -} -static inline size_t _cvector_safe_size(const void* data) { - return data ? ((const size_t *) data)[-2] : 0; -} -static inline size_t _cvector_safe_capacity(const void* data) { - return data ? ((const size_t *) data)[-1] : 0; -} - -#endif diff --git a/stc/carray.h b/stc/carray.h new file mode 100644 index 00000000..ddb4bd9d --- /dev/null +++ b/stc/carray.h @@ -0,0 +1,65 @@ +#ifndef CARRAY__H__ +#define CARRAY__H__ + +#include "cdefs.h" + +#define carray_xdim(a) ((a).xdim) +#define carray_ydim(a) ((a)._yxdim / (a).xdim) +#define carray_zdim(a) ((a).zdim) +#define carray_ref(a) (++(a)._refCount, a) +#define carray_unref(a) ({if (--(a)._refCount == 0) free((a).data);0;}) + +/* // demo: +#include "ccl/carray.h" +declare_CArray(f, float); + +int main() +{ + CArray3f a3 = carray3f_make(30, 20, 10); + carray3f_at2(a3, 3, 2).data[1] = 10.2f; + CArray2f a2 = carray3f_at(a3, 3); + printf("%f\n", carray2f_at(a2, 2).data[1]); + carray_unref(a2); + carray_unref(a3); +} +*/ + +#define declare_CArray(tag, T) \ + c_struct (CArray1##tag) { \ + T* data; \ + int _refCount; \ + size_t xdim; \ + }; \ + c_struct (CArray2##tag) { \ + T* data; \ + int _refCount; \ + size_t xdim, _yxdim; \ + }; \ + c_struct (CArray3##tag) { \ + T* data; \ + int _refCount; \ + size_t xdim, _yxdim, zdim; \ + }; \ + \ + static inline CArray1##tag carray1##tag##_make(size_t xdim) { \ + CArray1##tag a = {c_new_2(T, xdim), 1, xdim}; return a; \ + } \ + static inline CArray2##tag carray2##tag##_make(size_t ydim, size_t xdim) { \ + CArray2##tag a = {c_new_2(T, ydim*xdim), 1, xdim, ydim*xdim}; return a; \ + } \ + static inline CArray3##tag carray3##tag##_make(size_t zdim, size_t ydim, size_t xdim) { \ + CArray3##tag a = {c_new_2(T, zdim*ydim*xdim), 1, xdim, ydim*xdim, zdim}; return a; \ + } \ + \ + static inline CArray1##tag carray2##tag##_at(CArray2##tag a, size_t y) { \ + CArray1##tag out = {a.data + y*a.xdim, 1000, a.xdim}; return out; \ + } \ + static inline CArray2##tag carray3##tag##_at(CArray3##tag a, size_t z) { \ + CArray2##tag out = {a.data + z*a._yxdim, 1000, a.xdim, a._yxdim}; return out; \ + } \ + static inline CArray1##tag carray3##tag##_at2(CArray3##tag a, size_t z, size_t y) { \ + CArray1##tag out = {a.data + z*a._yxdim + y*a.xdim, 1000, a.xdim}; return out; \ + } \ + typedef T carray_##tag##_t + +#endif \ No newline at end of file diff --git a/stc/cdefs.h b/stc/cdefs.h new file mode 100644 index 00000000..9a29c36b --- /dev/null +++ b/stc/cdefs.h @@ -0,0 +1,85 @@ +// MIT License +// +// Copyright (c) 2020 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 CDEFS__H__ +#define CDEFS__H__ + +#include +#include + +// Macro overloading feature support: https://rextester.com/ONP80107 +#define c_CAT( A, B ) A ## B +#define c_EXPAND(...) __VA_ARGS__ +#define c_VA_ARG_SIZE(...) c_EXPAND(c_APPLY_ARG_N((__VA_ARGS__, c_RSEQ_N))) +#define c_APPLY_ARG_N(ARGS) c_EXPAND(c_ARG_N ARGS) +#define c_ARG_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N,...) N +#define c_RSEQ_N 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +#define c_OVERLOAD_SELECT(NAME, NUM) c_CAT( NAME ## _, NUM) + +#define c_MACRO_OVERLOAD(NAME, ...) c_OVERLOAD_SELECT(NAME, c_VA_ARG_SIZE(__VA_ARGS__))(__VA_ARGS__) + + +#define c_new(...) c_MACRO_OVERLOAD(c_new, __VA_ARGS__) +#define c_new_1(T) ((T *) malloc(sizeof(T))) +#define c_new_2(T, n) ((T *) malloc(sizeof(T) * (n))) + +#define c_struct(S) typedef struct S S; struct S +#define c_npos ((size_t) -1) +#define c_max_alloca (1000) +#define c_swap(T, x, y) { T __t = x; x = y; y = __t; } + +#define c_defaultInitRaw(x) (x) +#define c_defaultGetRaw(x) (x) +#define c_defaultCompare(x, y) (*(x) == *(y) ? 0 : *(x) < *(y) ? -1 : 1) +#define c_defaultEquals(x, y) (memcmp(x, y, sizeof(*(y))) == 0) +#define c_defaultDestroy(p) (p) +//static inline void c_defaultDestroy(void* value) {} + +#define c_foreach(it, ctag, con) \ + for (ctag##_iter_t it = ctag##_begin(con); it.item != ctag##_end(con).item; it = ctag##_next(it)) + +// One-byte-at-a-time hash based on Murmur's mix +static inline uint32_t c_defaultHash(const void *data, size_t len) { + const uint8_t *key = (const uint8_t *) data; + uint32_t x = UINT32_C(0xc613fc15); + while (len--) { + x ^= *key++; + x *= UINT32_C(0x5bd1e995); + x ^= x >> 15; + } + return x; +} + +// https://nullprogram.com/blog/2018/07/31/: assume len positive multiple of 4 +static inline uint32_t c_lowbias32Hash(const void *data, size_t len) { + const uint32_t *key = (const uint32_t *) data; uint32_t x = *key; + do { + x ^= *key++ >> 16; + x *= UINT32_C(0x7feb352d); + x ^= x >> 15; + x *= UINT32_C(0x846ca68b); + x ^= x >> 16; + } while (len -= 4); + return x; +} + +#endif diff --git a/stc/cmap.h b/stc/cmap.h new file mode 100644 index 00000000..b14f9e3b --- /dev/null +++ b/stc/cmap.h @@ -0,0 +1,257 @@ +// MIT License +// +// Copyright (c) 2020 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 CMAP_H_ +#define CMAP_H_ + +#include "cvector.h" + + +#define cmap_init {cvector_init, 0, 90, 0} +#define cmap_size(map) ((size_t) (map)._size) +#define cmap_bucketCount(map) cvector_capacity((map)._table) + + +// CMapEntry: +#define declare_CMapEntry(tag, Key, Value, valueDestroy, keyDestroy) \ +struct CMapEntry_##tag { \ + Key key; \ + Value value; \ + uint16_t hashx; \ +}; \ + \ +static inline struct CMapEntry_##tag cmapentry_##tag##_make(Key key, Value value) { \ + struct CMapEntry_##tag e = {key, value, 0}; \ + return e; \ +} \ +static inline void cmapentry_##tag##_destroy(struct CMapEntry_##tag* e) { \ + keyDestroy(&e->key); \ + valueDestroy(&e->value); \ + e->hashx = 0; \ +} \ +typedef struct CMapEntry_##tag CMapEntry_##tag + +enum {cmapentry_HASH=0x7fff, cmapentry_USED=0x8000}; +#define cmapentry_noCompare(x, y) (0) + + +// CMap: +#define declare_CMap(...) c_MACRO_OVERLOAD(declare_CMap, __VA_ARGS__) + +#define declare_CMap_3(tag, Key, Value) \ + declare_CMap_4(tag, Key, Value, c_defaultDestroy) + +#define declare_CMap_4(tag, Key, Value, valueDestroy) \ + declare_CMap_5(tag, Key, Value, valueDestroy, c_defaultHash) + +#define declare_CMap_5(tag, Key, Value, valueDestroy, keyHash) \ + declare_CMap_7(tag, Key, Value, valueDestroy, keyHash, c_defaultEquals, c_defaultDestroy) + +#define declare_CMap_7(tag, Key, Value, valueDestroy, keyHash, keyEquals, keyDestroy) \ + declare_CMap_10(tag, Key, Value, valueDestroy, keyHash, keyEquals, keyDestroy, \ + Key, c_defaultGetRaw, c_defaultInitRaw) + + +// CMap: +#define declare_CMap_stringkey(...) c_MACRO_OVERLOAD(declare_CMap_stringkey, __VA_ARGS__) + +#define declare_CMap_stringkey_2(tag, Value) \ + declare_CMap_stringkey_3(tag, Value, c_defaultDestroy) + +#define declare_CMap_stringkey_3(tag, Value, valueDestroy) \ + declare_CMap_10(tag, CString, Value, valueDestroy, cstring_hashRaw, cstring_equalsRaw, cstring_destroy, \ + const char* const, cstring_getRaw, cstring_make) + + +// CMap full: +#define declare_CMap_10(tag, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, keyDestroy, \ + RawKey, keyGetRaw, keyInitRaw) \ + declare_CMapEntry(tag, Key, Value, valueDestroy, keyDestroy); \ + declare_CVector_4(map_##tag, CMapEntry_##tag, cmapentry_##tag##_destroy, cmapentry_noCompare); \ + typedef RawKey cmap_##tag##_rawkey_t; \ + \ +typedef struct CMap_##tag { \ + CVector_map_##tag _table; \ + size_t _size; \ + uint8_t maxLoadPercent; \ + uint8_t shrinkLimitPercent; \ +} CMap_##tag; \ +static const CMap_##tag cmap_##tag##_init = cmap_init; \ + \ +typedef struct cmap_##tag##_iter_t { \ + CMapEntry_##tag *item, *_end; \ +} cmap_##tag##_iter_t; \ + \ +static inline void cmap_##tag##_destroy(CMap_##tag* self) { \ + if (cmap_size(*self)) { \ + size_t cap = _cvector_capacity(self->_table); \ + CMapEntry_##tag* e = self->_table.data, *end = e + cap; \ + for (; e != end; ++e) if (e->hashx) cmapentry_##tag##_destroy(e); \ + } \ + free(_cvector_alloced(self->_table.data)); \ +} \ + \ +static inline size_t cmap_##tag##_reserve(CMap_##tag* self, size_t size); /* predeclared */ \ + \ +static inline void cmap_##tag##_clear(CMap_##tag* self) { \ + memset(self->_table.data, 0, sizeof(CMapEntry_##tag) * _cvector_capacity(self->_table)); \ + self->_size = 0; \ +} \ + \ +static inline void cmap_##tag##_swap(CMap_##tag* a, CMap_##tag* b) { \ + c_swap(CMap_##tag, *a, *b); \ +} \ + \ +static inline void cmap_##tag##_setMaxLoadFactor(CMap_##tag* self, double fac) { \ + self->maxLoadPercent = (uint8_t) (fac * 100); \ + if (cmap_size(*self) >= cmap_bucketCount(*self) * fac) \ + cmap_##tag##_reserve(self, (size_t) (cmap_size(*self) / fac)); \ +} \ + \ +static inline void cmap_##tag##_setShrinkLimitFactor(CMap_##tag* self, double limit) { \ + self->shrinkLimitPercent = (uint8_t) (limit * 100); \ + if (cmap_size(*self) < cmap_bucketCount(*self) * limit) \ + cmap_##tag##_reserve(self, (size_t) (cmap_size(*self) * 1.2 / limit)); \ +} \ + \ +static inline size_t cmap_##tag##_bucket(CMap_##tag* self, cmap_##tag##_rawkey_t* const rawKey, uint32_t* hxPtr) { \ + uint32_t hash = keyHashRaw(rawKey, sizeof(cmap_##tag##_rawkey_t)), hx = (hash & cmapentry_HASH) | cmapentry_USED; \ + size_t cap = cvector_capacity(self->_table); \ + size_t idx = cmap_reduce(hash, cap); \ + CMapEntry_##tag* slot = self->_table.data; \ + while (slot[idx].hashx && (slot[idx].hashx != hx || !keyEqualsRaw((RawKey* const) keyGetRaw(&slot[idx].key), rawKey))) { \ + if (++idx == cap) idx = 0; \ + } \ + *hxPtr = hx; \ + return idx; \ +} \ + \ +static inline CMapEntry_##tag* cmap_##tag##_get(CMap_##tag map, cmap_##tag##_rawkey_t rawKey) { \ + if (cmap_size(map) == 0) return NULL; \ + uint32_t hx; \ + size_t idx = cmap_##tag##_bucket(&map, &rawKey, &hx); \ + return map._table.data[idx].hashx ? &map._table.data[idx] : NULL; \ +} \ + \ +static inline void cmap_##tag##_expand(CMap_##tag* self) { \ + size_t cap = cvector_capacity(self->_table); \ + if (cmap_size(*self) + 1 >= cap * self->maxLoadPercent * 0.01) \ + cmap_##tag##_reserve(self, (size_t) 7 + (1.6 * cap)); \ +} \ + \ +static inline CMapEntry_##tag* cmap_##tag##_put(CMap_##tag* self, cmap_##tag##_rawkey_t rawKey, Value value) { \ + cmap_##tag##_expand(self); \ + uint32_t hx; \ + size_t idx = cmap_##tag##_bucket(self, &rawKey, &hx); \ + CMapEntry_##tag* e = &self->_table.data[idx]; \ + if (! e->hashx) { \ + e->key = keyInitRaw(rawKey); \ + e->hashx = hx; \ + ++self->_size; \ + } \ + e->value = value; \ + return e; \ +} \ + \ +static inline CMapEntry_##tag* cmap_##tag##_insert(CMap_##tag* self, CMapEntry_##tag entry) { \ + cmap_##tag##_expand(self); \ + uint32_t hx; \ + size_t idx = cmap_##tag##_bucket(self, (RawKey* const) keyGetRaw(&entry.key), &hx); \ + CMapEntry_##tag* e = &self->_table.data[idx]; \ + if (! e->hashx) { \ + e->key = entry.key; \ + e->hashx = hx; \ + ++self->_size; \ + } \ + e->value = entry.value; \ + return e; \ +} \ + \ +static inline size_t cmap_##tag##_reserve(CMap_##tag* self, size_t size) { \ + size_t oldcap = cvector_capacity(self->_table), newcap = 1 + (size / 2) * 2; \ + if (cmap_size(*self) >= newcap * self->maxLoadPercent * 0.01) return oldcap; \ + CVector_map_##tag vec = cvector_map_##tag##_init; \ + cvector_map_##tag##_reserve(&vec, newcap); \ + memset(vec.data, 0, sizeof(CMapEntry_##tag) * newcap); \ + cvector_map_##tag##_swap(&self->_table, &vec); \ + \ + CMapEntry_##tag* e = vec.data, *slot = self->_table.data; \ + uint32_t hx; \ + for (size_t i = 0; i < oldcap; ++i, ++e) \ + if (e->hashx) \ + slot[ cmap_##tag##_bucket(self, (RawKey* const) keyGetRaw(&e->key), &hx) ] = *e; \ + free(_cvector_alloced(vec.data)); /* not cvector_destroy() here */ \ + return newcap; \ +} \ + \ +static inline bool cmap_##tag##_erase(CMap_##tag* self, cmap_##tag##_rawkey_t rawKey) { \ + if (cmap_size(*self) == 0) \ + return false; \ + size_t cap = cvector_capacity(self->_table); \ + if (cmap_size(*self) < cap * self->shrinkLimitPercent * 0.01) \ + cap = cmap_##tag##_reserve(self, cmap_size(*self) * 120 / self->maxLoadPercent); \ + uint32_t hx; \ + size_t i = cmap_##tag##_bucket(self, &rawKey, &hx), j = i, k; \ + CMapEntry_##tag* slot = self->_table.data; \ + if (! slot[i].hashx) \ + return false; \ + do { /* deletion from hash table without tombstone */ \ + if (++j == cap) j = 0; /* j %= cap; is slow */ \ + if (! slot[j].hashx) \ + break; \ + k = cmap_reduce(keyHashRaw((RawKey* const) keyGetRaw(&slot[j].key), sizeof(cmap_##tag##_rawkey_t)), cap); \ + if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */ \ + slot[i] = slot[j], i = j; \ + } while (true); \ + cmapentry_##tag##_destroy(&slot[i]); /* sets used=false */ \ + --self->_size; \ + return true; \ +} \ + \ +static inline cmap_##tag##_iter_t cmap_##tag##_begin(CMap_##tag map) { \ + cmap_##tag##_iter_t null = {NULL, NULL}; \ + if (cmap_size(map) == 0) return null; \ + CMapEntry_##tag* e = map._table.data, *end = e + _cvector_capacity(map._table); \ + while (e != end && !e->hashx) ++e; \ + cmap_##tag##_iter_t it = {e, end}; return it; \ +} \ + \ +static inline cmap_##tag##_iter_t cmap_##tag##_next(cmap_##tag##_iter_t it) { \ + do { ++it.item; } while (it.item != it._end && !it.item->hashx); \ + return it; \ +} \ + \ +static inline cmap_##tag##_iter_t cmap_##tag##_end(CMap_##tag map) { \ + CMapEntry_##tag* end = (cmap_size(map) == 0) ? NULL : map._table.data + _cvector_capacity(map._table); \ + cmap_##tag##_iter_t it = {end, end}; \ + return it; \ +} \ +typedef Key cmap_##tag##_key_t; \ +typedef Value cmap_##tag##_value_t + + +// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ +static inline uint32_t cmap_reduce(uint32_t x, uint32_t N) { + return ((uint64_t) x * (uint64_t) N) >> 32 ; +} + +#endif diff --git a/stc/copt.h b/stc/copt.h new file mode 100644 index 00000000..fb810e10 --- /dev/null +++ b/stc/copt.h @@ -0,0 +1,181 @@ +// MIT License +// +// Copyright (c) 2020 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. + +// Inspired by https://attractivechaos.wordpress.com/2018/08/31/a-survey-of-argument-parsing-libraries-in-c-c +// Fixed major bugs with option arguments (both long and short), and shows a useful demo of the features. +// Has a more consistent API, added arg->bad output field, written in C99. + +#ifndef COPT__H__ +#define COPT__H__ + +#include +#include + +enum { + copt_no_argument = 0, + copt_required_argument = 1, + copt_optional_argument = 2 +}; +typedef struct { + int ind; // equivalent to optind + int opt; // equivalent to optopt + char *arg; // equivalent to optarg + char *bad; // points to the faulty option + int longindex; // idx of long option; or -1 if short + int _i, _pos, _nargs; + char _bad[4]; +} copt_t; + +struct copt_option { + char *name; + int has_arg; + int val; +}; + +static const copt_t copt_init = {1, 0, NULL, NULL, -1, 1, 0, 0, {'-', 0, 0, 0}}; + +static void _copt_permute(char *argv[], int j, int n) { // move argv[j] over n elements to the left + int k; + char *p = argv[j]; + for (k = 0; k < n; ++k) + argv[j - k] = argv[j - k - 1]; + argv[j - k] = p; +} + + +// Parse command-line options and arguments +// +// This fuction has a similar interface to GNU's getopt_long(). Each call +// parses one option and returns the option name. opt->arg points to the option +// argument if present. The function returns -1 when all command-line arguments +// are parsed. In this case, opt->ind is the index of the first non-option +// argument. +// +// @param opt output; must be initialized to copt_init on first call +// @param posixly_correct if true, do not move options ahead of non-option arguments, +// instead stop option processing on first nonoption argument. +// @return ASCII val for a short option; longopt.val for a long option; +// -1 if argv[] is fully processed; '?' for an unknown option or +// an ambiguous long option; ':' if an option argument is missing +// +static int copt_getopt(copt_t *opt, int argc, char *argv[], + const char *shortopts, const struct copt_option *longopts, + bool posixly_correct) { + int optc = -1, i0, j; + if (!posixly_correct) { + while (opt->_i < argc && (argv[opt->_i][0] != '-' || argv[opt->_i][1] == '\0')) + ++opt->_i, ++opt->_nargs; + } + opt->arg = 0, opt->longindex = -1, i0 = opt->_i; + if (opt->_i >= argc || argv[opt->_i][0] != '-' || argv[opt->_i][1] == '\0') { + opt->ind = opt->_i - opt->_nargs; + return -1; + } + if (argv[opt->_i][0] == '-' && argv[opt->_i][1] == '-') { // "--" or a long option + if (argv[opt->_i][2] == '\0') { // a bare "--" + _copt_permute(argv, opt->_i, opt->_nargs); + ++opt->_i, opt->ind = opt->_i - opt->_nargs; + return -1; + } + opt->opt = 0, optc = '?', opt->_pos = -1; + if (longopts) { // parse long options + int k, n_exact = 0, n_partial = 0; + const struct copt_option *o = 0, *o_exact = 0, *o_partial = 0; + for (j = 2; argv[opt->_i][j] != '\0' && argv[opt->_i][j] != '='; ++j) {} // find the end of the option name + for (k = 0; longopts[k].name != 0; ++k) + if (strncmp(&argv[opt->_i][2], longopts[k].name, j - 2) == 0) { + if (longopts[k].name[j - 2] == 0) ++n_exact, o_exact = &longopts[k]; + else ++n_partial, o_partial = &longopts[k]; + } + opt->bad = argv[opt->_i]; + if (n_exact > 1 || (n_exact == 0 && n_partial > 1)) return '?'; + o = n_exact == 1? o_exact : n_partial == 1? o_partial : 0; + if (o) { + opt->opt = optc = o->val, opt->longindex = o - longopts; + if (o->has_arg != copt_no_argument) { + if (argv[opt->_i][j] == '=') + opt->arg = &argv[opt->_i][j + 1]; + else if (argv[opt->_i][j] == '\0' && opt->_i < argc - 1 && (o->has_arg == copt_required_argument || + argv[opt->_i + 1][0] != '-')) + opt->arg = argv[++opt->_i]; + else if (o->has_arg == copt_required_argument) + optc = ':'; // missing option argument + } + } + } + } else { // a short option + const char *p; + if (opt->_pos == 0) opt->_pos = 1; + optc = opt->opt = argv[opt->_i][opt->_pos++]; + opt->_bad[1] = optc, opt->bad = opt->_bad; + p = strchr((char *) shortopts, optc); + if (p == 0) { + optc = '?'; // unknown option + } else if (p[1] == ':') { + if (argv[opt->_i][opt->_pos] != '\0') + opt->arg = &argv[opt->_i][opt->_pos]; + else if (opt->_i < argc - 1 && (p[2] != ':' || argv[opt->_i + 1][0] != '-')) + opt->arg = argv[++opt->_i]; + else if (p[2] != ':') + optc = ':'; + opt->_pos = -1; + } + } + if (opt->_pos < 0 || argv[opt->_i][opt->_pos] == 0) { + ++opt->_i, opt->_pos = 0; + if (opt->_nargs > 0) // permute + for (j = i0; j < opt->_i; ++j) + _copt_permute(argv, j, opt->_nargs); + } + opt->ind = opt->_i - opt->_nargs; + return optc; +} + +/* // demo: + int main(int argc, char *argv[]) + { + static struct copt_option longopts[] = { + {"foo", copt_no_argument, 'f'}, + {"bar", copt_required_argument, 'b'}, + {"opt", copt_optional_argument, 'o'}, + {NULL} + }; + const char* optstr = "xy:z::123"; + printf("program -x -y ARG -z [ARG] -1 -2 -3 --foo --bar ARG --opt [ARG] [ARGUMENTS]\n"); + int c; + copt_t opt = copt_init; + while ((c = copt_getopt(&opt, argc, argv, optstr, longopts, false)) != -1) { + switch (c) { + case '?': printf("error: unknown option: %s\n", opt.bad); break; + case ':': printf("error: missing argument for %s\n", opt.bad); break; + default: printf("option: %c [%s]\n", c, opt.arg ? opt.arg : ""); break; + } + } + printf("\nNon-option arguments:"); + for (int i = opt.ind; i < argc; ++i) + printf(" %s", argv[i]); + putchar('\n'); + return 0; + } +*/ + +#endif diff --git a/stc/cstring.h b/stc/cstring.h new file mode 100644 index 00000000..d0719cb6 --- /dev/null +++ b/stc/cstring.h @@ -0,0 +1,246 @@ +// MIT License +// +// Copyright (c) 2020 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 CSTRING__H__ +#define CSTRING__H__ + +#include +#include +#include +#include + +#include "cdefs.h" + +typedef struct CString { + char* str; +} CString; + + +static size_t _cstring_null_rep[] = {0, 0, 0}; +#define _cstring_rep(cs) (((size_t *) (cs).str) - 2) + +#define cstring_size(cs) ((size_t) _cstring_rep(cs)[0]) +#define cstring_capacity(cs) ((size_t) _cstring_rep(cs)[1]) +#define cstring_npos c_npos + + +static const CString cstring_init = {(char* ) &_cstring_null_rep[2]}; + +static inline void cstring_reserve(CString* self, size_t cap) { + size_t len = cstring_size(*self), oldcap = cstring_capacity(*self); + if (cap > oldcap) { + size_t* rep = (size_t *) realloc(oldcap ? _cstring_rep(*self) : NULL, sizeof(size_t) * 2 + cap + 1); + self->str = (char* ) (rep + 2); + self->str[ rep[0] = len ] = '\0'; + rep[1] = cap; + } +} + +static inline void cstring_destroy(CString* self) { + if (cstring_capacity(*self)) { + free(_cstring_rep(*self)); + } +} + +static inline CString cstring_makeN(const char* str, size_t len) { + CString cs = cstring_init; + if (len) { + cstring_reserve(&cs, len); + memcpy(cs.str, str, len); + cs.str[ _cstring_rep(cs)[0] = len ] = '\0'; + } + return cs; +} + +static inline CString cstring_make(const char* str) { + return cstring_makeN(str, strlen(str)); +} + +static inline CString cstring_makeCopy(CString cs) { + return cstring_makeN(cs.str, cstring_size(cs)); +} + +static inline void cstring_clear(CString* self) { + CString cs = cstring_init; + cstring_destroy(self); + *self = cs; +} + +static inline CString* cstring_assignN(CString* self, const char* str, size_t len) { + if (len) { + cstring_reserve(self, len); + memmove(self->str, str, len); + self->str[_cstring_rep(*self)[0] = len] = '\0'; + } + return self; +} + +static inline CString* cstring_assign(CString* self, const char* str) { + return cstring_assignN(self, str, strlen(str)); +} + +static inline CString* cstring_copy(CString* self, CString cs2) { + return cstring_assignN(self, cs2.str, cstring_size(cs2)); +} + + +static inline CString* cstring_appendN(CString* self, const char* str, size_t len) { + if (len) { + size_t oldlen = cstring_size(*self), newlen = oldlen + len; + if (newlen > cstring_capacity(*self)) + cstring_reserve(self, newlen * 5 / 3); + memmove(&self->str[oldlen], str, len); + self->str[_cstring_rep(*self)[0] = newlen] = '\0'; + } + return self; +} + +static inline CString* cstring_append(CString* self, const char* str) { + return cstring_appendN(self, str, strlen(str)); +} +static inline CString* cstring_appendS(CString* self, CString cs2) { + return cstring_appendN(self, cs2.str, cstring_size(cs2)); +} + + +static inline void _cstring_internalMove(CString* self, size_t pos1, size_t pos2) { + if (pos1 == pos2) + return; + size_t len = cstring_size(*self), newlen = len + pos2 - pos1; + if (newlen > cstring_capacity(*self)) + cstring_reserve(self, newlen * 5 / 3); + memmove(&self->str[pos2], &self->str[pos1], len - pos1); + self->str[_cstring_rep(*self)[0] = newlen] = '\0'; +} + +static inline void cstring_insertN(CString* self, size_t pos, const char* str, size_t n) { + char* xstr = (char *) memcpy(n > c_max_alloca ? malloc(n) : alloca(n), str, n); + _cstring_internalMove(self, pos, pos + n); + memcpy(&self->str[pos], xstr, n); + if (n > c_max_alloca) free(xstr); +} + +static inline void cstring_insert(CString* self, size_t pos, const char* str) { + cstring_insertN(self, pos, str, strlen(str)); +} + +static inline void cstring_erase(CString* self, size_t pos, size_t n) { + size_t len = cstring_size(*self); + if (len) { + memmove(&self->str[pos], &self->str[pos + n], len - (pos + n)); + self->str[_cstring_rep(*self)[0] -= n] = '\0'; + } +} + +static inline size_t cstring_findN(CString cs, size_t pos, const char* needle, size_t n); + +static inline size_t cstring_replaceN(CString* self, size_t pos, const char* s1, size_t n1, const char* s2, size_t n2) { + size_t pos2 = cstring_findN(*self, pos, s1, n1); + if (pos2 == cstring_npos) return cstring_npos; + char* xs2 = (char *) memcpy(n2 > c_max_alloca ? malloc(n2) : alloca(n2), s2, n2); + _cstring_internalMove(self, pos2 + n1, pos2 + n2); + memcpy(&self->str[pos2], xs2, n2); + if (n2 > c_max_alloca) free(xs2); + return pos2; +} + +static inline size_t cstring_replace(CString* self, size_t pos, const char* s1, const char* s2) { + return cstring_replaceN(self, pos, s1, strlen(s1), s2, strlen(s2)); +} + + +static inline char cstring_back(CString cs) { + return cs.str[cstring_size(cs) - 1]; +} + +static inline CString* cstring_push(CString* self, char value) { + return cstring_appendN(self, &value, 1); +} + + +static inline void cstring_pop(CString* self) { + --_cstring_rep(*self)[0]; +} + +/* readonly */ + +static inline bool cstring_empty(CString cs) { + return cstring_size(cs) == 0; +} + +static inline bool cstring_equals(CString cs1, const char* str) { + return strcmp(cs1.str, str) == 0; +} +static inline bool cstring_equalsS(CString cs1, CString cs2) { + return strcmp(cs1.str, cs2.str) == 0; +} + +static inline char* cstring_strnstr(CString cs, size_t pos, const char* needle, size_t n) { + char *x = cs.str + pos, // haystack + *z = cs.str + cstring_size(cs) - n + 1; + if (x >= z) + return NULL; + ptrdiff_t sum = 0; + const char *y = x, *p = needle, *q = needle + n; + while (p != q) + sum += *y++ - *p++; + while (x != z) { + if (sum == 0 && memcmp(x, needle, n) == 0) + return x; + sum += *y++ - *x++; + } + return NULL; +} + +static inline size_t cstring_findN(CString cs, size_t pos, const char* needle, size_t n) { + char* res = cstring_strnstr(cs, pos, needle, n); + return res ? res - cs.str : cstring_npos; +} + +static inline size_t cstring_find(CString cs, size_t pos, const char* needle) { + char* res = strstr(cs.str + pos, needle); + return res ? res - cs.str : cstring_npos; +} + +static inline char* cstring_splitFirst(const char* delimiters, CString cs) { + return strtok(cs.str, delimiters); +} + +static inline char* cstring_splitNext(const char* delimiters) { + return strtok(NULL, delimiters); +} + +static inline CString cstring_temp(const char* str) { + // May only be used for accessing .str + CString temp = {(char *) str}; + return temp; +} + +// CVector / CMap API functions: + +#define cstring_getRaw(x) (&(x)->str) +#define cstring_compareRaw(x, y) strcmp(*(x), *(y)) +#define cstring_equalsRaw(x, y) (strcmp(*(x), *(y)) == 0) +static inline uint32_t cstring_hashRaw(const char* const* str, size_t ignored) { return c_defaultHash(*str, strlen(*str)); } + + +#endif diff --git a/stc/cvec3.h b/stc/cvec3.h new file mode 100644 index 00000000..3d8d91dc --- /dev/null +++ b/stc/cvec3.h @@ -0,0 +1,151 @@ +// MIT License +// +// Copyright (c) 2020 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 CVEC3__H__ +#define CVEC3__H__ + +#include +#include +#include + +#define cvec3_data(v) (&(v).x) + +#define declare_CVec3(tag, T) \ + typedef struct CVec3##tag { T x, y, z; } CVec3##tag; \ + static CVec3##tag cvec3##tag##_null = {0, 0, 0}; \ + static CVec3##tag cvec3##tag##_axis[3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; \ + \ + static inline CVec3##tag cvec3##tag(T x, T y, T z) { CVec3##tag v = {x, y, z}; return v; } \ + static inline CVec3##tag cvec3##tag##_init(const T* a) { CVec3##tag v = {a[0], a[1], a[2]}; return v; } \ + \ + static inline CVec3##tag cvec3##tag##_set(CVec3##tag* self, T x, T y, T z) { \ + self->x = x, self->y = y, self->z = z; return *self; \ + } \ + static inline CVec3##tag cvec3##tag##_setv(CVec3##tag* self, const T* a) { \ + self->x = a[0], self->y = a[1], self->z = a[2]; return *self; \ + } \ + static inline CVec3##tag cvec3##tag##_add(CVec3##tag* self, CVec3##tag v) { \ + self->x += v.x, self->y += v.y, self->z += v.z; return *self; \ + } \ + static inline CVec3##tag cvec3##tag##_subtract(CVec3##tag* self, CVec3##tag v) { \ + self->x -= v.x, self->y -= v.y, self->z -= v.z; return *self; \ + } \ + static inline CVec3##tag cvec3##tag##_scale(CVec3##tag* self, double s) { \ + self->x = (T)(self->x*s), self->y = (T)(self->y*s), self->z = (T)(self->z*s); \ + return *self; \ + } \ + static inline double cvec3##tag##_length(CVec3##tag v) { \ + return sqrt(_cvec3_DOT(v, v)); \ + } \ + static inline double cvec3##tag##_length2(CVec3##tag v) { \ + return _cvec3_DOT(v, v); \ + } \ + static inline CVec3##tag cvec3##tag##_plus(CVec3##tag u, CVec3##tag v) { \ + u.x += v.x, u.y += v.y, u.z += v.z; return u; \ + } \ + static inline CVec3##tag cvec3##tag##_minus(CVec3##tag u, CVec3##tag v) { \ + u.x -= v.x, u.y -= v.y, u.z -= v.z; return u; \ + } \ + static inline CVec3##tag cvec3##tag##_mult(CVec3##tag v, double s) { \ + v.x = (T)(s*v.x), v.y = (T)(s*v.y), v.z = (T)(s*v.z); return v; \ + } \ + static inline CVec3##tag cvec3##tag##_multInverse(CVec3##tag v, double s) { \ + v.x = (T)(s/v.x), v.y = (T)(s/v.y), v.z = (T)(s/v.z); return v; \ + } \ + static inline CVec3##tag cvec3##tag##_neg(CVec3##tag v) { \ + v.x = -v.x, v.y = -v.y, v.z = -v.z; return v; \ + } \ + static inline CVec3##tag cvec3##tag##_unit(CVec3##tag v) { \ + double s = 1.0 / sqrt(_cvec3_DOT(v, v)); \ + v.x = (T)(s*v.x), v.y = (T)(s*v.y), v.z = (T)(s*v.z); return v; \ + } \ + static inline double cvec3##tag##_dot(CVec3##tag u, CVec3##tag v) { \ + return _cvec3_DOT(u, v); \ + } \ + static inline CVec3##tag cvec3##tag##_cross(CVec3##tag u, CVec3##tag v) { \ + CVec3##tag c = {_cvec3_CROSS(T, u, v)}; \ + return c; \ + } \ + static inline double cvec3##tag##_triple(CVec3##tag u, CVec3##tag v, CVec3##tag w) { \ + CVec3##tag c = {_cvec3_CROSS(T, u, v)}; \ + return _cvec3_DOT(c, w); \ + } \ + /* Reflect u on plane with given normal vector n */ \ + static inline CVec3##tag cvec3##tag##_reflect(CVec3##tag u, CVec3##tag pn) { \ + double dot2 = 2.0 * _cvec3_DOT(u, pn); \ + u.x = (T)(u.x - dot2*pn.x), u.y = (T)(u.y - dot2*pn.y), u.z = (T)(u.z - dot2*pn.z); \ + return u; \ + } \ + /* Signed distance between point u and a plane (pp, pn), pn normalized. */ \ + static inline double cvec3##tag##_distanceToPlane(CVec3##tag u, CVec3##tag pp, CVec3##tag pn) { \ + u.x -= pp.x, u.y -= pp.y, u.z -= pp.z; \ + return _cvec3_DOT(u, pn); \ + } \ + /* Linear interpolation */ \ + static inline CVec3##tag cvec3##tag##_lerp(CVec3##tag u, CVec3##tag v, double t) { \ + double m = 1.0 - t; \ + u.x = (T)(m*u.x + t*v.x), u.y = (T)(m*u.y + t*v.y), u.z = (T)(m*u.z + t*v.z); \ + return u; \ + } \ + static inline bool cvec3##tag##_rayPlaneIntersection(CVec3##tag* out, CVec3##tag u, CVec3##tag dir, \ + CVec3##tag pp, CVec3##tag pn) { \ + double d = _cvec3_DOT(dir, pn); if (d == 0) return false; \ + double t = (_cvec3_DOT(pp, pn) - _cvec3_DOT(u, pn)) / d; \ + if (t < 0) return false; \ + u.x = (T)(u.x + dir.x*t), u.y = (T)(u.y + dir.y*t), u.z = (T)(u.z + dir.z*t); \ + *out = u; return true; \ + } \ + static inline bool cvec3##tag##_equals(CVec3##tag u, CVec3##tag v) { \ + if (u.x != v.x) return false; \ + if (u.y != v.y) return false; \ + return u.z == v.z; \ + } \ + static inline int cvec3##tag##_compare(CVec3##tag* u, CVec3##tag* v) { \ + if (u->x != v->x) return 1 - ((u->x < v->x)<<1); \ + if (u->y != v->y) return 1 - ((u->y < v->y)<<1); \ + return u->z == v->z ? 0 : 1 - ((u->z < v->z)<<1); \ + } \ + typedef T cvec3_##tag##_value_t + +#define _cvec3_DOT(u, v) ((double) u.x*v.x + u.y*v.y + u.z*v.z) +#define _cvec3_SUB(u, v) u.x - v.x, u.y - v.y, u.z - v.z +#define _cvec3_CROSS(T, u, v) (T) (u.y*v.z - v.y*u.z), (T) (u.z*v.x - v.z*u.x), (T) (u.x*v.y - u.y*v.x) + +declare_CVec3(d, double); +declare_CVec3(f, float); +declare_CVec3(i, int32_t); +//declare_CVec3(ui, uint32_t); +//declare_CVec3(s, int16_t); +//declare_CVec3(us, uint16_t); +declare_CVec3(ub, uint8_t); + +static inline CVec3f cvec3d_to3f(CVec3d v) { + CVec3f w = {(float) v.x, (float) v.y, (float) v.z}; return w; +} +static inline CVec3d cvec3f_to3d(CVec3f v) { + CVec3d w = {v.x, v.y, v.z}; return w; +} +static inline CVec3d cvec3i_to3d(CVec3i v) { + CVec3d w = {(double) v.x, (double) v.y, (double) v.z}; return w; +} + +#endif diff --git a/stc/cvec4.h b/stc/cvec4.h new file mode 100644 index 00000000..abc5f3dd --- /dev/null +++ b/stc/cvec4.h @@ -0,0 +1,126 @@ +// MIT License +// +// Copyright (c) 2020 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 CVEC4__H__ +#define CVEC4__H__ + +#include "cvec3.h" + +#define cvec4_data(v) (&(v).x) + +#define declare_CVec4(tag, T) \ + typedef struct CVec4##tag { T x, y, z, w; } CVec4##tag; \ + static CVec4##tag cvec4##tag##_null = {0, 0, 0, 0}; \ + static CVec4##tag cvec4##tag##_axis[4] = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}; \ + \ + static inline CVec4##tag cvec4##tag(T x, T y, T z, T w) { CVec4##tag v = {x, y, z, w}; return v; } \ + static inline CVec4##tag cvec4##tag##_init(const T* a) { CVec4##tag v = {a[0], a[1], a[2], a[3]}; return v; } \ + \ + static inline CVec4##tag cvec4##tag##_set(CVec4##tag* self, T x, T y, T z, T w) { \ + self->x = x, self->y = y, self->z = z, self->z = z, self->w = w; return *self; \ + } \ + static inline CVec4##tag cvec4##tag##_setv(CVec4##tag* self, const T* a) { \ + self->x = a[0], self->y = a[1], self->z = a[2], self->w = a[3]; return *self; \ + } \ + static inline CVec4##tag cvec4##tag##_add(CVec4##tag* self, CVec4##tag v) { \ + self->x += v.x, self->y += v.y, self->z += v.z, self->w += v.w; return *self; \ + } \ + static inline CVec4##tag cvec4##tag##_subtract(CVec4##tag* self, CVec4##tag v) { \ + self->x -= v.x, self->y -= v.y, self->z -= v.z, self->w -= v.w; return *self; \ + } \ + static inline CVec4##tag cvec4##tag##_scale(CVec4##tag* self, double s) { \ + self->x = (T)(self->x*s), self->y = (T)(self->y*s), self->z = (T)(self->z*s), self->w = (T)(self->w*s); \ + return *self; \ + } \ + static inline double cvec4##tag##_length(CVec4##tag v) { \ + return sqrt(_cvec4_DOT(v, v)); \ + } \ + static inline double cvec4##tag##_length2(CVec4##tag v) { \ + return _cvec4_DOT(v, v); \ + } \ + static inline CVec4##tag cvec4##tag##_plus(CVec4##tag u, CVec4##tag v) { \ + u.x += v.x, u.y += v.y, u.z += v.z, u.w += v.w; return u; \ + } \ + static inline CVec4##tag cvec4##tag##_minus(CVec4##tag u, CVec4##tag v) { \ + u.x -= v.x, u.y -= v.y, u.z -= v.z, u.w -= v.w; return u; \ + } \ + static inline CVec4##tag cvec4##tag##_mult(CVec4##tag v, double s) { \ + v.x = (T)(s*v.x), v.y = (T)(s*v.y), v.z = (T)(s*v.z), v.w = (T)(s*v.w); return v; \ + } \ + static inline CVec4##tag cvec4##tag##_multInverse(CVec4##tag v, double s) { \ + v.x = (T)(s/v.x), v.y = (T)(s/v.y), v.z = (T)(s/v.z), v.w = (T)(s/v.w); return v; \ + } \ + static inline CVec4##tag cvec4##tag##_neg(CVec4##tag v) { \ + v.x = -v.x, v.y = -v.y, v.z = -v.z, v.w = -v.w; return v; \ + } \ + static inline CVec4##tag cvec4##tag##_unit(CVec4##tag v) { \ + double s = 1.0 / sqrt(_cvec4_DOT(v, v)); \ + v.x = (T)(s*v.x), v.y = (T)(s*v.y), v.z = (T)(s*v.z), v.w = (T)(s*v.w); return v; \ + } \ + static inline double cvec4##tag##_dot(CVec4##tag u, CVec4##tag v) { \ + return _cvec4_DOT(u, v); \ + } \ + /* Linear interpolation */ \ + static inline CVec4##tag cvec4##tag##_lerp(CVec4##tag u, CVec4##tag v, double t) { \ + double m = 1.0 - t; \ + u.x = (T)(m*u.x + t*v.x), u.y = (T)(m*u.y + t*v.y), u.z = (T)(m*u.z + t*v.z), u.w = (T)(m*u.w + t*v.w); \ + return u; \ + } \ + static inline bool cvec4##tag##_equals(CVec4##tag u, CVec4##tag v) { \ + if (u.x != v.x) return false; \ + if (u.y != v.y) return false; \ + if (u.z != v.z) return false; \ + return u.w == v.w; \ + } \ + static inline int cvec4##tag##_compare(CVec4##tag* u, CVec4##tag* v) { \ + if (u->x != v->x) return 1 - ((u->x < v->x)<<1); \ + if (u->y != v->y) return 1 - ((u->y < v->y)<<1); \ + if (u->z != v->z) return 1 - ((u->z < v->z)<<1); \ + return u->w == v->w ? 0 : 1 - ((u->w < v->w)<<1); \ + } \ + typedef T cvec4_##tag##_value_t + +#define _cvec4_DOT(u, v) ((double) u.x*v.x + u.y*v.y + u.z*v.z + u.w*v.w) +#define _cvec4_SUB(u, v) u.x - v.x, u.y - v.y, u.z - v.z, u.w - v.w + +declare_CVec4(d, double); +declare_CVec4(f, float); +declare_CVec4(i, int32_t); +//declare_CVec4(ui, uint32_t); +//declare_CVec4(s, int16_t); +//declare_CVec4(us, uint16_t); +declare_CVec4(ub, uint8_t); + +static inline CVec4d cvec4f_to4d(CVec4f v) { + CVec4d u = {v.x, v.y, v.z, v.w}; return u; +} +static inline CVec4f cvec4d_to4f(CVec4d v) { + CVec4f u = {(float) v.x, (float) v.y, (float) v.z, (float) v.w}; return u; +} +static inline CVec3d cvec4d_to3d(CVec4d v) { + CVec3d u = {v.x, v.y, v.z}; return u; +} +static inline CVec3f cvec4d_to3f(CVec4d v) { + CVec3f u = {(float) v.x, (float) v.y, (float) v.z}; return u; +} + +#endif diff --git a/stc/cvector.h b/stc/cvector.h new file mode 100644 index 00000000..93aaa550 --- /dev/null +++ b/stc/cvector.h @@ -0,0 +1,165 @@ +// MIT License +// +// Copyright (c) 2020 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 CVECTOR__H__ +#define CVECTOR__H__ + +#include +#include +#include "cdefs.h" + +#define cvector_init {NULL} +#define cvector_size(cv) _cvector_safe_size((cv).data) +#define cvector_capacity(cv) _cvector_safe_capacity((cv).data) +#define cvector_empty(cv) (_cvector_safe_size((cv).data) == 0) + +#define declare_CVector(...) c_MACRO_OVERLOAD(declare_CVector, __VA_ARGS__) +#define declare_CVector_2(tag, Value) \ + declare_CVector_3(tag, Value, c_defaultDestroy) +#define declare_CVector_3(tag, Value, valueDestroy) \ + declare_CVector_4(tag, Value, valueDestroy, c_defaultCompare) +#define declare_CVector_4(tag, Value, valueDestroy, valueCompare) \ + declare_CVector_6(tag, Value, valueDestroy, valueCompare, Value, c_defaultGetRaw) +#define declare_CVector_string(tag) \ + declare_CVector_6(tag, CString, cstring_destroy, cstring_compareRaw, const char*, cstring_getRaw) + +#define declare_CVector_6(tag, Value, valueDestroy, valueCompare, ValueRaw, valueGetRaw) \ +typedef struct CVector_##tag { \ + Value* data; \ +} CVector_##tag; \ +static const CVector_##tag cvector_##tag##_init = cvector_init; \ + \ +typedef struct cvector_##tag##_iter_t { \ + Value* item; \ +} cvector_##tag##_iter_t; \ + \ +static inline void cvector_##tag##_swap(CVector_##tag* a, CVector_##tag* b) { \ + Value* data = a->data; a->data = b->data; b->data = data; \ +} \ + \ +static inline void cvector_##tag##_destroy(CVector_##tag* self) { \ + Value* p = self->data; \ + size_t i = 0, n = cvector_size(*self); \ + for (; i < n; ++p, ++i) valueDestroy(p); \ + free(_cvector_alloced(self->data)); \ +} \ + \ +static inline void cvector_##tag##_reserve(CVector_##tag* self, size_t cap) { \ + size_t len = cvector_size(*self); \ + if (cap >= len) { \ + size_t* rep = (size_t *) realloc(_cvector_alloced(self->data), 2 * sizeof(size_t) + cap * sizeof(Value)); \ + self->data = (Value *) (rep + 2); \ + rep[0] = len; \ + rep[1] = cap; \ + } \ +} \ + \ +static inline void cvector_##tag##_clear(CVector_##tag* self) { \ + CVector_##tag cv = cvector_##tag##_init; \ + cvector_##tag##_destroy(self); \ + *self = cv; \ +} \ + \ + \ +static inline void cvector_##tag##_push(CVector_##tag* self, Value value) { \ + size_t newsize = cvector_size(*self) + 1; \ + if (newsize > cvector_capacity(*self)) \ + cvector_##tag##_reserve(self, 7 + newsize * 5 / 3); \ + self->data[cvector_size(*self)] = value; \ + _cvector_size(*self) = newsize; \ +} \ + \ +static inline void cvector_##tag##_insert(CVector_##tag* self, size_t pos, Value value) { \ + cvector_##tag##_push(self, value); \ + size_t len = cvector_size(*self); \ + memmove(&self->data[pos + 1], &self->data[pos], (len - pos - 1) * sizeof(Value)); \ + self->data[pos] = value; \ +} \ + \ +static inline void cvector_##tag##_erase(CVector_##tag* self, size_t pos, size_t size) { \ + size_t len = cvector_size(*self); \ + if (len) { \ + Value* p = &self->data[pos], *start = p, *end = p + size; \ + while (p != end) valueDestroy(p++); \ + memmove(start, end, (len - pos - size) * sizeof(Value)); \ + _cvector_size(*self) -= size; \ + } \ +} \ + \ +static inline int cvector_##tag##_sortCompare(const void* x, const void* y) { \ + return valueCompare(valueGetRaw((const Value *) x), valueGetRaw((const Value *) y)); \ +} \ + \ +static inline void cvector_##tag##_sort(CVector_##tag* self) { \ + size_t len = cvector_size(*self); \ + if (len) qsort(self->data, len, sizeof(Value), cvector_##tag##_sortCompare); \ +} \ + \ +static inline size_t cvector_##tag##_find(CVector_##tag cv, ValueRaw rawValue) { \ + size_t n = cvector_size(cv); \ + for (size_t i = 0; i < n; ++i) { \ + if (valueCompare(valueGetRaw(&cv.data[i]), &rawValue) == 0) return i; \ + } \ + return c_npos; \ +} \ + \ + \ +static inline Value cvector_##tag##_back(CVector_##tag cv) { \ + return cv.data[_cvector_size(cv) - 1]; \ +} \ + \ +static inline void cvector_##tag##_pop(CVector_##tag* self) { \ + valueDestroy(&self->data[_cvector_size(*self) - 1]); \ + --_cvector_size(*self); \ +} \ + \ +static inline cvector_##tag##_iter_t cvector_##tag##_begin(CVector_##tag vec) { \ + cvector_##tag##_iter_t it = {vec.data}; \ + return it; \ +} \ + \ +static inline cvector_##tag##_iter_t cvector_##tag##_next(cvector_##tag##_iter_t it) { \ + ++it.item; \ + return it; \ +} \ + \ +static inline cvector_##tag##_iter_t cvector_##tag##_end(CVector_##tag vec) { \ + cvector_##tag##_iter_t it = {vec.data + cvector_size(vec)}; \ + return it; \ +} \ +typedef Value cvector_##tag##_value_t + + +#define _cvector_size(cv) ((size_t *)(cv).data)[-2] +#define _cvector_capacity(cv) ((size_t *)(cv).data)[-1] + +static inline size_t* _cvector_alloced(void* data) { + return data ? ((size_t *) data) - 2 : NULL; +} +static inline size_t _cvector_safe_size(const void* data) { + return data ? ((const size_t *) data)[-2] : 0; +} +static inline size_t _cvector_safe_capacity(const void* data) { + return data ? ((const size_t *) data)[-1] : 0; +} + +#endif -- cgit v1.2.3