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