From b9408f914611826d23f8b03097bd9e07fbb0fc5e Mon Sep 17 00:00:00 2001
From: Dmitri Pal <dpal@redhat.com>
Date: Fri, 4 Dec 2009 17:00:47 -0500
Subject: [PATCH] DHASH: Adding new function to interface

This function allows deleting the hesh element
without destroying the actual data in the hash.
This is for "give me the data and remove the hash
element" use case.
---
 common/dhash/dhash.c         |   34 ++++++++++++++++++++++++++++++++--
 common/dhash/dhash.h         |   14 +++++++++++++-
 common/dhash/dhash_example.c |   11 +++++++++++
 3 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/common/dhash/dhash.c b/common/dhash/dhash.c
index 92283a2..2530795 100644
--- a/common/dhash/dhash.c
+++ b/common/dhash/dhash.c
@@ -889,7 +889,8 @@ int hash_lookup(hash_table_t *table, hash_key_t *key, hash_value_t *value)
     }
 }
 
-int hash_delete(hash_table_t *table, hash_key_t *key)
+
+int hash_remove(hash_table_t *table, hash_key_t *key, hash_value_t *value)
 {
     int error;
     segment_t element, *chain;
@@ -902,7 +903,7 @@ int hash_delete(hash_table_t *table, hash_key_t *key)
     lookup(table, key, &element, &chain);
 
     if (element) {
-        if (table->delete_callback) table->delete_callback(&element->entry);
+        if (value) *value = element->entry.value;
         *chain = element->next; /* remove from chain */
         /*
          * Table too sparse?
@@ -920,4 +921,33 @@ int hash_delete(hash_table_t *table, hash_key_t *key)
     }
 }
 
+int hash_delete(hash_table_t *table, hash_key_t *key)
+{
+    int error;
+    segment_t element, *chain;
+
+    if (!table) return HASH_ERROR_BAD_TABLE;
+
+    if (!is_valid_key_type(key->type))
+        return HASH_ERROR_BAD_KEY_TYPE;
 
+    lookup(table, key, &element, &chain);
+
+    if (element) {
+        if (table->delete_callback) table->delete_callback(&element->entry);
+        *chain = element->next; /* remove from chain */
+        /*
+         * Table too sparse?
+         */
+        if (--table->entry_count / table->bucket_count < table->min_load_factor) {
+            if ((error = contract_table(table)) != HASH_SUCCESS) { /* doesn't affect element */
+                return error;
+            }
+        }
+        if (element->entry.key.type == HASH_KEY_STRING) table->free ((char *)element->entry.key.str);
+        table->free(element);
+        return HASH_SUCCESS;
+    } else {
+        return HASH_ERROR_KEY_NOT_FOUND;
+    }
+}
diff --git a/common/dhash/dhash.h b/common/dhash/dhash.h
index 2bc5e6e..53589bb 100644
--- a/common/dhash/dhash.h
+++ b/common/dhash/dhash.h
@@ -244,13 +244,25 @@ int hash_get_default(hash_table_t *table, hash_key_t *key, hash_value_t *value,
  * Delete the item from the table. The key and its type are specified in the key
  * parameter which are passed by reference. If the key was in the table
  * HASH_SUCCESS is returned otherwise HASH_ERROR_KEY_NOT_FOUND is
- * returned. Memory allocated to hold the key if it was a string is free by the
+ * returned. Memory allocated to hold the key if it was a string is freed by the
  * hash library, but values which are pointers to user data must be freed by the
  * caller (see delete_callback).
  */
 int hash_delete(hash_table_t *table, hash_key_t *key);
 
 /*
+ * Delete the key from the table and return the value if value pointer is not NULL.
+ * If value ponter is NULL the value is not returned but also not destroyed.
+ * The key and its type are specified in the key parameter which are passed
+ * by reference. If the key was in the table HASH_SUCCESS is returned otherwise
+ * HASH_ERROR_KEY_NOT_FOUND is returned. Memory allocated to hold the key
+ * if it was a string is freed by the hash library, but values which are pointers
+ * to user data must be freed by the caller.
+ */
+int hash_remove(hash_table_t *table, hash_key_t *key, hash_value_t *value);
+
+
+/*
  * Often it is useful to operate on every key and/or value in the hash
  * table. The hash_iterate function will invoke the users callback on every item
  * in the table as long as the callback returns a non-zero value. Returning a
diff --git a/common/dhash/dhash_example.c b/common/dhash/dhash_example.c
index b7de623..2875a2f 100644
--- a/common/dhash/dhash_example.c
+++ b/common/dhash/dhash_example.c
@@ -78,6 +78,17 @@ int main(int argc, char **argv)
         fprintf(stderr, "cannot find key \"%s\" (%s)\n", key.str, hash_error_string(error));
     }
 
+    /* Get value back removing element from the table */
+    if ((error = hash_remove(table, &key, &value)) != HASH_SUCCESS) {
+        fprintf(stderr, "cannot find and remove key \"%s\" (%s)\n", key.str, hash_error_string(error));
+    }
+
+    /* Add the element back */
+    if ((error = hash_enter(table, &key, &value)) != HASH_SUCCESS) {
+        fprintf(stderr, "cannot add to table \"%s\" (%s)\n", key.str, hash_error_string(error));
+        return error;
+    }
+
     /* Visit each entry in the table, callback will increment count on each visit */
     printf("Iterate using callback\n");
     count = 0;
-- 
1.5.5.6

