diff options
| author | Tyge Løvset <[email protected]> | 2020-03-11 19:09:38 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2020-03-11 19:09:38 +0100 |
| commit | a6653bfb5ec8e04bef66ae0b0fead08662c986a4 (patch) | |
| tree | 0534cf02bdffbbc211640b9d9bbd6ce9bb7c1e9e | |
| parent | 18399f0b3000ec4d949aa45e3e72fbc7db651d41 (diff) | |
| download | STC-modified-a6653bfb5ec8e04bef66ae0b0fead08662c986a4.tar.gz STC-modified-a6653bfb5ec8e04bef66ae0b0fead08662c986a4.zip | |
Added vector params
| -rw-r--r-- | c_defs.h | 127 | ||||
| -rw-r--r-- | c_hashmap.h | 453 | ||||
| -rw-r--r-- | c_string.h | 488 | ||||
| -rw-r--r-- | c_vector.h | 308 | ||||
| -rw-r--r-- | cmap_test.c | 2 |
5 files changed, 698 insertions, 680 deletions
@@ -1,64 +1,65 @@ -// 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 C_DEFS__H__ -#define C_DEFS__H__ - -#include <stdint.h> -#include <stdbool.h> - -// Macro overloading feature support: https://rextester.com/ONP80107 -#define c_defs_CAT( A, B ) A ## B -#define c_defs_EXPAND(...) __VA_ARGS__ -#define c_defs_VA_ARG_SIZE(...) c_defs_EXPAND(c_defs_APPLY_ARG_N((__VA_ARGS__, c_defs_RSEQ_N))) -#define c_defs_APPLY_ARG_N(ARGS) c_defs_EXPAND(c_defs_ARG_N ARGS) -#define c_defs_ARG_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N,...) N -#define c_defs_RSEQ_N 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 -#define c_defs_OVERLOAD_SELECT(NAME, NUM) c_defs_CAT( NAME ## _, NUM) - -#define c_defs_MACRO_OVERLOAD(NAME, ...) c_defs_OVERLOAD_SELECT(NAME, c_defs_VA_ARG_SIZE(__VA_ARGS__))(__VA_ARGS__) -// #define foo(...) c_defs_MACRO_OVERLOAD(foo, __VA_ARGS__) -// #define foo_1(X) foo_2(X, 100) -// #define foo_2(X, Y) X + Y - -#define c_defs_max_alloca (1000) -#define c_defs_swap(T, x, y) { T __t = x; x = y; y = __t; } - -#define c_defs_initRaw(x) (x) -#define c_defs_getRaw(x) (x) -static inline void c_defs_destroy(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)) - -static inline uint32_t c_defs_murmurHash(const void *data, size_t len) { // One-at-a-time 32bit - const unsigned char *key = (const unsigned char *) data; - uint32_t h = 0xC613FC15; // 0x749E3E6989DF617; 64bit - while (len--) { - h ^= *key++; - h *= 0x5bd1e995; // 0x5bd1e9955bd1e995; 64bit - h ^= h >> 15; // 47; 64bit - } - return h; -} - +// 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 C_DEFS__H__
+#define C_DEFS__H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+// Macro overloading feature support: https://rextester.com/ONP80107
+#define c_defs_CAT( A, B ) A ## B
+#define c_defs_EXPAND(...) __VA_ARGS__
+#define c_defs_VA_ARG_SIZE(...) c_defs_EXPAND(c_defs_APPLY_ARG_N((__VA_ARGS__, c_defs_RSEQ_N)))
+#define c_defs_APPLY_ARG_N(ARGS) c_defs_EXPAND(c_defs_ARG_N ARGS)
+#define c_defs_ARG_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N,...) N
+#define c_defs_RSEQ_N 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+#define c_defs_OVERLOAD_SELECT(NAME, NUM) c_defs_CAT( NAME ## _, NUM)
+
+#define c_defs_MACRO_OVERLOAD(NAME, ...) c_defs_OVERLOAD_SELECT(NAME, c_defs_VA_ARG_SIZE(__VA_ARGS__))(__VA_ARGS__)
+// #define foo(...) c_defs_MACRO_OVERLOAD(foo, __VA_ARGS__)
+// #define foo_1(X) foo_2(X, 100)
+// #define foo_2(X, Y) X + Y
+
+#define c_defs_npos ((size_t) -1)
+#define c_defs_max_alloca (1000)
+#define c_defs_swap(T, x, y) { T __t = x; x = y; y = __t; }
+
+#define c_defs_initRaw(x) (x)
+#define c_defs_getRaw(x) (x)
+static inline void c_defs_destroy(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))
+
+static inline uint32_t c_defs_murmurHash(const void *data, size_t len) { // One-at-a-time 32bit
+ const unsigned char *key = (const unsigned char *) data;
+ uint32_t h = 0xC613FC15; // 0x749E3E6989DF617; 64bit
+ while (len--) {
+ h ^= *key++;
+ h *= 0x5bd1e995; // 0x5bd1e9955bd1e995; 64bit
+ h ^= h >> 15; // 47; 64bit
+ }
+ return h;
+}
+
#endif
\ No newline at end of file diff --git a/c_hashmap.h b/c_hashmap.h index a0f85def..d0a0c8c7 100644 --- a/c_hashmap.h +++ b/c_hashmap.h @@ -1,225 +1,228 @@ -// 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 C_HASHMAP_H_ -#define C_HASHMAP_H_ - -#include "c_vector.h" - -#define c_hashmap_initializer {c_vector_initializer, 0, 0.8f} -#define c_hashmap_size(cm) ((size_t) (cm)._size) -#define c_hashmap_buckets(cm) c_vector_capacity((cm)._vec) - - -// c_HashmapEntry: -enum { c_HashmapEntry_VACANT = 0, - c_HashmapEntry_INUSE = 1, - c_HashmapEntry_ERASED = 2 -}; -#define c_declare_HashmapEntry(tag, Key, Value, keyDestroy, valueDestroy) \ -struct c_HashmapEntry_##tag { \ - Key key; \ - Value value; \ - uint8_t state, changed; \ -}; \ - \ -static inline void c_hashmapentry_##tag##_destroy(struct c_HashmapEntry_##tag* e) { \ - keyDestroy(&e->key); \ - valueDestroy(&e->value); \ - e->state = c_HashmapEntry_VACANT; \ -} \ -typedef struct c_HashmapEntry_##tag c_HashmapEntry_##tag - - -// c_Hashmap: -#define c_declare_Hashmap(...) c_defs_MACRO_OVERLOAD(c_declare_Hashmap, __VA_ARGS__) - -#define c_declare_Hashmap_3(tag, Key, Value) \ - c_declare_Hashmap_4(tag, Key, Value, c_defs_destroy) - -#define c_declare_Hashmap_4(tag, Key, Value, valueDestroy) \ - c_declare_Hashmap_10(tag, Key, Value, valueDestroy, Key, memcmp, c_defs_murmurHash, c_defs_initRaw, c_defs_getRaw, c_defs_destroy) - - -// c_Hashmap<c_String, Value>: -#define c_declare_Hashmap_stringkey(...) c_defs_MACRO_OVERLOAD(c_declare_Hashmap_stringkey, __VA_ARGS__) - -#define c_declare_Hashmap_stringkey_2(tag, Value) \ - c_declare_Hashmap_stringkey_3(tag, Value, c_defs_destroy) - -#define c_declare_Hashmap_stringkey_3(tag, Value, valueDestroy) \ - c_declare_Hashmap_10(tag, c_String, Value, valueDestroy, const char*, c_string_compareRaw, c_string_hashRaw, c_string_make, c_string_getRaw, c_string_destroy) - - -// c_Hashmap full: -#define c_declare_Hashmap_10(tag, Key, Value, valueDestroy, KeyRaw, keyCompareRaw, keyHashRaw, keyInitRaw, keyGetRaw, keyDestroy) \ - c_declare_HashmapEntry(tag, Key, Value, keyDestroy, valueDestroy); \ - c_declare_Vector_3(map_##tag, c_HashmapEntry_##tag, c_hashmapentry_##tag##_destroy); \ - \ -typedef struct c_Hashmap_##tag { \ - c_Vector_map_##tag _vec; \ - size_t _size; \ - float maxLoadFactor; \ -} c_Hashmap_##tag; \ - \ -typedef struct c_hashmap_##tag##_iter_t { \ - c_HashmapEntry_##tag *item, *_end; \ -} c_hashmap_##tag##_iter_t; \ - \ -static inline c_Hashmap_##tag c_hashmap_##tag##_init(void) { \ - c_Hashmap_##tag map = c_hashmap_initializer; \ - return map; \ -} \ - \ -static inline void c_hashmap_##tag##_destroy(c_Hashmap_##tag* self) { \ - if (c_hashmap_size(*self)) { \ - size_t cap = _c_vector_capacity(self->_vec); \ - c_HashmapEntry_##tag* e = self->_vec.data, *end = e + cap; \ - for (; e != end; ++e) if (e->state == c_HashmapEntry_INUSE) c_hashmapentry_##tag##_destroy(e); \ - } \ - c_vector_map_##tag##_destroy(&self->_vec); \ -} \ - \ -static inline size_t c_hashmap_##tag##_reserve(c_Hashmap_##tag* self, size_t size); /* predeclared */ \ - \ -static inline void c_hashmap_##tag##_clear(c_Hashmap_##tag* self) { \ - c_Hashmap_##tag cm = c_hashmap_initializer; \ - c_hashmap_##tag##_destroy(self); \ - *self = cm; \ -} \ - \ -static inline void c_hashmap_##tag##_swap(c_Hashmap_##tag* a, c_Hashmap_##tag* b) { \ - c_vector_map_##tag##_swap(&a->_vec, &b->_vec); \ - c_defs_swap(size_t, a->_size, b->_size); \ -} \ - \ -static inline void c_hashmap_##tag##_setMaxLoadFactor(c_Hashmap_##tag* self, float fac) { \ - self->maxLoadFactor = fac; \ - if (c_hashmap_size(*self) > c_hashmap_buckets(*self) * fac) \ - c_hashmap_##tag##_reserve(self, 1 + (size_t) (c_hashmap_size(*self) / fac)); \ -} \ - \ -static inline size_t c_hashmap_##tag##_bucket(c_Hashmap_##tag cm, KeyRaw rawKey) { \ - size_t cap = c_vector_capacity(cm._vec); \ - size_t idx = c_hashmap_reduce(keyHashRaw(&rawKey, sizeof(Key)), cap); \ - size_t first = idx, erased_idx = cap; \ - FIBONACCI_DECL; \ - do { \ - switch (cm._vec.data[idx].state) { \ - case c_HashmapEntry_VACANT: \ - return erased_idx != cap ? erased_idx : idx; \ - case c_HashmapEntry_INUSE: \ - if (keyCompareRaw(&cm._vec.data[idx].key, &rawKey, sizeof(Key)) != 0) \ - break; \ - if (erased_idx != cap) { \ - c_defs_swap(c_HashmapEntry_##tag, cm._vec.data[erased_idx], cm._vec.data[idx]); \ - return erased_idx; \ - } \ - return idx; \ - case c_HashmapEntry_ERASED: \ - if (erased_idx == cap) erased_idx = idx; \ - break; \ - } \ - idx = first + FIBONACCI_NEXT; \ - if (idx >= cap) idx %= cap; \ - } while (1); \ -} \ - \ -static inline c_HashmapEntry_##tag* c_hashmap_##tag##_get(c_Hashmap_##tag cm, KeyRaw rawKey) { \ - if (c_hashmap_size(cm) == 0) return NULL; \ - size_t idx = c_hashmap_##tag##_bucket(cm, rawKey); \ - return cm._vec.data[idx].state == c_HashmapEntry_INUSE ? &cm._vec.data[idx] : NULL; \ -} \ - \ -static inline c_HashmapEntry_##tag* c_hashmap_##tag##_put(c_Hashmap_##tag* self, KeyRaw rawKey, Value value) { \ - size_t cap = c_vector_capacity(self->_vec); \ - if (c_hashmap_size(*self) >= cap * self->maxLoadFactor) \ - cap = c_hashmap_##tag##_reserve(self, (size_t) (cap * 1.8)); \ - size_t idx = c_hashmap_##tag##_bucket(*self, rawKey); \ - c_HashmapEntry_##tag* e = &self->_vec.data[idx]; \ - e->value = value; \ - e->changed = (e->state == c_HashmapEntry_INUSE); \ - if (e->state != c_HashmapEntry_INUSE) { \ - e->key = keyInitRaw(rawKey); \ - e->state = c_HashmapEntry_INUSE; \ - ++self->_size; \ - } \ - return e; \ -} \ - \ -static inline size_t c_hashmap_##tag##_reserve(c_Hashmap_##tag* self, size_t size) { \ - size_t oldcap = c_vector_capacity(self->_vec), newcap = (oldcap ? 1 : 7) + (size / 2) * 2; \ - if (oldcap >= newcap) return oldcap; \ - c_Vector_map_##tag vec = c_vector_initializer; \ - c_vector_map_##tag##_swap(&self->_vec, &vec); \ - c_vector_map_##tag##_reserve(&self->_vec, newcap); \ - self->_size = 0; \ - memset(self->_vec.data, 0, sizeof(c_HashmapEntry_##tag) * newcap); \ - c_HashmapEntry_##tag* e = vec.data; \ - for (size_t i = 0; i < oldcap; ++i, ++e) \ - if (e->state == c_HashmapEntry_INUSE) c_hashmap_##tag##_put(self, keyGetRaw(e->key), e->value); \ - return newcap; \ -} \ - \ -static inline bool c_hashmap_##tag##_erase(c_Hashmap_##tag* self, KeyRaw rawKey) { \ - c_HashmapEntry_##tag* e = c_hashmap_##tag##_get(*self, rawKey); \ - if (e) { \ - c_hashmapentry_##tag##_destroy(e); \ - e->state = c_HashmapEntry_ERASED; \ - --self->_size; \ - return true; \ - } \ - return false; \ -} \ - \ -static inline c_hashmap_##tag##_iter_t c_hashmap_##tag##_begin(c_Hashmap_##tag map) { \ - c_hashmap_##tag##_iter_t null = {NULL, NULL}; \ - if (c_hashmap_size(map) == 0) return null; \ - c_HashmapEntry_##tag* e = map._vec.data, *end = e + _c_vector_capacity(map._vec); \ - while (e != end && e->state != c_HashmapEntry_INUSE) ++e; \ - c_hashmap_##tag##_iter_t it = {e, end}; return it; \ -} \ - \ -static inline c_hashmap_##tag##_iter_t c_hashmap_##tag##_next(c_hashmap_##tag##_iter_t it) { \ - do { ++it.item; } while (it.item != it._end && it.item->state != c_HashmapEntry_INUSE); \ - return it; \ -} \ - \ -static inline c_hashmap_##tag##_iter_t c_hashmap_##tag##_end(c_Hashmap_##tag map) { \ - c_HashmapEntry_##tag* end = (c_hashmap_size(map) == 0) ? NULL : map._vec.data + _c_vector_capacity(map._vec); \ - c_hashmap_##tag##_iter_t it = {end, end}; \ - return it; \ -} \ -typedef Key c_hashmap_##tag##_key_t; \ -typedef Value c_hashmap_##tag##_value_t - - -#define FIBONACCI_DECL size_t fib1 = 0, fib2 = 1, fibx -#define FIBONACCI_NEXT (fibx = fib1 + fib2, fib1 = fib2, fib2 = fibx) - -// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ -static inline uint32_t c_hashmap_reduce(uint32_t x, uint32_t N) { - return ((uint64_t) x * (uint64_t) N) >> 32 ; -} - - -#endif +// 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 C_HASHMAP_H_
+#define C_HASHMAP_H_
+
+#include "c_vector.h"
+
+#define c_hashmap_initializer {c_vector_initializer, 0, 0.8f}
+#define c_hashmap_size(cm) ((size_t) (cm)._size)
+#define c_hashmap_buckets(cm) c_vector_capacity((cm)._vec)
+
+
+// c_HashmapEntry:
+enum { c_HashmapEntry_VACANT = 0,
+ c_HashmapEntry_INUSE = 1,
+ c_HashmapEntry_ERASED = 2
+};
+#define c_declare_HashmapEntry(tag, Key, Value, valueDestroy, keyDestroy) \
+struct c_HashmapEntry_##tag { \
+ Key key; \
+ Value value; \
+ uint8_t state, changed; \
+}; \
+ \
+static inline void c_hashmapentry_##tag##_destroy(struct c_HashmapEntry_##tag* e) { \
+ keyDestroy(&e->key); \
+ valueDestroy(&e->value); \
+ e->state = c_HashmapEntry_VACANT; \
+} \
+typedef struct c_HashmapEntry_##tag c_HashmapEntry_##tag
+
+
+// c_Hashmap:
+#define c_declare_Hashmap(...) c_defs_MACRO_OVERLOAD(c_declare_Hashmap, __VA_ARGS__)
+
+#define c_declare_Hashmap_3(tag, Key, Value) \
+ c_declare_Hashmap_4(tag, Key, Value, c_defs_destroy)
+
+#define c_declare_Hashmap_4(tag, Key, Value, valueDestroy) \
+ c_declare_Hashmap_6(tag, Key, Value, valueDestroy, memcmp, c_defs_murmurHash)
+
+#define c_declare_Hashmap_6(tag, Key, Value, valueDestroy, keyCompare, keyHash) \
+ c_declare_Hashmap_10(tag, Key, Value, valueDestroy, keyCompare, keyHash, c_defs_destroy, Key, c_defs_getRaw, c_defs_initRaw)
+
+
+// c_Hashmap<c_String, Value>:
+#define c_declare_Hashmap_stringkey(...) c_defs_MACRO_OVERLOAD(c_declare_Hashmap_stringkey, __VA_ARGS__)
+
+#define c_declare_Hashmap_stringkey_2(tag, Value) \
+ c_declare_Hashmap_stringkey_3(tag, Value, c_defs_destroy)
+
+#define c_declare_Hashmap_stringkey_3(tag, Value, valueDestroy) \
+ c_declare_Hashmap_10(tag, c_String, Value, valueDestroy, c_string_compareRaw, c_string_hashRaw, c_string_destroy, const char*, c_string_getRaw, c_string_make)
+
+
+// c_Hashmap full:
+#define c_declare_Hashmap_10(tag, Key, Value, valueDestroy, keyCompareRaw, keyHashRaw, keyDestroy, KeyRaw, keyGetRaw, keyInitRaw) \
+ c_declare_HashmapEntry(tag, Key, Value, valueDestroy, keyDestroy); \
+ c_declare_Vector_3(map_##tag, c_HashmapEntry_##tag, c_hashmapentry_##tag##_destroy); \
+ \
+typedef struct c_Hashmap_##tag { \
+ c_Vector_map_##tag _vec; \
+ size_t _size; \
+ float maxLoadFactor; \
+} c_Hashmap_##tag; \
+ \
+typedef struct c_hashmap_##tag##_iter_t { \
+ c_HashmapEntry_##tag *item, *_end; \
+} c_hashmap_##tag##_iter_t; \
+ \
+static inline c_Hashmap_##tag c_hashmap_##tag##_init(void) { \
+ c_Hashmap_##tag map = c_hashmap_initializer; \
+ return map; \
+} \
+ \
+static inline void c_hashmap_##tag##_destroy(c_Hashmap_##tag* self) { \
+ if (c_hashmap_size(*self)) { \
+ size_t cap = _c_vector_capacity(self->_vec); \
+ c_HashmapEntry_##tag* e = self->_vec.data, *end = e + cap; \
+ for (; e != end; ++e) if (e->state == c_HashmapEntry_INUSE) c_hashmapentry_##tag##_destroy(e); \
+ } \
+ c_vector_map_##tag##_destroy(&self->_vec); \
+} \
+ \
+static inline size_t c_hashmap_##tag##_reserve(c_Hashmap_##tag* self, size_t size); /* predeclared */ \
+ \
+static inline void c_hashmap_##tag##_clear(c_Hashmap_##tag* self) { \
+ c_Hashmap_##tag cm = c_hashmap_initializer; \
+ c_hashmap_##tag##_destroy(self); \
+ *self = cm; \
+} \
+ \
+static inline void c_hashmap_##tag##_swap(c_Hashmap_##tag* a, c_Hashmap_##tag* b) { \
+ c_vector_map_##tag##_swap(&a->_vec, &b->_vec); \
+ c_defs_swap(size_t, a->_size, b->_size); \
+} \
+ \
+static inline void c_hashmap_##tag##_setMaxLoadFactor(c_Hashmap_##tag* self, float fac) { \
+ self->maxLoadFactor = fac; \
+ if (c_hashmap_size(*self) > c_hashmap_buckets(*self) * fac) \
+ c_hashmap_##tag##_reserve(self, 1 + (size_t) (c_hashmap_size(*self) / fac)); \
+} \
+ \
+static inline size_t c_hashmap_##tag##_bucket(c_Hashmap_##tag cm, KeyRaw rawKey) { \
+ size_t cap = c_vector_capacity(cm._vec); \
+ size_t idx = c_hashmap_reduce(keyHashRaw(&rawKey, sizeof(Key)), cap); \
+ size_t first = idx, erased_idx = cap; \
+ FIBONACCI_DECL; \
+ do { \
+ switch (cm._vec.data[idx].state) { \
+ case c_HashmapEntry_VACANT: \
+ return erased_idx != cap ? erased_idx : idx; \
+ case c_HashmapEntry_INUSE: \
+ if (keyCompareRaw(&cm._vec.data[idx].key, &rawKey, sizeof(Key)) != 0) \
+ break; \
+ if (erased_idx != cap) { \
+ c_defs_swap(c_HashmapEntry_##tag, cm._vec.data[erased_idx], cm._vec.data[idx]); \
+ return erased_idx; \
+ } \
+ return idx; \
+ case c_HashmapEntry_ERASED: \
+ if (erased_idx == cap) erased_idx = idx; \
+ break; \
+ } \
+ idx = first + FIBONACCI_NEXT; \
+ if (idx >= cap) idx %= cap; \
+ } while (1); \
+} \
+ \
+static inline c_HashmapEntry_##tag* c_hashmap_##tag##_get(c_Hashmap_##tag cm, KeyRaw rawKey) { \
+ if (c_hashmap_size(cm) == 0) return NULL; \
+ size_t idx = c_hashmap_##tag##_bucket(cm, rawKey); \
+ return cm._vec.data[idx].state == c_HashmapEntry_INUSE ? &cm._vec.data[idx] : NULL; \
+} \
+ \
+static inline c_HashmapEntry_##tag* c_hashmap_##tag##_put(c_Hashmap_##tag* self, KeyRaw rawKey, Value value) { \
+ size_t cap = c_vector_capacity(self->_vec); \
+ if (c_hashmap_size(*self) >= cap * self->maxLoadFactor) \
+ cap = c_hashmap_##tag##_reserve(self, (size_t) (cap * 1.8)); \
+ size_t idx = c_hashmap_##tag##_bucket(*self, rawKey); \
+ c_HashmapEntry_##tag* e = &self->_vec.data[idx]; \
+ e->value = value; \
+ e->changed = (e->state == c_HashmapEntry_INUSE); \
+ if (e->state != c_HashmapEntry_INUSE) { \
+ e->key = keyInitRaw(rawKey); \
+ e->state = c_HashmapEntry_INUSE; \
+ ++self->_size; \
+ } \
+ return e; \
+} \
+ \
+static inline size_t c_hashmap_##tag##_reserve(c_Hashmap_##tag* self, size_t size) { \
+ size_t oldcap = c_vector_capacity(self->_vec), newcap = (oldcap ? 1 : 7) + (size / 2) * 2; \
+ if (oldcap >= newcap) return oldcap; \
+ c_Vector_map_##tag vec = c_vector_initializer; \
+ c_vector_map_##tag##_swap(&self->_vec, &vec); \
+ c_vector_map_##tag##_reserve(&self->_vec, newcap); \
+ self->_size = 0; \
+ memset(self->_vec.data, 0, sizeof(c_HashmapEntry_##tag) * newcap); \
+ c_HashmapEntry_##tag* e = vec.data; \
+ for (size_t i = 0; i < oldcap; ++i, ++e) \
+ if (e->state == c_HashmapEntry_INUSE) c_hashmap_##tag##_put(self, keyGetRaw(e->key), e->value); \
+ return newcap; \
+} \
+ \
+static inline bool c_hashmap_##tag##_erase(c_Hashmap_##tag* self, KeyRaw rawKey) { \
+ c_HashmapEntry_##tag* e = c_hashmap_##tag##_get(*self, rawKey); \
+ if (e) { \
+ c_hashmapentry_##tag##_destroy(e); \
+ e->state = c_HashmapEntry_ERASED; \
+ --self->_size; \
+ return true; \
+ } \
+ return false; \
+} \
+ \
+static inline c_hashmap_##tag##_iter_t c_hashmap_##tag##_begin(c_Hashmap_##tag map) { \
+ c_hashmap_##tag##_iter_t null = {NULL, NULL}; \
+ if (c_hashmap_size(map) == 0) return null; \
+ c_HashmapEntry_##tag* e = map._vec.data, *end = e + _c_vector_capacity(map._vec); \
+ while (e != end && e->state != c_HashmapEntry_INUSE) ++e; \
+ c_hashmap_##tag##_iter_t it = {e, end}; return it; \
+} \
+ \
+static inline c_hashmap_##tag##_iter_t c_hashmap_##tag##_next(c_hashmap_##tag##_iter_t it) { \
+ do { ++it.item; } while (it.item != it._end && it.item->state != c_HashmapEntry_INUSE); \
+ return it; \
+} \
+ \
+static inline c_hashmap_##tag##_iter_t c_hashmap_##tag##_end(c_Hashmap_##tag map) { \
+ c_HashmapEntry_##tag* end = (c_hashmap_size(map) == 0) ? NULL : map._vec.data + _c_vector_capacity(map._vec); \
+ c_hashmap_##tag##_iter_t it = {end, end}; \
+ return it; \
+} \
+typedef Key c_hashmap_##tag##_key_t; \
+typedef Value c_hashmap_##tag##_value_t
+
+
+#define FIBONACCI_DECL size_t fib1 = 0, fib2 = 1, fibx
+#define FIBONACCI_NEXT (fibx = fib1 + fib2, fib1 = fib2, fib2 = fibx)
+
+// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
+static inline uint32_t c_hashmap_reduce(uint32_t x, uint32_t N) {
+ return ((uint64_t) x * (uint64_t) N) >> 32 ;
+}
+
+
+#endif
@@ -1,244 +1,244 @@ -// 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 C_STRING__H__ -#define C_STRING__H__ - -#include <malloc.h> -#include <stdbool.h> -#include <string.h> -#include <stdint.h> - -#include "c_defs.h" - -typedef struct c_String { - char* str; -} c_String; - - -static size_t _c_string_null_rep[] = {0, 0, 0}; -#define _c_string_rep(cs) (((size_t *) (cs).str) - 2) - -#define c_string_initializer {(char* ) (_c_string_null_rep + 2)} -#define c_string_size(cs) ((size_t) _c_string_rep(cs)[0]) -#define c_string_capacity(cs) ((size_t) _c_string_rep(cs)[1]) -#define c_string_npos ((size_t) -1) - - -static inline void c_string_reserve(c_String* self, size_t cap) { - size_t len = c_string_size(*self), oldcap = c_string_capacity(*self); - if (cap > oldcap) { - size_t* rep = (size_t *) realloc(oldcap ? _c_string_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 c_string_destroy(c_String* self) { - if (c_string_capacity(*self)) { - free(_c_string_rep(*self)); - } -} - -static inline c_String c_string_init(void) { - c_String cs = c_string_initializer; - return cs; -} - -static inline c_String c_string_makeN(const char* str, size_t len) { - c_String cs = c_string_initializer; - if (len) { - c_string_reserve(&cs, len); - memcpy(cs.str, str, len); - cs.str[ _c_string_rep(cs)[0] = len ] = '\0'; - } - return cs; -} - -static inline c_String c_string_make(const char* str) { - return c_string_makeN(str, strlen(str)); -} - -static inline c_String c_string_makeCopy(c_String cs) { - return c_string_makeN(cs.str, c_string_size(cs)); -} - -static inline void c_string_clear(c_String* self) { - c_String cs = c_string_initializer; - c_string_destroy(self); - *self = cs; -} - -static inline c_String* c_string_assignN(c_String* self, const char* str, size_t len) { - if (len) { - c_string_reserve(self, len); - memmove(self->str, str, len); - self->str[_c_string_rep(*self)[0] = len] = '\0'; - } - return self; -} - -static inline c_String* c_string_assign(c_String* self, const char* str) { - return c_string_assignN(self, str, strlen(str)); -} - -static inline c_String* c_string_copy(c_String* self, c_String cs2) { - return c_string_assignN(self, cs2.str, c_string_size(cs2)); -} - - -static inline c_String* c_string_appendN(c_String* self, const char* str, size_t len) { - if (len) { - size_t oldlen = c_string_size(*self), newlen = oldlen + len; - if (newlen > c_string_capacity(*self)) - c_string_reserve(self, newlen * 5 / 3); - memmove(&self->str[oldlen], str, len); - self->str[_c_string_rep(*self)[0] = newlen] = '\0'; - } - return self; -} - -static inline c_String* c_string_append(c_String* self, const char* str) { - return c_string_appendN(self, str, strlen(str)); -} -static inline c_String* c_string_appendS(c_String* self, c_String cs2) { - return c_string_appendN(self, cs2.str, c_string_size(cs2)); -} - - -static inline void _c_string_internalMove(c_String* self, size_t pos1, size_t pos2) { - if (pos1 == pos2) - return; - size_t len = c_string_size(*self), newlen = len + pos2 - pos1; - if (newlen > c_string_capacity(*self)) - c_string_reserve(self, newlen * 5 / 3); - memmove(&self->str[pos2], &self->str[pos1], len - pos1); - self->str[_c_string_rep(*self)[0] = newlen] = '\0'; -} - -static inline void c_string_insertN(c_String* self, size_t pos, const char* str, size_t n) { - char* xstr = (char *) memcpy(n > c_defs_max_alloca ? malloc(n) : alloca(n), str, n); - _c_string_internalMove(self, pos, pos + n); - memcpy(&self->str[pos], xstr, n); - if (n > c_defs_max_alloca) free(xstr); -} - -static inline void c_string_insert(c_String* self, size_t pos, const char* str) { - c_string_insertN(self, pos, str, strlen(str)); -} - -static inline void c_string_erase(c_String* self, size_t pos, size_t n) { - size_t len = c_string_size(*self); - if (len) { - memmove(&self->str[pos], &self->str[pos + n], len - (pos + n)); - self->str[_c_string_rep(*self)[0] -= n] = '\0'; - } -} - -static inline size_t c_string_findN(c_String cs, size_t pos, const char* needle, size_t n); - -static inline size_t c_string_replaceN(c_String* self, size_t pos, const char* s1, size_t n1, const char* s2, size_t n2) { - size_t pos2 = c_string_findN(*self, pos, s1, n1); - if (pos2 == c_string_npos) return c_string_npos; - char* xs2 = (char *) memcpy(n2 > c_defs_max_alloca ? malloc(n2) : alloca(n2), s2, n2); - _c_string_internalMove(self, pos2 + n1, pos2 + n2); - memcpy(&self->str[pos2], xs2, n2); - if (n2 > c_defs_max_alloca) free(xs2); - return pos2; -} - -static inline size_t c_string_replace(c_String* self, size_t pos, const char* s1, const char* s2) { - return c_string_replaceN(self, pos, s1, strlen(s1), s2, strlen(s2)); -} - - -static inline char c_string_back(c_String cs) { - return cs.str[c_string_size(cs) - 1]; -} - -static inline c_String* c_string_push(c_String* self, char value) { - return c_string_appendN(self, &value, 1); -} - - -static inline void c_string_pop(c_String* self) { - --_c_string_rep(*self)[0]; -} - -/* readonly */ - -static inline bool c_string_empty(c_String cs) { - return c_string_size(cs) == 0; -} - -static inline bool c_string_equals(c_String cs1, const char* str) { - return strcmp(cs1.str, str) == 0; -} -static inline bool c_string_equalsS(c_String cs1, c_String cs2) { - return strcmp(cs1.str, cs2.str) == 0; -} - -static inline char* c_string_strnstr(c_String cs, size_t pos, const char* needle, size_t n) { - char *x = cs.str + pos, // haystack - *z = cs.str + c_string_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 c_string_findN(c_String cs, size_t pos, const char* needle, size_t n) { - char* res = c_string_strnstr(cs, pos, needle, n); - return res ? res - cs.str : c_string_npos; -} - -static inline size_t c_string_find(c_String cs, size_t pos, const char* needle) { - char* res = strstr(cs.str + pos, needle); - return res ? res - cs.str : c_string_npos; -} - -static inline char* c_string_splitFirst(const char* delimiters, c_String cs) { - return strtok(cs.str, delimiters); -} - -static inline char* c_string_splitNext(const char* delimiters) { - return strtok(NULL, delimiters); -} - - -// c_Vector / c_Hashmap API functions: - -#define c_string_getRaw(x) ((x).str) -static inline uint32_t c_string_hashRaw(const char** str, size_t sz_ignored) { return c_defs_murmurHash(*str, strlen(*str)); } -static inline int c_string_compareRaw(c_String* self, const char** str, size_t sz_ignored) { return strcmp(self->str, *str); } - - -#endif +// 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 C_STRING__H__
+#define C_STRING__H__
+
+#include <malloc.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "c_defs.h"
+
+typedef struct c_String {
+ char* str;
+} c_String;
+
+
+static size_t _c_string_null_rep[] = {0, 0, 0};
+#define _c_string_rep(cs) (((size_t *) (cs).str) - 2)
+
+#define c_string_initializer {(char* ) (_c_string_null_rep + 2)}
+#define c_string_size(cs) ((size_t) _c_string_rep(cs)[0])
+#define c_string_capacity(cs) ((size_t) _c_string_rep(cs)[1])
+#define c_string_npos c_defs_npos
+
+
+static inline void c_string_reserve(c_String* self, size_t cap) {
+ size_t len = c_string_size(*self), oldcap = c_string_capacity(*self);
+ if (cap > oldcap) {
+ size_t* rep = (size_t *) realloc(oldcap ? _c_string_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 c_string_destroy(c_String* self) {
+ if (c_string_capacity(*self)) {
+ free(_c_string_rep(*self));
+ }
+}
+
+static inline c_String c_string_init(void) {
+ c_String cs = c_string_initializer;
+ return cs;
+}
+
+static inline c_String c_string_makeN(const char* str, size_t len) {
+ c_String cs = c_string_initializer;
+ if (len) {
+ c_string_reserve(&cs, len);
+ memcpy(cs.str, str, len);
+ cs.str[ _c_string_rep(cs)[0] = len ] = '\0';
+ }
+ return cs;
+}
+
+static inline c_String c_string_make(const char* str) {
+ return c_string_makeN(str, strlen(str));
+}
+
+static inline c_String c_string_makeCopy(c_String cs) {
+ return c_string_makeN(cs.str, c_string_size(cs));
+}
+
+static inline void c_string_clear(c_String* self) {
+ c_String cs = c_string_initializer;
+ c_string_destroy(self);
+ *self = cs;
+}
+
+static inline c_String* c_string_assignN(c_String* self, const char* str, size_t len) {
+ if (len) {
+ c_string_reserve(self, len);
+ memmove(self->str, str, len);
+ self->str[_c_string_rep(*self)[0] = len] = '\0';
+ }
+ return self;
+}
+
+static inline c_String* c_string_assign(c_String* self, const char* str) {
+ return c_string_assignN(self, str, strlen(str));
+}
+
+static inline c_String* c_string_copy(c_String* self, c_String cs2) {
+ return c_string_assignN(self, cs2.str, c_string_size(cs2));
+}
+
+
+static inline c_String* c_string_appendN(c_String* self, const char* str, size_t len) {
+ if (len) {
+ size_t oldlen = c_string_size(*self), newlen = oldlen + len;
+ if (newlen > c_string_capacity(*self))
+ c_string_reserve(self, newlen * 5 / 3);
+ memmove(&self->str[oldlen], str, len);
+ self->str[_c_string_rep(*self)[0] = newlen] = '\0';
+ }
+ return self;
+}
+
+static inline c_String* c_string_append(c_String* self, const char* str) {
+ return c_string_appendN(self, str, strlen(str));
+}
+static inline c_String* c_string_appendS(c_String* self, c_String cs2) {
+ return c_string_appendN(self, cs2.str, c_string_size(cs2));
+}
+
+
+static inline void _c_string_internalMove(c_String* self, size_t pos1, size_t pos2) {
+ if (pos1 == pos2)
+ return;
+ size_t len = c_string_size(*self), newlen = len + pos2 - pos1;
+ if (newlen > c_string_capacity(*self))
+ c_string_reserve(self, newlen * 5 / 3);
+ memmove(&self->str[pos2], &self->str[pos1], len - pos1);
+ self->str[_c_string_rep(*self)[0] = newlen] = '\0';
+}
+
+static inline void c_string_insertN(c_String* self, size_t pos, const char* str, size_t n) {
+ char* xstr = (char *) memcpy(n > c_defs_max_alloca ? malloc(n) : alloca(n), str, n);
+ _c_string_internalMove(self, pos, pos + n);
+ memcpy(&self->str[pos], xstr, n);
+ if (n > c_defs_max_alloca) free(xstr);
+}
+
+static inline void c_string_insert(c_String* self, size_t pos, const char* str) {
+ c_string_insertN(self, pos, str, strlen(str));
+}
+
+static inline void c_string_erase(c_String* self, size_t pos, size_t n) {
+ size_t len = c_string_size(*self);
+ if (len) {
+ memmove(&self->str[pos], &self->str[pos + n], len - (pos + n));
+ self->str[_c_string_rep(*self)[0] -= n] = '\0';
+ }
+}
+
+static inline size_t c_string_findN(c_String cs, size_t pos, const char* needle, size_t n);
+
+static inline size_t c_string_replaceN(c_String* self, size_t pos, const char* s1, size_t n1, const char* s2, size_t n2) {
+ size_t pos2 = c_string_findN(*self, pos, s1, n1);
+ if (pos2 == c_string_npos) return c_string_npos;
+ char* xs2 = (char *) memcpy(n2 > c_defs_max_alloca ? malloc(n2) : alloca(n2), s2, n2);
+ _c_string_internalMove(self, pos2 + n1, pos2 + n2);
+ memcpy(&self->str[pos2], xs2, n2);
+ if (n2 > c_defs_max_alloca) free(xs2);
+ return pos2;
+}
+
+static inline size_t c_string_replace(c_String* self, size_t pos, const char* s1, const char* s2) {
+ return c_string_replaceN(self, pos, s1, strlen(s1), s2, strlen(s2));
+}
+
+
+static inline char c_string_back(c_String cs) {
+ return cs.str[c_string_size(cs) - 1];
+}
+
+static inline c_String* c_string_push(c_String* self, char value) {
+ return c_string_appendN(self, &value, 1);
+}
+
+
+static inline void c_string_pop(c_String* self) {
+ --_c_string_rep(*self)[0];
+}
+
+/* readonly */
+
+static inline bool c_string_empty(c_String cs) {
+ return c_string_size(cs) == 0;
+}
+
+static inline bool c_string_equals(c_String cs1, const char* str) {
+ return strcmp(cs1.str, str) == 0;
+}
+static inline bool c_string_equalsS(c_String cs1, c_String cs2) {
+ return strcmp(cs1.str, cs2.str) == 0;
+}
+
+static inline char* c_string_strnstr(c_String cs, size_t pos, const char* needle, size_t n) {
+ char *x = cs.str + pos, // haystack
+ *z = cs.str + c_string_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 c_string_findN(c_String cs, size_t pos, const char* needle, size_t n) {
+ char* res = c_string_strnstr(cs, pos, needle, n);
+ return res ? res - cs.str : c_string_npos;
+}
+
+static inline size_t c_string_find(c_String cs, size_t pos, const char* needle) {
+ char* res = strstr(cs.str + pos, needle);
+ return res ? res - cs.str : c_string_npos;
+}
+
+static inline char* c_string_splitFirst(const char* delimiters, c_String cs) {
+ return strtok(cs.str, delimiters);
+}
+
+static inline char* c_string_splitNext(const char* delimiters) {
+ return strtok(NULL, delimiters);
+}
+
+
+// c_Vector / c_Hashmap API functions:
+
+#define c_string_getRaw(x) ((x).str)
+static inline uint32_t c_string_hashRaw(const char** str, size_t sz_ignored) { return c_defs_murmurHash(*str, strlen(*str)); }
+static inline int c_string_compareRaw(c_String* self, const char** str, size_t sz_ignored) { return strcmp(self->str, *str); }
+
+
+#endif
@@ -1,147 +1,161 @@ -// 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 C_VECTOR__H__ -#define C_VECTOR__H__ - -#include <malloc.h> -#include <string.h> -#include "c_defs.h" - - -#define c_vector_initializer {NULL} -#define c_vector_size(cv) _c_vector_safe_size((cv).data) -#define c_vector_capacity(cv) _c_vector_safe_capacity((cv).data) -#define c_vector_empty(cv) (_c_vector_safe_size((cv).data) == 0) - -#define c_declare_Vector(...) c_defs_MACRO_OVERLOAD(c_declare_Vector, __VA_ARGS__) -#define c_declare_Vector_2(tag, Value) c_declare_Vector_3(tag, Value, c_defs_destroy) -#define c_declare_Vector_string(tag) c_declare_Vector_3(tag, c_String, c_string_destroy) - - -#define c_declare_Vector_3(tag, Value, valueDestroy) \ -typedef struct c_Vector_##tag { \ - Value* data; \ -} c_Vector_##tag; \ -typedef struct c_vector_##tag##_iter_t { \ - Value* item; \ -} c_vector_##tag##_iter_t; \ - \ -static inline c_Vector_##tag c_vector_##tag##_init(void) { \ - c_Vector_##tag cv = c_vector_initializer; \ - return cv; \ -} \ - \ -static inline void c_vector_##tag##_swap(c_Vector_##tag* a, c_Vector_##tag* b) { \ - Value* data = a->data; a->data = b->data; b->data = data; \ -} \ - \ -static inline void c_vector_##tag##_destroy(c_Vector_##tag* self) { \ - Value* p = self->data; \ - size_t i = 0, n = c_vector_size(*self); \ - for (; i < n; ++p, ++i) valueDestroy(p); \ - free(_c_vector_alloced(self->data)); \ -} \ - \ -static inline void c_vector_##tag##_reserve(c_Vector_##tag* self, size_t cap) { \ - if (cap > c_vector_capacity(*self)) { \ - size_t len = c_vector_size(*self); \ - size_t* rep = (size_t *) realloc(_c_vector_alloced(self->data), 2 * sizeof(size_t) + cap * sizeof(Value)); \ - self->data = (Value *) (rep + 2); \ - rep[0] = len; \ - rep[1] = cap; \ - } \ -} \ - \ -static inline void c_vector_##tag##_clear(c_Vector_##tag* self) { \ - c_Vector_##tag cv = c_vector_initializer; \ - c_vector_##tag##_destroy(self); \ - *self = cv; \ -} \ - \ - \ -static inline void c_vector_##tag##_push(c_Vector_##tag* self, Value value) { \ - size_t newsize = c_vector_size(*self) + 1; \ - if (newsize > c_vector_capacity(*self)) \ - c_vector_##tag##_reserve(self, 7 + newsize * 5 / 3); \ - self->data[c_vector_size(*self)] = value; \ - _c_vector_size(*self) = newsize; \ -} \ - \ -static inline void c_vector_##tag##_insert(c_Vector_##tag* self, size_t pos, Value value) { \ - c_vector_##tag##_push(self, value); \ - size_t len = c_vector_size(*self); \ - memmove(&self->data[pos + 1], &self->data[pos], (len - pos - 1) * sizeof(Value)); \ - self->data[pos] = value; \ -} \ - \ -static inline void c_vector_##tag##_erase(c_Vector_##tag* self, size_t pos, size_t size) { \ - size_t len = c_vector_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)); \ - _c_vector_size(*self) -= size; \ - } \ -} \ - \ - \ -static inline Value c_vector_##tag##_back(c_Vector_##tag cv) { \ - return cv.data[_c_vector_size(cv) - 1]; \ -} \ - \ -static inline void c_vector_##tag##_pop(c_Vector_##tag* self) { \ - valueDestroy(&self->data[_c_vector_size(*self) - 1]); \ - --_c_vector_size(*self); \ -} \ - \ -static inline c_vector_##tag##_iter_t c_vector_##tag##_begin(c_Vector_##tag vec) { \ - c_vector_##tag##_iter_t it = {vec.data}; \ - return it; \ -} \ - \ -static inline c_vector_##tag##_iter_t c_vector_##tag##_next(c_vector_##tag##_iter_t it) { \ - ++it.item; \ - return it; \ -} \ - \ -static inline c_vector_##tag##_iter_t c_vector_##tag##_end(c_Vector_##tag vec) { \ - c_vector_##tag##_iter_t it = {vec.data + c_vector_size(vec)}; \ - return it; \ -} \ -typedef Value c_vector_##tag##_value_t - - -#define _c_vector_size(cv) ((size_t *)(cv).data)[-2] -#define _c_vector_capacity(cv) ((size_t *)(cv).data)[-1] - -static inline size_t* _c_vector_alloced(void* data) { - return data ? ((size_t *) data) - 2 : NULL; -} -static inline size_t _c_vector_safe_size(const void* data) { - return data ? ((const size_t *) data)[-2] : 0; -} -static inline size_t _c_vector_safe_capacity(const void* data) { - return data ? ((const size_t *) data)[-1] : 0; -} - -#endif +// 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 C_VECTOR__H__
+#define C_VECTOR__H__
+
+#include <malloc.h>
+#include <string.h>
+#include "c_defs.h"
+
+
+#define c_vector_initializer {NULL}
+#define c_vector_size(cv) _c_vector_safe_size((cv).data)
+#define c_vector_capacity(cv) _c_vector_safe_capacity((cv).data)
+#define c_vector_empty(cv) (_c_vector_safe_size((cv).data) == 0)
+
+#define c_declare_Vector(...) c_defs_MACRO_OVERLOAD(c_declare_Vector, __VA_ARGS__)
+#define c_declare_Vector_2(tag, Value) \
+ c_declare_Vector_3(tag, Value, c_defs_destroy)
+#define c_declare_Vector_3(tag, Value, valueDestroy) \
+ c_declare_Vector_5(tag, Value, valueDestroy, memcmp, Value)
+#define c_declare_Vector_4(tag, Value, valueDestroy, valueCompare) \
+ c_declare_Vector_5(tag, Value, valueDestroy, valueCompare, Value)
+#define c_declare_Vector_string(tag) \
+ c_declare_Vector_5(tag, c_String, c_string_destroy, c_string_compareRaw, const char*)
+
+#define c_declare_Vector_5(tag, Value, valueDestroy, valueCompareRaw, ValueRaw) \
+typedef struct c_Vector_##tag { \
+ Value* data; \
+} c_Vector_##tag; \
+ \
+typedef struct c_vector_##tag##_iter_t { \
+ Value* item; \
+} c_vector_##tag##_iter_t; \
+ \
+static inline c_Vector_##tag c_vector_##tag##_init(void) { \
+ c_Vector_##tag cv = c_vector_initializer; \
+ return cv; \
+} \
+ \
+static inline void c_vector_##tag##_swap(c_Vector_##tag* a, c_Vector_##tag* b) { \
+ Value* data = a->data; a->data = b->data; b->data = data; \
+} \
+ \
+static inline void c_vector_##tag##_destroy(c_Vector_##tag* self) { \
+ Value* p = self->data; \
+ size_t i = 0, n = c_vector_size(*self); \
+ for (; i < n; ++p, ++i) valueDestroy(p); \
+ free(_c_vector_alloced(self->data)); \
+} \
+ \
+static inline void c_vector_##tag##_reserve(c_Vector_##tag* self, size_t cap) { \
+ if (cap > c_vector_capacity(*self)) { \
+ size_t len = c_vector_size(*self); \
+ size_t* rep = (size_t *) realloc(_c_vector_alloced(self->data), 2 * sizeof(size_t) + cap * sizeof(Value)); \
+ self->data = (Value *) (rep + 2); \
+ rep[0] = len; \
+ rep[1] = cap; \
+ } \
+} \
+ \
+static inline void c_vector_##tag##_clear(c_Vector_##tag* self) { \
+ c_Vector_##tag cv = c_vector_initializer; \
+ c_vector_##tag##_destroy(self); \
+ *self = cv; \
+} \
+ \
+ \
+static inline void c_vector_##tag##_push(c_Vector_##tag* self, Value value) { \
+ size_t newsize = c_vector_size(*self) + 1; \
+ if (newsize > c_vector_capacity(*self)) \
+ c_vector_##tag##_reserve(self, 7 + newsize * 5 / 3); \
+ self->data[c_vector_size(*self)] = value; \
+ _c_vector_size(*self) = newsize; \
+} \
+ \
+static inline void c_vector_##tag##_insert(c_Vector_##tag* self, size_t pos, Value value) { \
+ c_vector_##tag##_push(self, value); \
+ size_t len = c_vector_size(*self); \
+ memmove(&self->data[pos + 1], &self->data[pos], (len - pos - 1) * sizeof(Value)); \
+ self->data[pos] = value; \
+} \
+ \
+static inline void c_vector_##tag##_erase(c_Vector_##tag* self, size_t pos, size_t size) { \
+ size_t len = c_vector_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)); \
+ _c_vector_size(*self) -= size; \
+ } \
+} \
+ \
+ \
+static inline size_t c_vector_##tag##_find(c_Vector_##tag cv, ValueRaw rawValue) { \
+ size_t n = c_vector_size(cv); \
+ for (size_t i = 0; i < n; ++i) \
+ if (valueCompareRaw(&cv.data[i], &rawValue, sizeof(Value)) == 0) return i; \
+ return c_defs_npos; \
+} \
+ \
+ \
+static inline Value c_vector_##tag##_back(c_Vector_##tag cv) { \
+ return cv.data[_c_vector_size(cv) - 1]; \
+} \
+ \
+static inline void c_vector_##tag##_pop(c_Vector_##tag* self) { \
+ valueDestroy(&self->data[_c_vector_size(*self) - 1]); \
+ --_c_vector_size(*self); \
+} \
+ \
+static inline c_vector_##tag##_iter_t c_vector_##tag##_begin(c_Vector_##tag vec) { \
+ c_vector_##tag##_iter_t it = {vec.data}; \
+ return it; \
+} \
+ \
+static inline c_vector_##tag##_iter_t c_vector_##tag##_next(c_vector_##tag##_iter_t it) { \
+ ++it.item; \
+ return it; \
+} \
+ \
+static inline c_vector_##tag##_iter_t c_vector_##tag##_end(c_Vector_##tag vec) { \
+ c_vector_##tag##_iter_t it = {vec.data + c_vector_size(vec)}; \
+ return it; \
+} \
+typedef Value c_vector_##tag##_value_t
+
+
+#define _c_vector_size(cv) ((size_t *)(cv).data)[-2]
+#define _c_vector_capacity(cv) ((size_t *)(cv).data)[-1]
+
+static inline size_t* _c_vector_alloced(void* data) {
+ return data ? ((size_t *) data) - 2 : NULL;
+}
+static inline size_t _c_vector_safe_size(const void* data) {
+ return data ? ((const size_t *) data)[-2] : 0;
+}
+static inline size_t _c_vector_safe_capacity(const void* data) {
+ return data ? ((const size_t *) data)[-1] : 0;
+}
+
+#endif
diff --git a/cmap_test.c b/cmap_test.c index 563c27c7..c02b25cd 100644 --- a/cmap_test.c +++ b/cmap_test.c @@ -79,7 +79,7 @@ void stringSpeed(int limit) { clock_t before = clock();
for (int n = 0; n < limit; ++n) {
p = c_string_find(s, 0, search + (n % 100));
- if (p != c_string_npos) x += p;
+ if (p != c_string_npos) x += p;
}
clock_t diff = clock() - before;
printf("string length = %llu / %llu, sum %llu speed: %f\n", c_string_size(s), c_string_capacity(s), x, 1.0 * diff / CLOCKS_PER_SEC);
|
