SHT Hash Table
SHT Hash Table
Loading...
Searching...
No Matches
sht.h
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2
3/*
4 *
5 * SHT - hash table with "Robin Hood" probing
6 *
7 * Copyright 2025 Ian Pilcher <arequipeno@gmail.com>
8 *
9 */
10
11
12/**
13 * @file
14 * SHT library API.
15 */
16
17
18#ifndef SHT_H
19#define SHT_H
20
21
22#include <stddef.h>
23#include <stdint.h>
24
25
26/**
27 * @internal
28 * @brief
29 * Maximum entry size.
30 */
31#define SHT_MAX_ESIZE 16384
32
33/**
34 * Critical error printing function.
35 *
36 * If the calling program violates this library's contract, the library will
37 * print an error message and abort the program. (See
38 * [Abort conditions](index.html#abort-conditions).) This variable can be set
39 * to customize how the error message is printed or logged.
40 *
41 * ```c
42 * static void log_sht_err(const char *msg)
43 * {
44 * syslog(LOG_CRIT, "SHT library error: %s", msg);
45 * }
46 *
47 * sht_abort_print = log_sht_err;
48 * ```
49 *
50 * @param msg The error message (not newline terminated).
51 *
52 * @see [Abort conditions](index.html#abort-conditions)
53 */
54extern void (*sht_abort_print)(const char *msg);
55
56
57/*******************************************************************************
58 *
59 *
60 * Callback function types
61 *
62 *
63 ******************************************************************************/
64
65/**
66 * Hash function type.
67 *
68 * Callback function type used to calculate hash values for keys.
69 *
70 * 32-bit example, using
71 * [`XXH32()`](https://xxhash.com/doc/v0.8.3/group___x_x_h32__family.html),
72 * which requires a seed:
73 *
74 * ```c
75 * uint32_t myhash32(const void *restrict key, void *restrict context)
76 * {
77 * const struct mykey *k = key;
78 * const XXH32_hash_t *seed = ctx;
79 *
80 * return XXH32(k, sizeof *k, *seed);
81 * }
82 * ```
83 *
84 * 64-bit example, using
85 * [`XXH3_64bits()`](https://xxhash.com/doc/v0.8.3/group___x_x_h3__family.html),
86 * which does not require a seed:
87 *
88 * ```c
89 * uint32_t myhash64(const void *restrict key, const void *restrict)
90 * {
91 * const struct mykey *k = key;
92 *
93 * // Throw away the upper 32 bits
94 * return (uint32_t)XXH3_64bits(k, sizeof *k);
95 * }
96 * ```
97 *
98 * @param key The key to be hashed.
99 * @param context Optional function-specific context.
100 *
101 * @returns The hash value of the key.
102 */
103typedef uint32_t (*sht_hashfn_t)(const void *restrict key,
104 void *restrict context);
105
106/**
107 * Equality comparison function type.
108 *
109 * Callback function type used to compare a key with the key of an existing
110 * bucket. This function is only called when the lower 24 bits of the hash
111 * values of the two keys are equal.
112 *
113 * ```c
114 * struct my_entry {
115 * const char *name;
116 * struct in_addr address;
117 * };
118 *
119 * bool my_cmp(const void *restrict key, const void *restrict entry,
120 * void *restrict)
121 * {
122 * const char *const name = key;
123 * const struct my_entry *const e = entry;
124 *
125 * return strcmp(name, e->name) == 0;
126 * }
127 * ```
128 *
129 * @param key The key to be compared against the key in the
130 * bucket.
131 * @param entry The entry whose key is to be compared.
132 * @param context Optional function-specific context.
133 *
134 * @returns A boolean value that indicates whether @p key is equal to the
135 * key in @p entry.
136 */
137typedef bool (*sht_eqfn_t)(const void *restrict key,
138 const void *restrict entry,
139 void *restrict context);
140
141/**
142 * Free function type.
143 *
144 * Callback function type used to free entry resources. For example:
145 *
146 * ```c
147 * struct my_entry {
148 * const char *name;
149 * struct in_addr address;
150 * };
151 *
152 * void my_free(const void *restrict entry, void *restrict)
153 * {
154 * const struct my_entry *const e = entry;
155 * free(e->name);
156 * }
157 * ```
158 *
159 * @param entry The entry whose resources should be freed.
160 * @param context Optional function-specific context.
161 */
162typedef void (*sht_freefn_t)(const void *restrict entry,
163 void *restrict context);
164
165
166/*******************************************************************************
167 *
168 *
169 * Other types
170 *
171 *
172 ******************************************************************************/
173
174/**
175 * A hash table.
176 */
177struct sht_ht;
178
179/**
180 * Iterator types.
181 */
182enum sht_iter_type: bool {
183 SHT_ITER_RO = 0, /**< Read-only iterator. */
184 SHT_ITER_RW = 1 /**< Read/write iterator. */
185};
186
187/**
188 * Hash table iterator.
189 */
190struct sht_iter;
191
192/**
193 * Error codes.
194 */
195enum sht_err: uint8_t {
196 SHT_ERR_OK = 0, /**< No error. */
197 SHT_ERR_ALLOC, /**< Memory allocation failed. */
198 SHT_ERR_BAD_ESIZE, /**< Entry size too large (> 16KiB). */
199 SHT_ERR_TOOBIG, /**< Requested table size too large. */
200 SHT_ERR_BAD_HASH, /**< Too many hash collisions. */
201 SHT_ERR_ITER_LOCK, /**< Can't acquire iterator lock. */
202 SHT_ERR_ITER_COUNT, /**< Table has too many iterators. */
203 SHT_ERR_ITER_NO_LAST, /**< Iterator at beginning or end. */
204 //
205 // Add all values above this comment
206 //
207 SHT_ERR_COUNT /**< (Not an error; used for bounds checks.) */
208};
209
210static_assert(sizeof(enum sht_err) == 1);
211
212
213
214/*******************************************************************************
215 *
216 *
217 * Functions - documented in ht.c
218 *
219 *
220 ******************************************************************************/
221
222
223/*
224 * Table lifecycle - create, configure, initialize & free
225 */
226
227// Create a new hash table (call via SHT_NEW()).
228[[gnu::nonnull(1, 2)]]
229struct sht_ht *sht_new_(sht_hashfn_t hashfn, sht_eqfn_t eqfn,
230 sht_freefn_t freefn, size_t esize,
231 size_t ealign, enum sht_err *err);
232
233// Set the "context" for a table's hash function.
234[[gnu::nonnull(1)]]
235void sht_set_hash_ctx(struct sht_ht *ht, void *context);
236
237// Set the "context" for a table's equality function.
238[[gnu::nonnull(1)]]
239void sht_set_eq_ctx(struct sht_ht *ht, void *context);
240
241// Set the "context" for a table's free function.
242[[gnu::nonnull(1)]]
243void sht_set_free_ctx(struct sht_ht *ht, void *context);
244
245// Set the load factor threshold for a table.
246[[gnu::nonnull]]
247void sht_set_lft(struct sht_ht *ht, uint8_t lft);
248
249// Set the PSL limit of a table.
250[[gnu::nonnull]]
251void sht_set_psl_limit(struct sht_ht *ht, uint8_t limit);
252
253// Initialize a hash table.
254[[gnu::nonnull]]
255bool sht_init(struct sht_ht *ht, uint32_t capacity);
256
257// Free the resources used by a hash table.
258[[gnu::nonnull]]
259void sht_free(struct sht_ht *ht);
260
261
262/*
263 * Table operations - get, set, delete, etc.
264 */
265
266// Add an entry to the table, if its key is not already present.
267[[gnu::nonnull]]
268int sht_add(struct sht_ht *ht, const void *key, const void *entry);
269
270// Unconditionally set the value associated with a key.
271[[gnu::nonnull]]
272int sht_set(struct sht_ht *ht, const void *key, const void *entry);
273
274// Lookup an entry in a table.
275[[gnu::nonnull]]
276const void *sht_get(struct sht_ht *ht, const void *restrict key);
277
278// Get the number of entries in a table.
279[[gnu::nonnull]]
280uint32_t sht_size(const struct sht_ht *ht);
281
282// Determine whether a table is empty.
283[[gnu::nonnull]]
284bool sht_empty(const struct sht_ht *ht);
285
286// Get the "peak" probe sequence length (PSL) of a table.
287[[gnu::nonnull]]
288uint8_t sht_peak_psl(const struct sht_ht *ht);
289
290// Remove an entry from the table.
291[[gnu::nonnull]]
292bool sht_delete(struct sht_ht *ht, const void *restrict key);
293
294// Remove and return an entry from the table.
295[[gnu::nonnull]]
296bool sht_pop(struct sht_ht *ht, const void *restrict key, void *restrict out);
297
298// Replace the entry associated with an existing key.
299[[gnu::nonnull]]
300bool sht_replace(struct sht_ht *ht, const void *key,
301 const void *entry);
302
303// Exchange an existing entry and a new entry.
304[[gnu::nonnull]]
305bool sht_swap(struct sht_ht *ht, const void *key,
306 const void *entry, void *out);
307
308
309/*
310 * Iterators
311 */
312
313// Create a new iterator
314[[gnu::nonnull]]
315struct sht_iter *sht_iter_new(struct sht_ht *ht, enum sht_iter_type type);
316
317// Free an iterator.
318[[gnu::nonnull]]
319void sht_iter_free(struct sht_iter *iter);
320
321// Get the next entry from an iterator.
322[[gnu::nonnull]]
323const void *sht_iter_next(struct sht_iter *iter);
324
325// Remove the last entry returned by a read/write iterator.
326[[gnu::nonnull]]
327bool sht_iter_delete(struct sht_iter *iter);
328
329// Replace the last entry returned by an iterator.
330[[gnu::nonnull]]
331bool sht_iter_replace(struct sht_iter *iter, const void *restrict entry);
332
333
334/*
335 * Error reporting
336 */
337
338// Get the error code of a table's last error.
339[[gnu::nonnull]]
340enum sht_err sht_get_err(const struct sht_ht *ht);
341
342// Get the error code of an iterator's last error.
343[[gnu::nonnull]]
344enum sht_err sht_iter_err(const struct sht_iter *iter);
345
346// Get the description for an error code.
347const char *sht_msg(enum sht_err err);
348
349// Get a description of a table's last error.
350[[gnu::nonnull]]
351const char *sht_get_msg(const struct sht_ht *ht);
352
353// Get a description of an iterator's last error.
354[[gnu::nonnull]]
355const char *sht_iter_msg(const struct sht_iter *iter);
356
357
358/*******************************************************************************
359 *
360 *
361 * Helper macros
362 *
363 *
364 ******************************************************************************/
365
366/*
367 * SHT_NEW()
368 */
369
370/**
371 * @internal
372 * @brief
373 * Macro that expands to its second argument.
374 *
375 * This macro is used by SHT_HT_NEW() to accept an "optional" `err` argument.
376 *
377 * @param _ Dummy argument; only present to make syntax valid.
378 * @param a2 The expression to which this macro will expand.
379 * @param ... Possible additional arguments. Not used.
380 *
381 * @returns This macro expands to its second argument (@p a2).
382 */
383#define SHT_ARG2(_, a2, ...) (a2)
384
385/**
386 * Create a new hash table.
387 *
388 * This macro is a wrapper for sht_new_().
389 *
390 * ```c
391 * struct entry {
392 * const char *name;
393 * struct in_addr address;
394 * };
395 *
396 * struct sht_ht *ht;
397 * enum sht_err err;
398 *
399 * ht = sht_new(hashfn, eqfn, NULL, sizeof(struct entry),
400 * alignof(struct entry), &err);
401 *
402 * // Rewrite as ...
403 * ht = SHT_NEW(hashfn, eqfn, NULL, struct entry, &err);
404 *
405 * // Without error reporting ...
406 * ht = sht_new(hashfn, eqfn, NULL, sizeof(struct entry),
407 * alignof(struct entry), NULL);
408 *
409 * // Becomes ...
410 * ht = SHT_NEW(hashfn, eqfn, NULL, struct entry);
411 * ```
412 *
413 * @param hashfn Function to be used to compute the hash values of keys.
414 * @param eqfn Function to be used to compare keys for equality.
415 * @param freefn Function to be used to free entry resources. (May be
416 * `NULL`.)
417 * @param etype The type of the entries to be stored in the table.
418 * @param[out] ... Optional output pointer for error reporting.
419 *
420 * @returns On success, a pointer to the new hash table is returned. On
421 * error, `NULL` is returned, and an error code is returned in
422 * @p err (if it is not `NULL`).
423 *
424 * @see sht_new_()
425 */
426#define SHT_NEW(hashfn, eqfn, freefn, etype, ...) \
427 ({ \
428 static_assert(sizeof(etype) <= SHT_MAX_ESIZE, \
429 "Entry type (" #etype ") too large"); \
430 sht_new_(hashfn, eqfn, freefn, \
431 sizeof(etype), alignof(etype), \
432 SHT_ARG2(_, ##__VA_ARGS__, nullptr)); \
433 })
434
435
436#endif /* SHT_H */
const void * sht_get(struct sht_ht *ht, const void *restrict key)
Lookup an entry in a table.
Definition sht.c:985
sht_err
Error codes.
Definition sht.h:195
@ SHT_ERR_TOOBIG
Requested table size too large.
Definition sht.h:199
@ SHT_ERR_ITER_COUNT
Table has too many iterators.
Definition sht.h:202
@ SHT_ERR_BAD_ESIZE
Entry size too large (> 16KiB).
Definition sht.h:198
@ SHT_ERR_ALLOC
Memory allocation failed.
Definition sht.h:197
@ SHT_ERR_BAD_HASH
Too many hash collisions.
Definition sht.h:200
@ SHT_ERR_ITER_NO_LAST
Iterator at beginning or end.
Definition sht.h:203
@ SHT_ERR_COUNT
(Not an error; used for bounds checks.)
Definition sht.h:207
@ SHT_ERR_ITER_LOCK
Can't acquire iterator lock.
Definition sht.h:201
@ SHT_ERR_OK
No error.
Definition sht.h:196
bool sht_delete(struct sht_ht *ht, const void *restrict key)
Remove an entry from the table.
Definition sht.c:1335
bool sht_replace(struct sht_ht *ht, const void *key, const void *entry)
Replace the entry associated with an existing key.
Definition sht.c:1097
void(* sht_freefn_t)(const void *restrict entry, void *restrict context)
Free function type.
Definition sht.h:162
const char * sht_iter_msg(const struct sht_iter *iter)
Get a description of an iterator's last error.
Definition sht.c:1454
uint8_t sht_peak_psl(const struct sht_ht *ht)
Get the "peak" probe sequence length (PSL) of a table.
Definition sht.c:626
const void * sht_iter_next(struct sht_iter *iter)
Get the next entry from an iterator.
Definition sht.c:1467
int sht_set(struct sht_ht *ht, const void *key, const void *entry)
Unconditionally set the value associated with a key.
Definition sht.c:957
void sht_set_hash_ctx(struct sht_ht *ht, void *context)
Set the "context" for a table's hash function.
Definition sht.c:336
bool sht_init(struct sht_ht *ht, uint32_t capacity)
Initialize a hash table.
Definition sht.c:541
int sht_add(struct sht_ht *ht, const void *key, const void *entry)
Add an entry to the table, if its key is not already present.
Definition sht.c:929
uint32_t(* sht_hashfn_t)(const void *restrict key, void *restrict context)
Hash function type.
Definition sht.h:103
bool sht_iter_replace(struct sht_iter *iter, const void *restrict entry)
Replace the last entry returned by an iterator.
Definition sht.c:1544
bool sht_empty(const struct sht_ht *ht)
Determine whether a table is empty.
Definition sht.c:606
bool sht_swap(struct sht_ht *ht, const void *key, const void *entry, void *out)
Exchange an existing entry and a new entry.
Definition sht.c:1124
bool sht_pop(struct sht_ht *ht, const void *restrict key, void *restrict out)
Remove and return an entry from the table.
Definition sht.c:1312
uint32_t sht_size(const struct sht_ht *ht)
Get the number of entries in a table.
Definition sht.c:584
struct sht_iter * sht_iter_new(struct sht_ht *ht, enum sht_iter_type type)
Create a new iterator.
Definition sht.c:1386
bool sht_iter_delete(struct sht_iter *iter)
Remove the last entry returned by a read/write iterator.
Definition sht.c:1507
enum sht_err sht_get_err(const struct sht_ht *ht)
Get the error code of a table's last error.
Definition sht.c:170
sht_iter_type
Iterator types.
Definition sht.h:182
@ SHT_ITER_RO
Read-only iterator.
Definition sht.h:183
@ SHT_ITER_RW
Read/write iterator.
Definition sht.h:184
void sht_set_lft(struct sht_ht *ht, uint8_t lft)
Set the load factor threshold for a table.
Definition sht.c:412
void sht_set_eq_ctx(struct sht_ht *ht, void *context)
Set the "context" for a table's equality function.
Definition sht.c:360
void sht_set_psl_limit(struct sht_ht *ht, uint8_t limit)
Set the PSL limit of a table.
Definition sht.c:442
const char * sht_msg(enum sht_err err)
Get the description for an error code.
Definition sht.c:186
const char * sht_get_msg(const struct sht_ht *ht)
Get a description of a table's last error.
Definition sht.c:218
void sht_set_free_ctx(struct sht_ht *ht, void *context)
Set the "context" for a table's free function.
Definition sht.c:384
enum sht_err sht_iter_err(const struct sht_iter *iter)
Get the error code of an iterator's last error.
Definition sht.c:1439
void sht_iter_free(struct sht_iter *iter)
Free an iterator.
Definition sht.c:1564
bool(* sht_eqfn_t)(const void *restrict key, const void *restrict entry, void *restrict context)
Equality comparison function type.
Definition sht.h:137
struct sht_ht * sht_new_(sht_hashfn_t hashfn, sht_eqfn_t eqfn, sht_freefn_t freefn, size_t esize, size_t ealign, enum sht_err *err)
Create a new hash table (call via SHT_NEW()).
Definition sht.c:283
void sht_free(struct sht_ht *ht)
Free the resources used by a hash table.
Definition sht.c:1352