Skip to content

Commit b6c1ffa

Browse files
committed
ccan/htable: update to explicit DUPS/NODUPS types.
The updated API requires typed htables to explicitly state whether they allow duplicates: for most cases we don't, but we've had issues in the past. This is a big patch, but mainly mechanical. Signed-off-by: Rusty Russell <[email protected]>
1 parent 5cecdd7 commit b6c1ffa

37 files changed

+237
-182
lines changed

ccan/README

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
CCAN imported from http://ccodearchive.net.
22

3-
CCAN version: init-2589-g161fe383
3+
CCAN version: init-2590-gaf04734d

ccan/ccan/htable/htable_type.h

Lines changed: 82 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
/* Licensed under LGPLv2+ - see LICENSE file for details */
22
#ifndef CCAN_HTABLE_TYPE_H
33
#define CCAN_HTABLE_TYPE_H
4+
#include "config.h"
5+
#include <assert.h>
46
#include <ccan/htable/htable.h>
57
#include <ccan/compiler/compiler.h>
6-
#include "config.h"
78

89
/**
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
1011
* @type: a type whose pointers will be values in the hash.
1112
* @keyof: a function/macro to extract a key: <keytype> @keyof(const type *elem)
1213
* @hashfn: a hash function for a @key: size_t @hashfn(const <keytype> *)
1314
* @eqfn: an equality function keys: bool @eqfn(const type *, const <keytype> *)
1415
* @prefix: a prefix for all the functions to define (of form <name>_*)
1516
*
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).
1721
*
1822
* This defines the type hashtable type and an iterator type:
1923
* struct <name>;
@@ -33,15 +37,18 @@
3337
*
3438
* Delete and delete-by key return true if it was in the set:
3539
* 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);
3741
*
3842
* Delete by iterator:
3943
* bool <name>_delval(struct <name> *ht, struct <name>_iter *i);
4044
*
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);
4347
*
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):
4552
* type *<name>_getfirst(const struct @name *ht, const <keytype> *k,
4653
* struct <name>_iter *i);
4754
* type *<name>_getnext(const struct @name *ht, const <keytype> *k,
@@ -59,7 +66,7 @@
5966
* You can use HTABLE_INITIALIZER like so:
6067
* struct <name> ht = { HTABLE_INITIALIZER(ht.raw, <name>_hash, NULL) };
6168
*/
62-
#define HTABLE_DEFINE_TYPE(type, keyof, hashfn, eqfn, name) \
69+
#define HTABLE_DEFINE_TYPE_CORE(type, keyof, hashfn, eqfn, name) \
6370
struct name { struct htable raw; }; \
6471
struct name##_iter { struct htable_iter i; }; \
6572
static inline size_t name##_hash(const void *elem, void *priv) \
@@ -89,66 +96,33 @@
8996
{ \
9097
return htable_copy(&dst->raw, &src->raw); \
9198
} \
92-
static inline bool name##_add(struct name *ht, const type *elem) \
93-
{ \
94-
return htable_add(&ht->raw, hashfn(keyof(elem)), elem); \
95-
} \
9699
static inline UNNEEDED bool name##_del(struct name *ht, \
97100
const type *elem) \
98101
{ \
99102
return htable_del(&ht->raw, hashfn(keyof(elem)), elem); \
100103
} \
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-
} \
116104
static inline UNNEEDED type *name##_getmatch_(const struct name *ht, \
117105
const HTABLE_KTYPE(keyof, type) k, \
118106
size_t h, \
119107
type *v, \
120-
struct name##_iter *iter) \
108+
struct htable_iter *iter) \
121109
{ \
122110
while (v) { \
123111
if (eqfn(v, k)) \
124112
break; \
125-
v = htable_nextval(&ht->raw, &iter->i, h); \
113+
v = htable_nextval(&ht->raw, iter, h); \
126114
} \
127115
return v; \
128116
} \
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) \
140119
{ \
120+
struct htable_iter i; \
141121
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; \
152126
} \
153127
static inline UNNEEDED void name##_delval(struct name *ht, \
154128
struct name##_iter *iter) \
@@ -177,6 +151,64 @@
177151
return htable_prev(&ht->raw, &iter->i); \
178152
}
179153

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+
180212
#if HAVE_TYPEOF
181213
#define HTABLE_KTYPE(keyof, type) typeof(keyof((const type *)NULL))
182214
#else

ccan/ccan/htable/test/run-type-int.c

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ static bool cmp(const struct obj *obj, const unsigned int key)
3838
return obj->key == key;
3939
}
4040

41-
HTABLE_DEFINE_TYPE(struct obj, objkey, objhash, cmp, htable_obj);
41+
HTABLE_DEFINE_NODUPS_TYPE(struct obj, objkey, objhash, cmp, htable_obj);
4242

4343
static void add_vals(struct htable_obj *ht,
4444
struct obj val[], unsigned int num)
@@ -112,14 +112,19 @@ static bool check_mask(struct htable *ht, const struct obj val[], unsigned num)
112112
return true;
113113
}
114114

115+
/* This variant allows duplicates! */
116+
HTABLE_DEFINE_DUPS_TYPE(struct obj, objkey, objhash, cmp, htable_obj_dups);
117+
115118
int main(void)
116119
{
117120
unsigned int i;
118121
struct htable_obj ht, ht2;
122+
struct htable_obj_dups ht_dups;
119123
struct obj val[NUM_VALS], *result;
120124
unsigned int dne;
121125
void *p;
122126
struct htable_obj_iter iter;
127+
struct htable_obj_dups_iter dups_iter;
123128

124129
plan_tests(29);
125130
for (i = 0; i < NUM_VALS; i++)
@@ -183,32 +188,35 @@ int main(void)
183188
del_vals_bykey(&ht, val, NUM_VALS);
184189
del_vals_bykey(&ht2, val, NUM_VALS);
185190

191+
/* Duplicates-allowed tests */
192+
htable_obj_dups_init(&ht_dups);
186193
/* Write two of the same value. */
187194
val[1] = val[0];
188-
htable_obj_add(&ht, &val[0]);
189-
htable_obj_add(&ht, &val[1]);
195+
htable_obj_dups_add(&ht_dups, &val[0]);
196+
htable_obj_dups_add(&ht_dups, &val[1]);
190197
i = 0;
191198

192-
result = htable_obj_getfirst(&ht, i, &iter);
199+
result = htable_obj_dups_getfirst(&ht_dups, i, &dups_iter);
193200
ok1(result == &val[0] || result == &val[1]);
194201
if (result == &val[0]) {
195-
ok1(htable_obj_getnext(&ht, i, &iter) == &val[1]);
196-
ok1(htable_obj_getnext(&ht, i, &iter) == NULL);
202+
ok1(htable_obj_dups_getnext(&ht_dups, i, &dups_iter) == &val[1]);
203+
ok1(htable_obj_dups_getnext(&ht_dups, i, &dups_iter) == NULL);
197204

198205
/* Deleting first should make us iterate over the other. */
199-
ok1(htable_obj_del(&ht, &val[0]));
200-
ok1(htable_obj_getfirst(&ht, i, &iter) == &val[1]);
201-
ok1(htable_obj_getnext(&ht, i, &iter) == NULL);
206+
ok1(htable_obj_dups_del(&ht_dups, &val[0]));
207+
ok1(htable_obj_dups_getfirst(&ht_dups, i, &dups_iter) == &val[1]);
208+
ok1(htable_obj_dups_getnext(&ht_dups, i, &dups_iter) == NULL);
202209
} else {
203-
ok1(htable_obj_getnext(&ht, i, &iter) == &val[0]);
204-
ok1(htable_obj_getnext(&ht, i, &iter) == NULL);
210+
ok1(htable_obj_dups_getnext(&ht_dups, i, &dups_iter) == &val[0]);
211+
ok1(htable_obj_dups_getnext(&ht_dups, i, &dups_iter) == NULL);
205212

206213
/* Deleting first should make us iterate over the other. */
207-
ok1(htable_obj_del(&ht, &val[1]));
208-
ok1(htable_obj_getfirst(&ht, i, &iter) == &val[0]);
209-
ok1(htable_obj_getnext(&ht, i, &iter) == NULL);
214+
ok1(htable_obj_dups_del(&ht_dups, &val[1]));
215+
ok1(htable_obj_dups_getfirst(&ht_dups, i, &dups_iter) == &val[0]);
216+
ok1(htable_obj_dups_getnext(&ht_dups, i, &dups_iter) == NULL);
210217
}
211218

219+
htable_obj_dups_clear(&ht_dups);
212220
htable_obj_clear(&ht);
213221
htable_obj_clear(&ht2);
214222
return exit_status();

ccan/ccan/htable/test/run-type.c

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ static bool cmp(const struct obj *obj, const unsigned int *key)
3333
return obj->key == *key;
3434
}
3535

36-
HTABLE_DEFINE_TYPE(struct obj, objkey, objhash, cmp, htable_obj);
36+
HTABLE_DEFINE_NODUPS_TYPE(struct obj, objkey, objhash, cmp,
37+
htable_obj);
38+
HTABLE_DEFINE_DUPS_TYPE(struct obj, objkey, objhash, cmp,
39+
htable_obj_dups);
3740

3841
static void add_vals(struct htable_obj *ht,
3942
struct obj val[], unsigned int num)
@@ -111,12 +114,14 @@ int main(void)
111114
{
112115
unsigned int i;
113116
struct htable_obj ht, ht2;
117+
struct htable_obj_dups ht_dups;
114118
struct obj val[NUM_VALS], *result;
115119
unsigned int dne;
116120
void *p;
117121
struct htable_obj_iter iter;
122+
struct htable_obj_dups_iter dups_iter;
118123

119-
plan_tests(35);
124+
plan_tests(36);
120125
for (i = 0; i < NUM_VALS; i++)
121126
val[i].key = i;
122127
dne = i;
@@ -182,32 +187,37 @@ int main(void)
182187
del_vals_bykey(&ht, val, NUM_VALS);
183188
del_vals_bykey(&ht2, val, NUM_VALS);
184189

190+
/* Duplicates-allowed tests */
191+
htable_obj_dups_init(&ht_dups);
192+
185193
/* Write two of the same value. */
186194
val[1] = val[0];
187-
htable_obj_add(&ht, &val[0]);
188-
htable_obj_add(&ht, &val[1]);
195+
htable_obj_dups_add(&ht_dups, &val[0]);
196+
htable_obj_dups_add(&ht_dups, &val[1]);
189197
i = 0;
190198

191-
result = htable_obj_getfirst(&ht, &i, &iter);
199+
result = htable_obj_dups_getfirst(&ht_dups, &i, &dups_iter);
192200
ok1(result == &val[0] || result == &val[1]);
193201
if (result == &val[0]) {
194-
ok1(htable_obj_getnext(&ht, &i, &iter) == &val[1]);
195-
ok1(htable_obj_getnext(&ht, &i, &iter) == NULL);
202+
ok1(htable_obj_dups_getnext(&ht_dups, &i, &dups_iter) == &val[1]);
203+
ok1(htable_obj_dups_getnext(&ht_dups, &i, &dups_iter) == NULL);
196204

197205
/* Deleting first should make us iterate over the other. */
198-
ok1(htable_obj_del(&ht, &val[0]));
199-
ok1(htable_obj_getfirst(&ht, &i, &iter) == &val[1]);
200-
ok1(htable_obj_getnext(&ht, &i, &iter) == NULL);
206+
ok1(htable_obj_dups_del(&ht_dups, &val[0]));
207+
ok1(htable_obj_dups_getfirst(&ht_dups, &i, &dups_iter) == &val[1]);
208+
ok1(htable_obj_dups_getnext(&ht_dups, &i, &dups_iter) == NULL);
201209
} else {
202-
ok1(htable_obj_getnext(&ht, &i, &iter) == &val[0]);
203-
ok1(htable_obj_getnext(&ht, &i, &iter) == NULL);
210+
ok1(htable_obj_dups_getnext(&ht_dups, &i, &dups_iter) == &val[0]);
211+
ok1(htable_obj_dups_getnext(&ht_dups, &i, &dups_iter) == NULL);
204212

205213
/* Deleting first should make us iterate over the other. */
206-
ok1(htable_obj_del(&ht, &val[1]));
207-
ok1(htable_obj_getfirst(&ht, &i, &iter) == &val[0]);
208-
ok1(htable_obj_getnext(&ht, &i, &iter) == NULL);
214+
ok1(htable_obj_dups_del(&ht_dups, &val[1]));
215+
ok1(htable_obj_dups_getfirst(&ht_dups, &i, &dups_iter) == &val[0]);
216+
ok1(htable_obj_dups_getnext(&ht_dups, &i, &dups_iter) == NULL);
209217
}
210218

219+
htable_obj_dups_clear(&ht_dups);
220+
ok1(htable_obj_dups_count(&ht_dups) == 0);
211221
htable_obj_clear(&ht);
212222
ok1(htable_obj_count(&ht) == 0);
213223
htable_obj_clear(&ht2);

ccan/ccan/htable/tools/density.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ static bool cmp(const ptrint_t *p, uintptr_t k)
2626
return key(p) == k;
2727
}
2828

29-
HTABLE_DEFINE_TYPE(ptrint_t, key, hash_uintptr, cmp, htable_ptrint);
29+
HTABLE_DEFINE_NODUPS_TYPE(ptrint_t, key, hash_uintptr, cmp, htable_ptrint);
3030

3131
/* Nanoseconds per operation */
3232
static size_t normalize(const struct timeabs *start,

ccan/ccan/htable/tools/speed.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ static bool cmp(const struct object *object, const unsigned int *key)
3333
return object->key == *key;
3434
}
3535

36-
HTABLE_DEFINE_TYPE(struct object, objkey, hash_obj, cmp, htable_obj);
36+
HTABLE_DEFINE_NODUPS_TYPE(struct object, objkey, hash_obj, cmp, htable_obj);
3737

3838
static unsigned int popcount(unsigned long val)
3939
{

ccan/ccan/htable/tools/stringspeed.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static bool cmp(const char *obj, const char *key)
3131
return strcmp(obj, key) == 0;
3232
}
3333

34-
HTABLE_DEFINE_TYPE(char, strkey, hash_str, cmp, htable_str);
34+
HTABLE_DEFINE_NODUPS_TYPE(char, strkey, hash_str, cmp, htable_str);
3535

3636
/* Nanoseconds per operation */
3737
static size_t normalize(const struct timeabs *start,

ccan/ccan/intmap/benchmark/speed.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ static bool eqfn(const struct htable_elem *elem, const uint64_t index)
5959
{
6060
return elem->index == index;
6161
}
62-
HTABLE_DEFINE_TYPE(struct htable_elem, keyof, hashfn, eqfn, hash);
62+
HTABLE_DEFINE_NODUPS_TYPE(struct htable_elem, keyof, hashfn, eqfn, hash);
6363

6464
static bool check_val(intmap_index_t i, uint64_t *v, uint64_t *expected)
6565
{

0 commit comments

Comments
 (0)