2.93 xs_set.h
  1/* copyright (c) 2022 - 2026 grunfink et al. / MIT license */
  2
  3#ifndef _XS_SET_H
  4
  5#define _XS_SET_H
  6
  7typedef struct _xs_set {
  8    int elems;              /* number of hash entries */
  9    int used;               /* number of used hash entries */
 10    int *hash;              /* hashed offsets */
 11    xs_list *list;          /* list of stored data */
 12} xs_set;
 13
 14void xs_set_init(xs_set *s);
 15xs_list *xs_set_result(xs_set *s);
 16void xs_set_free(xs_set *s);
 17int xs_set_in(const xs_set *s, const xs_val *data);
 18int xs_set_add(xs_set *s, const xs_val *data);
 19
 20
 21#ifdef XS_IMPLEMENTATION
 22
 23
 24void xs_set_init(xs_set *s)
 25/* initializes a set */
 26{
 27    /* arbitrary default */
 28    s->elems = 256;
 29    s->used  = 0;
 30    s->hash  = xs_realloc(NULL, s->elems * sizeof(int));
 31    s->list  = xs_list_new();
 32
 33    memset(s->hash, '\0', s->elems * sizeof(int));
 34}
 35
 36
 37xs_list *xs_set_result(xs_set *s)
 38/* returns the set as a list and frees it */
 39{
 40    xs_list *list = s->list;
 41    s->list = NULL;
 42    s->hash = xs_free(s->hash);
 43
 44    return list;
 45}
 46
 47
 48void xs_set_free(xs_set *s)
 49/* frees a set, dropping the list */
 50{
 51    xs_free(xs_set_result(s));
 52}
 53
 54
 55static int _store_hash(xs_set *s, const char *data, int value)
 56{
 57    unsigned int hash, i;
 58    int sz = xs_size(data);
 59
 60    hash = xs_hash_func(data, sz);
 61
 62    while (s->hash[(i = hash % s->elems)]) {
 63        /* get the pointer to the stored data */
 64        const char *p = &s->list[s->hash[i]];
 65
 66        /* already here? */
 67        if (memcmp(p, data, sz) == 0)
 68            return 0;
 69
 70        /* try next value */
 71        hash++;
 72    }
 73
 74    /* store the new value */
 75    s->hash[i] = value;
 76
 77    s->used++;
 78
 79    return 1;
 80}
 81
 82
 83int xs_set_in(const xs_set *s, const xs_val *data)
 84/* returns 1 if the data is already in the set */
 85{
 86    unsigned int hash, i;
 87    int sz = xs_size(data);
 88
 89    hash = xs_hash_func(data, sz);
 90
 91    while (s->hash[(i = hash % s->elems)]) {
 92        /* get the pointer to the stored data */
 93        const char *p = &s->list[s->hash[i]];
 94
 95        /* already here? */
 96        if (memcmp(p, data, sz) == 0)
 97            return 1;
 98
 99        /* try next value */
100        hash++;
101    }
102
103    return 0;
104}
105
106
107int xs_set_add(xs_set *s, const xs_val *data)
108/* adds the data to the set */
109/* returns: 1 if added, 0 if already there */
110{
111    /* is it 'full'? */
112    if (s->used >= s->elems / 2) {
113        const xs_val *v;
114
115        /* expand! */
116        s->elems *= 2;
117        s->used  = 0;
118        s->hash  = xs_realloc(s->hash, s->elems * sizeof(int));
119
120        memset(s->hash, '\0', s->elems * sizeof(int));
121
122        /* add the list elements back */
123        xs_list_foreach(s->list, v)
124            _store_hash(s, v, v - s->list);
125    }
126
127    int ret = _store_hash(s, data, xs_size(s->list));
128
129    /* if it's new, add the data */
130    if (ret)
131        s->list = xs_list_append(s->list, data);
132
133    return ret;
134}
135
136#endif /* XS_IMPLEMENTATION */
137
138#endif /* XS_SET_H */