Re: [PATCH 1/2] lib: Custom destructor for hashtable and list

  • From: Dimitri Staessens <dimitri.staessens@xxxxxxxx>
  • To: ouroboros@xxxxxxxxxxxxx
  • Date: Sun, 6 May 2018 10:25:07 +0200

Hi Nick,

can you split this and send a patch for the list destructor separately?
I'll have a look at that first and merge that into the code base, as
this is quite useful (been thinking of adding that myself, together with
macros to find list elements, we have a lot of duplicated code for that). 

Shouldn't you also call list_del() before destructor() in the
list_destroy() function?

By convention in Ouroboros, we use a new line per function argument.

thanks!

Dimitri


On 05/06/18 00:11, Nick Aerts wrote:

This patch adds the ability to use nested data structures with custom cleanup
code.
---
 include/ouroboros/hashtable.h        | 26 ++++++++++++++---
 include/ouroboros/list.h             |  2 ++
 src/ipcpd/normal/pol/alternate_pff.c | 10 +++----
 src/ipcpd/normal/pol/simple_pff.c    |  8 +++---
 src/lib/hashtable.c                  | 55 
++++++++++++++----------------------
 src/lib/list.c                       | 14 +++++++++
 6 files changed, 68 insertions(+), 47 deletions(-)

diff --git a/include/ouroboros/hashtable.h b/include/ouroboros/hashtable.h
index c9a6f72..b2c2794 100644
--- a/include/ouroboros/hashtable.h
+++ b/include/ouroboros/hashtable.h
@@ -27,15 +27,28 @@
 #include <stdbool.h>
 #include <stdlib.h>
 
-struct htable;
+#include "ouroboros/list.h"
+
+struct htable_entry {
+    struct list_head next;
+    uint64_t         key;
+    void *           val;
+    size_t           len;
+};
+
+struct htable {
+    struct list_head * buckets;
+    bool               hash_key;
+    uint64_t           buckets_size;
+};
 
 /* Buckets is rounded up to the nearest power of 2 */
 struct htable * htable_create(uint64_t buckets,
                               bool     hash_key);
 
-void            htable_destroy(struct htable * table);
+void            htable_destroy(struct htable * table, void (* 
destructor)(void*));
 
-void            htable_flush(struct htable * table);
+void            htable_flush(struct htable * table, void (* 
destructor)(void*));
 
 /* Passes ownership of the block of memory */
 int             htable_insert(struct htable * table,
@@ -50,6 +63,11 @@ int             htable_lookup(struct htable * table,
                               size_t *        len);
 
 int             htable_delete(struct htable * table,
-                              uint64_t        key);
+                              uint64_t        key,
+                              void         (* destructor)(void*));
+
+#define htable_for_each(p, i, h, table)                                      
  \
+        for(i=0; i < table->buckets_size; i++)                               
  \
+                for (h = &table->buckets[i], p = (h)->nxt; p != (h); p = 
p->nxt)
 
 #endif /* OUROBOROS_HASHTABLE_H */
diff --git a/include/ouroboros/list.h b/include/ouroboros/list.h
index 0c12fb6..afb006e 100644
--- a/include/ouroboros/list.h
+++ b/include/ouroboros/list.h
@@ -58,6 +58,8 @@ void list_add_tail(struct list_head * e,
 
 void list_del(struct list_head * e);
 
+void list_destroy(struct list_head * e, void (* destructor)(void *));
+
 void list_move(struct list_head * dst,
                struct list_head * src);
 
diff --git a/src/ipcpd/normal/pol/alternate_pff.c 
b/src/ipcpd/normal/pol/alternate_pff.c
index cb438c5..3447129 100644
--- a/src/ipcpd/normal/pol/alternate_pff.c
+++ b/src/ipcpd/normal/pol/alternate_pff.c
@@ -232,7 +232,7 @@ void alternate_pff_destroy(struct pff_i * pff_i)
 {
         assert(pff_i);
 
-        htable_destroy(pff_i->table);
+        htable_destroy(pff_i->table, NULL);
         del_nhops_down(pff_i);
         pthread_rwlock_destroy(&pff_i->lock);
         free(pff_i);
@@ -260,7 +260,7 @@ int alternate_pff_add(struct pff_i * pff_i,
                 return -1;
 
         if (add_addr(pff_i, addr)) {
-                htable_delete(pff_i->table, addr);
+                htable_delete(pff_i->table, addr, NULL);
                 return -1;
         }
 
@@ -275,7 +275,7 @@ int alternate_pff_update(struct pff_i * pff_i,
         assert(pff_i);
         assert(len > 0);
 
-        if (htable_delete(pff_i->table, addr))
+        if (htable_delete(pff_i->table, addr, NULL))
                 return -1;
 
         if (add_to_htable(pff_i, addr, fd, len))
@@ -291,7 +291,7 @@ int alternate_pff_del(struct pff_i * pff_i,
 
         del_addr(pff_i, addr);
 
-        if (htable_delete(pff_i->table, addr))
+        if (htable_delete(pff_i->table, addr, NULL))
                 return -1;
 
         return 0;
@@ -301,7 +301,7 @@ void alternate_pff_flush(struct pff_i * pff_i)
 {
         assert(pff_i);
 
-        htable_flush(pff_i->table);
+        htable_flush(pff_i->table, NULL);
 
         del_nhops_down(pff_i);
 
diff --git a/src/ipcpd/normal/pol/simple_pff.c 
b/src/ipcpd/normal/pol/simple_pff.c
index e91f119..43fb2e7 100644
--- a/src/ipcpd/normal/pol/simple_pff.c
+++ b/src/ipcpd/normal/pol/simple_pff.c
@@ -77,7 +77,7 @@ void simple_pff_destroy(struct pff_i * pff_i)
 {
         assert(pff_i);
 
-        htable_destroy(pff_i->table);
+        htable_destroy(pff_i->table, NULL);
 
         pthread_rwlock_destroy(&pff_i->lock);
         free(pff_i);
@@ -136,7 +136,7 @@ int simple_pff_update(struct pff_i * pff_i,
                 return -ENOMEM;
         *val = fd[0];
 
-        if (htable_delete(pff_i->table, addr)) {
+        if (htable_delete(pff_i->table, addr, NULL)) {
                 free(val);
                 return -1;
         }
@@ -154,7 +154,7 @@ int simple_pff_del(struct pff_i * pff_i,
 {
         assert(pff_i);
 
-        if (htable_delete(pff_i->table, addr))
+        if (htable_delete(pff_i->table, addr, NULL))
                 return -1;
 
         return 0;
@@ -164,7 +164,7 @@ void simple_pff_flush(struct pff_i * pff_i)
 {
         assert(pff_i);
 
-        htable_flush(pff_i->table);
+        htable_flush(pff_i->table, NULL);
 }
 
 int simple_pff_nhop(struct pff_i * pff_i,
diff --git a/src/lib/hashtable.c b/src/lib/hashtable.c
index be5c3ff..5e411d1 100644
--- a/src/lib/hashtable.c
+++ b/src/lib/hashtable.c
@@ -20,26 +20,15 @@
  * Foundation, Inc., http://www.fsf.org/about/contact/.
  */
 
+#define OUROBOROS_PREFIX "htable"
+
 #include <ouroboros/hashtable.h>
-#include <ouroboros/list.h>
 #include <ouroboros/errno.h>
 #include <ouroboros/hash.h>
 
 #include <assert.h>
 #include <string.h>
-
-struct htable_entry {
-        struct list_head next;
-        uint64_t         key;
-        void *           val;
-        size_t           len;
-};
-
-struct htable {
-        struct list_head * buckets;
-        bool               hash_key;
-        uint64_t           buckets_size;
-};
+#include <ouroboros/logs.h>
 
 struct htable * htable_create(uint64_t buckets,
                               bool     hash_key)
@@ -78,17 +67,17 @@ struct htable * htable_create(uint64_t buckets,
         return tmp;
 }
 
-void htable_destroy(struct htable * table)
+void htable_destroy(struct htable * table, void (* destructor)(void*))
 {
         assert(table);
         assert(table->buckets);
 
-        htable_flush(table);
+        htable_flush(table, destructor);
         free(table->buckets);
         free(table);
 }
 
-void htable_flush(struct htable * table)
+void htable_flush(struct htable * table, void (* destructor)(void*))
 {
         unsigned int          i;
         struct list_head *    pos = NULL;
@@ -97,11 +86,14 @@ void htable_flush(struct htable * table)
 
         assert(table);
 
+        if(destructor == NULL)
+                destructor = free;
+
         for (i = 0; i < table->buckets_size; i++) {
                 list_for_each_safe(pos, n, &(table->buckets[i])) {
                         entry = list_entry(pos, struct htable_entry, next);
                         list_del(&entry->next);
-                        free(entry->val);
+                        destructor(entry->val);
                         free(entry);
                 }
         }
@@ -172,27 +164,19 @@ int htable_lookup(struct htable * table,
                   size_t *        len)
 {
         struct htable_entry * entry;
-        struct list_head *    pos = NULL;
-        uint64_t              lookup_key;
 
-        assert(table);
+        if(htable_lookup_entry(table, key, &entry))
+                return -1;
 
-        lookup_key = calc_key(table, key);
+        *val = entry->val;
+        *len = entry->len;
 
-        list_for_each(pos, &(table->buckets[lookup_key])) {
-                entry = list_entry(pos, struct htable_entry, next);
-                if (entry->key == key) {
-                        *val = entry->val;
-                        *len = entry->len;
-                        return 0;
-                }
-        }
-
-        return -1;
+        return 0;
 }
 
 int htable_delete(struct htable * table,
-                  uint64_t        key)
+                  uint64_t        key,
+                  void         (* destructor)(void*))
 {
         struct htable_entry * entry;
         uint64_t              lookup_key;
@@ -201,13 +185,16 @@ int htable_delete(struct htable * table,
 
         assert(table);
 
+        if (destructor == NULL)
+                destructor = free;
+
         lookup_key = calc_key(table, key);
 
         list_for_each_safe(pos, n, &(table->buckets[lookup_key])) {
                 entry = list_entry(pos, struct htable_entry, next);
                 if (entry->key == key) {
                         list_del(&entry->next);
-                        free(entry->val);
+                        destructor(entry->val);
                         free(entry);
                         return 0;
                 }
diff --git a/src/lib/list.c b/src/lib/list.c
index c68bbe1..cb02b2e 100644
--- a/src/lib/list.c
+++ b/src/lib/list.c
@@ -23,6 +23,7 @@
 #include <ouroboros/list.h>
 
 #include <stddef.h>
+#include <malloc.h>
 
 void list_head_init(struct list_head * h)
 {
@@ -65,6 +66,19 @@ void list_del(struct list_head * e)
         e->nxt = e->prv = NULL;
 }
 
+void list_destroy(struct list_head * e, void (* destructor)(void *)){
+        struct list_head * p, * t;
+
+        if(destructor == NULL)
+                destructor = free;
+
+        list_for_each_safe(p, t, e) {
+                destructor(p);
+        }
+
+        destructor(e);
+}
+
 bool list_is_empty(struct list_head * h)
 {
         return h->nxt == h;

-- 
Dimitri Staessens
Ghent University - IMEC
Dept of Information Technology (INTEC)
iGent Tower, Technologiepark 15, 
9052 Gent - Zwijnaarde
tel: +32 496 18 04 17
www: https://idlab.technology
pgp fingerprint: 7D30 ADB0 0098 88F0
--
Talk is cheap. Show me the code. - Linus Torvalds


Attachment: signature.asc
Description: OpenPGP digital signature

Other related posts: