mcu_hi3321_watch/middleware/utils/algorithm/cstl/cstl_hash.h
2025-05-26 20:15:20 +08:00

388 lines
18 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file cstl_hash.h
* @copyright Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
* @brief cstl_hash 对外头文件
* @details 1、遍历过程中迭代器指向冲突链中节点的位置但end迭代器指向最后一个保留的hash桶该桶无数据。
* 2、关于(key, value)中的value
* a) 如果key、value是整型数据且长度 <= sizeof(uintptr_t)则直接记录在node后面紧邻位置
* b其它场景key或value位置记录的是指针指向真正的用户key或用户数据
* 此时用户必须注册duplicate函数和free函数对。
* 3、duplicate函数用户需要先根据源数据长度申请内存在把用户数拷贝到申请的内存中去最后返回分配的内存地址。
* +--------+
* | 控制块 |
* +------- + iter--->+------+ iter-->+------+
* | 0 | <-冲突链-> | prev | | prev |
* +--------+ | next | 场景1 | next | 场景2:
* | 1 | +------+ key长度<=sizeof(uintptr_t) +------+ key长度<sizeof(uintptr_t)
* |--------+ | key | value长度<=sizeof(uintptr_t) | key | value长度>sizeof(uintptr_t)
* | + +------+ +------+ 或字符串或自定义数据结构
* | ... | | value| | data |--+
* +--------+ +------+ | 指针 | +
* +------+ +
* +
* +----->+----------+
* | userdata |
* | area |
* +----------+
* iter-->+------+ iter-->+------+ 场景4:
* | prev | | prev | key长度>sizeof(uintptr_t)
* | next | 场景3: | next | 或字符串或自定义数据结构
* +------+ key长度>sizeof(uintptr_t)或字符串或自定义数据结构 +------+
* | key |---+ value长度<=sizeof(uintptr_t) | key |---+ value长度>sizeof(uintptr_t)
* | 指针 | + | 指针 | + 或字符串或自定义数据结构
* +------+ +---->+----------+ +------+ +---->+----------+
* | data | | userkey | | data |--+ | userkey |
* +------+ | area | | 指针 | + | area |
* +----------+ +------+ + +----------+
* +
* +----->+----------+
* | userdata |
* | area |
* +----------+
* @date 2021-05-14
* @version v0.1.0
* *******************************************************************************************
* @par 修改日志:
* <table>
* <tr><th>Date <th>Version <th>Description
* <tr><td>2021-05-14 <td>0.1.0 <td>创建初始版本
* </table>
* *******************************************************************************************
*/
/**
* @defgroup cstl_hash 哈希表
* @ingroup cstl
*/
#ifndef CSTL_HASH_H
#define CSTL_HASH_H
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "cstl_public.h"
#include "securec.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup cstl_hash
* @brief hash表句柄
*/
typedef struct CstlHashInfo CstlHash;
/**
* @ingroup cstl_hash
* @brief hash表迭代器定义指向hash节点
*/
typedef struct TagHashNode *CstlHashIterator;
/**
* @ingroup cstl_hash
* @brief 根据输入的Key生成hash表索引。
* @param key [IN] hash key
* @param bktSize [IN] hash桶大小
*/
typedef size_t (*CstlHashCodeCalcFunc)(uintptr_t key, size_t bktSize);
/**
* @ingroup cstl_hash
* @brief 该函数把输入数据与Key进行匹配比较。第一个哈希表中保存的key第二个是用户需要匹配的Key。如果不匹配返回值为false。
* @param key1 [IN] 哈希表中保存的key
* @param key2 [IN] 待匹配的key
* @retval #true key1和key2匹配。
* @retval #false key1和key2不匹配。
*/
typedef bool (*CstlHashMatchFunc)(uintptr_t key1, uintptr_t key2);
/**
* @ingroup cstl_hash
* @brief 默认整型哈希函数。
* @par 默认整型哈希函数。
* @attention \n
* 1.key为用户调用其他接口时的入参。\n
* 2.若key为整型用户可在创建hash时将该函数作为hashFunc参数。\n
* @param key [IN] 待计算的key。
* @param bktSize [IN] 哈希桶大小。
* @retval #哈希值 根据用户key计算出的哈希值。
* @par 依赖:无
* <ul><li>cstl_hash.h该接口声明所在的头文件。</li></ul>
*/
size_t CstlHashCodeCalcInt(uintptr_t key, size_t bktSize);
/**
* @ingroup cstl_hash
* @brief 默认字符串哈希函数。
* @par 默认字符串哈希函数。
* @attention \n
* 1.key为用户调用其他接口时的入参用户必须保证传入的key为合法的字符串首地址。\n
* 2.若key为字符串用户可在创建hash时将该函数作为hashFunc参数。\n
* @param key [IN] 待计算的key。
* @param bktSize [IN] 哈希桶大小。
* @retval #哈希值 根据用户key计算出的哈希值。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
size_t CstlHashCodeCalcStr(uintptr_t key, size_t bktSize);
/**
* @ingroup cstl_hash
* @brief 默认整型匹配函数。
* @par 默认整型匹配函数。
* @attention \n
* 1.key为用户调用其他接口时的入参。\n
* 2.若key为整型用户可在创建hash时将该函数作为matchFunc参数。\n
* @param key1 [IN] 待匹配的key。
* @param key2 [IN] 待匹配的key。
* @retval #true key1和key2匹配。
* @retval #false key1和key2不匹配。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
bool CstlHashMatchInt(uintptr_t key1, uintptr_t key2);
/**
* @ingroup cstl_hash
* @brief 默认字符串匹配函数。
* @par 默认字符串匹配函数。
* @attention \n
* 1.key1为用户调用其他接口时的入参用户必须保证传入的key1为合法的字符串首地址。\n
* 2.若key为字符串用户可在创建hash时将该函数作为matchFunc参数。\n
* @param key1 [IN] 待匹配的key。
* @param key2 [IN] 待匹配的key。
* @retval #true key1和key2匹配。
* @retval #false key1和key2不匹配。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
bool CstlHashMatchStr(uintptr_t key1, uintptr_t key2);
/**
* @ingroup cstl_hash
* @brief 创建一个Hash表返回Hash表的句柄
* @attention \n
* 1、关于key和data的拷贝函数\n
* 如下场景不需要注册拷贝函数如果是int型数据且长度<=sizeof(uintptr_t)。\n
* 其它场景必须注册拷贝函数:\n
* a是int型数据但长度 >sizeof(uintptr_t)\n
* b字符串\n
* c用户自定义数据结构\n
* 2、关于free函数简单来说如果注册了duplicate函数就必须注册相应的free函数。 \n
* 3、提供默认的整型、字符串哈希函数#CstlHashCodeCalcInt、#CstlHashCodeCalcStr。 \n
* 4、提供默认的整型、字符串匹配函数#CstlHashMatchInt、#CstlHashMatchStr。 \n
* @param bktSize [IN] hash桶的个数
* @param hashCalcFunc [IN] hash值计算函数。如果为NULL则默认key为整型使用#CstlHashCodeCalcInt。
* @param matchFunc [IN] hash key匹配函数。如为NULL则默认key为整型使用#CstlHashMatchInt。
* @param keyFunc [IN] hash key拷贝及释放函数对如果用户未注册keyFunc->dupFunc则默认为key为整型。
* @param valueFunc [IN] hash data拷贝及释放函数对。如果用户未注册valueFunc->dupFunc则默认为data为整型。
* @retval hash表句柄。NULL表示创建失败。
* @par 依赖:无
* @see #CstlHashCodeCalcInt、#CstlHashCodeCalcStr、#CstlHashMatchInt、#CstlHashMatchStr。
* @li cstl_hash.h该接口声明所在的头文件.
*/
CstlHash *CstlHashCreate(size_t bktSize,
CstlHashCodeCalcFunc hashFunc,
CstlHashMatchFunc matchFunc,
CstlDupFreeFuncPair *keyFunc,
CstlDupFreeFuncPair *valueFunc);
/**
* @ingroup cstl_hash
* @brief 插入hash数据
* @par 描述:创建节点,把数据(key、value)插入hash表
* @attention
* 1.不支持重复key。\n
* 2.key和value为整型值或指向用户key或value的地址。\n
* 3.如果扩展数据的生命周期小于节点的生命周期,则需要在创建哈希表时注册拷贝函数及释放函数。\n
* @param hash [IN] hash表的句柄。
* @param key [IN] key或保存key的地址。
* @param keySize [IN] key拷贝长度若用户未注册dupFunc该参数将不被使用
* @param value [IN] value或保存value的地址。
* @param valueSize [IN] value拷贝长度若用户未注册dupFunc该参数将不被使用
* @retval #CSTL_OK 插入节点成功。
* @retval #CSTL_ERROR 插入失败。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
int32_t CstlHashInsert(CstlHash *hash, uintptr_t key, size_t keySize, uintptr_t value, size_t valueSize);
/**
* @ingroup cstl_hash
* @brief 插入或更新hash数据
* @par 描述该接口用于将不存在的key插入到哈希表或更新已存在的key对应的value。
* @attention
* 1.支持重复key。\n
* 2.当key不存在时该接口的使用与#CstlHashInsert保持一致。\n
* 3.当key存在时该接口会更新value。\n
* @param hash [IN] hash表的句柄。
* @param key [IN] key或保存key的地址。
* @param keySize [IN] key拷贝长度若用户未注册dupFunc该参数将不被使用
* @param value [IN] value或保存value的地址。
* @param valueSize [IN] value拷贝长度若用户未注册dupFunc该参数将不被使用
* @retval #CSTL_OK 插入或更新节点成功。
* @retval #CSTL_ERROR 插入或更新节点失败。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
int32_t CstlHashPut(CstlHash *hash, uintptr_t key, size_t keySize, uintptr_t value, size_t valueSize);
/**
* @ingroup cstl_hash
* @brief 查找节点,返回节点数据。
* @par 描述: 根据key查找并返回节点数据。
* @param hash [IN] hash表的句柄。
* @param key [IN] key或保存key的地址。
* @param value [OUT] 查到的数据。
* @retval #CSTL_OK 查找成功。
* @retval #CSTL_ERROR 查找失败。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
int32_t CstlHashAt(const CstlHash *hash, uintptr_t key, uintptr_t *value);
/**
* @ingroup cstl_hash
* @brief 查找key所在迭代器。
* @par 描述: 根据key查找并返回key所在的迭代器。
* @param hash [IN] hash表的句柄。
* @param key [IN] key或保存key的地址。
* @retval key存在时返回key所在迭代器指向Node所在地址,其他情况返回#CstlHashIterEnd()。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
CstlHashIterator CstlHashFind(const CstlHash *hash, uintptr_t key);
/**
* @ingroup cstl_hash
* @brief 判断当前HASH表是否为空。
* @par 描述: 判断当前HASH表是否为空为空返回true否则返回false。
* @param hash [IN] hash表句柄。取值范围为有效指针。
* @retval #true 表示HASH表为空。
* @retval #false表示HASH表非空。
* @see #CstlHashSize
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
bool CstlHashEmpty(const CstlHash *hash);
/**
* @ingroup cstl_hash
* @brief 获取HASH表的节点数量。
* @par 描述: 用于获取HASH表的节点数量返回节点个数。
* @param hash [IN] hash表句柄。取值范围为有效指针。
* @retval hash节点数。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
size_t CstlHashSize(const CstlHash *hash);
/**
* @ingroup cstl_hash
* @brief 从hash表中移除指定结点。
* @par 描述: 根据key查找到节点并删除释放内存同时释放相应的节点内存。
* @param hash [IN] hash表句柄。取值范围为有效指针。
* @param key [IN] 移除节点key。
* @retval key存在时返回key所在迭代器的下一个迭代器指向Node所在地址,其他则返回#CstlHashIterEnd()。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
CstlHashIterator CstlHashErase(CstlHash *hash, uintptr_t key);
/**
* @ingroup cstl_hash
* @brief 删除hash表所有节点。
* @par 描述删除所有节点回收节点内存hash表还在只是没有成员
* @attention 注意如果用户数据中有私有资源则需要在创建时注册free钩子函数。
* @param hash [IN] hash表句柄。
* @retval 无。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
void CstlHashClear(CstlHash *hash);
/**
* @ingroup cstl_hash
* @brief 删除hash表
* @par 描述删除hash表如里面有节点先删除节点回收内存。
* @attention 注意如果用户数据中有私有资源则需要在创建时注册free钩子函数。
* @param hash [IN] hash表句柄。
* @retval 无。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
void CstlHashDestory(CstlHash *hash);
/**
* @ingroup cstl_hash
* @brief 获取hash表中的第一个节点的迭代器。
* @par 描述获取hash表中的第一个节点所在的迭代器。
* @param hash [IN] hash表的句柄。
* @retval 第一个节点迭代器若hash为空则返回#CstlHashIterEnd()。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
CstlHashIterator CstlHashIterBegin(const CstlHash *hash);
/**
* @ingroup cstl_hash
* @brief 获取hash表中最后一个节点之后预留的迭代器。
* @par 描述获取hash表中的最后一个节点之后预留的迭代器。该节点指向最后保留的hash桶该桶没有任何成员。
* @param hash [IN] hash表的句柄。
* @retval 最后一个节点之后预留的迭代器。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
CstlHashIterator CstlHashIterEnd(const CstlHash *hash);
/**
* @ingroup cstl_hash
* @brief 获取hash表的下一个节点迭代器。
* @par 描述获取hash表下一个节点迭代器。
* @param hash [IN] hash表的句柄。
* @param it [IN] 当前迭代器。
* @retval 下一个节点迭代器。若当前节点已是最后一个迭代器则返回#CstlHashIterEnd()。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
CstlHashIterator CstlHashIterNext(const CstlHash *hash, CstlHashIterator it);
/**
* @ingroup cstl_hash
* @brief 获取迭代器的key。
* @par 描述获取hash表中迭代器当前key。
* @attention \n
* 1.当hash为空指针或it等于#CstlHashIterEnd()时接口返回0该接口无法区分是错误码还是用户数据
* 用户调用该接口时必须保证hash为合法指针并且it不等于#CstlHashIterEnd()
* @param hash [IN] hash表的句柄。
* @param it [IN] 当前迭代器。
* @retval 迭代器对应的key。it等于#CstlHashIterEnd()时则返回0。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
uintptr_t CstlHashIterKey(const CstlHash *hash, CstlHashIterator it);
/**
* @ingroup cstl_hash
* @brief 获取迭代器的value。
* @par 描述获取hash表中迭代器当前key。
* @attention \n
* 1.当hash为空指针或it等于#CstlHashIterEnd()时接口返回0该接口无法区分是错误码还是用户数据
* 用户调用该接口时必须保证hash为合法指针并且it不等于#CstlHashIterEnd()
* @param hash [IN] hash表的句柄。
* @param it [IN] 当前迭代器。
* @retval 迭代器对应的value。it等于#CstlHashIterEnd()时则返回0。
* @par 依赖:无
* @li cstl_hash.h该接口声明所在的头文件.
*/
uintptr_t CstlHashIterValue(const CstlHash *hash, CstlHashIterator it);
#ifdef __cplusplus
}
#endif
#endif /* CSTL_HASH_H */