/****************************************************************************************** * * 作者: 杨小波 * * 链地址哈希模板 * * 目的: * 提供一个模板, 为日常应用中需要按哈希方法组织数据提供一个模板类. * 该哈希模板采用链地址法解决冲突. * * $Id: harximoban.h,v 1.2 2006/08/04 03:37:33 zhuzhenhua Exp $ * * $Log: harximoban.h,v $ * Revision 1.2 2006/08/04 03:37:33 zhuzhenhua * no message * * Revision 1.5 2003/06/05 03:56:21 jehu * 将注释修改为符合doxgen工具提取开发文档 * * Revision 1.4 2003/05/06 02:31:31 scada * 添加替换标记: $Id: harximoban.h,v 1.2 2006/08/04 03:37:33 zhuzhenhua Exp $, $Log: harximoban.h,v $ * 添加替换标记: $Id: chain_hash.h,v 1.5 2003/06/05 03:56:21 jehu Exp $, Revision 1.2 2006/08/04 03:37:33 zhuzhenhua * 添加替换标记: $Id: chain_hash.h,v 1.5 2003/06/05 03:56:21 jehu Exp $, no message * 添加替换标记: $Id: chain_hash.h,v 1.5 2003/06/05 03:56:21 jehu Exp $, * 添加替换标记: $Id: harximoban.h,v 1.2 2006/08/04 03:37:33 zhuzhenhua Exp $, Revision 1.5 2003/06/05 03:56:21 jehu * 添加替换标记: $Id: harximoban.h,v 1.2 2006/08/04 03:37:33 zhuzhenhua Exp $, 将注释修改为符合doxgen工具提取开发文档 * 添加替换标记: $Id: harximoban.h,v 1.2 2006/08/04 03:37:33 zhuzhenhua Exp $, * * ******************************************************************************************/ #ifndef __CHAIN_HASH_H__ASDFJQWPEUTOUDSAFHJDSAFADSAFWQERUGSKGEWRTPYZNXM #define __CHAIN_HASH_H__ASDFJQWPEUTOUDSAFHJDSAFADSAFWQERUGSKGEWRTPYZNXM /*! * \if developer_doc * \file * * \brief 链地址哈希模板,头文件。 * * 提供一个模板, 为日常应用中需要按哈希方法组织数据提供一个模板类, * 该哈希模板采用链地址法解决冲突.\n * id: $Id: harximoban.h,v 1.2 2006/08/04 03:37:33 zhuzhenhua Exp $ * * \author 杨小波 prcharold@sina.com.cn develop1@szscada.com * \endif */ /*! * \brief 最小的默认哈希表尺寸 */ #define CONST_CHAIN_HASH_DEFAULT_MIN_SIZE 0x10 /*! * \brief 最大的默认哈希尺寸 */ #define CONST_CHAIN_HASH_DEFAULT_MAX_SIZE 0xffff /*! * \brief 链地址哈希表模板 * \param T ---- 在哈希表中存储的元素的类型 * * \par 快速参考 * #include */ #pragma pack (1) // 是pc机系统还是嵌入式系统 #ifdef PC_MACHINE #ifdef OS_WINDOWS #pragma pack (push,1) #else// OS_UNIX #pragma pack(1) #endif //OS_UNIX #endif template class TChainHash { public: /*! 根据哈希表存储的元素的关键字以及哈希表的尺寸,求哈希序号的函数重定义 */ typedef u32 (* pfnindex_of_t)(const void * pKey, u32 hash_size); /*! 根据哈希表存储的元素的关键字的函数重定义 */ typedef void * (* pfnkey_of_t)(const T * pItem); /*! 两个哈希表中存储的元素的关键字之间的比较,主要是比较是否相等 */ typedef int (* pfncompare_t)(const void * pKey1, const void * pKey2); /*! 根据已经一个已经存在的哈希元素,赋值一个新的对象 */ typedef T * (* pfncreate_item_t)(const T * pItem); /*! 释放调用 *pfncreate_item_t 返回的对象 */ typedef void (* pfnfree_item_t)(T * pItem); /*! 哈希元素之间的拷贝 */ typedef T * (* pfncopy_item_t)(T * pItemDest, const T * pItemSrc); /*! 使用者提供的内存分配函数 */ typedef void * (* pfnalloc_t)(u32 size); /*! 释放调用 *pfnalloc_t 分配的内存 */ typedef void (* pfndealloc_t)(void *); /*! * 哈希数组项保存的"数据" */ typedef struct { /*! * 哈希数组项保存的"数据" */ T * pT; /*! * 调用使用者提供的哈希键值函数返回的键值 */ void * pvTKey; } ITEM_t, *PITEM_t, **PPITEM_t; /*! * 哈希表的一行, 这一行保存所有"同义"哈希项, \n * 这一行实际上是产生冲突的所有的哈希项的数组.\n * 在简单地使用线性数组的方式保存. */ typedef struct { /*! * 数组中已有数据项的大小--冲突的个数 */ u32 cntItems; /*! * 在这一行内能够容纳的最大冲突元素个数. * 实际上是分配给数组pItems的实际内存的大小 */ u32 cntAllocItems; /*! * 数组本身 */ PITEM_t pItems; /*! * 哈希项保存的"数据" */ T * pT; /*! * 数据项的键值 */ void * pvTKey; } TABLEENTRY_t, *PTABLEENTRY_t, **PPTABLEENTRY_t; private: /*! * 不容许使用缺省构造函数. */ TChainHash(){}; public: /*! * \brief 构造函数 * * \param u32TableSize --[in] 哈希表的大小 * \param pfnIndexOf --[in] 使用者提供的从键值到哈希值的转换函数 * \param pfnKeyOf --[in] 使用者提供的返回一个哈希项保存的数据项的关键值. * \param pfnCompare --[in] 比较两个数据项的关键字的大小 * \param pfnCreateItem --[in] 使用者提供的从一个给定数据项的创建另一个新的数据项的函数 * \param pfnFreeItem --[in] 使用者提供的用户释放数据项的函数 * \param pfnCopyItem --[in] 使用者提供的拷贝函数. * \param pfnAlloc --[in] 使用者提供的用户分配内存的函数. * \param pfnDeAlloc --[in] 使用者提供的用户释放由pfnAlloc所分配的内存的函数 * * \note * 在构造函数不会调用使用从构造函数传递的参数函数. * 参数中的函数指针的类型定义说明参见模板中与这些函数指针项对应的成员变量. */ TChainHash( u32 u32TableSize, u32 (* pfnIndexOf)(const void * pKey, u32 hash_size), void * (* pfnKeyOf)(const T * pItem), int (* pfnCompare)(const void * pKey1, const void * pKey2), T * (* pfnCreateItem)(const T * pItem), void (* pfnFreeItem)(T * pItem), T * (* pfnCopyItem)(T * pItemDest, const T * pItemSrc), void * (* pfnAlloc)(u32 size), void (* pfnDeAlloc)(void *) ) { /* * 记住使用者提供的工具函数 */ if(pfnIndexOf) m_pfnIndexOf = pfnIndexOf; else m_pfnIndexOf = NULL; if(pfnKeyOf) m_pfnKeyOf = pfnKeyOf; else m_pfnKeyOf = NULL; if(pfnCompare) m_pfnCompare = pfnCompare; else m_pfnCompare = NULL; if(pfnCreateItem) m_pfnCreateItem = pfnCreateItem; else m_pfnCreateItem = NULL; if(pfnFreeItem) m_pfnFreeItem = pfnFreeItem; else m_pfnFreeItem = NULL; if(pfnCopyItem) m_pfnCopyItem = pfnCopyItem; else m_pfnCopyItem = NULL; if(pfnAlloc) m_pfnAlloc = pfnAlloc; else m_pfnAlloc = NULL; if(pfnDeAlloc) m_pfnDeAlloc = pfnDeAlloc; else m_pfnDeAlloc = NULL; /* * 初始化哈希表的尺寸 */ m_uiSize = u32TableSize; if(m_uiSize > (u32)CONST_CHAIN_HASH_DEFAULT_MAX_SIZE) m_uiSize = (u32)CONST_CHAIN_HASH_DEFAULT_MAX_SIZE; if(m_uiSize < CONST_CHAIN_HASH_DEFAULT_MIN_SIZE) m_uiSize = CONST_CHAIN_HASH_DEFAULT_MIN_SIZE; /* * 初始化哈希表 */ if(m_pfnAlloc && m_pfnDeAlloc) m_pTable = (PTABLEENTRY_t)(*m_pfnAlloc)((u32)sizeof(TABLEENTRY_t) * m_uiSize); else m_pTable = (PTABLEENTRY_t) new u_8[(sizeof(TABLEENTRY_t) * m_uiSize)]; if(NULL != m_pTable) memset((void *)m_pTable, 0, sizeof(TABLEENTRY_t) * m_uiSize); } /*! * \brief 析构函数 */ virtual ~TChainHash() { if(NULL == m_pTable) return; /* * 释放哈希表中同义词数组所占用的内存空间. */ for(u32 i = 0; i < m_uiSize; i++) { if(NULL != m_pTable[i].pItems) { if(m_pfnAlloc && m_pfnDeAlloc) { (*m_pfnDeAlloc)(m_pTable[i].pItems); m_pTable[i].pItems = NULL; } else { delete m_pTable[i].pItems; m_pTable[i].pItems = NULL; } } } /* * 释放哈希表所占用的内存空间 */ if(m_pfnAlloc && m_pfnDeAlloc) { (*m_pfnDeAlloc)(m_pTable); m_pTable = NULL; } else { delete m_pTable; m_pTable = NULL; } } private: /*! * 哈希链表的尺寸 */ u32 m_uiSize; /*! * 哈希表 */ PTABLEENTRY_t m_pTable; /*! * \brief 用户定义的返回一个哈希表项的索引值函数, 传给函数的参数有本哈希表的当前无冲突尺寸 * * \param pKey --[in] 数据项的键值 * \param hash_size --[in] 本哈希表的尺寸 * * \return * [0 -- hash_size - 1)范围内的整数 */ u32 (* m_pfnIndexOf)(const void * pKey, u32 hash_size); /*! * \brief 返回一个哈希表项的键值 * * \param pItem --[in] 数据项 * * \return * 数据项的键值 */ void * (* m_pfnKeyOf)(const T * pItem); /*! * \brief 比较两个哈希表项的大小 * * \param pKey1 --[in] 键值1 * \param pKey2 --[in] 键值2 * * \return * 大于0 -- pKey1所代表的数据项大于pKey2所代表的数据项 * 0 -- pKey1所代表的数据项等于pKey2所代表的数据项 * 小于0 -- pKey1所代表的数据项小于pKey2所代表的数据项 */ int (* m_pfnCompare)(const void * pKey1, const void * pKey2); /*! * \brief 以一个已知表项为蓝本, 创建一个新的哈希表项. * * \param pItem --[in] 源数据项 * * \return * 新的数据项 */ T * (* m_pfnCreateItem)(const T * pItem); /*! * \brief 和m_pfnCreateItem的派对, 用于释放由m_pfnCreateItem创建的哈希表项 * * \param pItem --[in] 欲被释放的数据项 */ void (* m_pfnFreeItem)(T * pItem); /*! * \brief 拷贝源哈希表项到目的哈希表项. * * \param pItemDest --[in] 目的数据项 * \param pItemSrc --[in] 源数据项 * * \return * 目的数据项 */ T * (* m_pfnCopyItem)(T * pItemDest, const T * pItemSrc); /*! * \brief 用户提供的分配内存的函数, 使用该函数, 可以使该链地址哈希模板与内存分配方法无关. * * \param size --[in] 欲分配内存的尺寸, 以字节为单位 * * \return * 分配的内存的指针 */ void * (* m_pfnAlloc)(u32 size); /*! * \brief 是m_pfnAlloc的派对, 用于释放由m_pfnAlloc分配的内存, 其参数一定是由m_pfnAlloc所返回的值. * * \param pVoid --[in][out] 调用m_pfnAlloc分配的内存 */ void (* m_pfnDeAlloc)(void * pVoid); /*! * \brief 当哈希表中的一行空间不够时, 需要增加空间, * 由于是内部私有函数, 因此在调用时, 内部代码必须保证参数的正确性. * * \param pEntry -- 哈希表中的一行. * * \retval true -- 成功 * \retval false -- 失败 * * \note * 在函数实现中使用倍增式的分配内存 */ bool increaseSynonyms(PTABLEENTRY_t pEntry) { // 倍增式地分配内存 u32 count = pEntry->cntAllocItems; if(0 == count) count = 2; else count = count * 2; // 首先分配目的尺寸的哈希项数组--同义词数组 PITEM_t pItems = NULL; if(m_pfnAlloc && m_pfnDeAlloc) pItems = (PITEM_t) (*m_pfnAlloc)(count * (u32)sizeof(ITEM_t)); else pItems = (PITEM_t) new u_8[count * sizeof(ITEM_t)]; if(NULL != pItems) memset((void *)pItems, 0, count * sizeof(ITEM_t)); else return false; // 拷贝, 此处显然两块内存不会重叠, 所以使用memcpy内存拷贝, 而不是memmove memcpy((void *)pItems, (void *)pEntry->pItems, pEntry->cntItems * sizeof(ITEM_t)); if(m_pfnAlloc && m_pfnDeAlloc) { (*m_pfnDeAlloc)(pEntry->pItems); pEntry->pItems = NULL; } else { delete pEntry->pItems; pEntry->pItems = NULL; } pEntry->pItems = pItems; pEntry->cntAllocItems = count; return true; } /*! * \brief 将一个元素插入到指定的"行", 由于是内部私有函数, 因此在调用时, 内部代码必须保证参数的正确性. * * \param pEntry --[in] 哈希表中的一行 * \param pT --[in] 欲插入的数据项 * \param pvTKey --[in] 欲插入的数据项的键值. * * \retval true -- 成功 * \retval false -- 失败 * * \note * 如果返回失败, 则原同义词数组不发生任何变化. */ bool insertIntoEntry(PTABLEENTRY_t pEntry, T * pT, void * pvTKey) { if(NULL == pEntry->pT) { pEntry->pT = pT; pEntry->pvTKey = pvTKey; return true; } if(pEntry->cntItems == pEntry->cntAllocItems) { if(false == increaseSynonyms(pEntry)) return false; } u32 count = pEntry->cntItems; pEntry->pItems[count].pT = pT; pEntry->pItems[count].pvTKey = pvTKey; pEntry->cntItems++; return true; } public: /*! * \brief 返回哈希表的尺寸 */ u32 hash_size() { return m_uiSize; } /*! * \brief 返回在哈希表中保存的数据项的个数 */ u32 count() { u32 count; PTABLEENTRY_t pEntry = NULL; for(int i = 0; i < m_uiSize; i++) { if(NULL != pEntry->pT) count += 1; if(pEntry->cntItems > 0 && NULL != pEntry->pItems) count += pEntry->cntItems + 1; } return count; } /*! * \brief 搜索指定关键字的哈希元素, 返回第一个搜索到的元素, 因此, 应该保证没有重复的关键字. * * \param pKey --[in] 数据项的键值 * * \retval 和数据项的键值相对应的数据项 -- 成功 * \retval NULL -- 失败, 或者, 在哈希表中根本就没有这一项 * * \note * 搜索过程不会改变哈希表及哈希表所保存的数据项及数据项的键值,\n * 在函数的实现中使用到使用者提供的函数:\n * pfnKeyOf -- 使用者提供的返回一个哈希项保存的数据项的关键值;\n * pfnCompare -- 比较两个数据项的关键字的大小;\n */ T * searchItem(const void * pKey) { if(NULL == m_pTable || NULL == m_pfnIndexOf || NULL == m_pfnCompare) return NULL; /* * 由键值求哈希值. */ u32 u32index = (*m_pfnIndexOf)(pKey, m_uiSize); if(u32index >= m_uiSize) return NULL; // 找到同义词数组 PTABLEENTRY_t pEntry = &m_pTable[u32index]; if(NULL != pEntry->pT && 0 == (*m_pfnCompare)(pKey, pEntry->pvTKey)) return pEntry->pT; // 查看首项是否符合. u32 count = pEntry->cntItems; PITEM_t pSynonyms = pEntry->pItems; if(0 == count || NULL == pSynonyms) return NULL; // 在同义词数组中作线性搜索 for(u32 i = 0; i < count; i++) { if(pSynonyms[i].pT) { if(0 == (*m_pfnCompare)(pKey, pSynonyms[i].pvTKey)) return pSynonyms[i].pT; } } return NULL; } /*! * \brief 如果原先的哈希表的尺寸比较小, 后来需要其管理的数据项急剧增加, * 这样会造成冲突严重, 后果是影响到查询的效率, 因此, 需要能够动态 * 的改变哈希表的尺寸 * * \param size --[in] 新的哈希表尺寸 * * \retval true -- 成功 * \retval false -- 失败 * * \note * 如果调用失败, 函数保证原哈希表不发生任何变化.\n * 在函数实现中使用了使用者提供的函数, \n * pfnIndexOf -- 使用者提供的从键值到哈希值的转换函数. */ bool resize(u32 size) { if(size == m_uiSize || NULL == m_pfnIndexOf) return true; // 设置新的尺寸 u32 u32Size = size; if(u32Size > CONST_CHAIN_HASH_DEFAULT_MAX_SIZE) u32Size = CONST_CHAIN_HASH_DEFAULT_MAX_SIZE; if(u32Size < CONST_CHAIN_HASH_DEFAULT_MIN_SIZE) u32Size = CONST_CHAIN_HASH_DEFAULT_MIN_SIZE; // 分配哈希表 PTABLEENTRY_t pTable = NULL; if(m_pfnAlloc && m_pfnDeAlloc) pTable = (PTABLEENTRY_t) (*m_pfnAlloc)(sizeof(TABLEENTRY_t) * size); else pTable = (PTABLEENTRY_t) new unsigned char[sizeof(TABLEENTRY_t) * size]; if(NULL == pTable) return false; memset((void *)pTable, 0, sizeof(TABLEENTRY_t) * size); // 把原哈希表中的元素逐个插入到新的哈希表中去 u32 u32Index = 0; PITEM_t pSynonyms = NULL; u32 i = 0, j = 0; for(i = 0; i < m_uiSize; i++) { if(NULL != m_pTable[i].pT) { u32Index = (*m_pfnIndexOf)(m_pTable[i].pvTKey, u32Size); if(u32Index >= u32Size) goto label_failed_resize; if(!insertIntoEntry(&pTable[u32Index], m_pTable[i].pT, m_pTable[i].pvTKey)) goto label_failed_resize; } pSynonyms = m_pTable[i].pItems; for(j = 0; j < m_pTable[i].cntItems; j++) { if(NULL != pSynonyms[j].pT) { u32Index = (*m_pfnIndexOf)(pSynonyms[j].pvTKey, u32Size); if(u32Index >= u32Size) goto label_failed_resize; if(false == insertIntoEntry(&pTable[u32Index], pSynonyms[j].pT, pSynonyms[j].pvTKey)) goto label_failed_resize; } } } // 释放原哈希表所扎内存 for(i = 0; i < m_uiSize; i++) { if(NULL != m_pTable[i].pItems) { if(m_pfnAlloc && m_pfnDeAlloc) { (*m_pfnDeAlloc)(m_pTable[i].pItems); m_pTable[i].pItems = NULL; } else { delete m_pTable[i].pItems; m_pTable[i].pItems = NULL; } } } if(m_pfnAlloc && m_pfnDeAlloc) { (*m_pfnDeAlloc)(m_pTable); m_pTable = NULL; } else { delete m_pTable; m_pTable = NULL; } // 置换新的哈希表及尺寸 m_pTable = pTable; m_uiSize = u32Size; return true; // 如果执行失败, 则释放执行过程中分配的内存 label_failed_resize: for(i = 0; i < u32Size; i++) { if(NULL != pTable[i].pItems) { if(m_pfnAlloc && m_pfnDeAlloc) { (*m_pfnDeAlloc)(pTable[i].pItems); pTable[i].pItems = NULL; } else { delete pTable[i].pItems; pTable[i].pItems = NULL; } } } if(m_pfnAlloc && m_pfnDeAlloc) { (*m_pfnDeAlloc)(pTable); pTable = NULL; } else { delete pTable; pTable = NULL; } return false; } /*! * \brief 插入一个哈希表项 * * \param pT --[in] 欲插入的数据项 * * \retval true -- 成功 * \retval false -- 失败 * * \note * 在失败的情况下, 函数实现保证原哈希表不发生任何变化.\n * 在函数实现中使用了使用者提供的函数\n * pfnIndexOf -- 使用者提供的从键值到哈希值的转换函数\n * pfnKeyOf -- 使用者提供的返回一个哈希项保存的数据项的关键值. */ bool insertItem(T * pT) { if(NULL == pT || NULL == m_pTable || NULL == m_pfnKeyOf || NULL == m_pfnIndexOf) return false; // 求关键字及哈希值 void * pKey = (*m_pfnKeyOf)(pT); u32 index = (*m_pfnIndexOf)(pKey, m_uiSize); if(index >= m_uiSize) return false; PTABLEENTRY_t pEntry = &m_pTable[index]; if(NULL == pEntry->pT) { pEntry->pT = pT; pEntry->pvTKey = pKey; return true; } // 插入到同义词数组中去 if(pEntry->cntItems == pEntry->cntAllocItems) { if(false == this->increaseSynonyms(pEntry)) return false; } PITEM_t pSynonyms = pEntry->pItems; u32 count = pEntry->cntItems; pSynonyms[count].pT = pT; pSynonyms[count].pvTKey = pKey; pEntry->cntItems++; return true; } /*! * \brief 删除一个哈希表项 * * \param pT --[in] 数据项 * * \retval true -- 成功地删除了指定地数据项 * \retval false -- 失败, 或者, 哈希表中没有指定的数据项 * * \note * 在返回false的情况下, 函数实现保证原哈希表不发生任何变化\n * 在函数实现中使用了使用者提供的函数\n * pfnIndexOf -- 使用者提供的从键值到哈希值的转换函数\n * pfnKeyOf -- 使用者提供的返回一个哈希项保存的数据项的关键值. \n * pfnCompare -- 比较两个数据项的关键字的大小\n * pfnFreeItem-- 使用者提供的用户释放由pfnAlloc所分配的内存的函数 */ bool deleteItem(T * pT) { if(NULL == pT || NULL == m_pTable || NULL == m_pfnKeyOf || NULL == m_pfnIndexOf || NULL == m_pfnCompare || NULL == m_pfnFreeItem) return false; void * pKey = (*m_pfnKeyOf)(pT); return deleteItem_with_key(pKey); } /*! * \brief 删除一个哈希表项 * * \param pKey --[in] 欲被删除的数据项的键值 * * \retval true -- 成功地删除了指定地数据项 * \retval false -- 失败, 或者, 哈希表中没有指定的数据项 * * \note * 在返回false的情况下, 函数实现保证原哈希表不发生任何变化\n * 在函数实现中使用了使用者提供的函数\n * pfnIndexOf -- 使用者提供的从键值到哈希值的转换函数\n * pfnCompare -- 比较两个数据项的关键字的大小\n * pfnFreeItem -- 使用者提供的用户释放由pfnAlloc所分配的内存的函数 */ bool deleteItem_with_key(void * pKey) { u32 i = 0; if(NULL == m_pTable || NULL == m_pfnIndexOf || NULL == m_pfnCompare || NULL == m_pfnFreeItem) return false; // 求哈希值 u32 index = (*m_pfnIndexOf)(pKey, m_uiSize); if(index >= m_uiSize) return false; PTABLEENTRY_t pEntry = &m_pTable[index]; if(NULL != pEntry->pT && 0 == (*m_pfnCompare)(pKey, pEntry->pvTKey)) { (*m_pfnFreeItem)(pEntry->pT); pEntry->pT = NULL; pEntry->pvTKey = NULL; return true; } if(0 == pEntry->cntItems || NULL == pEntry->pItems) return false; u32 count = pEntry->cntItems; PITEM_t pSynonyms = pEntry->pItems; for(i = 0; i < count; i++) { if(NULL == pSynonyms[i].pT) continue; if(0 == (*m_pfnCompare)(pKey, pSynonyms[i].pvTKey)) { (*m_pfnFreeItem)(pSynonyms[i].pT); pSynonyms[i].pT = NULL; pSynonyms[i].pvTKey = NULL; memmove((void *)(pSynonyms + i), (void *)(pSynonyms + i + 1), sizeof(*pSynonyms) * (count - i - 1)); memset((void *)(pSynonyms + count - 1), 0, sizeof(*pSynonyms)); pEntry->cntItems -= 1; break; } } if(i == count) return false; else return true; } /*! * \brief 从哈希表中分离出一个指定的哈希表项 * * \param pT --[in] 欲被从哈希表中分离出来的数据项 * * \retval 分离出来的数据项 -- 成功 * \retval NULL -- 失败, 或者, 哈希表中根本就没有欲分离的数据项 * * \note * 在函数执行成功的情况下, 该数据项从哈希表中移出.\n * 在返回NULL的情况下, 函数实现保证原哈希表不发生任何变化\n * 在函数实现中使用了使用者提供的函数\n * pfnIndexOf -- 使用者提供的从键值到哈希值的转换函数\n * pfnKeyOf -- 使用者提供的返回一个哈希项保存的数据项的关键值. \n * pfnCompare -- 比较两个数据项的关键字的大小\n */ T * detachItem(T * pT) { if(NULL == pT || NULL == m_pfnKeyOf || NULL == m_pfnIndexOf || NULL == m_pfnCompare) return NULL; void * pKey = (*m_pfnKeyOf)(pT); return detachItem_with_key(pKey); } /*! * \brief 从哈希表中分离出一个指定的哈希表项 * * \param pKey --[in] 欲被从哈希表中分离出来的数据项的键值 * * \retval 分离出来的数据项 -- 成功 * \retval NULL -- 失败, 或者, 哈希表中根本就没有欲分离的数据项 * * \note * 在函数执行成功的情况下, 该数据项从哈希表中移出.\n * 在返回NULL的情况下, 函数实现保证原哈希表不发生任何变化\n * 在函数实现中使用了使用者提供的函数\n * pfnIndexOf -- 使用者提供的从键值到哈希值的转换函数\n * pfnCompare -- 比较两个数据项的关键字的大小\n */ T * detachItem_with_key(void * pKey) { if(NULL == m_pTable || NULL == m_pfnIndexOf || NULL == m_pfnCompare) return NULL; u32 index = (*m_pfnIndexOf)(pKey, m_uiSize); if(index >= m_uiSize) return NULL; PTABLEENTRY_t pEntry = &m_pTable[index]; if(NULL != pEntry->pT && 0 == (*m_pfnCompare)(pKey, pEntry->pvTKey)) { T * ptempT = pEntry->pT; pEntry->pT = NULL; pEntry->pvTKey = NULL; return ptempT; } if(0 == pEntry->cntItems || NULL == pEntry->pItems) return NULL; u32 count = pEntry->cntItems; PITEM_t pSynonyms = pEntry->pItems; for(u32 i = 0; i < count; i++) { if(NULL == pSynonyms[i].pT) continue; if(0 == (*m_pfnCompare)(pKey, pSynonyms[i].pvTKey)) { T * ptempT = NULL; ptempT = pSynonyms[i].pT; memmove((void *)(pSynonyms + i), (void *)(pSynonyms + i + 1), sizeof(*pSynonyms) * (count - i - 1)); memset((void *)(pSynonyms + count - 1), 0, sizeof(*pSynonyms)); pEntry->cntItems -= 1; return ptempT; } } return NULL; } /*! * \brief 释放哈希表所管理的所有数据项 * * \note * 在函数实现中使用了使用者提供的函数\n * pfnFreeItem -- 使用者提供的用户释放由pfnAlloc所分配的内存的函数 */ bool deleteItems() { if(NULL == m_pTable) return true; if(m_pfnFreeItem== NULL) return false; PTABLEENTRY_t pEntry = NULL; PITEM_t pSynonyms = NULL; for(u32 i = 0; i < m_uiSize; i++) { pEntry = &m_pTable[i]; if(pEntry->pT) (*m_pfnFreeItem)(pEntry->pT); pEntry->pT = NULL; pEntry->pvTKey = NULL; if(pEntry->cntItems > 0 && NULL != pEntry->pItems) { pSynonyms = pEntry->pItems; for(u32 j = 0; j < pEntry->cntItems; j++) { if(pSynonyms[j].pT) (*m_pfnFreeItem)(pSynonyms[j].pT); pSynonyms[j].pT = NULL; pSynonyms[j].pvTKey = NULL; } } pEntry->cntItems = 0; } return true; } /*! * \brief 分离哈希表所管理的所有数据项 */ void detachItems() { if(NULL == m_pTable) return; PTABLEENTRY_t pEntry = NULL; for(u32 i = 0; i < m_uiSize; i++) { pEntry = &m_pTable[i]; pEntry->pT = NULL; pEntry->pvTKey = NULL; if(pEntry->cntItems > 0 && NULL != pEntry->pItems) memset((void *)pEntry->pItems, 0, sizeof(pEntry->pItems[0]) * pEntry->cntAllocItems); pEntry->cntItems = 0; } } }; // 是pc机系统还是嵌入式系统 #ifdef PC_MACHINE #ifdef OS_WINDOWS #pragma pack (pop) #else// OS_UNIX #pragma pack (0) #endif //OS_UNIX #endif #endif //__CHAIN_HASH_H__ASDFJQWPEUTOUDSAFHJDSAFADSAFWQERUGSKGEWRTPYZNXM