diff --git a/opal/class/opal_hash_table.c b/opal/class/opal_hash_table.c index 82a6ad300a..92c6200712 100644 --- a/opal/class/opal_hash_table.c +++ b/opal/class/opal_hash_table.c @@ -9,10 +9,6 @@ * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. - * Copyright (c) 2014-2015 Hewlett-Packard Development Company, LP. - * All rights reserved. - * Copyright (c) 2014-2015 Mellanox Technologies, Inc. - * All rights reserved. * Copyright (c) 2014 Research Organization for Information Science * and Technology (RIST). All rights reserved. * $COPYRIGHT$ @@ -28,98 +24,20 @@ #include #include "opal/util/output.h" +#include "opal/class/opal_list.h" #include "opal/class/opal_hash_table.h" #include "opal/constants.h" +#include "opal/util/bit_ops.h" +#include "opal/util/crc.h" /* * opal_hash_table_t - * - * Sketch: [Constributed by David Linden of Hewlett-Packard] - * - * This has been found to be good for search and insert and - * (seldom-)remove, all with probablistic O(1) time. Having a good - * distribution of the hash indices is important, so even if you know - * the keys distribute well under a mask, that micro-optimization - * isn't worth doing. - * - * One aspect is that the concept of buckets and elements is - * unified. The buckets aka elements are in a single array, each - * element having a valid flag. The key hashes to a keyhash, the - * keyhash determines the first index to probe. Missing probes search - * forward (wrapping) until the key is found or an invalid entry is - * found. - * - * One parameter of the hash table is a maximum density, which must be - * less than 1, expressed a numerator and denominator. 1/2 seems to - * work well. A density less than 1 ensures the search will stop - * because searching will eventually find an invalid element. At - * maximum density, assuming random usage of the elements, the - * expected search length is 1/(1-density); for a density of 1/2, this - * is 2. - * - * I believe this blinded bucket/element scheme is actually more - * storage-efficient than a bucket having a linear list of elements. - * It is certainly better on the cache. - * - * Another parameter is the growth factor, another ratio, greater than - * 1, expressed as a numerator and denominator. 2/1 seems to work - * well. When the hash table reaches maximum density, it is grown by - * the growth factor (thus reducing the density). Growing requires - * rehashing and reinserting existing elements. It turns out this - * keeps insertion at O(1): multiplies the coefficient by - * growth/(growth-1); for a growth of 2/1 this is 2. - * - * The key is hashed to a keyhash. The keyhash determines the first - * index to probe by using the remainder of the keyhash by the table's - * 'capacity.' The capacity is not a power of 2. (Keys that vary - * only in the high 32 bits of a 64 bit key would always colide with a - * power-of-2 capacity.) Rather, the capacity is arranged not to be a - * multiple of 2, 3 or 5. A potential capacity is rounded up to be (1 - * mod 30). - * - * Removing a key is the most involved operation. It is necessary to - * rehash any valid elements immediately after the removed element, - * because some (perhaps all) of those elements would normally hash - * lower if the removed key were never there. This remains O(1); the - * implementation just needs to be a little careful. - * */ -#define HASH_MULTIPLIER 31 - -/* - * Define the structs that are opaque in the .h - */ - -struct opal_hash_element_t { - int valid; /* whether this element is valid */ - union { /* the key, in its various forms */ - uint32_t u32; - uint64_t u64; - struct { - const void * key; - size_t key_size; - } ptr; - } key; - void * value; /* the value */ -}; -typedef struct opal_hash_element_t opal_hash_element_t; - -struct opal_hash_type_methods_t { - /* Frees any storage associated with the element - * The value is not owned by the hash table - * The key,key_size of pointer keys is - */ - void (*elt_destructor)(opal_hash_element_t * elt); - /* Hash the key of the element -- for growing and adjusting-after-removal */ - uint64_t (*hash_elt)(opal_hash_element_t * elt); -}; - -/* interact with the class-like mechanism */ - static void opal_hash_table_construct(opal_hash_table_t* ht); static void opal_hash_table_destruct(opal_hash_table_t* ht); + OBJ_CLASS_INSTANCE( opal_hash_table_t, opal_object_t, @@ -127,695 +45,561 @@ OBJ_CLASS_INSTANCE( opal_hash_table_destruct ); -static void -opal_hash_table_construct(opal_hash_table_t* ht) + +static void opal_hash_table_construct(opal_hash_table_t* ht) { - ht->ht_table = NULL; - ht->ht_capacity = ht->ht_size = ht->ht_growth_trigger = 0; - ht->ht_density_numer = ht->ht_density_denom = 0; - ht->ht_growth_numer = ht->ht_growth_denom = 0; - ht->ht_type_methods = NULL; + OBJ_CONSTRUCT(&ht->ht_nodes, opal_list_t); + ht->ht_table = NULL; + ht->ht_table_size = 0; + ht->ht_size = 0; } -static void -opal_hash_table_destruct(opal_hash_table_t* ht) + +static void opal_hash_table_destruct(opal_hash_table_t* ht) { + size_t i; opal_hash_table_remove_all(ht); - free(ht->ht_table); + for(i=0; iht_table_size; i++) { + OBJ_DESTRUCT(ht->ht_table+i); + } + if(NULL != ht->ht_table) { + free(ht->ht_table); + } + OBJ_DESTRUCT(&ht->ht_nodes); } -/* - * Init, etc - */ -static size_t -opal_hash_round_capacity_up(size_t capacity) +int opal_hash_table_init(opal_hash_table_t* ht, size_t table_size) { - /* round up to (1 mod 30) */ - return ((capacity+29)/30*30 + 1); -} + size_t i; + size_t power2 = opal_next_poweroftwo (table_size); -/* this could be the new init if people wanted a more general API */ -/* (that's why it isn't static) */ -int /* OPAL_ return code */ -opal_hash_table_init2(opal_hash_table_t* ht, size_t estimated_max_size, - int density_numer, int density_denom, - int growth_numer, int growth_denom) -{ - size_t est_capacity = estimated_max_size * density_denom / density_numer; - size_t capacity = opal_hash_round_capacity_up(est_capacity); - ht->ht_table = (opal_hash_element_t*) calloc(capacity, sizeof(opal_hash_element_t)); - if (NULL == ht->ht_table) { + ht->ht_mask = power2-1; + ht->ht_table = (opal_list_t *)malloc(power2 * sizeof(opal_list_t)); + if(NULL == ht->ht_table) { return OPAL_ERR_OUT_OF_RESOURCE; } - ht->ht_capacity = capacity; - ht->ht_density_numer = density_numer; - ht->ht_density_denom = density_denom; - ht->ht_growth_numer = growth_numer; - ht->ht_growth_denom = growth_denom; - ht->ht_growth_trigger = capacity * density_numer / density_denom; - ht->ht_type_methods = NULL; + for(i=ht->ht_table_size; iht_table+i; + OBJ_CONSTRUCT(list, opal_list_t); + } + ht->ht_table_size = power2; return OPAL_SUCCESS; } -int /* OPAL_ return code */ -opal_hash_table_init(opal_hash_table_t* ht, size_t table_size) +int opal_hash_table_remove_all(opal_hash_table_t* ht) { - /* default to density of 1/2 and growth of 2/1 */ - return opal_hash_table_init2(ht, table_size, 1, 2, 2, 1); -} - -int /* OPAL_ return code */ -opal_hash_table_remove_all(opal_hash_table_t* ht) -{ - size_t ii; - for (ii = 0; ii < ht->ht_capacity; ii += 1) { - opal_hash_element_t * elt = &ht->ht_table[ii]; - if (elt->valid && ht->ht_type_methods && ht->ht_type_methods->elt_destructor) { - ht->ht_type_methods->elt_destructor(elt); + size_t i; + for(i=0; iht_table_size; i++) { + opal_list_t* list = ht->ht_table+i; + while(opal_list_get_size(list)) { + opal_list_item_t *item = opal_list_remove_first(list); + OBJ_RELEASE(item); } - elt->valid = 0; - elt->value = NULL; + } + + while(opal_list_get_size(&ht->ht_nodes)) { + opal_list_item_t* item = opal_list_remove_first(&ht->ht_nodes); + OBJ_RELEASE(item); } ht->ht_size = 0; - /* the tests reuse the hash table for different types after removing all */ - /* so we should allow that by forgetting what type it used to be */ - ht->ht_type_methods = NULL; - return OPAL_SUCCESS; -} - -static int /* OPAL_ return code */ -opal_hash_grow(opal_hash_table_t * ht) -{ - size_t jj, ii; - opal_hash_element_t* old_table; - opal_hash_element_t* new_table; - size_t old_capacity; - size_t new_capacity; - - old_table = ht->ht_table; - old_capacity = ht->ht_capacity; - - new_capacity = old_capacity * ht->ht_growth_numer / ht->ht_growth_denom; - new_capacity = opal_hash_round_capacity_up(new_capacity); - - new_table = (opal_hash_element_t*) calloc(new_capacity, sizeof(new_table[0])); - if (NULL == new_table) { - return OPAL_ERR_OUT_OF_RESOURCE; - } - - /* for each element of the old table (indexed by jj), insert it - into the new table (indexed by ii), using the hash_elt method - to generically hash an element, then modulo the new capacity, - and using struct-assignment to copy an old element into its - place int he new table. The hash table never owns the value, - and in the case of ptr keys the old dlements will be blindly - deleted, so we still own the ptr key storage, just in the new - table now */ - for (jj = 0; jj < old_capacity; jj += 1) { - opal_hash_element_t * old_elt; - opal_hash_element_t * new_elt; - old_elt = &old_table[jj]; - if (old_elt->valid) { - for (ii = (ht->ht_type_methods->hash_elt(old_elt)%new_capacity); ; ii += 1) { - if (ii == new_capacity) { ii = 0; } - new_elt = &new_table[ii]; - if (! new_elt->valid) { - *new_elt = *old_elt; - break; - } - } - } - } - /* update with the new, free the old, return */ - ht->ht_table = new_table; - ht->ht_capacity = new_capacity; - ht->ht_growth_trigger = new_capacity * ht->ht_density_numer / ht->ht_density_denom; - free(old_table); - return OPAL_SUCCESS; -} - -/* one of the removal functions has determined which element should be - removed. With the help of the type methods this can be generic. - The important thing is to rehash any valid elements immediately - following the element-being-removed */ -static int /* OPAL_ return code */ -opal_hash_table_remove_elt_at(opal_hash_table_t * ht, size_t ii) -{ - size_t jj, capacity = ht->ht_capacity; - opal_hash_element_t* elts = ht->ht_table; - opal_hash_element_t * elt; - - elt = &elts[ii]; - - if (! elt->valid) { - /* huh? removing a not-valid element? */ - return OPAL_ERROR; - } - - elt->valid = 0; - if (ht->ht_type_methods->elt_destructor) { - ht->ht_type_methods->elt_destructor(elt); - } - - /* need to possibly re-insert followers because of the now-gap */ - /* E.g., XYyAaCbz. (where upper is ideal, lower is not) - * remove A - * leaving XYy.aCbz. and we need to reconsider aCbz - * first a gets reinserted where it wants to be: XYya.Cbz. - * next C doesn't move: XYya.Cbz. - * then b gets put where it wants to be: XYyabC.z. - * then z moves down a little: XYyabCz.. - * then . means we're done - */ - for (ii = ii+1; ; ii += 1) { /* scan immediately following elements */ - if (ii == capacity) { ii = 0; } - elt = &elts[ii]; - if (! elt->valid) { - break; /* done */ - } - /* rehash it and move it if necessary */ - for (jj = ht->ht_type_methods->hash_elt(elt)%capacity; ; jj += 1) { - if (jj == capacity) { jj = 0; } - if (jj == ii) { - /* already in place, either ideal or best-for-now */ - break; - } else if (! elts[jj].valid) { - /* move it down, and invaildate where it came from */ - elts[jj] = elts[ii]; - elts[ii].valid = 0; - break; - } else { - /* still need to find its place */ - } - } - } ht->ht_size -= 1; return OPAL_SUCCESS; } - - + /***************************************************************************/ -static uint64_t -opal_hash_hash_elt_uint32(opal_hash_element_t * elt) -{ - return elt->key.u32; -} +/* + * opal_uint32_hash_node_t + */ -static const struct opal_hash_type_methods_t -opal_hash_type_methods_uint32 = { - NULL, - opal_hash_hash_elt_uint32 +struct opal_uint32_hash_node_t +{ + opal_list_item_t super; + uint32_t hn_key; + void *hn_value; }; +typedef struct opal_uint32_hash_node_t opal_uint32_hash_node_t; -int /* OPAL_ return code */ -opal_hash_table_get_value_uint32(opal_hash_table_t* ht, uint32_t key, void * *value) +static OBJ_CLASS_INSTANCE(opal_uint32_hash_node_t, + opal_list_item_t, + NULL, + NULL); + + +int opal_hash_table_get_value_uint32(opal_hash_table_t* ht, uint32_t key, + void **ptr) { - size_t ii, capacity = ht->ht_capacity; - opal_hash_element_t * elt; + opal_list_t* list = ht->ht_table + (key & ht->ht_mask); + opal_uint32_hash_node_t *node; #if OPAL_ENABLE_DEBUG - if(capacity == 0) { + if(ht->ht_table_size == 0) { opal_output(0, "opal_hash_table_get_value_uint32:" - "opal_hash_table_init() has not been called"); + "opal_hash_table_init() has not been called"); return OPAL_ERROR; } - if (NULL != ht->ht_type_methods && - &opal_hash_type_methods_uint32 != ht->ht_type_methods) { - opal_output(0, "opal_hash_table_get_value_uint32:" - "hash table is for a different key type"); - return OPAL_ERROR; - } #endif - - ht->ht_type_methods = &opal_hash_type_methods_uint32; - for (ii = key%capacity; ; ii += 1) { - if (ii == capacity) { ii = 0; } - elt = &ht->ht_table[ii]; - if (! elt->valid) { - return OPAL_ERR_NOT_FOUND; - } else if (elt->key.u32 == key) { - *value = elt->value; + for(node = (opal_uint32_hash_node_t*)opal_list_get_first(list); + node != (opal_uint32_hash_node_t*)opal_list_get_end(list); + node = (opal_uint32_hash_node_t*)opal_list_get_next(node)) { + if (node->hn_key == key) { + *ptr = node->hn_value; return OPAL_SUCCESS; - } else { - /* keey looking */ } - } - + } + return OPAL_ERR_NOT_FOUND; } -int /* OPAL_ return code */ -opal_hash_table_set_value_uint32(opal_hash_table_t * ht, uint32_t key, void * value) + +int opal_hash_table_set_value_uint32(opal_hash_table_t* ht, + uint32_t key, void* value) { - int rc; - size_t ii, capacity = ht->ht_capacity; - opal_hash_element_t * elt; + opal_list_t* list = ht->ht_table + (key & ht->ht_mask); + opal_uint32_hash_node_t *node; #if OPAL_ENABLE_DEBUG - if(capacity == 0) { + if(ht->ht_table_size == 0) { opal_output(0, "opal_hash_table_set_value_uint32:" - "opal_hash_table_init() has not been called"); + "opal_hash_table_init() has not been called"); return OPAL_ERR_BAD_PARAM; } - if (NULL != ht->ht_type_methods && - &opal_hash_type_methods_uint32 != ht->ht_type_methods) { - opal_output(0, "opal_hash_table_set_value_uint32:" - "hash table is for a different key type"); - return OPAL_ERROR; - } #endif - - ht->ht_type_methods = &opal_hash_type_methods_uint32; - for (ii = key%capacity; ; ii += 1) { - if (ii == capacity) { ii = 0; } - elt = &ht->ht_table[ii]; - if (! elt->valid) { - /* new entry */ - elt->key.u32 = key; - elt->value = value; - elt->valid = 1; - ht->ht_size += 1; - if (ht->ht_size >= ht->ht_growth_trigger) { - if (OPAL_SUCCESS != (rc = opal_hash_grow(ht))) { - return rc; - } - } + for(node = (opal_uint32_hash_node_t*)opal_list_get_first(list); + node != (opal_uint32_hash_node_t*)opal_list_get_end(list); + node = (opal_uint32_hash_node_t*)opal_list_get_next(node)) { + if (node->hn_key == key) { + node->hn_value = value; return OPAL_SUCCESS; - } else if (elt->key.u32 == key) { - /* replace existing element */ - elt->value = value; - return OPAL_SUCCESS; - } else { - /* keep looking */ } + } + + node = (opal_uint32_hash_node_t*)opal_list_remove_first(&ht->ht_nodes); + if(NULL == node) { + node = OBJ_NEW(opal_uint32_hash_node_t); + if(NULL == node) + return OPAL_ERR_OUT_OF_RESOURCE; } + node->hn_key = key; + node->hn_value = value; + opal_list_append(list, (opal_list_item_t*)node); + ht->ht_size++; + return OPAL_SUCCESS; } -int -opal_hash_table_remove_value_uint32(opal_hash_table_t * ht, uint32_t key) + +int opal_hash_table_remove_value_uint32(opal_hash_table_t* ht, uint32_t key) { - size_t ii, capacity = ht->ht_capacity; + opal_list_t* list = ht->ht_table + (key & ht->ht_mask); + opal_uint32_hash_node_t *node; #if OPAL_ENABLE_DEBUG - if(capacity == 0) { - opal_output(0, "opal_hash_table_get_value_uint32:" - "opal_hash_table_init() has not been called"); - return OPAL_ERROR; - } - if (NULL != ht->ht_type_methods && - &opal_hash_type_methods_uint32 != ht->ht_type_methods) { + if(ht->ht_table_size == 0) { opal_output(0, "opal_hash_table_remove_value_uint32:" - "hash table is for a different key type"); - return OPAL_ERROR; + "opal_hash_table_init() has not been called"); + return OPAL_ERR_BAD_PARAM; } #endif - - ht->ht_type_methods = &opal_hash_type_methods_uint32; - for (ii = key%capacity; ; ii += 1) { - opal_hash_element_t * elt; - if (ii == capacity) ii = 0; - elt = &ht->ht_table[ii]; - if (! elt->valid) { - return OPAL_ERR_NOT_FOUND; - } else if (elt->key.u32 == key) { - return opal_hash_table_remove_elt_at(ht, ii); - } else { - /* keep looking */ + for(node = (opal_uint32_hash_node_t*)opal_list_get_first(list); + node != (opal_uint32_hash_node_t*)opal_list_get_end(list); + node = (opal_uint32_hash_node_t*)opal_list_get_next(node)) { + if (node->hn_key == key) { + opal_list_remove_item(list, (opal_list_item_t*)node); + opal_list_append(&ht->ht_nodes, (opal_list_item_t*)node); + ht->ht_size--; + return OPAL_SUCCESS; } - } + } + return OPAL_ERR_NOT_FOUND; } - /***************************************************************************/ +/* + * opal_uint64_hash_node_t + */ -static uint64_t -opal_hash_hash_elt_uint64(opal_hash_element_t * elt) +struct opal_uint64_hash_node_t { - return elt->key.u64; -} - -static const struct opal_hash_type_methods_t -opal_hash_type_methods_uint64 = { - NULL, - opal_hash_hash_elt_uint64 + opal_list_item_t super; + uint64_t hn_key; + void* hn_value; }; +typedef struct opal_uint64_hash_node_t opal_uint64_hash_node_t; -int /* OPAL_ return code */ -opal_hash_table_get_value_uint64(opal_hash_table_t * ht, uint64_t key, void * *value) +static OBJ_CLASS_INSTANCE(opal_uint64_hash_node_t, + opal_list_item_t, + NULL, + NULL); + + +int opal_hash_table_get_value_uint64(opal_hash_table_t* ht, uint64_t key, + void **ptr) { - size_t ii; - size_t capacity = ht->ht_capacity; - opal_hash_element_t * elt; + opal_list_t* list = ht->ht_table + (key & ht->ht_mask); + opal_uint64_hash_node_t *node; #if OPAL_ENABLE_DEBUG - if(capacity == 0) { + if(ht->ht_table_size == 0) { opal_output(0, "opal_hash_table_get_value_uint64:" - "opal_hash_table_init() has not been called"); + "opal_hash_table_init() has not been called"); return OPAL_ERROR; } - if (NULL != ht->ht_type_methods && - &opal_hash_type_methods_uint64 != ht->ht_type_methods) { - opal_output(0, "opal_hash_table_get_value_uint64:" - "hash table is for a different key type"); - return OPAL_ERROR; - } #endif - - ht->ht_type_methods = &opal_hash_type_methods_uint64; - for (ii = key%capacity; ; ii += 1) { - if (ii == capacity) { ii = 0; } - elt = &ht->ht_table[ii]; - if (! elt->valid) { - return OPAL_ERR_NOT_FOUND; - } else if (elt->key.u64 == key) { - *value = elt->value; + for(node = (opal_uint64_hash_node_t*)opal_list_get_first(list); + node != (opal_uint64_hash_node_t*)opal_list_get_end(list); + node = (opal_uint64_hash_node_t*)opal_list_get_next(node)) { + if (node->hn_key == key) { + *ptr = node->hn_value; return OPAL_SUCCESS; - } else { - /* keep looking */ } - } - + } + return OPAL_ERR_NOT_FOUND; } -int /* OPAL_ return code */ -opal_hash_table_set_value_uint64(opal_hash_table_t * ht, uint64_t key, void * value) + +int opal_hash_table_set_value_uint64(opal_hash_table_t* ht, + uint64_t key, void* value) { - int rc; - size_t ii, capacity = ht->ht_capacity; - opal_hash_element_t * elt; + opal_list_t* list = ht->ht_table + (key & ht->ht_mask); + opal_uint64_hash_node_t *node; #if OPAL_ENABLE_DEBUG - if(capacity == 0) { + if(ht->ht_table_size == 0) { opal_output(0, "opal_hash_table_set_value_uint64:" - "opal_hash_table_init() has not been called"); + "opal_hash_table_init() has not been called"); return OPAL_ERR_BAD_PARAM; } - if (NULL != ht->ht_type_methods && - &opal_hash_type_methods_uint64 != ht->ht_type_methods) { - opal_output(0, "opal_hash_table_set_value_uint64:" - "hash table is for a different key type"); - return OPAL_ERROR; - } #endif + for(node = (opal_uint64_hash_node_t*)opal_list_get_first(list); + node != (opal_uint64_hash_node_t*)opal_list_get_end(list); + node = (opal_uint64_hash_node_t*)opal_list_get_next(node)) { + if (node->hn_key == key) { + node->hn_value = value; + return OPAL_SUCCESS; + } + } - ht->ht_type_methods = &opal_hash_type_methods_uint64; - for (ii = key%capacity; ; ii += 1) { - if (ii == capacity) { ii = 0; } - elt = &ht->ht_table[ii]; - if (! elt->valid) { - /* new entry */ - elt->key.u64 = key; - elt->value = value; - elt->valid = 1; - ht->ht_size += 1; - if (ht->ht_size >= ht->ht_growth_trigger) { - if (OPAL_SUCCESS != (rc = opal_hash_grow(ht))) { - return rc; - } - } - return OPAL_SUCCESS; - } else if (elt->key.u64 == key) { - elt->value = value; - return OPAL_SUCCESS; - } else { - /* keep looking */ + node = (opal_uint64_hash_node_t*)opal_list_remove_first(&ht->ht_nodes); + if(NULL == node) { + node = OBJ_NEW(opal_uint64_hash_node_t); + if(NULL == node) { + return OPAL_ERR_OUT_OF_RESOURCE; } } + node->hn_key = key; + node->hn_value = value; + opal_list_append(list, (opal_list_item_t*)node); + ht->ht_size++; + return OPAL_SUCCESS; } -int /* OPAL_ return code */ -opal_hash_table_remove_value_uint64(opal_hash_table_t * ht, uint64_t key) +int opal_hash_table_remove_value_uint64(opal_hash_table_t* ht, uint64_t key) { - size_t ii, capacity = ht->ht_capacity; + opal_list_t* list = ht->ht_table + (key & ht->ht_mask); + opal_uint64_hash_node_t *node; #if OPAL_ENABLE_DEBUG - if(capacity == 0) { - opal_output(0, "opal_hash_table_get_value_uint64:" - "opal_hash_table_init() has not been called"); - return OPAL_ERROR; - } - if (NULL != ht->ht_type_methods && - &opal_hash_type_methods_uint64 != ht->ht_type_methods) { + if(ht->ht_table_size == 0) { opal_output(0, "opal_hash_table_remove_value_uint64:" - "hash table is for a different key type"); - return OPAL_ERROR; - } -#endif - - ht->ht_type_methods = &opal_hash_type_methods_uint64; - for (ii = key%capacity; ; ii += 1) { - opal_hash_element_t * elt; - if (ii == capacity) { ii = 0; } - elt = &ht->ht_table[ii]; - if (! elt->valid) { - return OPAL_ERR_NOT_FOUND; - } else if (elt->key.u64 == key) { - return opal_hash_table_remove_elt_at(ht, ii); - } else { - /* keep looking */ - } - } -} - - -/***************************************************************************/ - -/* helper function used in several places */ -static uint64_t -opal_hash_hash_key_ptr(const void * key, size_t key_size) -{ - uint64_t hash; - const unsigned char *scanner; - size_t ii; - - hash = 0; - scanner = (const unsigned char *)key; - for (ii = 0; ii < key_size; ii += 1) { - hash = HASH_MULTIPLIER*hash + *scanner++; - } - return hash; -} - -/* ptr methods */ - -static void -opal_hash_destruct_elt_ptr(opal_hash_element_t * elt) -{ - elt->key.ptr.key_size = 0; - void * key = (void *) elt->key.ptr.key; /* cast away const so we can free it */ - if (NULL != key) { - elt->key.ptr.key = NULL; - free(key); - } -} - -static uint64_t -opal_hash_hash_elt_ptr(opal_hash_element_t * elt) -{ - return opal_hash_hash_key_ptr(elt->key.ptr.key, elt->key.ptr.key_size); -} - -static const struct opal_hash_type_methods_t -opal_hash_type_methods_ptr = { - opal_hash_destruct_elt_ptr, - opal_hash_hash_elt_ptr -}; - -int /* OPAL_ return code */ -opal_hash_table_get_value_ptr(opal_hash_table_t * ht, - const void * key, size_t key_size, - void * *value) -{ - size_t ii, capacity = ht->ht_capacity; - opal_hash_element_t * elt; - -#if OPAL_ENABLE_DEBUG - if(capacity == 0) { - opal_output(0, "opal_hash_table_get_value_ptr:" - "opal_hash_table_init() has not been called"); - return OPAL_ERROR; - } - if (NULL != ht->ht_type_methods && - &opal_hash_type_methods_ptr != ht->ht_type_methods) { - opal_output(0, "opal_hash_table_get_value_ptr:" - "hash table is for a different key type"); - return OPAL_ERROR; - } -#endif - - ht->ht_type_methods = &opal_hash_type_methods_ptr; - for (ii = opal_hash_hash_key_ptr(key, key_size)%capacity; ; ii += 1) { - if (ii == capacity) { ii = 0; } - elt = &ht->ht_table[ii]; - if (! elt->valid) { - return OPAL_ERR_NOT_FOUND; - } else if (elt->key.ptr.key_size == key_size && - 0 == memcmp(elt->key.ptr.key, key, key_size)) { - *value = elt->value; - return OPAL_SUCCESS; - } else { - /* keep going */ - } - } -} - -int /* OPAL_ return code */ -opal_hash_table_set_value_ptr(opal_hash_table_t * ht, - const void * key, size_t key_size, - void * value) -{ - int rc; - size_t ii, capacity = ht->ht_capacity; - opal_hash_element_t * elt; - -#if OPAL_ENABLE_DEBUG - if(capacity == 0) { - opal_output(0, "opal_hash_table_set_value_ptr:" - "opal_hash_table_init() has not been called"); + "opal_hash_table_init() has not been called"); return OPAL_ERR_BAD_PARAM; } - if (NULL != ht->ht_type_methods && - &opal_hash_type_methods_ptr != ht->ht_type_methods) { - opal_output(0, "opal_hash_table_set_value_ptr:" - "hash table is for a different key type"); - return OPAL_ERROR; - } #endif - - ht->ht_type_methods = &opal_hash_type_methods_ptr; - for (ii = opal_hash_hash_key_ptr(key, key_size)%capacity; ; ii += 1) { - if (ii == capacity) { ii = 0; } - elt = &ht->ht_table[ii]; - if (! elt->valid) { - /* new entry */ - void * key_local = malloc(key_size); - memcpy(key_local, key, key_size); - elt->key.ptr.key = key_local; - elt->key.ptr.key_size = key_size; - elt->value = value; - elt->valid = 1; - ht->ht_size += 1; - if (ht->ht_size >= ht->ht_growth_trigger) { - if (OPAL_SUCCESS != (rc = opal_hash_grow(ht))) { - return rc; - } - } + for(node = (opal_uint64_hash_node_t*)opal_list_get_first(list); + node != (opal_uint64_hash_node_t*)opal_list_get_end(list); + node = (opal_uint64_hash_node_t*)opal_list_get_next(node)) { + if (node->hn_key == key) { + opal_list_remove_item(list, (opal_list_item_t*)node); + opal_list_append(&ht->ht_nodes, (opal_list_item_t*)node); + ht->ht_size--; return OPAL_SUCCESS; - } else if (elt->key.ptr.key_size == key_size && - 0 == memcmp(elt->key.ptr.key, key, key_size)) { - /* replace existing value */ - elt->value = value; - return OPAL_SUCCESS; - } else { - /* keep looking */ } - } -} - -int /* OPAL_ return code */ -opal_hash_table_remove_value_ptr(opal_hash_table_t * ht, - const void * key, size_t key_size) -{ - size_t ii, capacity = ht->ht_capacity; - -#if OPAL_ENABLE_DEBUG - if(capacity == 0) { - opal_output(0, "opal_hash_table_get_value_ptr:" - "opal_hash_table_init() has not been called"); - return OPAL_ERROR; - } - if (NULL != ht->ht_type_methods && - &opal_hash_type_methods_ptr != ht->ht_type_methods) { - opal_output(0, "opal_hash_table_remove_value_ptr:" - "hash table is for a different key type"); - return OPAL_ERROR; - } -#endif - - ht->ht_type_methods = &opal_hash_type_methods_ptr; - for (ii = opal_hash_hash_key_ptr(key, key_size)%capacity; ; ii += 1) { - opal_hash_element_t * elt; - if (ii == capacity) { ii = 0; } - elt = &ht->ht_table[ii]; - if (! elt->valid) { - return OPAL_ERR_NOT_FOUND; - } else if (elt->key.ptr.key_size == key_size && - 0 == memcmp(elt->key.ptr.key, key, key_size)) { - return opal_hash_table_remove_elt_at(ht, ii); - } else { - /* keep looking */ - } - } + } + return OPAL_ERR_NOT_FOUND; } /***************************************************************************/ -/* Traversals */ -static int /* OPAL_ return code */ -opal_hash_table_get_next_elt(opal_hash_table_t *ht, - opal_hash_element_t * prev_elt, /* NULL means find first */ - opal_hash_element_t * *next_elt) +/* + * opal_ptr_hash_node_t + */ + +struct opal_ptr_hash_node_t { - opal_hash_element_t* elts = ht->ht_table; - size_t ii, capacity = ht->ht_capacity; + opal_list_item_t super; + void* hn_key; + size_t hn_key_size; + void* hn_value; +}; +typedef struct opal_ptr_hash_node_t opal_ptr_hash_node_t; - for (ii = (NULL == prev_elt ? 0 : (prev_elt-elts)+1); ii < capacity; ii += 1) { - opal_hash_element_t * elt = &elts[ii]; - if (elt->valid) { - *next_elt = elt; - return OPAL_SUCCESS; +static void opal_ptr_hash_node_construct(opal_ptr_hash_node_t* hn) +{ + hn->hn_key_size = 0; + hn->hn_key = NULL; + hn->hn_value = NULL; +} + +static void opal_ptr_hash_node_destruct(opal_ptr_hash_node_t* hn) +{ + if(NULL != hn->hn_key) { + free(hn->hn_key); } - } - return OPAL_ERROR; } -int /* OPAL_ return code */ -opal_hash_table_get_first_key_uint32(opal_hash_table_t * ht, - uint32_t *key, void * *value, - void * *node) +static OBJ_CLASS_INSTANCE(opal_ptr_hash_node_t, + opal_list_item_t, + opal_ptr_hash_node_construct, + opal_ptr_hash_node_destruct); + +static inline uint32_t opal_hash_value(size_t mask, const void *key, + size_t keysize) { - return opal_hash_table_get_next_key_uint32(ht, key, value, NULL, node); + unsigned int crc = opal_uicrc_partial (key, keysize, 0); + return (uint32_t) (crc & mask); } -int /* OPAL_ return code */ -opal_hash_table_get_next_key_uint32(opal_hash_table_t * ht, - uint32_t *key, void * *value, - void * in_node, void * *out_node) +int opal_hash_table_get_value_ptr(opal_hash_table_t* ht, const void* key, + size_t key_size, void **ptr) { - opal_hash_element_t * elt; - if (OPAL_SUCCESS == opal_hash_table_get_next_elt(ht, (opal_hash_element_t *) in_node, &elt)) { - *key = elt->key.u32; - *value = elt->value; - *out_node = elt; + opal_list_t* list = ht->ht_table + opal_hash_value(ht->ht_mask, key, + key_size); + opal_ptr_hash_node_t *node; + +#if OPAL_ENABLE_DEBUG + if(ht->ht_table_size == 0) { + opal_output(0, "opal_hash_table_get_value_ptr:" + "opal_hash_table_init() has not been called"); + return OPAL_ERROR; + } +#endif + for(node = (opal_ptr_hash_node_t*)opal_list_get_first(list); + node != (opal_ptr_hash_node_t*)opal_list_get_end(list); + node = (opal_ptr_hash_node_t*)opal_list_get_next(node)) { + if (node->hn_key_size == key_size && + memcmp(node->hn_key, key, key_size) == 0) { + *ptr = node->hn_value; + return OPAL_SUCCESS; + } + } + return OPAL_ERR_NOT_FOUND; +} + + +int opal_hash_table_set_value_ptr(opal_hash_table_t* ht, const void* key, + size_t key_size, void* value) +{ + opal_list_t* list = ht->ht_table + opal_hash_value(ht->ht_mask, key, + key_size); + opal_ptr_hash_node_t *node; + +#if OPAL_ENABLE_DEBUG + if(ht->ht_table_size == 0) { + opal_output(0, "opal_hash_table_set_value_ptr:" + "opal_hash_table_init() has not been called"); + return OPAL_ERR_BAD_PARAM; + } +#endif + for(node = (opal_ptr_hash_node_t*)opal_list_get_first(list); + node != (opal_ptr_hash_node_t*)opal_list_get_end(list); + node = (opal_ptr_hash_node_t*)opal_list_get_next(node)) { + if (node->hn_key_size == key_size && + memcmp(node->hn_key, key, key_size) == 0) { + node->hn_value = value; + return OPAL_SUCCESS; + } + } + + node = (opal_ptr_hash_node_t*)opal_list_remove_first(&ht->ht_nodes); + if(NULL == node) { + node = OBJ_NEW(opal_ptr_hash_node_t); + if(NULL == node) { + return OPAL_ERR_OUT_OF_RESOURCE; + } + } + node->hn_key = malloc(key_size); + node->hn_key_size = key_size; + node->hn_value = value; + memcpy(node->hn_key, key, key_size); + opal_list_append(list, (opal_list_item_t*)node); + ht->ht_size++; return OPAL_SUCCESS; - } - return OPAL_ERROR; } -int /* OPAL_ return code */ -opal_hash_table_get_first_key_uint64(opal_hash_table_t * ht, - uint64_t *key, void * *value, - void * *node) + +int opal_hash_table_remove_value_ptr(opal_hash_table_t* ht, + const void* key, size_t key_size) { - return opal_hash_table_get_next_key_uint64(ht, key, value, NULL, node); + opal_list_t* list = ht->ht_table + opal_hash_value(ht->ht_mask, + key, key_size); + opal_ptr_hash_node_t *node; + +#if OPAL_ENABLE_DEBUG + if(ht->ht_table_size == 0) { + opal_output(0, "opal_hash_table_remove_value_ptr: " + "opal_hash_table_init() has not been called"); + return OPAL_ERR_BAD_PARAM; + } +#endif + for(node = (opal_ptr_hash_node_t*)opal_list_get_first(list); + node != (opal_ptr_hash_node_t*)opal_list_get_end(list); + node = (opal_ptr_hash_node_t*)opal_list_get_next(node)) { + if (node->hn_key_size == key_size && + memcmp(node->hn_key, key, key_size) == 0) { + free(node->hn_key); + node->hn_key = NULL; + node->hn_key_size = 0; + opal_list_remove_item(list, (opal_list_item_t*)node); + opal_list_append(&ht->ht_nodes, (opal_list_item_t*)node); + ht->ht_size--; + return OPAL_SUCCESS; + } + } + return OPAL_ERR_NOT_FOUND; } -int /* OPAL_ return code */ -opal_hash_table_get_next_key_uint64(opal_hash_table_t * ht, - uint64_t *key, void * *value, - void * in_node, void * *out_node) + +int +opal_hash_table_get_first_key_uint32(opal_hash_table_t *ht, uint32_t *key, + void **value, void **node) { - opal_hash_element_t * elt; - if (OPAL_SUCCESS == opal_hash_table_get_next_elt(ht, (opal_hash_element_t *) in_node, &elt)) { - *key = elt->key.u64; - *value = elt->value; - *out_node = elt; + size_t i; + opal_uint32_hash_node_t *list_node; + + /* Go through all the lists and return the first element off the + first non-empty list */ + + for (i = 0; i < ht->ht_table_size; ++i) { + if (opal_list_get_size(ht->ht_table + i) > 0) { + list_node = (opal_uint32_hash_node_t*) + opal_list_get_first(ht->ht_table + i); + *node = list_node; + *key = list_node->hn_key; + *value = list_node->hn_value; + return OPAL_SUCCESS; + } + } + + /* The hash table is empty */ + + return OPAL_ERROR; +} + + +int +opal_hash_table_get_next_key_uint32(opal_hash_table_t *ht, uint32_t *key, + void **value, void *in_node, + void **out_node) +{ + size_t i; + opal_list_t *list; + opal_list_item_t *item; + opal_uint32_hash_node_t *next; + + /* Try to simply get the next value in the list. If there isn't + one, find the next non-empty list and take the first value */ + + next = (opal_uint32_hash_node_t*) in_node; + list = ht->ht_table + (next->hn_key & ht->ht_mask); + item = opal_list_get_next(next); + if (opal_list_get_end(list) == item) { + item = NULL; + for (i = (list - ht->ht_table) + 1; i < ht->ht_table_size; ++i) { + if (opal_list_get_size(ht->ht_table + i) > 0) { + item = opal_list_get_first(ht->ht_table + i); + break; + } + } + + /* If we didn't find another non-empty list after this one, + then we're at the end of the hash table */ + + if (NULL == item) { + return OPAL_ERROR; + } + } + + /* We found it. Save the values (use "next" to avoid some + typecasting) */ + + *out_node = (void *) item; + next = (opal_uint32_hash_node_t *) *out_node; + *key = next->hn_key; + *value = next->hn_value; + return OPAL_SUCCESS; - } - return OPAL_ERROR; } -/* there was/is no traversal for the ptr case; it would go here */ + +int +opal_hash_table_get_first_key_uint64(opal_hash_table_t *ht, uint64_t *key, + void **value, void **node) +{ + size_t i; + opal_uint64_hash_node_t *list_node; + + /* Go through all the lists and return the first element off the + first non-empty list */ + + for (i = 0; i < ht->ht_table_size; ++i) { + if (opal_list_get_size(ht->ht_table + i) > 0) { + list_node = (opal_uint64_hash_node_t*) + opal_list_get_first(ht->ht_table + i); + *node = list_node; + *key = list_node->hn_key; + *value = list_node->hn_value; + return OPAL_SUCCESS; + } + } + + /* The hash table is empty */ + + return OPAL_ERROR; +} + + +int +opal_hash_table_get_next_key_uint64(opal_hash_table_t *ht, uint64_t *key, + void **value, void *in_node, + void **out_node) +{ + size_t i; + opal_list_t *list; + opal_list_item_t *item; + opal_uint64_hash_node_t *next; + + /* Try to simply get the next value in the list. If there isn't + one, find the next non-empty list and take the first value */ + + next = (opal_uint64_hash_node_t*) in_node; + list = ht->ht_table + (next->hn_key & ht->ht_mask); + item = opal_list_get_next(next); + if (opal_list_get_end(list) == item) { + item = NULL; + for (i = (list - ht->ht_table) + 1; i < ht->ht_table_size; ++i) { + if (opal_list_get_size(ht->ht_table + i) > 0) { + item = opal_list_get_first(ht->ht_table + i); + break; + } + } + + /* If we didn't find another non-empty list after this one, + then we're at the end of the hash table */ + + if (NULL == item) { + return OPAL_ERROR; + } + } + + /* We found it. Save the values (use "next" to avoid some + typecasting) */ + + *out_node = (void *) item; + next = (opal_uint64_hash_node_t *) *out_node; + *key = next->hn_key; + *value = next->hn_value; + + return OPAL_SUCCESS; +} diff --git a/opal/class/opal_hash_table.h b/opal/class/opal_hash_table.h index a989482540..7338c36deb 100644 --- a/opal/class/opal_hash_table.h +++ b/opal/class/opal_hash_table.h @@ -9,10 +9,6 @@ * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. - * Copyright (c) 2014-2015 Hewlett-Packard Development Company, LP. - * All rights reserved. - * Copyright (c) 2014-2015 Mellanox Technologies, Inc. - * All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow @@ -46,18 +42,11 @@ OPAL_DECLSPEC OBJ_CLASS_DECLARATION(opal_hash_table_t); struct opal_hash_table_t { opal_object_t super; /**< subclass of opal_object_t */ - struct opal_hash_element_t * ht_table; /**< table of elements (opaque to users) */ - size_t ht_capacity; /**< allocated size (capacity) of table */ - size_t ht_size; /**< number of extant entries */ - size_t ht_growth_trigger; /**< size hits this and table is grown */ - int ht_density_numer, ht_density_denom; /**< max allowed density of table */ - int ht_growth_numer, ht_growth_denom; /**< growth factor when grown */ - const struct opal_hash_type_methods_t * ht_type_methods; - // FIXME - // Begin KLUDGE!! So ompi/debuggers/ompi_common_dll.c doesn't complain + opal_list_t ht_nodes; /**< free list of hash nodes */ + opal_list_t *ht_table; /**< each item is an array of opal_fhnode_t nodes */ size_t ht_table_size; /**< size of table */ + size_t ht_size; /**< number of values on table */ size_t ht_mask; - // End KLUDGE }; typedef struct opal_hash_table_t opal_hash_table_t; @@ -120,7 +109,7 @@ OPAL_DECLSPEC int opal_hash_table_remove_all(opal_hash_table_t *ht); */ OPAL_DECLSPEC int opal_hash_table_get_value_uint32(opal_hash_table_t* table, uint32_t key, - void** ptr); + void** ptr); /** * Set value based on uint32_t key. @@ -159,7 +148,7 @@ OPAL_DECLSPEC int opal_hash_table_remove_value_uint32(opal_hash_table_t* table, */ OPAL_DECLSPEC int opal_hash_table_get_value_uint64(opal_hash_table_t *table, uint64_t key, - void **ptr); + void **ptr); /** * Set value based on uint64_t key. @@ -198,7 +187,7 @@ OPAL_DECLSPEC int opal_hash_table_remove_value_uint64(opal_hash_table_t *table, */ OPAL_DECLSPEC int opal_hash_table_get_value_ptr(opal_hash_table_t *table, const void* key, - size_t keylen, void **ptr); + size_t keylen, void **ptr); /** * Set value based on arbitrary length binary key. @@ -247,7 +236,7 @@ OPAL_DECLSPEC int opal_hash_table_remove_value_ptr(opal_hash_table_t *table, con */ OPAL_DECLSPEC int opal_hash_table_get_first_key_uint32(opal_hash_table_t *table, uint32_t *key, - void **value, void **node); + void **value, void **node); /** @@ -265,8 +254,8 @@ OPAL_DECLSPEC int opal_hash_table_get_first_key_uint32(opal_hash_table_t *table, */ OPAL_DECLSPEC int opal_hash_table_get_next_key_uint32(opal_hash_table_t *table, uint32_t *key, - void **value, void *in_node, - void **out_node); + void **value, void *in_node, + void **out_node); /** @@ -283,7 +272,7 @@ OPAL_DECLSPEC int opal_hash_table_get_next_key_uint32(opal_hash_table_t *table, */ OPAL_DECLSPEC int opal_hash_table_get_first_key_uint64(opal_hash_table_t *table, uint64_t *key, - void **value, void **node); + void **value, void **node); /** @@ -301,8 +290,8 @@ OPAL_DECLSPEC int opal_hash_table_get_first_key_uint64(opal_hash_table_t *table, */ OPAL_DECLSPEC int opal_hash_table_get_next_key_uint64(opal_hash_table_t *table, uint64_t *key, - void **value, void *in_node, - void **out_node); + void **value, void *in_node, + void **out_node); END_C_DECLS diff --git a/test/class/opal_hash_table.c b/test/class/opal_hash_table.c index f5ed516529..35df9f6aa2 100644 --- a/test/class/opal_hash_table.c +++ b/test/class/opal_hash_table.c @@ -10,10 +10,6 @@ * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2010 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2014-2015 Hewlett-Packard Development Company, LP. - * All rights reserved. - * Copyright (c) 2014-2015 Mellanox Technologies, Inc. - * All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow @@ -66,23 +62,6 @@ char *perm_keys[] = { NULL }; -/* - * This data specifically knows about the April'2014 version of hash tables. - * It inserts some keys. - * It inserts some more with a capacity offset to generate collisions. - * Then it checks the table via traversal. - * Then... it removes a key and checks again (via traversal) - * and removes another key and re-checks. - */ -static char* remove_keys[] = { - "1", "A", "2", "B", "4", "D", "6", "F", "10", "J", NULL, /* insert as-is: ...AB.D.F...J... */ - "2", "b", "4", "d", "5", "e", "3", "c", NULL, /* insert with capacity-offset: ...ABbDdFec.J... */ - "ABbDdFecJ", /* traversal expectation */ - "4", "ABbdeFcJ", /* remove D (...ABbdeFc..J...) then expected traversal */ - "2", "AbcdeFJ", /* remove B (...AbcdeF...J...) then expected traversal */ - NULL /* end removals and expectations */ -}; - typedef union { uint32_t uvalue; void *vvalue; @@ -113,67 +92,6 @@ static void validate_table(opal_hash_table_t *table, char *keys[], int is_numeri test_verify_int(j/2, opal_hash_table_get_size(table)); } -static void -validate_remove_traversal(opal_hash_table_t * table, const char * expected_chars) -{ - /* all values are single-character strings */ - /* expected_chars are those single characters as a string */ - const int debug = 0; /* turn this on if you want to see the details */ - int rc, problems = 0; - const char * expected_scanner = expected_chars; - uint32_t key; - void * raw_value; - void * node; - if (debug) { - fprintf(stderr, "debug: expecting '%s' capacity is %d\n", - expected_chars, (int) table->ht_capacity); - } - for (rc = opal_hash_table_get_first_key_uint32(table, &key, &raw_value, &node); - OPAL_SUCCESS == rc; - rc = opal_hash_table_get_next_key_uint32(table, &key, &raw_value, node, &node)) { - const char * value = (const char *) raw_value; - char expected, actual; - if (debug) { - fprintf(stderr, "key %d (probe at %d) value '%s' excpected_scanner '%s'\n", - key, (int) (key%table->ht_capacity), value, expected_scanner); - } - if (1 != strlen(value)) { - fprintf(stderr, "key %d's value '%s' is not a one-character string\n", key, value); - problems += 1; - continue; /* might as well be completely noisy */ - } - if ('\0' == *expected_scanner) { - fprintf(stderr, "Found key %d value '%s' but not expected!\n", key, value); - problems += 1; - continue; - } - expected = *expected_scanner++; - actual = *value; - if (actual != expected) { - fprintf(stderr, "Expected '%c' but got '%c'\n", expected, actual); - problems += 1; - continue; - } - } - /* final checks */ - if (OPAL_ERROR != rc) { - fprintf(stderr, "table traversal did not end in OPAL_ERROR?!?\n"); - problems += 1; - } - if ('\0' != *expected_scanner) { - fprintf(stderr, "Still expecting more key/values: '%s'\n", expected_scanner); - problems += 1; - } - - /* resolution */ - if (problems > 0) { - fflush(stderr); - test_failure("validate_remove_traversal"); - } else { - test_success(); - } -} - static void test_htable(opal_hash_table_t *table) { int j; @@ -213,26 +131,6 @@ static void test_htable(opal_hash_table_t *table) opal_hash_table_remove_all(table); test_verify_int(0, opal_hash_table_get_size(table)); - fprintf(error_out, "\nTesting removal and traversal...\n"); - j = 0; - char * str; - while (NULL != (str = remove_keys[j++])) { - opal_hash_table_set_value_uint32(table, atoi(str), remove_keys[j++]); - } - while (NULL != (str = remove_keys[j++])) { - /* generate collisions */ - opal_hash_table_set_value_uint32(table, atoi(str) + table->ht_capacity, remove_keys[j++]); - } - validate_remove_traversal(table, remove_keys[j++]); - while (NULL != (str = remove_keys[j++])) { - opal_hash_table_remove_value_uint32(table, atoi(str)); - validate_remove_traversal(table, remove_keys[j++]); - } - - /* remove all values for next test */ - opal_hash_table_remove_all(table); - test_verify_int(0, opal_hash_table_get_size(table)); - fprintf(error_out, "\n\n"); }