沉淀之log4c的hash

    上回书说到,log4c的list模块,咱们书接上回,说一说他的hash模块,仍然用以模块代码进行注释的形式进行。
头文件如下:
hash.h:
  1. /* $Id: hash.h,v 1.4 2005/05/24 15:33:18 legoater Exp $
  2. *
  3. * Copyright 2001-2003, Meiosys (www.meiosys.com). All rights reserved.
  4. * Author: Marc Vertes <mvertes@meiosys.com>
  5. * See the COPYING file for the terms of usage and distribution.
  6. */
  7. #ifndef __sd_hash_h
  8. #define __sd_hash_h
  9. /**
  10. * @file hash.h
  11. *
  12. * @brief Generic hash table. It is implemented as an array of doubly-linked
  13. * lists of iterators. The index within the array is computed by a efficient
  14. * hash function.
  15. */
  16. #include <stddef.h>
  17. #include <sd/defs.h>
  18. __SD_BEGIN_DECLS
  19. struct __sd_hash_ops {
  20. unsigned int (*hash) (const void*);
  21. int (*compare) (const void*, const void*);
  22. void* (*key_dup) (const void*);
  23. void (*key_free) (void*);
  24. void* (*data_dup) (const void*);
  25. void (*data_free) (void*);
  26. };
  27. /**
  28. * 这个结构体保存hash表的操作信息
  29. */
  30. typedef struct __sd_hash_ops sd_hash_ops_t;
  31. /**
  32. * hash表的结构体类型
  33. */
  34. typedef struct __sd_hash sd_hash_t;
  35. struct __sd_hash_iter {
  36. void* key;
  37. void* data;
  38. struct __sd_hash* hash;
  39. unsigned int __hkey;
  40. struct __sd_hash_iter* __next;
  41. struct __sd_hash_iter* __prev;
  42. int __foreach;
  43. };
  44. /**
  45. * hash表元素的容器,用来存放用户数据
  46. */
  47. typedef struct __sd_hash_iter sd_hash_iter_t;
  48. /**
  49. * 遍历的回调函数类型
  50. */
  51. typedef unsigned int (*sd_hash_func_t)(void* a_key, void* a_data,
  52. void* a_userdata);
  53. /**
  54. * 新建一个hash表,用户可以指定内存的分配方式以及key值计算和数据存储方式
  55. * @param a_size 初始化数组的大小
  56. * @param a_ops hash操作函数,如果是NULL,默认字符串key值算法,另外没有为
  57. * key值计算和用户数据存储方式
  58. * @return hash表结构
  59. */
  60. extern sd_hash_t* sd_hash_new(size_t a_size, const sd_hash_ops_t* a_ops);
  61. /**
  62. * 销毁一个hash表
  63. */
  64. extern void sd_hash_delete(sd_hash_t* a_this);
  65. /**
  66. * 清空一个hash表
  67. */
  68. extern void sd_hash_clear(sd_hash_t* a_this);
  69. /**
  70. * 根据key值在hash表里查找元素容器
  71. * @param a_key key值
  72. * @return 指向找到的结构体地址或者NULL
  73. */
  74. extern sd_hash_iter_t* sd_hash_lookup(sd_hash_t* a_this, const void* a_key);
  75. /**
  76. * 根据key值在hash表里查找元素容器,如果不存在就新建一个。
  77. * @param a_key 与待查找容器相关联的key值
  78. * @return 返回查找到的容器或者NULL.
  79. */
  80. extern sd_hash_iter_t* sd_hash_lookadd(sd_hash_t* a_this, const void* a_key);
  81. /**
  82. * 通过给定的数据key值添加用户数据到hash表,如果已经存在那么就通过hash操作中的
  83. * 释放接口进行释放之前的,并将当前数据插入
  84. * @param a_key 容器的键值key值
  85. * @param a_data 数据
  86. * @return 返回指向数据容器的指针.
  87. */
  88. extern sd_hash_iter_t* sd_hash_add(sd_hash_t* a_this, const void* a_key,
  89. void* a_data);
  90. /**
  91. * 从hash表中移除一个容器
  92. * @param 容器的key值
  93. */
  94. extern void sd_hash_del(sd_hash_t* a_this, const void* a_key);
  95. /**
  96. * 调用回调函数a_fun遍历整个hash,直到该回调返回非0
  97. * @param a_func 回调函数
  98. * @param a_data 用户数据传如到a_func
  99. */
  100. extern void sd_hash_foreach(sd_hash_t* a_this, sd_hash_func_t a_func,
  101. void* a_data);
  102. /**
  103. * 获得hash表中所有的容器个数
  104. */
  105. extern unsigned int sd_hash_get_nelem(sd_hash_t* a_this);
  106. /**
  107. * 获得hash表的大小
  108. */
  109. extern unsigned int sd_hash_get_size(sd_hash_t* a_this);
  110. /**
  111. * 获取hash表的第一个元素容器
  112. */
  113. extern sd_hash_iter_t* sd_hash_begin(sd_hash_t* a_this);
  114. /**
  115. * 获取hash表的最后一个元素容器
  116. */
  117. extern sd_hash_iter_t* sd_hash_end(sd_hash_t* a_this);
  118. /**
  119. * 获取当前容器的下一个容器
  120. */
  121. extern sd_hash_iter_t* sd_hash_iter_next(sd_hash_iter_t* a_this);
  122. /**
  123. * 获取当前容器的上一个容器
  124. */
  125. extern sd_hash_iter_t* sd_hash_iter_prev(sd_hash_iter_t* a_this);
  126. /**
  127. * 删除一个容器,根据容器地址
  128. */
  129. extern void sd_hash_iter_del(sd_hash_iter_t* a_this);
  130. /**
  131. * Hashes strings.计算key值
  132. */
  133. extern unsigned int sd_hash_hash_string(const char* a_string);
  134. __SD_END_DECLS
  135. #endif
    头文件里面定义了hash操作的结构体,hash表元素容器的结构体,以及hash表的类型,其中hash表的类型是在hash.c中进行定义的,这样很好的屏蔽了hash结构。
    对于hash表的结构体定义如下:
  1. #define SD_HASH_FULLTAB 2 /* rehash when table gets this x full */
  2. #define SD_HASH_GROWTAB 4 /* grow table by this factor */
  3. #define SD_HASH_DEFAULT_SIZE 10 /* self explenatory */
  4. struct __sd_hash {
  5. size_t nelem; //hash表中元素个数
  6. size_t size; //hash大小
  7. sd_hash_iter_t** tab; //元素容器的表
  8. const sd_hash_ops_t* ops; //hash操作
  9. };
  10. #define hindex(h, n) ((h)%(n)) //计算hashkey

通过以上各个结构体的定义可以先给出整个hash表的总体结构,然后后续参考sd_hash_new进一步进行理解。

图一:hash结构图

具体代码以及分析如下:
sd_hash_new:
  1. /******************************************************************************/
  2. //创建一个hash表
  3. //a_size hash表能够容纳元素的数量
  4. //a_ops hash操作集合
  5. extern sd_hash_t* sd_hash_new(size_t a_size, const sd_hash_ops_t* a_ops)
  6. {
  7. //一个默认的hash操作集合、hash值计算,比较等
  8. const static sd_hash_ops_t default_ops = {
  9. (void*) &sd_hash_hash_string,
  10. (void*) &strcmp,
  11. 0, 0, 0, 0
  12. };
  13. //分配hash表和容器表内存并进行检查
  14. sd_hash_t* hash;
  15. sd_hash_iter_t** tab;
  16. if (a_size == 0) a_size = SD_HASH_DEFAULT_SIZE;
  17. hash = sd_calloc(1, sizeof(*hash));
  18. tab = sd_calloc(a_size, sizeof(*tab));
  19. if (hash == 0 || tab == 0) {
  20. free(hash);
  21. free(tab);
  22. return 0;
  23. }
  24. //初始化元素个数,大小,容器表地址以及操作集合
  25. hash->nelem = 0;
  26. hash->size = a_size;
  27. hash->tab = tab;
  28. hash->ops = a_ops != 0 ? a_ops : &default_ops;
  29. return hash;
  30. }

sd_hash_delete:
  1. /******************************************************************************/
  2. //销毁一个hash表,先将hash表清空,然后将hash进行回收
  3. //a_this 待清空的hash表
  4. extern void sd_hash_delete(sd_hash_t* a_this)
  5. {
  6. //将hash表中的元素进行清空
  7. sd_hash_clear(a_this);
  8. //释放hash的容器表和hash表
  9. free(a_this->tab);
  10. free(a_this);
  11. }

sd_hash_clear:
  1. /******************************************************************************/
  2. //清空一个hash表中的元素
  3. //a_this 待清空的hash表
  4. extern void sd_hash_clear(sd_hash_t* a_this)
  5. {
  6. size_t h;
  7. sd_hash_iter_t* p;
  8. sd_hash_iter_t* q;
  9. if (a_this == 0) return;
  10. //遍历一个hash的所有容器指针的下挂的所有容器,进行释放
  11. for (h = 0; h < a_this->size; h++) {
  12. for (p = a_this->tab[h]; p; p = q) {
  13. q = p->__next;
  14. if (a_this->ops->key_free) a_this->ops->key_free(p->key);
  15. if (a_this->ops->data_free) a_this->ops->data_free(p->data);
  16. free(p);
  17. }
  18. a_this->tab[h] = 0;
  19. }
  20. a_this->nelem = 0;
  21. }

sd_hash_lookup:
  1. /**
  2. * 根据key值在hash表里查找元素容器
  3. * @param a_key key值
  4. * @return 指向找到的结构体地址或者NULL
  5. */
  6. extern sd_hash_iter_t* sd_hash_lookup(sd_hash_t* a_this, const void* a_key)
  7. {
  8. int h;
  9. sd_hash_iter_t* p;
  10. //参数判断
  11. if (a_this == 0 || a_key == 0) return 0;
  12. //计算hash值
  13. h = hindex(a_this->ops->hash(a_key), a_this->size);
  14. //遍历该hash值所对应的容器指针下挂的所有容器并进行比较验证
  15. for (p = a_this->tab[h]; p != 0; p = p->__next)
  16. if (a_this->ops->compare(a_key, p->key) == 0) {
  17. return p;
  18. }
  19. return 0;
  20. }

sd_hash_lookadd:
  1. /**
  2. * 根据key值在hash表里查找元素容器,如果不存在就新建一个。
  3. * @param a_key 与待查找容器相关联的key值
  4. * @return 返回查找到的容器或者NULL.
  5. */
  6. extern sd_hash_iter_t* sd_hash_lookadd(sd_hash_t* a_this, const void* a_key)
  7. {
  8. int h;
  9. sd_hash_iter_t* p;
  10. if (a_this == 0 || a_key == 0) return 0;
  11. //先查找一遍,已经存在就进行返回,否则就分配空间然后进行初始化
  12. if ((p = sd_hash_lookup(a_this, a_key)) != 0) return p;
  13. if ((p = sd_calloc(1, sizeof(*p))) == 0) return 0;
  14. //如果有复制数据功能那么就复制一份否则就用原始数据
  15. if (a_this->ops->key_dup != 0)
  16. p->key = a_this->ops->key_dup(a_key);
  17. else
  18. p->key = (void*) a_key;
  19. //初始化容器一些参数
  20. p->hash = a_this;
  21. p->__hkey = a_this->ops->hash(a_key);
  22. //如果超过当前hash最大容量那么就进行扩张
  23. if (a_this->nelem > SD_HASH_FULLTAB * a_this->size) rehash(a_this);
  24. h = hindex(p->__hkey,
  25. a_this->size);
  26. //将当前容器挂到对应key值的容器指针下挂链表中。
  27. p->__next = a_this->tab[h];
  28. a_this->tab[h] = p;
  29. if (p->__next != 0) p->__next->__prev = p;
  30. //计数
  31. a_this->nelem++;
  32. return p;
  33. }

sd_hash_add:
  1. /**
  2. * 通过给定的数据key值添加用户数据到hash表,如果已经存在那么就通过hash操作中的
  3. * 释放接口进行释放之前的,并将当前数据插入
  4. * @param a_key 容器的键值key值
  5. * @param a_data 数据
  6. * @return 返回指向数据容器的指针.
  7. */
  8. extern sd_hash_iter_t* sd_hash_add(sd_hash_t* a_this, const void* a_key,
  9. void* a_data)
  10. {
  11. sd_hash_iter_t* p;
  12. //调用lookadd进行插入
  13. if ((p = sd_hash_lookadd(a_this, a_key)) == 0) return 0;
  14. //如果这个值已经存在,那么就释放了然后重新进行赋值当前值
  15. if (a_this->ops->data_free != 0) a_this->ops->data_free(p->data);
  16. //判断释放需要进行备份并进行赋值
  17. if (a_this->ops->data_dup != 0)
  18. p->data = a_this->ops->data_dup(a_data);
  19. else
  20. p->data = a_data;
  21. return p;
  22. }

sd_hash_del:
  1. /**
  2. * 从hash表中移除一个容器
  3. * @param 容器的key值
  4. */
  5. extern void sd_hash_del(sd_hash_t* a_this, const void* a_key)
  6. {
  7. int h;
  8. sd_hash_iter_t* p;
  9. //定位容器的容器指针
  10. h = hindex(a_this->ops->hash(a_key), a_this->size);
  11. //循环遍历容器指针下挂的链表找到待删除容器进行删除
  12. for (p = a_this->tab[h]; p != 0; p = p->__next)
  13. if (a_this->ops->compare(a_key, p->key) == 0) break;
  14. if (p == 0) return;
  15. //进行删除
  16. sd_hash_iter_del(p);
  17. }

sd_hash_foreach:
  1. /**
  2. * 调用回调函数a_fun遍历整个hash,直到该回调返回非0
  3. * @param a_func 回调函数
  4. * @param a_data 用户数据传如到a_func
  5. */
  6. extern void sd_hash_foreach(sd_hash_t* a_this, sd_hash_func_t a_func,
  7. void* a_data)
  8. {
  9. size_t h, ret;
  10. sd_hash_iter_t* p;
  11. sd_hash_iter_t* q;
  12. //参数验证
  13. if (a_this == 0 || a_func == 0) return;
  14. //定位容器指针,找到容器
  15. for (h = 0; h < a_this->size; h++)
  16. for (p = a_this->tab[h]; p != 0; p = q) {
  17. p->__foreach = 1;
  18. //调用遍历回调函数进行操作
  19. ret = (*a_func)(p->key, p->data, a_data);
  20. q = p->__next;
  21. //删除重复表项
  22. if (p->__foreach == 0)
  23. sd_hash_iter_del(p);
  24. else
  25. p->__foreach = 0;
  26. if (ret != 0) return;
  27. }
  28. }

sd_hash_get_nelem:
  1. /**
  2. * 获得hash表中所有的容器个数
  3. */
  4. extern unsigned int sd_hash_get_nelem(sd_hash_t* a_this)
  5. {
  6. if (a_this == 0) return 0;
  7. return a_this->nelem;
  8. }

sd_hash_get_size:
  1. /**
  2. * 获得hash表的大小
  3. */
  4. extern unsigned int sd_hash_get_size(sd_hash_t* a_this)
  5. {
  6. if (a_this == 0) return 0;
  7. return a_this->size;
  8. }

sd_hash_begin:
  1. /**
  2. * 获取hash表的第一个元素容器
  3. */
  4. extern sd_hash_iter_t* sd_hash_begin(sd_hash_t* a_this)
  5. {
  6. size_t h;
  7. if (a_this == 0) return 0;
  8. for (h = 0; h < a_this->size; h++)
  9. if (a_this->tab[h])
  10. return a_this->tab[h];
  11. return 0;
  12. }

sd_hash_end:未实现
  1. /**
  2. * 获取hash表的最后一个元素容器
  3. */
  4. extern sd_hash_iter_t* sd_hash_end(sd_hash_t* a_this)
  5. {
  6. return 0;
  7. }

sd_hash_iter_next:
  1. /**
  2. * 获取当前容器的下一个容器
  3. */
  4. extern sd_hash_iter_t* sd_hash_iter_next(sd_hash_iter_t* a_this)
  5. {
  6. int h;
  7. size_t i;
  8. //参数检查并进行链表递进后返回
  9. if (a_this == 0) return 0;
  10. if (a_this->__next != 0) return a_this->__next;
  11. //如果当前容器就是其容器指针的最后一个,那么要寻找到下一个容器指针的
  12. //第一个容器进行返回
  13. h = hindex(a_this->__hkey, a_this->hash->size);
  14. for (i = h + 1; i < a_this->hash->size; i++)
  15. if (a_this->hash->tab[i])
  16. return a_this->hash->tab[i];
  17. return 0;
  18. }

sd_hash_iter_prev:
  1. /**
  2. * 获取当前容器的上一个容器
  3. */
  4. extern sd_hash_iter_t* sd_hash_iter_prev(sd_hash_iter_t* a_this)
  5. {
  6. int h, i;
  7. sd_hash_iter_t* p;
  8. //参数验证,然后如果在当前容器指针的链表下存在前一个指针那么进行返回
  9. if (a_this == 0) return 0;
  10. if (a_this->__prev != 0) return a_this->__prev;
  11. //如果当前容器就是该链表下的第一个,那么返回前一个容器指针的第一个有效容器
  12. h = hindex(a_this->__hkey, a_this->hash->size);
  13. for (i = h - 1; i > 0; i--)
  14. for (p = a_this->hash->tab[i]; p; p = p->__next)
  15. if (p->__next == 0)
  16. return p;
  17. return 0;
  18. }

sd_hash_iter_del:
  1. /**
  2. * 删除一个容器,根据容器地址
  3. */
  4. extern void sd_hash_iter_del(sd_hash_iter_t* a_this)
  5. {
  6. if (a_this == 0) return;
  7. //释放容器存放的数据
  8. if (a_this->hash->ops->data_free != 0)
  9. a_this->hash->ops->data_free(a_this->data);
  10. a_this->data = 0;
  11. //释放容器的key值内存
  12. if (a_this->hash->ops->key_free != 0)
  13. a_this->hash->ops->key_free(a_this->key);
  14. a_this->key = 0;
  15. //已经删除的即不再进行遍历了。
  16. if (a_this->__foreach == 1) {
  17. a_this->__foreach = 0;
  18. return;
  19. }
  20. //从链表中摘除
  21. if (a_this->__next != 0) a_this->__next->__prev = a_this->__prev;
  22. if (a_this->__prev != 0)
  23. a_this->__prev->__next = a_this->__next;
  24. else
  25. a_this->hash->tab[hindex(a_this->__hkey, a_this->hash->size)] =
  26. a_this->__next;
  27. //减一数目
  28. a_this->hash->nelem--;
  29. //释放
  30. free(a_this);
  31. }

sd_hash_hash_string:
  1. /**
  2. * Hashes strings.计算key值
  3. */
  4. extern unsigned int sd_hash_hash_string(const char* a_string)
  5. {
  6. register unsigned int h;
  7. //一个hash计算方法
  8. for (h = 0; *a_string != '\0'; a_string++)
  9. h = *a_string + 31 * h;
  10. return h;
  11. }

一个示例程序
main.c
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "stack.h"
  5. #include "hash.h"
  6. #include "list.h"
  7. typedef struct test
  8. {
  9. char a[20];
  10. int b;
  11. int c;
  12. }test_t;
  13. static unsigned int print(void *data, void *p)
  14. {
  15. test_t *t = (test_t *)data;
  16. printf("a:%s b:%d c:%d\n",t->a, t->b, t->c);
  17. return 0;
  18. }
  19. unsigned int print_hash(void *a_key, void *a_data, void *a_userdata)
  20. {
  21. print(a_data, NULL);
  22. return 0;
  23. }
  24. int main()
  25. {
  26. sd_hash_ops_t ops = {
  27. (void*) &sd_hash_hash_string,
  28. (void*) &strcmp,
  29. 0, 0, 0, free
  30. };
  31. sd_hash_t*hash = sd_hash_new(20, &ops);
  32. test_t *fir = malloc(sizeof(test_t));
  33. strcpy(fir->a,"zhang");
  34. fir->b = 10;
  35. fir->c = 20;
  36. sd_hash_add(hash, fir->a,fir);
  37. test_t *sec = malloc(sizeof(test_t));
  38. strcpy(sec->a,"wang");
  39. sec->b = 20;
  40. sec->c = 30;
  41. sd_hash_add(hash, sec->a,sec);
  42. test_t *third = malloc(sizeof(test_t));
  43. strcpy(third->a,"zhongguo");
  44. third->b = 30;
  45. third->c = 40;
  46. sd_hash_iter_t *iter = sd_hash_lookadd(hash, "zhongguo");
  47. iter->data = third;
  48. int cnt = sd_hash_get_nelem(hash);
  49. printf("hash items is : %d\n",cnt);
  50. sd_hash_foreach(hash, print_hash, NULL);
  51. sd_hash_clear(hash);
  52. sd_hash_delete(hash);
  53. return 0;
  54. }








posted on 2017-08-28 11:35  cfzhang  阅读(200)  评论(0编辑  收藏  举报

导航