add hash table

This commit is contained in:
lixianjing 2021-11-15 17:07:33 +08:00
parent 5f570df4fc
commit ee695cf212
5 changed files with 537 additions and 0 deletions

View File

@ -1,5 +1,8 @@
# 最新动态
2021/11/15
* 增加hash table。
2021/11/11
* 修复在fb为bgra8888格式时半透明边缘出现明显边缘的问题以及前景和背景色都为半透明时候颜色不正常的问题感谢智明提供补丁

204
src/tkc/hash_table.c Normal file
View File

@ -0,0 +1,204 @@
/**
* File: hash_table.c
* Author: AWTK Develop Team
* Brief: hash table
*
* Copyright (c) 2018 - 2021 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2021-11-15 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "tkc/mem.h"
#include "tkc/utils.h"
#include "tkc/hash_table.h"
hash_table_t* hash_table_create(uint32_t capacity, tk_destroy_t destroy, tk_compare_t compare,
tk_hash_t hash) {
hash_table_t* hash_table = NULL;
return_value_if_fail(capacity > 0 && hash != NULL && compare != NULL, NULL);
hash_table = TKMEM_ZALLOC(hash_table_t);
return_value_if_fail(hash_table != NULL, NULL);
if (hash_table_init(hash_table, capacity, destroy, compare, hash) == NULL) {
TKMEM_FREE(hash_table);
}
return hash_table;
}
hash_table_t* hash_table_init(hash_table_t* hash_table, uint32_t capacity, tk_destroy_t destroy,
tk_compare_t compare, tk_hash_t hash) {
uint32_t i = 0;
return_value_if_fail(hash_table != NULL, NULL);
return_value_if_fail(capacity > 0 && hash != NULL && compare != NULL, NULL);
memset(hash_table, 0, sizeof(hash_table_t));
hash_table->hash = hash;
hash_table->destroy = destroy;
hash_table->compare = compare;
goto_error_if_fail(
darray_init(&(hash_table->buckets), capacity, (tk_destroy_t)darray_destroy, NULL));
for (i = 0; i < capacity; i++) {
darray_t* arr = darray_create(5, destroy, compare);
goto_error_if_fail(arr != NULL);
ENSURE(darray_push(&(hash_table->buckets), arr) == RET_OK);
}
return hash_table;
error:
hash_table_deinit(hash_table);
return NULL;
}
static darray_t* hash_table_get_array(hash_table_t* hash_table, void* ctx) {
uint32_t index = 0;
return_value_if_fail(hash_table != NULL, NULL);
return_value_if_fail(hash_table->hash != NULL && hash_table->buckets.size > 0, NULL);
index = hash_table->hash(ctx) % hash_table->buckets.size;
return (darray_t*)darray_get(&(hash_table->buckets), index);
}
void* hash_table_find(hash_table_t* hash_table, tk_compare_t cmp, void* ctx) {
darray_t* arr = hash_table_get_array(hash_table, ctx);
return_value_if_fail(arr != NULL, NULL);
return darray_find_ex(arr, cmp, ctx);
}
ret_t hash_table_add(hash_table_t* hash_table, void* data, bool_t replace_if_exist) {
darray_t* arr = hash_table_get_array(hash_table, data);
return_value_if_fail(arr != NULL, RET_BAD_PARAMS);
return darray_sorted_insert(arr, data, hash_table->compare, replace_if_exist);
}
ret_t hash_table_remove(hash_table_t* hash_table, tk_compare_t cmp, void* ctx) {
darray_t* arr = hash_table_get_array(hash_table, ctx);
return_value_if_fail(arr != NULL, RET_BAD_PARAMS);
return darray_remove_ex(arr, hash_table->compare, ctx);
}
ret_t hash_table_remove_all(hash_table_t* hash_table, tk_compare_t cmp, void* ctx) {
uint32_t i = 0;
uint32_t n = 0;
darray_t** arrs = NULL;
return_value_if_fail(hash_table != NULL, 0);
n = hash_table->buckets.size;
arrs = (darray_t**)(hash_table->buckets.elms);
for (i = 0; i < n; i++) {
darray_t* iter = arrs[i];
darray_remove_all(iter, cmp, ctx);
}
return RET_OK;
}
int32_t hash_table_count(hash_table_t* hash_table, tk_compare_t cmp, void* ctx) {
uint32_t i = 0;
uint32_t n = 0;
int32_t count = 0;
darray_t** arrs = NULL;
return_value_if_fail(hash_table != NULL, 0);
n = hash_table->buckets.size;
arrs = (darray_t**)(hash_table->buckets.elms);
for (i = 0; i < n; i++) {
darray_t* iter = arrs[i];
iter->compare = cmp;
count += darray_count(iter, ctx);
iter->compare = hash_table->compare;
}
return count;
}
ret_t hash_table_clear(hash_table_t* hash_table) {
uint32_t i = 0;
uint32_t n = 0;
darray_t** arrs = NULL;
return_value_if_fail(hash_table != NULL, RET_BAD_PARAMS);
n = hash_table->buckets.size;
arrs = (darray_t**)(hash_table->buckets.elms);
for (i = 0; i < n; i++) {
darray_t* iter = arrs[i];
darray_clear(iter);
}
return RET_OK;
}
ret_t hash_table_foreach(hash_table_t* hash_table, tk_visit_t visit, void* ctx) {
uint32_t i = 0;
uint32_t n = 0;
darray_t** arrs = NULL;
return_value_if_fail(hash_table != NULL, RET_BAD_PARAMS);
n = hash_table->buckets.size;
arrs = (darray_t**)(hash_table->buckets.elms);
for (i = 0; i < n; i++) {
darray_t* iter = arrs[i];
ret_t ret = darray_foreach(iter, visit, ctx);
if (ret != RET_OK) {
return ret;
}
}
return RET_OK;
}
ret_t hash_table_deinit(hash_table_t* hash_table) {
return_value_if_fail(hash_table != NULL, RET_BAD_PARAMS);
darray_deinit(&(hash_table->buckets));
memset(hash_table, 0x00, sizeof(hash_table_t));
return RET_OK;
}
ret_t hash_table_destroy(hash_table_t* hash_table) {
return_value_if_fail(hash_table != NULL, RET_BAD_PARAMS);
hash_table_deinit(hash_table);
TKMEM_FREE(hash_table);
return RET_OK;
}
uint32_t hash_table_hash_str(const void* data) {
const char* p = (const char*)data;
uint32_t value = 0;
return_value_if_fail(data != NULL, 0);
while (*p) {
value += *p++;
}
return value;
}
uint32_t hash_table_hash_int(const void* data) {
return tk_pointer_to_int(data);
}

222
src/tkc/hash_table.h Normal file
View File

@ -0,0 +1,222 @@
/**
* File: hash_table.h
* Author: AWTK Develop Team
* Brief: hash table
*
* Copyright (c) 2018 - 2021 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2021-11-15 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_HASH_TABLE_H
#define TK_HASH_TABLE_H
#include "tkc/darray.h"
BEGIN_C_DECLS
/**
* @class hash_table_t
*
*
* hash_table\_init初始化时hash_table\_deinit释放
*
* ```c
* hash_table_t hash_table;
* hash_table_init(&hash_table, 10, destroy, compare, hash);
* ...
* hash_table_deinit(&hash_table);
* ```
*
* hash_table\_create创建时hash_table\_destroy销毁
*
* ```c
* hash_table_t* hash_table = hash_table_create(10, destroy, compare, hash);
* ...
* hash_table_destroy(hash_table);
* ```
*
*/
typedef struct _hash_table_t {
/**
* @property {darray_t} buckets
* @annotation ["readable"]
* buckets
*/
darray_t buckets;
/**
* @property {tk_destroy_t} destroy
* @annotation ["readable"]
*
*/
tk_destroy_t destroy;
/**
* @property {tk_compare_t} compare
* @annotation ["readable"]
*
*/
tk_compare_t compare;
/**
* @property {tk_hash_t} hash
* @annotation ["readable"]
*
*/
tk_hash_t hash;
} hash_table_t;
/**
* @method hash_table_create
* @annotation ["constructor"]
* hash_table对象
*
* @param {uint32_t} capacity
* @param {tk_destroy_t} destroy
* @param {tk_compare_t} compare
* @param {tk_hash_t} hash
*
* @return {hash_table_t*}
*/
hash_table_t* hash_table_create(uint32_t capacity, tk_destroy_t destroy, tk_compare_t compare,
tk_hash_t hash);
/**
* @method hash_table_init
* hash_table对象
*
* @param {hash_table_t*} hash_table
* @param {uint32_t} capacity
* @param {tk_destroy_t} destroy
* @param {tk_compare_t} compare
* @param {tk_hash_t} hash
*
* @return {hash_table_t*}
*/
hash_table_t* hash_table_init(hash_table_t* hash_table, uint32_t capacity, tk_destroy_t destroy,
tk_compare_t compare, tk_hash_t hash);
/**
* @method hash_table_find
*
* @param {hash_table_t*} hash_table
* @param {tk_compare_t} cmp NULL则使用内置的比较函数
* @param {void*} ctx
*
* @return {void*} NULL
*/
void* hash_table_find(hash_table_t* hash_table, tk_compare_t cmp, void* ctx);
/**
* @method hash_table_add
*
* @param {hash_table_t*} hash_table
* @param {void*} data
* @param {bool_t} replace_if_exist
*
* @return {ret_t} RET_OK表示成功
*/
ret_t hash_table_add(hash_table_t* hash_table, void* data, bool_t replace_if_exist);
/**
* @method hash_table_remove
*
* @param {hash_table_t*} hash_table
* @param {tk_compare_t} cmp NULL则使用内置的比较函数
* @param {void*} ctx
*
* @return {ret_t} RET_OK表示成功
*/
ret_t hash_table_remove(hash_table_t* hash_table, tk_compare_t cmp, void* ctx);
/**
* @method hash_table_remove_all
*
* @param {hash_table_t*} hash_table
* @param {tk_compare_t} cmp NULL则使用内置的比较函数
* @param {void*} ctx
*
* @return {ret_t} RET_OK表示成功
*/
ret_t hash_table_remove_all(hash_table_t* hash_table, tk_compare_t cmp, void* ctx);
/**
* @method hash_table_count
*
* @param {hash_table_t*} hash_table
* @param {tk_compare_t} cmp NULL则使用内置的比较函数
* @param {void*} ctx
*
* @return {int32_t}
*/
int32_t hash_table_count(hash_table_t* hash_table, tk_compare_t cmp, void* ctx);
/**
* @method hash_table_clear
*
* @param {hash_table_t*} hash_table
*
* @return {ret_t} RET_OK表示成功
*/
ret_t hash_table_clear(hash_table_t* hash_table);
/**
* @method hash_table_foreach
*
* @param {hash_table_t*} hash_table
* @param {tk_visit_t} visit
* @param {void*} ctx
*
* @return {ret_t} RET_OK表示成功
*/
ret_t hash_table_foreach(hash_table_t* hash_table, tk_visit_t visit, void* ctx);
/**
* @method hash_table_deinit
* elms
* @param {hash_table_t*} hash_table
*
* @return {ret_t} RET_OK表示成功
*/
ret_t hash_table_deinit(hash_table_t* hash_table);
/**
* @method hash_table_destroy
* hash_table对象
* @param {hash_table_t*} hash_table
*
* @return {ret_t} RET_OK表示成功
*/
ret_t hash_table_destroy(hash_table_t* hash_table);
/**
* @method hash_table_hash_str
* hash值
* @param {const void*} data
*
* @return {uint32_t} hash值
*/
uint32_t hash_table_hash_str(const void* data);
/**
* @method hash_table_hash_int
* int的hash值
* @param {const void*} data
*
* @return {uint32_t} hash值
*/
uint32_t hash_table_hash_int(const void* data);
END_C_DECLS
#endif /*TK_HASH_TABLE_H*/

View File

@ -333,6 +333,7 @@ typedef bool_t (*tk_is_valid_t)(void* data);
typedef bool_t (*tk_filter_t)(void* ctx, const void* data);
typedef int (*tk_compare_t)(const void* a, const void* b);
typedef ret_t (*tk_visit_t)(void* ctx, const void* data);
typedef uint32_t (*tk_hash_t)(const void* data);
typedef ret_t (*tk_callback_t)(void* ctx);
/*TK_NAME_LEN+1 must aligned to 4*/

107
tests/hash_table_test.cc Normal file
View File

@ -0,0 +1,107 @@
#include "tkc/utils.h"
#include "tkc/hash_table.h"
#include "gtest/gtest.h"
static int int_compare(const void* a, const void* b) {
return tk_pointer_to_int(a) - tk_pointer_to_int(b);
}
TEST(DHashTable, int_add_remove) {
uint32_t i = 0;
uint32_t n = 10000;
hash_table_t* ht = hash_table_create(10, NULL, int_compare, hash_table_hash_int);
for (i = 0; i < n; i++) {
ASSERT_EQ(hash_table_add(ht, tk_pointer_from_int(i), TRUE), RET_OK);
ASSERT_EQ(hash_table_count(ht, compare_always_equal, NULL), (i + 1));
ASSERT_EQ(tk_pointer_to_int(hash_table_find(ht, int_compare, tk_pointer_from_int(i))), i);
}
for (i = 0; i < n; i++) {
ASSERT_EQ(hash_table_remove(ht, int_compare, tk_pointer_from_int(i)), RET_OK);
ASSERT_EQ(hash_table_count(ht, compare_always_equal, NULL), n - i - 1);
ASSERT_EQ(tk_pointer_to_int(hash_table_find(ht, int_compare, tk_pointer_from_int(i))), 0);
}
hash_table_destroy(ht);
}
TEST(DHashTable, int_add_clear) {
uint32_t i = 0;
uint32_t n = 10000;
hash_table_t* ht = hash_table_create(10, NULL, int_compare, hash_table_hash_int);
for (i = 0; i < n; i++) {
ASSERT_EQ(hash_table_add(ht, tk_pointer_from_int(i), TRUE), RET_OK);
ASSERT_EQ(hash_table_count(ht, compare_always_equal, NULL), (i + 1));
ASSERT_EQ(tk_pointer_to_int(hash_table_find(ht, int_compare, tk_pointer_from_int(i))), i);
}
ASSERT_EQ(hash_table_clear(ht), RET_OK);
ASSERT_EQ(hash_table_count(ht, compare_always_equal, NULL), 0);
hash_table_destroy(ht);
}
TEST(DHashTable, int_remove_all) {
uint32_t i = 0;
uint32_t n = 10000;
hash_table_t* ht = hash_table_create(10, NULL, int_compare, hash_table_hash_int);
for (i = 0; i < n; i++) {
ASSERT_EQ(hash_table_add(ht, tk_pointer_from_int(i), TRUE), RET_OK);
ASSERT_EQ(hash_table_count(ht, compare_always_equal, NULL), (i + 1));
ASSERT_EQ(tk_pointer_to_int(hash_table_find(ht, int_compare, tk_pointer_from_int(i))), i);
}
ASSERT_EQ(hash_table_remove_all(ht, compare_always_equal, NULL), RET_OK);
ASSERT_EQ(hash_table_count(ht, compare_always_equal, NULL), 0);
hash_table_destroy(ht);
}
static ret_t visit_int(void* ctx, const void* data) {
int32_t v = tk_pointer_to_int(data);
str_t* str = (str_t*)ctx;
str_append_char(str, ';');
str_append_int(str, v);
return RET_OK;
}
TEST(DHashTable, int_foreach) {
uint32_t i = 0;
uint32_t n = 20;
str_t str;
hash_table_t* ht = hash_table_create(10, NULL, int_compare, hash_table_hash_int);
for (i = 0; i < n; i++) {
ASSERT_EQ(hash_table_add(ht, tk_pointer_from_int(i), TRUE), RET_OK);
ASSERT_EQ(hash_table_count(ht, compare_always_equal, NULL), (i + 1));
ASSERT_EQ(tk_pointer_to_int(hash_table_find(ht, int_compare, tk_pointer_from_int(i))), i);
}
str_init(&str, 0);
ASSERT_EQ(hash_table_foreach(ht, visit_int, &str), RET_OK);
ASSERT_STREQ(str.str, ";0;10;1;11;2;12;3;13;4;14;5;15;6;16;7;17;8;18;9;19");
str_reset(&str);
hash_table_destroy(ht);
}
TEST(DHashTable, str_add_remove) {
char str[32];
uint32_t i = 0;
uint32_t n = 10000;
hash_table_t* ht =
hash_table_create(10, default_destroy, (tk_compare_t)strcmp, hash_table_hash_str);
for (i = 0; i < n; i++) {
tk_snprintf(str, sizeof(str), "%u", i);
ASSERT_EQ(hash_table_add(ht, tk_strdup(str), TRUE), RET_OK);
ASSERT_EQ(hash_table_count(ht, compare_always_equal, NULL), (i + 1));
ASSERT_STREQ((char*)hash_table_find(ht, (tk_compare_t)strcmp, str), str);
}
hash_table_destroy(ht);
}