// ----------------------------------------------------------------------------- // sort/less int sort_64(const void *a, const void *b) { return 0[(uint64_t*)a] - 0[(uint64_t*)b]; } int less_int(int a, int b) { return a - b; } int less_64(uint64_t a, uint64_t b) { return a > b ? +1 : -!!(a - b); } int less_ptr(void *a, void *b) { return (uintptr_t)a > (uintptr_t)b ? +1 : -!!((uintptr_t)a - (uintptr_t)b); } int less_str(char *a, char *b) { return strcmp((const char *)a, (const char *)b); } // ----------------------------------------------------------------------------- // un/hash uint32_t unhash_32(uint32_t x) { // Thomas Mueller at https://stackoverflow.com/questions/664014/ - says no collisions for 32bits! x = ((x >> 16) ^ x) * 0x119de1f3; x = ((x >> 16) ^ x) * 0x119de1f3; x = (x >> 16) ^ x; return x; } uint32_t hash_32(uint32_t x) { // Thomas Mueller at https://stackoverflow.com/questions/664014/ - says no collisions for 32bits! x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b; x = (x >> 16) ^ x; return x; } uint64_t hash_64(uint64_t x) { #if 1 x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb); x = x ^ (x >> 31); return x; #else // should we just use x2 hash_32? uint32_t hi = (x >> 32ull), lo = (x & ~0u); return (hash_32(hi) << 32ull) | hash_32(lo); #endif } uint64_t hash_flt(double x) { union { double d; uint64_t i; } c; return c.d = x, hash_64(c.i); } uint64_t hash_str(const char* str) { uint64_t hash = 14695981039346656037ULL; // hash(0),mul(131) faster than fnv1a, a few more collisions though while( *str ) hash = ( (unsigned char)*str++ ^ hash ) * 0x100000001b3ULL; return hash; } uint64_t hash_int(int key) { return hash_32((uint32_t)key); } uint64_t hash_ptr(const void *ptr) { uint64_t key = (uint64_t)(uintptr_t)ptr; return hash_64(key); // >> 3? needed? } // ----------------------------------------------------------------------------- // utils uint64_t popcnt64(uint64_t x) { // [src] https://en.wikipedia.org/wiki/Hamming_weight x -= (x >> 1) & 0x5555555555555555ULL; //put count of each 2 bits into those 2 bits x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL); //put count of each 4 bits into those 4 bits x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL; //put count of each 8 bits into those 8 bits return (x * 0x0101010101010101ULL) >> 56; //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ... } // ----------------------------------------------------------------------------- // vector based allocator (x1.75 enlarge factor) void* vrealloc( void* p, size_t sz ) { if( !sz ) { if( p ) { size_t *ret = (size_t*)p - 2; ret[0] = 0; ret[1] = 0; REALLOC( ret, 0 ); } return 0; } else { size_t *ret; if( !p ) { ret = (size_t*)REALLOC( 0, sizeof(size_t) * 2 + sz ); ret[0] = sz; ret[1] = 0; } else { ret = (size_t*)p - 2; size_t osz = ret[0]; size_t ocp = ret[1]; if( sz <= (osz + ocp) ) { ret[0] = sz; ret[1] = ocp - (sz - osz); } else { ret = (size_t*)REALLOC( ret, sizeof(size_t) * 2 + sz * 1.75 ); ret[0] = sz; ret[1] = (size_t)(sz * 1.75) - sz; } } return &ret[2]; } } size_t vlen( void* p ) { return p ? 0[ (size_t*)p - 2 ] : 0; } // ----------------------------------------------------------------------------- enum { MAP_GC_SLOT = MAP_HASHSIZE }; typedef int map_is_pow2_assert[ !(MAP_HASHSIZE & (MAP_HASHSIZE - 1)) ? 1:-1]; static int map_get_index(uint64_t hkey1) { return hkey1 & (MAP_HASHSIZE-1); } void (map_init)(map* m) { map c = {0}; *m = c; array_resize(m->array, (MAP_HASHSIZE+1)); memset(m->array, 0, (MAP_HASHSIZE+1) * sizeof(m->array[0]) ); // array_resize() just did memset() } void (map_insert)(map* m, pair *p, void *key, void *value, uint64_t keyhash, void *super) { p->keyhash = keyhash; p->key = key; p->value = value; p->super = super; /* Insert onto the beginning of the list */ int index = map_get_index(p->keyhash); p->next = m->array[index]; m->array[index] = p; m->is_sorted = 0; ++m->count; } void* (map_find)(map* m, void *key, uint64_t keyhash) { int index = map_get_index(keyhash); for( pair *cur = m->array[index]; cur; cur = cur->next ) { if( cur->keyhash == keyhash ) { char **c = (char **)cur->key; char **k = (char **)key; if( !m->cmp(c[0], k[0]) ) { return cur->super; } } } return 0; } void (map_erase)(map* m, void *key, uint64_t keyhash) { int index = map_get_index(keyhash); for( pair *prev = 0, *cur = m->array[index]; cur; (prev = cur), (cur = cur->next) ) { if( cur->keyhash == keyhash ) { char **c = (char **)cur->key; char **k = (char **)key; if( !m->cmp(c[0], k[0]) ) { if( prev ) prev->next = cur->next; else m->array[index] = cur->next ? cur->next : 0; #if MAP_DONT_ERASE /* Insert onto the beginning of the GC list */ cur->next = m->array[MAP_GC_SLOT]; m->array[MAP_GC_SLOT] = cur; #else REALLOC(cur,0); #endif --m->count; m->is_sorted = 0; return; } } } } int (map_count)(map* m) { return m->count; int counter = 0; for( int i = 0; i < MAP_HASHSIZE; ++i) { for( pair *cur = m->array[i]; cur; cur = cur->next ) { ++counter; } } return counter; } void (map_gc)(map* m) { #if MAP_DONT_ERASE for( pair *next, *cur = m->array[MAP_GC_SLOT]; cur; cur = next ) { next = cur->next; REALLOC(cur,0); } m->array[MAP_GC_SLOT] = 0; #endif } void (map_clear)(map* m) { for( int i = 0; i <= MAP_HASHSIZE; ++i) { for( pair *next, *cur = m->array[i]; cur; cur = next ) { next = cur->next; REALLOC(cur,0); } m->array[i] = 0; } m->count = 0; m->is_sorted = 0; } bool (map_sort)(map* m) { if( m->is_sorted ) return false; array_clear(m->sorted); // array_reserve(m->sorted, m->count); for( int i = 0; i < array_count(m->array); ++i) { for( pair *cur = m->array[i]; cur; cur = cur->next ) { array_push(m->sorted, cur); } } #if 0 array_sort(m->sorted, m->cmp); #else // @fixme: do better than bubble sort below for( int i = 0; i < array_count(m->sorted) - 1; ++i) for( int j = i+1; j < array_count(m->sorted); ++j) { pair *curi = m->sorted[i]; pair *curj = m->sorted[j]; char **c = (char **)curi->key; char **k = (char **)curj->key; if( m->cmp(c[0], k[0]) > 0 ) { pair *swap = m->sorted[i]; m->sorted[i] = m->sorted[j]; m->sorted[j] = swap; } } #endif return m->is_sorted = true; } void (map_free)(map* m) { (map_clear)(m); array_free(m->array); m->array = 0; map c = {0}; *m = c; } // ----------------------------------------------------------------------------- enum { set_GC_SLOT = SET_HASHSIZE }; typedef int set_is_pow2_assert[ !(SET_HASHSIZE & (SET_HASHSIZE - 1)) ? 1:-1]; static int set_get_index(uint64_t hkey1) { return hkey1 & (SET_HASHSIZE-1); } void (set_init)(set* m) { set zero = {0}; *m = zero; array_resize(m->array, (SET_HASHSIZE+1)); memset(m->array, 0, (SET_HASHSIZE+1) * sizeof(m->array[0]) ); // array_resize() just did memset() } void (set_insert)(set* m, set_item *p, void *key, uint64_t keyhash, void *super) { p->keyhash = keyhash; p->key = key; p->super = super; /* Insert onto the beginning of the list */ int index = set_get_index(p->keyhash); p->next = m->array[index]; m->array[index] = p; ++m->count; } void* (set_find)(const set* m, void *key, uint64_t keyhash) { int index = set_get_index(keyhash); for( const set_item *cur = m->array[index]; cur; cur = cur->next ) { if( cur->keyhash == keyhash ) { char **c = (char **)cur->key; char **k = (char **)key; if( !m->cmp(c[0], k[0]) ) { return cur->super; } } } return 0; } void (set_erase)(set* m, void *key, uint64_t keyhash) { int index = set_get_index(keyhash); for( set_item *prev = 0, *cur = m->array[index]; cur; (prev = cur), (cur = cur->next) ) { if( cur->keyhash == keyhash ) { char **c = (char **)cur->key; char **k = (char **)key; if( !m->cmp(c[0], k[0]) ) { if (prev) prev->next = cur->next; else m->array[index] = cur->next ? cur->next : 0; #if SET_DONT_ERASE /* Insert onto the beginning of the GC list */ cur->next = m->array[set_GC_SLOT]; m->array[set_GC_SLOT] = cur; #else REALLOC(cur,0); #endif --m->count; return; } } } } int (set_count)(const set* m) { // does not include GC_SLOT return m->count; int counter = 0; for( int i = 0; i < SET_HASHSIZE; ++i) { for( const set_item *cur = m->array[i]; cur; cur = cur->next ) { ++counter; } } return counter; } void (set_gc)(set* m) { // clean deferred GC_SLOT only #if SET_DONT_ERASE for( set_item *next, *cur = m->array[set_GC_SLOT]; cur; cur = next ) { next = cur->next; REALLOC(cur,0); } m->array[set_GC_SLOT] = 0; #endif } void (set_clear)(set* m) { // include GC_SLOT for( int i = 0; i <= SET_HASHSIZE; ++i) { for( set_item *next, *cur = m->array[i]; cur; cur = next ) { next = cur->next; REALLOC(cur,0); } m->array[i] = 0; } m->count = 0; } void (set_free)(set* m) { (set_clear)(m); array_free(m->array); m->array = 0; set zero = {0}; *m = zero; } char *cc4str(unsigned x) { static __thread char type[4+1] = {0}; type[3] = (x >> 24ULL) & 255; type[2] = (x >> 16ULL) & 255; type[1] = (x >> 8ULL) & 255; type[0] = (x >> 0ULL) & 255; return type; } char *cc8str(uint64_t x) { static __thread char type[8+1] = {0}; type[7] = (x >> 56ULL) & 255; type[6] = (x >> 48ULL) & 255; type[5] = (x >> 40ULL) & 255; type[4] = (x >> 32ULL) & 255; type[3] = (x >> 24ULL) & 255; type[2] = (x >> 16ULL) & 255; type[1] = (x >> 8ULL) & 255; type[0] = (x >> 0ULL) & 255; return type; }