summaryrefslogtreecommitdiff
path: root/src/libstrongswan/utils/hashtable.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/utils/hashtable.c')
-rw-r--r--src/libstrongswan/utils/hashtable.c225
1 files changed, 100 insertions, 125 deletions
diff --git a/src/libstrongswan/utils/hashtable.c b/src/libstrongswan/utils/hashtable.c
index 49b0bb68c..33f645170 100644
--- a/src/libstrongswan/utils/hashtable.c
+++ b/src/libstrongswan/utils/hashtable.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2010 Tobias Brunner
+ * Copyright (C) 2008-2011 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -13,7 +13,6 @@
* for more details.
*/
-#include <utils/linked_list.h>
#include "hashtable.h"
@@ -40,12 +39,17 @@ struct pair_t {
* Cached hash (used in case of a resize).
*/
u_int hash;
+
+ /**
+ * Next pair in an overflow list.
+ */
+ pair_t *next;
};
/**
* Creates an empty pair object.
*/
-pair_t *pair_create(void *key, void *value, u_int hash)
+static inline pair_t *pair_create(void *key, void *value, u_int hash)
{
pair_t *this;
@@ -93,7 +97,7 @@ struct private_hashtable_t {
/**
* The actual table.
*/
- linked_list_t **table;
+ pair_t **table;
/**
* The hashing function.
@@ -129,23 +133,21 @@ struct private_enumerator_t {
u_int row;
/**
+ * number of remaining items in hashtable
+ */
+ u_int count;
+
+ /**
* current pair
*/
- pair_t *pair;
+ pair_t *current;
/**
- * enumerator for the current row
+ * previous pair (used by remove_at)
*/
- enumerator_t *current;
-};
+ pair_t *prev;
-/**
- * Compare a pair in a list with the given key.
- */
-static inline bool pair_equals(pair_t *pair, private_hashtable_t *this, void *key)
-{
- return this->equals(key, pair->key);
-}
+};
/**
* This function returns the next-highest power of two for the given number.
@@ -175,7 +177,7 @@ static void init_hashtable(private_hashtable_t *this, u_int capacity)
this->mask = this->capacity - 1;
this->load_factor = 0.75;
- this->table = calloc(this->capacity, sizeof(linked_list_t*));
+ this->table = calloc(this->capacity, sizeof(pair_t*));
}
/**
@@ -183,7 +185,7 @@ static void init_hashtable(private_hashtable_t *this, u_int capacity)
*/
static void rehash(private_hashtable_t *this)
{
- linked_list_t **old_table;
+ pair_t **old_table;
u_int row, old_capacity;
if (this->capacity >= MAX_CAPACITY)
@@ -198,29 +200,17 @@ static void rehash(private_hashtable_t *this)
for (row = 0; row < old_capacity; row++)
{
- enumerator_t *enumerator;
- linked_list_t *list, *new_list;
- pair_t *pair;
+ pair_t *pair, *next;
u_int new_row;
- list = old_table[row];
- if (list)
- {
- enumerator = list->create_enumerator(list);
- while (enumerator->enumerate(enumerator, &pair))
- {
- new_row = pair->hash & this->mask;
-
- list->remove_at(list, enumerator);
- new_list = this->table[new_row];
- if (!new_list)
- {
- new_list = this->table[new_row] = linked_list_create();
- }
- new_list->insert_last(new_list, pair);
- }
- enumerator->destroy(enumerator);
- list->destroy(list);
+ pair = old_table[row];
+ while (pair)
+ { /* insert pair at the front of new bucket*/
+ next = pair->next;
+ new_row = pair->hash & this->mask;
+ pair->next = this->table[new_row];
+ this->table[new_row] = pair;
+ pair = next;
}
}
free(old_table);
@@ -230,38 +220,28 @@ METHOD(hashtable_t, put, void*,
private_hashtable_t *this, void *key, void *value)
{
void *old_value = NULL;
- linked_list_t *list;
- u_int hash;
- u_int row;
+ pair_t *pair;
+ u_int hash, row;
hash = this->hash(key);
row = hash & this->mask;
- list = this->table[row];
- if (list)
- {
- enumerator_t *enumerator;
- pair_t *pair;
-
- enumerator = list->create_enumerator(list);
- while (enumerator->enumerate(enumerator, &pair))
+ pair = this->table[row];
+ while (pair)
+ { /* search existing bucket for key */
+ if (this->equals(key, pair->key))
{
- if (pair_equals(pair, this, key))
- {
- old_value = pair->value;
- pair->value = value;
- pair->key = key;
- break;
- }
+ old_value = pair->value;
+ pair->value = value;
+ pair->key = key;
+ break;
}
- enumerator->destroy(enumerator);
- }
- else
- {
- list = this->table[row] = linked_list_create();
+ pair = pair->next;
}
- if (!old_value)
- {
- list->insert_last(list, pair_create(key, value, hash));
+ if (!pair)
+ { /* insert at the front of bucket */
+ pair = pair_create(key, value, hash);
+ pair->next = this->table[row];
+ this->table[row] = pair;
this->count++;
}
if (this->count >= this->capacity * this->load_factor)
@@ -275,17 +255,17 @@ METHOD(hashtable_t, get, void*,
private_hashtable_t *this, void *key)
{
void *value = NULL;
- linked_list_t *list;
pair_t *pair;
- list = this->table[this->hash(key) & this->mask];
- if (list)
+ pair = this->table[this->hash(key) & this->mask];
+ while (pair)
{
- if (list->find_first(list, (linked_list_match_t)pair_equals,
- (void**)&pair, this, key) == SUCCESS)
+ if (this->equals(key, pair->key))
{
value = pair->value;
+ break;
}
+ pair = pair->next;
}
return value;
}
@@ -294,27 +274,30 @@ METHOD(hashtable_t, remove_, void*,
private_hashtable_t *this, void *key)
{
void *value = NULL;
- linked_list_t *list;
+ pair_t *pair, *prev = NULL;
+ u_int row;
- list = this->table[this->hash(key) & this->mask];
- if (list)
+ row = this->hash(key) & this->mask;
+ pair = this->table[row];
+ while (pair)
{
- enumerator_t *enumerator;
- pair_t *pair;
-
- enumerator = list->create_enumerator(list);
- while (enumerator->enumerate(enumerator, &pair))
+ if (this->equals(key, pair->key))
{
- if (pair_equals(pair, this, key))
+ if (prev)
{
- list->remove_at(list, enumerator);
- value = pair->value;
- this->count--;
- free(pair);
- break;
+ prev->next = pair->next;
}
+ else
+ {
+ this->table[row] = pair->next;
+ }
+ value = pair->value;
+ this->count--;
+ free(pair);
+ break;
}
- enumerator->destroy(enumerator);
+ prev = pair;
+ pair = pair->next;
}
return value;
}
@@ -324,14 +307,18 @@ METHOD(hashtable_t, remove_at, void,
{
if (enumerator->table == this && enumerator->current)
{
- linked_list_t *list;
- list = this->table[enumerator->row];
- if (list)
+ pair_t *current = enumerator->current;
+ if (enumerator->prev)
{
- list->remove_at(list, enumerator->current);
- free(enumerator->pair);
- this->count--;
+ enumerator->prev->next = current->next;
+ }
+ else
+ {
+ this->table[enumerator->row] = current->next;
}
+ enumerator->current = enumerator->prev;
+ free(current);
+ this->count--;
}
}
@@ -344,50 +331,35 @@ METHOD(hashtable_t, get_count, u_int,
METHOD(enumerator_t, enumerate, bool,
private_enumerator_t *this, void **key, void **value)
{
- while (this->row < this->table->capacity)
+ while (this->count && this->row < this->table->capacity)
{
+ this->prev = this->current;
if (this->current)
{
- if (this->current->enumerate(this->current, &this->pair))
- {
- if (key)
- {
- *key = this->pair->key;
- }
- if (value)
- {
- *value = this->pair->value;
- }
- return TRUE;
- }
- this->current->destroy(this->current);
- this->current = NULL;
+ this->current = this->current->next;
}
else
{
- linked_list_t *list;
- list = this->table->table[this->row];
- if (list)
+ this->current = this->table->table[this->row];
+ }
+ if (this->current)
+ {
+ if (key)
{
- this->current = list->create_enumerator(list);
- continue;
+ *key = this->current->key;
}
+ if (value)
+ {
+ *value = this->current->value;
+ }
+ this->count--;
+ return TRUE;
}
this->row++;
}
return FALSE;
}
-METHOD(enumerator_t, enumerator_destroy, void,
- private_enumerator_t *this)
-{
- if (this->current)
- {
- this->current->destroy(this->current);
- }
- free(this);
-}
-
METHOD(hashtable_t, create_enumerator, enumerator_t*,
private_hashtable_t *this)
{
@@ -396,9 +368,10 @@ METHOD(hashtable_t, create_enumerator, enumerator_t*,
INIT(enumerator,
.enumerator = {
.enumerate = (void*)_enumerate,
- .destroy = (void*)_enumerator_destroy,
+ .destroy = (void*)free,
},
.table = this,
+ .count = this->count,
);
return &enumerator->enumerator;
@@ -407,15 +380,17 @@ METHOD(hashtable_t, create_enumerator, enumerator_t*,
METHOD(hashtable_t, destroy, void,
private_hashtable_t *this)
{
- linked_list_t *list;
+ pair_t *pair, *next;
u_int row;
for (row = 0; row < this->capacity; row++)
{
- list = this->table[row];
- if (list)
+ pair = this->table[row];
+ while (pair)
{
- list->destroy_function(list, free);
+ next = pair->next;
+ free(pair);
+ pair = next;
}
}
free(this->table);