From 3cb4dbde06c56c9ba069ca54ad6c6334e3b56943 Mon Sep 17 00:00:00 2001 From: Tyge Date: Sun, 26 Apr 2020 21:35:21 +0200 Subject: Refactored: Uses STC_API to control extern or static inline. Define STC_HEADER or STC_IMPLEMENTATION when using extern linkage. Fixed a few bugs. --- benchmark.c | 2 +- stc/cdefs.h | 6 +++ stc/cflist.h | 149 ++++++++++++++++++++++++++++++++++++---------------------- stc/cmap.h | 148 +++++++++++++++++++++++++++++++++++---------------------- stc/cvector.h | 136 +++++++++++++++++++++++++++++++++-------------------- 5 files changed, 276 insertions(+), 165 deletions(-) diff --git a/benchmark.c b/benchmark.c index 7f4e8cef..f4e16546 100644 --- a/benchmark.c +++ b/benchmark.c @@ -20,7 +20,7 @@ const size_t seed = 123; // time(NULL); const double maxLoadFactor = 0.77; #define RAND() rand() * rand() -#define CMAP_SETUP(tag, Key, Value) CMap_##tag map = cmap_##tag##_init; \ +#define CMAP_SETUP(tag, Key, Value) CMap_##tag map = cmap_init; \ cmap_##tag##_setMaxLoadFactor(&map, maxLoadFactor) #define CMAP_PUT(tag, __key, __value) cmap_##tag##_put(&map, __key, __value)->value #define CMAP_DEL(tag, key) cmap_##tag##_erase(&map, key) diff --git a/stc/cdefs.h b/stc/cdefs.h index b201dd59..f05c6ea0 100644 --- a/stc/cdefs.h +++ b/stc/cdefs.h @@ -26,6 +26,12 @@ #include #include +#if defined(STC_HEADER) || defined(STC_IMPLEMENTATION) +#define STC_API extern +#else +#define STC_API static inline +#endif + /* Macro overloading feature support: https://rextester.com/ONP80107 */ #define c_CAT( A, B ) A ## B #define c_EXPAND(...) __VA_ARGS__ diff --git a/stc/cflist.h b/stc/cflist.h index 80eff1d9..835548b3 100644 --- a/stc/cflist.h +++ b/stc/cflist.h @@ -74,7 +74,6 @@ } */ - #define declare_CFList(...) c_MACRO_OVERLOAD(declare_CFList, __VA_ARGS__) #define declare_CFList_2(tag, Value) \ @@ -86,7 +85,6 @@ #define declare_CFList_string(tag) \ declare_CFList_6(tag, CString, cstring_destroy, cstring_compareRaw, const char*, cstring_getRaw) - #define declare_CFListTypes(tag, Value) \ c_struct (CFListNode_##tag) { \ CFListNode_##tag *next; \ @@ -101,76 +99,103 @@ CFListNode_##tag *item, **_last; \ } - #define cflist_init {NULL} #define cflist_front(list) (list).last->next->value #define cflist_back(list) (list).last->value #define cflist_empty(list) ((list).last == NULL) + #define declare_CFList_6(tag, Value, valueDestroy, valueCompare, ValueRaw, valueGetRaw) \ \ declare_CFListTypes(tag, Value); \ typedef ValueRaw cflist_##tag##_raw_t; \ \ - static inline void \ - cflist_##tag##_pushFront(CFList_##tag* self, Value value) { \ - _cflist_insertAfter(tag, self->last, value); \ - if (!self->last) self->last = entry; \ + STC_API void \ + cflist_##tag##_destroy(CFList_##tag* self); \ + \ + STC_API void \ + cflist_##tag##_pushFront(CFList_##tag* self, Value value); \ + \ + STC_API void \ + cflist_##tag##_popFront(CFList_##tag* self); \ + \ + STC_API void \ + cflist_##tag##_pushBack(CFList_##tag* self, Value value); \ + \ + STC_API void \ + cflist_##tag##_insertAfter(CFList_##tag* self, cflist_##tag##_iter_t pos, Value value); \ + \ + STC_API void \ + cflist_##tag##_eraseAfter(CFList_##tag* self, cflist_##tag##_iter_t pos); \ + \ + STC_API void \ + cflist_##tag##_spliceFront(CFList_##tag* self, CFList_##tag* other); \ + \ + STC_API void \ + cflist_##tag##_spliceAfter(CFList_##tag* self, cflist_##tag##_iter_t pos, CFList_##tag* other); \ + \ + STC_API int \ + cflist_##tag##_remove(CFList_##tag* self, ValueRaw val); \ + \ + STC_API void \ + cflist_##tag##_sort(CFList_##tag* self); \ + \ + static inline cflist_##tag##_iter_t \ + cflist_##tag##_begin(CFList_##tag* lst) { \ + CFListNode_##tag *head = lst->last ? lst->last->next : NULL; \ + return (cflist_##tag##_iter_t) {head, &lst->last}; \ } \ - static inline void \ - cflist_##tag##_pushBack(CFList_##tag* self, Value value) { \ - _cflist_insertAfter(tag, self->last, value); \ - self->last = entry; \ + static inline cflist_##tag##_iter_t \ + cflist_##tag##_next(cflist_##tag##_iter_t it) { \ + it.item = it.item == *it._last ? NULL : it.item->next; \ + return it; \ } \ - static inline void \ - cflist_##tag##_insertAfter(CFList_##tag* self, cflist_##tag##_iter_t pos, Value value) { \ - _cflist_insertAfter(tag, pos.item, value); \ - if (!self->last || pos.item == self->last) self->last = entry; \ + static inline cflist_##tag##_iter_t \ + cflist_##tag##_last(CFList_##tag* lst) { \ + return (cflist_##tag##_iter_t) {lst->last, &lst->last}; \ } \ \ - static inline void \ - cflist_##tag##_eraseAfter(CFList_##tag* self, cflist_##tag##_iter_t pos) { \ - _cflist_eraseAfter(tag, pos.item, valueDestroy); \ - } \ + implement_CFList_6(tag, Value, valueDestroy, valueCompare, ValueRaw, valueGetRaw) \ \ - static inline void \ - cflist_##tag##_popFront(CFList_##tag* self) { \ - _cflist_eraseAfter(tag, self->last, valueDestroy); \ - } \ + typedef Value cflist_##tag##_value_t + + +/* -------------------------- IMPLEMENTATION ------------------------- */ + +#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) +#define implement_CFList_6(tag, Value, valueDestroy, valueCompare, ValueRaw, valueGetRaw) \ \ - static inline void \ + STC_API void \ cflist_##tag##_destroy(CFList_##tag* self) { \ while (self->last) \ cflist_##tag##_popFront(self); \ } \ \ - static inline int \ - cflist_##tag##_sortCmp(const void* x, const void* y) { \ - ValueRaw a = valueGetRaw(&((CFListNode_##tag *) x)->value); \ - ValueRaw b = valueGetRaw(&((CFListNode_##tag *) y)->value); \ - return valueCompare(&a, &b); \ + STC_API void \ + cflist_##tag##_pushFront(CFList_##tag* self, Value value) { \ + _cflist_insertAfter(tag, self->last, value); \ + if (!self->last) self->last = entry; \ } \ - \ - static inline void \ - cflist_##tag##_sort(CFList_##tag* self) { \ - CFListNode__base* last = cflist_mergesort((CFListNode__base *) self->last, cflist_##tag##_sortCmp); \ - self->last = (CFListNode_##tag *) last; \ + STC_API void \ + cflist_##tag##_popFront(CFList_##tag* self) { \ + _cflist_eraseAfter(tag, self->last, valueDestroy); \ } \ \ - static inline cflist_##tag##_iter_t \ - cflist_##tag##_begin(CFList_##tag* lst) { \ - CFListNode_##tag *head = lst->last ? lst->last->next : NULL; \ - return (cflist_##tag##_iter_t) {head, &lst->last}; \ + STC_API void \ + cflist_##tag##_pushBack(CFList_##tag* self, Value value) { \ + _cflist_insertAfter(tag, self->last, value); \ + self->last = entry; \ } \ - static inline cflist_##tag##_iter_t \ - cflist_##tag##_last(CFList_##tag* lst) { \ - return (cflist_##tag##_iter_t) {lst->last, &lst->last}; \ + \ + STC_API void \ + cflist_##tag##_insertAfter(CFList_##tag* self, cflist_##tag##_iter_t pos, Value value) { \ + _cflist_insertAfter(tag, pos.item, value); \ + if (!self->last || pos.item == self->last) self->last = entry; \ } \ \ - static inline cflist_##tag##_iter_t \ - cflist_##tag##_next(cflist_##tag##_iter_t it) { \ - it.item = it.item == *it._last ? NULL : it.item->next; \ - return it; \ + STC_API void \ + cflist_##tag##_eraseAfter(CFList_##tag* self, cflist_##tag##_iter_t pos) { \ + _cflist_eraseAfter(tag, pos.item, valueDestroy); \ } \ \ static inline void \ @@ -185,16 +210,16 @@ } \ other->last = NULL; \ } \ - static inline void \ + STC_API void \ cflist_##tag##_spliceFront(CFList_##tag* self, CFList_##tag* other) { \ _cflist_##tag##_splice(self, cflist_##tag##_last(self), other, false); \ } \ - static inline void \ + STC_API void \ cflist_##tag##_spliceAfter(CFList_##tag* self, cflist_##tag##_iter_t pos, CFList_##tag* other) { \ _cflist_##tag##_splice(self, pos, other, true); \ } \ \ - static inline int \ + STC_API int \ cflist_##tag##_remove(CFList_##tag* self, ValueRaw val) { \ cflist_##tag##_iter_t prev = {self->last}; int n = 0; \ ValueRaw r; \ @@ -208,18 +233,26 @@ return n; \ } \ \ - typedef Value cflist_##tag##_value_t - + static inline int \ + cflist_##tag##_sortCmp(const void* x, const void* y) { \ + ValueRaw a = valueGetRaw(&((CFListNode_##tag *) x)->value); \ + ValueRaw b = valueGetRaw(&((CFListNode_##tag *) y)->value); \ + return valueCompare(&a, &b); \ + } \ + STC_API void \ + cflist_##tag##_sort(CFList_##tag* self) { \ + CFListNode__base* last = _cflist_mergesort((CFListNode__base *) self->last, cflist_##tag##_sortCmp); \ + self->last = (CFListNode_##tag *) last; \ + } #define _cflist_insertAfter(tag, node, val) \ CFListNode_##tag *entry = c_new_1(CFListNode_##tag), \ *next = self->last ? node->next : entry; \ entry->value = val; \ entry->next = next; \ - if (node) node->next = entry \ + if (node) node->next = entry /* +: set self->last based on node */ - #define _cflist_eraseAfter(tag, node, valueDestroy) \ CFListNode_##tag* del = node->next, *next = del->next; \ node->next = next; \ @@ -228,15 +261,13 @@ valueDestroy(&del->value); \ free(del) - declare_CFListTypes(_base, int); -/* - * Singly linked list Mergesort implementation by Simon Tatham. O(n*log(n)). +/* Singly linked list Mergesort implementation by Simon Tatham. O(n*log(n)). * https://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html */ -static CFListNode__base * -cflist_mergesort(CFListNode__base *list, int (*cmp)(const void*, const void*)) { +static inline CFListNode__base * +_cflist_mergesort(CFListNode__base *list, int (*cmp)(const void*, const void*)) { CFListNode__base *p, *q, *e, *tail, *oldhead; int insize = 1, nmerges, psize, qsize, i; if (!list) return NULL; @@ -289,4 +320,8 @@ cflist_mergesort(CFListNode__base *list, int (*cmp)(const void*, const void*)) { } } +#else +#define implement_CFList_6(tag, Value, valueDestroy, valueCompare, ValueRaw, valueGetRaw) +#endif + #endif diff --git a/stc/cmap.h b/stc/cmap.h index 02b5ee93..feb665bc 100644 --- a/stc/cmap.h +++ b/stc/cmap.h @@ -25,38 +25,15 @@ #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(...) \ + c_MACRO_OVERLOAD(declare_CMap, __VA_ARGS__) #define declare_CMap_3(tag, Key, Value) \ declare_CMap_4(tag, Key, Value, c_defaultDestroy) @@ -73,21 +50,40 @@ enum {cmapentry_HASH=0x7fff, cmapentry_USED=0x8000}; /* CMap: */ -#define declare_CMap_stringkey(...) c_MACRO_OVERLOAD(declare_CMap_stringkey, __VA_ARGS__) +#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) + const char*, 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); \ +\ + 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; \ +\ + declare_CVector_4(map_##tag, CMapEntry_##tag, cmapentry_##tag##_destroy, c_noCompare); \ typedef RawKey cmap_##tag##_rawkey_t; \ \ typedef struct CMap_##tag { \ @@ -96,13 +92,62 @@ typedef struct CMap_##tag { \ 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; \ \ +STC_API void \ +cmap_##tag##_destroy(CMap_##tag* self); \ + \ +STC_API void \ +cmap_##tag##_clear(CMap_##tag* self); \ + \ static inline void \ +cmap_##tag##_swap(CMap_##tag* a, CMap_##tag* b) { \ + c_swap(CMap_##tag, *a, *b); \ +} \ + \ +STC_API void \ +cmap_##tag##_setMaxLoadFactor(CMap_##tag* self, double fac); \ + \ +STC_API void \ +cmap_##tag##_setShrinkLimitFactor(CMap_##tag* self, double limit); \ + \ +STC_API CMapEntry_##tag* \ +cmap_##tag##_get(CMap_##tag map, cmap_##tag##_rawkey_t rawKey); \ + \ +STC_API CMapEntry_##tag* \ +cmap_##tag##_put(CMap_##tag* self, cmap_##tag##_rawkey_t rawKey, Value value); \ + \ +STC_API CMapEntry_##tag* \ +cmap_##tag##_insert(CMap_##tag* self, CMapEntry_##tag entry); \ + \ +STC_API size_t \ +cmap_##tag##_reserve(CMap_##tag* self, size_t size); \ + \ +STC_API bool \ +cmap_##tag##_erase(CMap_##tag* self, cmap_##tag##_rawkey_t rawKey); \ + \ +STC_API cmap_##tag##_iter_t \ +cmap_##tag##_begin(CMap_##tag* map); \ + \ +STC_API cmap_##tag##_iter_t \ +cmap_##tag##_next(cmap_##tag##_iter_t it); \ + \ +implement_CMap_10(tag, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, keyDestroy, \ + RawKey, keyGetRaw, keyInitRaw) \ + \ +typedef Key cmap_##tag##_key_t; \ +typedef Value cmap_##tag##_value_t + +/* -------------------------- IMPLEMENTATION ------------------------- */ + +#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) +#define implement_CMap_10(tag, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, keyDestroy, \ + RawKey, keyGetRaw, keyInitRaw) \ + \ +STC_API void \ cmap_##tag##_destroy(CMap_##tag* self) { \ if (cmap_size(*self)) { \ size_t cap = _cvector_capacity(self->_table); \ @@ -112,34 +157,26 @@ cmap_##tag##_destroy(CMap_##tag* self) { \ 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) { \ +STC_API 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 \ +STC_API 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 \ +STC_API 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 \ +STC_API size_t \ cmap_##tag##_bucket(CMap_##tag* self, cmap_##tag##_rawkey_t* const rawKeyPtr, uint32_t* hxPtr) { \ uint32_t hash = keyHashRaw(rawKeyPtr, sizeof(cmap_##tag##_rawkey_t)), hx = (hash & cmapentry_HASH) | cmapentry_USED; \ size_t cap = cvector_capacity(self->_table); \ @@ -153,7 +190,7 @@ cmap_##tag##_bucket(CMap_##tag* self, cmap_##tag##_rawkey_t* const rawKeyPtr, ui return idx; \ } \ \ -static inline CMapEntry_##tag* \ +STC_API CMapEntry_##tag* \ cmap_##tag##_get(CMap_##tag map, cmap_##tag##_rawkey_t rawKey) { \ if (cmap_size(map) == 0) return NULL; \ uint32_t hx; \ @@ -161,14 +198,14 @@ cmap_##tag##_get(CMap_##tag map, cmap_##tag##_rawkey_t rawKey) { \ return map._table.data[idx].hashx ? &map._table.data[idx] : NULL; \ } \ \ -static inline void \ +STC_API 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* \ +STC_API CMapEntry_##tag* \ cmap_##tag##_put(CMap_##tag* self, cmap_##tag##_rawkey_t rawKey, Value value) { \ cmap_##tag##_expand(self); \ uint32_t hx; \ @@ -185,7 +222,7 @@ cmap_##tag##_put(CMap_##tag* self, cmap_##tag##_rawkey_t rawKey, Value value) { return e; \ } \ \ -static inline CMapEntry_##tag* \ +STC_API CMapEntry_##tag* \ cmap_##tag##_insert(CMap_##tag* self, CMapEntry_##tag entry) { \ cmap_##tag##_expand(self); \ uint32_t hx; \ @@ -203,11 +240,11 @@ cmap_##tag##_insert(CMap_##tag* self, CMapEntry_##tag entry) { \ return e; \ } \ \ -static inline size_t \ +STC_API 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 vec = cvector_init; \ cvector_map_##tag##_reserve(&vec, newcap); \ memset(vec.data, 0, sizeof(CMapEntry_##tag) * newcap); \ cvector_map_##tag##_swap(&self->_table, &vec); \ @@ -222,7 +259,7 @@ cmap_##tag##_reserve(CMap_##tag* self, size_t size) { \ return newcap; \ } \ \ -static inline bool \ +STC_API bool \ cmap_##tag##_erase(CMap_##tag* self, cmap_##tag##_rawkey_t rawKey) { \ if (cmap_size(*self) == 0) \ return false; \ @@ -249,22 +286,23 @@ cmap_##tag##_erase(CMap_##tag* self, cmap_##tag##_rawkey_t rawKey) { \ return true; \ } \ \ -static inline cmap_##tag##_iter_t \ +STC_API cmap_##tag##_iter_t \ cmap_##tag##_begin(CMap_##tag* map) { \ 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 ? NULL : e, end}; return it; \ } \ \ -static inline cmap_##tag##_iter_t \ +STC_API cmap_##tag##_iter_t \ cmap_##tag##_next(cmap_##tag##_iter_t it) { \ do { ++it.item; } while (it.item != it._end && !it.item->hashx); \ if (it.item == it._end) it.item = NULL; \ return it; \ -} \ - \ -typedef Key cmap_##tag##_key_t; \ -typedef Value cmap_##tag##_value_t +} +#else +#define implement_CMap_10(tag, Key, Value, valueDestroy, keyHashRaw, keyEqualsRaw, keyDestroy, \ + RawKey, keyGetRaw, keyInitRaw) +#endif /* https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction */ diff --git a/stc/cvector.h b/stc/cvector.h index 4bbc55cf..b86a0908 100644 --- a/stc/cvector.h +++ b/stc/cvector.h @@ -27,8 +27,6 @@ #include #include "cdefs.h" -extern void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*)); - #define cvector_init {NULL} #define cvector_size(cv) _cvector_safe_size((cv).data) #define cvector_capacity(cv) _cvector_safe_capacity((cv).data) @@ -45,21 +43,83 @@ extern void qsort(void *base, size_t nitems, size_t size, int (*compar)(const vo declare_CVector_6(tag, CString, cstring_destroy, cstring_compareRaw, const char*, cstring_getRaw) - #define declare_CVector_6(tag, Value, valueDestroy, valueCompare, ValueRaw, valueGetRaw) \ typedef ValueRaw cvector_##tag##_rawvalue_t; \ typedef struct CVector_##tag { \ Value* data; \ } CVector_##tag; \ \ -static const CVector_##tag cvector_##tag##_init = cvector_init; \ - \ static inline void \ cvector_##tag##_swap(CVector_##tag* a, CVector_##tag* b) { \ - Value* data = a->data; a->data = b->data; b->data = data; \ + c_swap(Value*, a->data, b->data); \ } \ \ +STC_API void \ +cvector_##tag##_destroy(CVector_##tag* self); \ + \ +STC_API void \ +cvector_##tag##_reserve(CVector_##tag* self, size_t cap); \ + \ +STC_API void \ +cvector_##tag##_clear(CVector_##tag* self); \ + \ +STC_API void \ +cvector_##tag##_pushBack(CVector_##tag* self, Value value); \ + \ static inline void \ +cvector_##tag##_popBack(CVector_##tag* self) { \ + valueDestroy(&self->data[_cvector_size(*self) - 1]); \ + --_cvector_size(*self); \ +} \ + \ +static inline Value \ +cvector_##tag##_back(CVector_##tag cv) { \ + return cv.data[_cvector_size(cv) - 1]; \ +} \ + \ +STC_API void \ +cvector_##tag##_insert(CVector_##tag* self, size_t pos, Value value); \ + \ +STC_API void \ +cvector_##tag##_erase(CVector_##tag* self, size_t pos, size_t size); \ + \ +static inline int \ +cvector_##tag##_sortCompare(const void* x, const void* y) { \ + ValueRaw rx = valueGetRaw((const Value *) x); \ + ValueRaw ry = valueGetRaw((const Value *) y); \ + return valueCompare(&rx, &ry); \ +} \ + \ +STC_API void \ +cvector_##tag##_sort(CVector_##tag* self); \ + \ +STC_API size_t \ +cvector_##tag##_find(CVector_##tag cv, ValueRaw rawValue); \ + \ + \ +typedef struct cvector_##tag##_iter_t { \ + Value *item, *end; \ +} cvector_##tag##_iter_t; \ + \ +STC_API cvector_##tag##_iter_t \ +cvector_##tag##_begin(CVector_##tag* vec); \ + \ +static inline cvector_##tag##_iter_t \ +cvector_##tag##_next(cvector_##tag##_iter_t it) { \ + if (++it.item == it.end) it.item = NULL; \ + return it; \ +} \ + \ +implement_CVector_6(tag, Value, valueDestroy, valueCompare, ValueRaw, valueGetRaw) \ + \ +typedef Value cvector_##tag##_value_t + +/* -------------------------- IMPLEMENTATION ------------------------- */ + +#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) +#define implement_CVector_6(tag, Value, valueDestroy, valueCompare, ValueRaw, valueGetRaw) \ + \ +STC_API void \ cvector_##tag##_destroy(CVector_##tag* self) { \ Value* p = self->data; \ size_t i = 0, n = cvector_size(*self); \ @@ -67,7 +127,7 @@ cvector_##tag##_destroy(CVector_##tag* self) { \ free(_cvector_alloced(self->data)); \ } \ \ -static inline void \ +STC_API void \ cvector_##tag##_reserve(CVector_##tag* self, size_t cap) { \ size_t len = cvector_size(*self); \ if (cap >= len) { \ @@ -78,15 +138,14 @@ cvector_##tag##_reserve(CVector_##tag* self, size_t cap) { \ } \ } \ \ -static inline void \ +STC_API void \ cvector_##tag##_clear(CVector_##tag* self) { \ - CVector_##tag cv = cvector_##tag##_init; \ + CVector_##tag cv = cvector_init; \ cvector_##tag##_destroy(self); \ *self = cv; \ } \ \ - \ -static inline void \ +STC_API void \ cvector_##tag##_pushBack(CVector_##tag* self, Value value) { \ size_t len = cvector_size(*self); \ if (len == cvector_capacity(*self)) \ @@ -95,7 +154,7 @@ cvector_##tag##_pushBack(CVector_##tag* self, Value value) { \ ++_cvector_size(*self); \ } \ \ -static inline void \ +STC_API void \ cvector_##tag##_insert(CVector_##tag* self, size_t pos, Value value) { \ size_t len = cvector_size(*self); \ if (len == cvector_capacity(*self)) \ @@ -105,7 +164,7 @@ cvector_##tag##_insert(CVector_##tag* self, size_t pos, Value value) { \ ++_cvector_size(*self); \ } \ \ -static inline void \ +STC_API void \ cvector_##tag##_erase(CVector_##tag* self, size_t pos, size_t size) { \ size_t len = cvector_size(*self); \ if (len) { \ @@ -116,20 +175,7 @@ cvector_##tag##_erase(CVector_##tag* self, size_t pos, size_t size) { \ } \ } \ \ -static inline int \ -cvector_##tag##_sortCompare(const void* x, const void* y) { \ - cvector_##tag##_rawvalue_t rx = valueGetRaw((const Value *) x); \ - cvector_##tag##_rawvalue_t ry = valueGetRaw((const Value *) y); \ - return valueCompare(&rx, &ry); \ -} \ - \ -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 \ +STC_API size_t \ cvector_##tag##_find(CVector_##tag cv, ValueRaw rawValue) { \ size_t n = cvector_size(cv); \ cvector_##tag##_rawvalue_t r; \ @@ -139,38 +185,23 @@ cvector_##tag##_find(CVector_##tag cv, ValueRaw rawValue) { \ return c_npos; \ } \ \ - \ -static inline Value \ -cvector_##tag##_back(CVector_##tag cv) { \ - return cv.data[_cvector_size(cv) - 1]; \ -} \ - \ -static inline void \ -cvector_##tag##_popBack(CVector_##tag* self) { \ - valueDestroy(&self->data[_cvector_size(*self) - 1]); \ - --_cvector_size(*self); \ +extern void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*)); \ +STC_API void \ +cvector_##tag##_sort(CVector_##tag* self) { \ + size_t len = cvector_size(*self); \ + if (len) qsort(self->data, len, sizeof(Value), cvector_##tag##_sortCompare); \ } \ \ - \ -typedef struct cvector_##tag##_iter_t { \ - Value *item, *end; \ -} cvector_##tag##_iter_t; \ - \ -static inline cvector_##tag##_iter_t \ +STC_API cvector_##tag##_iter_t \ cvector_##tag##_begin(CVector_##tag* vec) { \ cvector_##tag##_iter_t it; \ it.item = vec->data, it.end = it.item + cvector_size(*vec); \ if (it.item == it.end) it.item = NULL; \ return it; \ -} \ - \ -static inline cvector_##tag##_iter_t \ -cvector_##tag##_next(cvector_##tag##_iter_t it) { \ - if (++it.item == it.end) it.item = NULL; \ - return it; \ -} \ - \ -typedef Value cvector_##tag##_value_t +} +#else +#define implement_CVector_6(tag, Value, valueDestroy, valueCompare, ValueRaw, valueGetRaw) +#endif #define _cvector_size(cv) ((size_t *)(cv).data)[-2] @@ -186,4 +217,5 @@ static inline size_t _cvector_safe_capacity(const void* data) { return data ? ((const size_t *) data)[-1] : 0; } + #endif -- cgit v1.2.3