diff --git a/CMakeLists.txt b/CMakeLists.txt index d3ea94b..0164510 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,8 @@ add_subdirectory(external/milsko) add_subdirectory(engine) +include_directories(external/stb) + install( FILES resource/logo.png resource/font.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/assaultfish diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index cd3df3d..7cddded 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -17,5 +17,11 @@ endmacro() add_subdirectory(external/glad) add_subdirectory(net) +add_subdirectory(common) add_subdirectory(tools) + +install( + FILES resource/shadow.vs resource/shadow.fs + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/gearbox +) diff --git a/engine/common/CMakeLists.txt b/engine/common/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/engine/common/log.c b/engine/common/log.c new file mode 100644 index 0000000..e69de29 diff --git a/engine/net/include/gbnet.h b/engine/net/include/gbnet.h index eeaaabe..84d70b7 100644 --- a/engine/net/include/gbnet.h +++ b/engine/net/include/gbnet.h @@ -25,10 +25,10 @@ enum gbnet_packet_type { NET_PACKET_USER }; -typedef struct gbnet_client gbnet_client_t; -typedef struct gbnet_server gbnet_server_t; +typedef struct gbnet_client gbnet_client_t; +typedef struct gbnet_server gbnet_server_t; typedef struct gbnet_packet_header gbnet_packet_header_t; -typedef struct gbnet_packet gbnet_packet_t; +typedef struct gbnet_packet gbnet_packet_t; struct gbnet_client { int fd; @@ -45,7 +45,7 @@ struct gbnet_client { struct gbnet_server { int fd; struct sockaddr_in address; - gbnet_client_t* clients; + gbnet_client_t* clients; void* user; void (*on_client)(gbnet_server_t* server, gbnet_client_t* client); void (*on_tick)(gbnet_server_t* server); @@ -61,22 +61,22 @@ struct gbnet_packet_header { /* !!! REMEMBER TO FREE DATA AFTER RECV UNLESS IT'S NULL !!! */ struct gbnet_packet { gbnet_packet_header_t header; - void* data; + void* data; }; gbnet_client_t* gbnet_client(const char* host, int port); -void gbnet_client_on_packet(gbnet_client_t* client, void (*on_packet)(gbnet_client_t* client, gbnet_packet_t* packet)); -void gbnet_client_on_disconnect(gbnet_client_t* client, void (*on_disconnect)(gbnet_client_t* client)); -int gbnet_client_poll(gbnet_client_t* client); -void gbnet_client_destroy(gbnet_client_t* client); +void gbnet_client_on_packet(gbnet_client_t* client, void (*on_packet)(gbnet_client_t* client, gbnet_packet_t* packet)); +void gbnet_client_on_disconnect(gbnet_client_t* client, void (*on_disconnect)(gbnet_client_t* client)); +int gbnet_client_poll(gbnet_client_t* client); +void gbnet_client_destroy(gbnet_client_t* client); gbnet_server_t* gbnet_server(int port); -int gbnet_server_clients(gbnet_server_t* server); -void gbnet_server_loop(gbnet_server_t* server); -void gbnet_server_on_client(gbnet_server_t* server, void (*on_client)(gbnet_server_t* server, gbnet_client_t* client)); -void gbnet_server_on_tick(gbnet_server_t* server, void (*on_tick)(gbnet_server_t* server)); -void gbnet_server_broadcast(gbnet_server_t* server, gbnet_packet_t* packet); -void gbnet_server_destroy(gbnet_server_t* server); +int gbnet_server_clients(gbnet_server_t* server); +void gbnet_server_loop(gbnet_server_t* server); +void gbnet_server_on_client(gbnet_server_t* server, void (*on_client)(gbnet_server_t* server, gbnet_client_t* client)); +void gbnet_server_on_tick(gbnet_server_t* server, void (*on_tick)(gbnet_server_t* server)); +void gbnet_server_broadcast(gbnet_server_t* server, gbnet_packet_t* packet); +void gbnet_server_destroy(gbnet_server_t* server); int gbnet_fd_send(int fd, const void* buf, int length); int gbnet_fd_recv(int fd, void* buf, int length, int to); diff --git a/engine/net/src/client.c b/engine/net/src/client.c index 1753598..4e06a2d 100644 --- a/engine/net/src/client.c +++ b/engine/net/src/client.c @@ -1,11 +1,11 @@ #include gbnet_client_t* gbnet_client(const char* host, int port) { - gbnet_client_t* client = malloc(sizeof(*client)); - struct addrinfo hints; - char p[32]; - struct addrinfo* result; - struct addrinfo* rp; + gbnet_client_t* client = malloc(sizeof(*client)); + struct addrinfo hints; + char p[32]; + struct addrinfo* result; + struct addrinfo* rp; if(port == 0) port = NET_PORT; sprintf(p, "%d", port); @@ -55,9 +55,9 @@ void gbnet_client_on_disconnect(gbnet_client_t* client, void (*on_disconnect)(gb } int gbnet_client_poll(gbnet_client_t* client) { - struct pollfd pfd; + struct pollfd pfd; gbnet_packet_t pkt; - int ret; + int ret; pfd.fd = client->fd; pfd.events = POLLIN | POLLPRI; diff --git a/engine/net/src/server.c b/engine/net/src/server.c index 6e7132b..7aff955 100644 --- a/engine/net/src/server.c +++ b/engine/net/src/server.c @@ -4,7 +4,7 @@ gbnet_server_t* gbnet_server(int port) { gbnet_server_t* server = malloc(sizeof(*server)); - int val; + int val; if(port == 0) port = NET_PORT; @@ -68,7 +68,7 @@ void gbnet_server_loop(gbnet_server_t* server) { if(server->on_tick != NULL) server->on_tick(server); if(pfd[0].revents & POLLIN) { - gbnet_client_t client; + gbnet_client_t client; struct sockaddr_in address; int len = sizeof(address); diff --git a/engine/net/src/socket.c b/engine/net/src/socket.c index e235767..563f2d1 100644 --- a/engine/net/src/socket.c +++ b/engine/net/src/socket.c @@ -5,10 +5,10 @@ #define CHUNK 512 int gbnet_packet_send(int fd, gbnet_packet_t* packet) { - int r; + int r; gbnet_packet_header_t h; - int len = 0; - unsigned char* data = NULL; + int len = 0; + unsigned char* data = NULL; if(packet->header.length > 0) { z_stream strm; diff --git a/engine/net/src/stb_ds.h b/engine/net/src/stb_ds.h index e84c82d..c58b00f 100644 --- a/engine/net/src/stb_ds.h +++ b/engine/net/src/stb_ds.h @@ -71,80 +71,80 @@ DOCUMENTATION Non-function interface: Declare an empty dynamic array of type T - T* foo = NULL; + T* foo = NULL; Access the i'th item of a dynamic array 'foo' of type T, T* foo: - foo[i] + foo[i] Functions (actually macros) arrfree: - void arrfree(T*); - Frees the array. + void arrfree(T*); + Frees the array. arrlen: - ptrdiff_t arrlen(T*); - Returns the number of elements in the array. + ptrdiff_t arrlen(T*); + Returns the number of elements in the array. arrlenu: - size_t arrlenu(T*); - Returns the number of elements in the array as an unsigned type. + size_t arrlenu(T*); + Returns the number of elements in the array as an unsigned type. arrpop: - T arrpop(T* a) - Removes the final element of the array and returns it. + T arrpop(T* a) + Removes the final element of the array and returns it. arrput: - T arrput(T* a, T b); - Appends the item b to the end of array a. Returns b. + T arrput(T* a, T b); + Appends the item b to the end of array a. Returns b. arrins: - T arrins(T* a, int p, T b); - Inserts the item b into the middle of array a, into a[p], - moving the rest of the array over. Returns b. + T arrins(T* a, int p, T b); + Inserts the item b into the middle of array a, into a[p], + moving the rest of the array over. Returns b. arrinsn: - void arrinsn(T* a, int p, int n); - Inserts n uninitialized items into array a starting at a[p], - moving the rest of the array over. + void arrinsn(T* a, int p, int n); + Inserts n uninitialized items into array a starting at a[p], + moving the rest of the array over. arraddnptr: - T* arraddnptr(T* a, int n) - Appends n uninitialized items onto array at the end. - Returns a pointer to the first uninitialized item added. + T* arraddnptr(T* a, int n) + Appends n uninitialized items onto array at the end. + Returns a pointer to the first uninitialized item added. arraddnindex: - size_t arraddnindex(T* a, int n) - Appends n uninitialized items onto array at the end. - Returns the index of the first uninitialized item added. + size_t arraddnindex(T* a, int n) + Appends n uninitialized items onto array at the end. + Returns the index of 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. + void arrdel(T* a, int p); + Deletes the element at a[p], moving the rest of the array over. arrdeln: - void arrdeln(T* a, int p, int n); - Deletes n elements starting at a[p], moving the rest of the array over. + void arrdeln(T* a, int p, int n); + Deletes n elements starting at a[p], moving the rest of the array over. arrdelswap: - void arrdelswap(T* a, int p); - Deletes the element at a[p], replacing it with the element from - the end of the array. O(1) performance. + void arrdelswap(T* a, int p); + Deletes the element at a[p], replacing it with the element from + the end of the array. O(1) performance. arrsetlen: - void arrsetlen(T* a, int n); - Changes the length of the array to n. Allocates uninitialized - slots at the end if necessary. + void arrsetlen(T* a, int n); + Changes the length of the array to n. Allocates uninitialized + slots at the end if necessary. arrsetcap: - size_t arrsetcap(T* a, int n); - Sets the length of allocated storage to at least n. It will not - change the length of the array. + size_t arrsetcap(T* a, int n); + Sets the length of allocated storage to at least n. It will not + change the length of the array. arrcap: - size_t arrcap(T* a); - Returns the number of total elements the array can contain without - needing to be reallocated. + size_t arrcap(T* a); + Returns the number of total elements the array can contain without + needing to be reallocated. Hash maps & String hash maps @@ -155,140 +155,140 @@ DOCUMENTATION Special interface: stbds_rand_seed: - void stbds_rand_seed(size_t seed); - For security against adversarially chosen data, you should seed the - library with a strong random number. Or at least seed it with time(). + void stbds_rand_seed(size_t seed); + For security against adversarially chosen data, you should seed the + library with a strong random number. Or at least seed it with time(). stbds_hash_string: - size_t stbds_hash_string(char *str, size_t seed); - Returns a hash value for a string. + size_t stbds_hash_string(char *str, size_t seed); + Returns a hash value for a string. stbds_hash_bytes: - size_t stbds_hash_bytes(void *p, size_t len, size_t seed); - These functions hash an arbitrary number of bytes. The function - uses a custom hash for 4- and 8-byte data, and a weakened version - of SipHash for everything else. On 64-bit platforms you can get - specification-compliant SipHash-2-4 on all data by defining - STBDS_SIPHASH_2_4, at a significant cost in speed. + size_t stbds_hash_bytes(void *p, size_t len, size_t seed); + These functions hash an arbitrary number of bytes. The function + uses a custom hash for 4- and 8-byte data, and a weakened version + of SipHash for everything else. On 64-bit platforms you can get + specification-compliant SipHash-2-4 on all data by defining + STBDS_SIPHASH_2_4, at a significant cost in speed. Non-function interface: Declare an empty hash map of type T - T* foo = NULL; + T* foo = NULL; Access the i'th entry in a hash table T* foo: - foo[i] + foo[i] Function interface (actually macros): hmfree shfree - void hmfree(T*); - void shfree(T*); - Frees the hashmap and sets the pointer to NULL. + void hmfree(T*); + void shfree(T*); + Frees the hashmap and sets the pointer to NULL. hmlen shlen - ptrdiff_t hmlen(T*) - ptrdiff_t shlen(T*) - Returns the number of elements in the hashmap. + ptrdiff_t hmlen(T*) + ptrdiff_t shlen(T*) + Returns the number of elements in the hashmap. hmlenu shlenu - size_t hmlenu(T*) - size_t shlenu(T*) - Returns the number of elements in the hashmap. + size_t hmlenu(T*) + size_t shlenu(T*) + Returns the number of elements in the hashmap. 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. + 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 + 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 hmgets shgets - T hmgets(T*, TK key) - T shgets(T*, char* key) - Returns the structure corresponding to 'key' in the hashmap. + T hmgets(T*, TK key) + 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). + 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) - TV shdefault(T*, TV value) - Sets the default value for the hashmap, the value which will be - returned by hmget/shget if the key is not present. + TV hmdefault(T*, TV value) + TV shdefault(T*, TV value) + Sets the default value for the hashmap, the value which will be + returned by hmget/shget if the key is not present. hmdefaults shdefaults - TV hmdefaults(T*, T item) - TV shdefaults(T*, T item) - Sets the default struct for the hashmap, the contents which will be - returned by hmgets/shgets if the key is not present. + TV hmdefaults(T*, T item) + TV shdefaults(T*, T item) + Sets the default struct for the hashmap, the contents which will be + returned by hmgets/shgets if the key is not present. hmput shput - TV hmput(T*, TK key, TV value) - TV shput(T*, char* key, TV value) - Inserts a pair into the hashmap. If the key is already - present in the hashmap, updates its value. + TV hmput(T*, TK key, TV value) + TV shput(T*, char* key, TV value) + Inserts a pair into the hashmap. If the key is already + present in the hashmap, updates its value. hmputs shputs - T hmputs(T*, T item) - T shputs(T*, T item) - Inserts a struct with T.key into the hashmap. If the struct is already - present in the hashmap, updates it. + T hmputs(T*, T item) + T shputs(T*, T item) + Inserts a struct with T.key into the hashmap. If the struct is already + present in the hashmap, updates it. hmdel shdel - int hmdel(T*, TK key) - int shdel(T*, char* key) - If 'key' is in the hashmap, deletes its entry and returns 1. - Otherwise returns 0. + int hmdel(T*, TK key) + int shdel(T*, char* key) + If 'key' is in the hashmap, deletes its entry and returns 1. + Otherwise returns 0. Function interface (actually macros) for strings only: sh_new_strdup - void sh_new_strdup(T*); - Overwrites the existing pointer with a newly allocated - string hashmap which will automatically allocate and free - each string key using realloc/free + void sh_new_strdup(T*); + Overwrites the existing pointer with a newly allocated + string hashmap which will automatically allocate and free + each string key using realloc/free sh_new_arena - void sh_new_arena(T*); - Overwrites the existing pointer with a newly allocated - string hashmap which will automatically allocate each string - key to a string arena. Every string key ever used by this - hash table remains in the arena until the arena is freed. - Additionally, any key which is deleted and reinserted will - be allocated multiple times in the string arena. + void sh_new_arena(T*); + Overwrites the existing pointer with a newly allocated + string hashmap which will automatically allocate each string + key to a string arena. Every string key ever used by this + hash table remains in the arena until the arena is freed. + Additionally, any key which is deleted and reinserted will + be allocated multiple times in the string arena. NOTES @@ -303,17 +303,17 @@ NOTES * 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 + 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: for (i=0; i < arrlen(foo); ++i) - ... foo[i] ... + ... foo[i] ... * All operations except arrins/arrdel are O(1) amortized, but individual operations can be slow, so these data structures may not be suitable @@ -395,61 +395,61 @@ CREDITS #include #ifndef STBDS_NO_SHORT_NAMES -#define arrlen stbds_arrlen -#define arrlenu stbds_arrlenu -#define arrput stbds_arrput -#define arrpush stbds_arrput -#define arrpop stbds_arrpop -#define arrfree stbds_arrfree -#define arraddn stbds_arraddn // deprecated, use one of the following instead: -#define arraddnptr stbds_arraddnptr +#define arrlen stbds_arrlen +#define arrlenu stbds_arrlenu +#define arrput stbds_arrput +#define arrpush stbds_arrput +#define arrpop stbds_arrpop +#define arrfree stbds_arrfree +#define arraddn stbds_arraddn // deprecated, use one of the following instead: +#define arraddnptr stbds_arraddnptr #define arraddnindex stbds_arraddnindex -#define arrsetlen stbds_arrsetlen -#define arrlast stbds_arrlast -#define arrins stbds_arrins -#define arrinsn stbds_arrinsn -#define arrdel stbds_arrdel -#define arrdeln stbds_arrdeln -#define arrdelswap stbds_arrdelswap -#define arrcap stbds_arrcap -#define arrsetcap stbds_arrsetcap +#define arrsetlen stbds_arrsetlen +#define arrlast stbds_arrlast +#define arrins stbds_arrins +#define arrinsn stbds_arrinsn +#define arrdel stbds_arrdel +#define arrdeln stbds_arrdeln +#define arrdelswap stbds_arrdelswap +#define arrcap stbds_arrcap +#define arrsetcap stbds_arrsetcap -#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 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 -#define hmfree stbds_hmfree -#define hmdefault stbds_hmdefault -#define hmdefaults stbds_hmdefaults +#define hmgeti stbds_hmgeti +#define hmgeti_ts stbds_hmgeti_ts +#define hmdel stbds_hmdel +#define hmlen stbds_hmlen +#define hmlenu stbds_hmlenu +#define hmfree stbds_hmfree +#define hmdefault stbds_hmdefault +#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 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 shgetp_null stbds_shgetp_null -#define shdel stbds_shdel -#define shlen stbds_shlen -#define shlenu stbds_shlenu -#define shfree stbds_shfree -#define shdefault stbds_shdefault -#define shdefaults stbds_shdefaults -#define sh_new_arena stbds_sh_new_arena +#define shdel stbds_shdel +#define shlen stbds_shlen +#define shlenu stbds_shlenu +#define shfree stbds_shfree +#define shdefault stbds_shdefault +#define shdefaults stbds_shdefaults +#define sh_new_arena stbds_sh_new_arena #define sh_new_strdup stbds_sh_new_strdup -#define stralloc stbds_stralloc -#define strreset stbds_strreset +#define stralloc stbds_stralloc +#define strreset stbds_strreset #endif #if defined(STBDS_REALLOC) && !defined(STBDS_FREE) || !defined(STBDS_REALLOC) && defined(STBDS_FREE) @@ -457,14 +457,14 @@ CREDITS #endif #if !defined(STBDS_REALLOC) && !defined(STBDS_FREE) #include -#define STBDS_REALLOC(c,p,s) realloc(p,s) -#define STBDS_FREE(c,p) free(p) +#define STBDS_REALLOC(c, p, s) realloc(p, s) +#define STBDS_FREE(c, p) free(p) #endif #ifdef _MSC_VER -#define STBDS_NOTUSED(v) (void)(v) +#define STBDS_NOTUSED(v) (void)(v) #else -#define STBDS_NOTUSED(v) (void)sizeof(v) +#define STBDS_NOTUSED(v) (void)sizeof(v) #endif #ifdef __cplusplus @@ -475,13 +475,13 @@ extern "C" { extern void stbds_rand_seed(size_t seed); // these are the hash functions used internally if you want to test them or use them for other purposes -extern size_t stbds_hash_bytes(void *p, size_t len, size_t seed); -extern size_t stbds_hash_string(char *str, size_t seed); +extern size_t stbds_hash_bytes(void* p, size_t len, size_t seed); +extern size_t stbds_hash_string(char* str, size_t seed); // this is a simple string arena allocator, initialize with e.g. 'stbds_string_arena my_arena={0}'. typedef struct stbds_string_arena stbds_string_arena; -extern char * stbds_stralloc(stbds_string_arena *a, char *str); -extern void stbds_strreset(stbds_string_arena *a); +extern char* stbds_stralloc(stbds_string_arena* a, char* str); +extern void stbds_strreset(stbds_string_arena* a); // have to #define STBDS_UNIT_TESTS to call this extern void stbds_unit_tests(void); @@ -491,15 +491,15 @@ extern void stbds_unit_tests(void); // Everything below here is implementation details // -extern void * stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap); -extern void stbds_arrfreef(void *a); -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); -extern void * stbds_shmode_func(size_t elemsize, int mode); +extern void* stbds_arrgrowf(void* a, size_t elemsize, size_t addlen, size_t min_cap); +extern void stbds_arrfreef(void* a); +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); +extern void* stbds_shmode_func(size_t elemsize, int mode); #ifdef __cplusplus } @@ -508,7 +508,7 @@ extern void * stbds_shmode_func(size_t elemsize, int mode); #if defined(__GNUC__) || defined(__clang__) #define STBDS_HAS_TYPEOF #ifdef __cplusplus -//#define STBDS_HAS_LITERAL_ARRAY // this is currently broken for clang +// #define STBDS_HAS_LITERAL_ARRAY // this is currently broken for clang #endif #endif @@ -520,210 +520,214 @@ extern void * stbds_shmode_func(size_t elemsize, int mode); // this macro takes the address of the argument, but on gcc/clang can accept rvalues #if defined(STBDS_HAS_LITERAL_ARRAY) && defined(STBDS_HAS_TYPEOF) - #if __clang__ - #define STBDS_ADDRESSOF(typevar, value) ((__typeof__(typevar)[1]){value}) // literal array decays to pointer to value - #else - #define STBDS_ADDRESSOF(typevar, value) ((typeof(typevar)[1]){value}) // literal array decays to pointer to value - #endif +#if __clang__ +#define STBDS_ADDRESSOF(typevar, value) ((__typeof__(typevar)[1]){value}) // literal array decays to pointer to value #else -#define STBDS_ADDRESSOF(typevar, value) &(value) +#define STBDS_ADDRESSOF(typevar, value) ((typeof(typevar)[1]){value}) // literal array decays to pointer to value +#endif +#else +#define STBDS_ADDRESSOF(typevar, value) &(value) #endif -#define STBDS_OFFSETOF(var,field) ((char *) &(var)->field - (char *) (var)) +#define STBDS_OFFSETOF(var, field) ((char*)&(var)->field - (char*)(var)) -#define stbds_header(t) ((stbds_array_header *) (t) - 1) -#define stbds_temp(t) stbds_header(t)->temp -#define stbds_temp_key(t) (*(char **) stbds_header(t)->hash_table) +#define stbds_header(t) ((stbds_array_header*)(t) - 1) +#define stbds_temp(t) stbds_header(t)->temp +#define stbds_temp_key(t) (*(char**)stbds_header(t)->hash_table) -#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) ((void)(stbds_arraddnindex(a, n))) // deprecated, use one of the following instead: -#define stbds_arraddnptr(a,n) (stbds_arrmaybegrow(a,n), (n) ? (stbds_header(a)->length += (n), &(a)[stbds_header(a)->length-(n)]) : (a)) -#define stbds_arraddnindex(a,n)(stbds_arrmaybegrow(a,n), (n) ? (stbds_header(a)->length += (n), stbds_header(a)->length-(n)) : stbds_arrlen(a)) -#define stbds_arraddnoff stbds_arraddnindex -#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) -#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)) -#define stbds_arrdelswap(a,i) ((a)[i] = stbds_arrlast(a), stbds_header(a)->length -= 1) -#define stbds_arrinsn(a,i,n) (stbds_arraddn((a),(n)), memmove(&(a)[(i)+(n)], &(a)[i], sizeof *(a) * (stbds_header(a)->length-(n)-(i)))) -#define stbds_arrins(a,i,v) (stbds_arrinsn((a),(i),1), (a)[i]=(v)) +#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) ((void)(stbds_arraddnindex(a, n))) // deprecated, use one of the following instead: +#define stbds_arraddnptr(a, n) (stbds_arrmaybegrow(a, n), (n) ? (stbds_header(a)->length += (n), &(a)[stbds_header(a)->length - (n)]) : (a)) +#define stbds_arraddnindex(a, n) (stbds_arrmaybegrow(a, n), (n) ? (stbds_header(a)->length += (n), stbds_header(a)->length - (n)) : stbds_arrlen(a)) +#define stbds_arraddnoff stbds_arraddnindex +#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) +#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)) +#define stbds_arrdelswap(a, i) ((a)[i] = stbds_arrlast(a), stbds_header(a)->length -= 1) +#define stbds_arrinsn(a, i, n) (stbds_arraddn((a), (n)), memmove(&(a)[(i) + (n)], &(a)[i], sizeof *(a) * (stbds_header(a)->length - (n) - (i)))) +#define stbds_arrins(a, i, v) (stbds_arrinsn((a), (i), 1), (a)[i] = (v)) -#define stbds_arrmaybegrow(a,n) ((!(a) || stbds_header(a)->length + (n) > stbds_header(a)->capacity) \ - ? (stbds_arrgrow(a,n,0),0) : 0) +#define stbds_arrmaybegrow(a, n) ((!(a) || stbds_header(a)->length + (n) > stbds_header(a)->capacity) \ + ? (stbds_arrgrow(a, n, 0), 0) \ + : 0) -#define stbds_arrgrow(a,b,c) ((a) = stbds_arrgrowf_wrapper((a), sizeof *(a), (b), (c))) +#define stbds_arrgrow(a, b, c) ((a) = stbds_arrgrowf_wrapper((a), sizeof *(a), (b), (c))) #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)].value = (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)].value = (v)) #define stbds_hmputs(t, s) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), &(s).key, sizeof (s).key, STBDS_HM_BINARY), \ - (t)[stbds_temp((t)-1)] = (s)) + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), &(s).key, sizeof(s).key, STBDS_HM_BINARY), \ + (t)[stbds_temp((t) - 1)] = (s)) -#define stbds_hmgeti(t,k) \ - ((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(t, k) \ + ((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_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)]) + ((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]) + ((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) +#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) #define stbds_hmdefault(t, v) \ - ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1].value = (v)) + ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1].value = (v)) #define stbds_hmdefaults(t, s) \ - ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1] = (s)) + ((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)),0 : 0),(p)=NULL) +#define stbds_hmfree(p) \ + ((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_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_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)) + ((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)) + ((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), \ - (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 + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*)(s).key, sizeof(s).key, STBDS_HM_STRING), \ + (t)[stbds_temp((t) - 1)] = (s), \ + (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 #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)) + ((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_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_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)]) + ((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)]) + ((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_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_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)) + ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_STRDUP)) -#define stbds_shdefault(t, v) stbds_hmdefault(t,v) -#define stbds_shdefaults(t, s) stbds_hmdefaults(t,s) +#define stbds_shdefault(t, v) stbds_hmdefault(t, v) +#define stbds_shdefaults(t, s) stbds_hmdefaults(t, s) -#define stbds_shfree stbds_hmfree -#define stbds_shlenu stbds_hmlenu +#define stbds_shfree stbds_hmfree +#define stbds_shlenu stbds_hmlenu -#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 +#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 { - size_t length; - size_t capacity; - void * hash_table; - ptrdiff_t temp; + size_t length; + size_t capacity; + void* hash_table; + ptrdiff_t temp; } stbds_array_header; -typedef struct stbds_string_block -{ - struct stbds_string_block *next; - char storage[8]; +typedef struct stbds_string_block { + struct stbds_string_block* next; + char storage[8]; } stbds_string_block; -struct stbds_string_arena -{ - stbds_string_block *storage; - size_t remaining; - unsigned char block; - unsigned char mode; // this isn't used by the string arena itself +struct stbds_string_arena { + stbds_string_block* storage; + size_t remaining; + unsigned char block; + 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 +enum { + STBDS_SH_NONE, + STBDS_SH_DEFAULT, + STBDS_SH_STRDUP, + STBDS_SH_ARENA }; #ifdef __cplusplus // in C we use implicit assignment from these void*-returning functions to T*. // in C++ these templates make the same code work -template static T * stbds_arrgrowf_wrapper(T *a, size_t elemsize, size_t addlen, size_t min_cap) { - return (T*)stbds_arrgrowf((void *)a, elemsize, addlen, min_cap); +template +static T* stbds_arrgrowf_wrapper(T* a, size_t elemsize, size_t addlen, size_t min_cap) { + return (T*)stbds_arrgrowf((void*)a, elemsize, addlen, min_cap); } -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_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_ts((void*)a, elemsize, key, keysize, temp, 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_ts((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); +template +static T* stbds_hmput_default_wrapper(T* a, size_t elemsize) { + return (T*)stbds_hmput_default((void*)a, elemsize); } -template static T * stbds_hmput_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) { - return (T*)stbds_hmput_key((void*)a, elemsize, key, keysize, mode); +template +static T* stbds_hmput_key_wrapper(T* a, size_t elemsize, void* key, size_t keysize, int mode) { + return (T*)stbds_hmput_key((void*)a, elemsize, key, keysize, mode); } -template static T * stbds_hmdel_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode){ - return (T*)stbds_hmdel_key((void*)a, elemsize, key, keysize, keyoffset, mode); +template +static T* stbds_hmdel_key_wrapper(T* a, size_t elemsize, void* key, size_t keysize, size_t keyoffset, int mode) { + return (T*)stbds_hmdel_key((void*)a, elemsize, key, keysize, keyoffset, mode); } -template static T * stbds_shmode_func_wrapper(T *, size_t elemsize, int mode) { - return (T*)stbds_shmode_func(elemsize, mode); +template +static T* stbds_shmode_func_wrapper(T*, size_t elemsize, int mode) { + return (T*)stbds_shmode_func(elemsize, mode); } #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 -#define stbds_shmode_func_wrapper(t,e,m) stbds_shmode_func(e,m) +#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 +#define stbds_shmode_func_wrapper(t, e, m) stbds_shmode_func(e, m) #endif #endif // INCLUDE_STB_DS_H - ////////////////////////////////////////////////////////////////////////////// // // IMPLEMENTATION @@ -735,11 +739,11 @@ template static T * stbds_shmode_func_wrapper(T *, size_t elemsize, int #ifndef STBDS_ASSERT #define STBDS_ASSERT_WAS_UNDEFINED -#define STBDS_ASSERT(x) ((void) 0) +#define STBDS_ASSERT(x) ((void)0) #endif #ifdef STBDS_STATISTICS -#define STBDS_STATS(x) x +#define STBDS_STATS(x) x size_t stbds_array_grow; size_t stbds_hash_grow; size_t stbds_hash_shrink; @@ -756,50 +760,48 @@ size_t stbds_rehash_items; // stbds_arr implementation // -//int *prev_allocs[65536]; -//int num_prev; +// int *prev_allocs[65536]; +// int num_prev; -void *stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap) -{ - stbds_array_header temp={0}; // force debugging - void *b; - size_t min_len = stbds_arrlen(a) + addlen; - (void) sizeof(temp); +void* stbds_arrgrowf(void* a, size_t elemsize, size_t addlen, size_t min_cap) { + stbds_array_header temp = {0}; // force debugging + void* b; + size_t min_len = stbds_arrlen(a) + addlen; + (void)sizeof(temp); - // compute the minimum capacity needed - if (min_len > min_cap) - min_cap = min_len; + // compute the minimum capacity needed + if(min_len > min_cap) + min_cap = min_len; - if (min_cap <= stbds_arrcap(a)) - return a; + if(min_cap <= stbds_arrcap(a)) + return a; - // increase needed capacity to guarantee O(1) amortized - if (min_cap < 2 * stbds_arrcap(a)) - min_cap = 2 * stbds_arrcap(a); - else if (min_cap < 4) - min_cap = 4; + // increase needed capacity to guarantee O(1) amortized + if(min_cap < 2 * stbds_arrcap(a)) + min_cap = 2 * stbds_arrcap(a); + 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; - stbds_header(b)->hash_table = 0; - stbds_header(b)->temp = 0; - } else { - STBDS_STATS(++stbds_array_grow); - } - stbds_header(b)->capacity = min_cap; + // 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; + stbds_header(b)->hash_table = 0; + stbds_header(b)->temp = 0; + } else { + STBDS_STATS(++stbds_array_grow); + } + stbds_header(b)->capacity = min_cap; - return b; + return b; } -void stbds_arrfreef(void *a) -{ - STBDS_FREE(NULL, stbds_header(a)); +void stbds_arrfreef(void* a) { + STBDS_FREE(NULL, stbds_header(a)); } // @@ -807,227 +809,221 @@ void stbds_arrfreef(void *a) // #ifdef STBDS_INTERNAL_SMALL_BUCKET -#define STBDS_BUCKET_LENGTH 4 +#define STBDS_BUCKET_LENGTH 4 #else -#define STBDS_BUCKET_LENGTH 8 +#define STBDS_BUCKET_LENGTH 8 #endif -#define STBDS_BUCKET_SHIFT (STBDS_BUCKET_LENGTH == 8 ? 3 : 2) -#define STBDS_BUCKET_MASK (STBDS_BUCKET_LENGTH-1) -#define STBDS_CACHE_LINE_SIZE 64 +#define STBDS_BUCKET_SHIFT (STBDS_BUCKET_LENGTH == 8 ? 3 : 2) +#define STBDS_BUCKET_MASK (STBDS_BUCKET_LENGTH - 1) +#define STBDS_CACHE_LINE_SIZE 64 -#define STBDS_ALIGN_FWD(n,a) (((n) + (a) - 1) & ~((a)-1)) +#define STBDS_ALIGN_FWD(n, a) (((n) + (a) - 1) & ~((a) - 1)) typedef struct { - size_t hash [STBDS_BUCKET_LENGTH]; - ptrdiff_t index[STBDS_BUCKET_LENGTH]; + size_t hash[STBDS_BUCKET_LENGTH]; + ptrdiff_t index[STBDS_BUCKET_LENGTH]; } stbds_hash_bucket; // in 32-bit, this is one 64-byte cache line; in 64-bit, each array is one 64-byte cache line typedef struct { - char * temp_key; // this MUST be the first field of the hash table - size_t slot_count; - size_t used_count; - size_t used_count_threshold; - size_t used_count_shrink_threshold; - size_t tombstone_count; - size_t tombstone_count_threshold; - size_t seed; - size_t slot_count_log2; - stbds_string_arena string; - stbds_hash_bucket *storage; // not a separate allocation, just 64-byte aligned storage after this struct + char* temp_key; // this MUST be the first field of the hash table + size_t slot_count; + size_t used_count; + size_t used_count_threshold; + size_t used_count_shrink_threshold; + size_t tombstone_count; + size_t tombstone_count_threshold; + size_t seed; + size_t slot_count_log2; + stbds_string_arena string; + stbds_hash_bucket* storage; // not a separate allocation, just 64-byte aligned storage after this struct } stbds_hash_index; -#define STBDS_INDEX_EMPTY -1 -#define STBDS_INDEX_DELETED -2 -#define STBDS_INDEX_IN_USE(x) ((x) >= 0) +#define STBDS_INDEX_EMPTY -1 +#define STBDS_INDEX_DELETED -2 +#define STBDS_INDEX_IN_USE(x) ((x) >= 0) -#define STBDS_HASH_EMPTY 0 -#define STBDS_HASH_DELETED 1 +#define STBDS_HASH_EMPTY 0 +#define STBDS_HASH_DELETED 1 -static size_t stbds_hash_seed=0x31415926; +static size_t stbds_hash_seed = 0x31415926; -void stbds_rand_seed(size_t seed) -{ - stbds_hash_seed = seed; +void stbds_rand_seed(size_t seed) { + stbds_hash_seed = seed; } -#define stbds_load_32_or_64(var, temp, v32, v64_hi, v64_lo) \ - temp = v64_lo ^ v32, temp <<= 16, temp <<= 16, temp >>= 16, temp >>= 16, /* discard if 32-bit */ \ - var = v64_hi, var <<= 16, var <<= 16, /* discard if 32-bit */ \ - var ^= temp ^ v32 +#define stbds_load_32_or_64(var, temp, v32, v64_hi, v64_lo) \ + temp = v64_lo ^ v32, temp <<= 16, temp <<= 16, temp >>= 16, temp >>= 16, /* discard if 32-bit */ \ + var = v64_hi, var <<= 16, var <<= 16, /* discard if 32-bit */ \ + var ^= temp ^ v32 -#define STBDS_SIZE_T_BITS ((sizeof (size_t)) * 8) +#define STBDS_SIZE_T_BITS ((sizeof(size_t)) * 8) -static size_t stbds_probe_position(size_t hash, size_t slot_count, size_t slot_log2) -{ - size_t pos; - STBDS_NOTUSED(slot_log2); - pos = hash & (slot_count-1); - #ifdef STBDS_INTERNAL_BUCKET_START - pos &= ~STBDS_BUCKET_MASK; - #endif - return pos; +static size_t stbds_probe_position(size_t hash, size_t slot_count, size_t slot_log2) { + size_t pos; + STBDS_NOTUSED(slot_log2); + pos = hash & (slot_count - 1); +#ifdef STBDS_INTERNAL_BUCKET_START + pos &= ~STBDS_BUCKET_MASK; +#endif + return pos; } -static size_t stbds_log2(size_t slot_count) -{ - size_t n=0; - while (slot_count > 1) { - slot_count >>= 1; - ++n; - } - return n; +static size_t stbds_log2(size_t slot_count) { + size_t n = 0; + while(slot_count > 1) { + slot_count >>= 1; + ++n; + } + return n; } -static stbds_hash_index *stbds_make_hash_index(size_t slot_count, stbds_hash_index *ot) -{ - stbds_hash_index *t; - 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); - t->storage = (stbds_hash_bucket *) STBDS_ALIGN_FWD((size_t) (t+1), STBDS_CACHE_LINE_SIZE); - t->slot_count = slot_count; - t->slot_count_log2 = stbds_log2(slot_count); - t->tombstone_count = 0; - t->used_count = 0; +static stbds_hash_index* stbds_make_hash_index(size_t slot_count, stbds_hash_index* ot) { + stbds_hash_index* t; + 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); + t->storage = (stbds_hash_bucket*)STBDS_ALIGN_FWD((size_t)(t + 1), STBDS_CACHE_LINE_SIZE); + t->slot_count = slot_count; + t->slot_count_log2 = stbds_log2(slot_count); + t->tombstone_count = 0; + t->used_count = 0; - #if 0 // A1 +#if 0 // A1 t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink - #elif 1 // A2 - //t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow - //t->tombstone_count_threshold = slot_count* 3/16; // if tombstones are 3/16th of table, rebuild - //t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink +#elif 1 // A2 + // t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow + // t->tombstone_count_threshold = slot_count* 3/16; // if tombstones are 3/16th of table, rebuild + // t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink - // compute without overflowing - t->used_count_threshold = slot_count - (slot_count>>2); - t->tombstone_count_threshold = (slot_count>>3) + (slot_count>>4); - t->used_count_shrink_threshold = slot_count >> 2; + // compute without overflowing + t->used_count_threshold = slot_count - (slot_count >> 2); + t->tombstone_count_threshold = (slot_count >> 3) + (slot_count >> 4); + t->used_count_shrink_threshold = slot_count >> 2; - #elif 0 // B1 - t->used_count_threshold = slot_count*13/16; // if 13/16th of table is occupied, grow - t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild - t->used_count_shrink_threshold = slot_count* 5/16; // if table is only 5/16th full, shrink - #else // C1 - t->used_count_threshold = slot_count*14/16; // if 14/16th of table is occupied, grow - t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild - t->used_count_shrink_threshold = slot_count* 6/16; // if table is only 6/16th full, shrink - #endif - // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 - // Note that the larger tables have high variance as they were run fewer times - // A1 A2 B1 C1 - // 0.10ms : 0.10ms : 0.10ms : 0.11ms : 2,000 inserts creating 2K table - // 0.96ms : 0.95ms : 0.97ms : 1.04ms : 20,000 inserts creating 20K table - // 14.48ms : 14.46ms : 10.63ms : 11.00ms : 200,000 inserts creating 200K table - // 195.74ms : 196.35ms : 203.69ms : 214.92ms : 2,000,000 inserts creating 2M table - // 2193.88ms : 2209.22ms : 2285.54ms : 2437.17ms : 20,000,000 inserts creating 20M table - // 65.27ms : 53.77ms : 65.33ms : 65.47ms : 500,000 inserts & deletes in 2K table - // 72.78ms : 62.45ms : 71.95ms : 72.85ms : 500,000 inserts & deletes in 20K table - // 89.47ms : 77.72ms : 96.49ms : 96.75ms : 500,000 inserts & deletes in 200K table - // 97.58ms : 98.14ms : 97.18ms : 97.53ms : 500,000 inserts & deletes in 2M table - // 118.61ms : 119.62ms : 120.16ms : 118.86ms : 500,000 inserts & deletes in 20M table - // 192.11ms : 194.39ms : 196.38ms : 195.73ms : 500,000 inserts & deletes in 200M table +#elif 0 // B1 + t->used_count_threshold = slot_count * 13 / 16; // if 13/16th of table is occupied, grow + t->tombstone_count_threshold = slot_count * 2 / 16; // if tombstones are 2/16th of table, rebuild + t->used_count_shrink_threshold = slot_count * 5 / 16; // if table is only 5/16th full, shrink +#else // C1 + t->used_count_threshold = slot_count * 14 / 16; // if 14/16th of table is occupied, grow + t->tombstone_count_threshold = slot_count * 2 / 16; // if tombstones are 2/16th of table, rebuild + t->used_count_shrink_threshold = slot_count * 6 / 16; // if table is only 6/16th full, shrink +#endif + // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 + // Note that the larger tables have high variance as they were run fewer times + // A1 A2 B1 C1 + // 0.10ms : 0.10ms : 0.10ms : 0.11ms : 2,000 inserts creating 2K table + // 0.96ms : 0.95ms : 0.97ms : 1.04ms : 20,000 inserts creating 20K table + // 14.48ms : 14.46ms : 10.63ms : 11.00ms : 200,000 inserts creating 200K table + // 195.74ms : 196.35ms : 203.69ms : 214.92ms : 2,000,000 inserts creating 2M table + // 2193.88ms : 2209.22ms : 2285.54ms : 2437.17ms : 20,000,000 inserts creating 20M table + // 65.27ms : 53.77ms : 65.33ms : 65.47ms : 500,000 inserts & deletes in 2K table + // 72.78ms : 62.45ms : 71.95ms : 72.85ms : 500,000 inserts & deletes in 20K table + // 89.47ms : 77.72ms : 96.49ms : 96.75ms : 500,000 inserts & deletes in 200K table + // 97.58ms : 98.14ms : 97.18ms : 97.53ms : 500,000 inserts & deletes in 2M table + // 118.61ms : 119.62ms : 120.16ms : 118.86ms : 500,000 inserts & deletes in 20M table + // 192.11ms : 194.39ms : 196.38ms : 195.73ms : 500,000 inserts & deletes in 200M table - if (slot_count <= STBDS_BUCKET_LENGTH) - t->used_count_shrink_threshold = 0; - // to avoid infinite loop, we need to guarantee that at least one slot is empty and will terminate probes - STBDS_ASSERT(t->used_count_threshold + t->tombstone_count_threshold < t->slot_count); - STBDS_STATS(++stbds_hash_alloc); - if (ot) { - t->string = ot->string; - // reuse old seed so we can reuse old hashes so below "copy out old data" doesn't do any hashing - t->seed = ot->seed; - } else { - size_t a,b,temp; - memset(&t->string, 0, sizeof(t->string)); - t->seed = stbds_hash_seed; - // LCG - // in 32-bit, a = 2147001325 b = 715136305 - // in 64-bit, a = 2862933555777941757 b = 3037000493 - stbds_load_32_or_64(a,temp, 2147001325, 0x27bb2ee6, 0x87b0b0fd); - stbds_load_32_or_64(b,temp, 715136305, 0, 0xb504f32d); - stbds_hash_seed = stbds_hash_seed * a + b; - } + if(slot_count <= STBDS_BUCKET_LENGTH) + t->used_count_shrink_threshold = 0; + // to avoid infinite loop, we need to guarantee that at least one slot is empty and will terminate probes + STBDS_ASSERT(t->used_count_threshold + t->tombstone_count_threshold < t->slot_count); + STBDS_STATS(++stbds_hash_alloc); + if(ot) { + t->string = ot->string; + // reuse old seed so we can reuse old hashes so below "copy out old data" doesn't do any hashing + t->seed = ot->seed; + } else { + size_t a, b, temp; + memset(&t->string, 0, sizeof(t->string)); + t->seed = stbds_hash_seed; + // LCG + // in 32-bit, a = 2147001325 b = 715136305 + // in 64-bit, a = 2862933555777941757 b = 3037000493 + stbds_load_32_or_64(a, temp, 2147001325, 0x27bb2ee6, 0x87b0b0fd); + stbds_load_32_or_64(b, temp, 715136305, 0, 0xb504f32d); + stbds_hash_seed = stbds_hash_seed * a + b; + } - { - size_t i,j; - for (i=0; i < slot_count >> STBDS_BUCKET_SHIFT; ++i) { - stbds_hash_bucket *b = &t->storage[i]; - for (j=0; j < STBDS_BUCKET_LENGTH; ++j) - b->hash[j] = STBDS_HASH_EMPTY; - for (j=0; j < STBDS_BUCKET_LENGTH; ++j) - b->index[j] = STBDS_INDEX_EMPTY; - } - } + { + size_t i, j; + for(i = 0; i < slot_count >> STBDS_BUCKET_SHIFT; ++i) { + stbds_hash_bucket* b = &t->storage[i]; + for(j = 0; j < STBDS_BUCKET_LENGTH; ++j) + b->hash[j] = STBDS_HASH_EMPTY; + for(j = 0; j < STBDS_BUCKET_LENGTH; ++j) + b->index[j] = STBDS_INDEX_EMPTY; + } + } - // copy out the old data, if any - if (ot) { - size_t i,j; - t->used_count = ot->used_count; - for (i=0; i < ot->slot_count >> STBDS_BUCKET_SHIFT; ++i) { - stbds_hash_bucket *ob = &ot->storage[i]; - for (j=0; j < STBDS_BUCKET_LENGTH; ++j) { - if (STBDS_INDEX_IN_USE(ob->index[j])) { - size_t hash = ob->hash[j]; - size_t pos = stbds_probe_position(hash, t->slot_count, t->slot_count_log2); - size_t step = STBDS_BUCKET_LENGTH; - STBDS_STATS(++stbds_rehash_items); - for (;;) { - size_t limit,z; - stbds_hash_bucket *bucket; - bucket = &t->storage[pos >> STBDS_BUCKET_SHIFT]; - STBDS_STATS(++stbds_rehash_probes); + // copy out the old data, if any + if(ot) { + size_t i, j; + t->used_count = ot->used_count; + for(i = 0; i < ot->slot_count >> STBDS_BUCKET_SHIFT; ++i) { + stbds_hash_bucket* ob = &ot->storage[i]; + for(j = 0; j < STBDS_BUCKET_LENGTH; ++j) { + if(STBDS_INDEX_IN_USE(ob->index[j])) { + size_t hash = ob->hash[j]; + size_t pos = stbds_probe_position(hash, t->slot_count, t->slot_count_log2); + size_t step = STBDS_BUCKET_LENGTH; + STBDS_STATS(++stbds_rehash_items); + for(;;) { + size_t limit, z; + stbds_hash_bucket* bucket; + bucket = &t->storage[pos >> STBDS_BUCKET_SHIFT]; + STBDS_STATS(++stbds_rehash_probes); - for (z=pos & STBDS_BUCKET_MASK; z < STBDS_BUCKET_LENGTH; ++z) { - if (bucket->hash[z] == 0) { - bucket->hash[z] = hash; - bucket->index[z] = ob->index[j]; - goto done; - } - } + for(z = pos & STBDS_BUCKET_MASK; z < STBDS_BUCKET_LENGTH; ++z) { + if(bucket->hash[z] == 0) { + bucket->hash[z] = hash; + bucket->index[z] = ob->index[j]; + goto done; + } + } - limit = pos & STBDS_BUCKET_MASK; - for (z = 0; z < limit; ++z) { - if (bucket->hash[z] == 0) { - bucket->hash[z] = hash; - bucket->index[z] = ob->index[j]; - goto done; - } - } + limit = pos & STBDS_BUCKET_MASK; + for(z = 0; z < limit; ++z) { + if(bucket->hash[z] == 0) { + bucket->hash[z] = hash; + bucket->index[z] = ob->index[j]; + goto done; + } + } - pos += step; // quadratic probing - step += STBDS_BUCKET_LENGTH; - pos &= (t->slot_count-1); - } - } - done: - ; - } - } - } + pos += step; // quadratic probing + step += STBDS_BUCKET_LENGTH; + pos &= (t->slot_count - 1); + } + } + done:; + } + } + } - return t; + return t; } -#define STBDS_ROTATE_LEFT(val, n) (((val) << (n)) | ((val) >> (STBDS_SIZE_T_BITS - (n)))) -#define STBDS_ROTATE_RIGHT(val, n) (((val) >> (n)) | ((val) << (STBDS_SIZE_T_BITS - (n)))) +#define STBDS_ROTATE_LEFT(val, n) (((val) << (n)) | ((val) >> (STBDS_SIZE_T_BITS - (n)))) +#define STBDS_ROTATE_RIGHT(val, n) (((val) >> (n)) | ((val) << (STBDS_SIZE_T_BITS - (n)))) -size_t stbds_hash_string(char *str, size_t seed) -{ - size_t hash = seed; - while (*str) - hash = STBDS_ROTATE_LEFT(hash, 9) + (unsigned char) *str++; +size_t stbds_hash_string(char* str, size_t seed) { + size_t hash = seed; + while(*str) + hash = STBDS_ROTATE_LEFT(hash, 9) + (unsigned char)*str++; - // Thomas Wang 64-to-32 bit mix function, hopefully also works in 32 bits - hash ^= seed; - hash = (~hash) + (hash << 18); - hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,31); - hash = hash * 21; - hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,11); - hash += (hash << 6); - hash ^= STBDS_ROTATE_RIGHT(hash,22); - return hash+seed; + // Thomas Wang 64-to-32 bit mix function, hopefully also works in 32 bits + hash ^= seed; + hash = (~hash) + (hash << 18); + hash ^= hash ^ STBDS_ROTATE_RIGHT(hash, 31); + hash = hash * 21; + hash ^= hash ^ STBDS_ROTATE_RIGHT(hash, 11); + hash += (hash << 6); + hash ^= STBDS_ROTATE_RIGHT(hash, 22); + return hash + seed; } #ifdef STBDS_SIPHASH_2_4 @@ -1045,84 +1041,100 @@ typedef int STBDS_SIPHASH_2_4_can_only_be_used_in_64_bit_builds[sizeof(size_t) = #ifdef _MSC_VER #pragma warning(push) -#pragma warning(disable:4127) // conditional expression is constant, for do..while(0) and sizeof()== +#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; - size_t i,j; - size_t v0,v1,v2,v3, data; +static size_t stbds_siphash_bytes(void* p, size_t len, size_t seed) { + unsigned char* d = (unsigned char*)p; + size_t i, j; + size_t v0, v1, v2, v3, data; - // hash that works on 32- or 64-bit registers without knowing which we have - // (computes different results on 32-bit and 64-bit platform) - // derived from siphash, but on 32-bit platforms very different as it uses 4 32-bit state not 4 64-bit - v0 = ((((size_t) 0x736f6d65 << 16) << 16) + 0x70736575) ^ seed; - v1 = ((((size_t) 0x646f7261 << 16) << 16) + 0x6e646f6d) ^ ~seed; - v2 = ((((size_t) 0x6c796765 << 16) << 16) + 0x6e657261) ^ seed; - v3 = ((((size_t) 0x74656462 << 16) << 16) + 0x79746573) ^ ~seed; + // hash that works on 32- or 64-bit registers without knowing which we have + // (computes different results on 32-bit and 64-bit platform) + // derived from siphash, but on 32-bit platforms very different as it uses 4 32-bit state not 4 64-bit + v0 = ((((size_t)0x736f6d65 << 16) << 16) + 0x70736575) ^ seed; + v1 = ((((size_t)0x646f7261 << 16) << 16) + 0x6e646f6d) ^ ~seed; + v2 = ((((size_t)0x6c796765 << 16) << 16) + 0x6e657261) ^ seed; + v3 = ((((size_t)0x74656462 << 16) << 16) + 0x79746573) ^ ~seed; - #ifdef STBDS_TEST_SIPHASH_2_4 - // hardcoded with key material in the siphash test vectors - v0 ^= 0x0706050403020100ull ^ seed; - v1 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; - v2 ^= 0x0706050403020100ull ^ seed; - v3 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; - #endif +#ifdef STBDS_TEST_SIPHASH_2_4 + // hardcoded with key material in the siphash test vectors + v0 ^= 0x0706050403020100ull ^ seed; + v1 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; + v2 ^= 0x0706050403020100ull ^ seed; + v3 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; +#endif - #define STBDS_SIPROUND() \ - do { \ - v0 += v1; v1 = STBDS_ROTATE_LEFT(v1, 13); v1 ^= v0; v0 = STBDS_ROTATE_LEFT(v0,STBDS_SIZE_T_BITS/2); \ - v2 += v3; v3 = STBDS_ROTATE_LEFT(v3, 16); v3 ^= v2; \ - v2 += v1; v1 = STBDS_ROTATE_LEFT(v1, 17); v1 ^= v2; v2 = STBDS_ROTATE_LEFT(v2,STBDS_SIZE_T_BITS/2); \ - v0 += v3; v3 = STBDS_ROTATE_LEFT(v3, 21); v3 ^= v0; \ - } while (0) +#define STBDS_SIPROUND() \ + do { \ + v0 += v1; \ + v1 = STBDS_ROTATE_LEFT(v1, 13); \ + v1 ^= v0; \ + v0 = STBDS_ROTATE_LEFT(v0, STBDS_SIZE_T_BITS / 2); \ + v2 += v3; \ + v3 = STBDS_ROTATE_LEFT(v3, 16); \ + v3 ^= v2; \ + v2 += v1; \ + v1 = STBDS_ROTATE_LEFT(v1, 17); \ + v1 ^= v2; \ + v2 = STBDS_ROTATE_LEFT(v2, STBDS_SIZE_T_BITS / 2); \ + v0 += v3; \ + v3 = STBDS_ROTATE_LEFT(v3, 21); \ + v3 ^= v0; \ + } while(0) - for (i=0; i+sizeof(size_t) <= len; i += sizeof(size_t), d += sizeof(size_t)) { - data = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); - data |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // discarded if size_t == 4 + for(i = 0; i + sizeof(size_t) <= len; i += sizeof(size_t), d += sizeof(size_t)) { + data = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); + data |= (size_t)(d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // discarded if size_t == 4 - v3 ^= data; - for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) - STBDS_SIPROUND(); - v0 ^= data; - } - data = len << (STBDS_SIZE_T_BITS-8); - switch (len - i) { - case 7: data |= ((size_t) d[6] << 24) << 24; // fall through - case 6: data |= ((size_t) d[5] << 20) << 20; // fall through - case 5: data |= ((size_t) d[4] << 16) << 16; // fall through - case 4: data |= (d[3] << 24); // fall through - case 3: data |= (d[2] << 16); // fall through - case 2: data |= (d[1] << 8); // fall through - case 1: data |= d[0]; // fall through - case 0: break; - } - v3 ^= data; - for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) - STBDS_SIPROUND(); - v0 ^= data; - v2 ^= 0xff; - for (j=0; j < STBDS_SIPHASH_D_ROUNDS; ++j) - STBDS_SIPROUND(); + v3 ^= data; + for(j = 0; j < STBDS_SIPHASH_C_ROUNDS; ++j) + STBDS_SIPROUND(); + v0 ^= data; + } + data = len << (STBDS_SIZE_T_BITS - 8); + switch(len - i) { + case 7: + data |= ((size_t)d[6] << 24) << 24; // fall through + case 6: + data |= ((size_t)d[5] << 20) << 20; // fall through + case 5: + data |= ((size_t)d[4] << 16) << 16; // fall through + case 4: + data |= (d[3] << 24); // fall through + case 3: + data |= (d[2] << 16); // fall through + case 2: + data |= (d[1] << 8); // fall through + case 1: + data |= d[0]; // fall through + case 0: + break; + } + v3 ^= data; + for(j = 0; j < STBDS_SIPHASH_C_ROUNDS; ++j) + STBDS_SIPROUND(); + v0 ^= data; + v2 ^= 0xff; + for(j = 0; j < STBDS_SIPHASH_D_ROUNDS; ++j) + STBDS_SIPROUND(); #ifdef STBDS_SIPHASH_2_4 - return v0^v1^v2^v3; + return v0 ^ v1 ^ v2 ^ v3; #else - 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 + 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 #endif } -size_t stbds_hash_bytes(void *p, size_t len, size_t seed) -{ +size_t stbds_hash_bytes(void* p, size_t len, size_t seed) { #ifdef STBDS_SIPHASH_2_4 - return stbds_siphash_bytes(p,len,seed); + return stbds_siphash_bytes(p, len, seed); #else - unsigned char *d = (unsigned char *) p; + unsigned char* d = (unsigned char*)p; - if (len == 4) { - unsigned int hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); - #if 0 + if(len == 4) { + unsigned int hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); +#if 0 // HASH32-A Bob Jenkin's hash function w/o large constants hash ^= seed; hash -= (hash<<6); @@ -1133,485 +1145,480 @@ size_t stbds_hash_bytes(void *p, size_t len, size_t seed) hash -= (hash<<3); hash ^= (hash<<10); hash ^= (hash>>15); - #elif 1 - // HASH32-BB Bob Jenkin's presumably-accidental version of Thomas Wang hash with rotates turned into shifts. - // Note that converting these back to rotates makes it run a lot slower, presumably due to collisions, so I'm - // not really sure what's going on. - hash ^= seed; - hash = (hash ^ 61) ^ (hash >> 16); - hash = hash + (hash << 3); - hash = hash ^ (hash >> 4); - hash = hash * 0x27d4eb2d; - hash ^= seed; - hash = hash ^ (hash >> 15); - #else // HASH32-C - Murmur3 - hash ^= seed; - hash *= 0xcc9e2d51; - hash = (hash << 17) | (hash >> 15); - hash *= 0x1b873593; - hash ^= seed; - hash = (hash << 19) | (hash >> 13); - hash = hash*5 + 0xe6546b64; - hash ^= hash >> 16; - hash *= 0x85ebca6b; - hash ^= seed; - hash ^= hash >> 13; - hash *= 0xc2b2ae35; - hash ^= hash >> 16; - #endif - // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 - // Note that the larger tables have high variance as they were run fewer times - // HASH32-A // HASH32-BB // HASH32-C - // 0.10ms // 0.10ms // 0.10ms : 2,000 inserts creating 2K table - // 0.96ms // 0.95ms // 0.99ms : 20,000 inserts creating 20K table - // 14.69ms // 14.43ms // 14.97ms : 200,000 inserts creating 200K table - // 199.99ms // 195.36ms // 202.05ms : 2,000,000 inserts creating 2M table - // 2234.84ms // 2187.74ms // 2240.38ms : 20,000,000 inserts creating 20M table - // 55.68ms // 53.72ms // 57.31ms : 500,000 inserts & deletes in 2K table - // 63.43ms // 61.99ms // 65.73ms : 500,000 inserts & deletes in 20K table - // 80.04ms // 77.96ms // 81.83ms : 500,000 inserts & deletes in 200K table - // 100.42ms // 97.40ms // 102.39ms : 500,000 inserts & deletes in 2M table - // 119.71ms // 120.59ms // 121.63ms : 500,000 inserts & deletes in 20M table - // 185.28ms // 195.15ms // 187.74ms : 500,000 inserts & deletes in 200M table - // 15.58ms // 14.79ms // 15.52ms : 200,000 inserts creating 200K table with varying key spacing +#elif 1 + // HASH32-BB Bob Jenkin's presumably-accidental version of Thomas Wang hash with rotates turned into shifts. + // Note that converting these back to rotates makes it run a lot slower, presumably due to collisions, so I'm + // not really sure what's going on. + hash ^= seed; + hash = (hash ^ 61) ^ (hash >> 16); + hash = hash + (hash << 3); + hash = hash ^ (hash >> 4); + hash = hash * 0x27d4eb2d; + hash ^= seed; + hash = hash ^ (hash >> 15); +#else // HASH32-C - Murmur3 + hash ^= seed; + hash *= 0xcc9e2d51; + hash = (hash << 17) | (hash >> 15); + hash *= 0x1b873593; + hash ^= seed; + hash = (hash << 19) | (hash >> 13); + hash = hash * 5 + 0xe6546b64; + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= seed; + hash ^= hash >> 13; + hash *= 0xc2b2ae35; + hash ^= hash >> 16; +#endif + // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 + // Note that the larger tables have high variance as they were run fewer times + // HASH32-A // HASH32-BB // HASH32-C + // 0.10ms // 0.10ms // 0.10ms : 2,000 inserts creating 2K table + // 0.96ms // 0.95ms // 0.99ms : 20,000 inserts creating 20K table + // 14.69ms // 14.43ms // 14.97ms : 200,000 inserts creating 200K table + // 199.99ms // 195.36ms // 202.05ms : 2,000,000 inserts creating 2M table + // 2234.84ms // 2187.74ms // 2240.38ms : 20,000,000 inserts creating 20M table + // 55.68ms // 53.72ms // 57.31ms : 500,000 inserts & deletes in 2K table + // 63.43ms // 61.99ms // 65.73ms : 500,000 inserts & deletes in 20K table + // 80.04ms // 77.96ms // 81.83ms : 500,000 inserts & deletes in 200K table + // 100.42ms // 97.40ms // 102.39ms : 500,000 inserts & deletes in 2M table + // 119.71ms // 120.59ms // 121.63ms : 500,000 inserts & deletes in 20M table + // 185.28ms // 195.15ms // 187.74ms : 500,000 inserts & deletes in 200M table + // 15.58ms // 14.79ms // 15.52ms : 200,000 inserts creating 200K table with varying key spacing - return (((size_t) hash << 16 << 16) | hash) ^ seed; - } else if (len == 8 && sizeof(size_t) == 8) { - size_t hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); - hash |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // avoid warning if size_t == 4 - hash ^= seed; - hash = (~hash) + (hash << 21); - hash ^= STBDS_ROTATE_RIGHT(hash,24); - hash *= 265; - hash ^= STBDS_ROTATE_RIGHT(hash,14); - hash ^= seed; - hash *= 21; - hash ^= STBDS_ROTATE_RIGHT(hash,28); - hash += (hash << 31); - hash = (~hash) + (hash << 18); - return hash; - } else { - return stbds_siphash_bytes(p,len,seed); - } + return (((size_t)hash << 16 << 16) | hash) ^ seed; + } else if(len == 8 && sizeof(size_t) == 8) { + size_t hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); + hash |= (size_t)(d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // avoid warning if size_t == 4 + hash ^= seed; + hash = (~hash) + (hash << 21); + hash ^= STBDS_ROTATE_RIGHT(hash, 24); + hash *= 265; + hash ^= STBDS_ROTATE_RIGHT(hash, 14); + hash ^= seed; + hash *= 21; + hash ^= STBDS_ROTATE_RIGHT(hash, 28); + hash += (hash << 31); + hash = (~hash) + (hash << 18); + return hash; + } else { + return stbds_siphash_bytes(p, len, 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, size_t keyoffset, int mode, size_t i) -{ - if (mode >= STBDS_HM_STRING) - return 0==strcmp((char *) key, * (char **) ((char *) a + elemsize*i + keyoffset)); - else - return 0==memcmp(key, (char *) a + elemsize*i + keyoffset, keysize); +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 + keyoffset)); + else + return 0 == memcmp(key, (char*)a + elemsize * i + keyoffset, keysize); } -#define STBDS_HASH_TO_ARR(x,elemsize) ((char*) (x) - (elemsize)) -#define STBDS_ARR_TO_HASH(x,elemsize) ((char*) (x) + (elemsize)) +#define STBDS_HASH_TO_ARR(x, elemsize) ((char*)(x) - (elemsize)) +#define STBDS_ARR_TO_HASH(x, elemsize) ((char*)(x) + (elemsize)) -#define stbds_hash_table(a) ((stbds_hash_index *) stbds_header(a)->hash_table) +#define stbds_hash_table(a) ((stbds_hash_index*)stbds_header(a)->hash_table) -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); - } - STBDS_FREE(NULL, stbds_header(a)->hash_table); - STBDS_FREE(NULL, stbds_header(a)); +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); + } + 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, size_t keyoffset, int mode) -{ - void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); - stbds_hash_index *table = stbds_hash_table(raw_a); - size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); - size_t step = STBDS_BUCKET_LENGTH; - size_t limit,i; - size_t pos; - stbds_hash_bucket *bucket; +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); + size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key, table->seed) : stbds_hash_bytes(key, keysize, table->seed); + size_t step = STBDS_BUCKET_LENGTH; + size_t limit, i; + size_t pos; + stbds_hash_bucket* bucket; - if (hash < 2) hash += 2; // stored hash values are forbidden from being 0, so we can detect empty slots + if(hash < 2) hash += 2; // stored hash values are forbidden from being 0, so we can detect empty slots - pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); + pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); - for (;;) { - STBDS_STATS(++stbds_hash_probes); - bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + for(;;) { + STBDS_STATS(++stbds_hash_probes); + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; - // 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, keyoffset, mode, bucket->index[i])) { - return (pos & ~STBDS_BUCKET_MASK)+i; - } - } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { - return -1; - } - } + // 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, keyoffset, mode, bucket->index[i])) { + return (pos & ~STBDS_BUCKET_MASK) + i; + } + } else if(bucket->hash[i] == STBDS_HASH_EMPTY) { + return -1; + } + } - // search from beginning of bucket to pos - 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, keyoffset, mode, bucket->index[i])) { - return (pos & ~STBDS_BUCKET_MASK)+i; - } - } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { - return -1; - } - } + // search from beginning of bucket to pos + 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, keyoffset, mode, bucket->index[i])) { + return (pos & ~STBDS_BUCKET_MASK) + i; + } + } else if(bucket->hash[i] == STBDS_HASH_EMPTY) { + return -1; + } + } - // quadratic probing - pos += step; - step += STBDS_BUCKET_LENGTH; - pos &= (table->slot_count-1); - } - /* NOTREACHED */ + // quadratic probing + pos += step; + step += STBDS_BUCKET_LENGTH; + pos &= (table->slot_count - 1); + } + /* NOTREACHED */ } -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); - *temp = STBDS_INDEX_EMPTY; - // adjust a to point after the default element - return STBDS_ARR_TO_HASH(a,elemsize); - } else { - stbds_hash_index *table; - void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); - // adjust a to point to the default element - table = (stbds_hash_index *) stbds_header(raw_a)->hash_table; - if (table == 0) { - *temp = -1; - } else { - ptrdiff_t slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); - if (slot < 0) { - *temp = STBDS_INDEX_EMPTY; - } else { - stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; - *temp = b->index[slot & STBDS_BUCKET_MASK]; - } - } - return a; - } +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); + *temp = STBDS_INDEX_EMPTY; + // adjust a to point after the default element + return STBDS_ARR_TO_HASH(a, elemsize); + } else { + stbds_hash_index* table; + void* raw_a = STBDS_HASH_TO_ARR(a, elemsize); + // adjust a to point to the default element + table = (stbds_hash_index*)stbds_header(raw_a)->hash_table; + if(table == 0) { + *temp = -1; + } else { + ptrdiff_t slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); + if(slot < 0) { + *temp = STBDS_INDEX_EMPTY; + } else { + stbds_hash_bucket* b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; + *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_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: - // a is NULL <- allocate - // a has a hash table but no entries, because of shmode <- grow - // a has entries <- do nothing - if (a == NULL || stbds_header(STBDS_HASH_TO_ARR(a,elemsize))->length == 0) { - a = stbds_arrgrowf(a ? STBDS_HASH_TO_ARR(a,elemsize) : NULL, elemsize, 0, 1); - stbds_header(a)->length += 1; - memset(a, 0, elemsize); - a=STBDS_ARR_TO_HASH(a,elemsize); - } - return a; +void* stbds_hmput_default(void* a, size_t elemsize) { + // three cases: + // a is NULL <- allocate + // a has a hash table but no entries, because of shmode <- grow + // a has entries <- do nothing + if(a == NULL || stbds_header(STBDS_HASH_TO_ARR(a, elemsize))->length == 0) { + a = stbds_arrgrowf(a ? STBDS_HASH_TO_ARR(a, elemsize) : NULL, elemsize, 0, 1); + stbds_header(a)->length += 1; + memset(a, 0, elemsize); + a = STBDS_ARR_TO_HASH(a, elemsize); + } + return a; } -static char *stbds_strdup(char *str); +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; +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; - if (a == NULL) { - a = stbds_arrgrowf(0, elemsize, 0, 1); - memset(a, 0, elemsize); - stbds_header(a)->length += 1; - // adjust a to point AFTER the default element - a = STBDS_ARR_TO_HASH(a,elemsize); - } + if(a == NULL) { + a = stbds_arrgrowf(0, elemsize, 0, 1); + memset(a, 0, elemsize); + stbds_header(a)->length += 1; + // adjust a to point AFTER the default element + a = STBDS_ARR_TO_HASH(a, elemsize); + } - // adjust a to point to the default element - raw_a = a; - a = STBDS_HASH_TO_ARR(a,elemsize); + // adjust a to point to the default element + raw_a = a; + a = STBDS_HASH_TO_ARR(a, elemsize); - table = (stbds_hash_index *) stbds_header(a)->hash_table; + table = (stbds_hash_index*)stbds_header(a)->hash_table; - if (table == NULL || table->used_count >= table->used_count_threshold) { - stbds_hash_index *nt; - size_t slot_count; + if(table == NULL || table->used_count >= table->used_count_threshold) { + stbds_hash_index* nt; + size_t slot_count; - slot_count = (table == NULL) ? STBDS_BUCKET_LENGTH : table->slot_count*2; - nt = stbds_make_hash_index(slot_count, 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); - } + slot_count = (table == NULL) ? STBDS_BUCKET_LENGTH : table->slot_count * 2; + nt = stbds_make_hash_index(slot_count, 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); + } - // we iterate hash table explicitly because we want to track if we saw a tombstone - { - size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); - size_t step = STBDS_BUCKET_LENGTH; - size_t pos; - ptrdiff_t tombstone = -1; - stbds_hash_bucket *bucket; + // we iterate hash table explicitly because we want to track if we saw a tombstone + { + size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key, table->seed) : stbds_hash_bytes(key, keysize, table->seed); + size_t step = STBDS_BUCKET_LENGTH; + size_t pos; + ptrdiff_t tombstone = -1; + stbds_hash_bucket* bucket; - // stored hash values are forbidden from being 0, so we can detect empty slots to early out quickly - if (hash < 2) hash += 2; + // stored hash values are forbidden from being 0, so we can detect empty slots to early out quickly + if(hash < 2) hash += 2; - pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); + pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); - for (;;) { - size_t limit, i; - STBDS_STATS(++stbds_hash_probes); - bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + for(;;) { + size_t limit, i; + STBDS_STATS(++stbds_hash_probes); + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; - // 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, keyoffset, mode, bucket->index[i])) { - stbds_temp(a) = bucket->index[i]; - if (mode >= STBDS_HM_STRING) - stbds_temp_key(a) = * (char **) ((char *) raw_a + elemsize*bucket->index[i] + keyoffset); - return STBDS_ARR_TO_HASH(a,elemsize); - } - } else if (bucket->hash[i] == 0) { - pos = (pos & ~STBDS_BUCKET_MASK) + i; - goto found_empty_slot; - } else if (tombstone < 0) { - if (bucket->index[i] == STBDS_INDEX_DELETED) - tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); - } - } + // 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, keyoffset, mode, bucket->index[i])) { + stbds_temp(a) = bucket->index[i]; + if(mode >= STBDS_HM_STRING) + stbds_temp_key(a) = *(char**)((char*)raw_a + elemsize * bucket->index[i] + keyoffset); + return STBDS_ARR_TO_HASH(a, elemsize); + } + } else if(bucket->hash[i] == 0) { + pos = (pos & ~STBDS_BUCKET_MASK) + i; + goto found_empty_slot; + } else if(tombstone < 0) { + if(bucket->index[i] == STBDS_INDEX_DELETED) + tombstone = (ptrdiff_t)((pos & ~STBDS_BUCKET_MASK) + i); + } + } - // search from beginning of bucket to pos - 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, keyoffset, mode, bucket->index[i])) { - stbds_temp(a) = bucket->index[i]; - return STBDS_ARR_TO_HASH(a,elemsize); - } - } else if (bucket->hash[i] == 0) { - pos = (pos & ~STBDS_BUCKET_MASK) + i; - goto found_empty_slot; - } else if (tombstone < 0) { - if (bucket->index[i] == STBDS_INDEX_DELETED) - tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); - } - } + // search from beginning of bucket to pos + 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, keyoffset, mode, bucket->index[i])) { + stbds_temp(a) = bucket->index[i]; + return STBDS_ARR_TO_HASH(a, elemsize); + } + } else if(bucket->hash[i] == 0) { + pos = (pos & ~STBDS_BUCKET_MASK) + i; + goto found_empty_slot; + } else if(tombstone < 0) { + if(bucket->index[i] == STBDS_INDEX_DELETED) + tombstone = (ptrdiff_t)((pos & ~STBDS_BUCKET_MASK) + i); + } + } - // quadratic probing - pos += step; - step += STBDS_BUCKET_LENGTH; - pos &= (table->slot_count-1); - } - found_empty_slot: - if (tombstone >= 0) { - pos = tombstone; - --table->tombstone_count; - } - ++table->used_count; + // quadratic probing + pos += step; + step += STBDS_BUCKET_LENGTH; + pos &= (table->slot_count - 1); + } + found_empty_slot: + if(tombstone >= 0) { + pos = tombstone; + --table->tombstone_count; + } + ++table->used_count; - { - 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 - if ((size_t) i+1 > stbds_arrcap(a)) - *(void **) &a = stbds_arrgrowf(a, elemsize, 1, 0); - raw_a = STBDS_ARR_TO_HASH(a,elemsize); + { + 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 + if((size_t)i + 1 > stbds_arrcap(a)) + *(void**)&a = stbds_arrgrowf(a, elemsize, 1, 0); + raw_a = STBDS_ARR_TO_HASH(a, elemsize); - STBDS_ASSERT((size_t) i+1 <= stbds_arrcap(a)); - stbds_header(a)->length = i+1; - bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; - bucket->hash[pos & STBDS_BUCKET_MASK] = hash; - bucket->index[pos & STBDS_BUCKET_MASK] = i-1; - stbds_temp(a) = i-1; + STBDS_ASSERT((size_t)i + 1 <= stbds_arrcap(a)); + stbds_header(a)->length = i + 1; + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + bucket->hash[pos & STBDS_BUCKET_MASK] = hash; + bucket->index[pos & STBDS_BUCKET_MASK] = i - 1; + stbds_temp(a) = i - 1; - switch (table->string.mode) { - case STBDS_SH_STRDUP: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = stbds_strdup((char*) key); break; - case STBDS_SH_ARENA: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = stbds_stralloc(&table->string, (char*)key); break; - case STBDS_SH_DEFAULT: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = (char *) key; break; - default: memcpy((char *) a + elemsize*i, key, keysize); break; - } - } - return STBDS_ARR_TO_HASH(a,elemsize); - } + switch(table->string.mode) { + case STBDS_SH_STRDUP: + stbds_temp_key(a) = *(char**)((char*)a + elemsize * i) = stbds_strdup((char*)key); + break; + case STBDS_SH_ARENA: + stbds_temp_key(a) = *(char**)((char*)a + elemsize * i) = stbds_stralloc(&table->string, (char*)key); + break; + case STBDS_SH_DEFAULT: + stbds_temp_key(a) = *(char**)((char*)a + elemsize * i) = (char*)key; + break; + default: + memcpy((char*)a + elemsize * i, key, keysize); + break; + } + } + return STBDS_ARR_TO_HASH(a, elemsize); + } } -void * stbds_shmode_func(size_t elemsize, int mode) -{ - void *a = stbds_arrgrowf(0, elemsize, 0, 1); - stbds_hash_index *h; - 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 = (unsigned char) mode; - return STBDS_ARR_TO_HASH(a,elemsize); +void* stbds_shmode_func(size_t elemsize, int mode) { + void* a = stbds_arrgrowf(0, elemsize, 0, 1); + stbds_hash_index* h; + 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 = (unsigned char)mode; + return STBDS_ARR_TO_HASH(a, elemsize); } -void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode) -{ - if (a == NULL) { - return 0; - } else { - stbds_hash_index *table; - void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); - table = (stbds_hash_index *) stbds_header(raw_a)->hash_table; - stbds_temp(raw_a) = 0; - if (table == 0) { - return a; - } else { - ptrdiff_t slot; - slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); - if (slot < 0) - return a; - else { - stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; - int i = slot & STBDS_BUCKET_MASK; - ptrdiff_t old_index = b->index[i]; - 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' - STBDS_ASSERT(slot < (ptrdiff_t) table->slot_count); - --table->used_count; - ++table->tombstone_count; - stbds_temp(raw_a) = 1; - STBDS_ASSERT(table->used_count >= 0); - //STBDS_ASSERT(table->tombstone_count < table->slot_count/4); - b->hash[i] = STBDS_HASH_DELETED; - b->index[i] = STBDS_INDEX_DELETED; +void* stbds_hmdel_key(void* a, size_t elemsize, void* key, size_t keysize, size_t keyoffset, int mode) { + if(a == NULL) { + return 0; + } else { + stbds_hash_index* table; + void* raw_a = STBDS_HASH_TO_ARR(a, elemsize); + table = (stbds_hash_index*)stbds_header(raw_a)->hash_table; + stbds_temp(raw_a) = 0; + if(table == 0) { + return a; + } else { + ptrdiff_t slot; + slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); + if(slot < 0) + return a; + else { + stbds_hash_bucket* b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; + int i = slot & STBDS_BUCKET_MASK; + ptrdiff_t old_index = b->index[i]; + 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' + STBDS_ASSERT(slot < (ptrdiff_t)table->slot_count); + --table->used_count; + ++table->tombstone_count; + stbds_temp(raw_a) = 1; + STBDS_ASSERT(table->used_count >= 0); + // STBDS_ASSERT(table->tombstone_count < table->slot_count/4); + b->hash[i] = STBDS_HASH_DELETED; + b->index[i] = STBDS_INDEX_DELETED; - if (mode == STBDS_HM_STRING && table->string.mode == STBDS_SH_STRDUP) - STBDS_FREE(NULL, *(char**) ((char *) a+elemsize*old_index)); + if(mode == STBDS_HM_STRING && table->string.mode == STBDS_SH_STRDUP) + STBDS_FREE(NULL, *(char**)((char*)a + elemsize * old_index)); - // if indices are the same, memcpy is a no-op, but back-pointer-fixup will fail, so skip - if (old_index != final_index) { - // swap delete - memmove((char*) a + elemsize*old_index, (char*) a + elemsize*final_index, elemsize); + // if indices are the same, memcpy is a no-op, but back-pointer-fixup will fail, so skip + if(old_index != final_index) { + // swap delete + memmove((char*)a + elemsize * old_index, (char*)a + elemsize * final_index, elemsize); - // 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, keyoffset, mode); - else - 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; - STBDS_ASSERT(b->index[i] == final_index); - b->index[i] = old_index; - } - stbds_header(raw_a)->length -= 1; + // 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, keyoffset, mode); + else + 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; + STBDS_ASSERT(b->index[i] == final_index); + b->index[i] = old_index; + } + stbds_header(raw_a)->length -= 1; - if (table->used_count < table->used_count_shrink_threshold && table->slot_count > STBDS_BUCKET_LENGTH) { - stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count>>1, table); - STBDS_FREE(NULL, table); - STBDS_STATS(++stbds_hash_shrink); - } else if (table->tombstone_count > table->tombstone_count_threshold) { - stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count , table); - STBDS_FREE(NULL, table); - STBDS_STATS(++stbds_hash_rebuild); - } + if(table->used_count < table->used_count_shrink_threshold && table->slot_count > STBDS_BUCKET_LENGTH) { + stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count >> 1, table); + STBDS_FREE(NULL, table); + STBDS_STATS(++stbds_hash_shrink); + } else if(table->tombstone_count > table->tombstone_count_threshold) { + stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count, table); + STBDS_FREE(NULL, table); + STBDS_STATS(++stbds_hash_rebuild); + } - return a; - } - } - } - /* NOTREACHED */ + return a; + } + } + } + /* NOTREACHED */ } -static char *stbds_strdup(char *str) -{ - // to keep replaceable allocator simple, we don't want to use strdup. - // rolling our own also avoids problem of strdup vs _strdup - size_t len = strlen(str)+1; - char *p = (char*) STBDS_REALLOC(NULL, 0, len); - memmove(p, str, len); - return p; +static char* stbds_strdup(char* str) { + // to keep replaceable allocator simple, we don't want to use strdup. + // rolling our own also avoids problem of strdup vs _strdup + size_t len = strlen(str) + 1; + char* p = (char*)STBDS_REALLOC(NULL, 0, len); + memmove(p, str, len); + return p; } #ifndef STBDS_STRING_ARENA_BLOCKSIZE_MIN -#define STBDS_STRING_ARENA_BLOCKSIZE_MIN 512u +#define STBDS_STRING_ARENA_BLOCKSIZE_MIN 512u #endif #ifndef STBDS_STRING_ARENA_BLOCKSIZE_MAX -#define STBDS_STRING_ARENA_BLOCKSIZE_MAX (1u<<20) +#define STBDS_STRING_ARENA_BLOCKSIZE_MAX (1u << 20) #endif -char *stbds_stralloc(stbds_string_arena *a, char *str) -{ - char *p; - size_t len = strlen(str)+1; - if (len > a->remaining) { - // compute the next blocksize - size_t blocksize = a->block; +char* stbds_stralloc(stbds_string_arena* a, char* str) { + char* p; + size_t len = strlen(str) + 1; + if(len > a->remaining) { + // compute the next blocksize + size_t blocksize = a->block; - // size is 512, 512, 1024, 1024, 2048, 2048, 4096, 4096, etc., so that - // there are log(SIZE) allocations to free when we destroy the table - blocksize = (size_t) (STBDS_STRING_ARENA_BLOCKSIZE_MIN) << (blocksize>>1); + // size is 512, 512, 1024, 1024, 2048, 2048, 4096, 4096, etc., so that + // there are log(SIZE) allocations to free when we destroy the table + blocksize = (size_t)(STBDS_STRING_ARENA_BLOCKSIZE_MIN) << (blocksize >> 1); - // if size is under 1M, advance to next blocktype - if (blocksize < (size_t)(STBDS_STRING_ARENA_BLOCKSIZE_MAX)) - ++a->block; + // if size is under 1M, advance to next blocktype + if(blocksize < (size_t)(STBDS_STRING_ARENA_BLOCKSIZE_MAX)) + ++a->block; - if (len > blocksize) { - // if string is larger than blocksize, then just allocate the full size. - // note that we still advance string_block so block size will continue - // increasing, so e.g. if somebody only calls this with 1000-long strings, - // eventually the arena will start doubling and handling those as well - stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(NULL, 0, sizeof(*sb)-8 + len); - memmove(sb->storage, str, len); - if (a->storage) { - // insert it after the first element, so that we don't waste the space there - sb->next = a->storage->next; - a->storage->next = sb; - } else { - sb->next = 0; - a->storage = sb; - a->remaining = 0; // this is redundant, but good for clarity - } - return sb->storage; - } else { - stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(NULL, 0, sizeof(*sb)-8 + blocksize); - sb->next = a->storage; - a->storage = sb; - a->remaining = blocksize; - } - } + if(len > blocksize) { + // if string is larger than blocksize, then just allocate the full size. + // note that we still advance string_block so block size will continue + // increasing, so e.g. if somebody only calls this with 1000-long strings, + // eventually the arena will start doubling and handling those as well + stbds_string_block* sb = (stbds_string_block*)STBDS_REALLOC(NULL, 0, sizeof(*sb) - 8 + len); + memmove(sb->storage, str, len); + if(a->storage) { + // insert it after the first element, so that we don't waste the space there + sb->next = a->storage->next; + a->storage->next = sb; + } else { + sb->next = 0; + a->storage = sb; + a->remaining = 0; // this is redundant, but good for clarity + } + return sb->storage; + } else { + stbds_string_block* sb = (stbds_string_block*)STBDS_REALLOC(NULL, 0, sizeof(*sb) - 8 + blocksize); + sb->next = a->storage; + a->storage = sb; + a->remaining = blocksize; + } + } - STBDS_ASSERT(len <= a->remaining); - p = a->storage->storage + a->remaining - len; - a->remaining -= len; - memmove(p, str, len); - return p; + STBDS_ASSERT(len <= a->remaining); + p = a->storage->storage + a->remaining - len; + a->remaining -= len; + memmove(p, str, len); + return p; } -void stbds_strreset(stbds_string_arena *a) -{ - stbds_string_block *x,*y; - x = a->storage; - while (x) { - y = x->next; - STBDS_FREE(NULL, x); - x = y; - } - memset(a, 0, sizeof(*a)); +void stbds_strreset(stbds_string_arena* a) { + stbds_string_block *x, *y; + x = a->storage; + while(x) { + y = x->next; + STBDS_FREE(NULL, x); + x = y; + } + memset(a, 0, sizeof(*a)); } #endif @@ -1631,227 +1638,259 @@ void stbds_strreset(stbds_string_arena *a) #include #endif -typedef struct { int key,b,c,d; } stbds_struct; -typedef struct { int key[2],b,c,d; } stbds_struct2; +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) -{ +char* strkey(int n) { #if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) - sprintf_s(buffer, sizeof(buffer), "test_%d", n); + sprintf_s(buffer, sizeof(buffer), "test_%d", n); #else - sprintf(buffer, "test_%d", n); + sprintf(buffer, "test_%d", n); #endif - return buffer; + return buffer; } -void stbds_unit_tests(void) -{ +void stbds_unit_tests(void) { #if defined(_MSC_VER) && _MSC_VER <= 1200 && defined(__cplusplus) - // VC6 C++ doesn't like the template<> trick on unnamed structures, so do nothing! - STBDS_ASSERT(0); + // VC6 C++ doesn't like the template<> trick on unnamed structures, so do nothing! + 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, s; - 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; + 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, s; + 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; + int i, j; - STBDS_ASSERT(arrlen(arr)==0); - for (i=0; i < 20000; i += 50) { - for (j=0; j < i; ++j) - arrpush(arr,j); - arrfree(arr); - } + STBDS_ASSERT(arrlen(arr) == 0); + for(i = 0; i < 20000; i += 50) { + for(j = 0; j < i; ++j) + arrpush(arr, j); + arrfree(arr); + } - for (i=0; i < 4; ++i) { - arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); - arrdel(arr,i); - arrfree(arr); - arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); - arrdelswap(arr,i); - arrfree(arr); - } + for(i = 0; i < 4; ++i) { + arrpush(arr, 1); + arrpush(arr, 2); + arrpush(arr, 3); + arrpush(arr, 4); + arrdel(arr, i); + arrfree(arr); + arrpush(arr, 1); + arrpush(arr, 2); + arrpush(arr, 3); + arrpush(arr, 4); + arrdelswap(arr, i); + arrfree(arr); + } - for (i=0; i < 5; ++i) { - arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); - stbds_arrins(arr,i,5); - STBDS_ASSERT(arr[i] == 5); - if (i < 4) - STBDS_ASSERT(arr[4] == 4); - arrfree(arr); - } + for(i = 0; i < 5; ++i) { + arrpush(arr, 1); + arrpush(arr, 2); + arrpush(arr, 3); + arrpush(arr, 4); + stbds_arrins(arr, i, 5); + STBDS_ASSERT(arr[i] == 5); + if(i < 4) + STBDS_ASSERT(arr[4] == 4); + arrfree(arr); + } - i = 1; - STBDS_ASSERT(hmgeti(intmap,i) == -1); - hmdefault(intmap, -2); - STBDS_ASSERT(hmgeti(intmap, i) == -1); - 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) { - 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) - if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 ); - else STBDS_ASSERT(hmget(intmap, i) == i*3); - for (i=2; i < testsize; i+=4) - hmdel(intmap, i); // delete half the entries - for (i=0; i < testsize; i+=1) - if (i & 3) STBDS_ASSERT(hmget(intmap, i) == -2 ); - else STBDS_ASSERT(hmget(intmap, i) == i*3); - for (i=0; i < testsize; i+=1) - hmdel(intmap, i); // delete the rest of the entries - for (i=0; i < testsize; i+=1) - STBDS_ASSERT(hmget(intmap, i) == -2 ); - hmfree(intmap); - for (i=0; i < testsize; i+=2) - hmput(intmap, i, i*3); - hmfree(intmap); + i = 1; + STBDS_ASSERT(hmgeti(intmap, i) == -1); + hmdefault(intmap, -2); + STBDS_ASSERT(hmgeti(intmap, i) == -1); + 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) { + 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) + if(i & 1) STBDS_ASSERT(hmget(intmap, i) == -2); + else + STBDS_ASSERT(hmget(intmap, i) == i * 3); + for(i = 2; i < testsize; i += 4) + hmdel(intmap, i); // delete half the entries + for(i = 0; i < testsize; i += 1) + if(i & 3) STBDS_ASSERT(hmget(intmap, i) == -2); + else + STBDS_ASSERT(hmget(intmap, i) == i * 3); + for(i = 0; i < testsize; i += 1) + hmdel(intmap, i); // delete the rest of the entries + for(i = 0; i < testsize; i += 1) + STBDS_ASSERT(hmget(intmap, i) == -2); + hmfree(intmap); + for(i = 0; i < testsize; i += 2) + hmput(intmap, i, i * 3); + hmfree(intmap); - #if defined(__clang__) || defined(__GNUC__) - #ifndef __cplusplus - intmap = NULL; - hmput(intmap, 15, 7); - hmput(intmap, 11, 3); - hmput(intmap, 9, 5); - STBDS_ASSERT(hmget(intmap, 9) == 5); - STBDS_ASSERT(hmget(intmap, 11) == 3); - STBDS_ASSERT(hmget(intmap, 15) == 7); - #endif - #endif +#if defined(__clang__) || defined(__GNUC__) +#ifndef __cplusplus + intmap = NULL; + hmput(intmap, 15, 7); + hmput(intmap, 11, 3); + hmput(intmap, 9, 5); + STBDS_ASSERT(hmget(intmap, 9) == 5); + STBDS_ASSERT(hmget(intmap, 11) == 3); + STBDS_ASSERT(hmget(intmap, 15) == 7); +#endif +#endif - for (i=0; i < testsize; ++i) - stralloc(&sa, strkey(i)); - strreset(&sa); + for(i = 0; i < testsize; ++i) + stralloc(&sa, strkey(i)); + strreset(&sa); - { - s.key = "a", s.value = 1; - shputs(strmap, s); - STBDS_ASSERT(*strmap[0].key == 'a'); - STBDS_ASSERT(strmap[0].key == s.key); - STBDS_ASSERT(strmap[0].value == s.value); - shfree(strmap); - } + { + s.key = "a", s.value = 1; + shputs(strmap, s); + STBDS_ASSERT(*strmap[0].key == 'a'); + STBDS_ASSERT(strmap[0].key == s.key); + STBDS_ASSERT(strmap[0].value == s.value); + shfree(strmap); + } - { - s.key = "a", s.value = 1; - sh_new_strdup(strmap); - shputs(strmap, s); - STBDS_ASSERT(*strmap[0].key == 'a'); - STBDS_ASSERT(strmap[0].key != s.key); - STBDS_ASSERT(strmap[0].value == s.value); - shfree(strmap); - } + { + s.key = "a", s.value = 1; + sh_new_strdup(strmap); + shputs(strmap, s); + STBDS_ASSERT(*strmap[0].key == 'a'); + STBDS_ASSERT(strmap[0].key != s.key); + STBDS_ASSERT(strmap[0].value == s.value); + shfree(strmap); + } - { - s.key = "a", s.value = 1; - sh_new_arena(strmap); - shputs(strmap, s); - STBDS_ASSERT(*strmap[0].key == 'a'); - STBDS_ASSERT(strmap[0].key != s.key); - STBDS_ASSERT(strmap[0].value == s.value); - shfree(strmap); - } + { + s.key = "a", s.value = 1; + sh_new_arena(strmap); + shputs(strmap, s); + STBDS_ASSERT(*strmap[0].key == 'a'); + STBDS_ASSERT(strmap[0].key != s.key); + STBDS_ASSERT(strmap[0].value == s.value); + shfree(strmap); + } - for (j=0; j < 2; ++j) { - STBDS_ASSERT(shgeti(strmap,"foo") == -1); - if (j == 0) - sh_new_strdup(strmap); - else - sh_new_arena(strmap); - STBDS_ASSERT(shgeti(strmap,"foo") == -1); - shdefault(strmap, -2); - STBDS_ASSERT(shgeti(strmap,"foo") == -1); - for (i=0; i < testsize; i+=2) - shput(strmap, strkey(i), i*3); - for (i=0; i < testsize; i+=1) - if (i & 1) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); - else STBDS_ASSERT(shget(strmap, strkey(i)) == i*3); - for (i=2; i < testsize; i+=4) - shdel(strmap, strkey(i)); // delete half the entries - for (i=0; i < testsize; i+=1) - if (i & 3) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); - else STBDS_ASSERT(shget(strmap, strkey(i)) == i*3); - for (i=0; i < testsize; i+=1) - shdel(strmap, strkey(i)); // delete the rest of the entries - for (i=0; i < testsize; i+=1) - STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); - shfree(strmap); - } + for(j = 0; j < 2; ++j) { + STBDS_ASSERT(shgeti(strmap, "foo") == -1); + if(j == 0) + sh_new_strdup(strmap); + else + sh_new_arena(strmap); + STBDS_ASSERT(shgeti(strmap, "foo") == -1); + shdefault(strmap, -2); + STBDS_ASSERT(shgeti(strmap, "foo") == -1); + for(i = 0; i < testsize; i += 2) + shput(strmap, strkey(i), i * 3); + for(i = 0; i < testsize; i += 1) + if(i & 1) STBDS_ASSERT(shget(strmap, strkey(i)) == -2); + else + STBDS_ASSERT(shget(strmap, strkey(i)) == i * 3); + for(i = 2; i < testsize; i += 4) + shdel(strmap, strkey(i)); // delete half the entries + for(i = 0; i < testsize; i += 1) + if(i & 3) STBDS_ASSERT(shget(strmap, strkey(i)) == -2); + else + STBDS_ASSERT(shget(strmap, strkey(i)) == i * 3); + for(i = 0; i < testsize; i += 1) + shdel(strmap, strkey(i)); // delete the rest of the entries + for(i = 0; i < testsize; i += 1) + STBDS_ASSERT(shget(strmap, strkey(i)) == -2); + shfree(strmap); + } - { - struct { char *key; char value; } *hash = NULL; - char name[4] = "jen"; - shput(hash, "bob" , 'h'); - shput(hash, "sally" , 'e'); - shput(hash, "fred" , 'l'); - shput(hash, "jen" , 'x'); - shput(hash, "doug" , 'o'); + { + struct { + char* key; + char value; + }* hash = NULL; + char name[4] = "jen"; + shput(hash, "bob", 'h'); + shput(hash, "sally", 'e'); + shput(hash, "fred", 'l'); + shput(hash, "jen", 'x'); + shput(hash, "doug", 'o'); - shput(hash, name , 'l'); - shfree(hash); - } + shput(hash, name, 'l'); + shfree(hash); + } - for (i=0; i < testsize; i += 2) { - stbds_struct s = { i,i*2,i*3,i*4 }; - hmput(map, s, i*5); - } + for(i = 0; i < testsize; i += 2) { + stbds_struct s = {i, i * 2, i * 3, i * 4}; + hmput(map, s, i * 5); + } - for (i=0; i < testsize; i += 1) { - stbds_struct s = { i,i*2,i*3 ,i*4 }; - 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); - 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 += 1) { + stbds_struct s = {i, i * 2, i * 3, i * 4}; + 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); + 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) { - stbds_struct s = { i,i*2,i*3,i*4 }; - hmputs(map2, s); - } - hmfree(map); + for(i = 0; i < testsize; i += 2) { + stbds_struct s = {i, i * 2, i * 3, i * 4}; + hmputs(map2, s); + } + hmfree(map); - for (i=0; i < testsize; i += 1) { - stbds_struct s = { i,i*2,i*3,i*4 }; - 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(hmgetp(map2, t.key) == 0); - } - hmfree(map2); + for(i = 0; i < testsize; i += 1) { + stbds_struct s = {i, i * 2, i * 3, i * 4}; + 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(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); - } + 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 - /* ------------------------------------------------------------------------------ This software is available under 2 licenses -- choose whichever you prefer. diff --git a/resource/font.png b/engine/resource/font.png similarity index 100% rename from resource/font.png rename to engine/resource/font.png diff --git a/engine/tools/CMakeLists.txt b/engine/tools/CMakeLists.txt index cf0bc8f..9267760 100644 --- a/engine/tools/CMakeLists.txt +++ b/engine/tools/CMakeLists.txt @@ -3,7 +3,6 @@ include(GNUInstallDirs) macro(compile_tool name) file(GLOB ${name}_SRC ${name}/*.c) add_executable(${name} ${${name}_SRC}) - target_include_directories(${name} PRIVATE ../../external/stb) endmacro() compile_tool(gb_dumpfont) diff --git a/format.sh b/format.sh index e650534..730c50e 100755 --- a/format.sh +++ b/format.sh @@ -1,2 +1,2 @@ #!/bin/sh -clang-format --verbose -i `find include server client tools src -name "*.c" -or -name "*.h"` +clang-format --verbose -i `find engine/common engine/net engine/tools -name "*.c" -or -name "*.h"`