stb_ds.h: thread-safe functions; pointer-returning functions; change return value of arraddn
This commit is contained in:
parent
aa482fc4a1
commit
d693c6103a
257
stb_ds.h
257
stb_ds.h
@ -1,4 +1,5 @@
|
||||
/* stb_ds.h - v0.62 - public domain data structures - Sean Barrett 2019
|
||||
#include <stdio.h>
|
||||
/* stb_ds.h - v0.62b - public domain data structures - Sean Barrett 2019
|
||||
|
||||
This is a single-header-file library that provides easy-to-use
|
||||
dynamic arrays and hash tables for C (also works in C++).
|
||||
@ -108,6 +109,11 @@ DOCUMENTATION
|
||||
Inserts n uninitialized items into array a starting at a[p],
|
||||
moving the rest of the array over.
|
||||
|
||||
arraddn:
|
||||
T* arraddn(T* a, int n)
|
||||
Appends n uninitialized items onto array at the end.
|
||||
Returns a pointer to the first uninitialized item added.
|
||||
|
||||
arrdel:
|
||||
void arrdel(T* a, int p);
|
||||
Deletes the element at a[p], moving the rest of the array over.
|
||||
@ -191,15 +197,19 @@ DOCUMENTATION
|
||||
|
||||
hmgeti
|
||||
shgeti
|
||||
hmgeti_ts
|
||||
ptrdiff_t hmgeti(T*, TK key)
|
||||
ptrdiff_t shgeti(T*, char* key)
|
||||
ptrdiff_t hmgeti_ts(T*, TK key, ptrdiff_t tempvar)
|
||||
Returns the index in the hashmap which has the key 'key', or -1
|
||||
if the key is not present.
|
||||
|
||||
hmget
|
||||
hmget_ts
|
||||
shget
|
||||
TV hmget(T*, TK key)
|
||||
TV shget(T*, char* key)
|
||||
TV hmget_ts(T*, TK key, ptrdiff_t tempvar)
|
||||
Returns the value corresponding to 'key' in the hashmap.
|
||||
The structure must have a 'value' field
|
||||
|
||||
@ -209,6 +219,21 @@ DOCUMENTATION
|
||||
T shgets(T*, char* key)
|
||||
Returns the structure corresponding to 'key' in the hashmap.
|
||||
|
||||
hmgetp
|
||||
shgetp
|
||||
hmgetp_ts
|
||||
hmgetp_null
|
||||
shgetp_null
|
||||
T* hmgetp(T*, TK key)
|
||||
T* shgetp(T*, char* key)
|
||||
T* hmgetp_ts(T*, TK key, ptrdiff_t tempvar)
|
||||
T* hmgetp_null(T*, TK key)
|
||||
T* shgetp_null(T*, char *key)
|
||||
Returns a pointer to the structure corresponding to 'key' in
|
||||
the hashmap. Functions ending in "_null" return NULL if the key
|
||||
is not present in the hashmap; the others return a pointer to a
|
||||
structure holding the default value (but not the searched-for key).
|
||||
|
||||
hmdefault
|
||||
shdefault
|
||||
TV hmdefault(T*, TV value)
|
||||
@ -234,7 +259,7 @@ DOCUMENTATION
|
||||
shputs
|
||||
T hmputs(T*, T item)
|
||||
T shputs(T*, T item)
|
||||
Inserts a struct with T.key and T.value into the hashmap. If the struct is already
|
||||
Inserts a struct with T.key into the hashmap. If the struct is already
|
||||
present in the hashmap, updates it.
|
||||
|
||||
hmdel
|
||||
@ -263,12 +288,22 @@ DOCUMENTATION
|
||||
|
||||
NOTES
|
||||
|
||||
* These data structures are realloc'd when they grow, and the macro "functions"
|
||||
write to the provided pointer. This means: (a) the pointer must be an lvalue,
|
||||
and (b) the pointer to the data structure is not stable, and you must maintain
|
||||
it the same as you would a realloc'd pointer. For example, if you pass a pointer
|
||||
to a dynamic array to a function which updates it, the function must return
|
||||
back the new pointer to the caller. This is the price of trying to do this in C.
|
||||
* These data structures are realloc'd when they grow, and the macro
|
||||
"functions" write to the provided pointer. This means: (a) the pointer
|
||||
must be an lvalue, and (b) the pointer to the data structure is not
|
||||
stable, and you must maintain it the same as you would a realloc'd
|
||||
pointer. For example, if you pass a pointer to a dynamic array to a
|
||||
function which updates it, the function must return back the new
|
||||
pointer to the caller. This is the price of trying to do this in C.
|
||||
|
||||
* The following are the only functions that are thread-safe on a single data
|
||||
structure, i.e. can be run in multiple threads simultaneously on the same
|
||||
data structure
|
||||
hmlen shlen
|
||||
hmlenu shlenu
|
||||
hmget_ts shget_ts
|
||||
hmgeti_ts shgeti_ts
|
||||
hmgets_ts shgets_ts
|
||||
|
||||
* You iterate over the contents of a dynamic array and a hashmap in exactly
|
||||
the same way, using arrlen/hmlen/shlen:
|
||||
@ -298,7 +333,8 @@ NOTES - HASH MAP
|
||||
* For compilers other than GCC and clang (e.g. Visual Studio), for hmput/hmget/hmdel
|
||||
and variants, the key must be an lvalue (so the macro can take the address of it).
|
||||
Extensions are used that eliminate this requirement if you're using C99 and later
|
||||
in GCC or clang, or if you're using C++ in GCC.
|
||||
in GCC or clang, or if you're using C++ in GCC. But note that this can make your
|
||||
code less portable.
|
||||
|
||||
* To test for presence of a key in a hashmap, just do 'hmgeti(foo,key) >= 0'.
|
||||
|
||||
@ -368,9 +404,13 @@ CREDITS
|
||||
#define hmput stbds_hmput
|
||||
#define hmputs stbds_hmputs
|
||||
#define hmget stbds_hmget
|
||||
#define hmget_ts stbds_hmget_ts
|
||||
#define hmgets stbds_hmgets
|
||||
#define hmgetp stbds_hmgetp
|
||||
#define hmgetp_ts stbds_hmgetp_ts
|
||||
#define hmgetp_null stbds_hmgetp_null
|
||||
#define hmgeti stbds_hmgeti
|
||||
#define hmgeti_ts stbds_hmgeti_ts
|
||||
#define hmdel stbds_hmdel
|
||||
#define hmlen stbds_hmlen
|
||||
#define hmlenu stbds_hmlenu
|
||||
@ -379,11 +419,13 @@ CREDITS
|
||||
#define hmdefaults stbds_hmdefaults
|
||||
|
||||
#define shput stbds_shput
|
||||
#define shputi stbds_shputi
|
||||
#define shputs stbds_shputs
|
||||
#define shget stbds_shget
|
||||
#define shgeti stbds_shgeti
|
||||
#define shgets stbds_shgets
|
||||
#define shgetp stbds_shgetp
|
||||
#define shgeti stbds_shgeti
|
||||
#define shgetp_null stbds_shgetp_null
|
||||
#define shdel stbds_shdel
|
||||
#define shlen stbds_shlen
|
||||
#define shlenu stbds_shlenu
|
||||
@ -431,8 +473,9 @@ extern void stbds_unit_tests(void);
|
||||
//
|
||||
|
||||
extern void * stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap);
|
||||
extern void stbds_hmfree_func(void *p, size_t elemsize, size_t keyoff);
|
||||
extern void stbds_hmfree_func(void *p, size_t elemsize);
|
||||
extern void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode);
|
||||
extern void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode);
|
||||
extern void * stbds_hmput_default(void *a, size_t elemsize);
|
||||
extern void * stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode);
|
||||
extern void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode);
|
||||
@ -471,15 +514,15 @@ extern void * stbds_shmode_func(size_t elemsize, int mode);
|
||||
#define stbds_header(t) ((stbds_array_header *) (t) - 1)
|
||||
#define stbds_temp(t) stbds_header(t)->temp
|
||||
|
||||
#define stbds_arrsetcap(a,n) (stbds_arrgrow(a,0,n))
|
||||
#define stbds_arrsetlen(a,n) ((stbds_arrcap(a) < n ? stbds_arrsetcap(a,n),0 : 0), (a) ? stbds_header(a)->length = (n) : 0)
|
||||
#define stbds_arrsetcap(a,n) (stbds_arrgrow(a,0,n))
|
||||
#define stbds_arrsetlen(a,n) ((stbds_arrcap(a) < (size_t) (n) ? stbds_arrsetcap((a),(size_t)(n)),0 : 0), (a) ? stbds_header(a)->length = (size_t) (n) : 0)
|
||||
#define stbds_arrcap(a) ((a) ? stbds_header(a)->capacity : 0)
|
||||
#define stbds_arrlen(a) ((a) ? (ptrdiff_t) stbds_header(a)->length : 0)
|
||||
#define stbds_arrlenu(a) ((a) ? stbds_header(a)->length : 0)
|
||||
#define stbds_arrput(a,v) (stbds_arrmaybegrow(a,1), (a)[stbds_header(a)->length++] = (v))
|
||||
#define stbds_arrpush stbds_arrput // synonym
|
||||
#define stbds_arrpop(a) (stbds_header(a)->length--, (a)[stbds_header(a)->length])
|
||||
#define stbds_arraddn(a,n) (stbds_arrmaybegrow(a,n), stbds_header(a)->length += (n))
|
||||
#define stbds_arraddn(a,n) (stbds_arrmaybegrow(a,n), stbds_header(a)->length += (n), stbds_header(a)->length-(n))
|
||||
#define stbds_arrlast(a) ((a)[stbds_header(a)->length-1])
|
||||
#define stbds_arrfree(a) ((void) ((a) ? STBDS_FREE(NULL,stbds_header(a)) : (void)0), (a)=NULL)
|
||||
#define stbds_arrdel(a,i) stbds_arrdeln(a,i,1)
|
||||
@ -495,7 +538,7 @@ extern void * stbds_shmode_func(size_t elemsize, int mode);
|
||||
|
||||
#define stbds_hmput(t, k, v) \
|
||||
((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, 0), \
|
||||
(t)[stbds_temp((t)-1)].key = (k), \
|
||||
(t)[stbds_temp((t)-1)].key = (k), \
|
||||
(t)[stbds_temp((t)-1)].value = (v))
|
||||
|
||||
#define stbds_hmputs(t, s) \
|
||||
@ -506,9 +549,16 @@ extern void * stbds_shmode_func(size_t elemsize, int mode);
|
||||
((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_HM_BINARY), \
|
||||
stbds_temp((t)-1))
|
||||
|
||||
#define stbds_hmgeti_ts(t,k,temp) \
|
||||
((t) = stbds_hmget_key_ts_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, &(temp), STBDS_HM_BINARY), \
|
||||
(temp))
|
||||
|
||||
#define stbds_hmgetp(t, k) \
|
||||
((void) stbds_hmgeti(t,k), &(t)[stbds_temp((t)-1)])
|
||||
|
||||
#define stbds_hmgetp_ts(t, k, temp) \
|
||||
((void) stbds_hmgeti_ts(t,k,temp), &(t)[temp])
|
||||
|
||||
#define stbds_hmdel(t,k) \
|
||||
(((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_OFFSETOF((t),key), STBDS_HM_BINARY)),(t)?stbds_temp((t)-1):0)
|
||||
|
||||
@ -519,37 +569,56 @@ extern void * stbds_shmode_func(size_t elemsize, int mode);
|
||||
((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1] = (s))
|
||||
|
||||
#define stbds_hmfree(p) \
|
||||
((void) ((p) != NULL ? stbds_hmfree_func((p)-1,sizeof*(p),STBDS_OFFSETOF((p),key)),0 : 0),(p)=NULL)
|
||||
((void) ((p) != NULL ? stbds_hmfree_func((p)-1,sizeof*(p)),0 : 0),(p)=NULL)
|
||||
|
||||
#define stbds_hmgets(t, k) (*stbds_hmgetp(t,k))
|
||||
#define stbds_hmget(t, k) (stbds_hmgetp(t,k)->value)
|
||||
#define stbds_hmlen(t) ((t) ? (ptrdiff_t) stbds_header((t)-1)->length-1 : 0)
|
||||
#define stbds_hmlenu(t) ((t) ? stbds_header((t)-1)->length-1 : 0)
|
||||
#define stbds_hmgets(t, k) (*stbds_hmgetp(t,k))
|
||||
#define stbds_hmget(t, k) (stbds_hmgetp(t,k)->value)
|
||||
#define stbds_hmget_ts(t, k, temp) (stbds_hmgetp_ts(t,k,temp)->value)
|
||||
#define stbds_hmlen(t) ((t) ? (ptrdiff_t) stbds_header((t)-1)->length-1 : 0)
|
||||
#define stbds_hmlenu(t) ((t) ? stbds_header((t)-1)->length-1 : 0)
|
||||
#define stbds_hmgetp_null(t,k) (stbds_hmgeti(t,k) == -1 ? NULL : &(t)[stbds_temp(t)-1])
|
||||
|
||||
#define stbds_shput(t, k, v) \
|
||||
((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \
|
||||
(t)[stbds_temp((t)-1)].value = (v))
|
||||
|
||||
#define stbds_shputi(t, k, v) \
|
||||
((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \
|
||||
(t)[stbds_temp((t)-1)].value = (v), stbds_temp((t)-1))
|
||||
|
||||
#define stbds_shputs(t, s) \
|
||||
((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (s).key, sizeof (s).key, STBDS_HM_STRING), \
|
||||
(t)[stbds_temp((t)-1)] = (s))
|
||||
|
||||
#define stbds_pshput(t, p) \
|
||||
((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (p)->key, sizeof (p)->key, STBDS_HM_PTR_TO_STRING), \
|
||||
(t)[stbds_temp((t)-1)] = (p))
|
||||
|
||||
#define stbds_shgeti(t,k) \
|
||||
((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \
|
||||
stbds_temp((t)-1))
|
||||
|
||||
#define stbds_pshgeti(t,k) \
|
||||
((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (*(t))->key, STBDS_HM_PTR_TO_STRING), \
|
||||
stbds_temp((t)-1))
|
||||
|
||||
#define stbds_shgetp(t, k) \
|
||||
((void) stbds_shgeti(t,k), &(t)[stbds_temp((t)-1)])
|
||||
|
||||
#define stbds_pshget(t, k) \
|
||||
((void) stbds_pshgeti(t,k), (t)[stbds_temp((t)-1)])
|
||||
|
||||
#define stbds_shdel(t,k) \
|
||||
(((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_OFFSETOF((t),key), STBDS_HM_STRING)),(t)?stbds_temp((t)-1):0)
|
||||
#define stbds_pshdel(t,k) \
|
||||
(((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) (k), sizeof (*(t))->key, STBDS_OFFSETOF(*(t),key), STBDS_HM_PTR_TO_STRING)),(t)?stbds_temp((t)-1):0)
|
||||
|
||||
#define stbds_sh_new_arena(t) \
|
||||
((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_ARENA))
|
||||
#define stbds_sh_new_strdup(t) \
|
||||
((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_STRDUP))
|
||||
|
||||
#define stbds_shdefault(t, v) stbds_hmdefault(t,v)
|
||||
#define stbds_shdefault(t, v) stbds_hmdefault(t,v)
|
||||
#define stbds_shdefaults(t, s) stbds_hmdefaults(t,s)
|
||||
|
||||
#define stbds_shfree stbds_hmfree
|
||||
@ -557,6 +626,7 @@ extern void * stbds_shmode_func(size_t elemsize, int mode);
|
||||
|
||||
#define stbds_shgets(t, k) (*stbds_shgetp(t,k))
|
||||
#define stbds_shget(t, k) (stbds_shgetp(t,k)->value)
|
||||
#define stbds_shgetp_null(t,k) (stbds_shgeti(t,k) == -1 ? NULL : &(t)[stbds_temp(t)-1])
|
||||
#define stbds_shlen stbds_hmlen
|
||||
|
||||
typedef struct
|
||||
@ -581,12 +651,13 @@ struct stbds_string_arena
|
||||
unsigned char mode; // this isn't used by the string arena itself
|
||||
};
|
||||
|
||||
#define STBDS_HM_BINARY 0
|
||||
#define STBDS_HM_STRING 1
|
||||
#define STBDS_HM_BINARY 0
|
||||
#define STBDS_HM_STRING 1
|
||||
|
||||
enum
|
||||
{
|
||||
STBDS_SH_NONE,
|
||||
STBDS_SH_DEFAULT,
|
||||
STBDS_SH_STRDUP,
|
||||
STBDS_SH_ARENA
|
||||
};
|
||||
@ -600,6 +671,9 @@ template<class T> static T * stbds_arrgrowf_wrapper(T *a, size_t elemsize, size_
|
||||
template<class T> static T * stbds_hmget_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) {
|
||||
return (T*)stbds_hmget_key((void*)a, elemsize, key, keysize, mode);
|
||||
}
|
||||
template<class T> static T * stbds_hmget_key_ts_wrapper(T *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode) {
|
||||
return (T*)stbds_hmget_key((void*)a, elemsize, key, keysize, temp, mode);
|
||||
}
|
||||
template<class T> static T * stbds_hmput_default_wrapper(T *a, size_t elemsize) {
|
||||
return (T*)stbds_hmput_default((void *)a, elemsize);
|
||||
}
|
||||
@ -615,6 +689,7 @@ template<class T> static T * stbds_shmode_func_wrapper(T *, size_t elemsize, int
|
||||
#else
|
||||
#define stbds_arrgrowf_wrapper stbds_arrgrowf
|
||||
#define stbds_hmget_key_wrapper stbds_hmget_key
|
||||
#define stbds_hmget_key_ts_wrapper stbds_hmget_key_ts
|
||||
#define stbds_hmput_default_wrapper stbds_hmput_default
|
||||
#define stbds_hmput_key_wrapper stbds_hmput_key
|
||||
#define stbds_hmdel_key_wrapper stbds_hmdel_key
|
||||
@ -656,6 +731,9 @@ size_t stbds_rehash_items;
|
||||
// stbds_arr implementation
|
||||
//
|
||||
|
||||
//int *prev_allocs[65536];
|
||||
//int num_prev;
|
||||
|
||||
void *stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap)
|
||||
{
|
||||
void *b;
|
||||
@ -674,7 +752,11 @@ void *stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap)
|
||||
else if (min_cap < 4)
|
||||
min_cap = 4;
|
||||
|
||||
//if (num_prev < 65536) if (a) prev_allocs[num_prev++] = (int *) ((char *) a+1);
|
||||
//if (num_prev == 2201)
|
||||
// num_prev = num_prev;
|
||||
b = STBDS_REALLOC(NULL, (a) ? stbds_header(a) : 0, elemsize * min_cap + sizeof(stbds_array_header));
|
||||
//if (num_prev < 65536) prev_allocs[num_prev++] = (int *) (char *) b;
|
||||
b = (char *) b + sizeof(stbds_array_header);
|
||||
if (a == NULL) {
|
||||
stbds_header(b)->length = 0;
|
||||
@ -683,6 +765,7 @@ void *stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap)
|
||||
STBDS_STATS(++stbds_array_grow);
|
||||
}
|
||||
stbds_header(b)->capacity = min_cap;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
@ -925,6 +1008,11 @@ typedef int STBDS_SIPHASH_2_4_can_only_be_used_in_64_bit_builds[sizeof(size_t) =
|
||||
#define STBDS_SIPHASH_D_ROUNDS 1
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant, for do..while(0) and sizeof()==
|
||||
#endif
|
||||
|
||||
static size_t stbds_siphash_bytes(void *p, size_t len, size_t seed)
|
||||
{
|
||||
unsigned char *d = (unsigned char *) p;
|
||||
@ -982,6 +1070,7 @@ static size_t stbds_siphash_bytes(void *p, size_t len, size_t seed)
|
||||
v2 ^= 0xff;
|
||||
for (j=0; j < STBDS_SIPHASH_D_ROUNDS; ++j)
|
||||
STBDS_SIPROUND();
|
||||
|
||||
#ifdef STBDS_SIPHASH_2_4
|
||||
return v0^v1^v2^v3;
|
||||
#else
|
||||
@ -1071,8 +1160,12 @@ size_t stbds_hash_bytes(void *p, size_t len, size_t seed)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
static int stbds_is_key_equal(void *a, size_t elemsize, void *key, size_t keysize, int mode, size_t i)
|
||||
|
||||
static int stbds_is_key_equal(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode, size_t i)
|
||||
{
|
||||
if (mode >= STBDS_HM_STRING)
|
||||
return 0==strcmp((char *) key, * (char **) ((char *) a + elemsize*i));
|
||||
@ -1085,23 +1178,23 @@ static int stbds_is_key_equal(void *a, size_t elemsize, void *key, size_t keysiz
|
||||
|
||||
#define stbds_hash_table(a) ((stbds_hash_index *) stbds_header(a)->hash_table)
|
||||
|
||||
void stbds_hmfree_func(void *a, size_t elemsize, size_t keyoff)
|
||||
void stbds_hmfree_func(void *a, size_t elemsize)
|
||||
{
|
||||
if (a == NULL) return;
|
||||
if (stbds_hash_table(a) != NULL) {
|
||||
if (stbds_hash_table(a)->string.mode == STBDS_SH_STRDUP) {
|
||||
size_t i;
|
||||
// skip 0th element, which is default
|
||||
for (i=1; i < stbds_header(a)->length; ++i)
|
||||
STBDS_FREE(NULL, *(char**) ((char *) a + elemsize*i));
|
||||
}
|
||||
stbds_strreset(&stbds_hash_table(a)->string);
|
||||
}
|
||||
if (stbds_hash_table(a)->string.mode == STBDS_SH_STRDUP) {
|
||||
size_t i;
|
||||
// skip 0th element, which is default
|
||||
for (i=1; i < stbds_header(a)->length; ++i)
|
||||
STBDS_FREE(NULL, *(char**) ((char *) a + elemsize*i));
|
||||
}
|
||||
stbds_strreset(&stbds_hash_table(a)->string);
|
||||
}
|
||||
STBDS_FREE(NULL, stbds_header(a)->hash_table);
|
||||
STBDS_FREE(NULL, stbds_header(a));
|
||||
}
|
||||
|
||||
static ptrdiff_t stbds_hm_find_slot(void *a, size_t elemsize, void *key, size_t keysize, int mode)
|
||||
static ptrdiff_t stbds_hm_find_slot(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode)
|
||||
{
|
||||
void *raw_a = STBDS_HASH_TO_ARR(a,elemsize);
|
||||
stbds_hash_index *table = stbds_hash_table(raw_a);
|
||||
@ -1122,7 +1215,7 @@ static ptrdiff_t stbds_hm_find_slot(void *a, size_t elemsize, void *key, size_t
|
||||
// start searching from pos to end of bucket, this should help performance on small hash tables that fit in cache
|
||||
for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) {
|
||||
if (bucket->hash[i] == hash) {
|
||||
if (stbds_is_key_equal(a, elemsize, key, keysize, mode, bucket->index[i])) {
|
||||
if (stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) {
|
||||
return (pos & ~STBDS_BUCKET_MASK)+i;
|
||||
}
|
||||
} else if (bucket->hash[i] == STBDS_HASH_EMPTY) {
|
||||
@ -1134,7 +1227,7 @@ static ptrdiff_t stbds_hm_find_slot(void *a, size_t elemsize, void *key, size_t
|
||||
limit = pos & STBDS_BUCKET_MASK;
|
||||
for (i = 0; i < limit; ++i) {
|
||||
if (bucket->hash[i] == hash) {
|
||||
if (stbds_is_key_equal(a, elemsize, key, keysize, mode, bucket->index[i])) {
|
||||
if (stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) {
|
||||
return (pos & ~STBDS_BUCKET_MASK)+i;
|
||||
}
|
||||
} else if (bucket->hash[i] == STBDS_HASH_EMPTY) {
|
||||
@ -1148,17 +1241,17 @@ static ptrdiff_t stbds_hm_find_slot(void *a, size_t elemsize, void *key, size_t
|
||||
pos &= (table->slot_count-1);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return -1;
|
||||
}
|
||||
|
||||
void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode)
|
||||
void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode)
|
||||
{
|
||||
size_t keyoffset = 0;
|
||||
if (a == NULL) {
|
||||
// make it non-empty so we can return a temp
|
||||
a = stbds_arrgrowf(0, elemsize, 0, 1);
|
||||
stbds_header(a)->length += 1;
|
||||
memset(a, 0, elemsize);
|
||||
stbds_temp(a) = STBDS_INDEX_EMPTY;
|
||||
*temp = STBDS_INDEX_EMPTY;
|
||||
// adjust a to point after the default element
|
||||
return STBDS_ARR_TO_HASH(a,elemsize);
|
||||
} else {
|
||||
@ -1167,20 +1260,28 @@ void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int
|
||||
// adjust a to point to the default element
|
||||
table = (stbds_hash_index *) stbds_header(raw_a)->hash_table;
|
||||
if (table == 0) {
|
||||
stbds_temp(raw_a) = -1;
|
||||
*temp = -1;
|
||||
} else {
|
||||
ptrdiff_t slot = stbds_hm_find_slot(a, elemsize, key, keysize, mode);
|
||||
ptrdiff_t slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode);
|
||||
if (slot < 0) {
|
||||
stbds_temp(raw_a) = STBDS_INDEX_EMPTY;
|
||||
*temp = STBDS_INDEX_EMPTY;
|
||||
} else {
|
||||
stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT];
|
||||
stbds_temp(raw_a) = b->index[slot & STBDS_BUCKET_MASK];
|
||||
*temp = b->index[slot & STBDS_BUCKET_MASK];
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode)
|
||||
{
|
||||
ptrdiff_t temp;
|
||||
void *p = stbds_hmget_key_ts(a, elemsize, key, keysize, &temp, mode);
|
||||
stbds_temp(STBDS_HASH_TO_ARR(p,elemsize)) = temp;
|
||||
return p;
|
||||
}
|
||||
|
||||
void * stbds_hmput_default(void *a, size_t elemsize)
|
||||
{
|
||||
// three cases:
|
||||
@ -1200,6 +1301,7 @@ static char *stbds_strdup(char *str);
|
||||
|
||||
void *stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode)
|
||||
{
|
||||
size_t keyoffset=0;
|
||||
void *raw_a;
|
||||
stbds_hash_index *table;
|
||||
|
||||
@ -1223,9 +1325,10 @@ void *stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int m
|
||||
|
||||
slot_count = (table == NULL) ? STBDS_BUCKET_LENGTH : table->slot_count*2;
|
||||
nt = stbds_make_hash_index(slot_count, table);
|
||||
if (table) {
|
||||
if (table)
|
||||
STBDS_FREE(NULL, table);
|
||||
}
|
||||
else
|
||||
nt->string.mode = mode >= STBDS_HM_STRING ? STBDS_SH_DEFAULT : 0;
|
||||
stbds_header(a)->hash_table = table = nt;
|
||||
STBDS_STATS(++stbds_hash_grow);
|
||||
}
|
||||
@ -1251,7 +1354,7 @@ void *stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int m
|
||||
// start searching from pos to end of bucket
|
||||
for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) {
|
||||
if (bucket->hash[i] == hash) {
|
||||
if (stbds_is_key_equal(raw_a, elemsize, key, keysize, mode, bucket->index[i])) {
|
||||
if (stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) {
|
||||
stbds_temp(a) = bucket->index[i];
|
||||
return STBDS_ARR_TO_HASH(a,elemsize);
|
||||
}
|
||||
@ -1268,7 +1371,7 @@ void *stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int m
|
||||
limit = pos & STBDS_BUCKET_MASK;
|
||||
for (i = 0; i < limit; ++i) {
|
||||
if (bucket->hash[i] == hash) {
|
||||
if (stbds_is_key_equal(raw_a, elemsize, key, keysize, mode, bucket->index[i])) {
|
||||
if (stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) {
|
||||
stbds_temp(a) = bucket->index[i];
|
||||
return STBDS_ARR_TO_HASH(a,elemsize);
|
||||
}
|
||||
@ -1295,7 +1398,7 @@ void *stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int m
|
||||
|
||||
{
|
||||
ptrdiff_t i = (ptrdiff_t) stbds_arrlen(a);
|
||||
// we want to do stbds_arraddn(1), but we can't use the macros since we don't have something of the right type
|
||||
// we want to do stbds_arraddn(1), but we can't use the macros since we don't have something of the right type
|
||||
if ((size_t) i+1 > stbds_arrcap(a))
|
||||
*(void **) &a = stbds_arrgrowf(a, elemsize, 1, 0);
|
||||
raw_a = STBDS_ARR_TO_HASH(a,elemsize);
|
||||
@ -1308,9 +1411,10 @@ void *stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int m
|
||||
stbds_temp(a) = i-1;
|
||||
|
||||
switch (table->string.mode) {
|
||||
case STBDS_SH_STRDUP: *(char **) ((char *) a + elemsize*i) = stbds_strdup((char*) key); break;
|
||||
case STBDS_SH_ARENA: *(char **) ((char *) a + elemsize*i) = stbds_stralloc(&table->string, (char*)key); break;
|
||||
default: *(char **) ((char *) a + elemsize*i) = (char *) key; break;
|
||||
case STBDS_SH_STRDUP: *(char **) ((char *) a + elemsize*i) = stbds_strdup((char*) key); break;
|
||||
case STBDS_SH_ARENA: *(char **) ((char *) a + elemsize*i) = stbds_stralloc(&table->string, (char*)key); break;
|
||||
case STBDS_SH_DEFAULT: *(char **) ((char *) a + elemsize*i) = (char *) key; break;
|
||||
default: memcpy((char *) a + elemsize*i, key, keysize); break;
|
||||
}
|
||||
}
|
||||
return STBDS_ARR_TO_HASH(a,elemsize);
|
||||
@ -1324,7 +1428,7 @@ void * stbds_shmode_func(size_t elemsize, int mode)
|
||||
memset(a, 0, elemsize);
|
||||
stbds_header(a)->length = 1;
|
||||
stbds_header(a)->hash_table = h = (stbds_hash_index *) stbds_make_hash_index(STBDS_BUCKET_LENGTH, NULL);
|
||||
h->string.mode = mode;
|
||||
h->string.mode = (unsigned char) mode;
|
||||
return STBDS_ARR_TO_HASH(a,elemsize);
|
||||
}
|
||||
|
||||
@ -1341,7 +1445,7 @@ void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size
|
||||
return a;
|
||||
} else {
|
||||
ptrdiff_t slot;
|
||||
slot = stbds_hm_find_slot(a, elemsize, key, keysize, mode);
|
||||
slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode);
|
||||
if (slot < 0)
|
||||
return a;
|
||||
else {
|
||||
@ -1368,9 +1472,9 @@ void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size
|
||||
|
||||
// now find the slot for the last element
|
||||
if (mode == STBDS_HM_STRING)
|
||||
slot = stbds_hm_find_slot(a, elemsize, *(char**) ((char *) a+elemsize*old_index + keyoffset), keysize, mode);
|
||||
slot = stbds_hm_find_slot(a, elemsize, *(char**) ((char *) a+elemsize*old_index + keyoffset), keysize, keyoffset, mode);
|
||||
else
|
||||
slot = stbds_hm_find_slot(a, elemsize, (char* ) a+elemsize*old_index + keyoffset, keysize, mode);
|
||||
slot = stbds_hm_find_slot(a, elemsize, (char* ) a+elemsize*old_index + keyoffset, keysize, keyoffset, mode);
|
||||
STBDS_ASSERT(slot >= 0);
|
||||
b = &table->storage[slot >> STBDS_BUCKET_SHIFT];
|
||||
i = slot & STBDS_BUCKET_MASK;
|
||||
@ -1394,7 +1498,6 @@ void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size
|
||||
}
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *stbds_strdup(char *str)
|
||||
@ -1408,10 +1511,10 @@ static char *stbds_strdup(char *str)
|
||||
}
|
||||
|
||||
#ifndef STBDS_STRING_ARENA_BLOCKSIZE_MIN
|
||||
#define STBDS_STRING_ARENA_BLOCKSIZE_MIN 512
|
||||
#define STBDS_STRING_ARENA_BLOCKSIZE_MIN 512u
|
||||
#endif
|
||||
#ifndef STBDS_STRING_ARENA_BLOCKSIZE_MAX
|
||||
#define STBDS_STRING_ARENA_BLOCKSIZE_MAX 1<<20
|
||||
#define STBDS_STRING_ARENA_BLOCKSIZE_MAX (1u<<20)
|
||||
#endif
|
||||
|
||||
char *stbds_stralloc(stbds_string_arena *a, char *str)
|
||||
@ -1492,6 +1595,7 @@ void stbds_strreset(stbds_string_arena *a)
|
||||
#endif
|
||||
|
||||
typedef struct { int key,b,c,d; } stbds_struct;
|
||||
typedef struct { int key[2],b,c,d; } stbds_struct2;
|
||||
|
||||
static char buffer[256];
|
||||
char *strkey(int n)
|
||||
@ -1511,12 +1615,16 @@ void stbds_unit_tests(void)
|
||||
STBDS_ASSERT(0);
|
||||
#else
|
||||
const int testsize = 100000;
|
||||
const int testsize2 = testsize/20;
|
||||
int *arr=NULL;
|
||||
struct { int key; int value; } *intmap = NULL;
|
||||
struct { char *key; int value; } *strmap = NULL;
|
||||
struct { stbds_struct key; int value; } *map = NULL;
|
||||
stbds_struct *map2 = NULL;
|
||||
stbds_string_arena sa = { 0 };
|
||||
struct { int key; int value; } *intmap = NULL;
|
||||
struct { char *key; int value; } *strmap = NULL;
|
||||
struct { stbds_struct key; int value; } *map = NULL;
|
||||
stbds_struct *map2 = NULL;
|
||||
stbds_struct2 *map3 = NULL;
|
||||
stbds_string_arena sa = { 0 };
|
||||
int key3[2] = { 1,2 };
|
||||
ptrdiff_t temp;
|
||||
|
||||
int i,j;
|
||||
|
||||
@ -1552,9 +1660,12 @@ void stbds_unit_tests(void)
|
||||
STBDS_ASSERT(hmget (intmap, i) == -2);
|
||||
for (i=0; i < testsize; i+=2)
|
||||
hmput(intmap, i, i*5);
|
||||
for (i=0; i < testsize; i+=1)
|
||||
for (i=0; i < testsize; i+=1) {
|
||||
if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 );
|
||||
else STBDS_ASSERT(hmget(intmap, i) == i*5);
|
||||
if (i & 1) STBDS_ASSERT(hmget_ts(intmap, i, temp) == -2 );
|
||||
else STBDS_ASSERT(hmget_ts(intmap, i, temp) == i*5);
|
||||
}
|
||||
for (i=0; i < testsize; i+=2)
|
||||
hmput(intmap, i, i*3);
|
||||
for (i=0; i < testsize; i+=1)
|
||||
@ -1639,7 +1750,9 @@ void stbds_unit_tests(void)
|
||||
stbds_struct t = { i,i*2,i*3+1,i*4 };
|
||||
if (i & 1) STBDS_ASSERT(hmget(map, s) == 0);
|
||||
else STBDS_ASSERT(hmget(map, s) == i*5);
|
||||
STBDS_ASSERT(hmget(map, t) == 0);
|
||||
if (i & 1) STBDS_ASSERT(hmget_ts(map, s, temp) == 0);
|
||||
else STBDS_ASSERT(hmget_ts(map, s, temp) == i*5);
|
||||
//STBDS_ASSERT(hmget(map, t.key) == 0);
|
||||
}
|
||||
|
||||
for (i=0; i < testsize; i += 2) {
|
||||
@ -1653,9 +1766,21 @@ void stbds_unit_tests(void)
|
||||
stbds_struct t = { i,i*2,i*3+1,i*4 };
|
||||
if (i & 1) STBDS_ASSERT(hmgets(map2, s.key).d == 0);
|
||||
else STBDS_ASSERT(hmgets(map2, s.key).d == i*4);
|
||||
STBDS_ASSERT(hmget(map, t) == 0);
|
||||
//STBDS_ASSERT(hmgetp(map2, t.key) == 0);
|
||||
}
|
||||
hmfree(map2);
|
||||
|
||||
for (i=0; i < testsize; i += 2) {
|
||||
stbds_struct2 s = { { i,i*2 }, i*3,i*4, i*5 };
|
||||
hmputs(map3, s);
|
||||
}
|
||||
for (i=0; i < testsize; i += 1) {
|
||||
stbds_struct2 s = { { i,i*2}, i*3, i*4, i*5 };
|
||||
stbds_struct2 t = { { i,i*2}, i*3+1, i*4, i*5 };
|
||||
if (i & 1) STBDS_ASSERT(hmgets(map3, s.key).d == 0);
|
||||
else STBDS_ASSERT(hmgets(map3, s.key).d == i*5);
|
||||
//STBDS_ASSERT(hmgetp(map3, t.key) == 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user