summaryrefslogtreecommitdiffstats
path: root/ccan/ccan/htable/htable.h
blob: faaf541bd8ce8c5ee5f5ea64eab3649e1462fade (plain)
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
/* Licensed under LGPLv2+ - see LICENSE file for details */
#ifndef CCAN_HTABLE_H
#define CCAN_HTABLE_H
#include "config.h"
#include <ccan/str/str.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>

/* Define CCAN_HTABLE_DEBUG for expensive debugging checks on each call. */
#define HTABLE_LOC __FILE__ ":" stringify(__LINE__)
#ifdef CCAN_HTABLE_DEBUG
#define htable_debug(h, loc) htable_check((h), loc)
#else
#define htable_debug(h, loc) ((void)loc, h)
#endif

/**
 * struct htable - private definition of a htable.
 *
 * It's exposed here so you can put it in your structures and so we can
 * supply inline functions.
 */
struct htable {
	size_t (*rehash)(const void *elem, void *priv);
	void *priv;
	unsigned int bits, perfect_bitnum;
	size_t elems, deleted;
	/* These are the bits which are the same in all pointers. */
	uintptr_t common_mask, common_bits;
	uintptr_t *table;
};

/**
 * HTABLE_INITIALIZER - static initialization for a hash table.
 * @name: name of this htable.
 * @rehash: hash function to use for rehashing.
 * @priv: private argument to @rehash function.
 *
 * This is useful for setting up static and global hash tables.
 *
 * Example:
 *	// For simplicity's sake, say hash value is contents of elem.
 *	static size_t rehash(const void *elem, void *unused)
 *	{
 *		(void)unused;
 *		return *(size_t *)elem;
 *	}
 *	static struct htable ht = HTABLE_INITIALIZER(ht, rehash, NULL);
 */
#define HTABLE_INITIALIZER(name, rehash, priv)				\
	{ rehash, priv, 0, 0, 0, 0, -1, 0, &name.common_bits }

/**
 * htable_init - initialize an empty hash table.
 * @ht: the hash table to initialize
 * @rehash: hash function to use for rehashing.
 * @priv: private argument to @rehash function.
 */
void htable_init(struct htable *ht,
		 size_t (*rehash)(const void *elem, void *priv), void *priv);

/**
 * htable_init_sized - initialize an empty hash table of given size.
 * @ht: the hash table to initialize
 * @rehash: hash function to use for rehashing.
 * @priv: private argument to @rehash function.
 * @size: the number of element.
 *
 * If this returns false, @ht is still usable, but may need to do reallocation
 * upon an add.  If this returns true, it will not need to reallocate within
 * @size htable_adds.
 */
bool htable_init_sized(struct htable *ht,
		       size_t (*rehash)(const void *elem, void *priv),
		       void *priv, size_t size);

/**
 * htable_count - count number of entries in a hash table.
 * @ht: the hash table
 */
static inline size_t htable_count(const struct htable *ht)
{
	return ht->elems;
}

/**
 * htable_clear - empty a hash table.
 * @ht: the hash table to clear
 *
 * This doesn't do anything to any pointers left in it.
 */
void htable_clear(struct htable *ht);


/**
 * htable_check - check hash table for consistency
 * @ht: the htable
 * @abortstr: the location to print on aborting, or NULL.
 *
 * Because hash tables have redundant information, consistency checking that
 * each element is in the correct location can be done.  This is useful as a
 * debugging check.  If @abortstr is non-NULL, that will be printed in a
 * diagnostic if the htable is inconsistent, and the function will abort.
 *
 * Returns the htable if it is consistent, NULL if not (it can never return
 * NULL if @abortstr is set).
 */
struct htable *htable_check(const struct htable *ht, const char *abortstr);

/**
 * htable_copy - duplicate a hash table.
 * @dst: the hash table to overwrite
 * @src: the hash table to copy
 *
 * Only fails on out-of-memory.
 *
 * Equivalent to (but faster than):
 *    if (!htable_init_sized(dst, src->rehash, src->priv, 1U << src->bits))
 *	   return false;
 *    v = htable_first(src, &i);
 *    while (v) {
 *		htable_add(dst, v);
 *		v = htable_next(src, i);
 *    }
 *    return true;
 */
#define htable_copy(dst, src) htable_copy_(dst, htable_debug(src, HTABLE_LOC))
bool htable_copy_(struct htable *dst, const struct htable *src);

/**
 * htable_add - add a pointer into a hash table.
 * @ht: the htable
 * @hash: the hash value of the object
 * @p: the non-NULL pointer (also cannot be (void *)1).
 *
 * Also note that this can only fail due to allocation failure.  Otherwise, it
 * returns true.
 */
#define htable_add(ht, hash, p) \
	htable_add_(htable_debug(ht, HTABLE_LOC), hash, p)
bool htable_add_(struct htable *ht, size_t hash, const void *p);

/**
 * htable_del - remove a pointer from a hash table
 * @ht: the htable
 * @hash: the hash value of the object
 * @p: the pointer
 *
 * Returns true if the pointer was found (and deleted).
 */
#define htable_del(ht, hash, p) \
	htable_del_(htable_debug(ht, HTABLE_LOC), hash, p)
bool htable_del_(struct htable *ht, size_t hash, const void *p);

/**
 * struct htable_iter - iterator or htable_first or htable_firstval etc.
 *
 * This refers to a location inside the hashtable.
 */
struct htable_iter {
	size_t off;
};

/**
 * htable_firstval - find a candidate for a given hash value
 * @htable: the hashtable
 * @i: the struct htable_iter to initialize
 * @hash: the hash value
 *
 * You'll need to check the value is what you want; returns NULL if none.
 * See Also:
 *	htable_delval()
 */
#define htable_firstval(htable, i, hash) \
	htable_firstval_(htable_debug(htable, HTABLE_LOC), i, hash)

void *htable_firstval_(const struct htable *htable,
		       struct htable_iter *i, size_t hash);

/**
 * htable_nextval - find another candidate for a given hash value
 * @htable: the hashtable
 * @i: the struct htable_iter to initialize
 * @hash: the hash value
 *
 * You'll need to check the value is what you want; returns NULL if no more.
 */
#define htable_nextval(htable, i, hash) \
	htable_nextval_(htable_debug(htable, HTABLE_LOC), i, hash)
void *htable_nextval_(const struct htable *htable,
		      struct htable_iter *i, size_t hash);

/**
 * htable_get - find an entry in the hash table
 * @ht: the hashtable
 * @h: the hash value of the entry
 * @cmp: the comparison function
 * @ptr: the pointer to hand to the comparison function.
 *
 * Convenient inline wrapper for htable_firstval/htable_nextval loop.
 */
static inline void *htable_get(const struct htable *ht,
			       size_t h,
			       bool (*cmp)(const void *candidate, void *ptr),
			       const void *ptr)
{
	struct htable_iter i;
	void *c;

	for (c = htable_firstval(ht,&i,h); c; c = htable_nextval(ht,&i,h)) {
		if (cmp(c, (void *)ptr))
			return c;
	}
	return NULL;
}

/**
 * htable_first - find an entry in the hash table
 * @ht: the hashtable
 * @i: the struct htable_iter to initialize
 *
 * Get an entry in the hashtable; NULL if empty.
 */
#define htable_first(htable, i) \
	htable_first_(htable_debug(htable, HTABLE_LOC), i)
void *htable_first_(const struct htable *htable, struct htable_iter *i);

/**
 * htable_next - find another entry in the hash table
 * @ht: the hashtable
 * @i: the struct htable_iter to use
 *
 * Get another entry in the hashtable; NULL if all done.
 * This is usually used after htable_first or prior non-NULL htable_next.
 */
#define htable_next(htable, i) \
	htable_next_(htable_debug(htable, HTABLE_LOC), i)
void *htable_next_(const struct htable *htable, struct htable_iter *i);

/**
 * htable_prev - find the previous entry in the hash table
 * @ht: the hashtable
 * @i: the struct htable_iter to use
 *
 * Get previous entry in the hashtable; NULL if all done.
 *
 * "previous" here only means the item that would have been returned by
 * htable_next() before the item it returned most recently.
 *
 * This is usually used in the middle of (or after) a htable_next iteration and
 * to "unwind" actions taken.
 */
#define htable_prev(htable, i) \
	htable_prev_(htable_debug(htable, HTABLE_LOC), i)
void *htable_prev_(const struct htable *htable, struct htable_iter *i);

/**
 * htable_delval - remove an iterated pointer from a hash table
 * @ht: the htable
 * @i: the htable_iter
 *
 * Usually used to delete a hash entry after it has been found with
 * htable_firstval etc.
 */
#define htable_delval(htable, i) \
	htable_delval_(htable_debug(htable, HTABLE_LOC), i)
void htable_delval_(struct htable *ht, struct htable_iter *i);

/**
 * htable_pick - set iterator to a random valid entry.
 * @ht: the htable
 * @seed: a random number to use.
 * @i: the htable_iter which is output (or NULL).
 *
 * Usually used with htable_delval to delete a random entry.  Returns
 * NULL iff the table is empty, otherwise a random entry.
 */
#define htable_pick(htable, seed, i)					\
	htable_pick_(htable_debug(htable, HTABLE_LOC), seed, i)
void *htable_pick_(const struct htable *ht, size_t seed, struct htable_iter *i);

/**
 * htable_set_allocator - set calloc/free functions.
 * @alloc: allocator to use, must zero memory!
 * @free: unallocator to use (@p is NULL or a return from @alloc)
 */
void htable_set_allocator(void *(*alloc)(struct htable *, size_t len),
			  void (*free)(struct htable *, void *p));
#endif /* CCAN_HTABLE_H */