xs_set.h 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /* copyright (c) 2022 grunfink - MIT license */
  2. #ifndef _XS_SET_H
  3. #define _XS_SET_H
  4. typedef struct _xs_set {
  5. int elems; /* number of hash entries */
  6. int used; /* number of used hash entries */
  7. int *hash; /* hashed offsets */
  8. d_char *list; /* list of stored data */
  9. } xs_set;
  10. void xs_set_init(xs_set *s);
  11. void xs_set_free(xs_set *s);
  12. int xs_set_add(xs_set *s, const char *data);
  13. #ifdef XS_IMPLEMENTATION
  14. void xs_set_init(xs_set *s)
  15. /* initializes a set */
  16. {
  17. /* arbitrary default */
  18. s->elems = 256;
  19. s->used = 0;
  20. s->hash = xs_realloc(NULL, s->elems * sizeof(int));
  21. s->list = xs_list_new();
  22. memset(s->hash, '\0', s->elems * sizeof(int));
  23. }
  24. void xs_set_free(xs_set *s)
  25. /* frees a set */
  26. {
  27. s->hash = xs_free(s->hash);
  28. s->list = xs_free(s->list);
  29. }
  30. static unsigned int _calc_hash(const char *data, int size)
  31. {
  32. unsigned int hash = 0x666;
  33. int n;
  34. for (n = 0; n < size; n++) {
  35. hash ^= data[n];
  36. hash *= 111111111;
  37. }
  38. return hash ^ hash >> 16;
  39. }
  40. static int _store_hash(xs_set *s, const char *data, int value)
  41. {
  42. unsigned int hash, i;
  43. int sz = xs_size(data);
  44. hash = _calc_hash(data, sz);
  45. while (s->hash[(i = hash % s->elems)]) {
  46. /* get the pointer to the stored data */
  47. char *p = &s->list[s->hash[i]];
  48. /* already here? */
  49. if (memcmp(p, data, sz) == 0)
  50. return 0;
  51. /* try next value */
  52. hash++;
  53. }
  54. /* store the new value */
  55. s->hash[i] = value;
  56. s->used++;
  57. return 1;
  58. }
  59. int xs_set_add(xs_set *s, const char *data)
  60. /* adds the data to the set */
  61. /* returns: 1 if added, 0 if already there */
  62. {
  63. /* is it 'full'? */
  64. if (s->used >= s->elems / 2) {
  65. char *p, *v;
  66. /* expand! */
  67. s->elems *= 2;
  68. s->used = 0;
  69. s->hash = xs_realloc(s->hash, s->elems * sizeof(int));
  70. memset(s->hash, '\0', s->elems * sizeof(int));
  71. /* add the list elements back */
  72. p = s->list;
  73. while (xs_list_iter(&p, &v))
  74. _store_hash(s, v, v - s->list);
  75. }
  76. int ret = _store_hash(s, data, xs_size(s->list));
  77. /* if it's new, add the data */
  78. if (ret)
  79. s->list = xs_list_append_m(s->list, data, xs_size(data));
  80. return ret;
  81. }
  82. #endif /* XS_IMPLEMENTATION */
  83. #endif /* XS_SET_H */