SHT Hash Table
SHT Hash Table
Loading...
Searching...
No Matches
sht-ts.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 * Generates type-safe wrappers for the SHT API.
15 *
16 * @include{doc} docs/type-safe.md
17 */
18
19
20#ifndef SHT_TS_H
21#define SHT_TS_H
22
23
24#include "sht.h"
25
26
27/*******************************************************************************
28 *
29 *
30 * Low-level helper macros
31 *
32 * See https://github.com/ipilcher/cpp-tricks
33 *
34 *
35 ******************************************************************************/
36
37#ifndef SHT_DOXYGEN
38
39// Conditional expansion
40#define SHT_ARG1_NX(a1, ...) a1
41#define SHT_ARG1(...) SHT_ARG1_NX(__VA_ARGS__)
42#define SHT_IF_ELSE(a, b, ...) SHT_ARG1(__VA_OPT__(a,) b)
43
44// Removing parentheses: Required parentheses
45#define SHT_EXPAND(...) __VA_ARGS__
46#define SHT_DEPAREN(x) SHT_EXPAND x
47
48// Removing parentheses: Optional parentheses
49#define SHT_PAREN_PROBE(...)
50#define SHT_CDP_MACRO(x) \
51 SHT_IF_ELSE( \
52 SHT_EXPAND, \
53 SHT_DEPAREN, \
54 SHT_PAREN_PROBE x \
55 )
56#define SHT_COND_DEPAREN(x) SHT_CDP_MACRO(x)(x)
57
58// Stringification
59#define SHT_STR_NX(x) #x
60#define SHT_STR(x) SHT_STR_NX(x)
61
62// Type checking
63#define SHT_CHECK_TYPE(expr, type, ...) \
64 static_assert( \
65 _Generic((expr), \
66 type: 1, \
67 default: 0 \
68 ) \
69 __VA_OPT__(,) \
70 __VA_ARGS__ \
71 )
72
73// Tuples: First required, second optional
74#define SHT_STRIP_ARG1_NX(a1, ...) __VA_ARGS__
75#define SHT_STRIP_ARG1(...) SHT_STRIP_ARG1_NX(__VA_ARGS__)
76#define SHT_FRSO_REQ(t) SHT_ARG1(SHT_COND_DEPAREN(t))
77#define SHT_FRSO_OPT(t) SHT_STRIP_ARG1(SHT_COND_DEPAREN(t))
78
79// Tuples: First optional, second required
80#define SHT_FOSR_OPT(t) \
81 SHT_IF_ELSE( \
82 SHT_ARG1(SHT_COND_DEPAREN(t)), \
83 SHT_STRIP_ARG1(SHT_COND_DEPAREN(t)), \
84 SHT_STRIP_ARG1(SHT_COND_DEPAREN(t)) \
85 )
86
87#define SHT_FOSR_REQ(t) \
88 SHT_IF_ELSE( \
89 SHT_STRIP_ARG1(SHT_COND_DEPAREN(t)), \
90 SHT_ARG1(SHT_COND_DEPAREN(t)), \
91 SHT_STRIP_ARG1(SHT_COND_DEPAREN(t)) \
92 )
93
94// Unique identifiers
95#define SHT_CONCAT_NX(a, b) a##b
96#define SHT_CONCAT(a, b) SHT_CONCAT_NX(a, b)
97#define SHT_MKID(base) SHT_CONCAT(base, __LINE__)
98
99#endif
100
101
102/*******************************************************************************
103 *
104 *
105 * Callback function context arguments/types
106 *
107 * Type-safe callback functions do not have a context argument if those
108 * arguments would be unused. When generating a typedef for a pointer
109 * or a call to such a function, the context type or argument must be
110 * omitted in that case.
111 *
112 *
113 ******************************************************************************/
114
115/**
116 * @internal
117 * @brief
118 * Expands to the context argument (if any) of a call to a wrapped function.
119 *
120 * If the context referent type argument is present, this macro expands to a
121 * sequence of 2 tokens &mdash; a comma followed by the identifier `context`
122 * (`, context`). If the argument is not present, it expands to nothing.
123 *
124 * @param ... Optional callback function context referent type.
125 *
126 */
127#define SHT_CB_CTX_ARG(...) \
128 SHT_DEPAREN( \
129 SHT_IF_ELSE( \
130 (, context), \
131 (), \
132 __VA_ARGS__ \
133 ) \
134 )
135
136/**
137 * @internal
138 * @brief
139 * The type of the context argument (if any) in a wrapped function's signature.
140 *
141 * If the context referent type argument is present, this macro expands to a
142 * token sequence that contains a comma followed by the type and `*restrict`.
143 * For example, if the context type is `int`, this macro expands to
144 * `, int *restrict`. If the context referent type is not present, this macro
145 * expands to nothing.
146 *
147 * @param ... Optional callback function context referent type.
148 *
149 */
150#define SHT_CB_CTX_TYPE(...) \
151 SHT_DEPAREN( \
152 SHT_IF_ELSE( \
153 (, __VA_ARGS__ *restrict), \
154 (), \
155 __VA_ARGS__ \
156 ) \
157 )
158
159
160/*******************************************************************************
161 *
162 *
163 * Type-safe hash function wrapper
164 *
165 *
166 ******************************************************************************/
167
168/**
169 * @internal
170 * @brief
171 * Creates a typedef for a pointer to the expected type-safe hash function.
172 *
173 * > **NOTE**
174 * >
175 * > The name of the generated typedef is always `ts_hashfn_t`. Therefore, this
176 * > macro should only be used **inside** a function.
177 *
178 * @param ktype Key referent type.
179 * @param ... Optional context referent type.
180 *
181 */
182#define SHT_HASHFN_TD(ktype, ...) \
183 typedef uint32_t (*ts_hashfn_t)( \
184 const ktype *restrict \
185 SHT_CB_CTX_TYPE(__VA_ARGS__) \
186 )
187
188/**
189 * @internal
190 * @brief
191 * Error message string for incorrect type-safe hash function signature.
192 *
193 * @param hashfn Type-safe hash function name.
194 * @param ktype Key referent type.
195 * @param ... Optional type-safe hash function context referent type.
196 *
197 */
198#define SHT_HASHFN_ERR(hashfn, ktype, ...) \
199 SHT_STR( \
200 hashfn has incorrect signature; expected: \
201 uint32_t hashfn ( const ktype *restrict \
202 SHT_CB_CTX_TYPE(__VA_ARGS__) ) \
203 )
204
205/**
206 * @internal
207 * @brief
208 * Generates a wrapper for a type-safe hash function.
209 *
210 * The generated function definition accepts void pointers for both its @p key
211 * and @p context arguments and calls the type-safe hash function identified by
212 * @p hasnfn. If the context referent type argument is not present, the
213 * type-safe function is called with only the @p key argument.
214 *
215 * The generated function also includes a compile-time check of the type-safe
216 * hash function's signature.
217 *
218 * @param name Wrapper function name.
219 * @param ktype Key referent type.
220 * @param hashfn The type-safe hash function to be wrapped.
221 * @param ... Optional context referent type.
222 */
223#define SHT_MKHASHFN(name, ktype, hashfn, ...) \
224 static uint32_t name(const void *restrict key, \
225 void *restrict context) \
226 { \
227 /* typedef for wrapped function signature check */ \
228 SHT_HASHFN_TD(ktype, __VA_ARGS__); \
229 /* Check that wrapped function matches typedef */ \
230 SHT_CHECK_TYPE( \
231 hashfn, \
232 ts_hashfn_t, \
233 SHT_HASHFN_ERR(hashfn, ktype, __VA_ARGS__) \
234 ); \
235 /* Suppress potential unused argument warning */ \
236 (void)context; \
237 /* Call the type-safe function */ \
238 return hashfn(key SHT_CB_CTX_ARG(__VA_ARGS__)); \
239 }
240
241
242/*******************************************************************************
243 *
244 *
245 * Type-safe equality function wrapper
246 *
247 *
248 ******************************************************************************/
249
250/**
251 * @internal
252 * @brief
253 * Creates a typedef for a pointer to the expected type-safe equality function.
254 *
255 * > **NOTE**
256 * >
257 * > The name of the generated typedef is always `ts_eqfn_t`. Therefore, this
258 * > macro should only be used **inside** a function.
259 *
260 * @param ktype Key referent type.
261 * @param etype Entry referent type.
262 * @param ... Optional type-safe equality function context referent
263 * type.
264 *
265 */
266#define SHT_EQFN_TD(ktype, etype, ...) \
267 typedef bool (*ts_eqfn_t)( \
268 const ktype *restrict, \
269 const etype *restrict \
270 SHT_CB_CTX_TYPE(__VA_ARGS__) \
271 )
272
273/**
274 * @internal
275 * @brief
276 * Error message string for incorrect type-safe equality function signature.
277 *
278 * @param eqfn Type-safe equality function name.
279 * @param ktype Key referent type.
280 * @param etype Entry referent type.
281 * @param ... Optional type-safe equality function context referent
282 * type.
283 *
284 */
285#define SHT_EQFN_ERR(eqfn, ktype, etype, ...) \
286 SHT_STR( \
287 eqfn has incorrect signature; expected: \
288 bool eqfn ( const ktype *restrict , \
289 const etype *restrict \
290 SHT_CB_CTX_TYPE(__VA_ARGS__) ) \
291 )
292
293/**
294 * @internal
295 * @brief
296 * Generates a wrapper for a type-safe equality function.
297 *
298 * The generated function definition accepts void pointers for its @p key,
299 * @p entry, and @p context arguments and calls the type-safe equality function
300 * identified by @p eqfn. If the context referent type argument is not present,
301 * the type-safe function is called with only the @p key and @p entry arguments.
302 *
303 * The generated function also includes a compile-time check of the type-safe
304 * equality function's signature.
305 *
306 * @param name Wrapper function name.
307 * @param ktype Key referent type.
308 * @param etype Entry referent type.
309 * @param eqfn The type-safe equality function to be wrapped.
310 * @param ... Optional context referent type.
311 */
312#define SHT_MKEQFN(name, ktype, etype, eqfn, ...) \
313 static bool name(const void *restrict key, \
314 const void *restrict entry, \
315 void *restrict context) \
316 { \
317 /* typedef for wrapped function signature check */ \
318 SHT_EQFN_TD(ktype, etype, __VA_ARGS__); \
319 /* Check that wrapped function matches typedef */ \
320 SHT_CHECK_TYPE( \
321 eqfn, \
322 ts_eqfn_t, \
323 SHT_EQFN_ERR(eqfn, ktype, etype, __VA_ARGS__) \
324 ); \
325 /* Suppress potential unused argument warning */ \
326 (void)context; \
327 /* Call the type-safe function */ \
328 return eqfn(key, entry SHT_CB_CTX_ARG(__VA_ARGS__)); \
329 }
330
331
332/*******************************************************************************
333 *
334 *
335 * Type-safe free function wrapper
336 *
337 *
338 ******************************************************************************/
339
340/**
341 * @internal
342 * @brief
343 * Creates a typedef for a pointer to the expected type-safe free function.
344 *
345 * > **NOTE**
346 * >
347 * > The name of the generated typedef is always `ts_freefn_t`. Therefore, this
348 * > macro should only be used **inside** a function.
349 *
350 * @param etype Entry referent type.
351 * @param ... Optional type-safe free function context referent type.
352 *
353 */
354#define SHT_FREEFN_TD(etype, ...) \
355 typedef void (*ts_freefn_t)( \
356 const etype *restrict \
357 SHT_CB_CTX_TYPE(__VA_ARGS__) \
358 )
359
360/**
361 * @internal
362 * @brief
363 * Error message string for incorrect type-safe free function signature.
364 *
365 * @param freefn Type-safe free function name.
366 * @param etype Entry referent type.
367 * @param ... Optional type-safe free function context referent type.
368 *
369 */
370#define SHT_FREEFN_ERR(freefn, etype, ...) \
371 SHT_STR( \
372 freefn has incorrect signature; expected: \
373 void freefn ( const etype *restrict \
374 SHT_CB_CTX_TYPE(__VA_ARGS__) ) \
375 )
376
377/**
378 * @internal
379 * @brief
380 * Generates a wrapper for a type-safe free function.
381 *
382 * The generated function definition accepts void pointers for both its @p entry
383 * and @p context arguments and calls the type-safe free function identified by
384 * @p freefn. If the context referent type argument is not present, the
385 * type-safe function is called with only the @p entry argument.
386 *
387 * The generated function also included a compile-time check of the type-safe
388 * free function's signature.
389 *
390 * @param name Wrapper function name.
391 * @param etype Entry referent type.
392 * @param freefn The type-safe free function to be wrapped.
393 * @param ... Optional free function context type.
394 */
395#define SHT_MKFREEFN(name, etype, freefn, ...) \
396 static void name(const void *restrict entry, \
397 void *restrict context) \
398 { \
399 /* typedef for wrapped function signature check */ \
400 SHT_FREEFN_TD(etype, __VA_ARGS__); \
401 /* Check that wrapped function matches typedef */ \
402 SHT_CHECK_TYPE( \
403 freefn, \
404 ts_freefn_t, \
405 SHT_FREEFN_ERR(freefn, etype, __VA_ARGS__) \
406 ); \
407 /* Suppress potential unused argument warning */ \
408 (void)context; \
409 /* Call the type-safe function */ \
410 freefn(entry SHT_CB_CTX_ARG(__VA_ARGS__)); \
411 }
412
413
414/*******************************************************************************
415 *
416 *
417 * const stripping
418 *
419 *
420 ******************************************************************************/
421
422/**
423 * Cast a `const`-qualified pointer to a non-`const`-qualified pointer.
424 *
425 * The callback function types (#sht_hashfn_t, #sht_eqfn_t, and #sht_freefn_t)
426 * all accept a `context` argument that library users may use to provide
427 * additional data to their callback functions (e.g., a hash function seed).
428 * The library also defines a "setter" function for each context type &mdash;
429 * sht_set_hash_ctx(), sht_set_eq_ctx(), and sht_set_free_ctx(). The `context`
430 * argument to these functions is not `const`-qualified; this allows callback
431 * functions to modify their context referents, if desired.
432 *
433 * In many cases, there is no requirement for callback function contexts to be
434 * mutable, so the type-safe hash, equality, or free function can declare its
435 * context argument to be a `const`-qualified pointer type. The generated
436 * wrapper function, which accepts a non-`const` context pointer in order to
437 * conform to the library API, can simply call the type-safe function, because
438 * **adding** a `const` qualifier to a pointer is always allowed.
439 *
440 * This case presents a problem for the generated setter functions. They should
441 * accept a `const`-qualified `context` argument and pass it to the library
442 * setter function which expects a non-`const` pointer. This can generate an
443 * unwanted warning.
444 *
445 * This function exists to "cast away" the `const` qualifier from a pointer
446 * without generating any warnings. It should not generate any actual object
447 * code when optimization is enabled.
448 *
449 * @param p A (possibly) `const`-qualified pointer.
450 *
451 * @returns The value of @p p, as a non-`const`-qualified pointer.
452 */
453static inline void *sht_strip_const_(const void *p)
454{
455 _Pragma("GCC diagnostic push")
456 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
457
458 return (void *)p;
459
460 _Pragma("GCC diagnostic pop")
461}
462
463
464/*******************************************************************************
465 *
466 *
467 * Other function wrappers
468 *
469 *
470 ******************************************************************************/
471
472/**
473 * @internal
474 * @brief
475 * Generate a type-safe wrapper for sht_new_().
476 *
477 * @param sc Storage class (e.g., `static`). May be empty.
478 * @param ttype Type-safe table type (incomplete).
479 * @param name Wrapper function name.
480 * @param etype Entry type.
481 * @param hashfn Hash function wrapper name.
482 * @param eqfn Equality function wrapper name.
483 * @param freefn Free function wrapper name or `nullptr`.
484 * @param ... Absorbs `nullptr` argument , if free function exists.
485 */
486#define SHT_WRAP_NEW(sc, ttype, name, etype, hashfn, eqfn, freefn, ...) \
487 [[maybe_unused]] \
488 sc ttype *name(void) \
489 { \
490 return (ttype *)sht_new_(hashfn, eqfn, freefn, \
491 sizeof(etype), alignof(etype), \
492 nullptr); \
493 }
494
495/**
496 * @internal
497 * @brief
498 * Generate a type-safe wrapper for sht_set_hash_ctx(), if applicable.
499 *
500 * This macro expands to nothing if the context referent type is empty.
501 *
502 * @param sc Storage class (e.g., `static`). May be empty.
503 * @param name Wrapper function name.
504 * @param ttype Type-safe table type (incomplete).
505 * @param ... Optional context referent type.
506 */
507#define SHT_WRAP_SET_HASH_CTX(sc, name, ttype, ...) \
508 __VA_OPT__( \
509 [[maybe_unused, gnu::nonnull(1)]] \
510 sc void name(ttype *ht, __VA_ARGS__ *context) \
511 { \
512 sht_set_hash_ctx((struct sht_ht *)ht, \
513 sht_strip_const_(context)); \
514 } \
515 )
516
517/**
518 * @internal
519 * @brief
520 * Generate a type-safe wrapper for sht_set_eq_ctx(), if applicable.
521 *
522 * This macro expands to nothing if the context referent type is empty.
523 *
524 * @param sc Storage clas (e.g., `static`). May be empty.
525 * @param name Wrapper function name.
526 * @param ttype Type-safe table type (incomplete).
527 * @param ... Optional context referent type.
528 */
529#define SHT_WRAP_SET_EQ_CTX(sc, name, ttype, ...) \
530 __VA_OPT__( \
531 [[maybe_unused, gnu::nonnull(1)]] \
532 sc void name(ttype *ht, __VA_ARGS__ *context) \
533 { \
534 sht_set_eq_ctx((struct sht_ht *)ht, \
535 sht_strip_const_(context)); \
536 } \
537 )
538
539/**
540 * @internal
541 * @brief
542 * Generate a type-safe wrapper for sht_set_free_ctx(), if applicable.
543 *
544 * This macro expands to nothing if the context referent type is empty.
545 *
546 * @param sc Storage class (e.g., `static`). May be empty.
547 * @param name Wrapper function name.
548 * @param ttype Type-safe table type (incomplete).
549 * @param ... Optional context referent type.
550 */
551#define SHT_WRAP_SET_FREE_CTX(sc, name, ttype, ...) \
552 __VA_OPT__( \
553 [[maybe_unused, gnu::nonnull(1)]] \
554 sc void name(ttype *ht, __VA_ARGS__ *context) \
555 { \
556 sht_set_free_ctx((struct sht_ht *)ht, \
557 sht_strip_const_(context)); \
558 } \
559 )
560
561/**
562 * @internal
563 * @brief
564 * Generate a type-safe wrapper for sht_set_lft().
565 *
566 * @param sc Storage class (e.g., `static`). May be empty.
567 * @param name Wrapper function name.
568 * @param ttype Type-safe table type (incomplete).
569 */
570#define SHT_WRAP_SET_LFT(sc, name, ttype) \
571 [[maybe_unused, gnu::nonnull]] \
572 sc void name(ttype *ht, uint8_t lft) \
573 { \
574 sht_set_lft((struct sht_ht *)ht, lft); \
575 }
576
577/**
578 * @internal
579 * @brief
580 * Generate a type-safe wrapper for sht_set_psl_limit().
581 *
582 * @param sc Storage class (e.g., `static`). May be empty.
583 * @param name Wrapper function name.
584 * @param ttype Type-safe table type (incomplete).
585 */
586#define SHT_WRAP_SET_PSL_LIMIT(sc, name, ttype) \
587 [[maybe_unused, gnu::nonnull]] \
588 sc void name(ttype *ht, uint8_t limit) \
589 { \
590 sht_set_psl_limit((struct sht_ht *)ht, limit); \
591 }
592
593/**
594 * @internal
595 * @brief
596 * Generate a type-safe wrapper for sht_init().
597 *
598 * @param sc Storage class (e.g., `static`). May be empty.
599 * @param name Wrapper function name.
600 * @param ttype Type-safe table type (incomplete).
601 */
602#define SHT_WRAP_INIT(sc, name, ttype) \
603 [[maybe_unused, gnu::nonnull]] \
604 sc bool name(ttype *ht, uint32_t capacity) \
605 { \
606 return sht_init((struct sht_ht *)ht, capacity); \
607 }
608
609/**
610 * @internal
611 * @brief
612 * Generate a type-safe wrapper for sht_free().
613 *
614 * @param sc Storage class (e.g., `static`). May be empty.
615 * @param name Wrapper function name.
616 * @param ttype Type-safe table type (incomplete).
617 */
618#define SHT_WRAP_FREE(sc, name, ttype) \
619 [[maybe_unused, gnu::nonnull]] \
620 sc void name(ttype *ht) \
621 { \
622 sht_free((struct sht_ht *)ht); \
623 }
624
625/**
626 * @internal
627 * @brief
628 * Generate a type-safe wrapper for sht_add().
629 *
630 * @param sc Storage class (e.g., `static`). May be empty.
631 * @param name Wrapper function name.
632 * @param ttype Type-safe table type (incomplete).
633 * @param ktype Key referent type.
634 * @param etype Entry referent type.
635 */
636#define SHT_WRAP_ADD(sc, name, ttype, ktype, etype) \
637 [[maybe_unused, gnu::nonnull]] \
638 sc int name(ttype *ht, const ktype *key, const etype *entry) \
639 { \
640 return sht_add((struct sht_ht *)ht, key, entry); \
641 }
642
643/**
644 * @internal
645 * @brief
646 * Generate a type-safe wrapper for sht_set().
647 *
648 * @param sc Storage class (e.g., `static`). May be empty.
649 * @param name Wrapper function name.
650 * @param ttype Type-safe table type (incomplete).
651 * @param ktype Key referent type.
652 * @param etype Entry referent type.
653 */
654#define SHT_WRAP_SET(sc, name, ttype, ktype, etype) \
655 [[maybe_unused, gnu::nonnull]] \
656 sc int name(ttype *ht, const ktype *key, const etype *entry) \
657 { \
658 return sht_set((struct sht_ht *)ht, key, entry); \
659 }
660
661/**
662 * @internal
663 * @brief
664 * Generate a type-safe wrapper for sht_get().
665 *
666 * @param sc Storage class (e.g., `static`). May be empty.
667 * @param name Wrapper function name.
668 * @param ttype Type-safe table type (incomplete).
669 * @param ktype Key referent type.
670 * @param etype Entry referent type.
671 */
672#define SHT_WRAP_GET(sc, name, ttype, ktype, etype) \
673 [[maybe_unused, gnu::nonnull]] \
674 sc const etype *name(ttype *ht, const ktype *key) \
675 { \
676 return sht_get((struct sht_ht *)ht, key); \
677 }
678
679/**
680 * @internal
681 * @brief
682 * Generate a type-safe wrapper for sht_size().
683 *
684 * @param sc Storage class (e.g., `static`). May be empty.
685 * @param name Wrapper function name.
686 * @param ttype Type-safe table type (incomplete).
687 */
688#define SHT_WRAP_SIZE(sc, name, ttype) \
689 [[maybe_unused, gnu::nonnull]] \
690 sc uint32_t name(const ttype *ht) \
691 { \
692 return sht_size((const struct sht_ht *)ht); \
693 }
694
695/**
696 * @internal
697 * @brief
698 * Generate a type-safe wrapper for sht_empty().
699 *
700 * @param sc Storage class (e.g., `static`). May be empty.
701 * @param name Wrapper function name.
702 * @param ttype Type-safe table type (incomplete).
703 */
704#define SHT_WRAP_EMPTY(sc, name, ttype) \
705 [[maybe_unused, gnu::nonnull]] \
706 sc bool name(const ttype *ht) \
707 { \
708 return sht_empty((const struct sht_ht *)ht); \
709 }
710
711/**
712 * @internal
713 * @brief
714 * Generate a type-safe wrapper for sht_peakk_psl().
715 *
716 * @param sc Storage class (e.g., `static`). May be empty.
717 * @param name Wrapper function name.
718 * @param ttype Type-safe table type (incomplete).
719 */
720#define SHT_WRAP_PEAK_PSL(sc, name, ttype) \
721 [[maybe_unused, gnu::nonnull]] \
722 sc uint8_t name(const ttype *ht) \
723 { \
724 return sht_peak_psl((const struct sht_ht *)ht); \
725 }
726
727/**
728 * @internal
729 * @brief
730 * Generate a type-safe wrapper for sht_delete().
731 *
732 * @param sc Storage class (e.g., `static`). May be empty.
733 * @param name Wrapper function name.
734 * @param ttype Type-safe table type (incomplete).
735 * @param ktype Key referent type.
736 */
737#define SHT_WRAP_DELETE(sc, name, ttype, ktype) \
738 [[maybe_unused, gnu::nonnull]] \
739 sc bool name(ttype *ht, const ktype *key) \
740 { \
741 return sht_delete((struct sht_ht *)ht, key); \
742 }
743
744/**
745 * @internal
746 * @brief
747 * Generate a type-safe wrapper for sht_pop().
748 *
749 * @param sc Storage class (e.g., `static`). May be empty.
750 * @param name Wrapper function name.
751 * @param ttype Type-safe table type (incomplete).
752 * @param ktype Key referent type.
753 * @param etype Entry referent type.
754 */
755#define SHT_WRAP_POP(sc, name, ttype, ktype, etype) \
756 [[maybe_unused, gnu::nonnull]] \
757 sc bool name(ttype *ht, const ktype *restrict key, \
758 etype *restrict out) \
759 { \
760 return sht_pop((struct sht_ht *)ht, key, out); \
761 }
762
763/**
764 * @internal
765 * @brief
766 * Generate a type-safe wrapper for sht_replace().
767 *
768 * @param sc Storage class (e.g., `static`). May be empty.
769 * @param name Wrapper function name.
770 * @param ttype Type-safe table type (incomplete).
771 * @param ktype Key referent type.
772 * @param etype Entry referent type.
773 */
774#define SHT_WRAP_REPLACE(sc, name, ttype, ktype, etype) \
775 [[maybe_unused, gnu::nonnull]] \
776 sc bool name(ttype *ht, const ktype *key, const etype *entry) \
777 { \
778 return sht_replace((struct sht_ht *)ht, key, entry); \
779 }
780
781/**
782 * @internal
783 * @brief
784 * Generate a type-safe wrapper for sht_swap().
785 *
786 * @param sc Storage class (e.g., `static`). May be empty.
787 * @param name Wrapper function name.
788 * @param ttype Type-safe table type (incomplete).
789 * @param ktype Key referent type.
790 * @param etype Entry referent type.
791 */
792#define SHT_WRAP_SWAP(sc, name, ttype, ktype, etype) \
793 [[maybe_unused, gnu::nonnull]] \
794 sc bool name(ttype *ht, const ktype *key, \
795 const etype *entry, etype *out) \
796 { \
797 return sht_swap((struct sht_ht *)ht, key, entry, out); \
798 }
799
800/**
801 * @internal
802 * @brief
803 * Generate a type-safe wrapper for sht_iter_new().
804 *
805 * @param sc Storage class (e.g., `static`). May be empty.
806 * @param name Wrapper function name.
807 * @param ttype Type-safe table type (incomplete).
808 * @param itype Type-safe iterator type (incomplete).
809 */
810#define SHT_WRAP_ITER_NEW(sc, name, ttype, itype) \
811 [[maybe_unused, gnu::nonnull]] \
812 sc itype *name(ttype *ht, enum sht_iter_type type) \
813 { \
814 return (itype *)sht_iter_new((struct sht_ht *)ht, \
815 type); \
816 }
817
818/**
819 * @internal
820 * @brief
821 * Generate a type-safe wrapper for sht_iter_free().
822 *
823 * @param sc Storage class (e.g., `static`). May be empty.
824 * @param name Wrapper function name.
825 * @param itype Type-safe iterator type (incomplete).
826 */
827#define SHT_WRAP_ITER_FREE(sc, name, itype) \
828 [[maybe_unused, gnu::nonnull]] \
829 sc void name(itype *iter) \
830 { \
831 sht_iter_free((struct sht_iter *)iter); \
832 }
833
834/**
835 * @internal
836 * @brief
837 * Generate a type-safe wrapper for sht_iter_next().
838 *
839 * @param sc Storage class (e.g., `static`). May be empty.
840 * @param name Wrapper function name.
841 * @param itype Type-safe iterator type (incomplete).
842 * @param etype Entry referent type.
843 */
844#define SHT_WRAP_ITER_NEXT(sc, name, itype, etype) \
845 [[maybe_unused, gnu::nonnull]] \
846 sc const etype *name(itype *iter) \
847 { \
848 return sht_iter_next((struct sht_iter *)iter); \
849 }
850
851/**
852 * @internal
853 * @brief
854 * Generate a type-safe wrapper for sht_iter_delete().
855 *
856 * @param sc Storage class (e.g., `static`). May be empty.
857 * @param name Wrapper function name.
858 * @param itype Type-safe iterator type (incomplete).
859 */
860#define SHT_WRAP_ITER_DELETE(sc, name, itype) \
861 [[maybe_unused, gnu::nonnull]] \
862 sc bool name(itype *iter) \
863 { \
864 return sht_iter_delete((struct sht_iter *)iter); \
865 }
866
867/**
868 * @internal
869 * @brief
870 * Generate a type-safe wrapper for sht_iter_replace().
871 *
872 * @param sc Storage class (e.g., `static`). May be empty.
873 * @param name Wrapper function name.
874 * @param itype Type-safe iterator type (incomplete).
875 * @param etype Entry referent type.
876 */
877#define SHT_WRAP_ITER_REPLACE(sc, name, itype, etype) \
878 [[maybe_unused, gnu::nonnull]] \
879 sc bool name(itype *iter, const etype *entry) \
880 { \
881 return sht_iter_replace((struct sht_iter *)iter, \
882 entry); \
883 }
884
885/**
886 * @internal
887 * @brief
888 * Generate a type-safe wrapper for sht_get_err().
889 *
890 * @param sc Storage class (e.g., `static`). May be empty.
891 * @param name Wrapper function name.
892 * @param ttype Type-safe table type (incomplete).
893 */
894#define SHT_WRAP_GET_ERR(sc, name, ttype) \
895 [[maybe_unused, gnu::nonnull]] \
896 sc enum sht_err name(ttype *ht) \
897 { \
898 return sht_get_err((struct sht_ht *)ht); \
899 }
900
901/**
902 * @internal
903 * @brief
904 * Generate a type-safe wrapper for sht_get_msg().
905 *
906 * @param sc Storage class (e.g., `static`). May be empty.
907 * @param name Wrapper function name.
908 * @param ttype Type-safe table type (incomplete).
909 */
910#define SHT_WRAP_GET_MSG(sc, name, ttype) \
911 [[maybe_unused, gnu::nonnull]] \
912 sc const char *name(ttype *ht) \
913 { \
914 return sht_get_msg((struct sht_ht *)ht); \
915 }
916
917/**
918 * @internal
919 * @brief
920 * Generate a type-safe wrapper for sht_iter_err().
921 *
922 * @param sc Storage class (e.g., `static`). May be empty.
923 * @param name Wrapper function name.
924 * @param itype Type-safe iterator type (incomplete).
925 */
926#define SHT_WRAP_ITER_ERR(sc, name, itype) \
927 [[maybe_unused, gnu::nonnull]] \
928 sc enum sht_err name(itype *iter) \
929 { \
930 return sht_iter_err((struct sht_iter *)iter); \
931 }
932
933/**
934 * @internal
935 * @brief
936 * Generate a type-safe wrapper for sht_iter_msg().
937 *
938 * @param sc Storage class (e.g., `static`). May be empty.
939 * @param name Wrapper function name.
940 * @param itype Type-safe iterator type (incomplete).
941 */
942#define SHT_WRAP_ITER_MSG(sc, name, itype) \
943 [[maybe_unused, gnu::nonnull]] \
944 sc const char *name(itype *iter) \
945 { \
946 return sht_iter_msg((struct sht_iter *)iter); \
947 }
948
949
950/*******************************************************************************
951 *
952 *
953 * Table type helpers
954 *
955 *
956 ******************************************************************************/
957
958
959/*
960 *
961 * Function names
962 *
963 */
964
965/**
966 * @internal
967 * @brief
968 * Generate a function name.
969 *
970 * @param ttspec Table type spec.
971 * @param base Function name base.
972 */
973#define SHT_FN_NAME(ttspec, base) SHT_CONCAT(SHT_FOSR_REQ(ttspec), base)
974
975/**
976 * @internal
977 * @brief
978 * Generate a hash function wrapper name.
979 *
980 * @param ttspec Table type spec.
981 */
982#define SHT_HF_NAME(ttspec) SHT_FN_NAME(ttspec, _hash_wrapper_)
983
984/**
985 * @internal
986 * @brief
987 * Generate an equalify function wrapper name.
988 *
989 * @param ttspec Table type spec.
990 */
991#define SHT_EF_NAME(ttspec) SHT_FN_NAME(ttspec, _eq_wrapper_)
992
993/**
994 * @internal
995 * @brief
996 * Generate a free function wrapper name.
997 *
998 * @param ttspec Table type spec.
999 */
1000#define SHT_FF_NAME(ttspec) SHT_FN_NAME(ttspec, _free_wrapper_)
1001
1002
1003/*
1004 *
1005 * Type names
1006 *
1007 */
1008
1009/**
1010 * @internal
1011 * @brief
1012 * Generate a type-safe table type name.
1013 *
1014 * @param ttspec Table type spec.
1015 */
1016#define SHT_HT_T(ttspec) \
1017 struct SHT_CONCAT(SHT_FOSR_REQ(ttspec), _ht)
1018
1019/**
1020 * @internal
1021 * @brief
1022 * Generate a type-safe iterator type name.
1023 *
1024 * @param ttspec Table type spec.
1025 */
1026#define SHT_ITER_T(ttspec) \
1027 struct SHT_CONCAT(SHT_FOSR_REQ(ttspec), _iter)
1028
1029
1030/*
1031 *
1032 * Function storage class
1033 *
1034 * (Callback functions are always static.)
1035 *
1036 */
1037
1038/**
1039 * @internal
1040 * @brief
1041 * Expands to nothing.
1042 */
1043#define SHT_FN_SC_PROBE_extern
1044
1045/**
1046 * @internal
1047 * @brief
1048 * Expands to nothing if (pre-expanded) @p sc is `extern`, otherwise @p sc.
1049 *
1050 * > **NOTE**
1051 * >
1052 * > This macro relies on the fact that `SHT_FN_SC_PROBE_##sc` is not defined
1053 * > for any value of @p sc other than `extern`.
1054 *
1055 * @param sc The expanded storage class from the table type spec,
1056 * with an empty value replaced by `static`.
1057 */
1058#define SHT_EXTERN_2_EMPTY_NX(sc) SHT_IF_ELSE(sc, , SHT_FN_SC_PROBE_##sc)
1059
1060/**
1061 * @internal
1062 * @brief
1063 * Forces expansion of @p sc before invoking SHT_EXTERN_2_EMPTY_NX().
1064 *
1065 * @param sc The unexpanded storage class from the table type spec,
1066 * with an empty value replaced by `static`.
1067 */
1068#define SHT_EXTERN_2_EMPTY(sc) SHT_EXTERN_2_EMPTY_NX(sc)
1069
1070/**
1071 * @internal
1072 * @brief
1073 * Expands to `static` if @p sc is empty; otherwise expands to @p sc.
1074 *
1075 * @param sc The storage class from the table type spec, which may be
1076 * empty.
1077 */
1078#define SHT_EMPTY_2_STATIC(sc) SHT_IF_ELSE(sc, static, sc)
1079
1080/**
1081 * @internal
1082 * @brief
1083 * Generates the storage class for a generated function.
1084 *
1085 * Callback function wrappers are always `static`. Other generated functions
1086 * default to `static`, if no storage class is specified in the table type spec.
1087 * but this can be changed by specifying a storage class of `extern`, which will
1088 * suppress the default `static`. Any other storage class will be applied to
1089 * the generated functions unchanged.
1090 *
1091 * In summary:
1092 *
1093 * * (Nothing) → `static`
1094 * * `extern` → (nothing)
1095 * * (Anything else) → (unchanged)
1096 */
1097#define SHT_FN_SC(ttspec) \
1098 SHT_EXTERN_2_EMPTY( \
1099 SHT_EMPTY_2_STATIC( \
1100 SHT_FOSR_OPT(ttspec) \
1101 ) \
1102 )
1103
1104
1105
1106/*******************************************************************************
1107 *
1108 *
1109 * Table type macro
1110 *
1111 *
1112 ******************************************************************************/
1113
1114/**
1115 * Generate types and functions for a type-safe hash table type.
1116 *
1117 * @param ttspec Table type spec &mdash; a 1- or 2-member tuple that
1118 * contains an optional storage class (e.g., `static`)
1119 * followed by a required name prefix. If a storage class
1120 * is specified, the tuple must be enclosed in parentheses.
1121 * Thus, the following formats are allowed.
1122 * * `prefix`
1123 * * `(prefix)`
1124 * * `(, prefix)`
1125 * * `(storage_class, prefix)`
1126 *
1127 * @param ktype The type of the table's keys. For example, if the
1128 * type-safe hash and equality functions accept a
1129 * `const char *` as their `key` argument, then @p ktype
1130 * should be `char`.
1131 *
1132 * @param etype The type of the table's entries. If the type-safe
1133 * equality and free functions (if any) accept a
1134 * `const struct foo_entry *`, then @p etype should be
1135 * `struct foo_entry`.
1136 *
1137 * @param hfspec Hash function spec &mdash; a 1- or 2-member tuple that
1138 * contains a required type-safe hash function name
1139 * followed by an optional hash function context type. For
1140 * example, if the type-safe hash function accepts a
1141 * `const uint32_t *` as its `context` argument, then the
1142 * context type should be `const uint32_t`. (Context
1143 * pointers may be either `const`-qualified or non-`const`,
1144 * depending on the needs of the application.) If a
1145 * context type is specified, the tuple must be enclosed in
1146 * parentheses. Thus, the following formats are allowed.
1147 * * `function_name`
1148 * * `(function_name)`
1149 * * `(function_name, )`
1150 * * `(function_name, context_type)`
1151 *
1152 * @param efspec Equality function spec &mdash; a 1- or 2-member tuple
1153 * that contains a required type-safe equality function
1154 * name followed by an optional context type. (See
1155 * @p hfspec for the allowed formats.)
1156 *
1157 * @param ... **Optional** free function spec &mdash; a 1- or 2-member
1158 * tuple that contains a required (if the spec if present)
1159 * type-safe free function name followed by an optional
1160 * context type. (See @p hfspec for the allowed formats.)
1161 */
1162#define SHT_TABLE_TYPE(ttspec, ktype, etype, hfspec, efspec, ...) \
1163 \
1164 /* Entry size check */ \
1165 static_assert(sizeof(etype) <= SHT_MAX_ESIZE, \
1166 SHT_STR(Entry type (etype) too large)); \
1167 \
1168 /* Incomplete type that represents a table */ \
1169 SHT_HT_T(ttspec); \
1170 \
1171 /* Incomplete type that represents an iterator */ \
1172 SHT_ITER_T(ttspec); \
1173 \
1174 /* Hash function wrapper */ \
1175 SHT_MKHASHFN( \
1176 SHT_HF_NAME(ttspec), /* name */ \
1177 ktype, /* ktype */ \
1178 SHT_FRSO_REQ(hfspec), /* hashfn */ \
1179 SHT_FRSO_OPT(hfspec) /* ...? */ \
1180 ) \
1181 \
1182 /* Equality function wrapper */ \
1183 SHT_MKEQFN( \
1184 SHT_EF_NAME(ttspec), /* name */ \
1185 ktype, /* ktype */ \
1186 etype, /* etype */ \
1187 SHT_FRSO_REQ(efspec), /* eqfn */ \
1188 SHT_FRSO_OPT(efspec) /* ...? */ \
1189 ) \
1190 \
1191 /* Free function wrapper, if necessary */ \
1192 __VA_OPT__( \
1193 SHT_MKFREEFN( \
1194 SHT_FF_NAME(ttspec), /* name */ \
1195 etype, /* etype */ \
1196 SHT_FRSO_REQ(__VA_ARGS__), /* freefn */ \
1197 SHT_FRSO_OPT(__VA_ARGS__) /* ...? */ \
1198 ) \
1199 ) \
1200 \
1201 /* sht_new_() wrapper */ \
1202 SHT_WRAP_NEW( \
1203 SHT_FN_SC(ttspec), /* sc */ \
1204 SHT_HT_T(ttspec), /* ttype */ \
1205 SHT_FN_NAME(ttspec, _new), /* name */ \
1206 etype, /* etype */ \
1207 SHT_HF_NAME(ttspec), /* hashfn */ \
1208 SHT_EF_NAME(ttspec), /* eqfn */ \
1209 __VA_OPT__(SHT_FF_NAME(ttspec),) /* freefn? */ \
1210 nullptr /* freefn? */ \
1211 ) \
1212 \
1213 /* sht_set_hash_ctx() wrapper */ \
1214 SHT_WRAP_SET_HASH_CTX( \
1215 SHT_FN_SC(ttspec), /* sc */ \
1216 SHT_FN_NAME(ttspec, _set_hash_ctx), /* name */ \
1217 SHT_HT_T(ttspec), /* ttype */ \
1218 SHT_FRSO_OPT(hfspec) /* ...? */ \
1219 ) \
1220 \
1221 /* sht_set_eq_ctx() wrapper */ \
1222 SHT_WRAP_SET_EQ_CTX( \
1223 SHT_FN_SC(ttspec), /* sc */ \
1224 SHT_FN_NAME(ttspec, _set_eq_ctx), /* name */ \
1225 SHT_HT_T(ttspec), /* ttype */ \
1226 SHT_FRSO_OPT(efspec) /* ...? */ \
1227 ) \
1228 \
1229 /* sht_set_free_ctx() wrapper, if necessary */ \
1230 __VA_OPT__( \
1231 SHT_WRAP_SET_FREE_CTX( \
1232 SHT_FN_SC(ttspec), /* sc */ \
1233 SHT_FN_NAME(ttspec, /* name */ \
1234 _set_free_ctx), \
1235 SHT_HT_T(ttspec), /* ttype */ \
1236 SHT_FRSO_OPT(__VA_ARGS__) /* ...? */ \
1237 ) \
1238 ) \
1239 \
1240 /* sht_set_lft() wrapper */ \
1241 SHT_WRAP_SET_LFT( \
1242 SHT_FN_SC(ttspec), /* sc */ \
1243 SHT_FN_NAME(ttspec, _set_lft), /* name */ \
1244 SHT_HT_T(ttspec) /* ttype */ \
1245 ) \
1246 \
1247 /* sht_set_psl_limit() wrapper */ \
1248 SHT_WRAP_SET_PSL_LIMIT( \
1249 SHT_FN_SC(ttspec), /* sc */ \
1250 SHT_FN_NAME(ttspec, _set_psl_limit), /* name */ \
1251 SHT_HT_T(ttspec) /* ttype */ \
1252 ) \
1253 \
1254 /* sht_init() wrapper */ \
1255 SHT_WRAP_INIT( \
1256 SHT_FN_SC(ttspec), /* sc */ \
1257 SHT_FN_NAME(ttspec, _init), /* name */ \
1258 SHT_HT_T(ttspec) /* ttype */ \
1259 ) \
1260 \
1261 /* sht_free() wrapper */ \
1262 SHT_WRAP_FREE( \
1263 SHT_FN_SC(ttspec), /* sc */ \
1264 SHT_FN_NAME(ttspec, _free), /* name */ \
1265 SHT_HT_T(ttspec) /* ttype */ \
1266 ) \
1267 \
1268 /* sht_add() wrapper */ \
1269 SHT_WRAP_ADD( \
1270 SHT_FN_SC(ttspec), /* sc */ \
1271 SHT_FN_NAME(ttspec, _add), /* name */ \
1272 SHT_HT_T(ttspec), /* ttype */ \
1273 ktype, /* ktype */ \
1274 etype /* etype */ \
1275 ) \
1276 \
1277 /* sht_set() wrapper */ \
1278 SHT_WRAP_SET( \
1279 SHT_FN_SC(ttspec), /* sc */ \
1280 SHT_FN_NAME(ttspec, _set), /* name */ \
1281 SHT_HT_T(ttspec), /* ttype */ \
1282 ktype, /* ktype */ \
1283 etype /* etype */ \
1284 ) \
1285 \
1286 /* sht_get() wrapper */ \
1287 SHT_WRAP_GET( \
1288 SHT_FN_SC(ttspec), /* sc */ \
1289 SHT_FN_NAME(ttspec, _get), /* name */ \
1290 SHT_HT_T(ttspec), /* ttype */ \
1291 ktype, /* ktype */ \
1292 etype /* etype */ \
1293 ) \
1294 \
1295 /* sht_size() wrapper */ \
1296 SHT_WRAP_SIZE( \
1297 SHT_FN_SC(ttspec), /* sc */ \
1298 SHT_FN_NAME(ttspec, _size), /* name */ \
1299 SHT_HT_T(ttspec) /* ttype */ \
1300 ) \
1301 \
1302 /* sht_empty() wrapper */ \
1303 SHT_WRAP_EMPTY( \
1304 SHT_FN_SC(ttspec), /* sc */ \
1305 SHT_FN_NAME(ttspec, _empty), /* name */ \
1306 SHT_HT_T(ttspec) /* ttype */ \
1307 ) \
1308 \
1309 /* sht_peak_psl() wrapper */ \
1310 SHT_WRAP_PEAK_PSL( \
1311 SHT_FN_SC(ttspec), /* sc */ \
1312 SHT_FN_NAME(ttspec, _peak_psl), /* name */ \
1313 SHT_HT_T(ttspec) /* ttype */ \
1314 ) \
1315 \
1316 /* sht_delete() wrapper */ \
1317 SHT_WRAP_DELETE( \
1318 SHT_FN_SC(ttspec), /* sc */ \
1319 SHT_FN_NAME(ttspec, _delete), /* name */ \
1320 SHT_HT_T(ttspec), /* ttype */ \
1321 ktype /* ktype */ \
1322 ) \
1323 \
1324 /* sht_pop() wrapper */ \
1325 SHT_WRAP_POP( \
1326 SHT_FN_SC(ttspec), /* sc */ \
1327 SHT_FN_NAME(ttspec, _pop), /* name */ \
1328 SHT_HT_T(ttspec), /* ttype */ \
1329 ktype, /* ktype */ \
1330 etype /* etype */ \
1331 ) \
1332 \
1333 /* sht_replace() wrapper */ \
1334 SHT_WRAP_REPLACE( \
1335 SHT_FN_SC(ttspec), /* sc */ \
1336 SHT_FN_NAME(ttspec, _replace), /* name */ \
1337 SHT_HT_T(ttspec), /* ttype */ \
1338 ktype, /* ktype */ \
1339 etype /* etype */ \
1340 ) \
1341 \
1342 /* sht_swap() wrapper */ \
1343 SHT_WRAP_SWAP( \
1344 SHT_FN_SC(ttspec), /* sc */ \
1345 SHT_FN_NAME(ttspec, _swap), /* name */ \
1346 SHT_HT_T(ttspec), /* ttype */ \
1347 ktype, /* ktype */ \
1348 etype /* etype */ \
1349 ) \
1350 \
1351 /* sht_iter_new() wrapper */ \
1352 SHT_WRAP_ITER_NEW( \
1353 SHT_FN_SC(ttspec), /* sc */ \
1354 SHT_FN_NAME(ttspec, _iter_new), /* name */ \
1355 SHT_HT_T(ttspec), /* ttype */ \
1356 SHT_ITER_T(ttspec) /* itype */ \
1357 ) \
1358 \
1359 /* sht_iter_free() wrapper */ \
1360 SHT_WRAP_ITER_FREE( \
1361 SHT_FN_SC(ttspec), /* sc */ \
1362 SHT_FN_NAME(ttspec, _iter_free), /* name */ \
1363 SHT_ITER_T(ttspec) /* itype */ \
1364 ) \
1365 \
1366 /* sht_iter_next() wrapper */ \
1367 SHT_WRAP_ITER_NEXT( \
1368 SHT_FN_SC(ttspec), /* sc */ \
1369 SHT_FN_NAME(ttspec, _iter_next), /* name */ \
1370 SHT_ITER_T(ttspec), /* itype */ \
1371 etype /* etype */ \
1372 ) \
1373 \
1374 /* sht_iter_delete() wrapper */ \
1375 SHT_WRAP_ITER_DELETE( \
1376 SHT_FN_SC(ttspec), /* sc */ \
1377 SHT_FN_NAME(ttspec, _iter_delete), /* name */ \
1378 SHT_ITER_T(ttspec) /* itype */ \
1379 ) \
1380 \
1381 /* sht_iter_replace() wrapper */ \
1382 SHT_WRAP_ITER_REPLACE( \
1383 SHT_FN_SC(ttspec), /* sc */ \
1384 SHT_FN_NAME(ttspec, _iter_replace), /* name */ \
1385 SHT_ITER_T(ttspec), /* itype */ \
1386 etype /* etype */ \
1387 ) \
1388 \
1389 /* sht_get_err() wrapper */ \
1390 SHT_WRAP_GET_ERR( \
1391 SHT_FN_SC(ttspec), /* sc */ \
1392 SHT_FN_NAME(ttspec, _get_err), /* name */ \
1393 SHT_HT_T(ttspec) /* ttype */ \
1394 ) \
1395 \
1396 /* sht_get_msg() wrapper */ \
1397 SHT_WRAP_GET_MSG( \
1398 SHT_FN_SC(ttspec), /* sc */ \
1399 SHT_FN_NAME(ttspec, _get_msg), /* name */ \
1400 SHT_HT_T(ttspec) /* ttype */ \
1401 ) \
1402 \
1403 /* sht_iter_err() wrapper */ \
1404 SHT_WRAP_ITER_ERR( \
1405 SHT_FN_SC(ttspec), /* sc */ \
1406 SHT_FN_NAME(ttspec, _iter_err), /* name */ \
1407 SHT_ITER_T(ttspec) /* itype */ \
1408 ) \
1409 \
1410 /* sht_iter_msg() wrapper */ \
1411 SHT_WRAP_ITER_MSG( \
1412 SHT_FN_SC(ttspec), /* sc */ \
1413 SHT_FN_NAME(ttspec, _iter_msg), /* name */ \
1414 SHT_ITER_T(ttspec) /* itype */ \
1415 )
1416
1417
1418#endif // SHT_TS_H
SHT library API.