>> Does the hashtable_t+enumerator_t support this mode of operation ?
>
> I think so. The hashtable is based on many linked_lists, and the
> remove function from list can handle this.
>
> @Tobias: Please correct me if I'm wrong.

That wouldn't work.  For the linked list you also can't just call
remove, but have to call remove_at, otherwise the enumerator's internal
state would get invalid.  I've added such a function to the hash table,
see the attached patch (I hope it compiles, did this on a Windows machine).

>> Or, is there a better way of doing this ?
>
> Our list has handy destroy_offset/destroy_function helpers for cleanup
> purposes, but the hashtable is currently missing these functions. So:
> No.

We could add such functions to the hash table too, but we would probably
need two parameters, in order to free the keys and the values (since you
could use the same object as key and as value one of these would be
optional).

Alternatively, we could also add a new constructor, which would take two
new function parameters to free the keys and the values.  If they were
set, destroy/remove/remove_at would automatically free the memory of the
key and value.  We could then also easily add a remove_all method to
clear the whole hash table.

>> If all else fails, it may be better to free all the memory that the
>> elements point to and to then destroy the hashtable_t and create a
>> new one.
>
> Might be a little more efficient for large tables (?), but shouldn't
> really matter.

It probably depends on how often you have to clear the whole hash table,
how large it gets and how fast it grows.  If it grows fast to about the
same significant size, it might be better to remove all elements to
avoid the hash table getting resized all the time (you can avoid this if
you set the initial capacity to an appropriate value).

Regards,
Tobias
>From 3339a7e974eaa581678d3e57f1cc9c94924acecd Mon Sep 17 00:00:00 2001
From: Tobias Brunner <tob...@strongswan.org>
Date: Sat, 5 Jun 2010 09:50:07 +0200
Subject: [PATCH] Adding a remove_at method to the hash table in order to remove 
items while enumerating them.

---
 src/libstrongswan/utils/hashtable.c |   33 ++++++++++++++++++++++++++++-----
 src/libstrongswan/utils/hashtable.h |    7 +++++++
 2 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/src/libstrongswan/utils/hashtable.c 
b/src/libstrongswan/utils/hashtable.c
index 02c2258..1813d42 100644
--- a/src/libstrongswan/utils/hashtable.c
+++ b/src/libstrongswan/utils/hashtable.c
@@ -127,6 +127,11 @@ struct private_enumerator_t {
        u_int row;
 
        /**
+        * current pair
+        */
+       pair_t *pair;
+
+       /**
         * enumerator for the current row
         */
        enumerator_t *current;
@@ -318,6 +323,25 @@ static void *remove_(private_hashtable_t *this, void *key)
 }
 
 /**
+ * Implementation of hashtable_t.remove_at
+ */
+static void remove_at(private_hashtable_t *this,
+                                         private_enumerator_t *enumerator)
+{
+       if (enumerator->current)
+       {
+               linked_list_t *list;
+               list = this->table->table[enumerator->row];
+               if (list)
+               {
+                       list->remove_at(list, enumerator->current);
+                       free(enumerator->pair);
+                       this->count--;
+               }
+       }
+}
+
+/**
  * Implementation of hashtable_t.get_count
  */
 static u_int get_count(private_hashtable_t *this)
@@ -334,17 +358,15 @@ static bool enumerate(private_enumerator_t *this, void 
**key, void **value)
        {
                if (this->current)
                {
-                       pair_t *pair;
-
-                       if (this->current->enumerate(this->current, &pair))
+                       if (this->current->enumerate(this->current, 
&this->pair))
                        {
                                if (key)
                                {
-                                       *key = pair->key;
+                                       *key = this->pair->key;
                                }
                                if (value)
                                {
-                                       *value = pair->value;
+                                       *value = this->pair->value;
                                }
                                return TRUE;
                        }
@@ -426,6 +448,7 @@ hashtable_t *hashtable_create(hashtable_hash_t hash, 
hashtable_equals_t equals,
        this->public.put = (void*(*)(hashtable_t*,void*,void*))put;
        this->public.get = (void*(*)(hashtable_t*,void*))get;
        this->public.remove = (void*(*)(hashtable_t*,void*))remove_;
+       this->public.remove_at = (void(*)(hashtable_t*,enumerator_t*))remove_at;
        this->public.get_count = (u_int(*)(hashtable_t*))get_count;
        this->public.create_enumerator = 
(enumerator_t*(*)(hashtable_t*))create_enumerator;
        this->public.destroy = (void(*)(hashtable_t*))destroy;
diff --git a/src/libstrongswan/utils/hashtable.h 
b/src/libstrongswan/utils/hashtable.h
index 142ea63..a0bc124 100644
--- a/src/libstrongswan/utils/hashtable.h
+++ b/src/libstrongswan/utils/hashtable.h
@@ -87,6 +87,13 @@ struct hashtable_t {
        void *(*remove) (hashtable_t *this, void *key);
 
        /**
+        * Remove an item from the hash table where the enumerator points to.
+        *
+        * @param enumerator    enumerator
+        */
+       void (*remove_at) (hashtable_t *this, enumerator_t *enumerator);
+
+       /**
         * Gets the number of items in the hash table.
         *
         * @return                      number of items
-- 
1.7.0.4

_______________________________________________
Users mailing list
Users@lists.strongswan.org
https://lists.strongswan.org/mailman/listinfo/users

Reply via email to