hash.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. * Part of Very Secure FTPd
  3. * Licence: GPL v2
  4. * Author: Chris Evans
  5. * hash.c
  6. *
  7. * Routines to handle simple hash table lookups and modifications.
  8. */
  9. #include "hash.h"
  10. #include "sysutil.h"
  11. #include "utility.h"
  12. struct hash_node
  13. {
  14. void* p_key;
  15. void* p_value;
  16. struct hash_node* p_prev;
  17. struct hash_node* p_next;
  18. };
  19. struct hash
  20. {
  21. unsigned int buckets;
  22. unsigned int key_size;
  23. unsigned int value_size;
  24. hashfunc_t hash_func;
  25. struct hash_node** p_nodes;
  26. };
  27. /* Internal functions */
  28. struct hash_node** hash_get_bucket(struct hash* p_hash, void* p_key);
  29. struct hash_node* hash_get_node_by_key(struct hash* p_hash, void* p_key);
  30. struct hash*
  31. hash_alloc(unsigned int buckets, unsigned int key_size,
  32. unsigned int value_size, hashfunc_t hash_func)
  33. {
  34. unsigned int size;
  35. struct hash* p_hash = vsf_sysutil_malloc(sizeof(*p_hash));
  36. p_hash->buckets = buckets;
  37. p_hash->key_size = key_size;
  38. p_hash->value_size = value_size;
  39. p_hash->hash_func = hash_func;
  40. size = (unsigned int) sizeof(struct hash_node*) * buckets;
  41. p_hash->p_nodes = vsf_sysutil_malloc(size);
  42. vsf_sysutil_memclr(p_hash->p_nodes, size);
  43. return p_hash;
  44. }
  45. void*
  46. hash_lookup_entry(struct hash* p_hash, void* p_key)
  47. {
  48. struct hash_node* p_node = hash_get_node_by_key(p_hash, p_key);
  49. if (!p_node)
  50. {
  51. return p_node;
  52. }
  53. return p_node->p_value;
  54. }
  55. void
  56. hash_add_entry(struct hash* p_hash, void* p_key, void* p_value)
  57. {
  58. struct hash_node** p_bucket;
  59. struct hash_node* p_new_node;
  60. if (hash_lookup_entry(p_hash, p_key))
  61. {
  62. bug("duplicate hash key");
  63. }
  64. p_bucket = hash_get_bucket(p_hash, p_key);
  65. p_new_node = vsf_sysutil_malloc(sizeof(*p_new_node));
  66. p_new_node->p_prev = 0;
  67. p_new_node->p_next = 0;
  68. p_new_node->p_key = vsf_sysutil_malloc(p_hash->key_size);
  69. vsf_sysutil_memcpy(p_new_node->p_key, p_key, p_hash->key_size);
  70. p_new_node->p_value = vsf_sysutil_malloc(p_hash->value_size);
  71. vsf_sysutil_memcpy(p_new_node->p_value, p_value, p_hash->value_size);
  72. if (!*p_bucket)
  73. {
  74. *p_bucket = p_new_node;
  75. }
  76. else
  77. {
  78. p_new_node->p_next = *p_bucket;
  79. (*p_bucket)->p_prev = p_new_node;
  80. *p_bucket = p_new_node;
  81. }
  82. }
  83. void
  84. hash_free_entry(struct hash* p_hash, void* p_key)
  85. {
  86. struct hash_node* p_node = hash_get_node_by_key(p_hash, p_key);
  87. if (!p_node)
  88. {
  89. bug("hash node not found");
  90. }
  91. vsf_sysutil_free(p_node->p_key);
  92. vsf_sysutil_free(p_node->p_value);
  93. if (p_node->p_prev)
  94. {
  95. p_node->p_prev->p_next = p_node->p_next;
  96. }
  97. else
  98. {
  99. struct hash_node** p_bucket = hash_get_bucket(p_hash, p_key);
  100. *p_bucket = p_node->p_next;
  101. }
  102. if (p_node->p_next)
  103. {
  104. p_node->p_next->p_prev = p_node->p_prev;
  105. }
  106. vsf_sysutil_free(p_node);
  107. }
  108. struct hash_node**
  109. hash_get_bucket(struct hash* p_hash, void* p_key)
  110. {
  111. unsigned int bucket = (*p_hash->hash_func)(p_hash->buckets, p_key);
  112. if (bucket >= p_hash->buckets)
  113. {
  114. bug("bad bucket lookup");
  115. }
  116. return &(p_hash->p_nodes[bucket]);
  117. }
  118. struct hash_node*
  119. hash_get_node_by_key(struct hash* p_hash, void* p_key)
  120. {
  121. struct hash_node** p_bucket = hash_get_bucket(p_hash, p_key);
  122. struct hash_node* p_node = *p_bucket;
  123. if (!p_node)
  124. {
  125. return p_node;
  126. }
  127. while (p_node != 0 &&
  128. vsf_sysutil_memcmp(p_key, p_node->p_key, p_hash->key_size) != 0)
  129. {
  130. p_node = p_node->p_next;
  131. }
  132. return p_node;
  133. }