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

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