/**
* Map for IP addresses to iface_entry_t objects (addr_map_entry_t)
*/
- hashtable_t *addrs;
+ hashlist_t *addrs;
/**
* Map for virtual IP addresses to iface_entry_t objects (addr_map_entry_t)
*/
- hashtable_t *vips;
+ hashlist_t *vips;
/**
* netlink rt socket (routing)
/**
* installed routes
*/
- hashtable_t *routes;
+ hashlist_t *routes;
/**
* mutex for routes
this->net_changes_lock->lock(this->net_changes_lock);
this->routes_lock->lock(this->routes_lock);
- enumerator = this->routes->create_enumerator(this->routes);
+ enumerator = this->routes->ht.create_enumerator(&this->routes->ht);
while (enumerator->enumerate(enumerator, NULL, (void**)&route))
{
net_change_t *change, lookup = {
/**
* Add an address map entry
*/
-static void addr_map_entry_add(hashtable_t *map, addr_entry_t *addr,
+static void addr_map_entry_add(hashlist_t *map, addr_entry_t *addr,
iface_entry_t *iface)
{
addr_map_entry_t *entry;
.addr = addr,
.iface = iface,
);
- entry = map->put(map, entry, entry);
+ entry = map->ht.put(&map->ht, entry, entry);
free(entry);
}
/**
* Remove an address map entry
*/
-static void addr_map_entry_remove(hashtable_t *map, addr_entry_t *addr,
+static void addr_map_entry_remove(hashlist_t *map, addr_entry_t *addr,
iface_entry_t *iface)
{
addr_map_entry_t *entry, lookup = {
.iface = iface,
};
- entry = map->remove(map, &lookup);
+ entry = map->ht.remove(&map->ht, &lookup);
free(entry);
}
};
addr_entry_t *addr;
- entry = this->vips->get(this->vips, &lookup);
+ entry = this->vips->ht.get(&this->vips->ht, &lookup);
if (entry)
{
if (hdr->nlmsg_type == RTM_NEWADDR)
host->destroy(host);
return;
}
- entry = this->addrs->get(this->addrs, &lookup);
+ entry = this->addrs->ht.get(&this->addrs->ht, &lookup);
if (entry)
{
if (hdr->nlmsg_type == RTM_DELADDR)
}
this->routes_lock->lock(this->routes_lock);
- found = this->routes->get(this->routes, &lookup.route);
+ found = this->routes->ht.get(&this->routes->ht, &lookup.route);
if (found)
{
this->routes_lock->unlock(this->routes_lock);
if (status == SUCCESS)
{
found = route_entry_clone(&lookup.route);
- this->routes->put(this->routes, found, found);
+ this->routes->ht.put(&this->routes->ht, found, found);
}
this->routes_lock->unlock(this->routes_lock);
return status;
}
this->routes_lock->lock(this->routes_lock);
- found = this->routes->remove(this->routes, &lookup.route);
+ found = this->routes->ht.remove(&this->routes->ht, &lookup.route);
if (!found)
{
this->routes_lock->unlock(this->routes_lock);
/**
* Destroy an address to iface map
*/
-static void addr_map_destroy(hashtable_t *map)
+static void addr_map_destroy(hashlist_t *map)
{
- enumerator_t *enumerator;
- addr_map_entry_t *addr;
-
- enumerator = map->create_enumerator(map);
- while (enumerator->enumerate(enumerator, NULL, (void**)&addr))
- {
- free(addr);
- }
- enumerator->destroy(enumerator);
- map->destroy(map);
+ map->ht.destroy_function(&map->ht, (void*)free);
}
METHOD(kernel_net_t, destroy, void,
lib->watcher->remove(lib->watcher, this->socket_events);
close(this->socket_events);
}
- enumerator = this->routes->create_enumerator(this->routes);
+ enumerator = this->routes->ht.create_enumerator(&this->routes->ht);
while (enumerator->enumerate(enumerator, NULL, (void**)&route))
{
manage_srcroute(this, RTM_DELROUTE, 0, route->dst_net, route->prefixlen,
lib->settings->get_bool(lib->settings,
"%s.plugins.kernel-netlink.parallel_route", FALSE, lib->ns)),
.rt_exclude = linked_list_create(),
- .routes = hashtable_create((hashtable_hash_t)route_entry_hash,
- (hashtable_equals_t)route_entry_equals, 16),
+ .routes = hashlist_create((hashtable_hash_t)route_entry_hash,
+ (hashtable_equals_t)route_entry_equals, 16),
.net_changes = hashtable_create(
(hashtable_hash_t)net_change_hash,
(hashtable_equals_t)net_change_equals, 16),
- .addrs = hashtable_create(
+ .addrs = hashlist_create(
(hashtable_hash_t)addr_map_entry_hash,
(hashtable_equals_t)addr_map_entry_equals, 16),
- .vips = hashtable_create((hashtable_hash_t)addr_map_entry_hash,
+ .vips = hashlist_create((hashtable_hash_t)addr_map_entry_hash,
(hashtable_equals_t)addr_map_entry_equals, 16),
.routes_lock = mutex_create(MUTEX_TYPE_DEFAULT),
.net_changes_lock = mutex_create(MUTEX_TYPE_DEFAULT),
/**
* Map for IP addresses to iface_entry_t objects (addr_map_entry_t)
*/
- hashtable_t *addrs;
+ hashlist_t *addrs;
/**
* List of tun devices we installed for virtual IPs
.addr = addr,
.iface = iface,
);
- entry = this->addrs->put(this->addrs, entry, entry);
+ entry = this->addrs->ht.put(&this->addrs->ht, entry, entry);
free(entry);
}
.iface = iface,
};
- entry = this->addrs->remove(this->addrs, &lookup);
+ entry = this->addrs->ht.remove(&this->addrs->ht, &lookup);
free(entry);
}
{
enumerator_t *enumerator;
route_entry_t *route;
- addr_entry_t *addr;
enumerator = this->routes->create_enumerator(this->routes);
while (enumerator->enumerate(enumerator, NULL, (void**)&route))
this->net_changes->destroy(this->net_changes);
this->net_changes_lock->destroy(this->net_changes_lock);
- enumerator = this->addrs->create_enumerator(this->addrs);
- while (enumerator->enumerate(enumerator, NULL, (void**)&addr))
- {
- free(addr);
- }
- enumerator->destroy(enumerator);
- this->addrs->destroy(this->addrs);
+ this->addrs->ht.destroy_function(&this->addrs->ht, (void*)free);
this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy);
this->tuns->destroy(this->tuns);
this->lock->destroy(this->lock);
},
.pid = getpid(),
.ifaces = linked_list_create(),
- .addrs = hashtable_create(
+ .addrs = hashlist_create(
(hashtable_hash_t)addr_map_entry_hash,
(hashtable_equals_t)addr_map_entry_equals, 16),
.routes = hashtable_create((hashtable_hash_t)route_entry_hash,
#endif
};
+typedef struct private_hashlist_t private_hashlist_t;
+
+/**
+ * Private data of a hashlist_t object.
+ */
+struct private_hashlist_t {
+
+ /**
+ * Public part of hash table.
+ */
+ hashlist_t public;
+
+ /**
+ * Inherited private part of hash table (we get the public part too, but
+ * ignore it).
+ */
+ private_hashtable_t super;
+};
+
#ifdef HASHTABLE_PROFILER
#define lookup_start() \
while (pair)
{
lookup_probing();
- /* when keys are ordered, we compare all items so we can abort earlier
+ /* when keys are sorted, we compare all items so we can abort earlier
* even if the hash does not match, but only as long as we don't
* have a callback */
if (!use_callback && this->cmp)
return pair ? pair->value : NULL;
}
-METHOD(hashtable_t, get_match, void*,
- private_hashtable_t *this, const void *key, hashtable_equals_t match)
-{
- pair_t *pair = find_key(this, key, match, NULL, NULL);
- return pair ? pair->value : NULL;
-}
-
METHOD(hashtable_t, remove_, void*,
private_hashtable_t *this, const void *key)
{
}
}
free(this->table);
- free(this);
}
METHOD(hashtable_t, destroy, void,
private_hashtable_t *this)
{
destroy_internal(this, NULL);
+ free(this);
}
METHOD(hashtable_t, destroy_function, void,
private_hashtable_t *this, void (*fn)(void*,const void*))
{
destroy_internal(this, fn);
+ free(this);
}
-/**
- * Create a hash table
+METHOD(hashtable_t, create_enumerator_hashlist, enumerator_t*,
+ private_hashlist_t *this)
+{
+ return create_enumerator(&this->super);
+}
+
+METHOD(hashtable_t, put_hashlist, void*,
+ private_hashlist_t *this, const void *key, void *value)
+{
+ return put(&this->super, key, value);
+}
+
+METHOD(hashtable_t, get_hashlist, void*,
+ private_hashlist_t *this, const void *key)
+{
+ return get(&this->super, key);
+}
+
+METHOD(hashlist_t, get_match, void*,
+ private_hashlist_t *this, const void *key, hashtable_equals_t match)
+{
+ pair_t *pair = find_key(&this->super, key, match, NULL, NULL);
+ return pair ? pair->value : NULL;
+}
+
+METHOD(hashtable_t, remove_hashlist, void*,
+ private_hashlist_t *this, const void *key)
+{
+ return remove_(&this->super, key);
+}
+
+METHOD(hashtable_t, remove_at_hashlist, void,
+ private_hashlist_t *this, private_enumerator_t *enumerator)
+{
+ remove_at(&this->super, enumerator);
+}
+
+METHOD(hashtable_t, get_count_hashlist, u_int,
+ private_hashlist_t *this)
+{
+ return get_count(&this->super);
+}
+
+METHOD2(hashtable_t, hashlist_t, destroy_hashlist, void,
+ private_hashlist_t *this)
+{
+ destroy_internal(&this->super, NULL);
+ free(this);
+}
+
+METHOD(hashtable_t, destroy_function_hashlist, void,
+ private_hashlist_t *this, void (*fn)(void*,const void*))
+{
+ destroy_internal(&this->super, fn);
+ free(this);
+}
+
+/*
+ * Described in header
*/
-static private_hashtable_t *hashtable_create_internal(hashtable_hash_t hash,
- u_int size)
+hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals,
+ u_int size)
{
private_hashtable_t *this;
.public = {
.put = _put,
.get = _get,
- .get_match = _get_match,
.remove = _remove_,
.remove_at = (void*)_remove_at,
.get_count = _get_count,
.destroy_function = _destroy_function,
},
.hash = hash,
+ .equals = equals,
);
init_hashtable(this, size);
this->backtrace = backtrace_create(3);
#endif
+ return &this->public;
+}
+
+/**
+ * Create a hash table
+ */
+static private_hashlist_t *hashlist_create_internal(hashtable_hash_t hash,
+ u_int size)
+{
+ private_hashlist_t *this;
+
+ INIT(this,
+ .public = {
+ .ht = {
+ .put = _put_hashlist,
+ .get = _get_hashlist,
+ .remove = _remove_hashlist,
+ .remove_at = (void*)_remove_at_hashlist,
+ .get_count = _get_count_hashlist,
+ .create_enumerator = _create_enumerator_hashlist,
+ .destroy = _destroy_hashlist,
+ .destroy_function = _destroy_function_hashlist,
+ },
+ .get_match = _get_match,
+ .destroy = _destroy_hashlist,
+ },
+ .super = {
+ .hash = hash,
+ }
+ );
+
+ init_hashtable(&this->super, size);
+
+#ifdef HASHTABLE_PROFILER
+ this->super.backtrace = backtrace_create(3);
+#endif
+
return this;
}
/*
* Described in header
*/
-hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals,
- u_int size)
+hashlist_t *hashlist_create(hashtable_hash_t hash, hashtable_equals_t equals,
+ u_int size)
{
- private_hashtable_t *this = hashtable_create_internal(hash, size);
+ private_hashlist_t *this = hashlist_create_internal(hash, size);
- this->equals = equals;
+ this->super.equals = equals;
return &this->public;
}
/*
* Described in header
*/
-hashtable_t *hashtable_create_sorted(hashtable_hash_t hash,
- hashtable_cmp_t cmp, u_int size)
+hashlist_t *hashlist_create_sorted(hashtable_hash_t hash,
+ hashtable_cmp_t cmp, u_int size)
{
- private_hashtable_t *this = hashtable_create_internal(hash, size);
+ private_hashlist_t *this = hashlist_create_internal(hash, size);
- this->cmp = cmp;
+ this->super.cmp = cmp;
return &this->public;
}
#include <collections/enumerator.h>
typedef struct hashtable_t hashtable_t;
+typedef struct hashlist_t hashlist_t;
/**
* Prototype for a function that computes the hash code from the given key.
*/
void *(*get)(hashtable_t *this, const void *key);
- /**
- * Returns the first value with a matching key, if the hash table contains
- * such an entry, otherwise NULL is returned.
- *
- * Compared to get() the given match function is used to compare the keys
- * for equality. The hash function does have to be devised specially in
- * order to make this work if the match function compares keys differently
- * than the equals/comparison function provided to the constructor.
- *
- * This basically allows to enumerate all entries with the same hash value
- * in their key's order.
- *
- * @param key the key to match against
- * @param match match function to be used when comparing keys
- * @return the value, NULL if not found
- */
- void *(*get_match)(hashtable_t *this, const void *key,
- hashtable_equals_t match);
-
/**
* Removes the value with the given key from the hash table and returns the
* removed value (or NULL if no such value existed).
};
/**
- * Creates an empty hash table object. Items in buckets are ordered in
- * insertion order.
+ * Class implementing a hash table with ordered keys/items and special query
+ * method.
+ *
+ * @note The ordering only pertains to keys/items in the same bucket (with or
+ * without the same hash value), not to the order when enumerating.
+ *
+ * This is intended to be used with hash functions that intentionally return the
+ * same hash value for different keys so multiple items can be retrieved for a
+ * key.
+ *
+ * It's like storing sorted linked lists in a hash table but with less overhead.
+ */
+struct hashlist_t {
+
+ /**
+ * Implements the hash table interface.
+ */
+ hashtable_t ht;
+
+ /**
+ * Returns the first value with a matching key if the hash table contains
+ * such an entry, otherwise NULL is returned.
+ *
+ * Compared to get() the given match function is used to compare the keys
+ * for equality. The hash function does have to be devised specially in
+ * order to make this work if the match function compares keys differently
+ * than the equals/comparison function provided to the constructor.
+ *
+ * This basically allows to enumerate all entries with the same hash value
+ * in their key's order.
+ *
+ * @param key the key to match against
+ * @param match match function to be used when comparing keys
+ * @return the value, NULL if not found
+ */
+ void *(*get_match)(hashlist_t *this, const void *key,
+ hashtable_equals_t match);
+
+ /**
+ * Destroys a hash list object.
+ */
+ void (*destroy)(hashlist_t *this);
+};
+
+/**
+ * Creates an empty hash table object.
*
* @param hash hash function
* @param equals equals function
u_int size);
/**
- * Creates an empty hash table object with keys in each bucket sorted according
- * to the given comparison function.
+ * Creates an empty hash list object with each bucket's keys in insertion order.
+ *
+ * @param hash hash function
+ * @param equals equals function
+ * @param size initial size
+ * @return hashtable_t object
+ */
+hashlist_t *hashlist_create(hashtable_hash_t hash, hashtable_equals_t equals,
+ u_int size);
+
+/**
+ * Creates an empty hash list object with sorted keys in each bucket.
*
* @param hash hash function
* @param cmp comparison function
* @param size initial size
* @return hashtable_t object.
*/
-hashtable_t *hashtable_create_sorted(hashtable_hash_t hash,
- hashtable_cmp_t cmp, u_int size);
+hashlist_t *hashlist_create_sorted(hashtable_hash_t hash,
+ hashtable_cmp_t cmp, u_int size);
#endif /** HASHTABLE_H_ @}*/
/**
* Hashtable for registered features, as registered_feature_t
*/
- hashtable_t *features;
+ hashlist_t *features;
/**
* Loaded features (stored in reverse order), as provided_feature_t
{
case FEATURE_PROVIDE:
lookup.feature = feature;
- registered = this->features->get(this->features, &lookup);
+ registered = this->features->ht.get(&this->features->ht,
+ &lookup);
if (!registered)
{
INIT(registered,
.feature = feature,
.plugins = linked_list_create(),
);
- this->features->put(this->features, registered, registered);
+ this->features->ht.put(&this->features->ht, registered,
+ registered);
}
INIT(provided,
.entry = entry,
registered_feature_t *registered, lookup;
lookup.feature = provided->feature;
- registered = this->features->get(this->features, &lookup);
+ registered = this->features->ht.get(&this->features->ht, &lookup);
if (registered)
{
registered->plugins->remove(registered->plugins, provided, NULL);
if (registered->plugins->get_count(registered->plugins) == 0)
{
- this->features->remove(this->features, &lookup);
+ this->features->ht.remove(&this->features->ht, &lookup);
registered->plugins->destroy(registered->plugins);
free(registered);
}
},
.plugins = linked_list_create(),
.loaded = linked_list_create(),
- .features = hashtable_create(
+ .features = hashlist_create(
(hashtable_hash_t)registered_feature_hash,
(hashtable_equals_t)registered_feature_equals, 64),
);
#include <utils/chunk.h>
/*******************************************************************************
- * string hash table functions
+ * hash table functions
*/
-static u_int hash(char *key)
+static u_int hash_match(char *key)
{
- return chunk_hash(chunk_from_str(key));
+ return chunk_hash(chunk_create(key, 4));
}
-static bool equals(char *key1, char *key2)
+static bool equal_match(char *key1, char *key2)
{
- return streq(key1, key2);
+ if (!strneq(key1, key2, 4))
+ {
+ return FALSE;
+ }
+ /* look for an item with a key < than what we look for */
+ return strcmp(key1, key2) >= 0;
}
/*******************************************************************************
static hashtable_t *ht;
-START_SETUP(setup_ht)
+typedef enum {
+ /* regular string hash table */
+ HASHTABLE_REGULAR,
+ /* regular string hash list */
+ HASHLIST_REGULAR,
+ /* sorted string hash list */
+ HASHLIST_REGULAR_SORTED,
+ REGULAR_MAX,
+ /* hash table with only 4 characters hashed -> one bucket tests */
+ HASHTABLE_FUZZY = REGULAR_MAX,
+ /* hash list with only 4 characters hashed */
+ HASHLIST_FUZZY,
+ /* sorted string hash list with only 4 characters hashed */
+ HASHLIST_FUZZY_SORTED,
+ HASHTABLE_MAX,
+} hashtable_type_t;
+
+/**
+ * Create a specific hash table/list
+ */
+static hashtable_t *create_hashtable(int i)
{
- ht = hashtable_create((hashtable_hash_t)hash,
- (hashtable_equals_t)equals, 0);
+ hashlist_t *hl = NULL;
+
+ DESTROY_IF(ht);
+
+ switch (i)
+ {
+ case HASHTABLE_REGULAR:
+ ht = hashtable_create(hashtable_hash_str,
+ hashtable_equals_str, 0);
+ break;
+ case HASHLIST_REGULAR:
+ hl = hashlist_create(hashtable_hash_str,
+ hashtable_equals_str, 0);
+ break;
+ case HASHLIST_REGULAR_SORTED:
+ hl = hashlist_create_sorted(hashtable_hash_str,
+ (hashtable_cmp_t)strcmp, 0);
+ break;
+ case HASHTABLE_FUZZY:
+ ht = hashtable_create((hashtable_hash_t)hash_match,
+ hashtable_equals_str, 0);
+ break;
+ case HASHLIST_FUZZY:
+ hl = hashlist_create((hashtable_hash_t)hash_match,
+ hashtable_equals_str, 0);
+ break;
+ case HASHLIST_FUZZY_SORTED:
+ hl = hashlist_create_sorted((hashtable_hash_t)hash_match,
+ (hashtable_cmp_t)strcmp, 0);
+ break;
+ }
+ if (hl)
+ {
+ ht = &hl->ht;
+ }
ck_assert_int_eq(ht->get_count(ht), 0);
+ return ht;
+}
+
+START_SETUP(setup_ht)
+{
+ create_hashtable(_i);
}
END_SETUP
START_TEARDOWN(teardown_ht)
{
ht->destroy(ht);
+ ht = NULL;
}
END_TEARDOWN
* get_match
*/
-static u_int hash_match(char *key)
-{
- return chunk_hash(chunk_create(key, 4));
-}
-
-static bool equal_match(char *key1, char *key2)
-{
- if (!strneq(key1, key2, 4))
- {
- return FALSE;
- }
- /* look for an item with a key < than what we look for */
- return strcmp(key1, key2) >= 0;
-}
-
START_TEST(test_get_match)
{
+ hashlist_t *hl;
char *k1 = "key1_a", *k2 = "key2", *k3 = "key1_b", *k4 = "key1_c";
char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value;
- ht = hashtable_create((hashtable_hash_t)hash_match,
- (hashtable_equals_t)equals, 0);
+ hl = (hashlist_t*)create_hashtable(HASHLIST_FUZZY);
ht->put(ht, k1, v1);
ht->put(ht, k2, v2);
ck_assert(streq(ht->get(ht, k3), v3));
ck_assert(value == NULL);
- value = ht->get_match(ht, k1, (hashtable_equals_t)equal_match);
+ value = hl->get_match(hl, k1, (hashtable_equals_t)equal_match);
ck_assert(value != NULL);
ck_assert(streq(value, v1));
- value = ht->get_match(ht, k2, (hashtable_equals_t)equal_match);
+ value = hl->get_match(hl, k2, (hashtable_equals_t)equal_match);
ck_assert(value != NULL);
ck_assert(streq(value, v2));
- value = ht->get_match(ht, k3, (hashtable_equals_t)equal_match);
+ value = hl->get_match(hl, k3, (hashtable_equals_t)equal_match);
ck_assert(value != NULL);
ck_assert(streq(value, v1));
- value = ht->get_match(ht, k4, (hashtable_equals_t)equal_match);
+ value = hl->get_match(hl, k4, (hashtable_equals_t)equal_match);
ck_assert(value != NULL);
ck_assert(streq(value, v1));
-
- ht->destroy(ht);
}
END_TEST
START_TEST(test_get_match_remove)
{
+ hashlist_t *hl;
char *k1 = "key1_a", *k2 = "key2", *k3 = "key1_b", *k4 = "key1_c";
char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value;
- ht = hashtable_create((hashtable_hash_t)hash_match,
- (hashtable_equals_t)equals, 0);
+ hl = (hashlist_t*)create_hashtable(HASHLIST_FUZZY);
+ /* by removing and reinserting the first item we verify that insertion
+ * order is adhered */
ht->put(ht, k1, v1);
ht->put(ht, k2, v2);
ht->put(ht, k3, v3);
ck_assert(streq(ht->get(ht, k2), v2));
ck_assert(streq(ht->get(ht, k3), v3));
- value = ht->get_match(ht, k1, (hashtable_equals_t)equal_match);
+ value = hl->get_match(hl, k1, (hashtable_equals_t)equal_match);
ck_assert(value != NULL);
ck_assert(streq(value, v1));
- value = ht->get_match(ht, k2, (hashtable_equals_t)equal_match);
+ value = hl->get_match(hl, k2, (hashtable_equals_t)equal_match);
ck_assert(value != NULL);
ck_assert(streq(value, v2));
- value = ht->get_match(ht, k3, (hashtable_equals_t)equal_match);
+ value = hl->get_match(hl, k3, (hashtable_equals_t)equal_match);
ck_assert(value != NULL);
ck_assert(streq(value, v3));
- value = ht->get_match(ht, k4, (hashtable_equals_t)equal_match);
+ value = hl->get_match(hl, k4, (hashtable_equals_t)equal_match);
ck_assert(value != NULL);
ck_assert(streq(value, v3));
-
- ht->destroy(ht);
}
END_TEST
START_TEST(test_get_match_sorted)
{
+ hashlist_t *hl;
char *k1 = "key1_a", *k2 = "key2", *k3 = "key1_b", *k4 = "key1_c";
char *v1 = "val1", *v2 = "val2", *v3 = "val3", *value;
- ht = hashtable_create_sorted((hashtable_hash_t)hash_match,
- (hashtable_cmp_t)strcmp, 0);
+ hl = (hashlist_t*)create_hashtable(HASHLIST_FUZZY_SORTED);
+ /* since the keys are sorted, the insertion order doesn't matter */
ht->put(ht, k3, v3);
ht->put(ht, k2, v2);
ht->put(ht, k1, v1);
ck_assert(streq(ht->get(ht, k3), v3));
ck_assert(streq(ht->get(ht, k4), v1));
- value = ht->get_match(ht, k1, (hashtable_equals_t)equal_match);
+ value = hl->get_match(hl, k1, (hashtable_equals_t)equal_match);
ck_assert(value != NULL);
ck_assert(streq(value, v1));
- value = ht->get_match(ht, k2, (hashtable_equals_t)equal_match);
+ value = hl->get_match(hl, k2, (hashtable_equals_t)equal_match);
ck_assert(value != NULL);
ck_assert(streq(value, v2));
- value = ht->get_match(ht, k3, (hashtable_equals_t)equal_match);
+ value = hl->get_match(hl, k3, (hashtable_equals_t)equal_match);
ck_assert(value != NULL);
ck_assert(streq(value, v1));
- value = ht->get_match(ht, k4, (hashtable_equals_t)equal_match);
+ value = hl->get_match(hl, k4, (hashtable_equals_t)equal_match);
ck_assert(value != NULL);
ck_assert(streq(value, v1));
-
- ht->destroy(ht);
}
END_TEST
{
char *k1 = "key1_a", *k2 = "key1_b", *k3 = "key1_c";
- ht->destroy(ht);
- ht = hashtable_create((hashtable_hash_t)hash_match,
- (hashtable_equals_t)equals, 0);
-
- do_remove(k1, k2, k3);
- do_remove(k3, k2, k1);
- do_remove(k1, k3, k2);
-}
-END_TEST
-
-START_TEST(test_remove_sorted)
-{
- char *k1 = "key1", *k2 = "key2", *k3 = "key3";
-
- ht->destroy(ht);
- ht = hashtable_create_sorted((hashtable_hash_t)hash,
- (hashtable_cmp_t)strcmp, 0);
-
- do_remove(k1, k2, k3);
- do_remove(k3, k2, k1);
- do_remove(k1, k3, k2);
-}
-END_TEST
-
-START_TEST(test_remove_sorted_one_bucket)
-{
- char *k1 = "key1_a", *k2 = "key1_b", *k3 = "key1_c";
-
- ht->destroy(ht);
- ht = hashtable_create_sorted((hashtable_hash_t)hash_match,
- (hashtable_cmp_t)strcmp, 0);
-
do_remove(k1, k2, k3);
do_remove(k3, k2, k1);
do_remove(k1, k3, k2);
{
char *k1 = "key1_a", *k2 = "key1_b", *k3 = "key1_c";
- ht->destroy(ht);
- ht = hashtable_create((hashtable_hash_t)hash_match,
- (hashtable_equals_t)equals, 0);
-
do_remove_at(k1, k2, k3);
}
END_TEST
-
/*******************************************************************************
* many items
*/
return *key1 - *key2;
}
-START_SETUP(setup_ht_many)
+/**
+ * Create a specific hash table with integers as keys.
+ */
+static hashtable_t *create_int_hashtable(int i)
{
- ht = hashtable_create((hashtable_hash_t)hash_int,
- (hashtable_equals_t)equals_int, 0);
+ hashlist_t *hl = NULL;
+
+ DESTROY_IF(ht);
+
+ switch (i)
+ {
+ case HASHTABLE_REGULAR:
+ ht = hashtable_create((hashtable_hash_t)hash_int,
+ (hashtable_equals_t)equals_int, 0);
+ break;
+ case HASHLIST_REGULAR:
+ hl = hashlist_create((hashtable_hash_t)hash_int,
+ (hashtable_equals_t)equals_int, 0);
+ break;
+ case HASHLIST_REGULAR_SORTED:
+ hl = hashlist_create_sorted((hashtable_hash_t)hash_int,
+ (hashtable_cmp_t)cmp_int, 0);
+ break;
+ }
+ if (hl)
+ {
+ ht = &hl->ht;
+ }
ck_assert_int_eq(ht->get_count(ht), 0);
+ return ht;
+}
+
+START_SETUP(setup_ht_many)
+{
+ create_int_hashtable(_i >> 1);
}
END_SETUP
-START_SETUP(setup_ht_many_cmp)
+START_SETUP(setup_ht_lookups)
{
- ht = hashtable_create_sorted((hashtable_hash_t)hash_int,
- (hashtable_cmp_t)cmp_int, 0);
- ck_assert_int_eq(ht->get_count(ht), 0);
+ create_int_hashtable(_i);
}
END_SETUP
START_TEARDOWN(teardown_ht_many)
{
ht->destroy_function(ht, (void*)free);
+ ht = NULL;
}
END_TEARDOWN
START_TEST(test_many_items)
{
- u_int count = 250000;
+ u_int count = 100000;
int i, *val, r;
-#define GET_VALUE(i) ({ _i == 0 ? i : (count-1-i); })
+#define GET_VALUE(i) ({ (_i % 2) == 0 ? i : (count-1-i); })
for (i = 0; i < count; i++)
{
tc = tcase_create("put/get");
tcase_add_checked_fixture(tc, setup_ht, teardown_ht);
- tcase_add_test(tc, test_put_get);
+ tcase_add_loop_test(tc, test_put_get, 0, HASHTABLE_MAX);
suite_add_tcase(s, tc);
tc = tcase_create("get_match");
+ tcase_add_checked_fixture(tc, NULL, teardown_ht);
tcase_add_test(tc, test_get_match);
tcase_add_test(tc, test_get_match_remove);
tcase_add_test(tc, test_get_match_sorted);
tc = tcase_create("remove");
tcase_add_checked_fixture(tc, setup_ht, teardown_ht);
- tcase_add_test(tc, test_remove);
- tcase_add_test(tc, test_remove_one_bucket);
- tcase_add_test(tc, test_remove_sorted);
- tcase_add_test(tc, test_remove_sorted_one_bucket);
+ tcase_add_loop_test(tc, test_remove, 0, REGULAR_MAX);
+ tcase_add_loop_test(tc, test_remove_one_bucket, HASHTABLE_FUZZY, HASHTABLE_MAX);
suite_add_tcase(s, tc);
tc = tcase_create("enumerator");
tcase_add_checked_fixture(tc, setup_ht, teardown_ht);
- tcase_add_test(tc, test_enumerator);
+ tcase_add_loop_test(tc, test_enumerator, 0, HASHTABLE_MAX);
suite_add_tcase(s, tc);
tc = tcase_create("remove_at");
tcase_add_checked_fixture(tc, setup_ht, teardown_ht);
- tcase_add_test(tc, test_remove_at);
- tcase_add_test(tc, test_remove_at_one_bucket);
+ tcase_add_loop_test(tc, test_remove_at, 0, REGULAR_MAX);
+ tcase_add_loop_test(tc, test_remove_at_one_bucket, HASHTABLE_FUZZY, HASHTABLE_MAX);
suite_add_tcase(s, tc);
tc = tcase_create("many items");
tcase_add_checked_fixture(tc, setup_ht_many, teardown_ht_many);
tcase_set_timeout(tc, 10);
- tcase_add_loop_test(tc, test_many_items, 0, 2);
- tcase_add_test(tc, test_many_lookups_success);
- tcase_add_test(tc, test_many_lookups_failure_larger);
- tcase_add_test(tc, test_many_lookups_failure_smaller);
+ tcase_add_loop_test(tc, test_many_items, 0, REGULAR_MAX << 1);
suite_add_tcase(s, tc);
- tc = tcase_create("many items sorted");
- tcase_add_checked_fixture(tc, setup_ht_many_cmp, teardown_ht_many);
- tcase_set_timeout(tc, 10);
- tcase_add_loop_test(tc, test_many_items, 0, 2);
- tcase_add_test(tc, test_many_lookups_success);
- tcase_add_test(tc, test_many_lookups_failure_larger);
- tcase_add_test(tc, test_many_lookups_failure_smaller);
+ tc = tcase_create("many lookups");
+ tcase_add_checked_fixture(tc, setup_ht_lookups, teardown_ht_many);
+ tcase_add_loop_test(tc, test_many_lookups_success, 0, REGULAR_MAX);
+ tcase_add_loop_test(tc, test_many_lookups_failure_larger, 0, REGULAR_MAX);
+ tcase_add_loop_test(tc, test_many_lookups_failure_smaller, 0, REGULAR_MAX);
suite_add_tcase(s, tc);
return s;