htable.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #include "htable.h"
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #define HTFL_NUL 0
  5. #define HTFL_VAL 1
  6. #define HTFL_DEL 2
  7. static void* htable_end(HTable *ht) {
  8. return ht->buf + ht->cap * (ht->elemsz + 1);
  9. }
  10. static void rebuild(HTable *ht) {
  11. HTable newht;
  12. htable_init(&newht, ht->elemsz, ht->size * 6, ht->hash, ht->eq);
  13. void *iter = htable_begin(ht);
  14. while (iter != NULL) {
  15. htable_insert(&newht, iter);
  16. iter = htable_next(ht, iter);
  17. }
  18. free(ht->buf);
  19. *ht = newht;
  20. }
  21. static uint8_t getflag(void *iter) {
  22. return *(uint8_t*)(iter - 1);
  23. }
  24. static void setflag(void *iter, uint8_t flag) {
  25. *(uint8_t *)(iter - 1) = flag;
  26. }
  27. void htable_init(HTable *ht, int elemsz, int cap, uint32_t (*hash)(void*),
  28. bool (*eq)(void*, void*)) {
  29. if (cap < 16) cap = 16;
  30. ht->buf = malloc(cap * (elemsz + 1));
  31. memset(ht->buf, 0, cap * (elemsz + 1));
  32. ht->size = 0;
  33. ht->cap = cap;
  34. ht->taken = 0;
  35. ht->begin = NULL;
  36. ht->elemsz = elemsz;
  37. ht->hash = hash;
  38. ht->eq = eq;
  39. }
  40. bool htable_insert(HTable *ht, void* elem) {
  41. if (ht->taken + 1 > ht->cap / 2) {
  42. rebuild(ht);
  43. }
  44. ht->taken++;
  45. ht->size++;
  46. int hashcode = ht->hash(elem) % ht->cap;
  47. void *pos = ht->buf + hashcode * (ht->elemsz + 1) + 1;
  48. while (getflag(pos) != HTFL_NUL) {
  49. if (getflag(pos) == HTFL_VAL && ht->eq(pos, elem)) return false;
  50. pos += ht->elemsz + 1;
  51. if (pos >= htable_end(ht)) { // arrived end, restart from beginning
  52. pos = ht->buf + 1;
  53. }
  54. }
  55. memcpy(pos, elem, ht->elemsz);
  56. setflag(pos, HTFL_VAL);
  57. if (pos < ht->begin || ht->begin == NULL) {
  58. ht->begin = pos;
  59. }
  60. return true;
  61. }
  62. void htable_del(HTable *ht, void* iter) {
  63. ht->size--;
  64. setflag(iter, HTFL_DEL);
  65. if (iter == ht->begin) {
  66. ht->begin = htable_next(ht, iter);
  67. }
  68. }
  69. void* htable_find(HTable *ht, void* elem) {
  70. int hashcode = ht->hash(elem) % ht->cap;
  71. void *pos = ht->buf + hashcode * (ht->elemsz + 1) + 1;
  72. while (getflag(pos) != HTFL_NUL) {
  73. if (getflag(pos) == HTFL_VAL && ht->eq(pos, elem)) return pos;
  74. pos += ht->elemsz + 1;
  75. if (pos >= htable_end(ht)) { // arrived end, restart from beginning
  76. pos = ht->buf + 1;
  77. }
  78. }
  79. return NULL;
  80. }
  81. void* htable_begin(HTable *ht) {
  82. return ht->begin;
  83. }
  84. void* htable_next(HTable *ht, void *iter) {
  85. void *pos = iter;
  86. do {
  87. pos += ht->elemsz + 1;
  88. if (pos >= htable_end(ht)) {
  89. return NULL;
  90. }
  91. } while (getflag(pos) != HTFL_VAL);
  92. return pos;
  93. }