diff options
| author | Tyge <[email protected]> | 2020-04-26 21:35:21 +0200 |
|---|---|---|
| committer | Tyge <[email protected]> | 2020-04-26 21:35:21 +0200 |
| commit | 3cb4dbde06c56c9ba069ca54ad6c6334e3b56943 (patch) | |
| tree | 90a1ea2d3870dea9951338d181c5ad07d20f3989 | |
| parent | 8f6bcbadeaf345cb181f78e768052b60c16fd49a (diff) | |
| download | STC-modified-3cb4dbde06c56c9ba069ca54ad6c6334e3b56943.tar.gz STC-modified-3cb4dbde06c56c9ba069ca54ad6c6334e3b56943.zip | |
Refactored: Uses STC_API to control extern or static inline. Define STC_HEADER or STC_IMPLEMENTATION when using extern linkage.
Fixed a few bugs.
| -rw-r--r-- | benchmark.c | 2 | ||||
| -rw-r--r-- | stc/cdefs.h | 6 | ||||
| -rw-r--r-- | stc/cflist.h | 149 | ||||
| -rw-r--r-- | stc/cmap.h | 148 | ||||
| -rw-r--r-- | 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 <stdint.h>
#include <stdbool.h>
+#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 @@ -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<CString, Value>: */
-#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 <string.h>
#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
|
