Added SilcStack support for memory allocation.
authorPekka Riikonen <priikone@silcnet.org>
Tue, 3 Jul 2007 19:43:38 +0000 (19:43 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 3 Jul 2007 19:43:38 +0000 (19:43 +0000)
lib/silcutil/silcdlist.h
lib/silcutil/silchashtable.c
lib/silcutil/silchashtable.h
lib/silcutil/tests/test_silchashtable.c

index 87dfb4cce6cb26871b4602d23153cd55a0e8934d..54c2a8bacadb402631bedf481c26df8ab9cde5e3 100644 (file)
@@ -52,6 +52,7 @@
  *
  ***/
 typedef struct SilcDListStruct {
+  SilcStack stack;
   SilcList list;
   void *current;
   void *prev;
@@ -74,7 +75,7 @@ typedef struct SilcDListEntryStruct {
  *
  * DESCRIPTION
  *
- *    Initializes SilcDList.
+ *    Initializes SilcDList.  Returns the SilcDList context or NULL on error.
  *
  ***/
 
@@ -92,6 +93,40 @@ SilcDList silc_dlist_init(void)
   return list;
 }
 
+/****f* silcutil/SilcDListAPI/silc_dlist_sinit
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcDList silc_dlist_sinit(SilcStack stack);
+ *
+ * DESCRIPTION
+ *
+ *    Initializes SilcDList.  Returns the SilcDList context or NULL on error.
+ *    This is same as silc_dlist_init but allocates the memory from `stack'
+ *    if `stack' is non-NULL.
+ *
+ ***/
+
+static inline
+SilcDList silc_dlist_sinit(SilcStack stack)
+{
+  SilcDList list;
+
+  if (stack)
+    stack = silc_stack_alloc(0, stack);
+  list = (SilcDList)silc_smalloc(stack, sizeof(*list));
+  if (!list) {
+    silc_stack_free(stack);
+    return NULL;
+  }
+  list->stack = stack;
+  list->current = list->prev = NULL;
+  silc_list_init_prev(list->list, struct SilcDListEntryStruct, next, prev);
+
+  return list;
+}
+
 /****f* silcutil/SilcDListAPI/silc_dlist_uninit
  *
  * SYNOPSIS
@@ -102,7 +137,9 @@ SilcDList silc_dlist_init(void)
  * DESCRIPTION
  *
  *    Uninits and frees all memory. Must be called to free memory. Does NOT
- *    free the contexts saved by caller.
+ *    free the contexts saved by caller.  If the silc_dlist_sinit was used
+ *    with SilcStack this will release all memory allocated by the SilcDList
+ *    back to the SilcStack.
  *
  ***/
 
@@ -111,12 +148,14 @@ void silc_dlist_uninit(SilcDList list)
 {
   if (list) {
     SilcDListEntry e;
+    SilcStack stack = list->stack;
     silc_list_start(list->list);
     while ((e = (SilcDListEntry)silc_list_get(list->list)) != SILC_LIST_END) {
       silc_list_del(list->list, e);
-      silc_free(e);
+      silc_sfree(stack, e);
     }
-    silc_free(list);
+    silc_sfree(stack, list);
+    silc_stack_free(stack);
   }
 }
 
@@ -198,7 +237,7 @@ void silc_dlist_end(SilcDList list)
 static inline
 SilcBool silc_dlist_add(SilcDList list, void *context)
 {
-  SilcDListEntry e = (SilcDListEntry)silc_malloc(sizeof(*e));
+  SilcDListEntry e = (SilcDListEntry)silc_smalloc(list->stack, sizeof(*e));
   if (silc_unlikely(!e))
     return FALSE;
   e->context = context;
@@ -224,7 +263,7 @@ SilcBool silc_dlist_add(SilcDList list, void *context)
 static inline
 SilcBool silc_dlist_insert(SilcDList list, void *context)
 {
-  SilcDListEntry e = (SilcDListEntry)silc_malloc(sizeof(*e));
+  SilcDListEntry e = (SilcDListEntry)silc_smalloc(list->stack, sizeof(*e));
   if (silc_unlikely(!e))
     return FALSE;
   e->context = context;
@@ -261,7 +300,7 @@ void silc_dlist_del(SilcDList list, void *entry)
        list->current = NULL;
       if (list->prev == e)
        list->prev = NULL;
-      silc_free(e);
+      silc_sfree(list->stack, e);
       break;
     }
   }
index 6ba2e0a2411662ed48c892163e5aef9abfe74d3f..dd59263fa85dfcfa9af8b0954ec33f5a525b003f 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2006 Pekka Riikonen
+  Copyright (C) 2001 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -63,6 +63,7 @@ typedef struct SilcHashTableEntryStruct {
 
 /* Hash table. */
 struct SilcHashTableStruct {
+  SilcStack stack;
   SilcHashTableEntry *table;
   SilcUInt32 table_size;
   SilcUInt32 entry_count;
@@ -281,7 +282,7 @@ silc_hash_table_add_internal(SilcHashTable ht, void *key, void *context,
 
     SILC_HT_DEBUG(("Collision; adding new key to list"));
 
-    e->next = silc_calloc(1, sizeof(*e->next));
+    e->next = silc_scalloc(ht->stack, 1, sizeof(*e->next));
     if (!e->next)
       return FALSE;
     e->next->key = key;
@@ -290,7 +291,7 @@ silc_hash_table_add_internal(SilcHashTable ht, void *key, void *context,
   } else {
     /* New key */
     SILC_HT_DEBUG(("New key"));
-    *entry = silc_calloc(1, sizeof(**entry));
+    *entry = silc_scalloc(ht->stack, 1, sizeof(**entry));
     if (!(*entry))
       return FALSE;
     (*entry)->key = key;
@@ -325,7 +326,7 @@ silc_hash_table_replace_internal(SilcHashTable ht, void *key, void *context,
                     ht->destructor_user_context);
   } else {
     /* New key */
-    *entry = silc_calloc(1, sizeof(**entry));
+    *entry = silc_scalloc(ht->stack, 1, sizeof(**entry));
     if (!(*entry))
       return FALSE;
     ht->entry_count++;
@@ -348,7 +349,8 @@ silc_hash_table_replace_internal(SilcHashTable ht, void *key, void *context,
    destructor function, respectively. The `hash' is mandatory, the others
    are optional. */
 
-SilcHashTable silc_hash_table_alloc(SilcUInt32 table_size,
+SilcHashTable silc_hash_table_alloc(SilcStack stack,
+                                   SilcUInt32 table_size,
                                    SilcHashFunction hash,
                                    void *hash_user_context,
                                    SilcHashCompare compare,
@@ -363,17 +365,25 @@ SilcHashTable silc_hash_table_alloc(SilcUInt32 table_size,
   if (!hash)
     return NULL;
 
-  ht = silc_calloc(1, sizeof(*ht));
-  if (!ht)
+  if (stack)
+    stack = silc_stack_alloc(0, stack);
+
+  ht = silc_scalloc(stack, 1, sizeof(*ht));
+  if (!ht) {
+    silc_stack_free(stack);
     return NULL;
-  ht->table = silc_calloc(table_size ? silc_hash_table_primesize(table_size,
-                                                                &size_index) :
-                         primesize[SILC_HASH_TABLE_SIZE],
-                         sizeof(*ht->table));
+  }
+  ht->table = silc_scalloc(stack,
+                          table_size ? silc_hash_table_primesize(table_size,
+                                                                 &size_index) :
+                          primesize[SILC_HASH_TABLE_SIZE],
+                          sizeof(*ht->table));
   if (!ht->table) {
-    silc_free(ht);
+    silc_stack_free(stack);
+    silc_sfree(stack, ht);
     return NULL;
   }
+  ht->stack = stack;
   ht->table_size = size_index;
   ht->hash = hash;
   ht->compare = compare;
@@ -391,6 +401,7 @@ SilcHashTable silc_hash_table_alloc(SilcUInt32 table_size,
 
 void silc_hash_table_free(SilcHashTable ht)
 {
+  SilcStack stack = ht->stack;
   SilcHashTableEntry e, tmp;
   int i;
 
@@ -401,12 +412,13 @@ void silc_hash_table_free(SilcHashTable ht)
        ht->destructor(e->key, e->context, ht->destructor_user_context);
       tmp = e;
       e = e->next;
-      silc_free(tmp);
+      silc_sfree(stack, tmp);
     }
   }
 
-  silc_free(ht->table);
-  silc_free(ht);
+  silc_sfree(stack, ht->table);
+  silc_sfree(stack, ht);
+  silc_stack_free(stack);
 }
 
 /* Returns the size of the hash table */
@@ -451,7 +463,7 @@ SilcBool silc_hash_table_add_ext(SilcHashTable ht, void *key, void *context,
    the `context. The destructor function will be called for the
    replaced key and context. */
 
-SilcBool silc_hash_table_replace(SilcHashTable ht, void *key, void *context)
+SilcBool silc_hash_table_set(SilcHashTable ht, void *key, void *context)
 {
   return silc_hash_table_replace_internal(ht, key, context, ht->hash,
                                          ht->hash_user_context);
@@ -459,10 +471,10 @@ SilcBool silc_hash_table_replace(SilcHashTable ht, void *key, void *context)
 
 /* Same as above but with specific hash function. */
 
-SilcBool silc_hash_table_replace_ext(SilcHashTable ht, void *key,
-                                    void *context,
-                                    SilcHashFunction hash,
-                                    void *hash_user_context)
+SilcBool silc_hash_table_set_ext(SilcHashTable ht, void *key,
+                                void *context,
+                                SilcHashFunction hash,
+                                void *hash_user_context)
 {
   return silc_hash_table_replace_internal(ht, key, context,
                                          hash, hash_user_context);
@@ -495,7 +507,7 @@ SilcBool silc_hash_table_del(SilcHashTable ht, void *key)
 
   if (ht->destructor)
     ht->destructor(e->key, e->context, ht->destructor_user_context);
-  silc_free(e);
+  silc_sfree(ht->stack, e);
 
   ht->entry_count--;
 
@@ -545,7 +557,7 @@ SilcBool silc_hash_table_del_ext(SilcHashTable ht, void *key,
     if (ht->destructor)
       ht->destructor(e->key, e->context, ht->destructor_user_context);
   }
-  silc_free(e);
+  silc_sfree(ht->stack, e);
 
   ht->entry_count--;
 
@@ -586,7 +598,7 @@ SilcBool silc_hash_table_del_by_context(SilcHashTable ht, void *key,
 
   if (ht->destructor)
     ht->destructor(e->key, e->context, ht->destructor_user_context);
-  silc_free(e);
+  silc_sfree(ht->stack, e);
 
   ht->entry_count--;
 
@@ -639,7 +651,7 @@ SilcBool silc_hash_table_del_by_context_ext(SilcHashTable ht, void *key,
     if (ht->destructor)
       ht->destructor(e->key, e->context, ht->destructor_user_context);
   }
-  silc_free(e);
+  silc_sfree(ht->stack, e);
 
   ht->entry_count--;
 
@@ -827,7 +839,8 @@ void silc_hash_table_rehash(SilcHashTable ht, SilcUInt32 new_size)
   ht->auto_rehash = FALSE;
 
   /* Allocate new table */
-  ht->table = silc_calloc(primesize[size_index], sizeof(*ht->table));
+  ht->table = silc_scalloc(ht->stack,
+                          primesize[size_index], sizeof(*ht->table));
   if (!ht->table)
     return;
   ht->table_size = size_index;
@@ -842,14 +855,14 @@ void silc_hash_table_rehash(SilcHashTable ht, SilcUInt32 new_size)
       e = e->next;
 
       /* Remove old entry */
-      silc_free(tmp);
+      silc_sfree(ht->stack, tmp);
     }
   }
 
   ht->auto_rehash = auto_rehash;
 
   /* Remove old table */
-  silc_free(table);
+  silc_sfree(ht->stack, table);
 }
 
 /* Same as above but with specific hash function. */
@@ -882,7 +895,8 @@ void silc_hash_table_rehash_ext(SilcHashTable ht, SilcUInt32 new_size,
   ht->auto_rehash = FALSE;
 
   /* Allocate new table */
-  ht->table = silc_calloc(primesize[size_index], sizeof(*ht->table));
+  ht->table = silc_scalloc(ht->stack,
+                          primesize[size_index], sizeof(*ht->table));
   if (!ht->table)
     return;
   ht->table_size = size_index;
@@ -898,14 +912,14 @@ void silc_hash_table_rehash_ext(SilcHashTable ht, SilcUInt32 new_size,
       e = e->next;
 
       /* Remove old entry */
-      silc_free(tmp);
+      silc_sfree(ht->stack, tmp);
     }
   }
 
   ht->auto_rehash = auto_rehash;
 
   /* Remove old table */
-  silc_free(table);
+  silc_sfree(ht->stack, table);
 }
 
 /* Prepares the `htl' list structure sent as argument to be used in the
index f7d21cb4eb51e1cf14c8b7087d4f0e6ffb3e998d..6cecb2741a1cfdfa0ff0f52167a8ce7357e0d688 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2006 Pekka Riikonen
+  Copyright (C) 2001 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
  * Implementation of collision resistant hash table. This is a hash table
  * that provides a reliable (what you add there stays there, and duplicate
  * keys are allowed) with as fast reference to the key as possible. If
- * there are a lot of duplicate keys in the hash table the lookup gets
- * slower of course. However, this is reliable and no data is lost at any
- * point. If you know that you never have duplicate keys then this is as
- * fast as any simple hash table.
+ * there are a lot of duplicate keys in the hash table the lookup slows down.
+ * However, this is reliable and no data is lost at any point. If you know
+ * that you never have duplicate keys then this is as fast as any simple hash
+ * table.
  *
  * The interface provides many ways to search the hash table including
  * an extended interface where caller can specify its own hash and comparison
- * functions.
+ * functions.  The interface also supports SilcStack and all memory allocated
+ * by the hash table can be allocated from SilcStack.
  *
  * There are two ways to traverse the entire hash table if this feature
  * is needed. There exists a foreach function that calls a foreach
@@ -39,8 +40,8 @@
  * SilcHashTableList structure and traverse the hash table inside while()
  * using the list structure. Both are equally fast.
  *
- * The hash table is not thread safe.  If same hash table context is used in
- * multi thread environment concurrency control must be employed.
+ * The hash table is not thread safe.  If same SilcHashtable context is used
+ * in multi thread environment concurrency control must be employed.
  *
  ***/
 
@@ -172,7 +173,8 @@ typedef void (*SilcHashForeach)(void *key, void *context, void *user_context);
  *
  * SYNOPSIS
  *
- *    SilcHashTable silc_hash_table_alloc(SilcUInt32 table_size,
+ *    SilcHashTable silc_hash_table_alloc(SilcStack stack,
+ *                                        SilcUInt32 table_size,
  *                                        SilcHashFunction hash,
  *                                        void *hash_user_context,
  *                                        SilcHashCompare compare,
@@ -183,7 +185,8 @@ typedef void (*SilcHashForeach)(void *key, void *context, void *user_context);
  *
  * DESCRIPTION
  *
- *    Allocates new hash table and returns it.  If the `table_size' is not
+ *    Allocates new hash table and returns it.  If the `stack' is non-NULL
+ *    the hash table is allocated from `stack'.  If the `table_size' is not
  *    zero then the hash table size is the size provided. If zero then the
  *    default size will be used. Note that if the `table_size' is provided
  *    it should be a prime. The `hash', `compare' and `destructor' are
@@ -192,7 +195,8 @@ typedef void (*SilcHashForeach)(void *key, void *context, void *user_context);
  *    are optional.
  *
  ***/
-SilcHashTable silc_hash_table_alloc(SilcUInt32 table_size,
+SilcHashTable silc_hash_table_alloc(SilcStack stack,
+                                   SilcUInt32 table_size,
                                    SilcHashFunction hash,
                                    void *hash_user_context,
                                    SilcHashCompare compare,
@@ -212,6 +216,10 @@ SilcHashTable silc_hash_table_alloc(SilcUInt32 table_size,
  *    Frees the hash table. The destructor function provided in the
  *    silc_hash_table_alloc will be called for all keys in the hash table.
  *
+ *    If the SilcStack was given to silc_hash_table_alloc this call will
+ *    release all memory allocated during the life time of the `ht' back
+ *    to the SilcStack.
+ *
  ***/
 void silc_hash_table_free(SilcHashTable ht);
 
@@ -260,12 +268,12 @@ SilcUInt32 silc_hash_table_count(SilcHashTable ht);
  ***/
 SilcBool silc_hash_table_add(SilcHashTable ht, void *key, void *context);
 
-/****f* silcutil/SilcHashTableAPI/silc_hash_table_replace
+/****f* silcutil/SilcHashTableAPI/silc_hash_table_set
  *
  * SYNOPSIS
  *
- *    SilcBool silc_hash_table_replace(SilcHashTable ht, void *key,
- *                                     void *context);
+ *    SilcBool silc_hash_table_set(SilcHashTable ht, void *key,
+ *                                 void *context);
  *
  * DESCRIPTION
  *
@@ -275,7 +283,7 @@ SilcBool silc_hash_table_add(SilcHashTable ht, void *key, void *context);
  *    replaced key and context.
  *
  ***/
-SilcBool silc_hash_table_replace(SilcHashTable ht, void *key, void *context);
+SilcBool silc_hash_table_set(SilcHashTable ht, void *key, void *context);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_del
  *
@@ -505,14 +513,14 @@ SilcBool silc_hash_table_add_ext(SilcHashTable ht,
                                 SilcHashFunction hash,
                                 void *hash_user_context);
 
-/****f* silcutil/SilcHashTableAPI/silc_hash_table_replace_ext
+/****f* silcutil/SilcHashTableAPI/silc_hash_table_set_ext
  *
  * SYNOPSIS
  *
- *    SilcBool silc_hash_table_replace_ext(SilcHashTable ht, void *key,
- *                                         void *context,
- *                                         SilcHashFunction hash,
- *                                         void *hash_user_context);
+ *    SilcBool silc_hash_table_set_ext(SilcHashTable ht, void *key,
+ *                                     void *context,
+ *                                     SilcHashFunction hash,
+ *                                     void *hash_user_context);
  *
  * DESCRIPTION
  *
@@ -525,10 +533,10 @@ SilcBool silc_hash_table_add_ext(SilcHashTable ht,
  *    function. If not provided the hash table's default is used.
  *
  ***/
-SilcBool silc_hash_table_replace_ext(SilcHashTable ht,
-                                    void *key, void *context,
-                                    SilcHashFunction hash,
-                                    void *hash_user_context);
+SilcBool silc_hash_table_set_ext(SilcHashTable ht,
+                                void *key, void *context,
+                                SilcHashFunction hash,
+                                void *hash_user_context);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_del_ext
  *
index 622fc4536647868c726adb791e0799f938224734..a09727b3cee0a6e58939331de00bd7390d3f33c8 100644 (file)
@@ -120,7 +120,7 @@ SilcBool alloc_table()
   SILC_LOG_DEBUG(("Allocating hash table with %d entries (%s)",
                  count, auto_rehash ? "auto rehash" : "no auto rehash"));
 
-  t = silc_hash_table_alloc(0, hash_entry, NULL,
+  t = silc_hash_table_alloc(NULL, 0, hash_entry, NULL,
                            hash_compare, NULL,
                            hash_destructor, NULL, auto_rehash);