└── stb_ds.h /stb_ds.h: -------------------------------------------------------------------------------- 1 | /* stb_ds.h - v0.67 - public domain data structures - Sean Barrett 2019 2 | 3 | This is a single-header-file library that provides easy-to-use 4 | dynamic arrays and hash tables for C (also works in C++). 5 | 6 | For a gentle introduction: 7 | http://nothings.org/stb_ds 8 | 9 | To use this library, do this in *one* C or C++ file: 10 | #define STB_DS_IMPLEMENTATION 11 | #include "stb_ds.h" 12 | 13 | TABLE OF CONTENTS 14 | 15 | Table of Contents 16 | Compile-time options 17 | License 18 | Documentation 19 | Notes 20 | Notes - Dynamic arrays 21 | Notes - Hash maps 22 | Credits 23 | 24 | COMPILE-TIME OPTIONS 25 | 26 | #define STBDS_NO_SHORT_NAMES 27 | 28 | This flag needs to be set globally. 29 | 30 | By default stb_ds exposes shorter function names that are not qualified 31 | with the "stbds_" prefix. If these names conflict with the names in your 32 | code, define this flag. 33 | 34 | #define STBDS_SIPHASH_2_4 35 | 36 | This flag only needs to be set in the file containing #define STB_DS_IMPLEMENTATION. 37 | 38 | By default stb_ds.h hashes using a weaker variant of SipHash and a custom hash for 39 | 4- and 8-byte keys. On 64-bit platforms, you can define the above flag to force 40 | stb_ds.h to use specification-compliant SipHash-2-4 for all keys. Doing so makes 41 | hash table insertion about 20% slower on 4- and 8-byte keys, 5% slower on 42 | 64-byte keys, and 10% slower on 256-byte keys on my test computer. 43 | 44 | #define STBDS_REALLOC(context,ptr,size) better_realloc 45 | #define STBDS_FREE(context,ptr) better_free 46 | 47 | These defines only need to be set in the file containing #define STB_DS_IMPLEMENTATION. 48 | 49 | By default stb_ds uses stdlib realloc() and free() for memory management. You can 50 | substitute your own functions instead by defining these symbols. You must either 51 | define both, or neither. Note that at the moment, 'context' will always be NULL. 52 | @TODO add an array/hash initialization function that takes a memory context pointer. 53 | 54 | #define STBDS_UNIT_TESTS 55 | 56 | Defines a function stbds_unit_tests() that checks the functioning of the data structures. 57 | 58 | Note that on older versions of gcc (e.g. 5.x.x) you may need to build with '-std=c++0x' 59 | (or equivalentally '-std=c++11') when using anonymous structures as seen on the web 60 | page or in STBDS_UNIT_TESTS. 61 | 62 | LICENSE 63 | 64 | Placed in the public domain and also MIT licensed. 65 | See end of file for detailed license information. 66 | 67 | DOCUMENTATION 68 | 69 | Dynamic Arrays 70 | 71 | Non-function interface: 72 | 73 | Declare an empty dynamic array of type T 74 | T* foo = NULL; 75 | 76 | Access the i'th item of a dynamic array 'foo' of type T, T* foo: 77 | foo[i] 78 | 79 | Functions (actually macros) 80 | 81 | arrfree: 82 | void arrfree(T*); 83 | Frees the array. 84 | 85 | arrlen: 86 | ptrdiff_t arrlen(T*); 87 | Returns the number of elements in the array. 88 | 89 | arrlenu: 90 | size_t arrlenu(T*); 91 | Returns the number of elements in the array as an unsigned type. 92 | 93 | arrpop: 94 | T arrpop(T* a) 95 | Removes the final element of the array and returns it. 96 | 97 | arrput: 98 | T arrput(T* a, T b); 99 | Appends the item b to the end of array a. Returns b. 100 | 101 | arrins: 102 | T arrins(T* a, int p, T b); 103 | Inserts the item b into the middle of array a, into a[p], 104 | moving the rest of the array over. Returns b. 105 | 106 | arrinsn: 107 | void arrinsn(T* a, int p, int n); 108 | Inserts n uninitialized items into array a starting at a[p], 109 | moving the rest of the array over. 110 | 111 | arraddnptr: 112 | T* arraddnptr(T* a, int n) 113 | Appends n uninitialized items onto array at the end. 114 | Returns a pointer to the first uninitialized item added. 115 | 116 | arraddnindex: 117 | size_t arraddnindex(T* a, int n) 118 | Appends n uninitialized items onto array at the end. 119 | Returns the index of the first uninitialized item added. 120 | 121 | arrdel: 122 | void arrdel(T* a, int p); 123 | Deletes the element at a[p], moving the rest of the array over. 124 | 125 | arrdeln: 126 | void arrdeln(T* a, int p, int n); 127 | Deletes n elements starting at a[p], moving the rest of the array over. 128 | 129 | arrdelswap: 130 | void arrdelswap(T* a, int p); 131 | Deletes the element at a[p], replacing it with the element from 132 | the end of the array. O(1) performance. 133 | 134 | arrsetlen: 135 | void arrsetlen(T* a, int n); 136 | Changes the length of the array to n. Allocates uninitialized 137 | slots at the end if necessary. 138 | 139 | arrsetcap: 140 | size_t arrsetcap(T* a, int n); 141 | Sets the length of allocated storage to at least n. It will not 142 | change the length of the array. 143 | 144 | arrcap: 145 | size_t arrcap(T* a); 146 | Returns the number of total elements the array can contain without 147 | needing to be reallocated. 148 | 149 | Hash maps & String hash maps 150 | 151 | Given T is a structure type: struct { TK key; TV value; }. Note that some 152 | functions do not require TV value and can have other fields. For string 153 | hash maps, TK must be 'char *'. 154 | 155 | Special interface: 156 | 157 | stbds_rand_seed: 158 | void stbds_rand_seed(size_t seed); 159 | For security against adversarially chosen data, you should seed the 160 | library with a strong random number. Or at least seed it with time(). 161 | 162 | stbds_hash_string: 163 | size_t stbds_hash_string(char *str, size_t seed); 164 | Returns a hash value for a string. 165 | 166 | stbds_hash_bytes: 167 | size_t stbds_hash_bytes(void *p, size_t len, size_t seed); 168 | These functions hash an arbitrary number of bytes. The function 169 | uses a custom hash for 4- and 8-byte data, and a weakened version 170 | of SipHash for everything else. On 64-bit platforms you can get 171 | specification-compliant SipHash-2-4 on all data by defining 172 | STBDS_SIPHASH_2_4, at a significant cost in speed. 173 | 174 | Non-function interface: 175 | 176 | Declare an empty hash map of type T 177 | T* foo = NULL; 178 | 179 | Access the i'th entry in a hash table T* foo: 180 | foo[i] 181 | 182 | Function interface (actually macros): 183 | 184 | hmfree 185 | shfree 186 | void hmfree(T*); 187 | void shfree(T*); 188 | Frees the hashmap and sets the pointer to NULL. 189 | 190 | hmlen 191 | shlen 192 | ptrdiff_t hmlen(T*) 193 | ptrdiff_t shlen(T*) 194 | Returns the number of elements in the hashmap. 195 | 196 | hmlenu 197 | shlenu 198 | size_t hmlenu(T*) 199 | size_t shlenu(T*) 200 | Returns the number of elements in the hashmap. 201 | 202 | hmgeti 203 | shgeti 204 | hmgeti_ts 205 | ptrdiff_t hmgeti(T*, TK key) 206 | ptrdiff_t shgeti(T*, char* key) 207 | ptrdiff_t hmgeti_ts(T*, TK key, ptrdiff_t tempvar) 208 | Returns the index in the hashmap which has the key 'key', or -1 209 | if the key is not present. 210 | 211 | hmget 212 | hmget_ts 213 | shget 214 | TV hmget(T*, TK key) 215 | TV shget(T*, char* key) 216 | TV hmget_ts(T*, TK key, ptrdiff_t tempvar) 217 | Returns the value corresponding to 'key' in the hashmap. 218 | The structure must have a 'value' field 219 | 220 | hmgets 221 | shgets 222 | T hmgets(T*, TK key) 223 | T shgets(T*, char* key) 224 | Returns the structure corresponding to 'key' in the hashmap. 225 | 226 | hmgetp 227 | shgetp 228 | hmgetp_ts 229 | hmgetp_null 230 | shgetp_null 231 | T* hmgetp(T*, TK key) 232 | T* shgetp(T*, char* key) 233 | T* hmgetp_ts(T*, TK key, ptrdiff_t tempvar) 234 | T* hmgetp_null(T*, TK key) 235 | T* shgetp_null(T*, char *key) 236 | Returns a pointer to the structure corresponding to 'key' in 237 | the hashmap. Functions ending in "_null" return NULL if the key 238 | is not present in the hashmap; the others return a pointer to a 239 | structure holding the default value (but not the searched-for key). 240 | 241 | hmdefault 242 | shdefault 243 | TV hmdefault(T*, TV value) 244 | TV shdefault(T*, TV value) 245 | Sets the default value for the hashmap, the value which will be 246 | returned by hmget/shget if the key is not present. 247 | 248 | hmdefaults 249 | shdefaults 250 | TV hmdefaults(T*, T item) 251 | TV shdefaults(T*, T item) 252 | Sets the default struct for the hashmap, the contents which will be 253 | returned by hmgets/shgets if the key is not present. 254 | 255 | hmput 256 | shput 257 | TV hmput(T*, TK key, TV value) 258 | TV shput(T*, char* key, TV value) 259 | Inserts a pair into the hashmap. If the key is already 260 | present in the hashmap, updates its value. 261 | 262 | hmputs 263 | shputs 264 | T hmputs(T*, T item) 265 | T shputs(T*, T item) 266 | Inserts a struct with T.key into the hashmap. If the struct is already 267 | present in the hashmap, updates it. 268 | 269 | hmdel 270 | shdel 271 | int hmdel(T*, TK key) 272 | int shdel(T*, char* key) 273 | If 'key' is in the hashmap, deletes its entry and returns 1. 274 | Otherwise returns 0. 275 | 276 | Function interface (actually macros) for strings only: 277 | 278 | sh_new_strdup 279 | void sh_new_strdup(T*); 280 | Overwrites the existing pointer with a newly allocated 281 | string hashmap which will automatically allocate and free 282 | each string key using realloc/free 283 | 284 | sh_new_arena 285 | void sh_new_arena(T*); 286 | Overwrites the existing pointer with a newly allocated 287 | string hashmap which will automatically allocate each string 288 | key to a string arena. Every string key ever used by this 289 | hash table remains in the arena until the arena is freed. 290 | Additionally, any key which is deleted and reinserted will 291 | be allocated multiple times in the string arena. 292 | 293 | NOTES 294 | 295 | * These data structures are realloc'd when they grow, and the macro 296 | "functions" write to the provided pointer. This means: (a) the pointer 297 | must be an lvalue, and (b) the pointer to the data structure is not 298 | stable, and you must maintain it the same as you would a realloc'd 299 | pointer. For example, if you pass a pointer to a dynamic array to a 300 | function which updates it, the function must return back the new 301 | pointer to the caller. This is the price of trying to do this in C. 302 | 303 | * The following are the only functions that are thread-safe on a single data 304 | structure, i.e. can be run in multiple threads simultaneously on the same 305 | data structure 306 | hmlen shlen 307 | hmlenu shlenu 308 | hmget_ts shget_ts 309 | hmgeti_ts shgeti_ts 310 | hmgets_ts shgets_ts 311 | 312 | * You iterate over the contents of a dynamic array and a hashmap in exactly 313 | the same way, using arrlen/hmlen/shlen: 314 | 315 | for (i=0; i < arrlen(foo); ++i) 316 | ... foo[i] ... 317 | 318 | * All operations except arrins/arrdel are O(1) amortized, but individual 319 | operations can be slow, so these data structures may not be suitable 320 | for real time use. Dynamic arrays double in capacity as needed, so 321 | elements are copied an average of once. Hash tables double/halve 322 | their size as needed, with appropriate hysteresis to maintain O(1) 323 | performance. 324 | 325 | NOTES - DYNAMIC ARRAY 326 | 327 | * If you know how long a dynamic array is going to be in advance, you can avoid 328 | extra memory allocations by using arrsetlen to allocate it to that length in 329 | advance and use foo[n] while filling it out, or arrsetcap to allocate the memory 330 | for that length and use arrput/arrpush as normal. 331 | 332 | * Unlike some other versions of the dynamic array, this version should 333 | be safe to use with strict-aliasing optimizations. 334 | 335 | NOTES - HASH MAP 336 | 337 | * For compilers other than GCC and clang (e.g. Visual Studio), for hmput/hmget/hmdel 338 | and variants, the key must be an lvalue (so the macro can take the address of it). 339 | Extensions are used that eliminate this requirement if you're using C99 and later 340 | in GCC or clang, or if you're using C++ in GCC. But note that this can make your 341 | code less portable. 342 | 343 | * To test for presence of a key in a hashmap, just do 'hmgeti(foo,key) >= 0'. 344 | 345 | * The iteration order of your data in the hashmap is determined solely by the 346 | order of insertions and deletions. In particular, if you never delete, new 347 | keys are always added at the end of the array. This will be consistent 348 | across all platforms and versions of the library. However, you should not 349 | attempt to serialize the internal hash table, as the hash is not consistent 350 | between different platforms, and may change with future versions of the library. 351 | 352 | * Use sh_new_arena() for string hashmaps that you never delete from. Initialize 353 | with NULL if you're managing the memory for your strings, or your strings are 354 | never freed (at least until the hashmap is freed). Otherwise, use sh_new_strdup(). 355 | @TODO: make an arena variant that garbage collects the strings with a trivial 356 | copy collector into a new arena whenever the table shrinks / rebuilds. Since 357 | current arena recommendation is to only use arena if it never deletes, then 358 | this can just replace current arena implementation. 359 | 360 | * If adversarial input is a serious concern and you're on a 64-bit platform, 361 | enable STBDS_SIPHASH_2_4 (see the 'Compile-time options' section), and pass 362 | a strong random number to stbds_rand_seed. 363 | 364 | * The default value for the hash table is stored in foo[-1], so if you 365 | use code like 'hmget(T,k)->value = 5' you can accidentally overwrite 366 | the value stored by hmdefault if 'k' is not present. 367 | 368 | CREDITS 369 | 370 | Sean Barrett -- library, idea for dynamic array API/implementation 371 | Per Vognsen -- idea for hash table API/implementation 372 | Rafael Sachetto -- arrpop() 373 | github:HeroicKatora -- arraddn() reworking 374 | 375 | Bugfixes: 376 | Andy Durdin 377 | Shane Liesegang 378 | Vinh Truong 379 | Andreas Molzer 380 | github:hashitaku 381 | github:srdjanstipic 382 | Macoy Madson 383 | Andreas Vennstrom 384 | Tobias Mansfield-Williams 385 | */ 386 | 387 | #ifdef STBDS_UNIT_TESTS 388 | #define _CRT_SECURE_NO_WARNINGS 389 | #endif 390 | 391 | #ifndef INCLUDE_STB_DS_H 392 | #define INCLUDE_STB_DS_H 393 | 394 | #include 395 | #include 396 | 397 | #ifndef STBDS_NO_SHORT_NAMES 398 | #define arrlen stbds_arrlen 399 | #define arrlenu stbds_arrlenu 400 | #define arrput stbds_arrput 401 | #define arrpush stbds_arrput 402 | #define arrpop stbds_arrpop 403 | #define arrfree stbds_arrfree 404 | #define arraddn stbds_arraddn // deprecated, use one of the following instead: 405 | #define arraddnptr stbds_arraddnptr 406 | #define arraddnindex stbds_arraddnindex 407 | #define arrsetlen stbds_arrsetlen 408 | #define arrlast stbds_arrlast 409 | #define arrins stbds_arrins 410 | #define arrinsn stbds_arrinsn 411 | #define arrdel stbds_arrdel 412 | #define arrdeln stbds_arrdeln 413 | #define arrdelswap stbds_arrdelswap 414 | #define arrcap stbds_arrcap 415 | #define arrsetcap stbds_arrsetcap 416 | 417 | #define hmput stbds_hmput 418 | #define hmputs stbds_hmputs 419 | #define hmget stbds_hmget 420 | #define hmget_ts stbds_hmget_ts 421 | #define hmgets stbds_hmgets 422 | #define hmgetp stbds_hmgetp 423 | #define hmgetp_ts stbds_hmgetp_ts 424 | #define hmgetp_null stbds_hmgetp_null 425 | #define hmgeti stbds_hmgeti 426 | #define hmgeti_ts stbds_hmgeti_ts 427 | #define hmdel stbds_hmdel 428 | #define hmlen stbds_hmlen 429 | #define hmlenu stbds_hmlenu 430 | #define hmfree stbds_hmfree 431 | #define hmdefault stbds_hmdefault 432 | #define hmdefaults stbds_hmdefaults 433 | 434 | #define shput stbds_shput 435 | #define shputi stbds_shputi 436 | #define shputs stbds_shputs 437 | #define shget stbds_shget 438 | #define shgeti stbds_shgeti 439 | #define shgets stbds_shgets 440 | #define shgetp stbds_shgetp 441 | #define shgetp_null stbds_shgetp_null 442 | #define shdel stbds_shdel 443 | #define shlen stbds_shlen 444 | #define shlenu stbds_shlenu 445 | #define shfree stbds_shfree 446 | #define shdefault stbds_shdefault 447 | #define shdefaults stbds_shdefaults 448 | #define sh_new_arena stbds_sh_new_arena 449 | #define sh_new_strdup stbds_sh_new_strdup 450 | 451 | #define stralloc stbds_stralloc 452 | #define strreset stbds_strreset 453 | #endif 454 | 455 | #if defined(STBDS_REALLOC) && !defined(STBDS_FREE) || !defined(STBDS_REALLOC) && defined(STBDS_FREE) 456 | #error "You must define both STBDS_REALLOC and STBDS_FREE, or neither." 457 | #endif 458 | #if !defined(STBDS_REALLOC) && !defined(STBDS_FREE) 459 | #include 460 | #define STBDS_REALLOC(c,p,s) realloc(p,s) 461 | #define STBDS_FREE(c,p) free(p) 462 | #endif 463 | 464 | #ifdef _MSC_VER 465 | #define STBDS_NOTUSED(v) (void)(v) 466 | #else 467 | #define STBDS_NOTUSED(v) (void)sizeof(v) 468 | #endif 469 | 470 | #ifdef __cplusplus 471 | extern "C" { 472 | #endif 473 | 474 | // for security against attackers, seed the library with a random number, at least time() but stronger is better 475 | extern void stbds_rand_seed(size_t seed); 476 | 477 | // these are the hash functions used internally if you want to test them or use them for other purposes 478 | extern size_t stbds_hash_bytes(void *p, size_t len, size_t seed); 479 | extern size_t stbds_hash_string(char *str, size_t seed); 480 | 481 | // this is a simple string arena allocator, initialize with e.g. 'stbds_string_arena my_arena={0}'. 482 | typedef struct stbds_string_arena stbds_string_arena; 483 | extern char * stbds_stralloc(stbds_string_arena *a, char *str); 484 | extern void stbds_strreset(stbds_string_arena *a); 485 | 486 | // have to #define STBDS_UNIT_TESTS to call this 487 | extern void stbds_unit_tests(void); 488 | 489 | /////////////// 490 | // 491 | // Everything below here is implementation details 492 | // 493 | 494 | extern void * stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap); 495 | extern void stbds_arrfreef(void *a); 496 | extern void stbds_hmfree_func(void *p, size_t elemsize); 497 | extern void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode); 498 | extern void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode); 499 | extern void * stbds_hmput_default(void *a, size_t elemsize); 500 | extern void * stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode); 501 | extern void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode); 502 | extern void * stbds_shmode_func(size_t elemsize, int mode); 503 | 504 | #ifdef __cplusplus 505 | } 506 | #endif 507 | 508 | #if defined(__GNUC__) || defined(__clang__) 509 | #define STBDS_HAS_TYPEOF 510 | #ifdef __cplusplus 511 | //#define STBDS_HAS_LITERAL_ARRAY // this is currently broken for clang 512 | #endif 513 | #endif 514 | 515 | #if !defined(__cplusplus) 516 | #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L 517 | #define STBDS_HAS_LITERAL_ARRAY 518 | #endif 519 | #endif 520 | 521 | // this macro takes the address of the argument, but on gcc/clang can accept rvalues 522 | #if defined(STBDS_HAS_LITERAL_ARRAY) && defined(STBDS_HAS_TYPEOF) 523 | #if __clang__ 524 | #define STBDS_ADDRESSOF(typevar, value) ((__typeof__(typevar)[1]){value}) // literal array decays to pointer to value 525 | #else 526 | #define STBDS_ADDRESSOF(typevar, value) ((typeof(typevar)[1]){value}) // literal array decays to pointer to value 527 | #endif 528 | #else 529 | #define STBDS_ADDRESSOF(typevar, value) &(value) 530 | #endif 531 | 532 | #define STBDS_OFFSETOF(var,field) ((char *) &(var)->field - (char *) (var)) 533 | 534 | #define stbds_header(t) ((stbds_array_header *) (t) - 1) 535 | #define stbds_temp(t) stbds_header(t)->temp 536 | #define stbds_temp_key(t) (*(char **) stbds_header(t)->hash_table) 537 | 538 | #define stbds_arrsetcap(a,n) (stbds_arrgrow(a,0,n)) 539 | #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) 540 | #define stbds_arrcap(a) ((a) ? stbds_header(a)->capacity : 0) 541 | #define stbds_arrlen(a) ((a) ? (ptrdiff_t) stbds_header(a)->length : 0) 542 | #define stbds_arrlenu(a) ((a) ? stbds_header(a)->length : 0) 543 | #define stbds_arrput(a,v) (stbds_arrmaybegrow(a,1), (a)[stbds_header(a)->length++] = (v)) 544 | #define stbds_arrpush stbds_arrput // synonym 545 | #define stbds_arrpop(a) (stbds_header(a)->length--, (a)[stbds_header(a)->length]) 546 | #define stbds_arraddn(a,n) ((void)(stbds_arraddnindex(a, n))) // deprecated, use one of the following instead: 547 | #define stbds_arraddnptr(a,n) (stbds_arrmaybegrow(a,n), (n) ? (stbds_header(a)->length += (n), &(a)[stbds_header(a)->length-(n)]) : (a)) 548 | #define stbds_arraddnindex(a,n)(stbds_arrmaybegrow(a,n), (n) ? (stbds_header(a)->length += (n), stbds_header(a)->length-(n)) : stbds_arrlen(a)) 549 | #define stbds_arraddnoff stbds_arraddnindex 550 | #define stbds_arrlast(a) ((a)[stbds_header(a)->length-1]) 551 | #define stbds_arrfree(a) ((void) ((a) ? STBDS_FREE(NULL,stbds_header(a)) : (void)0), (a)=NULL) 552 | #define stbds_arrdel(a,i) stbds_arrdeln(a,i,1) 553 | #define stbds_arrdeln(a,i,n) (memmove(&(a)[i], &(a)[(i)+(n)], sizeof *(a) * (stbds_header(a)->length-(n)-(i))), stbds_header(a)->length -= (n)) 554 | #define stbds_arrdelswap(a,i) ((a)[i] = stbds_arrlast(a), stbds_header(a)->length -= 1) 555 | #define stbds_arrinsn(a,i,n) (stbds_arraddn((a),(n)), memmove(&(a)[(i)+(n)], &(a)[i], sizeof *(a) * (stbds_header(a)->length-(n)-(i)))) 556 | #define stbds_arrins(a,i,v) (stbds_arrinsn((a),(i),1), (a)[i]=(v)) 557 | 558 | #define stbds_arrmaybegrow(a,n) ((!(a) || stbds_header(a)->length + (n) > stbds_header(a)->capacity) \ 559 | ? (stbds_arrgrow(a,n,0),0) : 0) 560 | 561 | #define stbds_arrgrow(a,b,c) ((a) = stbds_arrgrowf_wrapper((a), sizeof *(a), (b), (c))) 562 | 563 | #define stbds_hmput(t, k, v) \ 564 | ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, 0), \ 565 | (t)[stbds_temp((t)-1)].key = (k), \ 566 | (t)[stbds_temp((t)-1)].value = (v)) 567 | 568 | #define stbds_hmputs(t, s) \ 569 | ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), &(s).key, sizeof (s).key, STBDS_HM_BINARY), \ 570 | (t)[stbds_temp((t)-1)] = (s)) 571 | 572 | #define stbds_hmgeti(t,k) \ 573 | ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_HM_BINARY), \ 574 | stbds_temp((t)-1)) 575 | 576 | #define stbds_hmgeti_ts(t,k,temp) \ 577 | ((t) = stbds_hmget_key_ts_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, &(temp), STBDS_HM_BINARY), \ 578 | (temp)) 579 | 580 | #define stbds_hmgetp(t, k) \ 581 | ((void) stbds_hmgeti(t,k), &(t)[stbds_temp((t)-1)]) 582 | 583 | #define stbds_hmgetp_ts(t, k, temp) \ 584 | ((void) stbds_hmgeti_ts(t,k,temp), &(t)[temp]) 585 | 586 | #define stbds_hmdel(t,k) \ 587 | (((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) 588 | 589 | #define stbds_hmdefault(t, v) \ 590 | ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1].value = (v)) 591 | 592 | #define stbds_hmdefaults(t, s) \ 593 | ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1] = (s)) 594 | 595 | #define stbds_hmfree(p) \ 596 | ((void) ((p) != NULL ? stbds_hmfree_func((p)-1,sizeof*(p)),0 : 0),(p)=NULL) 597 | 598 | #define stbds_hmgets(t, k) (*stbds_hmgetp(t,k)) 599 | #define stbds_hmget(t, k) (stbds_hmgetp(t,k)->value) 600 | #define stbds_hmget_ts(t, k, temp) (stbds_hmgetp_ts(t,k,temp)->value) 601 | #define stbds_hmlen(t) ((t) ? (ptrdiff_t) stbds_header((t)-1)->length-1 : 0) 602 | #define stbds_hmlenu(t) ((t) ? stbds_header((t)-1)->length-1 : 0) 603 | #define stbds_hmgetp_null(t,k) (stbds_hmgeti(t,k) == -1 ? NULL : &(t)[stbds_temp((t)-1)]) 604 | 605 | #define stbds_shput(t, k, v) \ 606 | ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ 607 | (t)[stbds_temp((t)-1)].value = (v)) 608 | 609 | #define stbds_shputi(t, k, v) \ 610 | ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ 611 | (t)[stbds_temp((t)-1)].value = (v), stbds_temp((t)-1)) 612 | 613 | #define stbds_shputs(t, s) \ 614 | ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (s).key, sizeof (s).key, STBDS_HM_STRING), \ 615 | (t)[stbds_temp((t)-1)] = (s), \ 616 | (t)[stbds_temp((t)-1)].key = stbds_temp_key((t)-1)) // above line overwrites whole structure, so must rewrite key here if it was allocated internally 617 | 618 | #define stbds_pshput(t, p) \ 619 | ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (p)->key, sizeof (p)->key, STBDS_HM_PTR_TO_STRING), \ 620 | (t)[stbds_temp((t)-1)] = (p)) 621 | 622 | #define stbds_shgeti(t,k) \ 623 | ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ 624 | stbds_temp((t)-1)) 625 | 626 | #define stbds_pshgeti(t,k) \ 627 | ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (*(t))->key, STBDS_HM_PTR_TO_STRING), \ 628 | stbds_temp((t)-1)) 629 | 630 | #define stbds_shgetp(t, k) \ 631 | ((void) stbds_shgeti(t,k), &(t)[stbds_temp((t)-1)]) 632 | 633 | #define stbds_pshget(t, k) \ 634 | ((void) stbds_pshgeti(t,k), (t)[stbds_temp((t)-1)]) 635 | 636 | #define stbds_shdel(t,k) \ 637 | (((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) 638 | #define stbds_pshdel(t,k) \ 639 | (((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) 640 | 641 | #define stbds_sh_new_arena(t) \ 642 | ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_ARENA)) 643 | #define stbds_sh_new_strdup(t) \ 644 | ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_STRDUP)) 645 | 646 | #define stbds_shdefault(t, v) stbds_hmdefault(t,v) 647 | #define stbds_shdefaults(t, s) stbds_hmdefaults(t,s) 648 | 649 | #define stbds_shfree stbds_hmfree 650 | #define stbds_shlenu stbds_hmlenu 651 | 652 | #define stbds_shgets(t, k) (*stbds_shgetp(t,k)) 653 | #define stbds_shget(t, k) (stbds_shgetp(t,k)->value) 654 | #define stbds_shgetp_null(t,k) (stbds_shgeti(t,k) == -1 ? NULL : &(t)[stbds_temp((t)-1)]) 655 | #define stbds_shlen stbds_hmlen 656 | 657 | typedef struct 658 | { 659 | size_t length; 660 | size_t capacity; 661 | void * hash_table; 662 | ptrdiff_t temp; 663 | } stbds_array_header; 664 | 665 | typedef struct stbds_string_block 666 | { 667 | struct stbds_string_block *next; 668 | char storage[8]; 669 | } stbds_string_block; 670 | 671 | struct stbds_string_arena 672 | { 673 | stbds_string_block *storage; 674 | size_t remaining; 675 | unsigned char block; 676 | unsigned char mode; // this isn't used by the string arena itself 677 | }; 678 | 679 | #define STBDS_HM_BINARY 0 680 | #define STBDS_HM_STRING 1 681 | 682 | enum 683 | { 684 | STBDS_SH_NONE, 685 | STBDS_SH_DEFAULT, 686 | STBDS_SH_STRDUP, 687 | STBDS_SH_ARENA 688 | }; 689 | 690 | #ifdef __cplusplus 691 | // in C we use implicit assignment from these void*-returning functions to T*. 692 | // in C++ these templates make the same code work 693 | template static T * stbds_arrgrowf_wrapper(T *a, size_t elemsize, size_t addlen, size_t min_cap) { 694 | return (T*)stbds_arrgrowf((void *)a, elemsize, addlen, min_cap); 695 | } 696 | template static T * stbds_hmget_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) { 697 | return (T*)stbds_hmget_key((void*)a, elemsize, key, keysize, mode); 698 | } 699 | template static T * stbds_hmget_key_ts_wrapper(T *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode) { 700 | return (T*)stbds_hmget_key_ts((void*)a, elemsize, key, keysize, temp, mode); 701 | } 702 | template static T * stbds_hmput_default_wrapper(T *a, size_t elemsize) { 703 | return (T*)stbds_hmput_default((void *)a, elemsize); 704 | } 705 | template static T * stbds_hmput_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) { 706 | return (T*)stbds_hmput_key((void*)a, elemsize, key, keysize, mode); 707 | } 708 | template static T * stbds_hmdel_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode){ 709 | return (T*)stbds_hmdel_key((void*)a, elemsize, key, keysize, keyoffset, mode); 710 | } 711 | template static T * stbds_shmode_func_wrapper(T *, size_t elemsize, int mode) { 712 | return (T*)stbds_shmode_func(elemsize, mode); 713 | } 714 | #else 715 | #define stbds_arrgrowf_wrapper stbds_arrgrowf 716 | #define stbds_hmget_key_wrapper stbds_hmget_key 717 | #define stbds_hmget_key_ts_wrapper stbds_hmget_key_ts 718 | #define stbds_hmput_default_wrapper stbds_hmput_default 719 | #define stbds_hmput_key_wrapper stbds_hmput_key 720 | #define stbds_hmdel_key_wrapper stbds_hmdel_key 721 | #define stbds_shmode_func_wrapper(t,e,m) stbds_shmode_func(e,m) 722 | #endif 723 | 724 | #endif // INCLUDE_STB_DS_H 725 | 726 | 727 | ////////////////////////////////////////////////////////////////////////////// 728 | // 729 | // IMPLEMENTATION 730 | // 731 | 732 | #ifdef STB_DS_IMPLEMENTATION 733 | #include 734 | #include 735 | 736 | #ifndef STBDS_ASSERT 737 | #define STBDS_ASSERT_WAS_UNDEFINED 738 | #define STBDS_ASSERT(x) ((void) 0) 739 | #endif 740 | 741 | #ifdef STBDS_STATISTICS 742 | #define STBDS_STATS(x) x 743 | size_t stbds_array_grow; 744 | size_t stbds_hash_grow; 745 | size_t stbds_hash_shrink; 746 | size_t stbds_hash_rebuild; 747 | size_t stbds_hash_probes; 748 | size_t stbds_hash_alloc; 749 | size_t stbds_rehash_probes; 750 | size_t stbds_rehash_items; 751 | #else 752 | #define STBDS_STATS(x) 753 | #endif 754 | 755 | // 756 | // stbds_arr implementation 757 | // 758 | 759 | //int *prev_allocs[65536]; 760 | //int num_prev; 761 | 762 | void *stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap) 763 | { 764 | stbds_array_header temp={0}; // force debugging 765 | void *b; 766 | size_t min_len = stbds_arrlen(a) + addlen; 767 | (void) sizeof(temp); 768 | 769 | // compute the minimum capacity needed 770 | if (min_len > min_cap) 771 | min_cap = min_len; 772 | 773 | if (min_cap <= stbds_arrcap(a)) 774 | return a; 775 | 776 | // increase needed capacity to guarantee O(1) amortized 777 | if (min_cap < 2 * stbds_arrcap(a)) 778 | min_cap = 2 * stbds_arrcap(a); 779 | else if (min_cap < 4) 780 | min_cap = 4; 781 | 782 | //if (num_prev < 65536) if (a) prev_allocs[num_prev++] = (int *) ((char *) a+1); 783 | //if (num_prev == 2201) 784 | // num_prev = num_prev; 785 | b = STBDS_REALLOC(NULL, (a) ? stbds_header(a) : 0, elemsize * min_cap + sizeof(stbds_array_header)); 786 | //if (num_prev < 65536) prev_allocs[num_prev++] = (int *) (char *) b; 787 | b = (char *) b + sizeof(stbds_array_header); 788 | if (a == NULL) { 789 | stbds_header(b)->length = 0; 790 | stbds_header(b)->hash_table = 0; 791 | stbds_header(b)->temp = 0; 792 | } else { 793 | STBDS_STATS(++stbds_array_grow); 794 | } 795 | stbds_header(b)->capacity = min_cap; 796 | 797 | return b; 798 | } 799 | 800 | void stbds_arrfreef(void *a) 801 | { 802 | STBDS_FREE(NULL, stbds_header(a)); 803 | } 804 | 805 | // 806 | // stbds_hm hash table implementation 807 | // 808 | 809 | #ifdef STBDS_INTERNAL_SMALL_BUCKET 810 | #define STBDS_BUCKET_LENGTH 4 811 | #else 812 | #define STBDS_BUCKET_LENGTH 8 813 | #endif 814 | 815 | #define STBDS_BUCKET_SHIFT (STBDS_BUCKET_LENGTH == 8 ? 3 : 2) 816 | #define STBDS_BUCKET_MASK (STBDS_BUCKET_LENGTH-1) 817 | #define STBDS_CACHE_LINE_SIZE 64 818 | 819 | #define STBDS_ALIGN_FWD(n,a) (((n) + (a) - 1) & ~((a)-1)) 820 | 821 | typedef struct 822 | { 823 | size_t hash [STBDS_BUCKET_LENGTH]; 824 | ptrdiff_t index[STBDS_BUCKET_LENGTH]; 825 | } stbds_hash_bucket; // in 32-bit, this is one 64-byte cache line; in 64-bit, each array is one 64-byte cache line 826 | 827 | typedef struct 828 | { 829 | char * temp_key; // this MUST be the first field of the hash table 830 | size_t slot_count; 831 | size_t used_count; 832 | size_t used_count_threshold; 833 | size_t used_count_shrink_threshold; 834 | size_t tombstone_count; 835 | size_t tombstone_count_threshold; 836 | size_t seed; 837 | size_t slot_count_log2; 838 | stbds_string_arena string; 839 | stbds_hash_bucket *storage; // not a separate allocation, just 64-byte aligned storage after this struct 840 | } stbds_hash_index; 841 | 842 | #define STBDS_INDEX_EMPTY -1 843 | #define STBDS_INDEX_DELETED -2 844 | #define STBDS_INDEX_IN_USE(x) ((x) >= 0) 845 | 846 | #define STBDS_HASH_EMPTY 0 847 | #define STBDS_HASH_DELETED 1 848 | 849 | static size_t stbds_hash_seed=0x31415926; 850 | 851 | void stbds_rand_seed(size_t seed) 852 | { 853 | stbds_hash_seed = seed; 854 | } 855 | 856 | #define stbds_load_32_or_64(var, temp, v32, v64_hi, v64_lo) \ 857 | temp = v64_lo ^ v32, temp <<= 16, temp <<= 16, temp >>= 16, temp >>= 16, /* discard if 32-bit */ \ 858 | var = v64_hi, var <<= 16, var <<= 16, /* discard if 32-bit */ \ 859 | var ^= temp ^ v32 860 | 861 | #define STBDS_SIZE_T_BITS ((sizeof (size_t)) * 8) 862 | 863 | static size_t stbds_probe_position(size_t hash, size_t slot_count, size_t slot_log2) 864 | { 865 | size_t pos; 866 | STBDS_NOTUSED(slot_log2); 867 | pos = hash & (slot_count-1); 868 | #ifdef STBDS_INTERNAL_BUCKET_START 869 | pos &= ~STBDS_BUCKET_MASK; 870 | #endif 871 | return pos; 872 | } 873 | 874 | static size_t stbds_log2(size_t slot_count) 875 | { 876 | size_t n=0; 877 | while (slot_count > 1) { 878 | slot_count >>= 1; 879 | ++n; 880 | } 881 | return n; 882 | } 883 | 884 | static stbds_hash_index *stbds_make_hash_index(size_t slot_count, stbds_hash_index *ot) 885 | { 886 | stbds_hash_index *t; 887 | t = (stbds_hash_index *) STBDS_REALLOC(NULL,0,(slot_count >> STBDS_BUCKET_SHIFT) * sizeof(stbds_hash_bucket) + sizeof(stbds_hash_index) + STBDS_CACHE_LINE_SIZE-1); 888 | t->storage = (stbds_hash_bucket *) STBDS_ALIGN_FWD((size_t) (t+1), STBDS_CACHE_LINE_SIZE); 889 | t->slot_count = slot_count; 890 | t->slot_count_log2 = stbds_log2(slot_count); 891 | t->tombstone_count = 0; 892 | t->used_count = 0; 893 | 894 | #if 0 // A1 895 | t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow 896 | t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild 897 | t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink 898 | #elif 1 // A2 899 | //t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow 900 | //t->tombstone_count_threshold = slot_count* 3/16; // if tombstones are 3/16th of table, rebuild 901 | //t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink 902 | 903 | // compute without overflowing 904 | t->used_count_threshold = slot_count - (slot_count>>2); 905 | t->tombstone_count_threshold = (slot_count>>3) + (slot_count>>4); 906 | t->used_count_shrink_threshold = slot_count >> 2; 907 | 908 | #elif 0 // B1 909 | t->used_count_threshold = slot_count*13/16; // if 13/16th of table is occupied, grow 910 | t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild 911 | t->used_count_shrink_threshold = slot_count* 5/16; // if table is only 5/16th full, shrink 912 | #else // C1 913 | t->used_count_threshold = slot_count*14/16; // if 14/16th of table is occupied, grow 914 | t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild 915 | t->used_count_shrink_threshold = slot_count* 6/16; // if table is only 6/16th full, shrink 916 | #endif 917 | // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 918 | // Note that the larger tables have high variance as they were run fewer times 919 | // A1 A2 B1 C1 920 | // 0.10ms : 0.10ms : 0.10ms : 0.11ms : 2,000 inserts creating 2K table 921 | // 0.96ms : 0.95ms : 0.97ms : 1.04ms : 20,000 inserts creating 20K table 922 | // 14.48ms : 14.46ms : 10.63ms : 11.00ms : 200,000 inserts creating 200K table 923 | // 195.74ms : 196.35ms : 203.69ms : 214.92ms : 2,000,000 inserts creating 2M table 924 | // 2193.88ms : 2209.22ms : 2285.54ms : 2437.17ms : 20,000,000 inserts creating 20M table 925 | // 65.27ms : 53.77ms : 65.33ms : 65.47ms : 500,000 inserts & deletes in 2K table 926 | // 72.78ms : 62.45ms : 71.95ms : 72.85ms : 500,000 inserts & deletes in 20K table 927 | // 89.47ms : 77.72ms : 96.49ms : 96.75ms : 500,000 inserts & deletes in 200K table 928 | // 97.58ms : 98.14ms : 97.18ms : 97.53ms : 500,000 inserts & deletes in 2M table 929 | // 118.61ms : 119.62ms : 120.16ms : 118.86ms : 500,000 inserts & deletes in 20M table 930 | // 192.11ms : 194.39ms : 196.38ms : 195.73ms : 500,000 inserts & deletes in 200M table 931 | 932 | if (slot_count <= STBDS_BUCKET_LENGTH) 933 | t->used_count_shrink_threshold = 0; 934 | // to avoid infinite loop, we need to guarantee that at least one slot is empty and will terminate probes 935 | STBDS_ASSERT(t->used_count_threshold + t->tombstone_count_threshold < t->slot_count); 936 | STBDS_STATS(++stbds_hash_alloc); 937 | if (ot) { 938 | t->string = ot->string; 939 | // reuse old seed so we can reuse old hashes so below "copy out old data" doesn't do any hashing 940 | t->seed = ot->seed; 941 | } else { 942 | size_t a,b,temp; 943 | memset(&t->string, 0, sizeof(t->string)); 944 | t->seed = stbds_hash_seed; 945 | // LCG 946 | // in 32-bit, a = 2147001325 b = 715136305 947 | // in 64-bit, a = 2862933555777941757 b = 3037000493 948 | stbds_load_32_or_64(a,temp, 2147001325, 0x27bb2ee6, 0x87b0b0fd); 949 | stbds_load_32_or_64(b,temp, 715136305, 0, 0xb504f32d); 950 | stbds_hash_seed = stbds_hash_seed * a + b; 951 | } 952 | 953 | { 954 | size_t i,j; 955 | for (i=0; i < slot_count >> STBDS_BUCKET_SHIFT; ++i) { 956 | stbds_hash_bucket *b = &t->storage[i]; 957 | for (j=0; j < STBDS_BUCKET_LENGTH; ++j) 958 | b->hash[j] = STBDS_HASH_EMPTY; 959 | for (j=0; j < STBDS_BUCKET_LENGTH; ++j) 960 | b->index[j] = STBDS_INDEX_EMPTY; 961 | } 962 | } 963 | 964 | // copy out the old data, if any 965 | if (ot) { 966 | size_t i,j; 967 | t->used_count = ot->used_count; 968 | for (i=0; i < ot->slot_count >> STBDS_BUCKET_SHIFT; ++i) { 969 | stbds_hash_bucket *ob = &ot->storage[i]; 970 | for (j=0; j < STBDS_BUCKET_LENGTH; ++j) { 971 | if (STBDS_INDEX_IN_USE(ob->index[j])) { 972 | size_t hash = ob->hash[j]; 973 | size_t pos = stbds_probe_position(hash, t->slot_count, t->slot_count_log2); 974 | size_t step = STBDS_BUCKET_LENGTH; 975 | STBDS_STATS(++stbds_rehash_items); 976 | for (;;) { 977 | size_t limit,z; 978 | stbds_hash_bucket *bucket; 979 | bucket = &t->storage[pos >> STBDS_BUCKET_SHIFT]; 980 | STBDS_STATS(++stbds_rehash_probes); 981 | 982 | for (z=pos & STBDS_BUCKET_MASK; z < STBDS_BUCKET_LENGTH; ++z) { 983 | if (bucket->hash[z] == 0) { 984 | bucket->hash[z] = hash; 985 | bucket->index[z] = ob->index[j]; 986 | goto done; 987 | } 988 | } 989 | 990 | limit = pos & STBDS_BUCKET_MASK; 991 | for (z = 0; z < limit; ++z) { 992 | if (bucket->hash[z] == 0) { 993 | bucket->hash[z] = hash; 994 | bucket->index[z] = ob->index[j]; 995 | goto done; 996 | } 997 | } 998 | 999 | pos += step; // quadratic probing 1000 | step += STBDS_BUCKET_LENGTH; 1001 | pos &= (t->slot_count-1); 1002 | } 1003 | } 1004 | done: 1005 | ; 1006 | } 1007 | } 1008 | } 1009 | 1010 | return t; 1011 | } 1012 | 1013 | #define STBDS_ROTATE_LEFT(val, n) (((val) << (n)) | ((val) >> (STBDS_SIZE_T_BITS - (n)))) 1014 | #define STBDS_ROTATE_RIGHT(val, n) (((val) >> (n)) | ((val) << (STBDS_SIZE_T_BITS - (n)))) 1015 | 1016 | size_t stbds_hash_string(char *str, size_t seed) 1017 | { 1018 | size_t hash = seed; 1019 | while (*str) 1020 | hash = STBDS_ROTATE_LEFT(hash, 9) + (unsigned char) *str++; 1021 | 1022 | // Thomas Wang 64-to-32 bit mix function, hopefully also works in 32 bits 1023 | hash ^= seed; 1024 | hash = (~hash) + (hash << 18); 1025 | hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,31); 1026 | hash = hash * 21; 1027 | hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,11); 1028 | hash += (hash << 6); 1029 | hash ^= STBDS_ROTATE_RIGHT(hash,22); 1030 | return hash+seed; 1031 | } 1032 | 1033 | #ifdef STBDS_SIPHASH_2_4 1034 | #define STBDS_SIPHASH_C_ROUNDS 2 1035 | #define STBDS_SIPHASH_D_ROUNDS 4 1036 | typedef int STBDS_SIPHASH_2_4_can_only_be_used_in_64_bit_builds[sizeof(size_t) == 8 ? 1 : -1]; 1037 | #endif 1038 | 1039 | #ifndef STBDS_SIPHASH_C_ROUNDS 1040 | #define STBDS_SIPHASH_C_ROUNDS 1 1041 | #endif 1042 | #ifndef STBDS_SIPHASH_D_ROUNDS 1043 | #define STBDS_SIPHASH_D_ROUNDS 1 1044 | #endif 1045 | 1046 | #ifdef _MSC_VER 1047 | #pragma warning(push) 1048 | #pragma warning(disable:4127) // conditional expression is constant, for do..while(0) and sizeof()== 1049 | #endif 1050 | 1051 | static size_t stbds_siphash_bytes(void *p, size_t len, size_t seed) 1052 | { 1053 | unsigned char *d = (unsigned char *) p; 1054 | size_t i,j; 1055 | size_t v0,v1,v2,v3, data; 1056 | 1057 | // hash that works on 32- or 64-bit registers without knowing which we have 1058 | // (computes different results on 32-bit and 64-bit platform) 1059 | // derived from siphash, but on 32-bit platforms very different as it uses 4 32-bit state not 4 64-bit 1060 | v0 = ((((size_t) 0x736f6d65 << 16) << 16) + 0x70736575) ^ seed; 1061 | v1 = ((((size_t) 0x646f7261 << 16) << 16) + 0x6e646f6d) ^ ~seed; 1062 | v2 = ((((size_t) 0x6c796765 << 16) << 16) + 0x6e657261) ^ seed; 1063 | v3 = ((((size_t) 0x74656462 << 16) << 16) + 0x79746573) ^ ~seed; 1064 | 1065 | #ifdef STBDS_TEST_SIPHASH_2_4 1066 | // hardcoded with key material in the siphash test vectors 1067 | v0 ^= 0x0706050403020100ull ^ seed; 1068 | v1 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; 1069 | v2 ^= 0x0706050403020100ull ^ seed; 1070 | v3 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; 1071 | #endif 1072 | 1073 | #define STBDS_SIPROUND() \ 1074 | do { \ 1075 | v0 += v1; v1 = STBDS_ROTATE_LEFT(v1, 13); v1 ^= v0; v0 = STBDS_ROTATE_LEFT(v0,STBDS_SIZE_T_BITS/2); \ 1076 | v2 += v3; v3 = STBDS_ROTATE_LEFT(v3, 16); v3 ^= v2; \ 1077 | v2 += v1; v1 = STBDS_ROTATE_LEFT(v1, 17); v1 ^= v2; v2 = STBDS_ROTATE_LEFT(v2,STBDS_SIZE_T_BITS/2); \ 1078 | v0 += v3; v3 = STBDS_ROTATE_LEFT(v3, 21); v3 ^= v0; \ 1079 | } while (0) 1080 | 1081 | for (i=0; i+sizeof(size_t) <= len; i += sizeof(size_t), d += sizeof(size_t)) { 1082 | data = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); 1083 | data |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // discarded if size_t == 4 1084 | 1085 | v3 ^= data; 1086 | for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) 1087 | STBDS_SIPROUND(); 1088 | v0 ^= data; 1089 | } 1090 | data = len << (STBDS_SIZE_T_BITS-8); 1091 | switch (len - i) { 1092 | case 7: data |= ((size_t) d[6] << 24) << 24; // fall through 1093 | case 6: data |= ((size_t) d[5] << 20) << 20; // fall through 1094 | case 5: data |= ((size_t) d[4] << 16) << 16; // fall through 1095 | case 4: data |= (d[3] << 24); // fall through 1096 | case 3: data |= (d[2] << 16); // fall through 1097 | case 2: data |= (d[1] << 8); // fall through 1098 | case 1: data |= d[0]; // fall through 1099 | case 0: break; 1100 | } 1101 | v3 ^= data; 1102 | for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) 1103 | STBDS_SIPROUND(); 1104 | v0 ^= data; 1105 | v2 ^= 0xff; 1106 | for (j=0; j < STBDS_SIPHASH_D_ROUNDS; ++j) 1107 | STBDS_SIPROUND(); 1108 | 1109 | #ifdef STBDS_SIPHASH_2_4 1110 | return v0^v1^v2^v3; 1111 | #else 1112 | return v1^v2^v3; // slightly stronger since v0^v3 in above cancels out final round operation? I tweeted at the authors of SipHash about this but they didn't reply 1113 | #endif 1114 | } 1115 | 1116 | size_t stbds_hash_bytes(void *p, size_t len, size_t seed) 1117 | { 1118 | #ifdef STBDS_SIPHASH_2_4 1119 | return stbds_siphash_bytes(p,len,seed); 1120 | #else 1121 | unsigned char *d = (unsigned char *) p; 1122 | 1123 | if (len == 4) { 1124 | unsigned int hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); 1125 | #if 0 1126 | // HASH32-A Bob Jenkin's hash function w/o large constants 1127 | hash ^= seed; 1128 | hash -= (hash<<6); 1129 | hash ^= (hash>>17); 1130 | hash -= (hash<<9); 1131 | hash ^= seed; 1132 | hash ^= (hash<<4); 1133 | hash -= (hash<<3); 1134 | hash ^= (hash<<10); 1135 | hash ^= (hash>>15); 1136 | #elif 1 1137 | // HASH32-BB Bob Jenkin's presumably-accidental version of Thomas Wang hash with rotates turned into shifts. 1138 | // Note that converting these back to rotates makes it run a lot slower, presumably due to collisions, so I'm 1139 | // not really sure what's going on. 1140 | hash ^= seed; 1141 | hash = (hash ^ 61) ^ (hash >> 16); 1142 | hash = hash + (hash << 3); 1143 | hash = hash ^ (hash >> 4); 1144 | hash = hash * 0x27d4eb2d; 1145 | hash ^= seed; 1146 | hash = hash ^ (hash >> 15); 1147 | #else // HASH32-C - Murmur3 1148 | hash ^= seed; 1149 | hash *= 0xcc9e2d51; 1150 | hash = (hash << 17) | (hash >> 15); 1151 | hash *= 0x1b873593; 1152 | hash ^= seed; 1153 | hash = (hash << 19) | (hash >> 13); 1154 | hash = hash*5 + 0xe6546b64; 1155 | hash ^= hash >> 16; 1156 | hash *= 0x85ebca6b; 1157 | hash ^= seed; 1158 | hash ^= hash >> 13; 1159 | hash *= 0xc2b2ae35; 1160 | hash ^= hash >> 16; 1161 | #endif 1162 | // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 1163 | // Note that the larger tables have high variance as they were run fewer times 1164 | // HASH32-A // HASH32-BB // HASH32-C 1165 | // 0.10ms // 0.10ms // 0.10ms : 2,000 inserts creating 2K table 1166 | // 0.96ms // 0.95ms // 0.99ms : 20,000 inserts creating 20K table 1167 | // 14.69ms // 14.43ms // 14.97ms : 200,000 inserts creating 200K table 1168 | // 199.99ms // 195.36ms // 202.05ms : 2,000,000 inserts creating 2M table 1169 | // 2234.84ms // 2187.74ms // 2240.38ms : 20,000,000 inserts creating 20M table 1170 | // 55.68ms // 53.72ms // 57.31ms : 500,000 inserts & deletes in 2K table 1171 | // 63.43ms // 61.99ms // 65.73ms : 500,000 inserts & deletes in 20K table 1172 | // 80.04ms // 77.96ms // 81.83ms : 500,000 inserts & deletes in 200K table 1173 | // 100.42ms // 97.40ms // 102.39ms : 500,000 inserts & deletes in 2M table 1174 | // 119.71ms // 120.59ms // 121.63ms : 500,000 inserts & deletes in 20M table 1175 | // 185.28ms // 195.15ms // 187.74ms : 500,000 inserts & deletes in 200M table 1176 | // 15.58ms // 14.79ms // 15.52ms : 200,000 inserts creating 200K table with varying key spacing 1177 | 1178 | return (((size_t) hash << 16 << 16) | hash) ^ seed; 1179 | } else if (len == 8 && sizeof(size_t) == 8) { 1180 | size_t hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); 1181 | hash |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // avoid warning if size_t == 4 1182 | hash ^= seed; 1183 | hash = (~hash) + (hash << 21); 1184 | hash ^= STBDS_ROTATE_RIGHT(hash,24); 1185 | hash *= 265; 1186 | hash ^= STBDS_ROTATE_RIGHT(hash,14); 1187 | hash ^= seed; 1188 | hash *= 21; 1189 | hash ^= STBDS_ROTATE_RIGHT(hash,28); 1190 | hash += (hash << 31); 1191 | hash = (~hash) + (hash << 18); 1192 | return hash; 1193 | } else { 1194 | return stbds_siphash_bytes(p,len,seed); 1195 | } 1196 | #endif 1197 | } 1198 | #ifdef _MSC_VER 1199 | #pragma warning(pop) 1200 | #endif 1201 | 1202 | 1203 | static int stbds_is_key_equal(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode, size_t i) 1204 | { 1205 | if (mode >= STBDS_HM_STRING) 1206 | return 0==strcmp((char *) key, * (char **) ((char *) a + elemsize*i + keyoffset)); 1207 | else 1208 | return 0==memcmp(key, (char *) a + elemsize*i + keyoffset, keysize); 1209 | } 1210 | 1211 | #define STBDS_HASH_TO_ARR(x,elemsize) ((char*) (x) - (elemsize)) 1212 | #define STBDS_ARR_TO_HASH(x,elemsize) ((char*) (x) + (elemsize)) 1213 | 1214 | #define stbds_hash_table(a) ((stbds_hash_index *) stbds_header(a)->hash_table) 1215 | 1216 | void stbds_hmfree_func(void *a, size_t elemsize) 1217 | { 1218 | if (a == NULL) return; 1219 | if (stbds_hash_table(a) != NULL) { 1220 | if (stbds_hash_table(a)->string.mode == STBDS_SH_STRDUP) { 1221 | size_t i; 1222 | // skip 0th element, which is default 1223 | for (i=1; i < stbds_header(a)->length; ++i) 1224 | STBDS_FREE(NULL, *(char**) ((char *) a + elemsize*i)); 1225 | } 1226 | stbds_strreset(&stbds_hash_table(a)->string); 1227 | } 1228 | STBDS_FREE(NULL, stbds_header(a)->hash_table); 1229 | STBDS_FREE(NULL, stbds_header(a)); 1230 | } 1231 | 1232 | static ptrdiff_t stbds_hm_find_slot(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode) 1233 | { 1234 | void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); 1235 | stbds_hash_index *table = stbds_hash_table(raw_a); 1236 | size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); 1237 | size_t step = STBDS_BUCKET_LENGTH; 1238 | size_t limit,i; 1239 | size_t pos; 1240 | stbds_hash_bucket *bucket; 1241 | 1242 | if (hash < 2) hash += 2; // stored hash values are forbidden from being 0, so we can detect empty slots 1243 | 1244 | pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); 1245 | 1246 | for (;;) { 1247 | STBDS_STATS(++stbds_hash_probes); 1248 | bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; 1249 | 1250 | // start searching from pos to end of bucket, this should help performance on small hash tables that fit in cache 1251 | for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { 1252 | if (bucket->hash[i] == hash) { 1253 | if (stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { 1254 | return (pos & ~STBDS_BUCKET_MASK)+i; 1255 | } 1256 | } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { 1257 | return -1; 1258 | } 1259 | } 1260 | 1261 | // search from beginning of bucket to pos 1262 | limit = pos & STBDS_BUCKET_MASK; 1263 | for (i = 0; i < limit; ++i) { 1264 | if (bucket->hash[i] == hash) { 1265 | if (stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { 1266 | return (pos & ~STBDS_BUCKET_MASK)+i; 1267 | } 1268 | } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { 1269 | return -1; 1270 | } 1271 | } 1272 | 1273 | // quadratic probing 1274 | pos += step; 1275 | step += STBDS_BUCKET_LENGTH; 1276 | pos &= (table->slot_count-1); 1277 | } 1278 | /* NOTREACHED */ 1279 | } 1280 | 1281 | void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode) 1282 | { 1283 | size_t keyoffset = 0; 1284 | if (a == NULL) { 1285 | // make it non-empty so we can return a temp 1286 | a = stbds_arrgrowf(0, elemsize, 0, 1); 1287 | stbds_header(a)->length += 1; 1288 | memset(a, 0, elemsize); 1289 | *temp = STBDS_INDEX_EMPTY; 1290 | // adjust a to point after the default element 1291 | return STBDS_ARR_TO_HASH(a,elemsize); 1292 | } else { 1293 | stbds_hash_index *table; 1294 | void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); 1295 | // adjust a to point to the default element 1296 | table = (stbds_hash_index *) stbds_header(raw_a)->hash_table; 1297 | if (table == 0) { 1298 | *temp = -1; 1299 | } else { 1300 | ptrdiff_t slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); 1301 | if (slot < 0) { 1302 | *temp = STBDS_INDEX_EMPTY; 1303 | } else { 1304 | stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; 1305 | *temp = b->index[slot & STBDS_BUCKET_MASK]; 1306 | } 1307 | } 1308 | return a; 1309 | } 1310 | } 1311 | 1312 | void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode) 1313 | { 1314 | ptrdiff_t temp; 1315 | void *p = stbds_hmget_key_ts(a, elemsize, key, keysize, &temp, mode); 1316 | stbds_temp(STBDS_HASH_TO_ARR(p,elemsize)) = temp; 1317 | return p; 1318 | } 1319 | 1320 | void * stbds_hmput_default(void *a, size_t elemsize) 1321 | { 1322 | // three cases: 1323 | // a is NULL <- allocate 1324 | // a has a hash table but no entries, because of shmode <- grow 1325 | // a has entries <- do nothing 1326 | if (a == NULL || stbds_header(STBDS_HASH_TO_ARR(a,elemsize))->length == 0) { 1327 | a = stbds_arrgrowf(a ? STBDS_HASH_TO_ARR(a,elemsize) : NULL, elemsize, 0, 1); 1328 | stbds_header(a)->length += 1; 1329 | memset(a, 0, elemsize); 1330 | a=STBDS_ARR_TO_HASH(a,elemsize); 1331 | } 1332 | return a; 1333 | } 1334 | 1335 | static char *stbds_strdup(char *str); 1336 | 1337 | void *stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode) 1338 | { 1339 | size_t keyoffset=0; 1340 | void *raw_a; 1341 | stbds_hash_index *table; 1342 | 1343 | if (a == NULL) { 1344 | a = stbds_arrgrowf(0, elemsize, 0, 1); 1345 | memset(a, 0, elemsize); 1346 | stbds_header(a)->length += 1; 1347 | // adjust a to point AFTER the default element 1348 | a = STBDS_ARR_TO_HASH(a,elemsize); 1349 | } 1350 | 1351 | // adjust a to point to the default element 1352 | raw_a = a; 1353 | a = STBDS_HASH_TO_ARR(a,elemsize); 1354 | 1355 | table = (stbds_hash_index *) stbds_header(a)->hash_table; 1356 | 1357 | if (table == NULL || table->used_count >= table->used_count_threshold) { 1358 | stbds_hash_index *nt; 1359 | size_t slot_count; 1360 | 1361 | slot_count = (table == NULL) ? STBDS_BUCKET_LENGTH : table->slot_count*2; 1362 | nt = stbds_make_hash_index(slot_count, table); 1363 | if (table) 1364 | STBDS_FREE(NULL, table); 1365 | else 1366 | nt->string.mode = mode >= STBDS_HM_STRING ? STBDS_SH_DEFAULT : 0; 1367 | stbds_header(a)->hash_table = table = nt; 1368 | STBDS_STATS(++stbds_hash_grow); 1369 | } 1370 | 1371 | // we iterate hash table explicitly because we want to track if we saw a tombstone 1372 | { 1373 | size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); 1374 | size_t step = STBDS_BUCKET_LENGTH; 1375 | size_t pos; 1376 | ptrdiff_t tombstone = -1; 1377 | stbds_hash_bucket *bucket; 1378 | 1379 | // stored hash values are forbidden from being 0, so we can detect empty slots to early out quickly 1380 | if (hash < 2) hash += 2; 1381 | 1382 | pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); 1383 | 1384 | for (;;) { 1385 | size_t limit, i; 1386 | STBDS_STATS(++stbds_hash_probes); 1387 | bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; 1388 | 1389 | // start searching from pos to end of bucket 1390 | for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { 1391 | if (bucket->hash[i] == hash) { 1392 | if (stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { 1393 | stbds_temp(a) = bucket->index[i]; 1394 | if (mode >= STBDS_HM_STRING) 1395 | stbds_temp_key(a) = * (char **) ((char *) raw_a + elemsize*bucket->index[i] + keyoffset); 1396 | return STBDS_ARR_TO_HASH(a,elemsize); 1397 | } 1398 | } else if (bucket->hash[i] == 0) { 1399 | pos = (pos & ~STBDS_BUCKET_MASK) + i; 1400 | goto found_empty_slot; 1401 | } else if (tombstone < 0) { 1402 | if (bucket->index[i] == STBDS_INDEX_DELETED) 1403 | tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); 1404 | } 1405 | } 1406 | 1407 | // search from beginning of bucket to pos 1408 | limit = pos & STBDS_BUCKET_MASK; 1409 | for (i = 0; i < limit; ++i) { 1410 | if (bucket->hash[i] == hash) { 1411 | if (stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { 1412 | stbds_temp(a) = bucket->index[i]; 1413 | return STBDS_ARR_TO_HASH(a,elemsize); 1414 | } 1415 | } else if (bucket->hash[i] == 0) { 1416 | pos = (pos & ~STBDS_BUCKET_MASK) + i; 1417 | goto found_empty_slot; 1418 | } else if (tombstone < 0) { 1419 | if (bucket->index[i] == STBDS_INDEX_DELETED) 1420 | tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); 1421 | } 1422 | } 1423 | 1424 | // quadratic probing 1425 | pos += step; 1426 | step += STBDS_BUCKET_LENGTH; 1427 | pos &= (table->slot_count-1); 1428 | } 1429 | found_empty_slot: 1430 | if (tombstone >= 0) { 1431 | pos = tombstone; 1432 | --table->tombstone_count; 1433 | } 1434 | ++table->used_count; 1435 | 1436 | { 1437 | ptrdiff_t i = (ptrdiff_t) stbds_arrlen(a); 1438 | // we want to do stbds_arraddn(1), but we can't use the macros since we don't have something of the right type 1439 | if ((size_t) i+1 > stbds_arrcap(a)) 1440 | *(void **) &a = stbds_arrgrowf(a, elemsize, 1, 0); 1441 | raw_a = STBDS_ARR_TO_HASH(a,elemsize); 1442 | 1443 | STBDS_ASSERT((size_t) i+1 <= stbds_arrcap(a)); 1444 | stbds_header(a)->length = i+1; 1445 | bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; 1446 | bucket->hash[pos & STBDS_BUCKET_MASK] = hash; 1447 | bucket->index[pos & STBDS_BUCKET_MASK] = i-1; 1448 | stbds_temp(a) = i-1; 1449 | 1450 | switch (table->string.mode) { 1451 | case STBDS_SH_STRDUP: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = stbds_strdup((char*) key); break; 1452 | case STBDS_SH_ARENA: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = stbds_stralloc(&table->string, (char*)key); break; 1453 | case STBDS_SH_DEFAULT: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = (char *) key; break; 1454 | default: memcpy((char *) a + elemsize*i, key, keysize); break; 1455 | } 1456 | } 1457 | return STBDS_ARR_TO_HASH(a,elemsize); 1458 | } 1459 | } 1460 | 1461 | void * stbds_shmode_func(size_t elemsize, int mode) 1462 | { 1463 | void *a = stbds_arrgrowf(0, elemsize, 0, 1); 1464 | stbds_hash_index *h; 1465 | memset(a, 0, elemsize); 1466 | stbds_header(a)->length = 1; 1467 | stbds_header(a)->hash_table = h = (stbds_hash_index *) stbds_make_hash_index(STBDS_BUCKET_LENGTH, NULL); 1468 | h->string.mode = (unsigned char) mode; 1469 | return STBDS_ARR_TO_HASH(a,elemsize); 1470 | } 1471 | 1472 | void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode) 1473 | { 1474 | if (a == NULL) { 1475 | return 0; 1476 | } else { 1477 | stbds_hash_index *table; 1478 | void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); 1479 | table = (stbds_hash_index *) stbds_header(raw_a)->hash_table; 1480 | stbds_temp(raw_a) = 0; 1481 | if (table == 0) { 1482 | return a; 1483 | } else { 1484 | ptrdiff_t slot; 1485 | slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); 1486 | if (slot < 0) 1487 | return a; 1488 | else { 1489 | stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; 1490 | int i = slot & STBDS_BUCKET_MASK; 1491 | ptrdiff_t old_index = b->index[i]; 1492 | ptrdiff_t final_index = (ptrdiff_t) stbds_arrlen(raw_a)-1-1; // minus one for the raw_a vs a, and minus one for 'last' 1493 | STBDS_ASSERT(slot < (ptrdiff_t) table->slot_count); 1494 | --table->used_count; 1495 | ++table->tombstone_count; 1496 | stbds_temp(raw_a) = 1; 1497 | STBDS_ASSERT(table->used_count >= 0); 1498 | //STBDS_ASSERT(table->tombstone_count < table->slot_count/4); 1499 | b->hash[i] = STBDS_HASH_DELETED; 1500 | b->index[i] = STBDS_INDEX_DELETED; 1501 | 1502 | if (mode == STBDS_HM_STRING && table->string.mode == STBDS_SH_STRDUP) 1503 | STBDS_FREE(NULL, *(char**) ((char *) a+elemsize*old_index)); 1504 | 1505 | // if indices are the same, memcpy is a no-op, but back-pointer-fixup will fail, so skip 1506 | if (old_index != final_index) { 1507 | // swap delete 1508 | memmove((char*) a + elemsize*old_index, (char*) a + elemsize*final_index, elemsize); 1509 | 1510 | // now find the slot for the last element 1511 | if (mode == STBDS_HM_STRING) 1512 | slot = stbds_hm_find_slot(a, elemsize, *(char**) ((char *) a+elemsize*old_index + keyoffset), keysize, keyoffset, mode); 1513 | else 1514 | slot = stbds_hm_find_slot(a, elemsize, (char* ) a+elemsize*old_index + keyoffset, keysize, keyoffset, mode); 1515 | STBDS_ASSERT(slot >= 0); 1516 | b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; 1517 | i = slot & STBDS_BUCKET_MASK; 1518 | STBDS_ASSERT(b->index[i] == final_index); 1519 | b->index[i] = old_index; 1520 | } 1521 | stbds_header(raw_a)->length -= 1; 1522 | 1523 | if (table->used_count < table->used_count_shrink_threshold && table->slot_count > STBDS_BUCKET_LENGTH) { 1524 | stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count>>1, table); 1525 | STBDS_FREE(NULL, table); 1526 | STBDS_STATS(++stbds_hash_shrink); 1527 | } else if (table->tombstone_count > table->tombstone_count_threshold) { 1528 | stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count , table); 1529 | STBDS_FREE(NULL, table); 1530 | STBDS_STATS(++stbds_hash_rebuild); 1531 | } 1532 | 1533 | return a; 1534 | } 1535 | } 1536 | } 1537 | /* NOTREACHED */ 1538 | } 1539 | 1540 | static char *stbds_strdup(char *str) 1541 | { 1542 | // to keep replaceable allocator simple, we don't want to use strdup. 1543 | // rolling our own also avoids problem of strdup vs _strdup 1544 | size_t len = strlen(str)+1; 1545 | char *p = (char*) STBDS_REALLOC(NULL, 0, len); 1546 | memmove(p, str, len); 1547 | return p; 1548 | } 1549 | 1550 | #ifndef STBDS_STRING_ARENA_BLOCKSIZE_MIN 1551 | #define STBDS_STRING_ARENA_BLOCKSIZE_MIN 512u 1552 | #endif 1553 | #ifndef STBDS_STRING_ARENA_BLOCKSIZE_MAX 1554 | #define STBDS_STRING_ARENA_BLOCKSIZE_MAX (1u<<20) 1555 | #endif 1556 | 1557 | char *stbds_stralloc(stbds_string_arena *a, char *str) 1558 | { 1559 | char *p; 1560 | size_t len = strlen(str)+1; 1561 | if (len > a->remaining) { 1562 | // compute the next blocksize 1563 | size_t blocksize = a->block; 1564 | 1565 | // size is 512, 512, 1024, 1024, 2048, 2048, 4096, 4096, etc., so that 1566 | // there are log(SIZE) allocations to free when we destroy the table 1567 | blocksize = (size_t) (STBDS_STRING_ARENA_BLOCKSIZE_MIN) << (blocksize>>1); 1568 | 1569 | // if size is under 1M, advance to next blocktype 1570 | if (blocksize < (size_t)(STBDS_STRING_ARENA_BLOCKSIZE_MAX)) 1571 | ++a->block; 1572 | 1573 | if (len > blocksize) { 1574 | // if string is larger than blocksize, then just allocate the full size. 1575 | // note that we still advance string_block so block size will continue 1576 | // increasing, so e.g. if somebody only calls this with 1000-long strings, 1577 | // eventually the arena will start doubling and handling those as well 1578 | stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(NULL, 0, sizeof(*sb)-8 + len); 1579 | memmove(sb->storage, str, len); 1580 | if (a->storage) { 1581 | // insert it after the first element, so that we don't waste the space there 1582 | sb->next = a->storage->next; 1583 | a->storage->next = sb; 1584 | } else { 1585 | sb->next = 0; 1586 | a->storage = sb; 1587 | a->remaining = 0; // this is redundant, but good for clarity 1588 | } 1589 | return sb->storage; 1590 | } else { 1591 | stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(NULL, 0, sizeof(*sb)-8 + blocksize); 1592 | sb->next = a->storage; 1593 | a->storage = sb; 1594 | a->remaining = blocksize; 1595 | } 1596 | } 1597 | 1598 | STBDS_ASSERT(len <= a->remaining); 1599 | p = a->storage->storage + a->remaining - len; 1600 | a->remaining -= len; 1601 | memmove(p, str, len); 1602 | return p; 1603 | } 1604 | 1605 | void stbds_strreset(stbds_string_arena *a) 1606 | { 1607 | stbds_string_block *x,*y; 1608 | x = a->storage; 1609 | while (x) { 1610 | y = x->next; 1611 | STBDS_FREE(NULL, x); 1612 | x = y; 1613 | } 1614 | memset(a, 0, sizeof(*a)); 1615 | } 1616 | 1617 | #endif 1618 | 1619 | ////////////////////////////////////////////////////////////////////////////// 1620 | // 1621 | // UNIT TESTS 1622 | // 1623 | 1624 | #ifdef STBDS_UNIT_TESTS 1625 | #include 1626 | #ifdef STBDS_ASSERT_WAS_UNDEFINED 1627 | #undef STBDS_ASSERT 1628 | #endif 1629 | #ifndef STBDS_ASSERT 1630 | #define STBDS_ASSERT assert 1631 | #include 1632 | #endif 1633 | 1634 | typedef struct { int key,b,c,d; } stbds_struct; 1635 | typedef struct { int key[2],b,c,d; } stbds_struct2; 1636 | 1637 | static char buffer[256]; 1638 | char *strkey(int n) 1639 | { 1640 | #if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) 1641 | sprintf_s(buffer, sizeof(buffer), "test_%d", n); 1642 | #else 1643 | sprintf(buffer, "test_%d", n); 1644 | #endif 1645 | return buffer; 1646 | } 1647 | 1648 | void stbds_unit_tests(void) 1649 | { 1650 | #if defined(_MSC_VER) && _MSC_VER <= 1200 && defined(__cplusplus) 1651 | // VC6 C++ doesn't like the template<> trick on unnamed structures, so do nothing! 1652 | STBDS_ASSERT(0); 1653 | #else 1654 | const int testsize = 100000; 1655 | const int testsize2 = testsize/20; 1656 | int *arr=NULL; 1657 | struct { int key; int value; } *intmap = NULL; 1658 | struct { char *key; int value; } *strmap = NULL, s; 1659 | struct { stbds_struct key; int value; } *map = NULL; 1660 | stbds_struct *map2 = NULL; 1661 | stbds_struct2 *map3 = NULL; 1662 | stbds_string_arena sa = { 0 }; 1663 | int key3[2] = { 1,2 }; 1664 | ptrdiff_t temp; 1665 | 1666 | int i,j; 1667 | 1668 | STBDS_ASSERT(arrlen(arr)==0); 1669 | for (i=0; i < 20000; i += 50) { 1670 | for (j=0; j < i; ++j) 1671 | arrpush(arr,j); 1672 | arrfree(arr); 1673 | } 1674 | 1675 | for (i=0; i < 4; ++i) { 1676 | arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); 1677 | arrdel(arr,i); 1678 | arrfree(arr); 1679 | arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); 1680 | arrdelswap(arr,i); 1681 | arrfree(arr); 1682 | } 1683 | 1684 | for (i=0; i < 5; ++i) { 1685 | arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); 1686 | stbds_arrins(arr,i,5); 1687 | STBDS_ASSERT(arr[i] == 5); 1688 | if (i < 4) 1689 | STBDS_ASSERT(arr[4] == 4); 1690 | arrfree(arr); 1691 | } 1692 | 1693 | i = 1; 1694 | STBDS_ASSERT(hmgeti(intmap,i) == -1); 1695 | hmdefault(intmap, -2); 1696 | STBDS_ASSERT(hmgeti(intmap, i) == -1); 1697 | STBDS_ASSERT(hmget (intmap, i) == -2); 1698 | for (i=0; i < testsize; i+=2) 1699 | hmput(intmap, i, i*5); 1700 | for (i=0; i < testsize; i+=1) { 1701 | if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 ); 1702 | else STBDS_ASSERT(hmget(intmap, i) == i*5); 1703 | if (i & 1) STBDS_ASSERT(hmget_ts(intmap, i, temp) == -2 ); 1704 | else STBDS_ASSERT(hmget_ts(intmap, i, temp) == i*5); 1705 | } 1706 | for (i=0; i < testsize; i+=2) 1707 | hmput(intmap, i, i*3); 1708 | for (i=0; i < testsize; i+=1) 1709 | if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 ); 1710 | else STBDS_ASSERT(hmget(intmap, i) == i*3); 1711 | for (i=2; i < testsize; i+=4) 1712 | hmdel(intmap, i); // delete half the entries 1713 | for (i=0; i < testsize; i+=1) 1714 | if (i & 3) STBDS_ASSERT(hmget(intmap, i) == -2 ); 1715 | else STBDS_ASSERT(hmget(intmap, i) == i*3); 1716 | for (i=0; i < testsize; i+=1) 1717 | hmdel(intmap, i); // delete the rest of the entries 1718 | for (i=0; i < testsize; i+=1) 1719 | STBDS_ASSERT(hmget(intmap, i) == -2 ); 1720 | hmfree(intmap); 1721 | for (i=0; i < testsize; i+=2) 1722 | hmput(intmap, i, i*3); 1723 | hmfree(intmap); 1724 | 1725 | #if defined(__clang__) || defined(__GNUC__) 1726 | #ifndef __cplusplus 1727 | intmap = NULL; 1728 | hmput(intmap, 15, 7); 1729 | hmput(intmap, 11, 3); 1730 | hmput(intmap, 9, 5); 1731 | STBDS_ASSERT(hmget(intmap, 9) == 5); 1732 | STBDS_ASSERT(hmget(intmap, 11) == 3); 1733 | STBDS_ASSERT(hmget(intmap, 15) == 7); 1734 | #endif 1735 | #endif 1736 | 1737 | for (i=0; i < testsize; ++i) 1738 | stralloc(&sa, strkey(i)); 1739 | strreset(&sa); 1740 | 1741 | { 1742 | s.key = "a", s.value = 1; 1743 | shputs(strmap, s); 1744 | STBDS_ASSERT(*strmap[0].key == 'a'); 1745 | STBDS_ASSERT(strmap[0].key == s.key); 1746 | STBDS_ASSERT(strmap[0].value == s.value); 1747 | shfree(strmap); 1748 | } 1749 | 1750 | { 1751 | s.key = "a", s.value = 1; 1752 | sh_new_strdup(strmap); 1753 | shputs(strmap, s); 1754 | STBDS_ASSERT(*strmap[0].key == 'a'); 1755 | STBDS_ASSERT(strmap[0].key != s.key); 1756 | STBDS_ASSERT(strmap[0].value == s.value); 1757 | shfree(strmap); 1758 | } 1759 | 1760 | { 1761 | s.key = "a", s.value = 1; 1762 | sh_new_arena(strmap); 1763 | shputs(strmap, s); 1764 | STBDS_ASSERT(*strmap[0].key == 'a'); 1765 | STBDS_ASSERT(strmap[0].key != s.key); 1766 | STBDS_ASSERT(strmap[0].value == s.value); 1767 | shfree(strmap); 1768 | } 1769 | 1770 | for (j=0; j < 2; ++j) { 1771 | STBDS_ASSERT(shgeti(strmap,"foo") == -1); 1772 | if (j == 0) 1773 | sh_new_strdup(strmap); 1774 | else 1775 | sh_new_arena(strmap); 1776 | STBDS_ASSERT(shgeti(strmap,"foo") == -1); 1777 | shdefault(strmap, -2); 1778 | STBDS_ASSERT(shgeti(strmap,"foo") == -1); 1779 | for (i=0; i < testsize; i+=2) 1780 | shput(strmap, strkey(i), i*3); 1781 | for (i=0; i < testsize; i+=1) 1782 | if (i & 1) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); 1783 | else STBDS_ASSERT(shget(strmap, strkey(i)) == i*3); 1784 | for (i=2; i < testsize; i+=4) 1785 | shdel(strmap, strkey(i)); // delete half the entries 1786 | for (i=0; i < testsize; i+=1) 1787 | if (i & 3) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); 1788 | else STBDS_ASSERT(shget(strmap, strkey(i)) == i*3); 1789 | for (i=0; i < testsize; i+=1) 1790 | shdel(strmap, strkey(i)); // delete the rest of the entries 1791 | for (i=0; i < testsize; i+=1) 1792 | STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); 1793 | shfree(strmap); 1794 | } 1795 | 1796 | { 1797 | struct { char *key; char value; } *hash = NULL; 1798 | char name[4] = "jen"; 1799 | shput(hash, "bob" , 'h'); 1800 | shput(hash, "sally" , 'e'); 1801 | shput(hash, "fred" , 'l'); 1802 | shput(hash, "jen" , 'x'); 1803 | shput(hash, "doug" , 'o'); 1804 | 1805 | shput(hash, name , 'l'); 1806 | shfree(hash); 1807 | } 1808 | 1809 | for (i=0; i < testsize; i += 2) { 1810 | stbds_struct s = { i,i*2,i*3,i*4 }; 1811 | hmput(map, s, i*5); 1812 | } 1813 | 1814 | for (i=0; i < testsize; i += 1) { 1815 | stbds_struct s = { i,i*2,i*3 ,i*4 }; 1816 | stbds_struct t = { i,i*2,i*3+1,i*4 }; 1817 | if (i & 1) STBDS_ASSERT(hmget(map, s) == 0); 1818 | else STBDS_ASSERT(hmget(map, s) == i*5); 1819 | if (i & 1) STBDS_ASSERT(hmget_ts(map, s, temp) == 0); 1820 | else STBDS_ASSERT(hmget_ts(map, s, temp) == i*5); 1821 | //STBDS_ASSERT(hmget(map, t.key) == 0); 1822 | } 1823 | 1824 | for (i=0; i < testsize; i += 2) { 1825 | stbds_struct s = { i,i*2,i*3,i*4 }; 1826 | hmputs(map2, s); 1827 | } 1828 | hmfree(map); 1829 | 1830 | for (i=0; i < testsize; i += 1) { 1831 | stbds_struct s = { i,i*2,i*3,i*4 }; 1832 | stbds_struct t = { i,i*2,i*3+1,i*4 }; 1833 | if (i & 1) STBDS_ASSERT(hmgets(map2, s.key).d == 0); 1834 | else STBDS_ASSERT(hmgets(map2, s.key).d == i*4); 1835 | //STBDS_ASSERT(hmgetp(map2, t.key) == 0); 1836 | } 1837 | hmfree(map2); 1838 | 1839 | for (i=0; i < testsize; i += 2) { 1840 | stbds_struct2 s = { { i,i*2 }, i*3,i*4, i*5 }; 1841 | hmputs(map3, s); 1842 | } 1843 | for (i=0; i < testsize; i += 1) { 1844 | stbds_struct2 s = { { i,i*2}, i*3, i*4, i*5 }; 1845 | stbds_struct2 t = { { i,i*2}, i*3+1, i*4, i*5 }; 1846 | if (i & 1) STBDS_ASSERT(hmgets(map3, s.key).d == 0); 1847 | else STBDS_ASSERT(hmgets(map3, s.key).d == i*5); 1848 | //STBDS_ASSERT(hmgetp(map3, t.key) == 0); 1849 | } 1850 | #endif 1851 | } 1852 | #endif 1853 | 1854 | 1855 | /* 1856 | ------------------------------------------------------------------------------ 1857 | This software is available under 2 licenses -- choose whichever you prefer. 1858 | ------------------------------------------------------------------------------ 1859 | ALTERNATIVE A - MIT License 1860 | Copyright (c) 2019 Sean Barrett 1861 | Permission is hereby granted, free of charge, to any person obtaining a copy of 1862 | this software and associated documentation files (the "Software"), to deal in 1863 | the Software without restriction, including without limitation the rights to 1864 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 1865 | of the Software, and to permit persons to whom the Software is furnished to do 1866 | so, subject to the following conditions: 1867 | The above copyright notice and this permission notice shall be included in all 1868 | copies or substantial portions of the Software. 1869 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1870 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1871 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1872 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1873 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1874 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1875 | SOFTWARE. 1876 | ------------------------------------------------------------------------------ 1877 | ALTERNATIVE B - Public Domain (www.unlicense.org) 1878 | This is free and unencumbered software released into the public domain. 1879 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 1880 | software, either in source code form or as a compiled binary, for any purpose, 1881 | commercial or non-commercial, and by any means. 1882 | In jurisdictions that recognize copyright laws, the author or authors of this 1883 | software dedicate any and all copyright interest in the software to the public 1884 | domain. We make this dedication for the benefit of the public at large and to 1885 | the detriment of our heirs and successors. We intend this dedication to be an 1886 | overt act of relinquishment in perpetuity of all present and future rights to 1887 | this software under copyright law. 1888 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1889 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1890 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1891 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 1892 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 1893 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1894 | ------------------------------------------------------------------------------ 1895 | */ 1896 | --------------------------------------------------------------------------------