1 | /** |
2 | * The purpose of this test is to check that we can call CRoaring from C++ |
3 | */ |
4 | |
5 | #include <type_traits> |
6 | #include <assert.h> |
7 | #include <roaring/roaring.h> |
8 | #include <stdio.h> |
9 | #include <stdlib.h> |
10 | #include <string.h> |
11 | #include <time.h> |
12 | #include <iostream> |
13 | #include "roaring.hh" |
14 | #include "roaring64map.hh" |
15 | extern "C" { |
16 | #include "test.h" |
17 | } |
18 | |
19 | |
20 | static_assert(std::is_nothrow_move_constructible<Roaring>::value, |
21 | "Expected Roaring to be no except move constructable" ); |
22 | |
23 | bool roaring_iterator_sumall(uint32_t value, void *param) { |
24 | *(uint32_t *)param += value; |
25 | return true; // we always process all values |
26 | } |
27 | |
28 | bool roaring_iterator_sumall64(uint64_t value, void *param) { |
29 | *(uint64_t *)param += value; |
30 | return true; // we always process all values |
31 | } |
32 | |
33 | |
34 | void serial_test(void **) { |
35 | uint32_t values[] = {5, 2, 3, 4, 1}; |
36 | Roaring r1(sizeof(values)/sizeof(uint32_t), values); |
37 | uint32_t serializesize = r1.getSizeInBytes(); |
38 | char *serializedbytes = new char [serializesize]; |
39 | r1.write(serializedbytes); |
40 | Roaring t = Roaring::read(serializedbytes); |
41 | assert_true(r1 == t); |
42 | char *copy = new char[serializesize]; |
43 | memcpy(copy, serializedbytes, serializesize); |
44 | Roaring t2 = Roaring::read(copy); |
45 | assert_true(t2== t); |
46 | delete[] serializedbytes; |
47 | delete[] copy; |
48 | } |
49 | |
50 | void test_example(bool copy_on_write) { |
51 | // create a new empty bitmap |
52 | roaring_bitmap_t *r1 = roaring_bitmap_create(); |
53 | roaring_bitmap_set_copy_on_write(r1, copy_on_write); |
54 | assert_ptr_not_equal(r1, NULL); |
55 | |
56 | // then we can add values |
57 | for (uint32_t i = 100; i < 1000; i++) { |
58 | roaring_bitmap_add(r1, i); |
59 | } |
60 | // check whether a value is contained |
61 | assert_true(roaring_bitmap_contains(r1, 500)); |
62 | |
63 | // compute how many bits there are: |
64 | uint64_t cardinality = roaring_bitmap_get_cardinality(r1); |
65 | printf("Cardinality = %d \n" , (int)cardinality); |
66 | assert_int_equal(900, cardinality); |
67 | |
68 | // if your bitmaps have long runs, you can compress them by calling |
69 | // run_optimize |
70 | size_t size = roaring_bitmap_portable_size_in_bytes(r1); |
71 | roaring_bitmap_run_optimize(r1); |
72 | size_t compact_size = roaring_bitmap_portable_size_in_bytes(r1); |
73 | printf("size before run optimize %zu bytes, and after %zu bytes\n" , size, |
74 | compact_size); |
75 | // create a new bitmap with varargs |
76 | roaring_bitmap_t *r2 = roaring_bitmap_of(5, 1, 2, 3, 5, 6); |
77 | assert_ptr_not_equal(r2, NULL); |
78 | roaring_bitmap_printf(r2); |
79 | printf("\n" ); |
80 | // we can also create a bitmap from a pointer to 32-bit integers |
81 | const uint32_t values[] = {2, 3, 4}; |
82 | roaring_bitmap_t *r3 = roaring_bitmap_of_ptr(3, values); |
83 | roaring_bitmap_set_copy_on_write(r3, copy_on_write); |
84 | // we can also go in reverse and go from arrays to bitmaps |
85 | uint64_t card1 = roaring_bitmap_get_cardinality(r1); |
86 | uint32_t *arr1 = new uint32_t[card1]; |
87 | assert_ptr_not_equal(arr1, NULL); |
88 | roaring_bitmap_to_uint32_array(r1, arr1); |
89 | |
90 | roaring_bitmap_t *r1f = roaring_bitmap_of_ptr(card1, arr1); |
91 | delete[] arr1; |
92 | assert_ptr_not_equal(r1f, NULL); |
93 | |
94 | // bitmaps shall be equal |
95 | assert_true(roaring_bitmap_equals(r1, r1f)); |
96 | roaring_bitmap_free(r1f); |
97 | |
98 | // we can copy and compare bitmaps |
99 | roaring_bitmap_t *z = roaring_bitmap_copy(r3); |
100 | roaring_bitmap_set_copy_on_write(z, copy_on_write); |
101 | assert_true(roaring_bitmap_equals(r3, z)); |
102 | |
103 | roaring_bitmap_free(z); |
104 | |
105 | // we can compute union two-by-two |
106 | roaring_bitmap_t *r1_2_3 = roaring_bitmap_or(r1, r2); |
107 | roaring_bitmap_set_copy_on_write(r1_2_3, copy_on_write); |
108 | roaring_bitmap_or_inplace(r1_2_3, r3); |
109 | |
110 | // we can compute a big union |
111 | const roaring_bitmap_t *allmybitmaps[] = {r1, r2, r3}; |
112 | roaring_bitmap_t *bigunion = roaring_bitmap_or_many(3, allmybitmaps); |
113 | assert_true(roaring_bitmap_equals(r1_2_3, bigunion)); |
114 | roaring_bitmap_t *bigunionheap = |
115 | roaring_bitmap_or_many_heap(3, allmybitmaps); |
116 | assert_true(roaring_bitmap_equals(r1_2_3, bigunionheap)); |
117 | roaring_bitmap_free(r1_2_3); |
118 | roaring_bitmap_free(bigunion); |
119 | roaring_bitmap_free(bigunionheap); |
120 | |
121 | // we can compute intersection two-by-two |
122 | roaring_bitmap_t *i1_2 = roaring_bitmap_and(r1, r2); |
123 | roaring_bitmap_free(i1_2); |
124 | |
125 | // we can write a bitmap to a pointer and recover it later |
126 | size_t expectedsize = roaring_bitmap_portable_size_in_bytes(r1); |
127 | char *serializedbytes = (char *)malloc(expectedsize); |
128 | roaring_bitmap_portable_serialize(r1, serializedbytes); |
129 | roaring_bitmap_t *t = roaring_bitmap_portable_deserialize(serializedbytes); |
130 | assert_true(expectedsize == roaring_bitmap_portable_size_in_bytes(t)); |
131 | assert_true(roaring_bitmap_equals(r1, t)); |
132 | roaring_bitmap_free(t); |
133 | free(serializedbytes); |
134 | |
135 | // we can iterate over all values using custom functions |
136 | uint32_t counter = 0; |
137 | roaring_iterate(r1, roaring_iterator_sumall, &counter); |
138 | /** |
139 | * void roaring_iterator_sumall(uint32_t value, void *param) { |
140 | * *(uint32_t *) param += value; |
141 | * } |
142 | * |
143 | */ |
144 | |
145 | roaring_bitmap_free(r1); |
146 | roaring_bitmap_free(r2); |
147 | roaring_bitmap_free(r3); |
148 | } |
149 | |
150 | void test_example_cpp(bool copy_on_write) { |
151 | // create a new empty bitmap |
152 | Roaring r1; |
153 | r1.setCopyOnWrite(copy_on_write); |
154 | // then we can add values |
155 | for (uint32_t i = 100; i < 1000; i++) { |
156 | r1.add(i); |
157 | } |
158 | |
159 | // check whether a value is contained |
160 | assert_true(r1.contains(500)); |
161 | |
162 | // compute how many bits there are: |
163 | uint64_t cardinality = r1.cardinality(); |
164 | std::cout << "Cardinality = " << cardinality << std::endl; |
165 | |
166 | // if your bitmaps have long runs, you can compress them by calling |
167 | // run_optimize |
168 | size_t size = r1.getSizeInBytes(); |
169 | r1.runOptimize(); |
170 | size_t compact_size = r1.getSizeInBytes(); |
171 | |
172 | std::cout << "size before run optimize " << size << " bytes, and after " |
173 | << compact_size << " bytes." << std::endl; |
174 | |
175 | // create a new bitmap with varargs |
176 | Roaring r2 = Roaring::bitmapOf(5, 1, 2, 3, 5, 6); |
177 | |
178 | r2.printf(); |
179 | printf("\n" ); |
180 | |
181 | // test select |
182 | uint32_t element; |
183 | r2.select(3, &element); |
184 | assert_true(element == 5); |
185 | |
186 | assert_true(r2.minimum() == 1); |
187 | |
188 | assert_true(r2.maximum() == 6); |
189 | |
190 | assert_true(r2.rank(4) == 3); |
191 | |
192 | // we can also create a bitmap from a pointer to 32-bit integers |
193 | const uint32_t values[] = {2, 3, 4}; |
194 | Roaring r3(3, values); |
195 | r3.setCopyOnWrite(copy_on_write); |
196 | |
197 | // we can also go in reverse and go from arrays to bitmaps |
198 | uint64_t card1 = r1.cardinality(); |
199 | uint32_t *arr1 = new uint32_t[card1]; |
200 | assert_true(arr1 != NULL); |
201 | r1.toUint32Array(arr1); |
202 | Roaring r1f(card1, arr1); |
203 | delete[] arr1; |
204 | |
205 | // bitmaps shall be equal |
206 | assert_true(r1 == r1f); |
207 | |
208 | // we can copy and compare bitmaps |
209 | Roaring z(r3); |
210 | z.setCopyOnWrite(copy_on_write); |
211 | assert_true(r3 == z); |
212 | |
213 | // we can compute union two-by-two |
214 | Roaring r1_2_3 = r1 | r2; |
215 | r1_2_3.setCopyOnWrite(copy_on_write); |
216 | r1_2_3 |= r3; |
217 | |
218 | // we can compute a big union |
219 | const Roaring *allmybitmaps[] = {&r1, &r2, &r3}; |
220 | Roaring bigunion = Roaring::fastunion(3, allmybitmaps); |
221 | assert_true(r1_2_3 == bigunion); |
222 | |
223 | // we can compute intersection two-by-two |
224 | Roaring i1_2 = r1 & r2; |
225 | |
226 | // we can write a bitmap to a pointer and recover it later |
227 | size_t expectedsize = r1.getSizeInBytes(); |
228 | char *serializedbytes = new char[expectedsize]; |
229 | r1.write(serializedbytes); |
230 | Roaring t = Roaring::read(serializedbytes); |
231 | assert_true(expectedsize == t.getSizeInBytes()); |
232 | assert_true(r1 == t); |
233 | |
234 | Roaring t2 = Roaring::readSafe(serializedbytes,expectedsize); |
235 | assert_true(expectedsize == t2.getSizeInBytes()); |
236 | assert_true(r1 == t2); |
237 | |
238 | delete[] serializedbytes; |
239 | |
240 | // we can iterate over all values using custom functions |
241 | uint32_t counter = 0; |
242 | r1.iterate(roaring_iterator_sumall, &counter); |
243 | /** |
244 | * void roaring_iterator_sumall(uint32_t value, void *param) { |
245 | * *(uint32_t *) param += value; |
246 | * } |
247 | * |
248 | */ |
249 | // we can also iterate the C++ way |
250 | counter = 0; |
251 | for (Roaring::const_iterator i = t.begin(); i != t.end(); i++) { |
252 | ++counter; |
253 | } |
254 | assert_true(counter == t.cardinality()); |
255 | |
256 | // we can move iterators |
257 | const uint32_t manyvalues[] = {2, 3, 4, 7, 8}; |
258 | Roaring rogue(5, manyvalues); |
259 | Roaring::const_iterator j = rogue.begin(); |
260 | j.equalorlarger(4); |
261 | assert_true(*j == 4); |
262 | |
263 | |
264 | // test move constructor |
265 | { |
266 | Roaring b; |
267 | b.add(10); |
268 | b.add(20); |
269 | |
270 | Roaring a(std::move(b)); |
271 | assert_true(a.cardinality() == 2); |
272 | assert_true(a.contains(10)); |
273 | assert_true(a.contains(20)); |
274 | |
275 | // b should be destroyed without any errors |
276 | assert_true(b.cardinality() == 0); |
277 | } |
278 | |
279 | // test move operator |
280 | { |
281 | Roaring b; |
282 | b.add(10); |
283 | b.add(20); |
284 | |
285 | Roaring a; |
286 | |
287 | a = std::move(b); |
288 | assert_int_equal(2, a.cardinality()); |
289 | assert_true(a.contains(10)); |
290 | assert_true(a.contains(20)); |
291 | |
292 | // b should be destroyed without any errors |
293 | assert_int_equal(0, b.cardinality()); |
294 | } |
295 | |
296 | // test toString |
297 | { |
298 | Roaring a; |
299 | a.add(1); |
300 | a.add(2); |
301 | a.add(3); |
302 | a.add(4); |
303 | |
304 | assert_string_equal("{1,2,3,4}" , a.toString().c_str()); |
305 | } |
306 | } |
307 | |
308 | void test_example_cpp_64(bool copy_on_write) { |
309 | // create a new empty bitmap |
310 | Roaring64Map r1; |
311 | r1.setCopyOnWrite(copy_on_write); |
312 | // then we can add values |
313 | for (uint64_t i = 100; i < 1000; i++) { |
314 | r1.add(i); |
315 | } |
316 | for (uint64_t i = 14000000000000000100ull; i < 14000000000000001000ull; |
317 | i++) { |
318 | r1.add(i); |
319 | } |
320 | |
321 | // check whether a value is contained |
322 | assert_true(r1.contains((uint64_t)14000000000000000500ull)); |
323 | |
324 | // compute how many bits there are: |
325 | uint64_t cardinality = r1.cardinality(); |
326 | std::cout << "Cardinality = " << cardinality << std::endl; |
327 | |
328 | // if your bitmaps have long runs, you can compress them by calling |
329 | // run_optimize |
330 | uint64_t size = r1.getSizeInBytes(); |
331 | r1.runOptimize(); |
332 | uint64_t compact_size = r1.getSizeInBytes(); |
333 | |
334 | std::cout << "size before run optimize " << size << " bytes, and after " |
335 | << compact_size << " bytes." << std::endl; |
336 | |
337 | // create a new bitmap with varargs |
338 | Roaring64Map r2 = |
339 | Roaring64Map::bitmapOf(5, 1ull, 2ull, 234294967296ull, 195839473298ull, |
340 | 14000000000000000100ull); |
341 | |
342 | r2.printf(); |
343 | printf("\n" ); |
344 | |
345 | // test select |
346 | uint64_t element; |
347 | r2.select(4, &element); |
348 | assert_true(element == 14000000000000000100ull); |
349 | |
350 | assert_true(r2.minimum() == 1ull); |
351 | |
352 | assert_true(r2.maximum() == 14000000000000000100ull); |
353 | |
354 | assert_true(r2.rank(234294967296ull) == 4ull); |
355 | |
356 | // we can also create a bitmap from a pointer to 32-bit integers |
357 | const uint32_t values[] = {2, 3, 4}; |
358 | Roaring64Map r3(3, values); |
359 | r3.setCopyOnWrite(copy_on_write); |
360 | |
361 | // we can also go in reverse and go from arrays to bitmaps |
362 | uint64_t card1 = r1.cardinality(); |
363 | uint64_t *arr1 = new uint64_t[card1]; |
364 | assert_true(arr1 != NULL); |
365 | r1.toUint64Array(arr1); |
366 | Roaring64Map r1f(card1, arr1); |
367 | delete[] arr1; |
368 | |
369 | // bitmaps shall be equal |
370 | assert_true(r1 == r1f); |
371 | |
372 | // we can copy and compare bitmaps |
373 | Roaring64Map z(r3); |
374 | z.setCopyOnWrite(copy_on_write); |
375 | assert_true(r3 == z); |
376 | |
377 | // we can compute union two-by-two |
378 | Roaring64Map r1_2_3 = r1 | r2; |
379 | r1_2_3.setCopyOnWrite(copy_on_write); |
380 | r1_2_3 |= r3; |
381 | |
382 | // we can compute a big union |
383 | const Roaring64Map *allmybitmaps[] = {&r1, &r2, &r3}; |
384 | Roaring64Map bigunion = Roaring64Map::fastunion(3, allmybitmaps); |
385 | assert_true(r1_2_3 == bigunion); |
386 | |
387 | // we can compute intersection two-by-two |
388 | Roaring64Map i1_2 = r1 & r2; |
389 | |
390 | // we can write a bitmap to a pointer and recover it later |
391 | size_t expectedsize = r1.getSizeInBytes(); |
392 | char *serializedbytes = new char[expectedsize]; |
393 | r1.write(serializedbytes); |
394 | Roaring64Map t = Roaring64Map::read(serializedbytes); |
395 | assert_true(expectedsize == t.getSizeInBytes()); |
396 | assert_true(r1 == t); |
397 | delete[] serializedbytes; |
398 | |
399 | // we can iterate over all values using custom functions |
400 | uint64_t counter = 0; |
401 | r1.iterate(roaring_iterator_sumall64, &counter); |
402 | /** |
403 | * void roaring_iterator_sumall64(uint64_t value, void *param) { |
404 | * *(uint64_t *) param += value; |
405 | * } |
406 | * |
407 | */ |
408 | // we can also iterate the C++ way |
409 | counter = 0; |
410 | for (Roaring64Map::const_iterator i = t.begin(); i != t.end(); i++) { |
411 | ++counter; |
412 | } |
413 | assert_true(counter == t.cardinality()); |
414 | |
415 | { |
416 | Roaring64Map b; |
417 | b.add(1u); |
418 | b.add(2u); |
419 | b.add(3u); |
420 | assert_int_equal(3, b.cardinality()); |
421 | |
422 | Roaring64Map a(std::move(b)); |
423 | assert_int_equal(3, a.cardinality()); |
424 | // assert_int_equal(0, b.cardinality()); // no: b is now unspecified. |
425 | } |
426 | |
427 | { |
428 | Roaring64Map a, b; |
429 | b.add(1u); |
430 | b.add(2u); |
431 | b.add(3u); |
432 | assert_int_equal(3, b.cardinality()); |
433 | |
434 | a = std::move(b); |
435 | assert_int_equal(3, a.cardinality()); |
436 | // assert_int_equal(0, b.cardinality()); // no: b is unspecified |
437 | } |
438 | } |
439 | |
440 | void test_example_true(void **) { test_example(true); } |
441 | |
442 | void test_example_false(void **) { test_example(false); } |
443 | |
444 | void test_example_cpp_true(void **) { test_example_cpp(true); } |
445 | |
446 | void test_example_cpp_false(void **) { test_example_cpp(false); } |
447 | |
448 | void test_example_cpp_64_true(void **) { test_example_cpp_64(true); } |
449 | |
450 | void test_example_cpp_64_false(void **) { test_example_cpp_64(false); } |
451 | |
452 | void test_cpp_add_remove_checked(void **) { |
453 | Roaring roaring; |
454 | uint32_t values[4] = { 123, 9999, 0xFFFFFFF7, 0xFFFFFFFF}; |
455 | for (int i = 0; i < 4; ++i) { |
456 | assert_true(roaring.addChecked(values[i])); |
457 | assert_false(roaring.addChecked(values[i])); |
458 | } |
459 | for (int i = 0; i < 4; ++i) { |
460 | assert_true(roaring.removeChecked(values[i])); |
461 | assert_false(roaring.removeChecked(values[i])); |
462 | } |
463 | assert_true(roaring.isEmpty()); |
464 | } |
465 | |
466 | void test_cpp_add_remove_checked_64(void **) { |
467 | Roaring64Map roaring; |
468 | |
469 | uint32_t values32[4] = { 123, 9999, 0xFFFFFFF7, 0xFFFFFFFF}; |
470 | for (int i = 0; i < 4; ++i) { |
471 | assert_true(roaring.addChecked(values32[i])); |
472 | assert_false(roaring.addChecked(values32[i])); |
473 | } |
474 | for (int i = 0; i < 4; ++i) { |
475 | assert_true(roaring.removeChecked(values32[i])); |
476 | assert_false(roaring.removeChecked(values32[i])); |
477 | } |
478 | |
479 | uint64_t values64[4] = { 123ULL, 0xA00000000AULL, 0xAFFFFFFF7ULL, 0xFFFFFFFFFULL}; |
480 | for (int i = 0; i < 4; ++i) { |
481 | assert_true(roaring.addChecked(values64[i])); |
482 | assert_false(roaring.addChecked(values64[i])); |
483 | } |
484 | for (int i = 0; i < 4; ++i) { |
485 | assert_true(roaring.removeChecked(values64[i])); |
486 | assert_false(roaring.removeChecked(values64[i])); |
487 | } |
488 | assert_true(roaring.isEmpty()); |
489 | } |
490 | |
491 | void test_cpp_clear_64(void **) { |
492 | Roaring64Map roaring; |
493 | |
494 | uint64_t values64[4] = { 123ULL, 0xA00000000AULL, 0xAFFFFFFF7ULL, 0xFFFFFFFFFULL}; |
495 | for (int i = 0; i < 4; ++i) { |
496 | assert_true(roaring.addChecked(values64[i])); |
497 | } |
498 | |
499 | roaring.clear(); |
500 | |
501 | assert_true(roaring.isEmpty()); |
502 | } |
503 | |
504 | void test_cpp_move_64(void **) { |
505 | Roaring64Map roaring; |
506 | |
507 | uint64_t values64[4] = { 123ULL, 0xA00000000AULL, 0xAFFFFFFF7ULL, 0xFFFFFFFFFULL}; |
508 | for (int i = 0; i < 4; ++i) { |
509 | assert_true(roaring.addChecked(values64[i])); |
510 | } |
511 | |
512 | Roaring64Map::const_iterator i(roaring); |
513 | i.move(123ULL); |
514 | assert_true(*i == 123ULL); |
515 | i.move(0xAFFFFFFF8ULL); |
516 | assert_true(*i == 0xFFFFFFFFFULL); |
517 | assert_false(i.move(0xFFFFFFFFFFULL)); |
518 | } |
519 | |
520 | void test_cpp_bidirectional_iterator_64(void **) { |
521 | Roaring64Map roaring; |
522 | |
523 | uint64_t values64[4] = { 123ULL, 0xA00000000AULL, 0xAFFFFFFF7ULL, 0xFFFFFFFFFULL}; |
524 | for (int i = 0; i < 4; ++i) { |
525 | assert_true(roaring.addChecked(values64[i])); |
526 | } |
527 | |
528 | Roaring64Map::const_bidirectional_iterator i(roaring); |
529 | i = roaring.begin(); |
530 | assert_true(*i++ == 123ULL); |
531 | assert_true(*i++ == 0xAFFFFFFF7ULL); |
532 | assert_true(*i++ == 0xFFFFFFFFFULL); |
533 | assert_true(*i++ == 0xA00000000AULL); |
534 | assert_true(i == roaring.end()); |
535 | assert_true(*--i == 0xA00000000AULL); |
536 | assert_true(*--i == 0xFFFFFFFFFULL); |
537 | assert_true(*--i == 0xAFFFFFFF7ULL); |
538 | assert_true(*--i == 123ULL); |
539 | assert_true(i == roaring.begin()); |
540 | i = roaring.end(); |
541 | i--; |
542 | assert_true(*i-- == 0xA00000000AULL); |
543 | assert_true(*i-- == 0xFFFFFFFFFULL); |
544 | assert_true(*i-- == 0xAFFFFFFF7ULL); |
545 | assert_true(*i == 123ULL); |
546 | assert_true(i == roaring.begin()); |
547 | } |
548 | |
549 | int main() { |
550 | const struct CMUnitTest tests[] = { |
551 | cmocka_unit_test(serial_test), |
552 | cmocka_unit_test(test_example_true), |
553 | cmocka_unit_test(test_example_false), |
554 | cmocka_unit_test(test_example_cpp_true), |
555 | cmocka_unit_test(test_example_cpp_false), |
556 | cmocka_unit_test(test_example_cpp_64_true), |
557 | cmocka_unit_test(test_example_cpp_64_false), |
558 | cmocka_unit_test(test_cpp_add_remove_checked), |
559 | cmocka_unit_test(test_cpp_add_remove_checked_64), |
560 | cmocka_unit_test(test_cpp_clear_64), |
561 | cmocka_unit_test(test_cpp_move_64), |
562 | cmocka_unit_test(test_cpp_bidirectional_iterator_64)}; |
563 | |
564 | return cmocka_run_group_tests(tests, NULL, NULL); |
565 | } |
566 | |