Skip to content

Commit 872a8bb

Browse files
authored
removing unnecessary boiler plate in unit.c (#65)
* first cut at reducing warnings binaryfusefilter.h only issues addressed 1. changed some return value and parameter types of (static) functions -- PLEASE CHECK THIS IN REVIEW 2. sprinkled 'U' into bitwise operations to silence warnings 3. casting to avoid "standard integer promotion rules" which resulted in signedness warnings 4. explicitly reducing results to the target type rather than letting it happen implicitly tests still passing * first cut at reducing warnings binaryfusefilter.h only issues addressed 1. changed some return value and parameter types of (static) functions -- PLEASE CHECK THIS IN REVIEW 2. sprinkled 'U' into bitwise operations to silence warnings 3. casting to avoid "standard integer promotion rules" which resulted in signedness warnings 4. explicitly reducing results to the target type rather than letting it happen implicitly 5. when and `if` statements ends in break or return, then a following `else if` can be just a new `if` tests still passing * starting work on xofilter.h * binclude/binaryfusefilter.h apparently clean for first time * formatting * first cut on xofilter.h mostly casting size_t down to uint32_t - maybe some internal struct types should have been size_t? also some integer promotion casts * round2 on xorfilter.h mostly casting blocklengt to uint32_t to fit into keyindex.index should keyindex.index be a size_t? * bench.c and unit.c very repetitive casting of mainly sizes and doubles. * all silent now on a clean compile with -Wconversion and -Wsign-conversion so putting these in the Makefile, so during "private" development with the Makefile new warnings will be noticed straight away but not in CMakeLists.txt, because as this is a header-only INTERFACE library, it would force these warning levels on the users. * another sweep from including c++ project turned up these additional 'U' tweaks * mistaken cast which broke test * factoring out the report functionality all sections were indentical except for the call to *contain() and *size_in_bytes some void* and function pointer juggling allowed to make this generic report code reduced by 2/3rds * iron out slight inconsistencies between tests * abstracting away the rest of the test logic for all but the special "failure rate test" the large function dispatch table is a litle annoying, but can be removed as well...TBC tests all pass * fixing a memory leak caught by sanitizer just a missing free() * _duplicates test cases can be convered by the same code remove initialization. it's not needed and compiler now happy * removing the need for large array of boiler plate function wrappers instead of having a wrapper function per action per filter type, we can cast the functions as a generic function pointer on the into the generic test runner, and then cast them as a compatible function pointer type inside the test runner. The generic `filter*` parameter cannot be `void*` and must be a dummy struct because: § 6.2.5..28: "All pointers to structure types shall have the same representation and alignment requirements as each other" (the same is not true for `void*` which may have different representation. This simple change results in a large code reduction and removes the unsightly and hard to remove array of boiler plate function wrappers.
1 parent 890b31d commit 872a8bb

File tree

1 file changed

+104
-175
lines changed

1 file changed

+104
-175
lines changed

tests/unit.c

Lines changed: 104 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -2,71 +2,33 @@
22
#include "xorfilter.h"
33
#include <assert.h>
44

5-
// generic function dispatch
6-
7-
bool gen_xor8_allocate(uint32_t size, void *filter) { return xor8_allocate(size, filter); }
8-
bool gen_xor16_allocate(uint32_t size, void *filter) { return xor16_allocate(size, filter); }
9-
bool gen_binary_fuse8_allocate(uint32_t size, void *filter) { return binary_fuse8_allocate(size, filter); }
10-
bool gen_binary_fuse16_allocate(uint32_t size, void *filter) { return binary_fuse16_allocate(size, filter); }
11-
12-
void gen_xor8_free(void *filter) { xor8_free(filter); }
13-
void gen_xor16_free(void *filter) { xor16_free(filter); }
14-
void gen_binary_fuse8_free(void *filter) { binary_fuse8_free(filter); }
15-
void gen_binary_fuse16_free(void *filter) { binary_fuse16_free(filter); }
16-
17-
size_t gen_xor8_size_in_bytes(const void *filter) { return xor8_size_in_bytes(filter); }
18-
size_t gen_xor16_size_in_bytes(const void *filter) { return xor16_size_in_bytes(filter); }
19-
size_t gen_binary_fuse8_size_in_bytes(const void *filter) { return binary_fuse8_size_in_bytes(filter); }
20-
size_t gen_binary_fuse16_size_in_bytes(const void *filter) { return binary_fuse16_size_in_bytes(filter); }
21-
22-
size_t gen_xor8_serialization_bytes(void *filter) { return xor8_serialization_bytes(filter); }
23-
size_t gen_xor16_serialization_bytes(void *filter) { return xor16_serialization_bytes(filter); }
24-
size_t gen_binary_fuse8_serialization_bytes(void *filter) { return binary_fuse8_serialization_bytes(filter); }
25-
size_t gen_binary_fuse16_serialization_bytes(void *filter) { return binary_fuse16_serialization_bytes(filter); }
26-
27-
void gen_xor8_serialize(void *filter, char *buffer) { xor8_serialize(filter, buffer); }
28-
void gen_xor16_serialize(void *filter, char *buffer) { xor16_serialize(filter, buffer); }
29-
void gen_binary_fuse8_serialize(void *filter, char *buffer) { binary_fuse8_serialize(filter, buffer); }
30-
void gen_binary_fuse16_serialize(void *filter, char *buffer) { binary_fuse16_serialize(filter, buffer); }
31-
32-
bool gen_xor8_deserialize(void *filter, const char *buffer) { return xor8_deserialize(filter, buffer); }
33-
bool gen_xor16_deserialize(void *filter, const char *buffer) { return xor16_deserialize(filter, buffer); }
34-
bool gen_binary_fuse8_deserialize(void *filter, const char *buffer) { return binary_fuse8_deserialize(filter, buffer); }
35-
bool gen_binary_fuse16_deserialize(void *filter, const char *buffer) { return binary_fuse16_deserialize(filter, buffer); }
36-
37-
bool gen_xor8_populate(uint64_t *keys, uint32_t size, void *filter) { return xor8_populate(keys, size, filter); }
38-
bool gen_xor8_buffered_populate(uint64_t *keys, uint32_t size, void *filter) { return xor8_buffered_populate(keys, size, filter); }
39-
bool gen_xor16_populate(uint64_t *keys, uint32_t size, void *filter) { return xor16_populate(keys, size, filter); }
40-
bool gen_xor16_buffered_populate(uint64_t *keys, uint32_t size, void *filter) { return xor16_buffered_populate(keys, size, filter); }
41-
bool gen_binary_fuse8_populate(uint64_t *keys, uint32_t size, void *filter) { return binary_fuse8_populate(keys, size, filter); }
42-
bool gen_binary_fuse16_populate(uint64_t *keys, uint32_t size, void *filter) { return binary_fuse16_populate(keys, size, filter); }
43-
44-
bool gen_xor8_contain(uint64_t key, const void *filter) { return xor8_contain(key, filter); }
45-
bool gen_xor16_contain(uint64_t key, const void *filter) { return xor16_contain(key, filter); }
46-
bool gen_binary_fuse8_contain(uint64_t key, const void *filter) { return binary_fuse8_contain(key, filter); }
47-
bool gen_binary_fuse16_contain(uint64_t key, const void *filter) { return binary_fuse16_contain(key, filter); }
48-
49-
typedef bool (*allocate_fpt)(uint32_t size, void *filter);
50-
typedef void (*free_fpt)(void *filter);
51-
typedef size_t (*size_in_bytes_fpt)(const void *filter);
52-
typedef size_t (*serialization_bytes_fpt)(void *filter);
53-
typedef void (*serialize_fpt)(void *filter, char *buffer);
54-
typedef bool (*deserialize_fpt)(void *filter, const char *buffer);
55-
typedef bool (*populate_fpt)(uint64_t *keys, uint32_t size, void *filter);
56-
typedef bool (*contain_fpt)(uint64_t key, const void *filter);
5+
// generic proxy for filter, important that this is a struct, not void
6+
// as § 6.2.5..28: "All pointers to structure types shall have the
7+
// same representation and alignment requirements as each other"
8+
typedef struct { int dummy_; } gen_filter;
9+
10+
typedef bool (*allocate_fpt)(uint32_t size, gen_filter *filter);
11+
typedef void (*free_fpt)(gen_filter *filter);
12+
typedef size_t (*size_in_bytes_fpt)(const gen_filter *filter);
13+
typedef size_t (*serialization_bytes_fpt)(gen_filter *filter);
14+
typedef void (*serialize_fpt)(gen_filter *filter, char *buffer);
15+
typedef bool (*deserialize_fpt)(gen_filter *filter, const char *buffer);
16+
typedef bool (*populate_fpt)(uint64_t *keys, uint32_t size, gen_filter *filter);
17+
typedef bool (*contain_fpt)(uint64_t key, const gen_filter *filter);
18+
19+
typedef void (*gfp)(void); // generic function pointer
5720

5821
// generic test runner
59-
6022
bool test(size_t size, size_t repeated_size, void *filter,
61-
allocate_fpt allocate,
62-
free_fpt free_filter,
63-
size_in_bytes_fpt size_in_bytes,
64-
serialization_bytes_fpt serialization_bytes,
65-
serialize_fpt serialize,
66-
deserialize_fpt deserialize,
67-
populate_fpt populate,
68-
contain_fpt contain) {
69-
allocate((uint32_t)size, filter);
23+
gfp allocate,
24+
gfp free_filter,
25+
gfp size_in_bytes,
26+
gfp serialization_bytes,
27+
gfp serialize,
28+
gfp deserialize,
29+
gfp populate,
30+
gfp contain) {
31+
((allocate_fpt)allocate)((uint32_t)size, filter);
7032
// we need some set of values
7133
uint64_t *big_set = (uint64_t *)malloc(sizeof(uint64_t) * size);
7234
for (size_t i = 0; i < size - repeated_size; i++) {
@@ -76,22 +38,22 @@ bool test(size_t size, size_t repeated_size, void *filter,
7638
big_set[size - i - 1] = i; // we use contiguous values
7739
}
7840
// we construct the filter
79-
if(!populate(big_set, (uint32_t)size, filter)) { return false; }
41+
if(!((populate_fpt)populate)(big_set, (uint32_t)size, filter)) { return false; }
8042
for (size_t i = 0; i < size; i++) {
81-
if (!contain(big_set[i], filter)) {
43+
if (!((contain_fpt)contain)(big_set[i], filter)) {
8244
printf("bug!\n");
8345
return false;
8446
}
8547
}
8648

87-
size_t buffer_size = serialization_bytes(filter);
49+
size_t buffer_size = ((serialization_bytes_fpt)serialization_bytes)(filter);
8850
char *buffer = (char*)malloc(buffer_size);
89-
serialize(filter, buffer);
90-
free_filter(filter);
91-
deserialize(filter, buffer);
51+
((serialize_fpt)serialize)(filter, buffer);
52+
((free_fpt)free_filter)(filter);
53+
((deserialize_fpt)deserialize)(filter, buffer);
9254
free(buffer);
9355
for (size_t i = 0; i < size; i++) {
94-
if (!contain(big_set[i], filter)) {
56+
if (!((contain_fpt)contain)(big_set[i], filter)) {
9557
printf("bug!\n");
9658
return false;
9759
}
@@ -101,143 +63,110 @@ bool test(size_t size, size_t repeated_size, void *filter,
10163
size_t trials = 10000000;
10264
for (size_t i = 0; i < trials; i++) {
10365
uint64_t random_key = ((uint64_t)rand() << 32U) + (uint64_t)rand();
104-
if (contain(random_key, filter)) {
66+
if (((contain_fpt)contain)(random_key, filter)) {
10567
if (random_key >= size) {
10668
random_matches++;
10769
}
10870
}
10971
}
11072
double fpp = (double)random_matches * 1.0 / (double)trials;
11173
printf(" fpp %3.5f (estimated) \n", fpp);
112-
double bpe = (double)size_in_bytes(filter) * 8.0 / (double)size;
74+
double bpe = (double)((size_in_bytes_fpt)size_in_bytes)(filter) * 8.0 / (double)size;
11375
printf(" bits per entry %3.2f\n", bpe);
11476
printf(" bits per entry %3.2f (theoretical lower bound)\n", - log(fpp)/log(2));
11577
printf(" efficiency ratio %3.3f \n", bpe /(- log(fpp)/log(2)));
116-
free_filter(filter);
78+
((free_fpt)free_filter)(filter);
11779
free(big_set);
11880
return true;
11981
}
12082

12183
bool testbufferedxor8(size_t size) {
12284
printf("testing buffered xor8\n");
123-
xor8_t filter = {0}; // zero initialisation silences unitialized warning
85+
xor8_t filter;
12486
return test(size, 0, &filter,
125-
gen_xor8_allocate,
126-
gen_xor8_free,
127-
gen_xor8_size_in_bytes,
128-
gen_xor8_serialization_bytes,
129-
gen_xor8_serialize,
130-
gen_xor8_deserialize,
131-
gen_xor8_buffered_populate,
132-
gen_xor8_contain);
87+
(gfp)xor8_allocate,
88+
(gfp)xor8_free,
89+
(gfp)xor8_size_in_bytes,
90+
(gfp)xor8_serialization_bytes,
91+
(gfp)xor8_serialize,
92+
(gfp)xor8_deserialize,
93+
(gfp)xor8_buffered_populate,
94+
(gfp)xor8_contain);
13395
}
13496

13597

13698
bool testxor8(size_t size) {
13799
printf("testing xor8\n");
138-
139-
xor8_t filter = {0}; // zero initialisation silences unitialized warning
100+
xor8_t filter;
140101
return test(size, 0, &filter,
141-
gen_xor8_allocate,
142-
gen_xor8_free,
143-
gen_xor8_size_in_bytes,
144-
gen_xor8_serialization_bytes,
145-
gen_xor8_serialize,
146-
gen_xor8_deserialize,
147-
gen_xor8_populate,
148-
gen_xor8_contain);
102+
(gfp)xor8_allocate,
103+
(gfp)xor8_free,
104+
(gfp)xor8_size_in_bytes,
105+
(gfp)xor8_serialization_bytes,
106+
(gfp)xor8_serialize,
107+
(gfp)xor8_deserialize,
108+
(gfp)xor8_populate,
109+
(gfp)xor8_contain);
149110
}
150111

151112
bool testxor16(size_t size) {
152113
printf("testing xor16\n");
153-
xor16_t filter = {0}; // zero initialisation silences unitialized warning
114+
xor16_t filter;
154115
return test(size, 0, &filter,
155-
gen_xor16_allocate,
156-
gen_xor16_free,
157-
gen_xor16_size_in_bytes,
158-
gen_xor16_serialization_bytes,
159-
gen_xor16_serialize,
160-
gen_xor16_deserialize,
161-
gen_xor16_populate,
162-
gen_xor16_contain);
116+
(gfp)xor16_allocate,
117+
(gfp)xor16_free,
118+
(gfp)xor16_size_in_bytes,
119+
(gfp)xor16_serialization_bytes,
120+
(gfp)xor16_serialize,
121+
(gfp)xor16_deserialize,
122+
(gfp)xor16_populate,
123+
(gfp)xor16_contain);
163124
}
164125

165126

166127

167128
bool testbufferedxor16(size_t size) {
168129
printf("testing buffered xor16\n");
169-
xor16_t filter = {0}; // zero initialisation silences unitialized warning
130+
xor16_t filter;
170131
return test(size, 0, &filter,
171-
gen_xor16_allocate,
172-
gen_xor16_free,
173-
gen_xor16_size_in_bytes,
174-
gen_xor16_serialization_bytes,
175-
gen_xor16_serialize,
176-
gen_xor16_deserialize,
177-
gen_xor16_buffered_populate,
178-
gen_xor16_contain);
132+
(gfp)xor16_allocate,
133+
(gfp)xor16_free,
134+
(gfp)xor16_size_in_bytes,
135+
(gfp)xor16_serialization_bytes,
136+
(gfp)xor16_serialize,
137+
(gfp)xor16_deserialize,
138+
(gfp)xor16_buffered_populate,
139+
(gfp)xor16_contain);
179140
}
180141

181-
bool testbinaryfuse8(size_t size) {
182-
printf("testing binary fuse8 with size %zu\n", size);
183-
binary_fuse8_t filter = {0}; // zero initialisation silences unitialized warning
184-
return test(size, 0, &filter,
185-
gen_binary_fuse8_allocate,
186-
gen_binary_fuse8_free,
187-
gen_binary_fuse8_size_in_bytes,
188-
gen_binary_fuse8_serialization_bytes,
189-
gen_binary_fuse8_serialize,
190-
gen_binary_fuse8_deserialize,
191-
gen_binary_fuse8_populate,
192-
gen_binary_fuse8_contain);
193-
}
194-
195-
196-
197-
bool testbinaryfuse16(size_t size) {
198-
printf("testing binary fuse16\n");
199-
binary_fuse16_t filter = {0}; // zero initialisation silences unitialized warning
200-
return test(size, 0, &filter,
201-
gen_binary_fuse16_allocate,
202-
gen_binary_fuse16_free,
203-
gen_binary_fuse16_size_in_bytes,
204-
gen_binary_fuse16_serialization_bytes,
205-
gen_binary_fuse16_serialize,
206-
gen_binary_fuse16_deserialize,
207-
gen_binary_fuse16_populate,
208-
gen_binary_fuse16_contain);
142+
bool testbinaryfuse8(size_t size, size_t repeated_size) {
143+
printf("testing binary fuse8 with size %zu and %zu duplicates\n", size, repeated_size);
144+
binary_fuse8_t filter;
145+
return test(size, repeated_size, &filter,
146+
(gfp)binary_fuse8_allocate,
147+
(gfp)binary_fuse8_free,
148+
(gfp)binary_fuse8_size_in_bytes,
149+
(gfp)binary_fuse8_serialization_bytes,
150+
(gfp)binary_fuse8_serialize,
151+
(gfp)binary_fuse8_deserialize,
152+
(gfp)binary_fuse8_populate,
153+
(gfp)binary_fuse8_contain);
209154
}
210155

211156

212157

213-
bool testbinaryfuse8_dup(size_t size) {
214-
printf("testing binary fuse8 with duplicates\n");
215-
binary_fuse8_t filter = {0}; // zero initialisation silences unitialized warning
216-
return test(size, 10, &filter,
217-
gen_binary_fuse8_allocate,
218-
gen_binary_fuse8_free,
219-
gen_binary_fuse8_size_in_bytes,
220-
gen_binary_fuse8_serialization_bytes,
221-
gen_binary_fuse8_serialize,
222-
gen_binary_fuse8_deserialize,
223-
gen_binary_fuse8_populate,
224-
gen_binary_fuse8_contain);
225-
}
226-
227-
228-
229-
bool testbinaryfuse16_dup(size_t size) {
230-
printf("testing binary fuse16 with duplicates\n");
231-
binary_fuse16_t filter = {0}; // zero initialisation silences unitialized warning
232-
return test(size, 10, &filter,
233-
gen_binary_fuse16_allocate,
234-
gen_binary_fuse16_free,
235-
gen_binary_fuse16_size_in_bytes,
236-
gen_binary_fuse16_serialization_bytes,
237-
gen_binary_fuse16_serialize,
238-
gen_binary_fuse16_deserialize,
239-
gen_binary_fuse16_populate,
240-
gen_binary_fuse16_contain);
158+
bool testbinaryfuse16(size_t size, size_t repeated_size) {
159+
printf("testing binary fuse16 with size %zu and %zu duplicates\n", size, repeated_size);
160+
binary_fuse16_t filter;
161+
return test(size, repeated_size, &filter,
162+
(gfp)binary_fuse16_allocate,
163+
(gfp)binary_fuse16_free,
164+
(gfp)binary_fuse16_size_in_bytes,
165+
(gfp)binary_fuse16_serialization_bytes,
166+
(gfp)binary_fuse16_serialize,
167+
(gfp)binary_fuse16_deserialize,
168+
(gfp)binary_fuse16_populate,
169+
(gfp)binary_fuse16_contain);
241170
}
242171

243172
void failure_rate_binary_fuse16() {
@@ -267,13 +196,13 @@ int main() {
267196
failure_rate_binary_fuse16();
268197
for(size_t size = 1000; size <= 1000000; size *= 300) {
269198
printf("== size = %zu \n", size);
270-
if(!testbinaryfuse8(size)) { abort(); }
199+
if(!testbinaryfuse8(size, 0)) { abort(); }
271200
printf("\n");
272-
if(!testbinaryfuse16(size)) { abort(); }
201+
if(!testbinaryfuse16(size, 0)) { abort(); }
273202
printf("\n");
274-
if(!testbinaryfuse8_dup(size)) { abort(); }
203+
if(!testbinaryfuse8(size, 10)) { abort(); }
275204
printf("\n");
276-
if(!testbinaryfuse16_dup(size)) { abort(); }
205+
if(!testbinaryfuse16(size, 10)) { abort(); }
277206
printf("\n");
278207
if(!testbufferedxor8(size)) { abort(); }
279208
printf("\n");
@@ -287,10 +216,10 @@ int main() {
287216
}
288217

289218
// test small edge-case binary fuse input sizes
290-
if(!testbinaryfuse8(0)) { abort(); }
291-
if(!testbinaryfuse8(1)) { abort(); }
292-
if(!testbinaryfuse8(2)) { abort(); }
293-
if(!testbinaryfuse16(0)) { abort(); }
294-
if(!testbinaryfuse16(1)) { abort(); }
295-
if(!testbinaryfuse16(2)) { abort(); }
219+
if(!testbinaryfuse8(0, 0)) { abort(); }
220+
if(!testbinaryfuse8(1, 0)) { abort(); }
221+
if(!testbinaryfuse8(2, 0)) { abort(); }
222+
if(!testbinaryfuse16(0, 0)) { abort(); }
223+
if(!testbinaryfuse16(1, 0)) { abort(); }
224+
if(!testbinaryfuse16(2, 0)) { abort(); }
296225
}

0 commit comments

Comments
 (0)