Exemplo n.º 1
0
Arquivo: HashTable.c Projeto: ATAIEC/C
int hashtable_add(HashTable * ht, void * key, void * value){
	size_t hash = ht->hf(key);
	Item * next = ht->table[ hash % ht->size ];
	size_t i = 0;

	while(next){
		// Replace data if key is same
		if(ht->eq( next->key, key )){
			next->value = value;
			return(1);
		}

		next = next->next;
		i++;
	}

	next = (Item *)malloc( sizeof(Item) );
	next->key = key;
	next->value = value;
	next->next = ht->table[ hash % ht->size ];
	ht->table[ hash % ht->size ] = next;

	if(i >= ht->maxCollisions){
		hashtable_resize(ht, ht->size + ht->growthFactor);
	}

	return(1);
}
Exemplo n.º 2
0
int hashtable_set(struct hashtable *ht, const void *key, size_t keylen,
                  void *data)
{
  int i, k;
  ht_size_p_t extend_trigger, extend;
  struct hashtableitem *new_item;

  k = hashtable_get(ht, key, keylen, NULL);

  if (k == HASHTABLE_SUCCESS)
  {
    return HASHTABLE_DUPLICATE;
  }
  else if (k != HASHTABLE_KEY_NOT_FOUND)
  {
    /* some other error; bail */
    return k;
  }

  extend         = ht->table_size_p + ht->table_settings.size_extend;
  extend_trigger = ht->table_size_p + ht->table_settings.size_extend_trigger;

  if (extend <= ht->table_settings.size_maximum && 
      extend <= ht_size_lim_p && extend_trigger <= ht_size_lim_p && 
      ht->table_itemcount == (1 << extend_trigger))
  {
    i = hashtable_resize(ht, extend);
  }
  else
  {
    i = HASHTABLE_SUCCESS;
  }

  new_item = malloc(sizeof(struct hashtableitem));

  if (new_item == NULL)
  {
    return HASHTABLE_OUT_OF_MEMORY;
  }

  new_item->key      = key;
  new_item->keylen   = keylen;
  new_item->key_hash = (ht->table_settings.hashfunction)(key, keylen);
  new_item->data     = data;

  hashtable_insert(ht, new_item);

  (ht->table_itemcount)++;

  if (i == HASHTABLE_OUT_OF_MEMORY)
  {
    return HASHTABLE_SUCCESS_YET_OUT_OF_MEMORY;
  }
  else
  {
    return HASHTABLE_SUCCESS;
  }
}
Exemplo n.º 3
0
/* Insert or update existing value. */
void hashtable_set(HashTable *table, const char *key, uint32_t len, void *value) {
	Entry *pEntry;
	/* 0 = Chain is empty, 1 = Found, 2 = Hit tail without finding. */
	int action = 0; 
	uint64_t hash = HASH(key, len);

	//DBGF("Insert: key %s hashed to %lu.\n", key, hash);
	/* TODO: Check if table is init'd. */
	pEntry = table->entries[hash & table->mask];
	/* Search chain. */
	while (!action && pEntry) {
		if (hashtable_entry_test(pEntry, hash, key, len)) {
			action = 1;
		}
		else if (!pEntry->pNext) {
			/* The current item is the tail. */
			action = 2;
		}
		else {
			pEntry = pEntry->pNext;
		}
	}

	if (action != 1) {
		if (action == 0) {
			/* Empty chain insert. */
			DBG("Set: inserting value (head).");
			pEntry = malloc(sizeof(Entry));
			table->entries[hash & table->mask] = pEntry;
			pEntry->pPrev = NULL;
		}
		else {
			/* Non-empty chain insert. */
			DBG("Set: inserting value.");
			pEntry->pNext = malloc(sizeof(Entry));
			/* Point new entry back at tail. */
			pEntry->pNext->pPrev = pEntry;
			pEntry = pEntry->pNext;
		}
		pEntry->pNext = NULL;
		pEntry->hash = hash;
		pEntry->key = malloc(len * sizeof(char));
		pEntry->key_len = len;
		memcpy(pEntry->key, key, len * sizeof(char));
		DBGF("Set: Allocated %u bytes for key %s.\n", len, key);
		table->count++;
	}
	else {
		DBG("Set: updating value.");
	}
	/* Set value. */
	pEntry->value = value;
	if (table->count > table->size) {
		hashtable_resize(table);
	}
}
Exemplo n.º 4
0
/* Create a new hashtable which is initially configured to hold up to
   initial_size buckets.  The table will be dynamically resized if
   more buckets are needed. */
struct hashtable *
hashtable_new(int initial_size)
{
  struct hashtable *table;

  table = (struct hashtable *)allocate(sizeof(struct hashtable));
  table->size = 0;
  table->count = 0;
  table->buckets = NULL;
  hashtable_resize(table, initial_size);
  if (table->buckets == NULL) {
    /* XXX error processing */
    free(table);
    return NULL;
  }
  return table;
}
Exemplo n.º 5
0
/**
 * Assign a value to the given key in the table.
 */
void hashtable_set(hashtable* t, char* key, void* value)
{
	int index = hashtable_find_slot(t, key);
	if (t->body[index].key != NULL) {
		/* Entry exists; update it. */
		t->body[index].value = value;
	} else {
		t->size++;
		/* Create a new  entry */
		if ((float)t->size / t->capacity > 0.8) {
			/* Resize the hash table */
			hashtable_resize(t, t->capacity * 2);
			index = hashtable_find_slot(t, key);
		}
		t->body[index].key = key;
		t->body[index].value = value;
	}
}
Exemplo n.º 6
0
int main(int argc, char* argv[])
{
    hashtable_t* table = NULL;
    hashnode_t* node = NULL;
    int i;
    int size;

    table = (hashtable_t*)malloc(sizeof(hashtable_t));
    assert(table != NULL);

    size = 50;
    hashtable_init(table, size);
    for (i = 0; i < size; i++) {
        assert(table->buckets[i] == NULL);
    }
    assert(table->size == 50);

    hashtable_insert(table, "abcd");
    node = hashtable_find(table, "abcd");
    assert(node != NULL);


    hashtable_insert(table, "bcde");
    node = hashtable_find(table, "bcde");
    assert(node != NULL);

    size = 80;
    hashtable_resize(&table, size);
    assert(table->size == size);

    node = hashtable_find(table, "abcd");
    assert(node != NULL);
    node = hashtable_find(table, "bcde");
    assert(node != NULL);

    hashtable_clear(table);
    free(table);

    return 0;
}
Exemplo n.º 7
0
/* Store a value in a hashtable, associated with a given key.  A copy
   of the key is made.  The previous association with this key is
   returned, or NULL if this is a new key for this hashtable.

   Note that you can specify NULL values to be stored, but you cannot
   remove a key association.  This would require searching for
   following buckets that might have to be moved to this one to
   restore table consistancy.  Since I don't see the need to delete at
   this time, I'm not worrying about it.
 */
void *
hashtable_put(struct hashtable *table, char *key, void *value)
{
  void *old;
  int hash = hash_string(key);
  struct hashtable_bucket *bucket = hashtable_find_bucket(table->buckets, table->size, hash, key);
  if (bucket->key == NULL) {
    bucket->hash = hash;
    bucket->key = copy_string(key);
    bucket->value = value;
    table->count++;
    if (((float)table->count) / (float)(table->size) > RESIDENCY) {
      hashtable_resize(table, table->size+1);
    }
    return NULL;
  } else {
    old = bucket->value;
    bucket->value = value;
    return old;
  }
  
}
Exemplo n.º 8
0
int hashtable_new_custom(struct hashtable *ht, 
                         const struct hashtablesettings *s)
{
  int r;

  r = hashtable_verify_settings(s);
  if (r != HASHTABLE_SUCCESS)
  {
    return r;
  }

  ht->table              = NULL;
  ht->table_size_p       = 0;
  ht->table_size         = 0;
  ht->table_itemcount    = 0;
  ht->table_mask         = 0;
  ht->table_settings     = *s;

  /* If this fails now it won't have allocated any memory 
   * (this is not true for its later use in hashtable_set) */
  return hashtable_resize(ht, ht->table_settings.size_initial);
}
Exemplo n.º 9
0
uint deps_add_evr(struct deps *deps, const char *name, int flags, uint epoch,
		const char *version, const char *release) {
	uint i, iter = 0, hash, size = array_get_size(&deps->names), ver, rel, nam;

	nam = strings_add(deps->strings, name);
	ver = strings_add(deps->strings, version != NULL ? version : "");
	rel = strings_add(deps->strings, release != NULL ? release : "");

	if (hashtable_resize(&deps->hashtable)) {
		for (i = 0; i < size; i++) {
			hash = dephash(array_get(&deps->names, i));
			hashtable_add(&deps->hashtable, i, hash);
		}
	}

	hash = dephash(nam);

	while ((i = hashtable_find(&deps->hashtable, hash, &iter)) != -1)
		if (array_get(&deps->names, i) == nam &&
				array_get(&deps->epochs, i) == epoch &&
				array_get(&deps->vers, i) == ver &&
				array_get(&deps->rels, i) == rel &&
				array_get(&deps->flags, i) == flags)
			break;
	if (i != -1)
		/* already stored */
		return i;

	i = size;
	array_set(&deps->names, i, nam);
	array_set(&deps->epochs, i, epoch);
	array_set(&deps->vers, i, ver);
	array_set(&deps->rels, i, rel);
	array_set(&deps->flags, i, flags);
	hashtable_add_dir(&deps->hashtable, i, hash, iter);

	return i;
}
Exemplo n.º 10
0
void test_basic(dict *dct, const struct key_info *keys, const unsigned nkeys,
		const struct closest_lookup_info *cl_infos,
		unsigned n_cl_infos) {
    dict_itor *itor = dict_itor_new(dct);

    CU_ASSERT_TRUE(dict_verify(dct));

    for (unsigned i = 0; i < nkeys; ++i) {
	bool inserted = false;
	void **datum_location = dict_insert(dct, keys[i].key, &inserted);
	CU_ASSERT_TRUE(inserted);
	CU_ASSERT_PTR_NOT_NULL(datum_location);
	CU_ASSERT_PTR_NULL(*datum_location);
	*datum_location = keys[i].value;

	CU_ASSERT_TRUE(dict_verify(dct));

	for (unsigned j = 0; j <= i; ++j)
	    test_search(dct, itor, keys[j].key, keys[j].value);
	for (unsigned j = i + 1; j < nkeys; ++j)
	    test_search(dct, itor, keys[j].key, NULL);
    }
    CU_ASSERT_EQUAL(dict_count(dct), nkeys);

    if (dct->_vtable->insert == (dict_insert_func)hashtable_insert ||
	dct->_vtable->insert == (dict_insert_func)hashtable2_insert) {
	/* Verify that hashtable_resize works as expected. */
	dict *clone = dict_clone(dct, NULL);
	CU_ASSERT_TRUE(dict_verify(dct));
	if (dct->_vtable->insert == (dict_insert_func)hashtable_insert) {
	    CU_ASSERT_TRUE(hashtable_resize(dict_private(clone), 3));
	} else {
	    CU_ASSERT_TRUE(hashtable2_resize(dict_private(clone), 3));
	}
	CU_ASSERT_TRUE(dict_verify(dct));
	for (unsigned j = 0; j < nkeys; ++j)
	    test_search(clone, NULL, keys[j].key, keys[j].value);
	dict_free(clone);
    }

    if (dct->_vtable->clone) {
	dict *clone = dict_clone(dct, NULL);
	CU_ASSERT_PTR_NOT_NULL(clone);
	CU_ASSERT_TRUE(dict_verify(clone));
	CU_ASSERT_EQUAL(dict_count(clone), nkeys);
	for (unsigned i = 0; i < nkeys; ++i) {
	    test_search(clone, itor, keys[i].key, keys[i].value);
	}
	for (unsigned i = 0; i < nkeys; ++i) {
	    CU_ASSERT_TRUE(dict_remove(clone, keys[i].key));
	}
	dict_free(clone);
    }

    for (unsigned i = 0; i < nkeys; ++i)
	test_search(dct, itor, keys[i].key, keys[i].value);

    for (unsigned i = 0; i < nkeys; ++i) {
	bool inserted = false;
	void **datum_location = dict_insert(dct, keys[i].key, &inserted);
	CU_ASSERT_FALSE(inserted);
	CU_ASSERT_PTR_NOT_NULL(datum_location);
	CU_ASSERT_EQUAL(*datum_location, keys[i].value);

	CU_ASSERT_TRUE(dict_verify(dct));
    }
    CU_ASSERT_EQUAL(dict_count(dct), nkeys);

    CU_ASSERT_PTR_NOT_NULL(itor);
    char *last_key = NULL;
    unsigned n = 0;
    for (dict_itor_first(itor); dict_itor_valid(itor); dict_itor_next(itor)) {
	CU_ASSERT_PTR_NOT_NULL(dict_itor_key(itor));
	CU_ASSERT_PTR_NOT_NULL(dict_itor_data(itor));
	CU_ASSERT_PTR_NOT_NULL(*dict_itor_data(itor));

	char *key = dict_itor_key(itor);
	bool key_matched = false;
	for (unsigned i = 0; i < nkeys; ++i) {
	    if (keys[i].key == key) {
		CU_ASSERT_EQUAL(*dict_itor_data(itor), keys[i].value);
		key_matched = true;
		break;
	    }
	}
	CU_ASSERT_TRUE(key_matched);

	if (dct->_vtable->insert != (dict_insert_func)hashtable_insert &&
	    dct->_vtable->insert != (dict_insert_func)hashtable2_insert) {
	    if (last_key) {
		CU_ASSERT_TRUE(strcmp(last_key, dict_itor_key(itor)) < 0);
	    }
	    last_key = dict_itor_key(itor);
	}

	++n;
    }
    CU_ASSERT_EQUAL(n, nkeys);
    last_key = NULL;
    n = 0;
    for (dict_itor_last(itor); dict_itor_valid(itor); dict_itor_prev(itor)) {
	CU_ASSERT_PTR_NOT_NULL(dict_itor_key(itor));
	CU_ASSERT_PTR_NOT_NULL(dict_itor_data(itor));
	CU_ASSERT_PTR_NOT_NULL(*dict_itor_data(itor));

	char *key = dict_itor_key(itor);
	bool key_matched = false;
	for (unsigned i = 0; i < nkeys; ++i) {
	    if (keys[i].key == key) {
		CU_ASSERT_EQUAL(*dict_itor_data(itor), keys[i].value);
		key_matched = true;
		break;
	    }
	}
	CU_ASSERT_TRUE(key_matched);

	if (dct->_vtable->insert != (dict_insert_func)hashtable_insert &&
	    dct->_vtable->insert != (dict_insert_func)hashtable2_insert) {
	    if (last_key) {
		CU_ASSERT_TRUE(strcmp(last_key, dict_itor_key(itor)) > 0);
	    }
	    last_key = dict_itor_key(itor);
	}

	++n;
    }
    CU_ASSERT_EQUAL(n, nkeys);

    for (unsigned i = 0; i < nkeys; ++i) {
	bool inserted = false;
	void **datum_location = dict_insert(dct, keys[i].key, &inserted);
	CU_ASSERT_FALSE(inserted);
	CU_ASSERT_PTR_NOT_NULL(datum_location);
	CU_ASSERT_PTR_NOT_NULL(*datum_location);
	*datum_location = keys[i].alt;

	CU_ASSERT_TRUE(dict_verify(dct));
    }
    CU_ASSERT_EQUAL(dict_count(dct), nkeys);

    for (unsigned i = 0; i < nkeys; ++i)
	test_search(dct, itor, keys[i].key, keys[i].alt);

    for (unsigned i = 0; i < nkeys; ++i) {
	test_search(dct, itor, keys[i].key, keys[i].alt);
	CU_ASSERT_TRUE(dict_remove(dct, keys[i].key));
	CU_ASSERT_TRUE(dict_verify(dct));

	CU_ASSERT_EQUAL(dict_remove(dct, keys[i].key), false);
	for (unsigned j = 0; j <= i; ++j) {
	    test_search(dct, itor, keys[j].key, NULL);
	}
	for (unsigned j = i + 1; j < nkeys; ++j) {
	    test_search(dct, itor, keys[j].key, keys[j].alt);
	}
    }

    for (unsigned i = 0; i < nkeys; ++i) {
	bool inserted = false;
	void **datum_location = dict_insert(dct, keys[i].key, &inserted);
	CU_ASSERT_TRUE(inserted);
	CU_ASSERT_PTR_NOT_NULL(datum_location);
	CU_ASSERT_PTR_NULL(*datum_location);
	*datum_location = keys[i].value;

	CU_ASSERT_TRUE(dict_verify(dct));
    }
    CU_ASSERT_EQUAL(dict_count(dct), nkeys);
    CU_ASSERT_EQUAL(dict_clear(dct), nkeys);

    for (unsigned i = 0; i < nkeys; ++i) {
	bool inserted = false;
	void **datum_location = dict_insert(dct, keys[i].key, &inserted);
	CU_ASSERT_TRUE(inserted);
	CU_ASSERT_PTR_NOT_NULL(datum_location);
	CU_ASSERT_PTR_NULL(*datum_location);
	*datum_location = keys[i].value;

	CU_ASSERT_TRUE(dict_verify(dct));
    }
    test_closest_lookup(dct, cl_infos, n_cl_infos);
    dict_itor_free(itor);
    CU_ASSERT_EQUAL(dict_count(dct), nkeys);
    CU_ASSERT_EQUAL(dict_free(dct), nkeys);
}
Exemplo n.º 11
0
void hashtable_set(hashtable_t* input, const void* key, size_t key_length, void* value)
{
	//fprintf(stderr,"store(%s,%p)\n",key,value);
	uint32_t hashcode=_hashtable_function(key, key_length);
	uint32_t bucket=hashcode%input->size;
	hashelement_t* element=input->buckets[bucket];
#ifdef HASHTABLE_REORDER_ON_ACCESS
	hashelement_t* previous_element=NULL;
#endif
#ifdef HASHTABLE_GATHER_STATS
	unsigned int num_hits=1;
#endif
	while(element!=NULL)
	{
		if(element->key_length==key_length && memcmp(element->key,key,key_length)==0)
		{
			element->value=value;
#ifdef HASHTABLE_GATHER_STATS
			input->num_hits_per_access+=num_hits;
			input->num_accesses++;
#endif
#ifdef HASHTABLE_REORDER_ON_ACCESS
			if(previous_element!=NULL)
			{
				previous_element->next_in_bucket=element->next_in_bucket;
				element->next_in_bucket=input->buckets[bucket];
				input->buckets[bucket]=element;
			}
#endif
			return;
		}
#ifdef HASHTABLE_GATHER_STATS
		num_hits++;
#endif
#ifdef HASHTABLE_REORDER_ON_ACCESS
		previous_element=element;
#endif
		element=element->next_in_bucket;
	}
#ifdef HASHTABLE_GATHER_STATS
	input->num_hits_per_access+=num_hits;
	input->num_accesses++;
#endif
	element = (hashelement_t*)MALLOC(sizeof(hashelement_t));
	element->hashcode=hashcode;
#ifdef HASHTABLE_CENTRALIZE_KEYS
	if(input==_hashtable_key_repository)
	{
		element->key=key;
	}
	else
	{
		if(_hashtable_key_repository==NULL)
			_hashtable_key_repository=hashtable_new();
		char* repository_key=hashtable_fetch(_hashtable_key_repository, key, key_length);
		if(repository_key==NULL)
		{
			repository_key=MALLOC(key_length);
			memcpy(repository_key,key,key_length);
			hashtable_store(_hashtable_key_repository, repository_key, key_length, repository_key);
		}
		element->key=repository_key;
	}
#else
	element->key=MALLOC(key_length);
	memcpy(element->key,key,key_length);
#endif
	element->key_length=key_length;
	element->value=value;
	element->next_in_bucket=input->buckets[bucket];
	input->buckets[bucket]=element;
	input->length++;
#ifdef HASHTABLE_INCREASE_SIZE
	if(input->length/input->size>input->max_average_collisions)hashtable_resize(input, (size_t)(input->size*(input->resize_factor)+1));//+input->size);
#endif
}
Exemplo n.º 12
0
void test_basic(dict *dct, const struct key_info *keys, const unsigned nkeys) {
    CU_ASSERT_TRUE(dict_verify(dct));

    for (unsigned i = 0; i < nkeys; ++i) {
	void **datum_location = NULL;
	CU_ASSERT_TRUE(dict_insert(dct, keys[i].key, &datum_location));
	CU_ASSERT_PTR_NOT_NULL(datum_location);
	*datum_location = keys[i].value;

	CU_ASSERT_TRUE(dict_verify(dct));

	for (unsigned j = 0; j <= i; ++j)
	    CU_ASSERT_EQUAL(dict_search(dct, keys[j].key), keys[j].value);
	for (unsigned j = i + 1; j < nkeys; ++j)
	    CU_ASSERT_EQUAL(dict_search(dct, keys[j].key), NULL);
    }
    CU_ASSERT_EQUAL(dict_count(dct), nkeys);

    if (dct->_vtable->insert == (dict_insert_func)hashtable_insert) {
	/* Verify that hashtable_resize works as expected. */
	dict *clone = dict_clone(dct, NULL);
	CU_ASSERT_TRUE(dict_verify(dct));
	CU_ASSERT_TRUE(hashtable_resize(dict_private(clone), 3));
	CU_ASSERT_TRUE(dict_verify(dct));
	for (unsigned j = 0; j < nkeys; ++j)
	    CU_ASSERT_EQUAL(dict_search(clone, keys[j].key), keys[j].value);
	dict_free(clone);
    }

    if (dct->_vtable->clone) {
	dict *clone = dict_clone(dct, NULL);
	CU_ASSERT_PTR_NOT_NULL(clone);
	CU_ASSERT_TRUE(dict_verify(clone));
	CU_ASSERT_EQUAL(dict_count(clone), nkeys);
	for (unsigned i = 0; i < nkeys; ++i) {
	    CU_ASSERT_EQUAL(dict_search(clone, keys[i].key), keys[i].value);
	}
	for (unsigned i = 0; i < nkeys; ++i) {
	    CU_ASSERT_TRUE(dict_remove(clone, keys[i].key));
	}
	dict_free(clone);
    }

    for (unsigned i = 0; i < nkeys; ++i)
	CU_ASSERT_EQUAL(dict_search(dct, keys[i].key), keys[i].value);

    for (unsigned i = 0; i < nkeys; ++i) {
	void **datum_location = NULL;
	CU_ASSERT_FALSE(dict_insert(dct, keys[i].key, &datum_location));
	CU_ASSERT_PTR_NOT_NULL(datum_location);
	CU_ASSERT_EQUAL(*datum_location, keys[i].value);

	CU_ASSERT_TRUE(dict_verify(dct));
    }
    CU_ASSERT_EQUAL(dict_count(dct), nkeys);

    dict_itor *itor = dict_itor_new(dct);
    CU_ASSERT_PTR_NOT_NULL(itor);
    char *last_key = NULL;
    unsigned n = 0;
    for (dict_itor_first(itor); dict_itor_valid(itor); dict_itor_next(itor)) {
	CU_ASSERT_PTR_NOT_NULL(dict_itor_key(itor));
	CU_ASSERT_PTR_NOT_NULL(dict_itor_data(itor));
	++n;
	if (dct->_vtable->insert != (dict_insert_func)hashtable_insert) {
	    if (last_key) {
		CU_ASSERT_TRUE(strcmp(last_key, dict_itor_key(itor)) < 0);
	    }
	    last_key = dict_itor_key(itor);
	}
    }
    CU_ASSERT_EQUAL(n, nkeys);
    last_key = NULL;
    n = 0;
    for (dict_itor_last(itor); dict_itor_valid(itor); dict_itor_prev(itor)) {
	CU_ASSERT_PTR_NOT_NULL(dict_itor_key(itor));
	CU_ASSERT_PTR_NOT_NULL(dict_itor_data(itor));
	++n;
	if (dct->_vtable->insert != (dict_insert_func)hashtable_insert) {
	    if (last_key) {
		CU_ASSERT_TRUE(strcmp(last_key, dict_itor_key(itor)) > 0);
	    }
	    last_key = dict_itor_key(itor);
	}
    }
    CU_ASSERT_EQUAL(n, nkeys);
    dict_itor_free(itor);

    for (unsigned i = 0; i < nkeys; ++i) {
	void **datum_location = NULL;
	CU_ASSERT_FALSE(dict_insert(dct, keys[i].key, &datum_location));
	CU_ASSERT_PTR_NOT_NULL(datum_location);
	*datum_location = keys[i].alt;

	CU_ASSERT_TRUE(dict_verify(dct));
    }
    CU_ASSERT_EQUAL(dict_count(dct), nkeys);

    for (unsigned i = 0; i < nkeys; ++i)
	CU_ASSERT_EQUAL(dict_search(dct, keys[i].key), keys[i].alt);

    for (unsigned i = 0; i < nkeys; ++i) {
	CU_ASSERT_EQUAL(dict_search(dct, keys[i].key), keys[i].alt);
	CU_ASSERT_TRUE(dict_remove(dct, keys[i].key));
	CU_ASSERT_TRUE(dict_verify(dct));

	CU_ASSERT_EQUAL(dict_remove(dct, keys[i].key), false);
	for (unsigned j = 0; j <= i; ++j) {
	    CU_ASSERT_EQUAL(dict_search(dct, keys[j].key), NULL);
	}
	for (unsigned j = i + 1; j < nkeys; ++j) {
	    CU_ASSERT_EQUAL(dict_search(dct, keys[j].key), keys[j].alt);
	}
    }

    for (unsigned i = 0; i < nkeys; ++i) {
	void **datum_location = NULL;
	CU_ASSERT_TRUE(dict_insert(dct, keys[i].key, &datum_location));
	CU_ASSERT_PTR_NOT_NULL(datum_location);
	*datum_location = keys[i].value;

	CU_ASSERT_TRUE(dict_verify(dct));
    }
    CU_ASSERT_EQUAL(dict_count(dct), nkeys);
    CU_ASSERT_EQUAL(dict_clear(dct), nkeys);

    for (unsigned i = 0; i < nkeys; ++i) {
	void **datum_location = NULL;
	CU_ASSERT_TRUE(dict_insert(dct, keys[i].key, &datum_location));
	CU_ASSERT_PTR_NOT_NULL(datum_location);
	*datum_location = keys[i].value;

	CU_ASSERT_TRUE(dict_verify(dct));
    }
    CU_ASSERT_EQUAL(dict_count(dct), nkeys);
    CU_ASSERT_EQUAL(dict_free(dct), nkeys);
}