xref: /netbsd-src/external/mit/isl/dist/isl_hash.c (revision 5971e316fdea024efff6be8f03536623db06833e)
1*5971e316Smrg /*
2*5971e316Smrg  * Copyright 2008-2009 Katholieke Universiteit Leuven
3*5971e316Smrg  *
4*5971e316Smrg  * Use of this software is governed by the MIT license
5*5971e316Smrg  *
6*5971e316Smrg  * Written by Sven Verdoolaege, K.U.Leuven, Departement
7*5971e316Smrg  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
8*5971e316Smrg  */
9*5971e316Smrg 
10*5971e316Smrg #include <stdlib.h>
11*5971e316Smrg #include <isl_hash_private.h>
12*5971e316Smrg #include <isl/ctx.h>
13*5971e316Smrg #include "isl_config.h"
14*5971e316Smrg 
isl_hash_string(uint32_t hash,const char * s)15*5971e316Smrg uint32_t isl_hash_string(uint32_t hash, const char *s)
16*5971e316Smrg {
17*5971e316Smrg 	for (; *s; s++)
18*5971e316Smrg 		isl_hash_byte(hash, *s);
19*5971e316Smrg 	return hash;
20*5971e316Smrg }
21*5971e316Smrg 
isl_hash_mem(uint32_t hash,const void * p,size_t len)22*5971e316Smrg uint32_t isl_hash_mem(uint32_t hash, const void *p, size_t len)
23*5971e316Smrg {
24*5971e316Smrg 	int i;
25*5971e316Smrg 	const char *s = p;
26*5971e316Smrg 	for (i = 0; i < len; ++i)
27*5971e316Smrg 		isl_hash_byte(hash, s[i]);
28*5971e316Smrg 	return hash;
29*5971e316Smrg }
30*5971e316Smrg 
round_up(unsigned int v)31*5971e316Smrg static unsigned int round_up(unsigned int v)
32*5971e316Smrg {
33*5971e316Smrg 	int old_v = v;
34*5971e316Smrg 
35*5971e316Smrg 	while (v) {
36*5971e316Smrg 		old_v = v;
37*5971e316Smrg 		v ^= v & -v;
38*5971e316Smrg 	}
39*5971e316Smrg 	return old_v << 1;
40*5971e316Smrg }
41*5971e316Smrg 
isl_hash_table_init(struct isl_ctx * ctx,struct isl_hash_table * table,int min_size)42*5971e316Smrg int isl_hash_table_init(struct isl_ctx *ctx, struct isl_hash_table *table,
43*5971e316Smrg 			int min_size)
44*5971e316Smrg {
45*5971e316Smrg 	size_t size;
46*5971e316Smrg 
47*5971e316Smrg 	if (!table)
48*5971e316Smrg 		return -1;
49*5971e316Smrg 
50*5971e316Smrg 	if (min_size < 2)
51*5971e316Smrg 		min_size = 2;
52*5971e316Smrg 	table->bits = ffs(round_up(4 * (min_size + 1) / 3 - 1)) - 1;
53*5971e316Smrg 	table->n = 0;
54*5971e316Smrg 
55*5971e316Smrg 	size = 1 << table->bits;
56*5971e316Smrg 	table->entries = isl_calloc_array(ctx, struct isl_hash_table_entry,
57*5971e316Smrg 					  size);
58*5971e316Smrg 	if (!table->entries)
59*5971e316Smrg 		return -1;
60*5971e316Smrg 
61*5971e316Smrg 	return 0;
62*5971e316Smrg }
63*5971e316Smrg 
64*5971e316Smrg /* Dummy comparison function that always returns false.
65*5971e316Smrg  */
no(const void * entry,const void * val)66*5971e316Smrg static isl_bool no(const void *entry, const void *val)
67*5971e316Smrg {
68*5971e316Smrg 	return isl_bool_false;
69*5971e316Smrg }
70*5971e316Smrg 
71*5971e316Smrg /* Extend "table" to twice its size.
72*5971e316Smrg  * Return 0 on success and -1 on error.
73*5971e316Smrg  *
74*5971e316Smrg  * We reuse isl_hash_table_find to create entries in the extended table.
75*5971e316Smrg  * Since all entries in the original table are assumed to be different,
76*5971e316Smrg  * there is no need to compare them against each other.
77*5971e316Smrg  */
grow_table(struct isl_ctx * ctx,struct isl_hash_table * table)78*5971e316Smrg static int grow_table(struct isl_ctx *ctx, struct isl_hash_table *table)
79*5971e316Smrg {
80*5971e316Smrg 	int n;
81*5971e316Smrg 	size_t old_size, size;
82*5971e316Smrg 	struct isl_hash_table_entry *entries;
83*5971e316Smrg 	uint32_t h;
84*5971e316Smrg 
85*5971e316Smrg 	entries = table->entries;
86*5971e316Smrg 	old_size = 1 << table->bits;
87*5971e316Smrg 	size = 2 * old_size;
88*5971e316Smrg 	table->entries = isl_calloc_array(ctx, struct isl_hash_table_entry,
89*5971e316Smrg 					  size);
90*5971e316Smrg 	if (!table->entries) {
91*5971e316Smrg 		table->entries = entries;
92*5971e316Smrg 		return -1;
93*5971e316Smrg 	}
94*5971e316Smrg 
95*5971e316Smrg 	n = table->n;
96*5971e316Smrg 	table->n = 0;
97*5971e316Smrg 	table->bits++;
98*5971e316Smrg 
99*5971e316Smrg 	for (h = 0; h < old_size; ++h) {
100*5971e316Smrg 		struct isl_hash_table_entry *entry;
101*5971e316Smrg 
102*5971e316Smrg 		if (!entries[h].data)
103*5971e316Smrg 			continue;
104*5971e316Smrg 
105*5971e316Smrg 		entry = isl_hash_table_find(ctx, table, entries[h].hash,
106*5971e316Smrg 					    &no, NULL, 1);
107*5971e316Smrg 		if (!entry) {
108*5971e316Smrg 			table->bits--;
109*5971e316Smrg 			free(table->entries);
110*5971e316Smrg 			table->entries = entries;
111*5971e316Smrg 			table->n = n;
112*5971e316Smrg 			return -1;
113*5971e316Smrg 		}
114*5971e316Smrg 
115*5971e316Smrg 		*entry = entries[h];
116*5971e316Smrg 	}
117*5971e316Smrg 
118*5971e316Smrg 	free(entries);
119*5971e316Smrg 
120*5971e316Smrg 	return 0;
121*5971e316Smrg }
122*5971e316Smrg 
isl_hash_table_alloc(struct isl_ctx * ctx,int min_size)123*5971e316Smrg struct isl_hash_table *isl_hash_table_alloc(struct isl_ctx *ctx, int min_size)
124*5971e316Smrg {
125*5971e316Smrg 	struct isl_hash_table *table = NULL;
126*5971e316Smrg 
127*5971e316Smrg 	table = isl_alloc_type(ctx, struct isl_hash_table);
128*5971e316Smrg 	if (isl_hash_table_init(ctx, table, min_size))
129*5971e316Smrg 		goto error;
130*5971e316Smrg 	return table;
131*5971e316Smrg error:
132*5971e316Smrg 	isl_hash_table_free(ctx, table);
133*5971e316Smrg 	return NULL;
134*5971e316Smrg }
135*5971e316Smrg 
isl_hash_table_clear(struct isl_hash_table * table)136*5971e316Smrg void isl_hash_table_clear(struct isl_hash_table *table)
137*5971e316Smrg {
138*5971e316Smrg 	if (!table)
139*5971e316Smrg 		return;
140*5971e316Smrg 	free(table->entries);
141*5971e316Smrg }
142*5971e316Smrg 
isl_hash_table_free(struct isl_ctx * ctx,struct isl_hash_table * table)143*5971e316Smrg void isl_hash_table_free(struct isl_ctx *ctx, struct isl_hash_table *table)
144*5971e316Smrg {
145*5971e316Smrg 	if (!table)
146*5971e316Smrg 		return;
147*5971e316Smrg 	isl_hash_table_clear(table);
148*5971e316Smrg 	free(table);
149*5971e316Smrg }
150*5971e316Smrg 
151*5971e316Smrg /* A dummy entry that is used by isl_hash_table_find
152*5971e316Smrg  * to make a distinction between a missing entry and an error condition.
153*5971e316Smrg  */
154*5971e316Smrg static struct isl_hash_table_entry none = { 0, NULL };
155*5971e316Smrg struct isl_hash_table_entry *isl_hash_table_entry_none = &none;
156*5971e316Smrg 
isl_hash_table_find(struct isl_ctx * ctx,struct isl_hash_table * table,uint32_t key_hash,isl_bool (* eq)(const void * entry,const void * val),const void * val,int reserve)157*5971e316Smrg struct isl_hash_table_entry *isl_hash_table_find(struct isl_ctx *ctx,
158*5971e316Smrg 			    struct isl_hash_table *table,
159*5971e316Smrg 			    uint32_t key_hash,
160*5971e316Smrg 			    isl_bool (*eq)(const void *entry, const void *val),
161*5971e316Smrg 			    const void *val, int reserve)
162*5971e316Smrg {
163*5971e316Smrg 	size_t size;
164*5971e316Smrg 	uint32_t h, key_bits;
165*5971e316Smrg 
166*5971e316Smrg 	key_bits = isl_hash_bits(key_hash, table->bits);
167*5971e316Smrg 	size = 1 << table->bits;
168*5971e316Smrg 	for (h = key_bits; table->entries[h].data; h = (h+1) % size) {
169*5971e316Smrg 		isl_bool equal;
170*5971e316Smrg 
171*5971e316Smrg 		if (table->entries[h].hash != key_hash)
172*5971e316Smrg 			continue;
173*5971e316Smrg 		equal = eq(table->entries[h].data, val);
174*5971e316Smrg 		if (equal < 0)
175*5971e316Smrg 			return NULL;
176*5971e316Smrg 		if (equal)
177*5971e316Smrg 			return &table->entries[h];
178*5971e316Smrg 	}
179*5971e316Smrg 
180*5971e316Smrg 	if (!reserve)
181*5971e316Smrg 		return isl_hash_table_entry_none;
182*5971e316Smrg 
183*5971e316Smrg 	if (4 * table->n >= 3 * size) {
184*5971e316Smrg 		if (grow_table(ctx, table) < 0)
185*5971e316Smrg 			return NULL;
186*5971e316Smrg 		return isl_hash_table_find(ctx, table, key_hash, eq, val, 1);
187*5971e316Smrg 	}
188*5971e316Smrg 
189*5971e316Smrg 	table->n++;
190*5971e316Smrg 	table->entries[h].hash = key_hash;
191*5971e316Smrg 
192*5971e316Smrg 	return &table->entries[h];
193*5971e316Smrg }
194*5971e316Smrg 
195*5971e316Smrg /* Return the first entry containing data in "table".
196*5971e316Smrg  * Return isl_hash_table_entry_none is there is no such entry and
197*5971e316Smrg  * NULL on error.
198*5971e316Smrg  */
isl_hash_table_first(struct isl_hash_table * table)199*5971e316Smrg struct isl_hash_table_entry *isl_hash_table_first(struct isl_hash_table *table)
200*5971e316Smrg {
201*5971e316Smrg 	size_t size;
202*5971e316Smrg 	uint32_t h;
203*5971e316Smrg 
204*5971e316Smrg 	if (!table->entries)
205*5971e316Smrg 		return NULL;
206*5971e316Smrg 
207*5971e316Smrg 	size = 1 << table->bits;
208*5971e316Smrg 	for (h = 0; h < size; ++ h)
209*5971e316Smrg 		if (table->entries[h].data)
210*5971e316Smrg 			return &table->entries[h];
211*5971e316Smrg 
212*5971e316Smrg 	return isl_hash_table_entry_none;
213*5971e316Smrg }
214*5971e316Smrg 
isl_hash_table_foreach(isl_ctx * ctx,struct isl_hash_table * table,isl_stat (* fn)(void ** entry,void * user),void * user)215*5971e316Smrg isl_stat isl_hash_table_foreach(isl_ctx *ctx, struct isl_hash_table *table,
216*5971e316Smrg 	isl_stat (*fn)(void **entry, void *user), void *user)
217*5971e316Smrg {
218*5971e316Smrg 	size_t size;
219*5971e316Smrg 	uint32_t h;
220*5971e316Smrg 
221*5971e316Smrg 	if (!table->entries)
222*5971e316Smrg 		return isl_stat_error;
223*5971e316Smrg 
224*5971e316Smrg 	size = 1 << table->bits;
225*5971e316Smrg 	for (h = 0; h < size; ++ h)
226*5971e316Smrg 		if (table->entries[h].data &&
227*5971e316Smrg 		    fn(&table->entries[h].data, user) < 0)
228*5971e316Smrg 			return isl_stat_error;
229*5971e316Smrg 
230*5971e316Smrg 	return isl_stat_ok;
231*5971e316Smrg }
232*5971e316Smrg 
233*5971e316Smrg /* Does "test" succeed on every (non-empty) entry of "table"?
234*5971e316Smrg  */
isl_hash_table_every(isl_ctx * ctx,struct isl_hash_table * table,isl_bool (* test)(void ** entry,void * user),void * user)235*5971e316Smrg isl_bool isl_hash_table_every(isl_ctx *ctx, struct isl_hash_table *table,
236*5971e316Smrg 	isl_bool (*test)(void **entry, void *user), void *user)
237*5971e316Smrg {
238*5971e316Smrg 	size_t size;
239*5971e316Smrg 	uint32_t h;
240*5971e316Smrg 
241*5971e316Smrg 	if (!table->entries)
242*5971e316Smrg 		return isl_bool_error;
243*5971e316Smrg 
244*5971e316Smrg 	size = 1 << table->bits;
245*5971e316Smrg 	for (h = 0; h < size; ++ h) {
246*5971e316Smrg 		isl_bool r;
247*5971e316Smrg 
248*5971e316Smrg 		if (!table->entries[h].data)
249*5971e316Smrg 			continue;
250*5971e316Smrg 		r = test(&table->entries[h].data, user);
251*5971e316Smrg 		if (r < 0 || !r)
252*5971e316Smrg 			return r;
253*5971e316Smrg 	}
254*5971e316Smrg 
255*5971e316Smrg 	return isl_bool_true;
256*5971e316Smrg }
257*5971e316Smrg 
isl_hash_table_remove(struct isl_ctx * ctx,struct isl_hash_table * table,struct isl_hash_table_entry * entry)258*5971e316Smrg void isl_hash_table_remove(struct isl_ctx *ctx,
259*5971e316Smrg 				struct isl_hash_table *table,
260*5971e316Smrg 				struct isl_hash_table_entry *entry)
261*5971e316Smrg {
262*5971e316Smrg 	int h, h2;
263*5971e316Smrg 	size_t size;
264*5971e316Smrg 
265*5971e316Smrg 	if (!table || !entry)
266*5971e316Smrg 		return;
267*5971e316Smrg 
268*5971e316Smrg 	size = 1 << table->bits;
269*5971e316Smrg 	h = entry - table->entries;
270*5971e316Smrg 	isl_assert(ctx, h >= 0 && h < size, return);
271*5971e316Smrg 
272*5971e316Smrg 	for (h2 = h+1; table->entries[h2 % size].data; h2++) {
273*5971e316Smrg 		uint32_t bits = isl_hash_bits(table->entries[h2 % size].hash,
274*5971e316Smrg 						table->bits);
275*5971e316Smrg 		uint32_t offset = (size + bits - (h+1)) % size;
276*5971e316Smrg 		if (offset <= h2 - (h+1))
277*5971e316Smrg 			continue;
278*5971e316Smrg 		*entry = table->entries[h2 % size];
279*5971e316Smrg 		h = h2;
280*5971e316Smrg 		entry = &table->entries[h % size];
281*5971e316Smrg 	}
282*5971e316Smrg 
283*5971e316Smrg 	entry->hash = 0;
284*5971e316Smrg 	entry->data = NULL;
285*5971e316Smrg 	table->n--;
286*5971e316Smrg }
287