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