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/** @file */
13
14
15#ifndef SHT_H
16#define SHT_H
17
18
19#include <stddef.h>
20#include <stdint.h>
21
22
23/**
24 * @internal
25 * Maximum entry size.
26 */
27#define SHT_MAX_ESIZE 16384
28
29/**
30 * @internal
31 * Set function attributes without confusing Doxygen.
32 */
33#ifndef SHT_DOXYGEN
34#define SHT_FNATTR(...) __attribute__((__VA_ARGS__))
35#else
36#define SHT_FNATTR(...)
37#endif
38
39
40/**
41 * Critical error printing function.
42 *
43 * If the calling program violates this library's contract, the library will
44 * print an error message and abort the program. (See
45 * [Abort conditions](index.html#abort-conditions).) This variable can be set
46 * to customize how the error message is printed or logged.
47 *
48 * ```c
49 * static void log_sht_err(const char *msg)
50 * {
51 * syslog(LOG_CRIT, "SHT library error: %s", msg);
52 * }
53 *
54 * sht_abort_print = log_sht_err;
55 * ```
56 *
57 * @param msg The error message (not newline terminated).
58 *
59 * @see [Abort conditions](index.html#abort-conditions)
60 */
61extern void (*sht_abort_print)(const char *msg);
62
63
64/*******************************************************************************
65 *
66 *
67 * Callback function types
68 *
69 *
70 ******************************************************************************/
71
72/**
73 * Hash function type.
74 *
75 * Callback function type used to calculate hash values for keys.
76 *
77 * 32-bit example, using
78 * [`XXH32()`](https://xxhash.com/doc/v0.8.3/group___x_x_h32__family.html),
79 * which requires a seed:
80 *
81 * ```c
82 * uint32_t myhash32(const void *restrict key, void *restrict context)
83 * {
84 * const struct mykey *k = key;
85 * const XXH32_hash_t *seed = ctx;
86 *
87 * return XXH32(k, sizeof *k, *seed);
88 * }
89 * ```
90 *
91 * 64-bit example, using
92 * [`XXH3_64bits()`](https://xxhash.com/doc/v0.8.3/group___x_x_h3__family.html),
93 * which does not require a seed:
94 *
95 * ```c
96 * uint32_t myhash64(const void *restrict key, const void *restrict)
97 * {
98 * const struct mykey *k = key;
99 *
100 * // Throw away the upper 32 bits
101 * return (uint32_t)XXH3_64bits(k, sizeof *k);
102 * }
103 * ```
104 *
105 * @param key The key to be hashed.
106 * @param context Optional function-specific context.
107 *
108 * @returns The hash value of the key.
109 */
110typedef uint32_t (*sht_hashfn_t)(const void *restrict key,
111 void *restrict context);
112
113/**
114 * Equality comparison function type.
115 *
116 * Callback function type used to compare a key with the key of an existing
117 * bucket. This function is only called when the lower 24 bits of the hash
118 * values of the two keys are equal.
119 *
120 * ```c
121 * struct my_entry {
122 * const char *name;
123 * struct in_addr address;
124 * };
125 *
126 * _Bool my_cmp(const void *restrict key, const void *restrict entry,
127 * void *restrict)
128 * {
129 * const char *const name = key;
130 * const struct my_entry *const e = entry;
131 *
132 * return strcmp(name, e->name) == 0;
133 * }
134 * ```
135 *
136 * @param key The key to be compared against the key in the
137 * bucket.
138 * @param entry The entry whose key is to be compared.
139 * @param context Optional function-specific context.
140 *
141 * @returns A boolean value that indicates whether @p key is equal to the
142 * key in @p entry.
143 */
144typedef _Bool (*sht_eqfn_t)(const void *restrict key,
145 const void *restrict entry,
146 void *restrict context);
147
148/**
149 * Free function type.
150 *
151 * Callback function type used to free entry resources. For example:
152 *
153 * ```c
154 * struct my_entry {
155 * const char *name;
156 * struct in_addr address;
157 * };
158 *
159 * void my_free(const void *restrict entry, void *restrict)
160 * {
161 * const struct my_entry *const e = entry;
162 * free(e->name);
163 * }
164 * ```
165 *
166 * @param entry The entry whose resources should be freed.
167 * @param context Optional function-specific context.
168 */
169typedef void (*sht_freefn_t)(const void *restrict entry,
170 void *restrict context);
171
172
173/*******************************************************************************
174 *
175 *
176 * Other types
177 *
178 *
179 ******************************************************************************/
180
181/**
182 * A hash table.
183 */
184struct sht_ht;
185
186/**
187 * Read-only hash table iterator.
188 */
189struct sht_ro_iter;
190
191/**
192 * Read/write hash table iterator.
193 */
194struct sht_rw_iter;
195
196/**
197 * Error codes.
198 */
199enum sht_err: uint8_t {
200 SHT_ERR_OK = 0, /**< No error. */
201 SHT_ERR_ALLOC, /**< Memory allocation failed. */
202 SHT_ERR_BAD_ESIZE, /**< Entry size too large (> 16KiB). */
203 SHT_ERR_TOOBIG, /**< Requested table size too large. */
204 SHT_ERR_BAD_HASH, /**< Too many hash collisions. */
205 SHT_ERR_ITER_LOCK, /**< Can't acquire iterator lock. */
206 SHT_ERR_ITER_COUNT, /**< Table has too many iterators. */
207 SHT_ERR_ITER_NO_LAST, /**< Iterator at beginning or end. */
208 //
209 // Add all values above this comment
210 //
211 SHT_ERR_COUNT /**< (Not an error; used for bounds checks.) */
212};
213
214_Static_assert(sizeof(enum sht_err) == 1, "sht_err size");
215
216
217
218/*******************************************************************************
219 *
220 *
221 * Functions - documented in ht.c
222 *
223 *
224 ******************************************************************************/
225
226
227/*
228 * Table lifecycle - create, configure, initialize & free
229 */
230
231// Create a new hash table.
232SHT_FNATTR(nonnull(1, 2))
233struct sht_ht *sht_new_(sht_hashfn_t hashfn, sht_eqfn_t eqfn, size_t esize,
234 size_t ealign, enum sht_err *err);
235
236// Set the "context" for a table's hash function.
237SHT_FNATTR(nonnull(1))
238void sht_set_hash_ctx(struct sht_ht *ht, void *context);
239
240// Set the "context" for a table's equality function.
241SHT_FNATTR(nonnull(1))
242void sht_set_eq_ctx(struct sht_ht *ht, void *context);
243
244// Set the optional entry resource free function for a table.
245SHT_FNATTR(nonnull(1))
246void sht_set_freefn(struct sht_ht *ht, sht_freefn_t freefn, void *context);
247
248// Set the load factor threshold for a table.
249SHT_FNATTR(nonnull)
250void sht_set_lft(struct sht_ht *ht, uint8_t lft);
251
252// Set the PSL limit of a table.
253SHT_FNATTR(nonnull)
254void sht_set_psl_limit(struct sht_ht *ht, uint8_t thold);
255
256// Initialize a hash table.
257SHT_FNATTR(nonnull)
258_Bool sht_init(struct sht_ht *ht, uint32_t capacity);
259
260// Free the resources used by a hash table.
261SHT_FNATTR(nonnull)
262void sht_free(struct sht_ht *ht);
263
264
265/*
266 * Table operations - get, set, delete, etc.
267 */
268
269// Add an entry to the table, if its key is not already present.
270SHT_FNATTR(nonnull)
271int sht_add(struct sht_ht *ht, const void *key, const void *entry);
272
273// Unconditionally set the value associated with a key.
274SHT_FNATTR(nonnull)
275int sht_set(struct sht_ht *ht, const void *key, const void *entry);
276
277// Lookup an entry in a table.
278SHT_FNATTR(nonnull)
279const void *sht_get(struct sht_ht *ht, const void *restrict key);
280
281// Get the number of entries in a table.
282SHT_FNATTR(nonnull)
283uint32_t sht_size(const struct sht_ht *ht);
284
285// Determine whether a table is empty.
286SHT_FNATTR(nonnull)
287_Bool sht_empty(const struct sht_ht *ht);
288
289// Remove an entry from the table.
290SHT_FNATTR(nonnull)
291_Bool sht_delete(struct sht_ht *ht, const void *restrict key);
292
293// Remove and return an entry from the table.
294SHT_FNATTR(nonnull)
295_Bool sht_pop(struct sht_ht *ht, const void *restrict key, void *restrict out);
296
297// Replace the entry associated with an existing key.
298SHT_FNATTR(nonnull)
299_Bool sht_replace(struct sht_ht *ht, const void *key,
300 const void *entry);
301
302// Exchange an existing entry and a new entry.
303SHT_FNATTR(nonnull)
304_Bool sht_swap(struct sht_ht *ht, const void *key,
305 const void *entry, void *out);
306
307
308/*
309 * Iterator lifecycle - create & free
310 */
311
312// Create a new read-only iterator.
313SHT_FNATTR(nonnull)
314struct sht_ro_iter *sht_ro_iter(struct sht_ht *ht);
315
316// Create a new read/write iterator.
317SHT_FNATTR(nonnull)
318struct sht_rw_iter *sht_rw_iter(struct sht_ht *ht);
319
320// Free a read-only iterator.
321SHT_FNATTR(nonnull)
322void sht_ro_iter_free_(struct sht_ro_iter *iter);
323
324// Free a read/write iterator.
325SHT_FNATTR(nonnull)
326void sht_rw_iter_free_(struct sht_rw_iter *iter);
327
328
329/*
330 * Iterator operations - next, delete & replace
331 */
332
333// Get the next entry from a read-only iterator.
334SHT_FNATTR(nonnull)
335const void *sht_ro_iter_next_(struct sht_ro_iter *iter);
336
337// Get the next entry from a read/write iterator.
338SHT_FNATTR(nonnull)
339void *sht_rw_iter_next_(struct sht_rw_iter *iter);
340
341// Remove the last entry returned by a read/write iterator.
342SHT_FNATTR(nonnull)
343_Bool sht_iter_delete(struct sht_rw_iter *iter);
344
345// Replace the last entry returned by a read-only iterator.
346SHT_FNATTR(nonnull)
347_Bool sht_ro_iter_replace_(struct sht_ro_iter *iter,
348 const void *restrict entry);
349
350// Replace the last entry returned by a read/write iterator.
351SHT_FNATTR(nonnull)
352_Bool sht_rw_iter_replace_(struct sht_rw_iter *iter,
353 const void *restrict entry);
354
355
356/*
357 * Error reporting
358 */
359
360// Get the error code of a table's last error.
361SHT_FNATTR(nonnull)
362enum sht_err sht_get_err(const struct sht_ht *ht);
363
364// Get the error code of a read-only iterator's last error.
365SHT_FNATTR(nonnull)
366enum sht_err sht_ro_iter_err_(const struct sht_ro_iter *iter);
367
368// Get the error code of a read/write iterator's last error.
369SHT_FNATTR(nonnull)
370enum sht_err sht_rw_iter_err_(const struct sht_rw_iter *iter);
371
372// Get the description for an error code.
373const char *sht_msg(enum sht_err err);
374
375// Get a description of a table's last error.
376SHT_FNATTR(nonnull)
377const char *sht_get_msg(const struct sht_ht *ht);
378
379// Get a description of a read-only iterator's last error.
380SHT_FNATTR(nonnull)
381const char *sht_ro_iter_msg_(const struct sht_ro_iter *iter);
382
383// Get a description of a read/write iterator's last error.
384SHT_FNATTR(nonnull)
385const char *sht_rw_iter_msg_(const struct sht_rw_iter *iter);
386
387
388/*******************************************************************************
389 *
390 *
391 * Helper macros
392 *
393 *
394 ******************************************************************************/
395
396/*
397 * SHT_NEW()
398 */
399
400/**
401 * @internal
402 * Macro that expands to its second argument.
403 *
404 * This macro is used by SHT_HT_NEW() to accept an "optional" `err` argument.
405 *
406 * @param _ Dummy argument; only present to make syntax valid.
407 * @param a2 The expression to which this macro will expand.
408 * @param ... Possible additional arguments. Not used.
409 *
410 * @returns This macro expands to its second argument (@p a2).
411 */
412#define SHT_ARG2(_, a2, ...) (a2)
413
414/**
415 * Create a new hash table.
416 *
417 * This macro is a wrapper for sht_new_().
418 *
419 * ```c
420 * struct entry {
421 * const char *name;
422 * struct in_addr address;
423 * };
424 *
425 * struct sht_ht *ht;
426 * enum sht_err err;
427 *
428 * ht = sht_new(hashfn, eqfn, sizeof(struct entry),
429 * _Alignof(struct entry), &err);
430 *
431 * // Rewrite as ...
432 * ht = SHT_NEW(hashfn, eqfn, struct entry, &err);
433 *
434 * // Without error reporting ...
435 * ht = sht_new(hashfn, eqfn, sizeof(struct entry),
436 * _Alignof(struct entry), NULL);
437 *
438 * // Becomes ...
439 * ht = SHT_NEW(hashfn, eqfn, struct entry);
440 * ```
441 *
442 * @param hashfn The function that will be used to compute the hash
443 * values of keys.
444 * @param eqfn The function that will be used to compare keys for
445 * equality.
446 * @param etype The type of the entries to be stored in the table.
447 * @param[out] ... Optional output pointer for error reporting.
448 *
449 * @returns On success, a pointer to the new hash table is returned. On
450 * error, `NULL` is returned, and an error code is returned in
451 * @p err (if it is not `NULL`).
452 *
453 * @see sht_new_()
454 */
455#define SHT_NEW(hashfn, eqfn, etype, ...) \
456 ({ \
457 _Static_assert(sizeof(etype) <= SHT_MAX_ESIZE, \
458 "Entry type (" #etype ") too large"); \
459 sht_new_(hashfn, eqfn, sizeof(etype), _Alignof(etype), \
460 SHT_ARG2(_, ##__VA_ARGS__, NULL)); \
461 })
462
463/*
464 * Iterator generics
465 */
466
467/**
468 * @internal
469 * Template macro for generic iterator helpers.
470 *
471 * @param op The "operation" portion of the underlying function
472 * names. E.g. `next` generates a helper macro for
473 * sht_ro_iter_next_() and sht_rw_iter_next_().
474 * @param iter The iterator that will be passed to the underlying
475 * function.
476 * @param ... Any additional arguments that will be passed to the
477 * underlying function.
478 *
479 * @returns This macro expands to a generic helper macro that calls the
480 * correct underlying function for read-only or read/write
481 * iterators.
482 */
483#define SHT_ITER_GENERIC(op, iter, ...) \
484 _Generic((iter), \
485 struct sht_ro_iter *: sht_ro_iter_##op##_, \
486 struct sht_rw_iter *: sht_rw_iter_##op##_ \
487 )(iter, ##__VA_ARGS__)
488
489/**
490 * Free a hash table iterator.
491 *
492 * @param iter The iterator.
493 *
494 * @see sht_ro_iter_free_()
495 * @see sht_rw_iter_free_()
496 */
497#define SHT_ITER_FREE(iter) SHT_ITER_GENERIC(free, iter)
498
499/**
500 * Get the next entry from an iterator.
501 *
502 * @param iter The iterator.
503 *
504 * @returns A pointer to the next entry, if any. If no more entries are
505 * available, `NULL` is returned.
506 *
507 * @see sht_ro_iter_next_()
508 * @see sht_rw_iter_next_()
509 */
510#define SHT_ITER_NEXT(iter) SHT_ITER_GENERIC(next, iter)
511
512
513/**
514 * Replace the last entry returned by an iterator.
515 *
516 * > **WARNING**
517 * >
518 * > The new entry **must** have the same key as the entry being replaced.
519 * > Replacing an entry with an entry that contains a different key will corrupt
520 * > the table.
521 *
522 * @param iter The iterator.
523 * @param entry The new entry.
524 *
525 * @returns On success, true (`1`) is returned. On error, false (`0`) is
526 * returned and the error status of the iterator is set.
527 *
528 * @see sht_ro_iter_replace_()
529 * @see sht_rw_iter_replace_()
530 */
531#define SHT_ITER_REPLACE(iter, entry) SHT_ITER_GENERIC(replace, iter, entry)
532
533/**
534 * Get the the error code of an iterator's last error.
535 *
536 * The value returned by this macro is only valid after a previous iterator
537 * function call indicated an error.
538 *
539 * @param iter The iterator.
540 *
541 * @returns A code that describes the error.
542 *
543 * @see sht_ro_iter_status_()
544 * @see sht_rw_iter_status_()
545 */
546#define SHT_ITER_ERR(iter) SHT_ITER_GENERIC(err, iter)
547
548/**
549 * Get a description of an iterator's last error.
550 *
551 * The value returned by this macro is only valid after a previous iterator
552 * function call indicated an error.
553 *
554 * @param iter The iterator.
555 *
556 * @returns A string that describes the error.
557 *
558 * @see sht_ro_iter_msg_()
559 * @see sht_rw_iter_msg_()
560 */
561#define SHT_ITER_MSG(iter) SHT_ITER_GENERIC(msg, iter)
562
563
564#endif /* SHT_H */
void * sht_rw_iter_next_(struct sht_rw_iter *iter)
(Get the next entry from a read/write iterator.)
Definition sht.c:1630
const void * sht_get(struct sht_ht *ht, const void *restrict key)
Lookup an entry in a table.
Definition sht.c:984
_Bool sht_empty(const struct sht_ht *ht)
Determine whether a table is empty.
Definition sht.c:623
void sht_rw_iter_free_(struct sht_rw_iter *iter)
(Free a read/write iterator.)
Definition sht.c:1804
int sht_set(struct sht_ht *ht, const void *key, const void *entry)
Unconditionally set the value associated with a key.
Definition sht.c:956
void sht_set_hash_ctx(struct sht_ht *ht, void *context)
Set the "context" for a table's hash function.
Definition sht.c:350
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:928
const void * sht_ro_iter_next_(struct sht_ro_iter *iter)
(Get the next entry from a read-only iterator.)
Definition sht.c:1611
const char * sht_rw_iter_msg_(const struct sht_rw_iter *iter)
(Get a description of a read/write iterator's last error.)
Definition sht.c:1553
_Bool sht_ro_iter_replace_(struct sht_ro_iter *iter, const void *restrict entry)
(Replace the last entry returned by a read-only iterator.)
Definition sht.c:1717
_Bool sht_delete(struct sht_ht *ht, const void *restrict key)
Remove an entry from the table.
Definition sht.c:1334
_Bool sht_replace(struct sht_ht *ht, const void *key, const void *entry)
Replace the entry associated with an existing key.
Definition sht.c:1096
_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:1311
uint32_t sht_size(const struct sht_ht *ht)
Get the number of entries in a table.
Definition sht.c:601
enum sht_err sht_get_err(const struct sht_ht *ht)
Get the error code of a table's last error.
Definition sht.c:185
enum sht_err sht_ro_iter_err_(const struct sht_ro_iter *iter)
(Get the error code of a read-only iterator's last error.)
Definition sht.c:1490
_Bool sht_iter_delete(struct sht_rw_iter *iter)
Remove the last entry returned by a read/write iterator.
Definition sht.c:1643
enum sht_err sht_rw_iter_err_(const struct sht_rw_iter *iter)
(Get the error code of a read/write iterator's last error.)
Definition sht.c:1511
void sht_set_lft(struct sht_ht *ht, uint8_t lft)
Set the load factor threshold for a table.
Definition sht.c:429
void sht_set_eq_ctx(struct sht_ht *ht, void *context)
Set the "context" for a table's equality function.
Definition sht.c:374
void sht_set_psl_limit(struct sht_ht *ht, uint8_t limit)
Set the PSL limit of a table.
Definition sht.c:459
const char * sht_msg(enum sht_err err)
Get the description for an error code.
Definition sht.c:201
struct sht_ht * sht_new_(sht_hashfn_t hashfn, sht_eqfn_t eqfn, size_t esize, size_t ealign, enum sht_err *err)
(Create a new hash table.)
Definition sht.c:298
void sht_ro_iter_free_(struct sht_ro_iter *iter)
(Free a read-only iterator.)
Definition sht.c:1788
const char * sht_get_msg(const struct sht_ht *ht)
Get a description of a table's last error.
Definition sht.c:234
_Bool sht_init(struct sht_ht *ht, uint32_t capacity)
Initialize a hash table.
Definition sht.c:558
void sht_set_freefn(struct sht_ht *ht, sht_freefn_t freefn, void *context)
Set the optional entry resource free function for a table.
Definition sht.c:400
_Bool sht_rw_iter_replace_(struct sht_rw_iter *iter, const void *restrict entry)
(Replace the last entry returned by a read/write iterator.)
Definition sht.c:1744
void sht_free(struct sht_ht *ht)
Free the resources used by a hash table.
Definition sht.c:1351
_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:1123
const char * sht_ro_iter_msg_(const struct sht_ro_iter *iter)
(Get a description of a read-only iterator's last error.)
Definition sht.c:1532
sht_err
Error codes.
Definition sht.h:199
@ SHT_ERR_TOOBIG
Requested table size too large.
Definition sht.h:203
@ SHT_ERR_ITER_COUNT
Table has too many iterators.
Definition sht.h:206
@ SHT_ERR_BAD_ESIZE
Entry size too large (> 16KiB).
Definition sht.h:202
@ SHT_ERR_ALLOC
Memory allocation failed.
Definition sht.h:201
@ SHT_ERR_BAD_HASH
Too many hash collisions.
Definition sht.h:204
@ SHT_ERR_ITER_NO_LAST
Iterator at beginning or end.
Definition sht.h:207
@ SHT_ERR_COUNT
(Not an error; used for bounds checks.)
Definition sht.h:211
@ SHT_ERR_ITER_LOCK
Can't acquire iterator lock.
Definition sht.h:205
@ SHT_ERR_OK
No error.
Definition sht.h:200
void(* sht_freefn_t)(const void *restrict entry, void *restrict context)
Free function type.
Definition sht.h:169
_Bool(* sht_eqfn_t)(const void *restrict key, const void *restrict entry, void *restrict context)
Equality comparison function type.
Definition sht.h:144
uint32_t(* sht_hashfn_t)(const void *restrict key, void *restrict context)
Hash function type.
Definition sht.h:110