diff --git a/stb_ds.h b/stb_ds.h index 7aa59a6..2001829 100644 --- a/stb_ds.h +++ b/stb_ds.h @@ -1,4 +1,5 @@ -/* stb_ds.h - v0.62 - public domain data structures - Sean Barrett 2019 +#include +/* 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 static T * stbds_arrgrowf_wrapper(T *a, size_t elemsize, size_ template 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 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 static T * stbds_hmput_default_wrapper(T *a, size_t elemsize) { return (T*)stbds_hmput_default((void *)a, elemsize); } @@ -615,6 +689,7 @@ template 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