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 — 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 —
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
*/
453
static
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 — 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 — 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 — 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 — 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.h
SHT library API.
src
sht-ts.h
Generated by
1.15.0