You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

strset.c 2.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #include "strset.h"
  2. #include <string.h>
  3. // sdbm from http://www.cse.yorku.ca/~oz/hash.html;
  4. // there are probably better algorithms out there
  5. static size_t hash(const void *ptr) {
  6. const unsigned char *str = ptr;
  7. size_t h = 0;
  8. int c;
  9. while ((c = *(str++)) != 0) {
  10. h = c + (h << 6) + (h << 16) - h;
  11. }
  12. return h;
  13. }
  14. void grow(struct l2_strset *set) {
  15. struct l2_strset old = *set;
  16. set->len = 0;
  17. set->size *= 2;
  18. set->mask = (set->mask << 1) | set->mask;
  19. set->keys = calloc(set->size, sizeof(*set->keys));
  20. set->vals = calloc(set->size, sizeof(*set->vals));
  21. for (size_t i = 0; i < old.size; ++i) {
  22. char *oldkey = old.keys[i];
  23. if (oldkey == NULL) {
  24. continue;
  25. }
  26. size_t h = hash(old.keys[i]);
  27. for (size_t j = 0; ; ++j) {
  28. size_t index = (h + j) & set->mask;
  29. char *k = set->keys[index];
  30. if (k != NULL) {
  31. continue;
  32. }
  33. set->keys[index] = oldkey;
  34. set->vals[index] = old.vals[i];
  35. break;
  36. }
  37. }
  38. free(old.keys);
  39. free(old.vals);
  40. }
  41. void l2_strset_init(struct l2_strset *set) {
  42. set->next = 1;
  43. set->len = 0;
  44. set->size = 16;
  45. set->mask = 0x0f;
  46. set->keys = calloc(set->size, sizeof(*set->keys));
  47. set->vals = calloc(set->size, sizeof(*set->vals));
  48. }
  49. void l2_strset_free(struct l2_strset *set) {
  50. for (size_t i = 0; i < set->size; ++i) {
  51. free(set->keys[i]);
  52. }
  53. free(set->keys);
  54. free(set->vals);
  55. }
  56. size_t l2_strset_put_move(struct l2_strset *set, char **str) {
  57. if (set->len >= set->size / 2) {
  58. grow(set);
  59. }
  60. size_t h = hash(*str);
  61. for (size_t i = 0; ; ++i) {
  62. size_t index = (h + i) & set->mask;
  63. char *k = set->keys[index];
  64. if (k == NULL) {
  65. set->keys[index] = *str;
  66. set->vals[index] = set->next++;
  67. set->len += 1;
  68. *str = NULL;
  69. return set->vals[index];
  70. } else if (strcmp(*str, k) == 0) {
  71. free(*str);
  72. *str = NULL;
  73. return set->vals[index];
  74. }
  75. }
  76. }
  77. size_t l2_strset_put_copy(struct l2_strset *set, const char *str) {
  78. if (set->len >= set->size / 2) {
  79. grow(set);
  80. }
  81. size_t h = hash(str);
  82. for (size_t i = 0; ; ++i) {
  83. size_t index = (h + i) & set->mask;
  84. char *k = set->keys[index];
  85. if (k == NULL) {
  86. set->keys[index] = strdup(str);
  87. set->vals[index] = set->next++;
  88. set->len += 1;
  89. return set->vals[index];
  90. } else if (strcmp(str, k) == 0) {
  91. return set->vals[index];
  92. }
  93. }
  94. }
  95. size_t l2_strset_get(struct l2_strset *set, const char *str) {
  96. size_t h = hash(str);
  97. for (size_t i = 0; ; ++i) {
  98. size_t index = (h + i) & set->mask;
  99. char *k = set->keys[index];
  100. if (k == NULL) {
  101. return 0;
  102. } else if (strcmp(str, k) == 0) {
  103. return set->vals[index];
  104. }
  105. }
  106. }