|
1 | 1 | /* Licensed under LGPLv2+ - see LICENSE file for details */ |
2 | 2 | #ifndef CCAN_HTABLE_TYPE_H |
3 | 3 | #define CCAN_HTABLE_TYPE_H |
| 4 | +#include "config.h" |
| 5 | +#include <assert.h> |
4 | 6 | #include <ccan/htable/htable.h> |
5 | 7 | #include <ccan/compiler/compiler.h> |
6 | | -#include "config.h" |
7 | 8 |
|
8 | 9 | /** |
9 | | - * HTABLE_DEFINE_TYPE - create a set of htable ops for a type |
| 10 | + * HTABLE_DEFINE_NODUPS_TYPE/HTABLE_DEFINE_DUPS_TYPE - create a set of htable ops for a type |
10 | 11 | * @type: a type whose pointers will be values in the hash. |
11 | 12 | * @keyof: a function/macro to extract a key: <keytype> @keyof(const type *elem) |
12 | 13 | * @hashfn: a hash function for a @key: size_t @hashfn(const <keytype> *) |
13 | 14 | * @eqfn: an equality function keys: bool @eqfn(const type *, const <keytype> *) |
14 | 15 | * @prefix: a prefix for all the functions to define (of form <name>_*) |
15 | 16 | * |
16 | | - * NULL values may not be placed into the hash table. |
| 17 | + * There are two variants, one of which allows duplicate keys, and one which |
| 18 | + * does not. The defined functions differ in some cases, as shown below. |
| 19 | + * |
| 20 | + * NULL values may not be placed into the hash table (nor (void *)1). |
17 | 21 | * |
18 | 22 | * This defines the type hashtable type and an iterator type: |
19 | 23 | * struct <name>; |
|
33 | 37 | * |
34 | 38 | * Delete and delete-by key return true if it was in the set: |
35 | 39 | * bool <name>_del(struct <name> *ht, const <type> *e); |
36 | | - * bool <name>_delkey(struct <name> *ht, const <keytype> *k); |
| 40 | + * bool <name>_delkey(struct <name> *ht, const <keytype> *k) (NODUPS only); |
37 | 41 | * |
38 | 42 | * Delete by iterator: |
39 | 43 | * bool <name>_delval(struct <name> *ht, struct <name>_iter *i); |
40 | 44 | * |
41 | | - * Find and return the (first) matching element, or NULL: |
42 | | - * type *<name>_get(const struct @name *ht, const <keytype> *k); |
| 45 | + * Find and return the matching element, or NULL: |
| 46 | + * type *<name>_get(const struct @name *ht, const <keytype> *k) (NODUPS only); |
43 | 47 | * |
44 | | - * Find and return all matching elements, or NULL: |
| 48 | + * Test for an element: |
| 49 | + * bool <name>_exists(const struct @name *ht, const <keytype> *k); |
| 50 | + * |
| 51 | + * Find and return all matching elements, or NULL (DUPS only): |
45 | 52 | * type *<name>_getfirst(const struct @name *ht, const <keytype> *k, |
46 | 53 | * struct <name>_iter *i); |
47 | 54 | * type *<name>_getnext(const struct @name *ht, const <keytype> *k, |
|
59 | 66 | * You can use HTABLE_INITIALIZER like so: |
60 | 67 | * struct <name> ht = { HTABLE_INITIALIZER(ht.raw, <name>_hash, NULL) }; |
61 | 68 | */ |
62 | | -#define HTABLE_DEFINE_TYPE(type, keyof, hashfn, eqfn, name) \ |
| 69 | +#define HTABLE_DEFINE_TYPE_CORE(type, keyof, hashfn, eqfn, name) \ |
63 | 70 | struct name { struct htable raw; }; \ |
64 | 71 | struct name##_iter { struct htable_iter i; }; \ |
65 | 72 | static inline size_t name##_hash(const void *elem, void *priv) \ |
|
89 | 96 | { \ |
90 | 97 | return htable_copy(&dst->raw, &src->raw); \ |
91 | 98 | } \ |
92 | | - static inline bool name##_add(struct name *ht, const type *elem) \ |
93 | | - { \ |
94 | | - return htable_add(&ht->raw, hashfn(keyof(elem)), elem); \ |
95 | | - } \ |
96 | 99 | static inline UNNEEDED bool name##_del(struct name *ht, \ |
97 | 100 | const type *elem) \ |
98 | 101 | { \ |
99 | 102 | return htable_del(&ht->raw, hashfn(keyof(elem)), elem); \ |
100 | 103 | } \ |
101 | | - static inline UNNEEDED type *name##_get(const struct name *ht, \ |
102 | | - const HTABLE_KTYPE(keyof, type) k) \ |
103 | | - { \ |
104 | | - struct htable_iter i; \ |
105 | | - size_t h = hashfn(k); \ |
106 | | - void *c; \ |
107 | | - \ |
108 | | - for (c = htable_firstval(&ht->raw,&i,h); \ |
109 | | - c; \ |
110 | | - c = htable_nextval(&ht->raw,&i,h)) { \ |
111 | | - if (eqfn(c, k)) \ |
112 | | - return c; \ |
113 | | - } \ |
114 | | - return NULL; \ |
115 | | - } \ |
116 | 104 | static inline UNNEEDED type *name##_getmatch_(const struct name *ht, \ |
117 | 105 | const HTABLE_KTYPE(keyof, type) k, \ |
118 | 106 | size_t h, \ |
119 | 107 | type *v, \ |
120 | | - struct name##_iter *iter) \ |
| 108 | + struct htable_iter *iter) \ |
121 | 109 | { \ |
122 | 110 | while (v) { \ |
123 | 111 | if (eqfn(v, k)) \ |
124 | 112 | break; \ |
125 | | - v = htable_nextval(&ht->raw, &iter->i, h); \ |
| 113 | + v = htable_nextval(&ht->raw, iter, h); \ |
126 | 114 | } \ |
127 | 115 | return v; \ |
128 | 116 | } \ |
129 | | - static inline UNNEEDED type *name##_getfirst(const struct name *ht, \ |
130 | | - const HTABLE_KTYPE(keyof, type) k, \ |
131 | | - struct name##_iter *iter) \ |
132 | | - { \ |
133 | | - size_t h = hashfn(k); \ |
134 | | - type *v = htable_firstval(&ht->raw, &iter->i, h); \ |
135 | | - return name##_getmatch_(ht, k, h, v, iter); \ |
136 | | - } \ |
137 | | - static inline UNNEEDED type *name##_getnext(const struct name *ht, \ |
138 | | - const HTABLE_KTYPE(keyof, type) k, \ |
139 | | - struct name##_iter *iter) \ |
| 117 | + static inline UNNEEDED bool name##_exists(const struct name *ht, \ |
| 118 | + const HTABLE_KTYPE(keyof, type) k) \ |
140 | 119 | { \ |
| 120 | + struct htable_iter i; \ |
141 | 121 | size_t h = hashfn(k); \ |
142 | | - type *v = htable_nextval(&ht->raw, &iter->i, h); \ |
143 | | - return name##_getmatch_(ht, k, h, v, iter); \ |
144 | | - } \ |
145 | | - static inline UNNEEDED bool name##_delkey(struct name *ht, \ |
146 | | - const HTABLE_KTYPE(keyof, type) k) \ |
147 | | - { \ |
148 | | - type *elem = name##_get(ht, k); \ |
149 | | - if (elem) \ |
150 | | - return name##_del(ht, elem); \ |
151 | | - return false; \ |
| 122 | + void *v; \ |
| 123 | + \ |
| 124 | + v = htable_firstval(&ht->raw, &i, h); \ |
| 125 | + return name##_getmatch_(ht, k, h, v, &i) != NULL; \ |
152 | 126 | } \ |
153 | 127 | static inline UNNEEDED void name##_delval(struct name *ht, \ |
154 | 128 | struct name##_iter *iter) \ |
|
177 | 151 | return htable_prev(&ht->raw, &iter->i); \ |
178 | 152 | } |
179 | 153 |
|
| 154 | +#define HTABLE_DEFINE_NODUPS_TYPE(type, keyof, hashfn, eqfn, name) \ |
| 155 | + HTABLE_DEFINE_TYPE_CORE(type, keyof, hashfn, eqfn, name) \ |
| 156 | + static inline UNNEEDED type *name##_get(const struct name *ht, \ |
| 157 | + const HTABLE_KTYPE(keyof, type) k) \ |
| 158 | + { \ |
| 159 | + struct htable_iter i; \ |
| 160 | + size_t h = hashfn(k); \ |
| 161 | + void *v; \ |
| 162 | + \ |
| 163 | + v = htable_firstval(&ht->raw, &i, h); \ |
| 164 | + return name##_getmatch_(ht, k, h, v, &i); \ |
| 165 | + } \ |
| 166 | + static inline bool name##_add(struct name *ht, const type *elem) \ |
| 167 | + { \ |
| 168 | + /* Open-coded for slightly more efficiency */ \ |
| 169 | + const HTABLE_KTYPE(keyof, type) k = keyof(elem); \ |
| 170 | + struct htable_iter i; \ |
| 171 | + size_t h = hashfn(k); \ |
| 172 | + void *v; \ |
| 173 | + \ |
| 174 | + v = htable_firstval(&ht->raw, &i, h); \ |
| 175 | + assert(!name##_getmatch_(ht, k, h, v, &i)); \ |
| 176 | + return htable_add(&ht->raw, h, elem); \ |
| 177 | + } \ |
| 178 | + static inline UNNEEDED bool name##_delkey(struct name *ht, \ |
| 179 | + const HTABLE_KTYPE(keyof, type) k) \ |
| 180 | + { \ |
| 181 | + type *elem = name##_get(ht, k); \ |
| 182 | + if (elem) \ |
| 183 | + return name##_del(ht, elem); \ |
| 184 | + return false; \ |
| 185 | + } |
| 186 | + |
| 187 | +#define HTABLE_DEFINE_DUPS_TYPE(type, keyof, hashfn, eqfn, name) \ |
| 188 | + HTABLE_DEFINE_TYPE_CORE(type, keyof, hashfn, eqfn, name) \ |
| 189 | + static inline bool name##_add(struct name *ht, const type *elem) \ |
| 190 | + { \ |
| 191 | + const HTABLE_KTYPE(keyof, type) k = keyof(elem); \ |
| 192 | + return htable_add(&ht->raw, hashfn(k), elem); \ |
| 193 | + } \ |
| 194 | + static inline UNNEEDED type *name##_getfirst(const struct name *ht, \ |
| 195 | + const HTABLE_KTYPE(keyof, type) k, \ |
| 196 | + struct name##_iter *iter) \ |
| 197 | + { \ |
| 198 | + size_t h = hashfn(k); \ |
| 199 | + type *v = htable_firstval(&ht->raw, &iter->i, h); \ |
| 200 | + return name##_getmatch_(ht, k, h, v, &iter->i); \ |
| 201 | + } \ |
| 202 | + static inline UNNEEDED type *name##_getnext(const struct name *ht, \ |
| 203 | + const HTABLE_KTYPE(keyof, type) k, \ |
| 204 | + struct name##_iter *iter) \ |
| 205 | + { \ |
| 206 | + size_t h = hashfn(k); \ |
| 207 | + type *v = htable_nextval(&ht->raw, &iter->i, h); \ |
| 208 | + return name##_getmatch_(ht, k, h, v, &iter->i); \ |
| 209 | + } |
| 210 | + |
| 211 | + |
180 | 212 | #if HAVE_TYPEOF |
181 | 213 | #define HTABLE_KTYPE(keyof, type) typeof(keyof((const type *)NULL)) |
182 | 214 | #else |
|
0 commit comments