hsearch.c 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <search.h>
  4. /*
  5. open addressing hash table with 2^n table size
  6. quadratic probing is used in case of hash collision
  7. tab indices and hash are size_t
  8. after resize fails with ENOMEM the state of tab is still usable
  9. with the posix api items cannot be iterated and length cannot be queried
  10. */
  11. #define MINSIZE 8
  12. #define MAXSIZE ((size_t)-1/2 + 1)
  13. struct entry {
  14. ENTRY item;
  15. size_t hash;
  16. };
  17. static size_t mask;
  18. static size_t used;
  19. static struct entry *tab;
  20. static size_t keyhash(char *k)
  21. {
  22. unsigned char *p = (void *)k;
  23. size_t h = 0;
  24. while (*p)
  25. h = 31*h + *p++;
  26. return h;
  27. }
  28. static int resize(size_t nel)
  29. {
  30. size_t newsize;
  31. size_t i, j;
  32. struct entry *e, *newe;
  33. struct entry *oldtab = tab;
  34. struct entry *oldend = tab + mask + 1;
  35. if (nel > MAXSIZE)
  36. nel = MAXSIZE;
  37. for (newsize = MINSIZE; newsize < nel; newsize *= 2);
  38. tab = calloc(newsize, sizeof *tab);
  39. if (!tab) {
  40. tab = oldtab;
  41. return 0;
  42. }
  43. mask = newsize - 1;
  44. if (!oldtab)
  45. return 1;
  46. for (e = oldtab; e < oldend; e++)
  47. if (e->item.key) {
  48. for (i=e->hash,j=1; ; i+=j++) {
  49. newe = tab + (i & mask);
  50. if (!newe->item.key)
  51. break;
  52. }
  53. *newe = *e;
  54. }
  55. free(oldtab);
  56. return 1;
  57. }
  58. int hcreate(size_t nel)
  59. {
  60. mask = 0;
  61. used = 0;
  62. tab = 0;
  63. return resize(nel);
  64. }
  65. void hdestroy(void)
  66. {
  67. free(tab);
  68. tab = 0;
  69. mask = 0;
  70. used = 0;
  71. }
  72. static struct entry *lookup(char *key, size_t hash)
  73. {
  74. size_t i, j;
  75. struct entry *e;
  76. for (i=hash,j=1; ; i+=j++) {
  77. e = tab + (i & mask);
  78. if (!e->item.key ||
  79. (e->hash==hash && strcmp(e->item.key, key)==0))
  80. break;
  81. }
  82. return e;
  83. }
  84. ENTRY *hsearch(ENTRY item, ACTION action)
  85. {
  86. size_t hash = keyhash(item.key);
  87. struct entry *e = lookup(item.key, hash);
  88. if (e->item.key)
  89. return &e->item;
  90. if (action == FIND)
  91. return 0;
  92. e->item = item;
  93. e->hash = hash;
  94. if (++used > mask - mask/4) {
  95. if (!resize(2*used)) {
  96. used--;
  97. e->item.key = 0;
  98. return 0;
  99. }
  100. e = lookup(item.key, hash);
  101. }
  102. return &e->item;
  103. }