|
|
| version 1.1.1.1, 2012/02/21 17:26:12 | version 1.1.1.2, 2016/11/02 10:09:11 |
|---|---|
| Line 31 hash_create_size (unsigned int size, unsigned int (*ha | Line 31 hash_create_size (unsigned int size, unsigned int (*ha |
| { | { |
| struct hash *hash; | struct hash *hash; |
| assert ((size & (size-1)) == 0); | |
| hash = XMALLOC (MTYPE_HASH, sizeof (struct hash)); | hash = XMALLOC (MTYPE_HASH, sizeof (struct hash)); |
| hash->index = XCALLOC (MTYPE_HASH_INDEX, | hash->index = XCALLOC (MTYPE_HASH_INDEX, |
| sizeof (struct hash_backet *) * size); | sizeof (struct hash_backet *) * size); |
| hash->size = size; | hash->size = size; |
| hash->no_expand = 0; | |
| hash->hash_key = hash_key; | hash->hash_key = hash_key; |
| hash->hash_cmp = hash_cmp; | hash->hash_cmp = hash_cmp; |
| hash->count = 0; | hash->count = 0; |
| Line 47 struct hash * | Line 49 struct hash * |
| hash_create (unsigned int (*hash_key) (void *), | hash_create (unsigned int (*hash_key) (void *), |
| int (*hash_cmp) (const void *, const void *)) | int (*hash_cmp) (const void *, const void *)) |
| { | { |
| return hash_create_size (HASHTABSIZE, hash_key, hash_cmp); | return hash_create_size (HASH_INITIAL_SIZE, hash_key, hash_cmp); |
| } | } |
| /* Utility function for hash_get(). When this function is specified | /* Utility function for hash_get(). When this function is specified |
| Line 59 hash_alloc_intern (void *arg) | Line 61 hash_alloc_intern (void *arg) |
| return arg; | return arg; |
| } | } |
| /* Expand hash if the chain length exceeds the threshold. */ | |
| static void hash_expand (struct hash *hash) | |
| { | |
| unsigned int i, new_size, losers; | |
| struct hash_backet *hb, *hbnext, **new_index; | |
| new_size = hash->size * 2; | |
| new_index = XCALLOC(MTYPE_HASH_INDEX, sizeof(struct hash_backet *) * new_size); | |
| if (new_index == NULL) | |
| return; | |
| for (i = 0; i < hash->size; i++) | |
| for (hb = hash->index[i]; hb; hb = hbnext) | |
| { | |
| unsigned int h = hb->key & (new_size - 1); | |
| hbnext = hb->next; | |
| hb->next = new_index[h]; | |
| new_index[h] = hb; | |
| } | |
| /* Switch to new table */ | |
| XFREE(MTYPE_HASH_INDEX, hash->index); | |
| hash->size = new_size; | |
| hash->index = new_index; | |
| /* Ideally, new index should have chains half as long as the original. | |
| If expansion didn't help, then not worth expanding again, | |
| the problem is the hash function. */ | |
| losers = 0; | |
| for (i = 0; i < hash->size; i++) | |
| { | |
| unsigned int len = 0; | |
| for (hb = hash->index[i]; hb; hb = hb->next) | |
| { | |
| if (++len > HASH_THRESHOLD/2) | |
| ++losers; | |
| if (len >= HASH_THRESHOLD) | |
| hash->no_expand = 1; | |
| } | |
| } | |
| if (losers > hash->count / 2) | |
| hash->no_expand = 1; | |
| } | |
| /* Lookup and return hash backet in hash. If there is no | /* Lookup and return hash backet in hash. If there is no |
| corresponding hash backet and alloc_func is specified, create new | corresponding hash backet and alloc_func is specified, create new |
| hash backet. */ | hash backet. */ |
| Line 68 hash_get (struct hash *hash, void *data, void * (*allo | Line 116 hash_get (struct hash *hash, void *data, void * (*allo |
| unsigned int key; | unsigned int key; |
| unsigned int index; | unsigned int index; |
| void *newdata; | void *newdata; |
| unsigned int len; | |
| struct hash_backet *backet; | struct hash_backet *backet; |
| key = (*hash->hash_key) (data); | key = (*hash->hash_key) (data); |
| index = key % hash->size; | index = key & (hash->size - 1); |
| len = 0; | |
| for (backet = hash->index[index]; backet != NULL; backet = backet->next) | for (backet = hash->index[index]; backet != NULL; backet = backet->next) |
| if (backet->key == key && (*hash->hash_cmp) (backet->data, data)) | { |
| return backet->data; | if (backet->key == key && (*hash->hash_cmp) (backet->data, data)) |
| return backet->data; | |
| ++len; | |
| } | |
| if (alloc_func) | if (alloc_func) |
| { | { |
| Line 83 hash_get (struct hash *hash, void *data, void * (*allo | Line 136 hash_get (struct hash *hash, void *data, void * (*allo |
| if (newdata == NULL) | if (newdata == NULL) |
| return NULL; | return NULL; |
| if (len > HASH_THRESHOLD && !hash->no_expand) | |
| { | |
| hash_expand (hash); | |
| index = key & (hash->size - 1); | |
| } | |
| backet = XMALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet)); | backet = XMALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet)); |
| backet->data = newdata; | backet->data = newdata; |
| backet->key = key; | backet->key = key; |
| Line 125 hash_release (struct hash *hash, void *data) | Line 184 hash_release (struct hash *hash, void *data) |
| struct hash_backet *pp; | struct hash_backet *pp; |
| key = (*hash->hash_key) (data); | key = (*hash->hash_key) (data); |
| index = key % hash->size; | index = key & (hash->size - 1); |
| for (backet = pp = hash->index[index]; backet; backet = backet->next) | for (backet = pp = hash->index[index]; backet; backet = backet->next) |
| { | { |