Browse Source

[hashtable] Fixing Hashtable

Vinicius Teshima 2 năm trước cách đây
mục cha
commit
3c9db890d2
2 tập tin đã thay đổi với 180 bổ sung139 xóa
  1. 25 26
      include/toolbox/hashtable.h
  2. 155 113
      src/toolbox/hashtable.c

+ 25 - 26
include/toolbox/hashtable.h

@@ -1,9 +1,8 @@
 #ifndef TOOLBOX_HASHTABLE_H
 #define TOOLBOX_HASHTABLE_H
 
-#include "toolbox/return_codes.h"
+#include "toolbox/errno.h"
 
-#include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
 
@@ -25,66 +24,66 @@ RET_TYPE
 hashtable_destroy(struct hashtable **self);
 
 __attribute__((__pure__))
-bool
+_Bool
 hashtable_contain_item(const struct hashtable *self
-						, const void* item, const size_t item_size);
+		       , const void* item, const size_t item_size);
 
 __attribute__((__pure__))
-bool
+_Bool
 hashtable_contain_key(const struct hashtable *self
-					   , const char *key);
+		      , const char *key);
 
 __attribute__((__pure__))
-bool
+_Bool
 hashtable_contain_key_hash(const struct hashtable *self
-							, const size_t key_hash);
+			   , const size_t key_hash);
 
 __attribute__((__pure__))
 const void *
 hashtable_get(const struct hashtable *self
-			  , const char *key);
+	      , const char *key);
 
 __attribute__((__pure__))
 const void *
 hashtable_get_or_default(const struct hashtable *self
-						 , const char *key
-						 , const void *default_item);
+			 , const char *key
+			 , const void *default_item);
 
 __attribute__((__pure__))
-bool
+_Bool
 hashtable_is_empty(const struct hashtable *self);
 
 RET_TYPE
 hashtable_put(struct hashtable *self
-			  , const char *key
-			  , const void *item, const size_t item_size);
+	      , const char *key
+	      , const void *item, const size_t item_size);
 
 const void *
 hashtable_remove(struct hashtable *self, const char *key);
 
-bool
+_Bool
 hashtable_remove_if_equal(struct hashtable *self
-						  , const char *key
-						  , const void *item, const size_t item_size);
+			  , const char *key
+			  , const void *item, const size_t item_size);
 
 const void *
 hashtable_replace(struct hashtable *self
-				  , const char *key
-				  , const void *item, const size_t item_size);
+		  , const char *key
+		  , const void *item, const size_t item_size);
 
-bool
+_Bool
 hashtable_replace_if_equal(struct hashtable *self
-						   , const char *key
-						   , const void *restrict old_item
-						   , const size_t item_old_size
-						   , const void *restrict new_item
-						   , const size_t item_new_size);
+			   , const char *key
+			   , const void *restrict old_item
+			   , const size_t item_old_size
+			   , const void *restrict new_item
+			   , const size_t item_new_size);
 
 size_t
 hashtable_used_size(const struct hashtable *self);
 
 RET_TYPE
 hashtable_for_each(struct hashtable *self
-				   , void (*for_each)(void *item, size_t *item_size));
+		   , void (*for_each)(void *item, size_t *item_size));
 
 #endif

+ 155 - 113
src/toolbox/hashtable.c

@@ -1,16 +1,33 @@
 #include "toolbox/hashtable.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
 #include "toolbox/hash.h"
 #include "toolbox/cstring.h"
 #include "toolbox/log.h"
-#include "toolbox/return_codes.h"
+#include "toolbox/errno.h"
 #include "toolbox/void_pointer.h"
 #include "toolbox/vptr.h"
 
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
+#define true ((unsigned char) 1L)
+#define false ((unsigned char) 0L)
+
+#define TEST_FOR_NULL(POINTER)						\
+	if ( POINTER == NULL ) {					\
+		LOG_ERROR("Null Pointer Not Expected");		\
+		toolbox_errno = RET_EVN;				\
+		return toolbox_errno;					\
+	}
+
+#define TEST_FOR_NULL_SR(POINTER, RET)					\
+	if ( POINTER == NULL ) {					\
+		LOG_ERROR("Null Pointer Not Expected");		\
+		toolbox_errno = RET_EVN;				\
+		return RET;						\
+	}
 
 struct hashtable_item {
 	struct {
@@ -35,29 +52,12 @@ struct hashtable {
 	struct hashtable_item data[HASHTABLE_SIZE];
 };
 
-#define TEST_FOR_NULL(POINTER)											\
-	if ( POINTER == NULL )												\
-		{																\
-			LOG_ERROR("Null Pointer Not Expected");					\
-			toolbox_errno = RET_ERR_VALUE_NULL;							\
-			return RET_ERR_VALUE_NULL;										\
-		}
-
-#define TEST_FOR_NULL_SR(POINTER, RETURN)								\
-	if ( POINTER == NULL )												\
-		{																\
-			LOG_ERROR("Null Pointer Not Expected");					\
-			toolbox_errno = RET_ERR_VALUE_NULL;							\
-			return RETURN;												\
-		}
-
-
 struct hashtable *
 hashtable_create(void) {
 	toolbox_errno = RET_OK;
 	struct hashtable *self = calloc(1, sizeof(struct hashtable));
 	if ( self == NULL ) {
-		toolbox_errno = RET_ERR_FAILED_MALLOC;
+		toolbox_errno = RET_EFM;
 	}
 	return self;
 }
@@ -67,19 +67,23 @@ hashtable_destroy(struct hashtable **self) {
 	toolbox_errno = RET_OK;
 	TEST_FOR_NULL(self);
 	TEST_FOR_NULL(*self);
-	for ( size_t i = 0; i < (*self)->used_keys.size; ++i ) {
-		if ( (*self)->data[(*self)->used_keys.data[i]].item.data != NULL ) {
-			free((*self)->data[(*self)->used_keys.data[i]].item.data);
-		}
+
+	struct hashtable *ht = (*self);
+
+	for ( size_t i = 0; i < ht->used_keys.size; ++i ) {
+		if ( ht->data[ht->used_keys.data[i]].item.data == NULL )
+			continue;
+
+		free(ht->data[ht->used_keys.data[i]].item.data);
 	}
 	free(*self);
 	*self = NULL;
 	return RET_OK;
 }
 
-bool
+_Bool
 hashtable_contain_item(const struct hashtable *self
-						, const void* p_item, const size_t p_item_size) {
+		       , const void* p_item, const size_t p_item_size) {
 	toolbox_errno = RET_OK;
 	TEST_FOR_NULL(self);
 	TEST_FOR_NULL(p_item);
@@ -87,13 +91,13 @@ hashtable_contain_item(const struct hashtable *self
 	for ( size_t i = 0; i < self->used_keys.size; ++i ) {
 		p_tmp = &self->data[self->used_keys.data[i]];
 		if ( void_pointer_equal(p_tmp->item.data, p_tmp->item.size
-								, p_item, p_item_size) ) {
+					, p_item, p_item_size) ) {
 			return true;
 		}
 		while ( p_tmp->p_next != NULL ) {
 			p_tmp = p_tmp->p_next;
 			if ( void_pointer_equal(p_tmp->item.data, p_tmp->item.size
-									, p_item, p_item_size) ) {
+						, p_item, p_item_size) ) {
 				return true;
 			}
 		}
@@ -101,9 +105,9 @@ hashtable_contain_item(const struct hashtable *self
 	return false;
 }
 
-bool
+_Bool
 hashtable_contain_key(const struct hashtable *self
-					   , const char *r_p_key) {
+		      , const char *r_p_key) {
 	toolbox_errno = RET_OK;
 	TEST_FOR_NULL(self);
 	TEST_FOR_NULL(r_p_key);
@@ -116,9 +120,9 @@ hashtable_contain_key(const struct hashtable *self
 	return false;
 }
 
-bool
+_Bool
 hashtable_contain_key_hash(const struct hashtable *self
-							, const size_t p_key_hash) {
+			   , const size_t p_key_hash) {
 	toolbox_errno = RET_OK;
 	TEST_FOR_NULL(self);
 	if ( self->data[p_key_hash].key.hash == p_key_hash ) {
@@ -129,7 +133,7 @@ hashtable_contain_key_hash(const struct hashtable *self
 
 const void *
 hashtable_get(const struct hashtable *self
-			  , const char *r_p_key) {
+	      , const char *r_p_key) {
 	toolbox_errno = RET_OK;
 	TEST_FOR_NULL_SR(self, NULL);
 	TEST_FOR_NULL_SR(r_p_key, NULL);
@@ -145,34 +149,37 @@ hashtable_get(const struct hashtable *self
 			return p_tmp->item.data;
 		}
 	}
-	toolbox_errno = RET_ERR_ITEM_DOES_NOT_EXIST;
+	toolbox_errno = RET_EIDNE;
 	return NULL;
 }
 
 const void *
 hashtable_get_or_default(const struct hashtable *self
-						 , const char *r_p_key
-						 , const void *p_default_item) {
+			 , const char *r_p_key
+			 , const void *p_default_item) {
 	toolbox_errno = RET_OK;
 	TEST_FOR_NULL_SR(self, NULL);
 	TEST_FOR_NULL_SR(r_p_key, NULL);
 	TEST_FOR_NULL_SR(p_default_item, NULL);
+
 	const uint64_t true_key_hash = hash_cstr(r_p_key);
 	const struct hashtable_item *p_tmp
 		= &self->data[true_key_hash % HASHTABLE_SIZE];
-	if ( p_tmp->key.true_hash == true_key_hash ) {
+
+	if ( p_tmp->key.true_hash == true_key_hash )
 		return p_tmp->item.data;
-	}
+
 	while ( p_tmp->p_next != NULL ) {
 		p_tmp = p_tmp->p_next;
-		if ( p_tmp->key.true_hash == true_key_hash ) {
+
+		if ( p_tmp->key.true_hash == true_key_hash )
 			return p_tmp->item.data;
-		}
 	}
+
 	return p_default_item;
 }
 
-bool
+_Bool
 hashtable_is_empty(const struct hashtable *self) {
 	toolbox_errno = RET_OK;
 	TEST_FOR_NULL(self);
@@ -181,21 +188,23 @@ hashtable_is_empty(const struct hashtable *self) {
 
 static RET_TYPE
 m_hashtable_put_helper(struct hashtable *self, struct hashtable_item *p_tmp
-					   , uint64_t true_key_hash, size_t key_hash
-					   , const void *r_p_item, size_t p_item_size) {
+		       , uint64_t true_key_hash, size_t key_hash
+		       , const void *r_p_item, size_t p_item_size) {
 	p_tmp->key.true_hash = true_key_hash;
 	p_tmp->key.hash = key_hash;
 	p_tmp->p_next = NULL;
 	p_tmp->item.size = p_item_size;
 	p_tmp->item.data = malloc(p_tmp->item.size);
+
 	if ( p_tmp->item.data == NULL ) {
 		self->used_keys.data[--self->used_keys.size] = 0;
 		p_tmp->key.true_hash = 0;
 		p_tmp->key.hash = 0;
 		p_tmp->item.size = 0;
-		toolbox_errno = RET_ERR_FAILED_MALLOC;
-		return RET_ERR_FAILED_MALLOC;
+		toolbox_errno = RET_EFM;
+		return RET_EFM;
 	}
+
 	memcpy(p_tmp->item.data, r_p_item, p_tmp->item.size);
 	return RET_OK;
 }
@@ -211,24 +220,29 @@ hashtable_put(struct hashtable *self
 	const uint64_t true_key_hash = hash_cstr(r_p_key);
 	const size_t key_hash = true_key_hash % HASHTABLE_SIZE;
 	struct hashtable_item *p_tmp = &self->data[key_hash];
+
 	if ( p_tmp->key.true_hash == true_key_hash ) {
-		toolbox_errno = RET_ERR_ITEM_ALREADY_EXIST;
-		return RET_ERR_ITEM_ALREADY_EXIST;
+		toolbox_errno = RET_EIAE;
+		return RET_EIAE;
 	}
+
 	if ( p_tmp->key.true_hash == 0 ) {
 		self->used_keys.data[self->used_keys.size++] = key_hash;
 		return m_hashtable_put_helper(self, p_tmp
-									  , true_key_hash, key_hash
-									  , r_p_item, p_item_size);
-	} else {
-		do {
-			p_tmp = p_tmp->p_next;
-		} while ( p_tmp != NULL );
-		p_tmp = malloc(sizeof(struct hashtable_item));
-		return m_hashtable_put_helper(self, p_tmp
-									  , true_key_hash, key_hash
-									  , r_p_item, p_item_size);
+					      , true_key_hash, key_hash
+					      , r_p_item, p_item_size);
 	}
+
+	do {
+		p_tmp = p_tmp->p_next;
+	} while ( p_tmp != NULL );
+
+	p_tmp = malloc(sizeof(struct hashtable_item));
+
+	return m_hashtable_put_helper(self, p_tmp
+				      , true_key_hash, key_hash
+				      , r_p_item, p_item_size);
+
 	return RET_OK;
 }
 
@@ -245,14 +259,14 @@ m_remove_index_carray(size_t *restrict r_p_carray, size_t *restrict r_p_size
 __attribute__((__nonnull__))
 inline static void
 m_remove_item(struct hashtable *self
-			  , const size_t p_key_hash, const uint64_t p_true_key_hash) {
+	      , const size_t p_key_hash, const uint64_t p_true_key_hash) {
 	struct hashtable_item *p_tmp = &self->data[p_key_hash];
 	if ( p_tmp->key.true_hash == p_true_key_hash ) {
 		if ( p_tmp->p_next == NULL ) {
 			for ( size_t i = 0; i < self->used_keys.size; ++i ) {
 				if ( self->used_keys.data[i] == p_key_hash ) {
 					m_remove_index_carray(self->used_keys.data
-										  , &self->used_keys.size, i);
+							      , &self->used_keys.size, i);
 				}
 			}
 			p_tmp->key.hash = 0;
@@ -280,123 +294,147 @@ hashtable_remove(struct hashtable *self, const char *r_p_key) {
 	toolbox_errno = RET_OK;
 	TEST_FOR_NULL_SR(self, NULL);
 	TEST_FOR_NULL_SR(r_p_key, NULL);
+
 	const uint64_t true_key_hash = hash_cstr(r_p_key);
 	const size_t key_hash = true_key_hash % HASHTABLE_SIZE;
 	const struct hashtable_item *p_tmp = &self->data[key_hash];
+
 	void *ret = NULL;
 	if ( p_tmp->key.true_hash == true_key_hash ) {
 		ret = malloc(p_tmp->item.size);
 		memcpy(ret, p_tmp->item.data, p_tmp->item.size);
 		m_remove_item(self, key_hash, true_key_hash);
-	} else {
-		while ( p_tmp->p_next != NULL ) {
-			if ( p_tmp->key.true_hash == true_key_hash ) {
-				ret = malloc(p_tmp->item.size);
-				memcpy(ret, p_tmp->item.data, p_tmp->item.size);
-				m_remove_item(self, key_hash, true_key_hash);
-			}
+		goto exit;
+	}
+
+	while ( p_tmp->p_next != NULL ) {
+		if ( p_tmp->key.true_hash == true_key_hash ) {
+			ret = malloc(p_tmp->item.size);
+			memcpy(ret, p_tmp->item.data, p_tmp->item.size);
+			m_remove_item(self, key_hash, true_key_hash);
 		}
 	}
+
+exit:
 	return ret;
 }
 
-bool
+_Bool
 hashtable_remove_if_equal(struct hashtable *self
-						  , const char *r_p_key
-						  , const void *r_p_item, const size_t p_item_size) {
+			  , const char *r_p_key
+			  , const void *r_p_item, const size_t p_item_size) {
 	toolbox_errno = RET_OK;
 	TEST_FOR_NULL(self);
 	TEST_FOR_NULL(r_p_key);
 	TEST_FOR_NULL(r_p_item);
+
 	const uint64_t true_key_hash = hash_cstr(r_p_key);
 	const size_t key_hash = true_key_hash % HASHTABLE_SIZE;
 	const struct hashtable_item *p_tmp = &self->data[key_hash];
+
 	if ( p_tmp->key.true_hash == true_key_hash
 		 && void_pointer_equal(p_tmp->item.data, p_tmp->item.size
-							   , r_p_item, p_item_size) ) {
+				       , r_p_item, p_item_size) ) {
 		m_remove_item(self, key_hash, true_key_hash);
 		return true;
-	} else {
-		while ( p_tmp->p_next != NULL ) {
-			if ( p_tmp->key.true_hash == true_key_hash
-				 && void_pointer_equal(p_tmp->item.data, p_tmp->item.size
-									   , r_p_item, p_item_size) ) {
-				m_remove_item(self, key_hash, true_key_hash);
-				return true;
-			}
+	}
+
+	while ( p_tmp->p_next != NULL ) {
+		if ( p_tmp->key.true_hash == true_key_hash
+		     && void_pointer_equal(p_tmp->item.data, p_tmp->item.size
+					   , r_p_item, p_item_size) ) {
+			m_remove_item(self, key_hash, true_key_hash);
+			return true;
 		}
 	}
+
 	return false;
 }
 
 const void *
 hashtable_replace(struct hashtable *self
-				  , const char *r_p_key
-				  , const void *r_p_item, const size_t p_item_size) {
+		  , const char *r_p_key
+		  , const void *r_p_item, const size_t p_item_size) {
 	toolbox_errno = RET_OK;
+
 	TEST_FOR_NULL_SR(self, NULL);
 	TEST_FOR_NULL_SR(r_p_key, NULL);
 	TEST_FOR_NULL_SR(r_p_item, NULL);
+
 	const uint64_t true_key_hash = hash_cstr(r_p_key);
 	struct hashtable_item *p_tmp
 		= &self->data[true_key_hash % HASHTABLE_SIZE];
 	void *ret = NULL;
+
 	if ( p_tmp->key.true_hash != true_key_hash ) {
 		while ( p_tmp->p_next != NULL ) {
 			p_tmp = p_tmp->p_next;
-			if ( p_tmp->key.true_hash == true_key_hash ) {
+
+			if ( p_tmp->key.true_hash == true_key_hash )
 				break;
-			}
 		}
 	}
+
 	ret = malloc(p_tmp->item.size);
 	memcpy(ret, p_tmp->item.data, p_tmp->item.size);
+
 	if ( p_tmp->item.size == p_item_size ) {
 		memcpy(p_tmp->item.data, r_p_item, p_tmp->item.size);
-	} else {
-		free(p_tmp->item.data);
-		p_tmp->item.size = p_item_size;
-		p_tmp->item.data = malloc(p_tmp->item.size);
-		memcpy(p_tmp->item.data, r_p_item, p_tmp->item.size);
+		goto exit;
 	}
+
+	free(p_tmp->item.data);
+	p_tmp->item.size = p_item_size;
+	p_tmp->item.data = malloc(p_tmp->item.size);
+	memcpy(p_tmp->item.data, r_p_item, p_tmp->item.size);
+
+exit:
 	return ret;
 }
 
-bool
+_Bool
 hashtable_replace_if_equal(struct hashtable *self
-						   , const char *r_p_key
-						   , const void *restrict r_p_old_item
-						   , const size_t p_old_item_size
-						   , const void *restrict r_p_new_item
-						   , const size_t p_new_item_size) {
+			   , const char *r_p_key
+			   , const void *restrict r_p_old_item
+			   , const size_t p_old_item_size
+			   , const void *restrict r_p_new_item
+			   , const size_t p_new_item_size) {
 	toolbox_errno = RET_OK;
 	TEST_FOR_NULL(self);
 	TEST_FOR_NULL(r_p_key);
 	TEST_FOR_NULL(r_p_old_item);
 	TEST_FOR_NULL(r_p_new_item);
+
 	const uint64_t true_key_hash = hash_cstr(r_p_key);
-	struct hashtable_item *p_tmp = &self->data[true_key_hash % HASHTABLE_SIZE];
+	struct hashtable_item *p_tmp
+		= &self->data[true_key_hash % HASHTABLE_SIZE];
+
 	if ( p_tmp->key.true_hash != true_key_hash ) {
 		while ( p_tmp->p_next != NULL ) {
 			p_tmp = p_tmp->p_next;
-			if ( p_tmp->key.true_hash == true_key_hash ) {
+
+			if ( p_tmp->key.true_hash == true_key_hash )
 				break;
-			}
 		}
 	}
-	if ( void_pointer_equal(p_tmp->item.data, p_tmp->item.size
-							, r_p_old_item, p_old_item_size) ) {
-		if ( p_tmp->item.size == p_new_item_size ) {
-			memcpy(p_tmp->item.data, r_p_new_item, p_tmp->item.size);
-		} else {
-			free(p_tmp->item.data);
-			p_tmp->item.size = p_new_item_size;
-			p_tmp->item.data = malloc(p_tmp->item.size);
-			memcpy(p_tmp->item.data, r_p_new_item, p_tmp->item.size);
-		}
-		return true;
+
+	if ( ! void_pointer_equal(p_tmp->item.data, p_tmp->item.size
+				  , r_p_old_item, p_old_item_size) ) {
+		return false;
 	}
-	return false;
+
+	if ( p_tmp->item.size == p_new_item_size ) {
+		memcpy(p_tmp->item.data, r_p_new_item, p_tmp->item.size);
+		goto exit_true;
+	}
+
+	free(p_tmp->item.data);
+	p_tmp->item.size = p_new_item_size;
+	p_tmp->item.data = malloc(p_tmp->item.size);
+	memcpy(p_tmp->item.data, r_p_new_item, p_tmp->item.size);
+
+exit_true:
+	return true;
 }
 
 size_t
@@ -408,7 +446,7 @@ hashtable_used_size(const struct hashtable *self) {
 
 RET_TYPE
 hashtable_for_each(struct hashtable *self
-				 , void (*for_each)(void *item, size_t *item_size)) {
+		   , void (*for_each)(void *item, size_t *item_size)) {
 	toolbox_errno = RET_OK;
 	for ( size_t i = 0; i < self->used_keys.size; ++i ) {
 		struct hashtable_item *tmp_it
@@ -424,4 +462,8 @@ hashtable_for_each(struct hashtable *self
 	return RET_OK;
 }
 
+#undef TEST_FOR_NULL_SR
 #undef TEST_FOR_NULL
+
+#undef false
+#undef true