void hash_stats(hash_entry h[], int * tables, int * entries, int * nulls, void ** max_ptr) { int i; for(i=0; i<HASH_KEYS_PER_TABLE; i++) { if ( h[i].key == NULL ) { (*nulls)++; } else if ( h[i].key == hash_next_magic ) { (*tables)++; if ( h[i].value > *max_ptr ) { *max_ptr = h[i].value; } hash_stats(h[i].value, tables, entries, nulls, max_ptr); } else { (*entries)++; if ( (void *)h[i].key > *max_ptr ) { *max_ptr = (void *)h[i].key; } } } }
void hash_destroy (HTAB *hashp) { /* cannot destroy a shared memory hash table */ Assert(! hashp->segbase); if (hashp != NULL) { register SEG_OFFSET segNum; SEGMENT segp; int nsegs = hashp->hctl->nsegs; int j; BUCKET_INDEX *elp,p,q; ELEMENT *curr; for (segNum = 0; nsegs > 0; nsegs--, segNum++) { segp = GET_SEG(hashp,segNum); for (j = 0, elp = segp; j < hashp->hctl->ssize; j++, elp++) { for ( p = *elp; p != INVALID_INDEX; p = q ){ curr = GET_BUCKET(hashp,p); q = curr->next; MEM_FREE((char *) curr); } } free((char *)segp); } (void) MEM_FREE( (char *) hashp->dir); (void) MEM_FREE( (char *) hashp->hctl); hash_stats("destroy",hashp); (void) MEM_FREE( (char *) hashp); } }
void hash_destroy(HTAB *hashp) { if (hashp != NULL) { /* allocation method must be one we know how to free, too */ Assert(hashp->alloc == MEM_ALLOC); /* so this hashtable must have it's own context */ Assert(hashp->hcxt != NULL); hash_stats("destroy", hashp); /* * Free buckets, dir etc. by destroying the hash table's memory * context. */ MemoryContextDelete(hashp->hcxt); /* * Free the HTAB and control structure, which are allocated in the * parent context (DynaHashCxt or the context given by the caller * of hash_create()). */ MEM_FREE(hashp->hctl); MEM_FREE(hashp->tabname); MEM_FREE(hashp); } }
int main(int argc, char * argv[]) { hash_entry * myhash = NULL; FILE * words; int i=0, j=0, k=0, l=0, m=0; char buf[1024]; char * dictionary = "/usr/share/dict/words"; char * value_sentinel = "value_sentinel"; char * testwords[KEYS_IN_FLIGHT]; void * max_ptr; printf("Churning through %s, %d keys \"in flight\" at any given moment\n", dictionary, KEYS_IN_FLIGHT); bzero(testwords, KEYS_IN_FLIGHT * sizeof(char*)); words = fopen(dictionary, "r"); // rotate words in and out of the hash tables... while ( fgets(buf, sizeof(buf)-1, words) ) { j = strlen(buf); buf[j-1] = '\0'; if ( testwords[i%KEYS_IN_FLIGHT] != NULL ) { hash_clear(myhash, testwords[i%KEYS_IN_FLIGHT]); free(testwords[i%KEYS_IN_FLIGHT]); } testwords[i%KEYS_IN_FLIGHT] = malloc(j); strncpy(testwords[i%KEYS_IN_FLIGHT], buf, j); hash_set(myhash, testwords[i%KEYS_IN_FLIGHT], value_sentinel); i++; } /* // clear the remaining words, commented so that hash_stats(), etc. below // have something to operate on for(i=0; i<KEYS_IN_FLIGHT; i++) { hash_clear(myhash, testwords[i%KEYS_IN_FLIGHT]); free(testwords[i%KEYS_IN_FLIGHT]); } */ hash_dump(myhash); i = j = k = 0; max_ptr = NULL; hash_stats(myhash, &i, &j, &k, &max_ptr); printf("depth:\t: %d\n", hash_depth(myhash)); printf("tables\t: %d\nentries\t: %d\nnulls\t: %d\n", i, j, k); printf("sparseness\t:%f\n", hash_sparseness(myhash)); printf("max pointer\t:%p\n", max_ptr); return 0; }
double hash_sparseness(hash_entry h[]) { int i=0, j=0, k=0; void * max_ptr = NULL; hash_stats(h, &i, &j, &k, &max_ptr); // the sum of ( tables + non-table entries + nulls ) is the number of key/value pairs // the hash has. The number of nulls divided by this nulls gives 'sparseness', which // can be as little as zero and in the most pathological case should never be more than // (HASH_KEYS_PER_TABLE-1)/HASH_KEYS_PER_TABLE return (double)k / (double)(i + j + k); }
void hash_destroy(HTAB *hashp) { if (hashp != NULL) { /* allocation method must be one we know how to free, too */ Assert(hashp->alloc == DynaHashAlloc); /* so this hashtable must have it's own context */ Assert(hashp->hcxt != NULL); hash_stats("destroy", hashp); /* * Free everything by destroying the hash table's memory context. */ MemoryContextDelete(hashp->hcxt); } }
void test_static_mem_pool_1(void) { ranctx rctx; raninit(&rctx, 0x128e437); struct static_mem_pool pool; struct hash *hs[20] = { 0 }; const size_t HSIZE = sizeof(hs)/sizeof(hs[0]); void *pp = static_mem_pool_init( &pool , 8192 - sizeof(struct static_mem_pool) , 0 , nomem , 0 , 0 , 0 ); if( !pp ) { fprintf(stderr, "Can't setup memory pool\n"); return; } size_t i = 0; for(; i < HSIZE; i++ ) { hs[i] = hash_create( hash_size , static_mem_pool_alloc(&pool, hash_size) , sizeof(uint32_t) , sizeof(uint32_t) , 32 , uint32_hash , uint32_eq , uint32_cpy , uint32_cpy , 0 , __alloc , __dealloc ); } for(i = 0; i < 100500; i++ ) { size_t hnum = ranval(&rctx) % HSIZE; uint32_t k = ranval(&rctx) % 1000001; uint32_t v = ranval(&rctx) % 99999999; hash_add(hs[hnum], &k, &v); } for(i = 0; i < HSIZE; i++ ) { size_t cap = 0, used = 0, cls = 0, maxb = 0; hash_stats(hs[i], &cap, &used, &cls, &maxb); fprintf( stdout , "\nhash#%zu\n" "capacity: %zu\n" "used: %zu\n" "collisions (avg): %zu\n" "max. row: %zu\n" , i , cap , used , cls , maxb ); hash_destroy(hs[i]); } static_mem_pool_destroy(&pool); }