1/*
2 * Amalgamated copy of CRoaring 0.2.66, modified for GTK to reduce compiler
3 * warnings.
4 *
5 * Copyright 2016-2020 The CRoaring authors
6 * Copyright 2020 Benjamin Otte
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 * SPDX-License-Identifier: Apache-2.0
21 */
22
23/* begin file include/roaring/roaring_version.h */
24// /include/roaring/roaring_version.h automatically generated by release.py, do not change by hand
25#ifndef ROARING_INCLUDE_ROARING_VERSION
26#define ROARING_INCLUDE_ROARING_VERSION
27#define ROARING_VERSION = 0.2.66,
28enum {
29 ROARING_VERSION_MAJOR = 0,
30 ROARING_VERSION_MINOR = 2,
31 ROARING_VERSION_REVISION = 66
32};
33#endif // ROARING_INCLUDE_ROARING_VERSION
34/* end file include/roaring/roaring_version.h */
35/* begin file include/roaring/portability.h */
36/*
37 * portability.h
38 *
39 */
40
41#ifndef INCLUDE_PORTABILITY_H_
42#define INCLUDE_PORTABILITY_H_
43
44#ifndef _GNU_SOURCE
45#define _GNU_SOURCE
46#endif
47#ifndef __STDC_FORMAT_MACROS
48#define __STDC_FORMAT_MACROS 1
49#endif
50
51#if !(defined(_POSIX_C_SOURCE)) || (_POSIX_C_SOURCE < 200809L)
52#define _POSIX_C_SOURCE 200809L
53#endif
54#if !(defined(_XOPEN_SOURCE)) || (_XOPEN_SOURCE < 700)
55#define _XOPEN_SOURCE 700
56#endif
57
58#include <stdbool.h>
59#include <stdint.h>
60#include <stdlib.h> // will provide posix_memalign with _POSIX_C_SOURCE as defined above
61#if !(defined(__APPLE__)) && !(defined(__FreeBSD__)) && !(defined(__OpenBSD__))
62#include <malloc.h> // this should never be needed but there are some reports that it is needed.
63#endif
64
65
66#if defined(_MSC_VER) && !defined(__clang__) && !defined(_WIN64) && !defined(ROARING_ACK_32BIT)
67#pragma message( \
68 "You appear to be attempting a 32-bit build under Visual Studio. We recommend a 64-bit build instead.")
69#endif
70
71#if defined(__SIZEOF_LONG_LONG__) && __SIZEOF_LONG_LONG__ != 8
72#error This code assumes 64-bit long longs (by use of the GCC intrinsics). Your system is not currently supported.
73#endif
74
75#if defined(_MSC_VER)
76#define __restrict__ __restrict
77#endif
78
79#ifndef DISABLE_X64 // some users may want to compile as if they did not have
80 // an x64 processor
81
82///////////////////////
83/// We support X64 hardware in the following manner:
84///
85/// if IS_X64 is defined then we have at least SSE and SSE2
86/// (All Intel processors sold in the recent past have at least SSE and SSE2 support,
87/// going back to the Pentium 4.)
88///
89/// if USESSE4 is defined then we assume at least SSE4.2, SSE4.1,
90/// SSSE3, SSE3... + IS_X64
91/// if USEAVX is defined, then we assume AVX2, AVX + USESSE4
92///
93/// So if you have hardware that supports AVX but not AVX2, then "USEAVX"
94/// won't be enabled.
95/// If you have hardware that supports SSE4.1, but not SSE4.2, then USESSE4
96/// won't be defined.
97//////////////////////
98
99// unless DISABLEAVX was defined, if we have __AVX2__, we enable AVX
100#if (!defined(USEAVX)) && (!defined(DISABLEAVX)) && (defined(__AVX2__))
101#define USEAVX
102#endif
103
104// if we have __SSE4_2__, we enable SSE4
105#if (defined(__POPCNT__)) && (defined(__SSE4_2__))
106#define USESSE4
107#endif
108
109#if defined(USEAVX) || defined(__x86_64__) || defined(_M_X64)
110// we have an x64 processor
111#define IS_X64
112// we include the intrinsic header
113#ifndef _MSC_VER
114/* Non-Microsoft C/C++-compatible compiler */
115#include <x86intrin.h> // on some recent GCC, this will declare posix_memalign
116#endif
117#endif
118
119#if !defined(USENEON) && !defined(DISABLENEON) && defined(__ARM_NEON)
120# define USENEON
121#endif
122#if defined(USENEON)
123# include <arm_neon.h>
124#endif
125
126#ifndef _MSC_VER
127/* Non-Microsoft C/C++-compatible compiler, assumes that it supports inline
128 * assembly */
129#define ROARING_INLINE_ASM
130#endif
131
132#ifdef USEAVX
133#define USESSE4 // if we have AVX, then we have SSE4
134#define USE_BMI // we assume that AVX2 and BMI go hand and hand
135#define USEAVX2FORDECODING // optimization
136// vector operations should work on not just AVX
137#define ROARING_VECTOR_OPERATIONS_ENABLED // vector unions (optimization)
138#endif
139
140#endif // DISABLE_X64
141
142#ifdef _MSC_VER
143/* Microsoft C/C++-compatible compiler */
144#include <intrin.h>
145
146#ifndef __clang__ // if one compiles with MSVC *with* clang, then these
147 // intrinsics are defined!!!
148// sadly there is no way to check whether we are missing these intrinsics
149// specifically.
150
151/* wrappers for Visual Studio built-ins that look like gcc built-ins */
152/* result might be undefined when input_num is zero */
153static inline int __builtin_ctzll(unsigned long long input_num) {
154 unsigned long index;
155#ifdef _WIN64 // highly recommended!!!
156 _BitScanForward64(&index, input_num);
157#else // if we must support 32-bit Windows
158 if ((uint32_t)input_num != 0) {
159 _BitScanForward(&index, (uint32_t)input_num);
160 } else {
161 _BitScanForward(&index, (uint32_t)(input_num >> 32));
162 index += 32;
163 }
164#endif
165 return index;
166}
167
168/* result might be undefined when input_num is zero */
169static inline int __builtin_clzll(unsigned long long input_num) {
170 unsigned long index;
171#ifdef _WIN64 // highly recommended!!!
172 _BitScanReverse64(&index, input_num);
173#else // if we must support 32-bit Windows
174 if (input_num > 0xFFFFFFFF) {
175 _BitScanReverse(&index, (uint32_t)(input_num >> 32));
176 index += 32;
177 } else {
178 _BitScanReverse(&index, (uint32_t)(input_num));
179 }
180#endif
181 return 63 - index;
182}
183
184/* result might be undefined when input_num is zero */
185#ifdef USESSE4
186/* POPCNT support was added to processors around the release of SSE4.2 */
187/* USESSE4 flag guarantees POPCNT support */
188static inline int __builtin_popcountll(unsigned long long input_num) {
189#ifdef _WIN64 // highly recommended!!!
190 return (int)__popcnt64(input_num);
191#else // if we must support 32-bit Windows
192 return (int)(__popcnt((uint32_t)input_num) +
193 __popcnt((uint32_t)(input_num >> 32)));
194#endif
195}
196#else
197/* software implementation avoids POPCNT */
198static inline int __builtin_popcountll(unsigned long long input_num) {
199 const uint64_t m1 = 0x5555555555555555; //binary: 0101...
200 const uint64_t m2 = 0x3333333333333333; //binary: 00110011..
201 const uint64_t m4 = 0x0f0f0f0f0f0f0f0f; //binary: 4 zeros, 4 ones ...
202 const uint64_t h01 = 0x0101010101010101; //the sum of 256 to the power of 0,1,2,3...
203
204 input_num -= (input_num >> 1) & m1;
205 input_num = (input_num & m2) + ((input_num >> 2) & m2);
206 input_num = (input_num + (input_num >> 4)) & m4;
207 return (input_num * h01) >> 56;
208}
209#endif
210
211/* Use #define so this is effective even under /Ob0 (no inline) */
212#define __builtin_unreachable() __assume(0)
213#endif
214
215#endif
216
217// portable version of posix_memalign
218static inline void *roaring_bitmap_aligned_malloc(size_t alignment, size_t size) {
219 void *p;
220#ifdef _MSC_VER
221 p = _aligned_malloc(size, alignment);
222#elif defined(__MINGW32__) || defined(__MINGW64__)
223 p = __mingw_aligned_malloc(size, alignment);
224#else
225 // somehow, if this is used before including "x86intrin.h", it creates an
226 // implicit defined warning.
227 if (posix_memalign(memptr: &p, alignment: alignment, size: size) != 0) return NULL;
228#endif
229 return p;
230}
231
232static inline void roaring_bitmap_aligned_free(void *memblock) {
233#ifdef _MSC_VER
234 _aligned_free(memblock);
235#elif defined(__MINGW32__) || defined(__MINGW64__)
236 __mingw_aligned_free(memblock);
237#else
238 free(ptr: memblock);
239#endif
240}
241
242#if defined(_MSC_VER)
243#define ALIGNED(x) __declspec(align(x))
244#else
245#if defined(__GNUC__)
246#define ALIGNED(x) __attribute__((aligned(x)))
247#endif
248#endif
249
250#ifdef __GNUC__
251#define WARN_UNUSED __attribute__((warn_unused_result))
252#else
253#define WARN_UNUSED
254#endif
255
256#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100)
257
258static inline int hamming(uint64_t x) {
259#ifdef USESSE4
260 return (int) _mm_popcnt_u64(x);
261#else
262 // won't work under visual studio, but hopeful we have _mm_popcnt_u64 in
263 // many cases
264 return __builtin_popcountll(x);
265#endif
266}
267
268#ifndef UINT64_C
269#define UINT64_C(c) (c##ULL)
270#endif
271
272#ifndef UINT32_C
273#define UINT32_C(c) (c##UL)
274#endif
275
276#endif /* INCLUDE_PORTABILITY_H_ */
277/* end file include/roaring/portability.h */
278/* begin file include/roaring/containers/perfparameters.h */
279#ifndef PERFPARAMETERS_H_
280#define PERFPARAMETERS_H_
281
282#include <stdbool.h>
283
284/**
285During lazy computations, we can transform array containers into bitset
286containers as
287long as we can expect them to have ARRAY_LAZY_LOWERBOUND values.
288*/
289enum { ARRAY_LAZY_LOWERBOUND = 1024 };
290
291/* default initial size of a run container
292 setting it to zero delays the malloc.*/
293enum { RUN_DEFAULT_INIT_SIZE = 0 };
294
295/* default initial size of an array container
296 setting it to zero delays the malloc */
297enum { ARRAY_DEFAULT_INIT_SIZE = 0 };
298
299/* automatic bitset conversion during lazy or */
300#ifndef LAZY_OR_BITSET_CONVERSION
301#define LAZY_OR_BITSET_CONVERSION true
302#endif
303
304/* automatically attempt to convert a bitset to a full run during lazy
305 * evaluation */
306#ifndef LAZY_OR_BITSET_CONVERSION_TO_FULL
307#define LAZY_OR_BITSET_CONVERSION_TO_FULL true
308#endif
309
310/* automatically attempt to convert a bitset to a full run */
311#ifndef OR_BITSET_CONVERSION_TO_FULL
312#define OR_BITSET_CONVERSION_TO_FULL true
313#endif
314
315#endif
316/* end file include/roaring/containers/perfparameters.h */
317/* begin file include/roaring/array_util.h */
318#ifndef ARRAY_UTIL_H
319#define ARRAY_UTIL_H
320
321#include <stddef.h> // for size_t
322#include <stdint.h>
323
324
325/*
326 * Good old binary search.
327 * Assumes that array is sorted, has logarithmic complexity.
328 * if the result is x, then:
329 * if ( x>0 ) you have array[x] = ikey
330 * if ( x<0 ) then inserting ikey at position -x-1 in array (insuring that array[-x-1]=ikey)
331 * keys the array sorted.
332 */
333static inline int32_t binarySearch(const uint16_t *array, int32_t lenarray,
334 uint16_t ikey) {
335 int32_t low = 0;
336 int32_t high = lenarray - 1;
337 while (low <= high) {
338 int32_t middleIndex = (low + high) >> 1;
339 uint16_t middleValue = array[middleIndex];
340 if (middleValue < ikey) {
341 low = middleIndex + 1;
342 } else if (middleValue > ikey) {
343 high = middleIndex - 1;
344 } else {
345 return middleIndex;
346 }
347 }
348 return -(low + 1);
349}
350
351/**
352 * Galloping search
353 * Assumes that array is sorted, has logarithmic complexity.
354 * if the result is x, then if x = length, you have that all values in array between pos and length
355 * are smaller than min.
356 * otherwise returns the first index x such that array[x] >= min.
357 */
358static inline int32_t advanceUntil(const uint16_t *array, int32_t pos,
359 int32_t length, uint16_t min) {
360 int32_t lower = pos + 1;
361
362 if ((lower >= length) || (array[lower] >= min)) {
363 return lower;
364 }
365
366 int32_t spansize = 1;
367
368 while ((lower + spansize < length) && (array[lower + spansize] < min)) {
369 spansize <<= 1;
370 }
371 int32_t upper = (lower + spansize < length) ? lower + spansize : length - 1;
372
373 if (array[upper] == min) {
374 return upper;
375 }
376 if (array[upper] < min) {
377 // means
378 // array
379 // has no
380 // item
381 // >= min
382 // pos = array.length;
383 return length;
384 }
385
386 // we know that the next-smallest span was too small
387 lower += (spansize >> 1);
388
389 int32_t mid = 0;
390 while (lower + 1 != upper) {
391 mid = (lower + upper) >> 1;
392 if (array[mid] == min) {
393 return mid;
394 } else if (array[mid] < min) {
395 lower = mid;
396 } else {
397 upper = mid;
398 }
399 }
400 return upper;
401}
402
403/**
404 * Returns number of elements which are less then $ikey.
405 * Array elements must be unique and sorted.
406 */
407static inline int32_t count_less(const uint16_t *array, int32_t lenarray,
408 uint16_t ikey) {
409 if (lenarray == 0) return 0;
410 int32_t pos = binarySearch(array, lenarray, ikey);
411 return pos >= 0 ? pos : -(pos+1);
412}
413
414/**
415 * Returns number of elements which are greater then $ikey.
416 * Array elements must be unique and sorted.
417 */
418static inline int32_t count_greater(const uint16_t *array, int32_t lenarray,
419 uint16_t ikey) {
420 if (lenarray == 0) return 0;
421 int32_t pos = binarySearch(array, lenarray, ikey);
422 if (pos >= 0) {
423 return lenarray - (pos+1);
424 } else {
425 return lenarray - (-pos-1);
426 }
427}
428
429/**
430 * From Schlegel et al., Fast Sorted-Set Intersection using SIMD Instructions
431 * Optimized by D. Lemire on May 3rd 2013
432 *
433 * C should have capacity greater than the minimum of s_1 and s_b + 8
434 * where 8 is sizeof(__m128i)/sizeof(uint16_t).
435 */
436int32_t intersect_vector16(const uint16_t *__restrict__ A, size_t s_a,
437 const uint16_t *__restrict__ B, size_t s_b,
438 uint16_t *C);
439
440/**
441 * Compute the cardinality of the intersection using SSE4 instructions
442 */
443int32_t intersect_vector16_cardinality(const uint16_t *__restrict__ A,
444 size_t s_a,
445 const uint16_t *__restrict__ B,
446 size_t s_b);
447
448/* Computes the intersection between one small and one large set of uint16_t.
449 * Stores the result into buffer and return the number of elements. */
450int32_t intersect_skewed_uint16(const uint16_t *smallarray, size_t size_s,
451 const uint16_t *largearray, size_t size_l,
452 uint16_t *buffer);
453
454/* Computes the size of the intersection between one small and one large set of
455 * uint16_t. */
456int32_t intersect_skewed_uint16_cardinality(const uint16_t *smallarray,
457 size_t size_s,
458 const uint16_t *largearray,
459 size_t size_l);
460
461
462/* Check whether the size of the intersection between one small and one large set of uint16_t is non-zero. */
463bool intersect_skewed_uint16_nonempty(const uint16_t *smallarray, size_t size_s,
464 const uint16_t *largearray, size_t size_l);
465/**
466 * Generic intersection function.
467 */
468int32_t intersect_uint16(const uint16_t *A, const size_t lenA,
469 const uint16_t *B, const size_t lenB, uint16_t *out);
470/**
471 * Compute the size of the intersection (generic).
472 */
473int32_t intersect_uint16_cardinality(const uint16_t *A, const size_t lenA,
474 const uint16_t *B, const size_t lenB);
475
476/**
477 * Checking whether the size of the intersection is non-zero.
478 */
479bool intersect_uint16_nonempty(const uint16_t *A, const size_t lenA,
480 const uint16_t *B, const size_t lenB);
481/**
482 * Generic union function.
483 */
484size_t union_uint16(const uint16_t *set_1, size_t size_1, const uint16_t *set_2,
485 size_t size_2, uint16_t *buffer);
486
487/**
488 * Generic XOR function.
489 */
490int32_t xor_uint16(const uint16_t *array_1, int32_t card_1,
491 const uint16_t *array_2, int32_t card_2, uint16_t *out);
492
493/**
494 * Generic difference function (ANDNOT).
495 */
496int difference_uint16(const uint16_t *a1, int length1, const uint16_t *a2,
497 int length2, uint16_t *a_out);
498
499/**
500 * Generic intersection function.
501 */
502size_t intersection_uint32(const uint32_t *A, const size_t lenA,
503 const uint32_t *B, const size_t lenB, uint32_t *out);
504
505/**
506 * Generic intersection function, returns just the cardinality.
507 */
508size_t intersection_uint32_card(const uint32_t *A, const size_t lenA,
509 const uint32_t *B, const size_t lenB);
510
511/**
512 * Generic union function.
513 */
514size_t union_uint32(const uint32_t *set_1, size_t size_1, const uint32_t *set_2,
515 size_t size_2, uint32_t *buffer);
516
517/**
518 * A fast SSE-based union function.
519 */
520uint32_t union_vector16(const uint16_t *__restrict__ set_1, uint32_t size_1,
521 const uint16_t *__restrict__ set_2, uint32_t size_2,
522 uint16_t *__restrict__ buffer);
523/**
524 * A fast SSE-based XOR function.
525 */
526uint32_t xor_vector16(const uint16_t *__restrict__ array1, uint32_t length1,
527 const uint16_t *__restrict__ array2, uint32_t length2,
528 uint16_t *__restrict__ output);
529
530/**
531 * A fast SSE-based difference function.
532 */
533int32_t difference_vector16(const uint16_t *__restrict__ A, size_t s_a,
534 const uint16_t *__restrict__ B, size_t s_b,
535 uint16_t *C);
536
537/**
538 * Generic union function, returns just the cardinality.
539 */
540size_t union_uint32_card(const uint32_t *set_1, size_t size_1,
541 const uint32_t *set_2, size_t size_2);
542
543/**
544* combines union_uint16 and union_vector16 optimally
545*/
546size_t fast_union_uint16(const uint16_t *set_1, size_t size_1, const uint16_t *set_2,
547 size_t size_2, uint16_t *buffer);
548
549
550bool memequals(const void *s1, const void *s2, size_t n);
551
552#endif
553/* end file include/roaring/array_util.h */
554/* begin file include/roaring/roaring_types.h */
555/*
556 Typedefs used by various components
557*/
558
559#ifndef ROARING_TYPES_H
560#define ROARING_TYPES_H
561
562typedef bool (*roaring_iterator)(uint32_t value, void *param);
563typedef bool (*roaring_iterator64)(uint64_t value, void *param);
564
565/**
566* (For advanced users.)
567* The roaring_statistics_t can be used to collect detailed statistics about
568* the composition of a roaring bitmap.
569*/
570typedef struct roaring_statistics_s {
571 uint32_t n_containers; /* number of containers */
572
573 uint32_t n_array_containers; /* number of array containers */
574 uint32_t n_run_containers; /* number of run containers */
575 uint32_t n_bitset_containers; /* number of bitmap containers */
576
577 uint32_t
578 n_values_array_containers; /* number of values in array containers */
579 uint32_t n_values_run_containers; /* number of values in run containers */
580 uint32_t
581 n_values_bitset_containers; /* number of values in bitmap containers */
582
583 uint32_t n_bytes_array_containers; /* number of allocated bytes in array
584 containers */
585 uint32_t n_bytes_run_containers; /* number of allocated bytes in run
586 containers */
587 uint32_t n_bytes_bitset_containers; /* number of allocated bytes in bitmap
588 containers */
589
590 uint32_t
591 max_value; /* the maximal value, undefined if cardinality is zero */
592 uint32_t
593 min_value; /* the minimal value, undefined if cardinality is zero */
594 uint64_t sum_value; /* the sum of all values (could be used to compute
595 average) */
596
597 uint64_t cardinality; /* total number of values stored in the bitmap */
598
599 // and n_values_arrays, n_values_rle, n_values_bitmap
600} roaring_statistics_t;
601
602#endif /* ROARING_TYPES_H */
603/* end file include/roaring/roaring_types.h */
604/* begin file include/roaring/utilasm.h */
605/*
606 * utilasm.h
607 *
608 */
609
610#ifndef INCLUDE_UTILASM_H_
611#define INCLUDE_UTILASM_H_
612
613
614#if defined(USE_BMI) & defined(ROARING_INLINE_ASM)
615#define ASMBITMANIPOPTIMIZATION // optimization flag
616
617#define ASM_SHIFT_RIGHT(srcReg, bitsReg, destReg) \
618 __asm volatile("shrx %1, %2, %0" \
619 : "=r"(destReg) \
620 : /* write */ \
621 "r"(bitsReg), /* read only */ \
622 "r"(srcReg) /* read only */ \
623 )
624
625#define ASM_INPLACESHIFT_RIGHT(srcReg, bitsReg) \
626 __asm volatile("shrx %1, %0, %0" \
627 : "+r"(srcReg) \
628 : /* read/write */ \
629 "r"(bitsReg) /* read only */ \
630 )
631
632#define ASM_SHIFT_LEFT(srcReg, bitsReg, destReg) \
633 __asm volatile("shlx %1, %2, %0" \
634 : "=r"(destReg) \
635 : /* write */ \
636 "r"(bitsReg), /* read only */ \
637 "r"(srcReg) /* read only */ \
638 )
639// set bit at position testBit within testByte to 1 and
640// copy cmovDst to cmovSrc if that bit was previously clear
641#define ASM_SET_BIT_INC_WAS_CLEAR(testByte, testBit, count) \
642 __asm volatile( \
643 "bts %2, %0\n" \
644 "sbb $-1, %1\n" \
645 : "+r"(testByte), /* read/write */ \
646 "+r"(count) \
647 : /* read/write */ \
648 "r"(testBit) /* read only */ \
649 )
650
651#define ASM_CLEAR_BIT_DEC_WAS_SET(testByte, testBit, count) \
652 __asm volatile( \
653 "btr %2, %0\n" \
654 "sbb $0, %1\n" \
655 : "+r"(testByte), /* read/write */ \
656 "+r"(count) \
657 : /* read/write */ \
658 "r"(testBit) /* read only */ \
659 )
660
661#define ASM_BT64(testByte, testBit, count) \
662 __asm volatile( \
663 "bt %2,%1\n" \
664 "sbb %0,%0" /*could use setb */ \
665 : "=r"(count) \
666 : /* write */ \
667 "r"(testByte), /* read only */ \
668 "r"(testBit) /* read only */ \
669 )
670
671#endif // USE_BMI
672#endif /* INCLUDE_UTILASM_H_ */
673/* end file include/roaring/utilasm.h */
674/* begin file include/roaring/bitset_util.h */
675#ifndef BITSET_UTIL_H
676#define BITSET_UTIL_H
677
678#include <stdint.h>
679
680
681/*
682 * Set all bits in indexes [begin,end) to true.
683 */
684static inline void bitset_set_range(uint64_t *bitmap, uint32_t start,
685 uint32_t end) {
686 if (start == end) return;
687 uint32_t firstword = start / 64;
688 uint32_t endword = (end - 1) / 64;
689 if (firstword == endword) {
690 bitmap[firstword] |= ((~UINT64_C(0)) << (start % 64)) &
691 ((~UINT64_C(0)) >> ((~end + 1) % 64));
692 return;
693 }
694 bitmap[firstword] |= (~UINT64_C(0)) << (start % 64);
695 for (uint32_t i = firstword + 1; i < endword; i++) bitmap[i] = ~UINT64_C(0);
696 bitmap[endword] |= (~UINT64_C(0)) >> ((~end + 1) % 64);
697}
698
699
700/*
701 * Find the cardinality of the bitset in [begin,begin+lenminusone]
702 */
703static inline int bitset_lenrange_cardinality(uint64_t *bitmap, uint32_t start,
704 uint32_t lenminusone) {
705 uint32_t firstword = start / 64;
706 uint32_t endword = (start + lenminusone) / 64;
707 if (firstword == endword) {
708 return hamming(x: bitmap[firstword] &
709 ((~UINT64_C(0)) >> ((63 - lenminusone) % 64))
710 << (start % 64));
711 }
712 int answer = hamming(x: bitmap[firstword] & ((~UINT64_C(0)) << (start % 64)));
713 for (uint32_t i = firstword + 1; i < endword; i++) {
714 answer += hamming(x: bitmap[i]);
715 }
716 answer +=
717 hamming(x: bitmap[endword] &
718 (~UINT64_C(0)) >> (((~start + 1) - lenminusone - 1) % 64));
719 return answer;
720}
721
722/*
723 * Check whether the cardinality of the bitset in [begin,begin+lenminusone] is 0
724 */
725static inline bool bitset_lenrange_empty(uint64_t *bitmap, uint32_t start,
726 uint32_t lenminusone) {
727 uint32_t firstword = start / 64;
728 uint32_t endword = (start + lenminusone) / 64;
729 if (firstword == endword) {
730 return (bitmap[firstword] & ((~UINT64_C(0)) >> ((63 - lenminusone) % 64))
731 << (start % 64)) == 0;
732 }
733 if(((bitmap[firstword] & ((~UINT64_C(0)) << (start%64)))) != 0) return false;
734 for (uint32_t i = firstword + 1; i < endword; i++) {
735 if(bitmap[i] != 0) return false;
736 }
737 if((bitmap[endword] & (~UINT64_C(0)) >> (((~start + 1) - lenminusone - 1) % 64)) != 0) return false;
738 return true;
739}
740
741
742/*
743 * Set all bits in indexes [begin,begin+lenminusone] to true.
744 */
745static inline void bitset_set_lenrange(uint64_t *bitmap, uint32_t start,
746 uint32_t lenminusone) {
747 uint32_t firstword = start / 64;
748 uint32_t endword = (start + lenminusone) / 64;
749 if (firstword == endword) {
750 bitmap[firstword] |= ((~UINT64_C(0)) >> ((63 - lenminusone) % 64))
751 << (start % 64);
752 return;
753 }
754 uint64_t temp = bitmap[endword];
755 bitmap[firstword] |= (~UINT64_C(0)) << (start % 64);
756 for (uint32_t i = firstword + 1; i < endword; i += 2)
757 bitmap[i] = bitmap[i + 1] = ~UINT64_C(0);
758 bitmap[endword] =
759 temp | (~UINT64_C(0)) >> (((~start + 1) - lenminusone - 1) % 64);
760}
761
762/*
763 * Flip all the bits in indexes [begin,end).
764 */
765static inline void bitset_flip_range(uint64_t *bitmap, uint32_t start,
766 uint32_t end) {
767 if (start == end) return;
768 uint32_t firstword = start / 64;
769 uint32_t endword = (end - 1) / 64;
770 bitmap[firstword] ^= ~((~UINT64_C(0)) << (start % 64));
771 for (uint32_t i = firstword; i < endword; i++) bitmap[i] = ~bitmap[i];
772 bitmap[endword] ^= ((~UINT64_C(0)) >> ((~end + 1) % 64));
773}
774
775/*
776 * Set all bits in indexes [begin,end) to false.
777 */
778static inline void bitset_reset_range(uint64_t *bitmap, uint32_t start,
779 uint32_t end) {
780 if (start == end) return;
781 uint32_t firstword = start / 64;
782 uint32_t endword = (end - 1) / 64;
783 if (firstword == endword) {
784 bitmap[firstword] &= ~(((~UINT64_C(0)) << (start % 64)) &
785 ((~UINT64_C(0)) >> ((~end + 1) % 64)));
786 return;
787 }
788 bitmap[firstword] &= ~((~UINT64_C(0)) << (start % 64));
789 for (uint32_t i = firstword + 1; i < endword; i++) bitmap[i] = UINT64_C(0);
790 bitmap[endword] &= ~((~UINT64_C(0)) >> ((~end + 1) % 64));
791}
792
793/*
794 * Given a bitset containing "length" 64-bit words, write out the position
795 * of all the set bits to "out", values start at "base".
796 *
797 * The "out" pointer should be sufficient to store the actual number of bits
798 * set.
799 *
800 * Returns how many values were actually decoded.
801 *
802 * This function should only be expected to be faster than
803 * bitset_extract_setbits
804 * when the density of the bitset is high.
805 *
806 * This function uses AVX2 decoding.
807 */
808size_t bitset_extract_setbits_avx2(uint64_t *bitset, size_t length, void *vout,
809 size_t outcapacity, uint32_t base);
810
811/*
812 * Given a bitset containing "length" 64-bit words, write out the position
813 * of all the set bits to "out", values start at "base".
814 *
815 * The "out" pointer should be sufficient to store the actual number of bits
816 *set.
817 *
818 * Returns how many values were actually decoded.
819 */
820size_t bitset_extract_setbits(uint64_t *bitset, size_t length, void *vout,
821 uint32_t base);
822
823/*
824 * Given a bitset containing "length" 64-bit words, write out the position
825 * of all the set bits to "out" as 16-bit integers, values start at "base" (can
826 *be set to zero)
827 *
828 * The "out" pointer should be sufficient to store the actual number of bits
829 *set.
830 *
831 * Returns how many values were actually decoded.
832 *
833 * This function should only be expected to be faster than
834 *bitset_extract_setbits_uint16
835 * when the density of the bitset is high.
836 *
837 * This function uses SSE decoding.
838 */
839size_t bitset_extract_setbits_sse_uint16(const uint64_t *bitset, size_t length,
840 uint16_t *out, size_t outcapacity,
841 uint16_t base);
842
843/*
844 * Given a bitset containing "length" 64-bit words, write out the position
845 * of all the set bits to "out", values start at "base"
846 * (can be set to zero)
847 *
848 * The "out" pointer should be sufficient to store the actual number of bits
849 *set.
850 *
851 * Returns how many values were actually decoded.
852 */
853size_t bitset_extract_setbits_uint16(const uint64_t *bitset, size_t length,
854 uint16_t *out, uint16_t base);
855
856/*
857 * Given two bitsets containing "length" 64-bit words, write out the position
858 * of all the common set bits to "out", values start at "base"
859 * (can be set to zero)
860 *
861 * The "out" pointer should be sufficient to store the actual number of bits
862 * set.
863 *
864 * Returns how many values were actually decoded.
865 */
866size_t bitset_extract_intersection_setbits_uint16(const uint64_t * __restrict__ bitset1,
867 const uint64_t * __restrict__ bitset2,
868 size_t length, uint16_t *out,
869 uint16_t base);
870
871/*
872 * Given a bitset having cardinality card, set all bit values in the list (there
873 * are length of them)
874 * and return the updated cardinality. This evidently assumes that the bitset
875 * already contained data.
876 */
877uint64_t bitset_set_list_withcard(void *bitset, uint64_t card,
878 const uint16_t *list, uint64_t length);
879/*
880 * Given a bitset, set all bit values in the list (there
881 * are length of them).
882 */
883void bitset_set_list(void *bitset, const uint16_t *list, uint64_t length);
884
885/*
886 * Given a bitset having cardinality card, unset all bit values in the list
887 * (there are length of them)
888 * and return the updated cardinality. This evidently assumes that the bitset
889 * already contained data.
890 */
891uint64_t bitset_clear_list(void *bitset, uint64_t card, const uint16_t *list,
892 uint64_t length);
893
894/*
895 * Given a bitset having cardinality card, toggle all bit values in the list
896 * (there are length of them)
897 * and return the updated cardinality. This evidently assumes that the bitset
898 * already contained data.
899 */
900
901uint64_t bitset_flip_list_withcard(void *bitset, uint64_t card,
902 const uint16_t *list, uint64_t length);
903
904void bitset_flip_list(void *bitset, const uint16_t *list, uint64_t length);
905
906#ifdef USEAVX
907/***
908 * BEGIN Harley-Seal popcount functions.
909 */
910
911/**
912 * Compute the population count of a 256-bit word
913 * This is not especially fast, but it is convenient as part of other functions.
914 */
915static inline __m256i popcount256(__m256i v) {
916 const __m256i lookuppos = _mm256_setr_epi8(
917 /* 0 */ 4 + 0, /* 1 */ 4 + 1, /* 2 */ 4 + 1, /* 3 */ 4 + 2,
918 /* 4 */ 4 + 1, /* 5 */ 4 + 2, /* 6 */ 4 + 2, /* 7 */ 4 + 3,
919 /* 8 */ 4 + 1, /* 9 */ 4 + 2, /* a */ 4 + 2, /* b */ 4 + 3,
920 /* c */ 4 + 2, /* d */ 4 + 3, /* e */ 4 + 3, /* f */ 4 + 4,
921
922 /* 0 */ 4 + 0, /* 1 */ 4 + 1, /* 2 */ 4 + 1, /* 3 */ 4 + 2,
923 /* 4 */ 4 + 1, /* 5 */ 4 + 2, /* 6 */ 4 + 2, /* 7 */ 4 + 3,
924 /* 8 */ 4 + 1, /* 9 */ 4 + 2, /* a */ 4 + 2, /* b */ 4 + 3,
925 /* c */ 4 + 2, /* d */ 4 + 3, /* e */ 4 + 3, /* f */ 4 + 4);
926 const __m256i lookupneg = _mm256_setr_epi8(
927 /* 0 */ 4 - 0, /* 1 */ 4 - 1, /* 2 */ 4 - 1, /* 3 */ 4 - 2,
928 /* 4 */ 4 - 1, /* 5 */ 4 - 2, /* 6 */ 4 - 2, /* 7 */ 4 - 3,
929 /* 8 */ 4 - 1, /* 9 */ 4 - 2, /* a */ 4 - 2, /* b */ 4 - 3,
930 /* c */ 4 - 2, /* d */ 4 - 3, /* e */ 4 - 3, /* f */ 4 - 4,
931
932 /* 0 */ 4 - 0, /* 1 */ 4 - 1, /* 2 */ 4 - 1, /* 3 */ 4 - 2,
933 /* 4 */ 4 - 1, /* 5 */ 4 - 2, /* 6 */ 4 - 2, /* 7 */ 4 - 3,
934 /* 8 */ 4 - 1, /* 9 */ 4 - 2, /* a */ 4 - 2, /* b */ 4 - 3,
935 /* c */ 4 - 2, /* d */ 4 - 3, /* e */ 4 - 3, /* f */ 4 - 4);
936 const __m256i low_mask = _mm256_set1_epi8(0x0f);
937
938 const __m256i lo = _mm256_and_si256(v, low_mask);
939 const __m256i hi = _mm256_and_si256(_mm256_srli_epi16(v, 4), low_mask);
940 const __m256i popcnt1 = _mm256_shuffle_epi8(lookuppos, lo);
941 const __m256i popcnt2 = _mm256_shuffle_epi8(lookupneg, hi);
942 return _mm256_sad_epu8(popcnt1, popcnt2);
943}
944
945/**
946 * Simple CSA over 256 bits
947 */
948static inline void CSA(__m256i *h, __m256i *l, __m256i a, __m256i b,
949 __m256i c) {
950 const __m256i u = _mm256_xor_si256(a, b);
951 *h = _mm256_or_si256(_mm256_and_si256(a, b), _mm256_and_si256(u, c));
952 *l = _mm256_xor_si256(u, c);
953}
954
955/**
956 * Fast Harley-Seal AVX population count function
957 */
958inline static uint64_t avx2_harley_seal_popcount256(const __m256i *data,
959 const uint64_t size) {
960 __m256i total = _mm256_setzero_si256();
961 __m256i ones = _mm256_setzero_si256();
962 __m256i twos = _mm256_setzero_si256();
963 __m256i fours = _mm256_setzero_si256();
964 __m256i eights = _mm256_setzero_si256();
965 __m256i sixteens = _mm256_setzero_si256();
966 __m256i twosA, twosB, foursA, foursB, eightsA, eightsB;
967
968 const uint64_t limit = size - size % 16;
969 uint64_t i = 0;
970
971 for (; i < limit; i += 16) {
972 CSA(&twosA, &ones, ones, _mm256_lddqu_si256(data + i),
973 _mm256_lddqu_si256(data + i + 1));
974 CSA(&twosB, &ones, ones, _mm256_lddqu_si256(data + i + 2),
975 _mm256_lddqu_si256(data + i + 3));
976 CSA(&foursA, &twos, twos, twosA, twosB);
977 CSA(&twosA, &ones, ones, _mm256_lddqu_si256(data + i + 4),
978 _mm256_lddqu_si256(data + i + 5));
979 CSA(&twosB, &ones, ones, _mm256_lddqu_si256(data + i + 6),
980 _mm256_lddqu_si256(data + i + 7));
981 CSA(&foursB, &twos, twos, twosA, twosB);
982 CSA(&eightsA, &fours, fours, foursA, foursB);
983 CSA(&twosA, &ones, ones, _mm256_lddqu_si256(data + i + 8),
984 _mm256_lddqu_si256(data + i + 9));
985 CSA(&twosB, &ones, ones, _mm256_lddqu_si256(data + i + 10),
986 _mm256_lddqu_si256(data + i + 11));
987 CSA(&foursA, &twos, twos, twosA, twosB);
988 CSA(&twosA, &ones, ones, _mm256_lddqu_si256(data + i + 12),
989 _mm256_lddqu_si256(data + i + 13));
990 CSA(&twosB, &ones, ones, _mm256_lddqu_si256(data + i + 14),
991 _mm256_lddqu_si256(data + i + 15));
992 CSA(&foursB, &twos, twos, twosA, twosB);
993 CSA(&eightsB, &fours, fours, foursA, foursB);
994 CSA(&sixteens, &eights, eights, eightsA, eightsB);
995
996 total = _mm256_add_epi64(total, popcount256(sixteens));
997 }
998
999 total = _mm256_slli_epi64(total, 4); // * 16
1000 total = _mm256_add_epi64(
1001 total, _mm256_slli_epi64(popcount256(eights), 3)); // += 8 * ...
1002 total = _mm256_add_epi64(
1003 total, _mm256_slli_epi64(popcount256(fours), 2)); // += 4 * ...
1004 total = _mm256_add_epi64(
1005 total, _mm256_slli_epi64(popcount256(twos), 1)); // += 2 * ...
1006 total = _mm256_add_epi64(total, popcount256(ones));
1007 for (; i < size; i++)
1008 total =
1009 _mm256_add_epi64(total, popcount256(_mm256_lddqu_si256(data + i)));
1010
1011 return (uint64_t)(_mm256_extract_epi64(total, 0)) +
1012 (uint64_t)(_mm256_extract_epi64(total, 1)) +
1013 (uint64_t)(_mm256_extract_epi64(total, 2)) +
1014 (uint64_t)(_mm256_extract_epi64(total, 3));
1015}
1016
1017#define AVXPOPCNTFNC(opname, avx_intrinsic) \
1018 static inline uint64_t avx2_harley_seal_popcount256_##opname( \
1019 const __m256i *data1, const __m256i *data2, const uint64_t size) { \
1020 __m256i total = _mm256_setzero_si256(); \
1021 __m256i ones = _mm256_setzero_si256(); \
1022 __m256i twos = _mm256_setzero_si256(); \
1023 __m256i fours = _mm256_setzero_si256(); \
1024 __m256i eights = _mm256_setzero_si256(); \
1025 __m256i sixteens = _mm256_setzero_si256(); \
1026 __m256i twosA, twosB, foursA, foursB, eightsA, eightsB; \
1027 __m256i A1, A2; \
1028 const uint64_t limit = size - size % 16; \
1029 uint64_t i = 0; \
1030 for (; i < limit; i += 16) { \
1031 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i), \
1032 _mm256_lddqu_si256(data2 + i)); \
1033 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 1), \
1034 _mm256_lddqu_si256(data2 + i + 1)); \
1035 CSA(&twosA, &ones, ones, A1, A2); \
1036 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 2), \
1037 _mm256_lddqu_si256(data2 + i + 2)); \
1038 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 3), \
1039 _mm256_lddqu_si256(data2 + i + 3)); \
1040 CSA(&twosB, &ones, ones, A1, A2); \
1041 CSA(&foursA, &twos, twos, twosA, twosB); \
1042 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 4), \
1043 _mm256_lddqu_si256(data2 + i + 4)); \
1044 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 5), \
1045 _mm256_lddqu_si256(data2 + i + 5)); \
1046 CSA(&twosA, &ones, ones, A1, A2); \
1047 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 6), \
1048 _mm256_lddqu_si256(data2 + i + 6)); \
1049 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 7), \
1050 _mm256_lddqu_si256(data2 + i + 7)); \
1051 CSA(&twosB, &ones, ones, A1, A2); \
1052 CSA(&foursB, &twos, twos, twosA, twosB); \
1053 CSA(&eightsA, &fours, fours, foursA, foursB); \
1054 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 8), \
1055 _mm256_lddqu_si256(data2 + i + 8)); \
1056 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 9), \
1057 _mm256_lddqu_si256(data2 + i + 9)); \
1058 CSA(&twosA, &ones, ones, A1, A2); \
1059 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 10), \
1060 _mm256_lddqu_si256(data2 + i + 10)); \
1061 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 11), \
1062 _mm256_lddqu_si256(data2 + i + 11)); \
1063 CSA(&twosB, &ones, ones, A1, A2); \
1064 CSA(&foursA, &twos, twos, twosA, twosB); \
1065 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 12), \
1066 _mm256_lddqu_si256(data2 + i + 12)); \
1067 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 13), \
1068 _mm256_lddqu_si256(data2 + i + 13)); \
1069 CSA(&twosA, &ones, ones, A1, A2); \
1070 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 14), \
1071 _mm256_lddqu_si256(data2 + i + 14)); \
1072 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 15), \
1073 _mm256_lddqu_si256(data2 + i + 15)); \
1074 CSA(&twosB, &ones, ones, A1, A2); \
1075 CSA(&foursB, &twos, twos, twosA, twosB); \
1076 CSA(&eightsB, &fours, fours, foursA, foursB); \
1077 CSA(&sixteens, &eights, eights, eightsA, eightsB); \
1078 total = _mm256_add_epi64(total, popcount256(sixteens)); \
1079 } \
1080 total = _mm256_slli_epi64(total, 4); \
1081 total = _mm256_add_epi64(total, \
1082 _mm256_slli_epi64(popcount256(eights), 3)); \
1083 total = \
1084 _mm256_add_epi64(total, _mm256_slli_epi64(popcount256(fours), 2)); \
1085 total = \
1086 _mm256_add_epi64(total, _mm256_slli_epi64(popcount256(twos), 1)); \
1087 total = _mm256_add_epi64(total, popcount256(ones)); \
1088 for (; i < size; i++) { \
1089 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i), \
1090 _mm256_lddqu_si256(data2 + i)); \
1091 total = _mm256_add_epi64(total, popcount256(A1)); \
1092 } \
1093 return (uint64_t)(_mm256_extract_epi64(total, 0)) + \
1094 (uint64_t)(_mm256_extract_epi64(total, 1)) + \
1095 (uint64_t)(_mm256_extract_epi64(total, 2)) + \
1096 (uint64_t)(_mm256_extract_epi64(total, 3)); \
1097 } \
1098 static inline uint64_t avx2_harley_seal_popcount256andstore_##opname( \
1099 const __m256i *__restrict__ data1, const __m256i *__restrict__ data2, \
1100 __m256i *__restrict__ out, const uint64_t size) { \
1101 __m256i total = _mm256_setzero_si256(); \
1102 __m256i ones = _mm256_setzero_si256(); \
1103 __m256i twos = _mm256_setzero_si256(); \
1104 __m256i fours = _mm256_setzero_si256(); \
1105 __m256i eights = _mm256_setzero_si256(); \
1106 __m256i sixteens = _mm256_setzero_si256(); \
1107 __m256i twosA, twosB, foursA, foursB, eightsA, eightsB; \
1108 __m256i A1, A2; \
1109 const uint64_t limit = size - size % 16; \
1110 uint64_t i = 0; \
1111 for (; i < limit; i += 16) { \
1112 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i), \
1113 _mm256_lddqu_si256(data2 + i)); \
1114 _mm256_storeu_si256(out + i, A1); \
1115 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 1), \
1116 _mm256_lddqu_si256(data2 + i + 1)); \
1117 _mm256_storeu_si256(out + i + 1, A2); \
1118 CSA(&twosA, &ones, ones, A1, A2); \
1119 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 2), \
1120 _mm256_lddqu_si256(data2 + i + 2)); \
1121 _mm256_storeu_si256(out + i + 2, A1); \
1122 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 3), \
1123 _mm256_lddqu_si256(data2 + i + 3)); \
1124 _mm256_storeu_si256(out + i + 3, A2); \
1125 CSA(&twosB, &ones, ones, A1, A2); \
1126 CSA(&foursA, &twos, twos, twosA, twosB); \
1127 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 4), \
1128 _mm256_lddqu_si256(data2 + i + 4)); \
1129 _mm256_storeu_si256(out + i + 4, A1); \
1130 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 5), \
1131 _mm256_lddqu_si256(data2 + i + 5)); \
1132 _mm256_storeu_si256(out + i + 5, A2); \
1133 CSA(&twosA, &ones, ones, A1, A2); \
1134 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 6), \
1135 _mm256_lddqu_si256(data2 + i + 6)); \
1136 _mm256_storeu_si256(out + i + 6, A1); \
1137 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 7), \
1138 _mm256_lddqu_si256(data2 + i + 7)); \
1139 _mm256_storeu_si256(out + i + 7, A2); \
1140 CSA(&twosB, &ones, ones, A1, A2); \
1141 CSA(&foursB, &twos, twos, twosA, twosB); \
1142 CSA(&eightsA, &fours, fours, foursA, foursB); \
1143 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 8), \
1144 _mm256_lddqu_si256(data2 + i + 8)); \
1145 _mm256_storeu_si256(out + i + 8, A1); \
1146 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 9), \
1147 _mm256_lddqu_si256(data2 + i + 9)); \
1148 _mm256_storeu_si256(out + i + 9, A2); \
1149 CSA(&twosA, &ones, ones, A1, A2); \
1150 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 10), \
1151 _mm256_lddqu_si256(data2 + i + 10)); \
1152 _mm256_storeu_si256(out + i + 10, A1); \
1153 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 11), \
1154 _mm256_lddqu_si256(data2 + i + 11)); \
1155 _mm256_storeu_si256(out + i + 11, A2); \
1156 CSA(&twosB, &ones, ones, A1, A2); \
1157 CSA(&foursA, &twos, twos, twosA, twosB); \
1158 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 12), \
1159 _mm256_lddqu_si256(data2 + i + 12)); \
1160 _mm256_storeu_si256(out + i + 12, A1); \
1161 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 13), \
1162 _mm256_lddqu_si256(data2 + i + 13)); \
1163 _mm256_storeu_si256(out + i + 13, A2); \
1164 CSA(&twosA, &ones, ones, A1, A2); \
1165 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 14), \
1166 _mm256_lddqu_si256(data2 + i + 14)); \
1167 _mm256_storeu_si256(out + i + 14, A1); \
1168 A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 15), \
1169 _mm256_lddqu_si256(data2 + i + 15)); \
1170 _mm256_storeu_si256(out + i + 15, A2); \
1171 CSA(&twosB, &ones, ones, A1, A2); \
1172 CSA(&foursB, &twos, twos, twosA, twosB); \
1173 CSA(&eightsB, &fours, fours, foursA, foursB); \
1174 CSA(&sixteens, &eights, eights, eightsA, eightsB); \
1175 total = _mm256_add_epi64(total, popcount256(sixteens)); \
1176 } \
1177 total = _mm256_slli_epi64(total, 4); \
1178 total = _mm256_add_epi64(total, \
1179 _mm256_slli_epi64(popcount256(eights), 3)); \
1180 total = \
1181 _mm256_add_epi64(total, _mm256_slli_epi64(popcount256(fours), 2)); \
1182 total = \
1183 _mm256_add_epi64(total, _mm256_slli_epi64(popcount256(twos), 1)); \
1184 total = _mm256_add_epi64(total, popcount256(ones)); \
1185 for (; i < size; i++) { \
1186 A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i), \
1187 _mm256_lddqu_si256(data2 + i)); \
1188 _mm256_storeu_si256(out + i, A1); \
1189 total = _mm256_add_epi64(total, popcount256(A1)); \
1190 } \
1191 return (uint64_t)(_mm256_extract_epi64(total, 0)) + \
1192 (uint64_t)(_mm256_extract_epi64(total, 1)) + \
1193 (uint64_t)(_mm256_extract_epi64(total, 2)) + \
1194 (uint64_t)(_mm256_extract_epi64(total, 3)); \
1195 }
1196
1197AVXPOPCNTFNC(or, _mm256_or_si256)
1198AVXPOPCNTFNC(union, _mm256_or_si256)
1199AVXPOPCNTFNC(and, _mm256_and_si256)
1200AVXPOPCNTFNC(intersection, _mm256_and_si256)
1201AVXPOPCNTFNC (xor, _mm256_xor_si256)
1202AVXPOPCNTFNC(andnot, _mm256_andnot_si256)
1203
1204/***
1205 * END Harley-Seal popcount functions.
1206 */
1207
1208#endif // USEAVX
1209
1210#endif
1211/* end file include/roaring/bitset_util.h */
1212/* begin file include/roaring/containers/array.h */
1213/*
1214 * array.h
1215 *
1216 */
1217
1218#ifndef INCLUDE_CONTAINERS_ARRAY_H_
1219#define INCLUDE_CONTAINERS_ARRAY_H_
1220
1221#include <string.h>
1222
1223
1224/* Containers with DEFAULT_MAX_SIZE or less integers should be arrays */
1225enum { DEFAULT_MAX_SIZE = 4096 };
1226
1227/* struct array_container - sparse representation of a bitmap
1228 *
1229 * @cardinality: number of indices in `array` (and the bitmap)
1230 * @capacity: allocated size of `array`
1231 * @array: sorted list of integers
1232 */
1233struct array_container_s {
1234 int32_t cardinality;
1235 int32_t capacity;
1236 uint16_t *array;
1237};
1238
1239typedef struct array_container_s array_container_t;
1240
1241/* Create a new array with default. Return NULL in case of failure. See also
1242 * array_container_create_given_capacity. */
1243array_container_t *array_container_create(void);
1244
1245/* Create a new array with a specified capacity size. Return NULL in case of
1246 * failure. */
1247array_container_t *array_container_create_given_capacity(int32_t size);
1248
1249/* Create a new array containing all values in [min,max). */
1250array_container_t * array_container_create_range(uint32_t min, uint32_t max);
1251
1252/*
1253 * Shrink the capacity to the actual size, return the number of bytes saved.
1254 */
1255int array_container_shrink_to_fit(array_container_t *src);
1256
1257/* Free memory owned by `array'. */
1258void array_container_free(array_container_t *array);
1259
1260/* Duplicate container */
1261array_container_t *array_container_clone(const array_container_t *src);
1262
1263int32_t array_container_serialize(const array_container_t *container,
1264 char *buf) WARN_UNUSED;
1265
1266uint32_t array_container_serialization_len(const array_container_t *container);
1267
1268void *array_container_deserialize(const char *buf, size_t buf_len);
1269
1270/* Get the cardinality of `array'. */
1271static inline int array_container_cardinality(const array_container_t *array) {
1272 return array->cardinality;
1273}
1274
1275static inline bool array_container_nonzero_cardinality(
1276 const array_container_t *array) {
1277 return array->cardinality > 0;
1278}
1279
1280/* Copy one container into another. We assume that they are distinct. */
1281void array_container_copy(const array_container_t *src, array_container_t *dst);
1282
1283/* Add all the values in [min,max) (included) at a distance k*step from min.
1284 The container must have a size less or equal to DEFAULT_MAX_SIZE after this
1285 addition. */
1286void array_container_add_from_range(array_container_t *arr, uint32_t min,
1287 uint32_t max, uint16_t step);
1288
1289/* Set the cardinality to zero (does not release memory). */
1290static inline void array_container_clear(array_container_t *array) {
1291 array->cardinality = 0;
1292}
1293
1294static inline bool array_container_empty(const array_container_t *array) {
1295 return array->cardinality == 0;
1296}
1297
1298/* check whether the cardinality is equal to the capacity (this does not mean
1299* that it contains 1<<16 elements) */
1300static inline bool array_container_full(const array_container_t *array) {
1301 return array->cardinality == array->capacity;
1302}
1303
1304
1305/* Compute the union of `src_1' and `src_2' and write the result to `dst'
1306 * It is assumed that `dst' is distinct from both `src_1' and `src_2'. */
1307void array_container_union(const array_container_t *src_1,
1308 const array_container_t *src_2,
1309 array_container_t *dst);
1310
1311/* symmetric difference, see array_container_union */
1312void array_container_xor(const array_container_t *array_1,
1313 const array_container_t *array_2,
1314 array_container_t *out);
1315
1316/* Computes the intersection of src_1 and src_2 and write the result to
1317 * dst. It is assumed that dst is distinct from both src_1 and src_2. */
1318void array_container_intersection(const array_container_t *src_1,
1319 const array_container_t *src_2,
1320 array_container_t *dst);
1321
1322/* Check whether src_1 and src_2 intersect. */
1323bool array_container_intersect(const array_container_t *src_1,
1324 const array_container_t *src_2);
1325
1326
1327/* computers the size of the intersection between two arrays.
1328 */
1329int array_container_intersection_cardinality(const array_container_t *src_1,
1330 const array_container_t *src_2);
1331
1332/* computes the intersection of array1 and array2 and write the result to
1333 * array1.
1334 * */
1335void array_container_intersection_inplace(array_container_t *src_1,
1336 const array_container_t *src_2);
1337
1338/*
1339 * Write out the 16-bit integers contained in this container as a list of 32-bit
1340 * integers using base
1341 * as the starting value (it might be expected that base has zeros in its 16
1342 * least significant bits).
1343 * The function returns the number of values written.
1344 * The caller is responsible for allocating enough memory in out.
1345 */
1346int array_container_to_uint32_array(void *vout, const array_container_t *cont,
1347 uint32_t base);
1348
1349/* Compute the number of runs */
1350int32_t array_container_number_of_runs(const array_container_t *a);
1351
1352/*
1353 * Print this container using printf (useful for debugging).
1354 */
1355void array_container_printf(const array_container_t *v);
1356
1357/*
1358 * Print this container using printf as a comma-separated list of 32-bit
1359 * integers starting at base.
1360 */
1361void array_container_printf_as_uint32_array(const array_container_t *v,
1362 uint32_t base);
1363
1364/**
1365 * Return the serialized size in bytes of a container having cardinality "card".
1366 */
1367static inline int32_t array_container_serialized_size_in_bytes(int32_t card) {
1368 return card * 2 + 2;
1369}
1370
1371/**
1372 * Increase capacity to at least min.
1373 * Whether the existing data needs to be copied over depends on the "preserve"
1374 * parameter. If preserve is false, then the new content will be uninitialized,
1375 * otherwise the old content is copied.
1376 */
1377void array_container_grow(array_container_t *container, int32_t min,
1378 bool preserve);
1379
1380bool array_container_iterate(const array_container_t *cont, uint32_t base,
1381 roaring_iterator iterator, void *ptr);
1382bool array_container_iterate64(const array_container_t *cont, uint32_t base,
1383 roaring_iterator64 iterator, uint64_t high_bits,
1384 void *ptr);
1385
1386/**
1387 * Writes the underlying array to buf, outputs how many bytes were written.
1388 * This is meant to be byte-by-byte compatible with the Java and Go versions of
1389 * Roaring.
1390 * The number of bytes written should be
1391 * array_container_size_in_bytes(container).
1392 *
1393 */
1394int32_t array_container_write(const array_container_t *container, char *buf);
1395/**
1396 * Reads the instance from buf, outputs how many bytes were read.
1397 * This is meant to be byte-by-byte compatible with the Java and Go versions of
1398 * Roaring.
1399 * The number of bytes read should be array_container_size_in_bytes(container).
1400 * You need to provide the (known) cardinality.
1401 */
1402int32_t array_container_read(int32_t cardinality, array_container_t *container,
1403 const char *buf);
1404
1405/**
1406 * Return the serialized size in bytes of a container (see
1407 * bitset_container_write)
1408 * This is meant to be compatible with the Java and Go versions of Roaring and
1409 * assumes
1410 * that the cardinality of the container is already known.
1411 *
1412 */
1413static inline int32_t array_container_size_in_bytes(
1414 const array_container_t *container) {
1415 return container->cardinality * sizeof(uint16_t);
1416}
1417
1418/**
1419 * Return true if the two arrays have the same content.
1420 */
1421static inline bool array_container_equals(
1422 const array_container_t *container1,
1423 const array_container_t *container2) {
1424
1425 if (container1->cardinality != container2->cardinality) {
1426 return false;
1427 }
1428 return memequals(s1: container1->array, s2: container2->array, n: container1->cardinality*2);
1429}
1430
1431/**
1432 * Return true if container1 is a subset of container2.
1433 */
1434bool array_container_is_subset(const array_container_t *container1,
1435 const array_container_t *container2);
1436
1437/**
1438 * If the element of given rank is in this container, supposing that the first
1439 * element has rank start_rank, then the function returns true and sets element
1440 * accordingly.
1441 * Otherwise, it returns false and update start_rank.
1442 */
1443static inline bool array_container_select(const array_container_t *container,
1444 uint32_t *start_rank, uint32_t rank,
1445 uint32_t *element) {
1446 int card = array_container_cardinality(array: container);
1447 if (*start_rank + card <= rank) {
1448 *start_rank += card;
1449 return false;
1450 } else {
1451 *element = container->array[rank - *start_rank];
1452 return true;
1453 }
1454}
1455
1456/* Computes the difference of array1 and array2 and write the result
1457 * to array out.
1458 * Array out does not need to be distinct from array_1
1459 */
1460void array_container_andnot(const array_container_t *array_1,
1461 const array_container_t *array_2,
1462 array_container_t *out);
1463
1464/* Append x to the set. Assumes that the value is larger than any preceding
1465 * values. */
1466static inline void array_container_append(array_container_t *arr,
1467 uint16_t pos) {
1468 const int32_t capacity = arr->capacity;
1469
1470 if (array_container_full(array: arr)) {
1471 array_container_grow(container: arr, min: capacity + 1, true);
1472 }
1473
1474 arr->array[arr->cardinality++] = pos;
1475}
1476
1477/**
1478 * Add value to the set if final cardinality doesn't exceed max_cardinality.
1479 * Return code:
1480 * 1 -- value was added
1481 * 0 -- value was already present
1482 * -1 -- value was not added because cardinality would exceed max_cardinality
1483 */
1484static inline int array_container_try_add(array_container_t *arr, uint16_t value,
1485 int32_t max_cardinality) {
1486 const int32_t cardinality = arr->cardinality;
1487
1488 // best case, we can append.
1489 if ((array_container_empty(array: arr) || arr->array[cardinality - 1] < value) &&
1490 cardinality < max_cardinality) {
1491 array_container_append(arr, pos: value);
1492 return 1;
1493 }
1494
1495 const int32_t loc = binarySearch(array: arr->array, lenarray: cardinality, ikey: value);
1496
1497 if (loc >= 0) {
1498 return 0;
1499 } else if (cardinality < max_cardinality) {
1500 if (array_container_full(array: arr)) {
1501 array_container_grow(container: arr, min: arr->capacity + 1, true);
1502 }
1503 const int32_t insert_idx = -loc - 1;
1504 memmove(dest: arr->array + insert_idx + 1, src: arr->array + insert_idx,
1505 n: (cardinality - insert_idx) * sizeof(uint16_t));
1506 arr->array[insert_idx] = value;
1507 arr->cardinality++;
1508 return 1;
1509 } else {
1510 return -1;
1511 }
1512}
1513
1514/* Add value to the set. Returns true if x was not already present. */
1515static inline bool array_container_add(array_container_t *arr, uint16_t value) {
1516 return array_container_try_add(arr, value, INT32_MAX) == 1;
1517}
1518
1519/* Remove x from the set. Returns true if x was present. */
1520static inline bool array_container_remove(array_container_t *arr,
1521 uint16_t pos) {
1522 const int32_t idx = binarySearch(array: arr->array, lenarray: arr->cardinality, ikey: pos);
1523 const bool is_present = idx >= 0;
1524 if (is_present) {
1525 memmove(dest: arr->array + idx, src: arr->array + idx + 1,
1526 n: (arr->cardinality - idx - 1) * sizeof(uint16_t));
1527 arr->cardinality--;
1528 }
1529
1530 return is_present;
1531}
1532
1533/* Check whether x is present. */
1534static inline bool array_container_contains(const array_container_t *arr,
1535 uint16_t pos) {
1536 // return binarySearch(arr->array, arr->cardinality, pos) >= 0;
1537 // binary search with fallback to linear search for short ranges
1538 int32_t low = 0;
1539 const uint16_t * carr = (const uint16_t *) arr->array;
1540 int32_t high = arr->cardinality - 1;
1541 // while (high - low >= 0) {
1542 while(high >= low + 16) {
1543 int32_t middleIndex = (low + high)>>1;
1544 uint16_t middleValue = carr[middleIndex];
1545 if (middleValue < pos) {
1546 low = middleIndex + 1;
1547 } else if (middleValue > pos) {
1548 high = middleIndex - 1;
1549 } else {
1550 return true;
1551 }
1552 }
1553
1554 for (int i=low; i <= high; i++) {
1555 uint16_t v = carr[i];
1556 if (v == pos) {
1557 return true;
1558 }
1559 if ( v > pos ) return false;
1560 }
1561 return false;
1562
1563}
1564
1565//* Check whether a range of values from range_start (included) to range_end (excluded) is present. */
1566static inline bool array_container_contains_range(const array_container_t *arr,
1567 uint32_t range_start, uint32_t range_end) {
1568
1569 const uint16_t rs_included = range_start;
1570 const uint16_t re_included = range_end - 1;
1571
1572 const uint16_t *carr = (const uint16_t *) arr->array;
1573
1574 const int32_t start = advanceUntil(array: carr, pos: -1, length: arr->cardinality, min: rs_included);
1575 const int32_t end = advanceUntil(array: carr, pos: start - 1, length: arr->cardinality, min: re_included);
1576
1577 return (start < arr->cardinality) && (end < arr->cardinality)
1578 && (((uint16_t)(end - start)) == re_included - rs_included)
1579 && (carr[start] == rs_included) && (carr[end] == re_included);
1580}
1581
1582/* Returns the smallest value (assumes not empty) */
1583static inline uint16_t array_container_minimum(const array_container_t *arr) {
1584 if (arr->cardinality == 0) return 0;
1585 return arr->array[0];
1586}
1587
1588/* Returns the largest value (assumes not empty) */
1589static inline uint16_t array_container_maximum(const array_container_t *arr) {
1590 if (arr->cardinality == 0) return 0;
1591 return arr->array[arr->cardinality - 1];
1592}
1593
1594/* Returns the number of values equal or smaller than x */
1595static inline int array_container_rank(const array_container_t *arr, uint16_t x) {
1596 const int32_t idx = binarySearch(array: arr->array, lenarray: arr->cardinality, ikey: x);
1597 const bool is_present = idx >= 0;
1598 if (is_present) {
1599 return idx + 1;
1600 } else {
1601 return -idx - 1;
1602 }
1603}
1604
1605/* Returns the index of the first value equal or smaller than x, or -1 */
1606static inline int array_container_index_equalorlarger(const array_container_t *arr, uint16_t x) {
1607 const int32_t idx = binarySearch(array: arr->array, lenarray: arr->cardinality, ikey: x);
1608 const bool is_present = idx >= 0;
1609 if (is_present) {
1610 return idx;
1611 } else {
1612 int32_t candidate = - idx - 1;
1613 if(candidate < arr->cardinality) return candidate;
1614 return -1;
1615 }
1616}
1617
1618/*
1619 * Adds all values in range [min,max] using hint:
1620 * nvals_less is the number of array values less than $min
1621 * nvals_greater is the number of array values greater than $max
1622 */
1623static inline void array_container_add_range_nvals(array_container_t *array,
1624 uint32_t min, uint32_t max,
1625 int32_t nvals_less,
1626 int32_t nvals_greater) {
1627 int32_t union_cardinality = nvals_less + (max - min + 1) + nvals_greater;
1628 if (union_cardinality > array->capacity) {
1629 array_container_grow(container: array, min: union_cardinality, true);
1630 }
1631 memmove(dest: &(array->array[union_cardinality - nvals_greater]),
1632 src: &(array->array[array->cardinality - nvals_greater]),
1633 n: nvals_greater * sizeof(uint16_t));
1634 for (uint32_t i = 0; i <= max - min; i++) {
1635 array->array[nvals_less + i] = min + i;
1636 }
1637 array->cardinality = union_cardinality;
1638}
1639
1640/**
1641 * Adds all values in range [min,max].
1642 */
1643static inline void array_container_add_range(array_container_t *array,
1644 uint32_t min, uint32_t max) {
1645 int32_t nvals_greater = count_greater(array: array->array, lenarray: array->cardinality, ikey: max);
1646 int32_t nvals_less = count_less(array: array->array, lenarray: array->cardinality - nvals_greater, ikey: min);
1647 array_container_add_range_nvals(array, min, max, nvals_less, nvals_greater);
1648}
1649
1650/*
1651 * Removes all elements array[pos] .. array[pos+count-1]
1652 */
1653static inline void array_container_remove_range(array_container_t *array,
1654 uint32_t pos, uint32_t count) {
1655 if (count != 0) {
1656 memmove(dest: &(array->array[pos]), src: &(array->array[pos+count]),
1657 n: (array->cardinality - pos - count) * sizeof(uint16_t));
1658 array->cardinality -= count;
1659 }
1660}
1661
1662#endif /* INCLUDE_CONTAINERS_ARRAY_H_ */
1663/* end file include/roaring/containers/array.h */
1664/* begin file include/roaring/containers/bitset.h */
1665/*
1666 * bitset.h
1667 *
1668 */
1669
1670#ifndef INCLUDE_CONTAINERS_BITSET_H_
1671#define INCLUDE_CONTAINERS_BITSET_H_
1672
1673#include <stdbool.h>
1674#include <stdint.h>
1675
1676#ifdef USEAVX
1677#define ALIGN_AVX __attribute__((aligned(sizeof(__m256i))))
1678#else
1679#define ALIGN_AVX
1680#endif
1681
1682enum {
1683 BITSET_CONTAINER_SIZE_IN_WORDS = (1 << 16) / 64,
1684 BITSET_UNKNOWN_CARDINALITY = -1
1685};
1686
1687struct bitset_container_s {
1688 int32_t cardinality;
1689 uint64_t *array;
1690};
1691
1692typedef struct bitset_container_s bitset_container_t;
1693
1694/* Create a new bitset. Return NULL in case of failure. */
1695bitset_container_t *bitset_container_create(void);
1696
1697/* Free memory. */
1698void bitset_container_free(bitset_container_t *bitset);
1699
1700/* Clear bitset (sets bits to 0). */
1701void bitset_container_clear(bitset_container_t *bitset);
1702
1703/* Set all bits to 1. */
1704void bitset_container_set_all(bitset_container_t *bitset);
1705
1706/* Duplicate bitset */
1707bitset_container_t *bitset_container_clone(const bitset_container_t *src);
1708
1709int32_t bitset_container_serialize(const bitset_container_t *container,
1710 char *buf) WARN_UNUSED;
1711
1712uint32_t bitset_container_serialization_len(void);
1713
1714void *bitset_container_deserialize(const char *buf, size_t buf_len);
1715
1716/* Set the bit in [begin,end). WARNING: as of April 2016, this method is slow
1717 * and
1718 * should not be used in performance-sensitive code. Ever. */
1719void bitset_container_set_range(bitset_container_t *bitset, uint32_t begin,
1720 uint32_t end);
1721
1722#ifdef ASMBITMANIPOPTIMIZATION
1723/* Set the ith bit. */
1724static inline void bitset_container_set(bitset_container_t *bitset,
1725 uint16_t pos) {
1726 uint64_t shift = 6;
1727 uint64_t offset;
1728 uint64_t p = pos;
1729 ASM_SHIFT_RIGHT(p, shift, offset);
1730 uint64_t load = bitset->array[offset];
1731 ASM_SET_BIT_INC_WAS_CLEAR(load, p, bitset->cardinality);
1732 bitset->array[offset] = load;
1733}
1734
1735/* Unset the ith bit. */
1736static inline void bitset_container_unset(bitset_container_t *bitset,
1737 uint16_t pos) {
1738 uint64_t shift = 6;
1739 uint64_t offset;
1740 uint64_t p = pos;
1741 ASM_SHIFT_RIGHT(p, shift, offset);
1742 uint64_t load = bitset->array[offset];
1743 ASM_CLEAR_BIT_DEC_WAS_SET(load, p, bitset->cardinality);
1744 bitset->array[offset] = load;
1745}
1746
1747/* Add `pos' to `bitset'. Returns true if `pos' was not present. Might be slower
1748 * than bitset_container_set. */
1749static inline bool bitset_container_add(bitset_container_t *bitset,
1750 uint16_t pos) {
1751 uint64_t shift = 6;
1752 uint64_t offset;
1753 uint64_t p = pos;
1754 ASM_SHIFT_RIGHT(p, shift, offset);
1755 uint64_t load = bitset->array[offset];
1756 // could be possibly slightly further optimized
1757 const int32_t oldcard = bitset->cardinality;
1758 ASM_SET_BIT_INC_WAS_CLEAR(load, p, bitset->cardinality);
1759 bitset->array[offset] = load;
1760 return bitset->cardinality - oldcard;
1761}
1762
1763/* Remove `pos' from `bitset'. Returns true if `pos' was present. Might be
1764 * slower than bitset_container_unset. */
1765static inline bool bitset_container_remove(bitset_container_t *bitset,
1766 uint16_t pos) {
1767 uint64_t shift = 6;
1768 uint64_t offset;
1769 uint64_t p = pos;
1770 ASM_SHIFT_RIGHT(p, shift, offset);
1771 uint64_t load = bitset->array[offset];
1772 // could be possibly slightly further optimized
1773 const int32_t oldcard = bitset->cardinality;
1774 ASM_CLEAR_BIT_DEC_WAS_SET(load, p, bitset->cardinality);
1775 bitset->array[offset] = load;
1776 return oldcard - bitset->cardinality;
1777}
1778
1779/* Get the value of the ith bit. */
1780static inline bool bitset_container_get(const bitset_container_t *bitset,
1781 uint16_t pos) {
1782 uint64_t word = bitset->array[pos >> 6];
1783 const uint64_t p = pos;
1784 ASM_INPLACESHIFT_RIGHT(word, p);
1785 return word & 1;
1786}
1787
1788#else
1789
1790/* Set the ith bit. */
1791static inline void bitset_container_set(bitset_container_t *bitset,
1792 uint16_t pos) {
1793 const uint64_t old_word = bitset->array[pos >> 6];
1794 const int index = pos & 63;
1795 const uint64_t new_word = old_word | (UINT64_C(1) << index);
1796 bitset->cardinality += (uint32_t)((old_word ^ new_word) >> index);
1797 bitset->array[pos >> 6] = new_word;
1798}
1799
1800/* Unset the ith bit. */
1801static inline void bitset_container_unset(bitset_container_t *bitset,
1802 uint16_t pos) {
1803 const uint64_t old_word = bitset->array[pos >> 6];
1804 const int index = pos & 63;
1805 const uint64_t new_word = old_word & (~(UINT64_C(1) << index));
1806 bitset->cardinality -= (uint32_t)((old_word ^ new_word) >> index);
1807 bitset->array[pos >> 6] = new_word;
1808}
1809
1810/* Add `pos' to `bitset'. Returns true if `pos' was not present. Might be slower
1811 * than bitset_container_set. */
1812static inline bool bitset_container_add(bitset_container_t *bitset,
1813 uint16_t pos) {
1814 const uint64_t old_word = bitset->array[pos >> 6];
1815 const int index = pos & 63;
1816 const uint64_t new_word = old_word | (UINT64_C(1) << index);
1817 const uint64_t increment = (old_word ^ new_word) >> index;
1818 bitset->cardinality += (uint32_t)increment;
1819 bitset->array[pos >> 6] = new_word;
1820 return increment > 0;
1821}
1822
1823/* Remove `pos' from `bitset'. Returns true if `pos' was present. Might be
1824 * slower than bitset_container_unset. */
1825static inline bool bitset_container_remove(bitset_container_t *bitset,
1826 uint16_t pos) {
1827 const uint64_t old_word = bitset->array[pos >> 6];
1828 const int index = pos & 63;
1829 const uint64_t new_word = old_word & (~(UINT64_C(1) << index));
1830 const uint64_t increment = (old_word ^ new_word) >> index;
1831 bitset->cardinality -= (uint32_t)increment;
1832 bitset->array[pos >> 6] = new_word;
1833 return increment > 0;
1834}
1835
1836/* Get the value of the ith bit. */
1837static inline bool bitset_container_get(const bitset_container_t *bitset,
1838 uint16_t pos) {
1839 const uint64_t word = bitset->array[pos >> 6];
1840 return (word >> (pos & 63)) & 1;
1841}
1842
1843#endif
1844
1845/*
1846* Check if all bits are set in a range of positions from pos_start (included) to
1847* pos_end (excluded).
1848*/
1849static inline bool bitset_container_get_range(const bitset_container_t *bitset,
1850 uint32_t pos_start, uint32_t pos_end) {
1851
1852 const uint32_t start = pos_start >> 6;
1853 const uint32_t end = pos_end >> 6;
1854
1855 const uint64_t first = ~((1ULL << (pos_start & 0x3F)) - 1);
1856 const uint64_t last = (1ULL << (pos_end & 0x3F)) - 1;
1857
1858 if (start == end) return ((bitset->array[end] & first & last) == (first & last));
1859 if ((bitset->array[start] & first) != first) return false;
1860
1861 if ((end < BITSET_CONTAINER_SIZE_IN_WORDS) && ((bitset->array[end] & last) != last)){
1862
1863 return false;
1864 }
1865
1866 for (uint16_t i = start + 1; (i < BITSET_CONTAINER_SIZE_IN_WORDS) && (i < end); ++i){
1867
1868 if (bitset->array[i] != UINT64_C(0xFFFFFFFFFFFFFFFF)) return false;
1869 }
1870
1871 return true;
1872}
1873
1874/* Check whether `bitset' is present in `array'. Calls bitset_container_get. */
1875static inline bool bitset_container_contains(const bitset_container_t *bitset,
1876 uint16_t pos) {
1877 return bitset_container_get(bitset, pos);
1878}
1879
1880/*
1881* Check whether a range of bits from position `pos_start' (included) to `pos_end' (excluded)
1882* is present in `bitset'. Calls bitset_container_get_all.
1883*/
1884static inline bool bitset_container_contains_range(const bitset_container_t *bitset,
1885 uint32_t pos_start, uint32_t pos_end) {
1886 return bitset_container_get_range(bitset, pos_start, pos_end);
1887}
1888
1889/* Get the number of bits set */
1890static inline int bitset_container_cardinality(
1891 const bitset_container_t *bitset) {
1892 return bitset->cardinality;
1893}
1894
1895
1896
1897
1898/* Copy one container into another. We assume that they are distinct. */
1899void bitset_container_copy(const bitset_container_t *source,
1900 bitset_container_t *dest);
1901
1902/* Add all the values [min,max) at a distance k*step from min: min,
1903 * min+step,.... */
1904void bitset_container_add_from_range(bitset_container_t *bitset, uint32_t min,
1905 uint32_t max, uint16_t step);
1906
1907/* Get the number of bits set (force computation). This does not modify bitset.
1908 * To update the cardinality, you should do
1909 * bitset->cardinality = bitset_container_compute_cardinality(bitset).*/
1910int bitset_container_compute_cardinality(const bitset_container_t *bitset);
1911
1912/* Get whether there is at least one bit set (see bitset_container_empty for the reverse),
1913 when the cardinality is unknown, it is computed and stored in the struct */
1914static inline bool bitset_container_nonzero_cardinality(
1915 bitset_container_t *bitset) {
1916 // account for laziness
1917 if (bitset->cardinality == BITSET_UNKNOWN_CARDINALITY) {
1918 // could bail early instead with a nonzero result
1919 bitset->cardinality = bitset_container_compute_cardinality(bitset);
1920 }
1921 return bitset->cardinality > 0;
1922}
1923
1924/* Check whether this bitset is empty (see bitset_container_nonzero_cardinality for the reverse),
1925 * it never modifies the bitset struct. */
1926static inline bool bitset_container_empty(
1927 const bitset_container_t *bitset) {
1928 if (bitset->cardinality == BITSET_UNKNOWN_CARDINALITY) {
1929 for (int i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; i ++) {
1930 if((bitset->array[i]) != 0) return false;
1931 }
1932 return true;
1933 }
1934 return bitset->cardinality == 0;
1935}
1936
1937
1938/* Get whether there is at least one bit set (see bitset_container_empty for the reverse),
1939 the bitset is never modified */
1940static inline bool bitset_container_const_nonzero_cardinality(
1941 const bitset_container_t *bitset) {
1942 return !bitset_container_empty(bitset);
1943}
1944
1945/*
1946 * Check whether the two bitsets intersect
1947 */
1948bool bitset_container_intersect(const bitset_container_t *src_1,
1949 const bitset_container_t *src_2);
1950
1951/* Computes the union of bitsets `src_1' and `src_2' into `dst' and return the
1952 * cardinality. */
1953int bitset_container_or(const bitset_container_t *src_1,
1954 const bitset_container_t *src_2,
1955 bitset_container_t *dst);
1956
1957/* Computes the union of bitsets `src_1' and `src_2' and return the cardinality.
1958 */
1959int bitset_container_or_justcard(const bitset_container_t *src_1,
1960 const bitset_container_t *src_2);
1961
1962/* Computes the union of bitsets `src_1' and `src_2' into `dst' and return the
1963 * cardinality. Same as bitset_container_or. */
1964int bitset_container_union(const bitset_container_t *src_1,
1965 const bitset_container_t *src_2,
1966 bitset_container_t *dst);
1967
1968/* Computes the union of bitsets `src_1' and `src_2' and return the
1969 * cardinality. Same as bitset_container_or_justcard. */
1970int bitset_container_union_justcard(const bitset_container_t *src_1,
1971 const bitset_container_t *src_2);
1972
1973/* Computes the union of bitsets `src_1' and `src_2' into `dst', but does not
1974 * update the cardinality. Provided to optimize chained operations. */
1975int bitset_container_or_nocard(const bitset_container_t *src_1,
1976 const bitset_container_t *src_2,
1977 bitset_container_t *dst);
1978
1979/* Computes the union of bitsets `src_1' and `src_2' into `dst', but does not
1980 * update the cardinality. Same as bitset_container_or_nocard */
1981int bitset_container_union_nocard(const bitset_container_t *src_1,
1982 const bitset_container_t *src_2,
1983 bitset_container_t *dst);
1984
1985/* Computes the intersection of bitsets `src_1' and `src_2' into `dst' and
1986 * return the cardinality. */
1987int bitset_container_and(const bitset_container_t *src_1,
1988 const bitset_container_t *src_2,
1989 bitset_container_t *dst);
1990
1991/* Computes the intersection of bitsets `src_1' and `src_2' and return the
1992 * cardinality. */
1993int bitset_container_and_justcard(const bitset_container_t *src_1,
1994 const bitset_container_t *src_2);
1995
1996/* Computes the intersection of bitsets `src_1' and `src_2' into `dst' and
1997 * return the cardinality. Same as bitset_container_and. */
1998int bitset_container_intersection(const bitset_container_t *src_1,
1999 const bitset_container_t *src_2,
2000 bitset_container_t *dst);
2001
2002/* Computes the intersection of bitsets `src_1' and `src_2' and return the
2003 * cardinality. Same as bitset_container_and_justcard. */
2004int bitset_container_intersection_justcard(const bitset_container_t *src_1,
2005 const bitset_container_t *src_2);
2006
2007/* Computes the intersection of bitsets `src_1' and `src_2' into `dst', but does
2008 * not update the cardinality. Provided to optimize chained operations. */
2009int bitset_container_and_nocard(const bitset_container_t *src_1,
2010 const bitset_container_t *src_2,
2011 bitset_container_t *dst);
2012
2013/* Computes the intersection of bitsets `src_1' and `src_2' into `dst', but does
2014 * not update the cardinality. Same as bitset_container_and_nocard */
2015int bitset_container_intersection_nocard(const bitset_container_t *src_1,
2016 const bitset_container_t *src_2,
2017 bitset_container_t *dst);
2018
2019/* Computes the exclusive or of bitsets `src_1' and `src_2' into `dst' and
2020 * return the cardinality. */
2021int bitset_container_xor(const bitset_container_t *src_1,
2022 const bitset_container_t *src_2,
2023 bitset_container_t *dst);
2024
2025/* Computes the exclusive or of bitsets `src_1' and `src_2' and return the
2026 * cardinality. */
2027int bitset_container_xor_justcard(const bitset_container_t *src_1,
2028 const bitset_container_t *src_2);
2029
2030/* Computes the exclusive or of bitsets `src_1' and `src_2' into `dst', but does
2031 * not update the cardinality. Provided to optimize chained operations. */
2032int bitset_container_xor_nocard(const bitset_container_t *src_1,
2033 const bitset_container_t *src_2,
2034 bitset_container_t *dst);
2035
2036/* Computes the and not of bitsets `src_1' and `src_2' into `dst' and return the
2037 * cardinality. */
2038int bitset_container_andnot(const bitset_container_t *src_1,
2039 const bitset_container_t *src_2,
2040 bitset_container_t *dst);
2041
2042/* Computes the and not of bitsets `src_1' and `src_2' and return the
2043 * cardinality. */
2044int bitset_container_andnot_justcard(const bitset_container_t *src_1,
2045 const bitset_container_t *src_2);
2046
2047/* Computes the and not or of bitsets `src_1' and `src_2' into `dst', but does
2048 * not update the cardinality. Provided to optimize chained operations. */
2049int bitset_container_andnot_nocard(const bitset_container_t *src_1,
2050 const bitset_container_t *src_2,
2051 bitset_container_t *dst);
2052
2053/*
2054 * Write out the 16-bit integers contained in this container as a list of 32-bit
2055 * integers using base
2056 * as the starting value (it might be expected that base has zeros in its 16
2057 * least significant bits).
2058 * The function returns the number of values written.
2059 * The caller is responsible for allocating enough memory in out.
2060 * The out pointer should point to enough memory (the cardinality times 32
2061 * bits).
2062 */
2063int bitset_container_to_uint32_array(void *out, const bitset_container_t *cont,
2064 uint32_t base);
2065
2066/*
2067 * Print this container using printf (useful for debugging).
2068 */
2069void bitset_container_printf(const bitset_container_t *v);
2070
2071/*
2072 * Print this container using printf as a comma-separated list of 32-bit
2073 * integers starting at base.
2074 */
2075void bitset_container_printf_as_uint32_array(const bitset_container_t *v,
2076 uint32_t base);
2077
2078/**
2079 * Return the serialized size in bytes of a container.
2080 */
2081static inline int32_t bitset_container_serialized_size_in_bytes(void) {
2082 return BITSET_CONTAINER_SIZE_IN_WORDS * 8;
2083}
2084
2085/**
2086 * Return the the number of runs.
2087 */
2088int bitset_container_number_of_runs(bitset_container_t *b);
2089
2090bool bitset_container_iterate(const bitset_container_t *cont, uint32_t base,
2091 roaring_iterator iterator, void *ptr);
2092bool bitset_container_iterate64(const bitset_container_t *cont, uint32_t base,
2093 roaring_iterator64 iterator, uint64_t high_bits,
2094 void *ptr);
2095
2096/**
2097 * Writes the underlying array to buf, outputs how many bytes were written.
2098 * This is meant to be byte-by-byte compatible with the Java and Go versions of
2099 * Roaring.
2100 * The number of bytes written should be
2101 * bitset_container_size_in_bytes(container).
2102 */
2103int32_t bitset_container_write(const bitset_container_t *container, char *buf);
2104
2105/**
2106 * Reads the instance from buf, outputs how many bytes were read.
2107 * This is meant to be byte-by-byte compatible with the Java and Go versions of
2108 * Roaring.
2109 * The number of bytes read should be bitset_container_size_in_bytes(container).
2110 * You need to provide the (known) cardinality.
2111 */
2112int32_t bitset_container_read(int32_t cardinality,
2113 bitset_container_t *container, const char *buf);
2114/**
2115 * Return the serialized size in bytes of a container (see
2116 * bitset_container_write).
2117 * This is meant to be compatible with the Java and Go versions of Roaring and
2118 * assumes
2119 * that the cardinality of the container is already known or can be computed.
2120 */
2121static inline int32_t bitset_container_size_in_bytes(
2122 const bitset_container_t *container) {
2123 (void)container;
2124 return BITSET_CONTAINER_SIZE_IN_WORDS * sizeof(uint64_t);
2125}
2126
2127/**
2128 * Return true if the two containers have the same content.
2129 */
2130bool bitset_container_equals(const bitset_container_t *container1,
2131 const bitset_container_t *container2);
2132
2133/**
2134* Return true if container1 is a subset of container2.
2135*/
2136bool bitset_container_is_subset(const bitset_container_t *container1,
2137 const bitset_container_t *container2);
2138
2139/**
2140 * If the element of given rank is in this container, supposing that the first
2141 * element has rank start_rank, then the function returns true and sets element
2142 * accordingly.
2143 * Otherwise, it returns false and update start_rank.
2144 */
2145bool bitset_container_select(const bitset_container_t *container,
2146 uint32_t *start_rank, uint32_t rank,
2147 uint32_t *element);
2148
2149/* Returns the smallest value (assumes not empty) */
2150uint16_t bitset_container_minimum(const bitset_container_t *container);
2151
2152/* Returns the largest value (assumes not empty) */
2153uint16_t bitset_container_maximum(const bitset_container_t *container);
2154
2155/* Returns the number of values equal or smaller than x */
2156int bitset_container_rank(const bitset_container_t *container, uint16_t x);
2157
2158/* Returns the index of the first value equal or larger than x, or -1 */
2159int bitset_container_index_equalorlarger(const bitset_container_t *container, uint16_t x);
2160#endif /* INCLUDE_CONTAINERS_BITSET_H_ */
2161/* end file include/roaring/containers/bitset.h */
2162/* begin file include/roaring/containers/run.h */
2163/*
2164 * run.h
2165 *
2166 */
2167
2168#ifndef INCLUDE_CONTAINERS_RUN_H_
2169#define INCLUDE_CONTAINERS_RUN_H_
2170
2171#include <assert.h>
2172#include <stdbool.h>
2173#include <stdint.h>
2174#include <string.h>
2175
2176
2177/* struct rle16_s - run length pair
2178 *
2179 * @value: start position of the run
2180 * @length: length of the run is `length + 1`
2181 *
2182 * An RLE pair {v, l} would represent the integers between the interval
2183 * [v, v+l+1], e.g. {3, 2} = [3, 4, 5].
2184 */
2185struct rle16_s {
2186 uint16_t value;
2187 uint16_t length;
2188};
2189
2190typedef struct rle16_s rle16_t;
2191
2192/* struct run_container_s - run container bitmap
2193 *
2194 * @n_runs: number of rle_t pairs in `runs`.
2195 * @capacity: capacity in rle_t pairs `runs` can hold.
2196 * @runs: pairs of rle_t.
2197 *
2198 */
2199struct run_container_s {
2200 int32_t n_runs;
2201 int32_t capacity;
2202 rle16_t *runs;
2203};
2204
2205typedef struct run_container_s run_container_t;
2206
2207/* Create a new run container. Return NULL in case of failure. */
2208run_container_t *run_container_create(void);
2209
2210/* Create a new run container with given capacity. Return NULL in case of
2211 * failure. */
2212run_container_t *run_container_create_given_capacity(int32_t size);
2213
2214/*
2215 * Shrink the capacity to the actual size, return the number of bytes saved.
2216 */
2217int run_container_shrink_to_fit(run_container_t *src);
2218
2219/* Free memory owned by `run'. */
2220void run_container_free(run_container_t *run);
2221
2222/* Duplicate container */
2223run_container_t *run_container_clone(const run_container_t *src);
2224
2225int32_t run_container_serialize(const run_container_t *container,
2226 char *buf) WARN_UNUSED;
2227
2228uint32_t run_container_serialization_len(const run_container_t *container);
2229
2230void *run_container_deserialize(const char *buf, size_t buf_len);
2231
2232/*
2233 * Effectively deletes the value at index index, repacking data.
2234 */
2235static inline void recoverRoomAtIndex(run_container_t *run, uint16_t index) {
2236 memmove(dest: run->runs + index, src: run->runs + (1 + index),
2237 n: (run->n_runs - index - 1) * sizeof(rle16_t));
2238 run->n_runs--;
2239}
2240
2241/**
2242 * Good old binary search through rle data
2243 */
2244static inline int32_t interleavedBinarySearch(const rle16_t *array, int32_t lenarray,
2245 uint16_t ikey) {
2246 int32_t low = 0;
2247 int32_t high = lenarray - 1;
2248 while (low <= high) {
2249 int32_t middleIndex = (low + high) >> 1;
2250 uint16_t middleValue = array[middleIndex].value;
2251 if (middleValue < ikey) {
2252 low = middleIndex + 1;
2253 } else if (middleValue > ikey) {
2254 high = middleIndex - 1;
2255 } else {
2256 return middleIndex;
2257 }
2258 }
2259 return -(low + 1);
2260}
2261
2262/*
2263 * Returns index of the run which contains $ikey
2264 */
2265static inline int32_t rle16_find_run(const rle16_t *array, int32_t lenarray,
2266 uint16_t ikey) {
2267 int32_t low = 0;
2268 int32_t high = lenarray - 1;
2269 while (low <= high) {
2270 int32_t middleIndex = (low + high) >> 1;
2271 uint16_t min = array[middleIndex].value;
2272 uint16_t max = array[middleIndex].value + array[middleIndex].length;
2273 if (ikey > max) {
2274 low = middleIndex + 1;
2275 } else if (ikey < min) {
2276 high = middleIndex - 1;
2277 } else {
2278 return middleIndex;
2279 }
2280 }
2281 return -(low + 1);
2282}
2283
2284
2285/**
2286 * Returns number of runs which can'be be merged with the key because they
2287 * are less than the key.
2288 * Note that [5,6,7,8] can be merged with the key 9 and won't be counted.
2289 */
2290static inline int32_t rle16_count_less(const rle16_t* array, int32_t lenarray,
2291 uint16_t key) {
2292 if (lenarray == 0) return 0;
2293 int32_t low = 0;
2294 int32_t high = lenarray - 1;
2295 while (low <= high) {
2296 int32_t middleIndex = (low + high) >> 1;
2297 uint16_t min_value = array[middleIndex].value;
2298 uint16_t max_value = array[middleIndex].value + array[middleIndex].length;
2299 if (max_value + UINT32_C(1) < key) { // uint32 arithmetic
2300 low = middleIndex + 1;
2301 } else if (key < min_value) {
2302 high = middleIndex - 1;
2303 } else {
2304 return middleIndex;
2305 }
2306 }
2307 return low;
2308}
2309
2310static inline int32_t rle16_count_greater(const rle16_t* array, int32_t lenarray,
2311 uint16_t key) {
2312 if (lenarray == 0) return 0;
2313 int32_t low = 0;
2314 int32_t high = lenarray - 1;
2315 while (low <= high) {
2316 int32_t middleIndex = (low + high) >> 1;
2317 uint16_t min_value = array[middleIndex].value;
2318 uint16_t max_value = array[middleIndex].value + array[middleIndex].length;
2319 if (max_value < key) {
2320 low = middleIndex + 1;
2321 } else if (key + UINT32_C(1) < min_value) { // uint32 arithmetic
2322 high = middleIndex - 1;
2323 } else {
2324 return lenarray - (middleIndex + 1);
2325 }
2326 }
2327 return lenarray - low;
2328}
2329
2330/**
2331 * increase capacity to at least min. Whether the
2332 * existing data needs to be copied over depends on copy. If "copy" is false,
2333 * then the new content will be uninitialized, otherwise a copy is made.
2334 */
2335void run_container_grow(run_container_t *run, int32_t min, bool copy);
2336
2337/**
2338 * Moves the data so that we can write data at index
2339 */
2340static inline void makeRoomAtIndex(run_container_t *run, uint16_t index) {
2341 /* This function calls realloc + memmove sequentially to move by one index.
2342 * Potentially copying twice the array.
2343 */
2344 if (run->n_runs + 1 > run->capacity)
2345 run_container_grow(run, min: run->n_runs + 1, true);
2346 memmove(dest: run->runs + 1 + index, src: run->runs + index,
2347 n: (run->n_runs - index) * sizeof(rle16_t));
2348 run->n_runs++;
2349}
2350
2351/* Add `pos' to `run'. Returns true if `pos' was not present. */
2352bool run_container_add(run_container_t *run, uint16_t pos);
2353
2354/* Remove `pos' from `run'. Returns true if `pos' was present. */
2355static inline bool run_container_remove(run_container_t *run, uint16_t pos) {
2356 int32_t index = interleavedBinarySearch(array: run->runs, lenarray: run->n_runs, ikey: pos);
2357 if (index >= 0) {
2358 int32_t le = run->runs[index].length;
2359 if (le == 0) {
2360 recoverRoomAtIndex(run, index: (uint16_t)index);
2361 } else {
2362 run->runs[index].value++;
2363 run->runs[index].length--;
2364 }
2365 return true;
2366 }
2367 index = -index - 2; // points to preceding value, possibly -1
2368 if (index >= 0) { // possible match
2369 int32_t offset = pos - run->runs[index].value;
2370 int32_t le = run->runs[index].length;
2371 if (offset < le) {
2372 // need to break in two
2373 run->runs[index].length = (uint16_t)(offset - 1);
2374 // need to insert
2375 uint16_t newvalue = pos + 1;
2376 int32_t newlength = le - offset - 1;
2377 makeRoomAtIndex(run, index: (uint16_t)(index + 1));
2378 run->runs[index + 1].value = newvalue;
2379 run->runs[index + 1].length = (uint16_t)newlength;
2380 return true;
2381
2382 } else if (offset == le) {
2383 run->runs[index].length--;
2384 return true;
2385 }
2386 }
2387 // no match
2388 return false;
2389}
2390
2391/* Check whether `pos' is present in `run'. */
2392static inline bool run_container_contains(const run_container_t *run, uint16_t pos) {
2393 int32_t index = interleavedBinarySearch(array: run->runs, lenarray: run->n_runs, ikey: pos);
2394 if (index >= 0) return true;
2395 index = -index - 2; // points to preceding value, possibly -1
2396 if (index != -1) { // possible match
2397 int32_t offset = pos - run->runs[index].value;
2398 int32_t le = run->runs[index].length;
2399 if (offset <= le) return true;
2400 }
2401 return false;
2402}
2403
2404/*
2405* Check whether all positions in a range of positions from pos_start (included)
2406* to pos_end (excluded) is present in `run'.
2407*/
2408static inline bool run_container_contains_range(const run_container_t *run,
2409 uint32_t pos_start, uint32_t pos_end) {
2410 uint32_t count = 0;
2411 int32_t index = interleavedBinarySearch(array: run->runs, lenarray: run->n_runs, ikey: pos_start);
2412 if (index < 0) {
2413 index = -index - 2;
2414 if ((index == -1) || ((pos_start - run->runs[index].value) > run->runs[index].length)){
2415 return false;
2416 }
2417 }
2418 for (int32_t i = index; i < run->n_runs; ++i) {
2419 const uint32_t stop = run->runs[i].value + run->runs[i].length;
2420 if (run->runs[i].value >= pos_end) break;
2421 if (stop >= pos_end) {
2422 count += (((pos_end - run->runs[i].value) > 0) ? (pos_end - run->runs[i].value) : 0);
2423 break;
2424 }
2425 const uint32_t min = (stop - pos_start) > 0 ? (stop - pos_start) : 0;
2426 count += (min < run->runs[i].length) ? min : run->runs[i].length;
2427 }
2428 return count >= (pos_end - pos_start - 1);
2429}
2430
2431#ifdef USEAVX
2432
2433/* Get the cardinality of `run'. Requires an actual computation. */
2434static inline int run_container_cardinality(const run_container_t *run) {
2435 const int32_t n_runs = run->n_runs;
2436 const rle16_t *runs = run->runs;
2437
2438 /* by initializing with n_runs, we omit counting the +1 for each pair. */
2439 int sum = n_runs;
2440 int32_t k = 0;
2441 const int32_t step = sizeof(__m256i) / sizeof(rle16_t);
2442 if (n_runs > step) {
2443 __m256i total = _mm256_setzero_si256();
2444 for (; k + step <= n_runs; k += step) {
2445 __m256i ymm1 = _mm256_lddqu_si256((const __m256i *)(runs + k));
2446 __m256i justlengths = _mm256_srli_epi32(ymm1, 16);
2447 total = _mm256_add_epi32(total, justlengths);
2448 }
2449 // a store might be faster than extract?
2450 uint32_t buffer[sizeof(__m256i) / sizeof(rle16_t)];
2451 _mm256_storeu_si256((__m256i *)buffer, total);
2452 sum += (buffer[0] + buffer[1]) + (buffer[2] + buffer[3]) +
2453 (buffer[4] + buffer[5]) + (buffer[6] + buffer[7]);
2454 }
2455 for (; k < n_runs; ++k) {
2456 sum += runs[k].length;
2457 }
2458
2459 return sum;
2460}
2461
2462#else
2463
2464/* Get the cardinality of `run'. Requires an actual computation. */
2465static inline int run_container_cardinality(const run_container_t *run) {
2466 const int32_t n_runs = run->n_runs;
2467 const rle16_t *runs = run->runs;
2468
2469 /* by initializing with n_runs, we omit counting the +1 for each pair. */
2470 int sum = n_runs;
2471 for (int k = 0; k < n_runs; ++k) {
2472 sum += runs[k].length;
2473 }
2474
2475 return sum;
2476}
2477#endif
2478
2479/* Card > 0?, see run_container_empty for the reverse */
2480static inline bool run_container_nonzero_cardinality(
2481 const run_container_t *run) {
2482 return run->n_runs > 0; // runs never empty
2483}
2484
2485/* Card == 0?, see run_container_nonzero_cardinality for the reverse */
2486static inline bool run_container_empty(
2487 const run_container_t *run) {
2488 return run->n_runs == 0; // runs never empty
2489}
2490
2491
2492
2493/* Copy one container into another. We assume that they are distinct. */
2494void run_container_copy(const run_container_t *src, run_container_t *dst);
2495
2496/* Set the cardinality to zero (does not release memory). */
2497static inline void run_container_clear(run_container_t *run) {
2498 run->n_runs = 0;
2499}
2500
2501/**
2502 * Append run described by vl to the run container, possibly merging.
2503 * It is assumed that the run would be inserted at the end of the container, no
2504 * check is made.
2505 * It is assumed that the run container has the necessary capacity: caller is
2506 * responsible for checking memory capacity.
2507 *
2508 *
2509 * This is not a safe function, it is meant for performance: use with care.
2510 */
2511static inline void run_container_append(run_container_t *run, rle16_t vl,
2512 rle16_t *previousrl) {
2513 const uint32_t previousend = previousrl->value + previousrl->length;
2514 if (vl.value > previousend + 1) { // we add a new one
2515 run->runs[run->n_runs] = vl;
2516 run->n_runs++;
2517 *previousrl = vl;
2518 } else {
2519 uint32_t newend = vl.value + vl.length + UINT32_C(1);
2520 if (newend > previousend) { // we merge
2521 previousrl->length = (uint16_t)(newend - 1 - previousrl->value);
2522 run->runs[run->n_runs - 1] = *previousrl;
2523 }
2524 }
2525}
2526
2527/**
2528 * Like run_container_append but it is assumed that the content of run is empty.
2529 */
2530static inline rle16_t run_container_append_first(run_container_t *run,
2531 rle16_t vl) {
2532 run->runs[run->n_runs] = vl;
2533 run->n_runs++;
2534 return vl;
2535}
2536
2537/**
2538 * append a single value given by val to the run container, possibly merging.
2539 * It is assumed that the value would be inserted at the end of the container,
2540 * no check is made.
2541 * It is assumed that the run container has the necessary capacity: caller is
2542 * responsible for checking memory capacity.
2543 *
2544 * This is not a safe function, it is meant for performance: use with care.
2545 */
2546static inline void run_container_append_value(run_container_t *run,
2547 uint16_t val,
2548 rle16_t *previousrl) {
2549 const uint32_t previousend = previousrl->value + previousrl->length;
2550 if (val > previousend + 1) { // we add a new one
2551 //*previousrl = (rle16_t){.value = val, .length = 0};// requires C99
2552 previousrl->value = val;
2553 previousrl->length = 0;
2554
2555 run->runs[run->n_runs] = *previousrl;
2556 run->n_runs++;
2557 } else if (val == previousend + 1) { // we merge
2558 previousrl->length++;
2559 run->runs[run->n_runs - 1] = *previousrl;
2560 }
2561}
2562
2563/**
2564 * Like run_container_append_value but it is assumed that the content of run is
2565 * empty.
2566 */
2567static inline rle16_t run_container_append_value_first(run_container_t *run,
2568 uint16_t val) {
2569 // rle16_t newrle = (rle16_t){.value = val, .length = 0};// requires C99
2570 rle16_t newrle;
2571 newrle.value = val;
2572 newrle.length = 0;
2573
2574 run->runs[run->n_runs] = newrle;
2575 run->n_runs++;
2576 return newrle;
2577}
2578
2579/* Check whether the container spans the whole chunk (cardinality = 1<<16).
2580 * This check can be done in constant time (inexpensive). */
2581static inline bool run_container_is_full(const run_container_t *run) {
2582 rle16_t vl = run->runs[0];
2583 return (run->n_runs == 1) && (vl.value == 0) && (vl.length == 0xFFFF);
2584}
2585
2586/* Compute the union of `src_1' and `src_2' and write the result to `dst'
2587 * It is assumed that `dst' is distinct from both `src_1' and `src_2'. */
2588void run_container_union(const run_container_t *src_1,
2589 const run_container_t *src_2, run_container_t *dst);
2590
2591/* Compute the union of `src_1' and `src_2' and write the result to `src_1' */
2592void run_container_union_inplace(run_container_t *src_1,
2593 const run_container_t *src_2);
2594
2595/* Compute the intersection of src_1 and src_2 and write the result to
2596 * dst. It is assumed that dst is distinct from both src_1 and src_2. */
2597void run_container_intersection(const run_container_t *src_1,
2598 const run_container_t *src_2,
2599 run_container_t *dst);
2600
2601/* Compute the size of the intersection of src_1 and src_2 . */
2602int run_container_intersection_cardinality(const run_container_t *src_1,
2603 const run_container_t *src_2);
2604
2605/* Check whether src_1 and src_2 intersect. */
2606bool run_container_intersect(const run_container_t *src_1,
2607 const run_container_t *src_2);
2608
2609/* Compute the symmetric difference of `src_1' and `src_2' and write the result
2610 * to `dst'
2611 * It is assumed that `dst' is distinct from both `src_1' and `src_2'. */
2612void run_container_xor(const run_container_t *src_1,
2613 const run_container_t *src_2, run_container_t *dst);
2614
2615/*
2616 * Write out the 16-bit integers contained in this container as a list of 32-bit
2617 * integers using base
2618 * as the starting value (it might be expected that base has zeros in its 16
2619 * least significant bits).
2620 * The function returns the number of values written.
2621 * The caller is responsible for allocating enough memory in out.
2622 */
2623int run_container_to_uint32_array(void *vout, const run_container_t *cont,
2624 uint32_t base);
2625
2626/*
2627 * Print this container using printf (useful for debugging).
2628 */
2629void run_container_printf(const run_container_t *v);
2630
2631/*
2632 * Print this container using printf as a comma-separated list of 32-bit
2633 * integers starting at base.
2634 */
2635void run_container_printf_as_uint32_array(const run_container_t *v,
2636 uint32_t base);
2637
2638/**
2639 * Return the serialized size in bytes of a container having "num_runs" runs.
2640 */
2641static inline int32_t run_container_serialized_size_in_bytes(int32_t num_runs) {
2642 return sizeof(uint16_t) +
2643 sizeof(rle16_t) * num_runs; // each run requires 2 2-byte entries.
2644}
2645
2646bool run_container_iterate(const run_container_t *cont, uint32_t base,
2647 roaring_iterator iterator, void *ptr);
2648bool run_container_iterate64(const run_container_t *cont, uint32_t base,
2649 roaring_iterator64 iterator, uint64_t high_bits,
2650 void *ptr);
2651
2652/**
2653 * Writes the underlying array to buf, outputs how many bytes were written.
2654 * This is meant to be byte-by-byte compatible with the Java and Go versions of
2655 * Roaring.
2656 * The number of bytes written should be run_container_size_in_bytes(container).
2657 */
2658int32_t run_container_write(const run_container_t *container, char *buf);
2659
2660/**
2661 * Reads the instance from buf, outputs how many bytes were read.
2662 * This is meant to be byte-by-byte compatible with the Java and Go versions of
2663 * Roaring.
2664 * The number of bytes read should be bitset_container_size_in_bytes(container).
2665 * The cardinality parameter is provided for consistency with other containers,
2666 * but
2667 * it might be effectively ignored..
2668 */
2669int32_t run_container_read(int32_t cardinality, run_container_t *container,
2670 const char *buf);
2671
2672/**
2673 * Return the serialized size in bytes of a container (see run_container_write).
2674 * This is meant to be compatible with the Java and Go versions of Roaring.
2675 */
2676static inline int32_t run_container_size_in_bytes(
2677 const run_container_t *container) {
2678 return run_container_serialized_size_in_bytes(num_runs: container->n_runs);
2679}
2680
2681/**
2682 * Return true if the two containers have the same content.
2683 */
2684static inline bool run_container_equals(const run_container_t *container1,
2685 const run_container_t *container2) {
2686 if (container1->n_runs != container2->n_runs) {
2687 return false;
2688 }
2689 return memequals(s1: container1->runs, s2: container2->runs,
2690 n: container1->n_runs * sizeof(rle16_t));
2691}
2692
2693/**
2694* Return true if container1 is a subset of container2.
2695*/
2696bool run_container_is_subset(const run_container_t *container1,
2697 const run_container_t *container2);
2698
2699/**
2700 * Used in a start-finish scan that appends segments, for XOR and NOT
2701 */
2702
2703void run_container_smart_append_exclusive(run_container_t *src,
2704 const uint16_t start,
2705 const uint16_t length);
2706
2707/**
2708* The new container consists of a single run [start,stop).
2709* It is required that stop>start, the caller is responsibility for this check.
2710* It is required that stop <= (1<<16), the caller is responsibility for this check.
2711* The cardinality of the created container is stop - start.
2712* Returns NULL on failure
2713*/
2714static inline run_container_t *run_container_create_range(uint32_t start,
2715 uint32_t stop) {
2716 run_container_t *rc = run_container_create_given_capacity(size: 1);
2717 if (rc) {
2718 rle16_t r;
2719 r.value = (uint16_t)start;
2720 r.length = (uint16_t)(stop - start - 1);
2721 run_container_append_first(run: rc, vl: r);
2722 }
2723 return rc;
2724}
2725
2726/**
2727 * If the element of given rank is in this container, supposing that the first
2728 * element has rank start_rank, then the function returns true and sets element
2729 * accordingly.
2730 * Otherwise, it returns false and update start_rank.
2731 */
2732bool run_container_select(const run_container_t *container,
2733 uint32_t *start_rank, uint32_t rank,
2734 uint32_t *element);
2735
2736/* Compute the difference of src_1 and src_2 and write the result to
2737 * dst. It is assumed that dst is distinct from both src_1 and src_2. */
2738
2739void run_container_andnot(const run_container_t *src_1,
2740 const run_container_t *src_2, run_container_t *dst);
2741
2742/* Returns the smallest value (assumes not empty) */
2743static inline uint16_t run_container_minimum(const run_container_t *run) {
2744 if (run->n_runs == 0) return 0;
2745 return run->runs[0].value;
2746}
2747
2748/* Returns the largest value (assumes not empty) */
2749static inline uint16_t run_container_maximum(const run_container_t *run) {
2750 if (run->n_runs == 0) return 0;
2751 return run->runs[run->n_runs - 1].value + run->runs[run->n_runs - 1].length;
2752}
2753
2754/* Returns the number of values equal or smaller than x */
2755int run_container_rank(const run_container_t *arr, uint16_t x);
2756
2757/* Returns the index of the first run containing a value at least as large as x, or -1 */
2758static inline int run_container_index_equalorlarger(const run_container_t *arr, uint16_t x) {
2759 int32_t index = interleavedBinarySearch(array: arr->runs, lenarray: arr->n_runs, ikey: x);
2760 if (index >= 0) return index;
2761 index = -index - 2; // points to preceding run, possibly -1
2762 if (index != -1) { // possible match
2763 int32_t offset = x - arr->runs[index].value;
2764 int32_t le = arr->runs[index].length;
2765 if (offset <= le) return index;
2766 }
2767 index += 1;
2768 if(index < arr->n_runs) {
2769 return index;
2770 }
2771 return -1;
2772}
2773
2774/*
2775 * Add all values in range [min, max] using hint.
2776 */
2777static inline void run_container_add_range_nruns(run_container_t* run,
2778 uint32_t min, uint32_t max,
2779 int32_t nruns_less,
2780 int32_t nruns_greater) {
2781 int32_t nruns_common = run->n_runs - nruns_less - nruns_greater;
2782 if (nruns_common == 0) {
2783 makeRoomAtIndex(run, index: nruns_less);
2784 run->runs[nruns_less].value = min;
2785 run->runs[nruns_less].length = max - min;
2786 } else {
2787 uint32_t common_min = run->runs[nruns_less].value;
2788 uint32_t common_max = run->runs[nruns_less + nruns_common - 1].value +
2789 run->runs[nruns_less + nruns_common - 1].length;
2790 uint32_t result_min = (common_min < min) ? common_min : min;
2791 uint32_t result_max = (common_max > max) ? common_max : max;
2792
2793 run->runs[nruns_less].value = result_min;
2794 run->runs[nruns_less].length = result_max - result_min;
2795
2796 memmove(dest: &(run->runs[nruns_less + 1]),
2797 src: &(run->runs[run->n_runs - nruns_greater]),
2798 n: nruns_greater*sizeof(rle16_t));
2799 run->n_runs = nruns_less + 1 + nruns_greater;
2800 }
2801}
2802
2803/**
2804 * Add all values in range [min, max]
2805 */
2806static inline void run_container_add_range(run_container_t* run,
2807 uint32_t min, uint32_t max) {
2808 int32_t nruns_greater = rle16_count_greater(array: run->runs, lenarray: run->n_runs, key: max);
2809 int32_t nruns_less = rle16_count_less(array: run->runs, lenarray: run->n_runs - nruns_greater, key: min);
2810 run_container_add_range_nruns(run, min, max, nruns_less, nruns_greater);
2811}
2812
2813/**
2814 * Shifts last $count elements either left (distance < 0) or right (distance > 0)
2815 */
2816static inline void run_container_shift_tail(run_container_t* run,
2817 int32_t count, int32_t distance) {
2818 if (distance > 0) {
2819 if (run->capacity < count+distance) {
2820 run_container_grow(run, min: count+distance, true);
2821 }
2822 }
2823 int32_t srcpos = run->n_runs - count;
2824 int32_t dstpos = srcpos + distance;
2825 memmove(dest: &(run->runs[dstpos]), src: &(run->runs[srcpos]), n: sizeof(rle16_t) * count);
2826 run->n_runs += distance;
2827}
2828
2829/**
2830 * Remove all elements in range [min, max]
2831 */
2832static inline void run_container_remove_range(run_container_t *run, uint32_t min, uint32_t max) {
2833 int32_t first = rle16_find_run(array: run->runs, lenarray: run->n_runs, ikey: min);
2834 int32_t last = rle16_find_run(array: run->runs, lenarray: run->n_runs, ikey: max);
2835
2836 if (first >= 0 && min > run->runs[first].value &&
2837 max < ((uint32_t)run->runs[first].value + (uint32_t)run->runs[first].length)) {
2838 // split this run into two adjacent runs
2839
2840 // right subinterval
2841 makeRoomAtIndex(run, index: first+1);
2842 run->runs[first+1].value = max + 1;
2843 run->runs[first+1].length = (run->runs[first].value + run->runs[first].length) - (max + 1);
2844
2845 // left subinterval
2846 run->runs[first].length = (min - 1) - run->runs[first].value;
2847
2848 return;
2849 }
2850
2851 // update left-most partial run
2852 if (first >= 0) {
2853 if (min > run->runs[first].value) {
2854 run->runs[first].length = (min - 1) - run->runs[first].value;
2855 first++;
2856 }
2857 } else {
2858 first = -first-1;
2859 }
2860
2861 // update right-most run
2862 if (last >= 0) {
2863 uint16_t run_max = run->runs[last].value + run->runs[last].length;
2864 if (run_max > max) {
2865 run->runs[last].value = max + 1;
2866 run->runs[last].length = run_max - (max + 1);
2867 last--;
2868 }
2869 } else {
2870 last = (-last-1) - 1;
2871 }
2872
2873 // remove intermediate runs
2874 if (first <= last) {
2875 run_container_shift_tail(run, count: run->n_runs - (last+1), distance: -(last-first+1));
2876 }
2877}
2878
2879
2880#endif /* INCLUDE_CONTAINERS_RUN_H_ */
2881/* end file include/roaring/containers/run.h */
2882/* begin file include/roaring/containers/convert.h */
2883/*
2884 * convert.h
2885 *
2886 */
2887
2888#ifndef INCLUDE_CONTAINERS_CONVERT_H_
2889#define INCLUDE_CONTAINERS_CONVERT_H_
2890
2891
2892/* Convert an array into a bitset. The input container is not freed or modified.
2893 */
2894bitset_container_t *bitset_container_from_array(const array_container_t *arr);
2895
2896/* Convert a run into a bitset. The input container is not freed or modified. */
2897bitset_container_t *bitset_container_from_run(const run_container_t *arr);
2898
2899/* Convert a run into an array. The input container is not freed or modified. */
2900array_container_t *array_container_from_run(const run_container_t *arr);
2901
2902/* Convert a bitset into an array. The input container is not freed or modified.
2903 */
2904array_container_t *array_container_from_bitset(const bitset_container_t *bits);
2905
2906/* Convert an array into a run. The input container is not freed or modified.
2907 */
2908run_container_t *run_container_from_array(const array_container_t *c);
2909
2910/* convert a run into either an array or a bitset
2911 * might free the container. This does not free the input run container. */
2912void *convert_to_bitset_or_array_container(run_container_t *r, int32_t card,
2913 uint8_t *resulttype);
2914
2915/* convert containers to and from runcontainers, as is most space efficient.
2916 * The container might be freed. */
2917void *convert_run_optimize(void *c, uint8_t typecode_original,
2918 uint8_t *typecode_after);
2919
2920/* converts a run container to either an array or a bitset, IF it saves space.
2921 */
2922/* If a conversion occurs, the caller is responsible to free the original
2923 * container and
2924 * he becomes responsible to free the new one. */
2925void *convert_run_to_efficient_container(run_container_t *c,
2926 uint8_t *typecode_after);
2927// like convert_run_to_efficient_container but frees the old result if needed
2928void *convert_run_to_efficient_container_and_free(run_container_t *c,
2929 uint8_t *typecode_after);
2930
2931/**
2932 * Create new bitset container which is a union of run container and
2933 * range [min, max]. Caller is responsible for freeing run container.
2934 */
2935bitset_container_t *bitset_container_from_run_range(const run_container_t *run,
2936 uint32_t min, uint32_t max);
2937
2938#endif /* INCLUDE_CONTAINERS_CONVERT_H_ */
2939/* end file include/roaring/containers/convert.h */
2940/* begin file include/roaring/containers/mixed_equal.h */
2941/*
2942 * mixed_equal.h
2943 *
2944 */
2945
2946#ifndef CONTAINERS_MIXED_EQUAL_H_
2947#define CONTAINERS_MIXED_EQUAL_H_
2948
2949
2950/**
2951 * Return true if the two containers have the same content.
2952 */
2953bool array_container_equal_bitset(const array_container_t* container1,
2954 const bitset_container_t* container2);
2955
2956/**
2957 * Return true if the two containers have the same content.
2958 */
2959bool run_container_equals_array(const run_container_t* container1,
2960 const array_container_t* container2);
2961/**
2962 * Return true if the two containers have the same content.
2963 */
2964bool run_container_equals_bitset(const run_container_t* container1,
2965 const bitset_container_t* container2);
2966
2967#endif /* CONTAINERS_MIXED_EQUAL_H_ */
2968/* end file include/roaring/containers/mixed_equal.h */
2969/* begin file include/roaring/containers/mixed_subset.h */
2970/*
2971 * mixed_subset.h
2972 *
2973 */
2974
2975#ifndef CONTAINERS_MIXED_SUBSET_H_
2976#define CONTAINERS_MIXED_SUBSET_H_
2977
2978
2979/**
2980 * Return true if container1 is a subset of container2.
2981 */
2982bool array_container_is_subset_bitset(const array_container_t* container1,
2983 const bitset_container_t* container2);
2984
2985/**
2986* Return true if container1 is a subset of container2.
2987 */
2988bool run_container_is_subset_array(const run_container_t* container1,
2989 const array_container_t* container2);
2990
2991/**
2992* Return true if container1 is a subset of container2.
2993 */
2994bool array_container_is_subset_run(const array_container_t* container1,
2995 const run_container_t* container2);
2996
2997/**
2998* Return true if container1 is a subset of container2.
2999 */
3000bool run_container_is_subset_bitset(const run_container_t* container1,
3001 const bitset_container_t* container2);
3002
3003/**
3004* Return true if container1 is a subset of container2.
3005*/
3006bool bitset_container_is_subset_run(const bitset_container_t* container1,
3007 const run_container_t* container2);
3008
3009#endif /* CONTAINERS_MIXED_SUBSET_H_ */
3010/* end file include/roaring/containers/mixed_subset.h */
3011/* begin file include/roaring/containers/mixed_andnot.h */
3012/*
3013 * mixed_andnot.h
3014 */
3015#ifndef INCLUDE_CONTAINERS_MIXED_ANDNOT_H_
3016#define INCLUDE_CONTAINERS_MIXED_ANDNOT_H_
3017
3018
3019/* Compute the andnot of src_1 and src_2 and write the result to
3020 * dst, a valid array container that could be the same as dst.*/
3021void array_bitset_container_andnot(const array_container_t *src_1,
3022 const bitset_container_t *src_2,
3023 array_container_t *dst);
3024
3025/* Compute the andnot of src_1 and src_2 and write the result to
3026 * src_1 */
3027
3028void array_bitset_container_iandnot(array_container_t *src_1,
3029 const bitset_container_t *src_2);
3030
3031/* Compute the andnot of src_1 and src_2 and write the result to
3032 * dst, which does not initially have a valid container.
3033 * Return true for a bitset result; false for array
3034 */
3035
3036bool bitset_array_container_andnot(const bitset_container_t *src_1,
3037 const array_container_t *src_2, void **dst);
3038
3039/* Compute the andnot of src_1 and src_2 and write the result to
3040 * dst (which has no container initially). It will modify src_1
3041 * to be dst if the result is a bitset. Otherwise, it will
3042 * free src_1 and dst will be a new array container. In both
3043 * cases, the caller is responsible for deallocating dst.
3044 * Returns true iff dst is a bitset */
3045
3046bool bitset_array_container_iandnot(bitset_container_t *src_1,
3047 const array_container_t *src_2, void **dst);
3048
3049/* Compute the andnot of src_1 and src_2 and write the result to
3050 * dst. Result may be either a bitset or an array container
3051 * (returns "result is bitset"). dst does not initially have
3052 * any container, but becomes either a bitset container (return
3053 * result true) or an array container.
3054 */
3055
3056bool run_bitset_container_andnot(const run_container_t *src_1,
3057 const bitset_container_t *src_2, void **dst);
3058
3059/* Compute the andnot of src_1 and src_2 and write the result to
3060 * dst. Result may be either a bitset or an array container
3061 * (returns "result is bitset"). dst does not initially have
3062 * any container, but becomes either a bitset container (return
3063 * result true) or an array container.
3064 */
3065
3066bool run_bitset_container_iandnot(run_container_t *src_1,
3067 const bitset_container_t *src_2, void **dst);
3068
3069/* Compute the andnot of src_1 and src_2 and write the result to
3070 * dst. Result may be either a bitset or an array container
3071 * (returns "result is bitset"). dst does not initially have
3072 * any container, but becomes either a bitset container (return
3073 * result true) or an array container.
3074 */
3075
3076bool bitset_run_container_andnot(const bitset_container_t *src_1,
3077 const run_container_t *src_2, void **dst);
3078
3079/* Compute the andnot of src_1 and src_2 and write the result to
3080 * dst (which has no container initially). It will modify src_1
3081 * to be dst if the result is a bitset. Otherwise, it will
3082 * free src_1 and dst will be a new array container. In both
3083 * cases, the caller is responsible for deallocating dst.
3084 * Returns true iff dst is a bitset */
3085
3086bool bitset_run_container_iandnot(bitset_container_t *src_1,
3087 const run_container_t *src_2, void **dst);
3088
3089/* dst does not indicate a valid container initially. Eventually it
3090 * can become any type of container.
3091 */
3092
3093int run_array_container_andnot(const run_container_t *src_1,
3094 const array_container_t *src_2, void **dst);
3095
3096/* Compute the andnot of src_1 and src_2 and write the result to
3097 * dst (which has no container initially). It will modify src_1
3098 * to be dst if the result is a bitset. Otherwise, it will
3099 * free src_1 and dst will be a new array container. In both
3100 * cases, the caller is responsible for deallocating dst.
3101 * Returns true iff dst is a bitset */
3102
3103int run_array_container_iandnot(run_container_t *src_1,
3104 const array_container_t *src_2, void **dst);
3105
3106/* dst must be a valid array container, allowed to be src_1 */
3107
3108void array_run_container_andnot(const array_container_t *src_1,
3109 const run_container_t *src_2,
3110 array_container_t *dst);
3111
3112/* dst does not indicate a valid container initially. Eventually it
3113 * can become any kind of container.
3114 */
3115
3116void array_run_container_iandnot(array_container_t *src_1,
3117 const run_container_t *src_2);
3118
3119/* dst does not indicate a valid container initially. Eventually it
3120 * can become any kind of container.
3121 */
3122
3123int run_run_container_andnot(const run_container_t *src_1,
3124 const run_container_t *src_2, void **dst);
3125
3126/* Compute the andnot of src_1 and src_2 and write the result to
3127 * dst (which has no container initially). It will modify src_1
3128 * to be dst if the result is a bitset. Otherwise, it will
3129 * free src_1 and dst will be a new array container. In both
3130 * cases, the caller is responsible for deallocating dst.
3131 * Returns true iff dst is a bitset */
3132
3133int run_run_container_iandnot(run_container_t *src_1,
3134 const run_container_t *src_2, void **dst);
3135
3136/*
3137 * dst is a valid array container and may be the same as src_1
3138 */
3139
3140void array_array_container_andnot(const array_container_t *src_1,
3141 const array_container_t *src_2,
3142 array_container_t *dst);
3143
3144/* inplace array-array andnot will always be able to reuse the space of
3145 * src_1 */
3146void array_array_container_iandnot(array_container_t *src_1,
3147 const array_container_t *src_2);
3148
3149/* Compute the andnot of src_1 and src_2 and write the result to
3150 * dst (which has no container initially). Return value is
3151 * "dst is a bitset"
3152 */
3153
3154bool bitset_bitset_container_andnot(const bitset_container_t *src_1,
3155 const bitset_container_t *src_2,
3156 void **dst);
3157
3158/* Compute the andnot of src_1 and src_2 and write the result to
3159 * dst (which has no container initially). It will modify src_1
3160 * to be dst if the result is a bitset. Otherwise, it will
3161 * free src_1 and dst will be a new array container. In both
3162 * cases, the caller is responsible for deallocating dst.
3163 * Returns true iff dst is a bitset */
3164
3165bool bitset_bitset_container_iandnot(bitset_container_t *src_1,
3166 const bitset_container_t *src_2,
3167 void **dst);
3168#endif
3169/* end file include/roaring/containers/mixed_andnot.h */
3170/* begin file include/roaring/containers/mixed_intersection.h */
3171/*
3172 * mixed_intersection.h
3173 *
3174 */
3175
3176#ifndef INCLUDE_CONTAINERS_MIXED_INTERSECTION_H_
3177#define INCLUDE_CONTAINERS_MIXED_INTERSECTION_H_
3178
3179/* These functions appear to exclude cases where the
3180 * inputs have the same type and the output is guaranteed
3181 * to have the same type as the inputs. Eg, array intersection
3182 */
3183
3184
3185/* Compute the intersection of src_1 and src_2 and write the result to
3186 * dst. It is allowed for dst to be equal to src_1. We assume that dst is a
3187 * valid container. */
3188void array_bitset_container_intersection(const array_container_t *src_1,
3189 const bitset_container_t *src_2,
3190 array_container_t *dst);
3191
3192/* Compute the size of the intersection of src_1 and src_2. */
3193int array_bitset_container_intersection_cardinality(
3194 const array_container_t *src_1, const bitset_container_t *src_2);
3195
3196
3197
3198/* Checking whether src_1 and src_2 intersect. */
3199bool array_bitset_container_intersect(const array_container_t *src_1,
3200 const bitset_container_t *src_2);
3201
3202/*
3203 * Compute the intersection between src_1 and src_2 and write the result
3204 * to *dst. If the return function is true, the result is a bitset_container_t
3205 * otherwise is a array_container_t. We assume that dst is not pre-allocated. In
3206 * case of failure, *dst will be NULL.
3207 */
3208bool bitset_bitset_container_intersection(const bitset_container_t *src_1,
3209 const bitset_container_t *src_2,
3210 void **dst);
3211
3212/* Compute the intersection between src_1 and src_2 and write the result to
3213 * dst. It is allowed for dst to be equal to src_1. We assume that dst is a
3214 * valid container. */
3215void array_run_container_intersection(const array_container_t *src_1,
3216 const run_container_t *src_2,
3217 array_container_t *dst);
3218
3219/* Compute the intersection between src_1 and src_2 and write the result to
3220 * *dst. If the result is true then the result is a bitset_container_t
3221 * otherwise is a array_container_t.
3222 * If *dst == src_2, then an in-place intersection is attempted
3223 **/
3224bool run_bitset_container_intersection(const run_container_t *src_1,
3225 const bitset_container_t *src_2,
3226 void **dst);
3227
3228/* Compute the size of the intersection between src_1 and src_2 . */
3229int array_run_container_intersection_cardinality(const array_container_t *src_1,
3230 const run_container_t *src_2);
3231
3232/* Compute the size of the intersection between src_1 and src_2
3233 **/
3234int run_bitset_container_intersection_cardinality(const run_container_t *src_1,
3235 const bitset_container_t *src_2);
3236
3237
3238/* Check that src_1 and src_2 intersect. */
3239bool array_run_container_intersect(const array_container_t *src_1,
3240 const run_container_t *src_2);
3241
3242/* Check that src_1 and src_2 intersect.
3243 **/
3244bool run_bitset_container_intersect(const run_container_t *src_1,
3245 const bitset_container_t *src_2);
3246
3247/*
3248 * Same as bitset_bitset_container_intersection except that if the output is to
3249 * be a
3250 * bitset_container_t, then src_1 is modified and no allocation is made.
3251 * If the output is to be an array_container_t, then caller is responsible
3252 * to free the container.
3253 * In all cases, the result is in *dst.
3254 */
3255bool bitset_bitset_container_intersection_inplace(
3256 bitset_container_t *src_1, const bitset_container_t *src_2, void **dst);
3257
3258#endif /* INCLUDE_CONTAINERS_MIXED_INTERSECTION_H_ */
3259/* end file include/roaring/containers/mixed_intersection.h */
3260/* begin file include/roaring/containers/mixed_negation.h */
3261/*
3262 * mixed_negation.h
3263 *
3264 */
3265
3266#ifndef INCLUDE_CONTAINERS_MIXED_NEGATION_H_
3267#define INCLUDE_CONTAINERS_MIXED_NEGATION_H_
3268
3269
3270/* Negation across the entire range of the container.
3271 * Compute the negation of src and write the result
3272 * to *dst. The complement of a
3273 * sufficiently sparse set will always be dense and a hence a bitmap
3274 * We assume that dst is pre-allocated and a valid bitset container
3275 * There can be no in-place version.
3276 */
3277void array_container_negation(const array_container_t *src,
3278 bitset_container_t *dst);
3279
3280/* Negation across the entire range of the container
3281 * Compute the negation of src and write the result
3282 * to *dst. A true return value indicates a bitset result,
3283 * otherwise the result is an array container.
3284 * We assume that dst is not pre-allocated. In
3285 * case of failure, *dst will be NULL.
3286 */
3287bool bitset_container_negation(const bitset_container_t *src, void **dst);
3288
3289/* inplace version */
3290/*
3291 * Same as bitset_container_negation except that if the output is to
3292 * be a
3293 * bitset_container_t, then src is modified and no allocation is made.
3294 * If the output is to be an array_container_t, then caller is responsible
3295 * to free the container.
3296 * In all cases, the result is in *dst.
3297 */
3298bool bitset_container_negation_inplace(bitset_container_t *src, void **dst);
3299
3300/* Negation across the entire range of container
3301 * Compute the negation of src and write the result
3302 * to *dst.
3303 * Return values are the *_TYPECODES as defined * in containers.h
3304 * We assume that dst is not pre-allocated. In
3305 * case of failure, *dst will be NULL.
3306 */
3307int run_container_negation(const run_container_t *src, void **dst);
3308
3309/*
3310 * Same as run_container_negation except that if the output is to
3311 * be a
3312 * run_container_t, and has the capacity to hold the result,
3313 * then src is modified and no allocation is made.
3314 * In all cases, the result is in *dst.
3315 */
3316int run_container_negation_inplace(run_container_t *src, void **dst);
3317
3318/* Negation across a range of the container.
3319 * Compute the negation of src and write the result
3320 * to *dst. Returns true if the result is a bitset container
3321 * and false for an array container. *dst is not preallocated.
3322 */
3323bool array_container_negation_range(const array_container_t *src,
3324 const int range_start, const int range_end,
3325 void **dst);
3326
3327/* Even when the result would fit, it is unclear how to make an
3328 * inplace version without inefficient copying. Thus this routine
3329 * may be a wrapper for the non-in-place version
3330 */
3331bool array_container_negation_range_inplace(array_container_t *src,
3332 const int range_start,
3333 const int range_end, void **dst);
3334
3335/* Negation across a range of the container
3336 * Compute the negation of src and write the result
3337 * to *dst. A true return value indicates a bitset result,
3338 * otherwise the result is an array container.
3339 * We assume that dst is not pre-allocated. In
3340 * case of failure, *dst will be NULL.
3341 */
3342bool bitset_container_negation_range(const bitset_container_t *src,
3343 const int range_start, const int range_end,
3344 void **dst);
3345
3346/* inplace version */
3347/*
3348 * Same as bitset_container_negation except that if the output is to
3349 * be a
3350 * bitset_container_t, then src is modified and no allocation is made.
3351 * If the output is to be an array_container_t, then caller is responsible
3352 * to free the container.
3353 * In all cases, the result is in *dst.
3354 */
3355bool bitset_container_negation_range_inplace(bitset_container_t *src,
3356 const int range_start,
3357 const int range_end, void **dst);
3358
3359/* Negation across a range of container
3360 * Compute the negation of src and write the result
3361 * to *dst. Return values are the *_TYPECODES as defined * in containers.h
3362 * We assume that dst is not pre-allocated. In
3363 * case of failure, *dst will be NULL.
3364 */
3365int run_container_negation_range(const run_container_t *src,
3366 const int range_start, const int range_end,
3367 void **dst);
3368
3369/*
3370 * Same as run_container_negation except that if the output is to
3371 * be a
3372 * run_container_t, and has the capacity to hold the result,
3373 * then src is modified and no allocation is made.
3374 * In all cases, the result is in *dst.
3375 */
3376int run_container_negation_range_inplace(run_container_t *src,
3377 const int range_start,
3378 const int range_end, void **dst);
3379
3380#endif /* INCLUDE_CONTAINERS_MIXED_NEGATION_H_ */
3381/* end file include/roaring/containers/mixed_negation.h */
3382/* begin file include/roaring/containers/mixed_union.h */
3383/*
3384 * mixed_intersection.h
3385 *
3386 */
3387
3388#ifndef INCLUDE_CONTAINERS_MIXED_UNION_H_
3389#define INCLUDE_CONTAINERS_MIXED_UNION_H_
3390
3391/* These functions appear to exclude cases where the
3392 * inputs have the same type and the output is guaranteed
3393 * to have the same type as the inputs. Eg, bitset unions
3394 */
3395
3396
3397/* Compute the union of src_1 and src_2 and write the result to
3398 * dst. It is allowed for src_2 to be dst. */
3399void array_bitset_container_union(const array_container_t *src_1,
3400 const bitset_container_t *src_2,
3401 bitset_container_t *dst);
3402
3403/* Compute the union of src_1 and src_2 and write the result to
3404 * dst. It is allowed for src_2 to be dst. This version does not
3405 * update the cardinality of dst (it is set to BITSET_UNKNOWN_CARDINALITY). */
3406void array_bitset_container_lazy_union(const array_container_t *src_1,
3407 const bitset_container_t *src_2,
3408 bitset_container_t *dst);
3409
3410/*
3411 * Compute the union between src_1 and src_2 and write the result
3412 * to *dst. If the return function is true, the result is a bitset_container_t
3413 * otherwise is a array_container_t. We assume that dst is not pre-allocated. In
3414 * case of failure, *dst will be NULL.
3415 */
3416bool array_array_container_union(const array_container_t *src_1,
3417 const array_container_t *src_2, void **dst);
3418
3419/*
3420 * Compute the union between src_1 and src_2 and write the result
3421 * to *dst if it cannot be written to src_1. If the return function is true,
3422 * the result is a bitset_container_t
3423 * otherwise is a array_container_t. When the result is an array_container_t, it
3424 * it either written to src_1 (if *dst is null) or to *dst.
3425 * If the result is a bitset_container_t and *dst is null, then there was a failure.
3426 */
3427bool array_array_container_inplace_union(array_container_t *src_1,
3428 const array_container_t *src_2, void **dst);
3429
3430/*
3431 * Same as array_array_container_union except that it will more eagerly produce
3432 * a bitset.
3433 */
3434bool array_array_container_lazy_union(const array_container_t *src_1,
3435 const array_container_t *src_2,
3436 void **dst);
3437
3438/*
3439 * Same as array_array_container_inplace_union except that it will more eagerly produce
3440 * a bitset.
3441 */
3442bool array_array_container_lazy_inplace_union(array_container_t *src_1,
3443 const array_container_t *src_2,
3444 void **dst);
3445
3446/* Compute the union of src_1 and src_2 and write the result to
3447 * dst. We assume that dst is a
3448 * valid container. The result might need to be further converted to array or
3449 * bitset container,
3450 * the caller is responsible for the eventual conversion. */
3451void array_run_container_union(const array_container_t *src_1,
3452 const run_container_t *src_2,
3453 run_container_t *dst);
3454
3455/* Compute the union of src_1 and src_2 and write the result to
3456 * src2. The result might need to be further converted to array or
3457 * bitset container,
3458 * the caller is responsible for the eventual conversion. */
3459void array_run_container_inplace_union(const array_container_t *src_1,
3460 run_container_t *src_2);
3461
3462/* Compute the union of src_1 and src_2 and write the result to
3463 * dst. It is allowed for dst to be src_2.
3464 * If run_container_is_full(src_1) is true, you must not be calling this
3465 *function.
3466 **/
3467void run_bitset_container_union(const run_container_t *src_1,
3468 const bitset_container_t *src_2,
3469 bitset_container_t *dst);
3470
3471/* Compute the union of src_1 and src_2 and write the result to
3472 * dst. It is allowed for dst to be src_2. This version does not
3473 * update the cardinality of dst (it is set to BITSET_UNKNOWN_CARDINALITY).
3474 * If run_container_is_full(src_1) is true, you must not be calling this
3475 * function.
3476 * */
3477void run_bitset_container_lazy_union(const run_container_t *src_1,
3478 const bitset_container_t *src_2,
3479 bitset_container_t *dst);
3480
3481#endif /* INCLUDE_CONTAINERS_MIXED_UNION_H_ */
3482/* end file include/roaring/containers/mixed_union.h */
3483/* begin file include/roaring/containers/mixed_xor.h */
3484/*
3485 * mixed_xor.h
3486 *
3487 */
3488
3489#ifndef INCLUDE_CONTAINERS_MIXED_XOR_H_
3490#define INCLUDE_CONTAINERS_MIXED_XOR_H_
3491
3492/* These functions appear to exclude cases where the
3493 * inputs have the same type and the output is guaranteed
3494 * to have the same type as the inputs. Eg, bitset unions
3495 */
3496
3497/*
3498 * Java implementation (as of May 2016) for array_run, run_run
3499 * and bitset_run don't do anything different for inplace.
3500 * (They are not truly in place.)
3501 */
3502
3503
3504
3505/* Compute the xor of src_1 and src_2 and write the result to
3506 * dst (which has no container initially).
3507 * Result is true iff dst is a bitset */
3508bool array_bitset_container_xor(const array_container_t *src_1,
3509 const bitset_container_t *src_2, void **dst);
3510
3511/* Compute the xor of src_1 and src_2 and write the result to
3512 * dst. It is allowed for src_2 to be dst. This version does not
3513 * update the cardinality of dst (it is set to BITSET_UNKNOWN_CARDINALITY).
3514 */
3515
3516void array_bitset_container_lazy_xor(const array_container_t *src_1,
3517 const bitset_container_t *src_2,
3518 bitset_container_t *dst);
3519/* Compute the xor of src_1 and src_2 and write the result to
3520 * dst (which has no container initially). Return value is
3521 * "dst is a bitset"
3522 */
3523
3524bool bitset_bitset_container_xor(const bitset_container_t *src_1,
3525 const bitset_container_t *src_2, void **dst);
3526
3527/* Compute the xor of src_1 and src_2 and write the result to
3528 * dst. Result may be either a bitset or an array container
3529 * (returns "result is bitset"). dst does not initially have
3530 * any container, but becomes either a bitset container (return
3531 * result true) or an array container.
3532 */
3533
3534bool run_bitset_container_xor(const run_container_t *src_1,
3535 const bitset_container_t *src_2, void **dst);
3536
3537/* lazy xor. Dst is initialized and may be equal to src_2.
3538 * Result is left as a bitset container, even if actual
3539 * cardinality would dictate an array container.
3540 */
3541
3542void run_bitset_container_lazy_xor(const run_container_t *src_1,
3543 const bitset_container_t *src_2,
3544 bitset_container_t *dst);
3545
3546/* dst does not indicate a valid container initially. Eventually it
3547 * can become any kind of container.
3548 */
3549
3550int array_run_container_xor(const array_container_t *src_1,
3551 const run_container_t *src_2, void **dst);
3552
3553/* dst does not initially have a valid container. Creates either
3554 * an array or a bitset container, indicated by return code
3555 */
3556
3557bool array_array_container_xor(const array_container_t *src_1,
3558 const array_container_t *src_2, void **dst);
3559
3560/* dst does not initially have a valid container. Creates either
3561 * an array or a bitset container, indicated by return code.
3562 * A bitset container will not have a valid cardinality and the
3563 * container type might not be correct for the actual cardinality
3564 */
3565
3566bool array_array_container_lazy_xor(const array_container_t *src_1,
3567 const array_container_t *src_2, void **dst);
3568
3569/* Dst is a valid run container. (Can it be src_2? Let's say not.)
3570 * Leaves result as run container, even if other options are
3571 * smaller.
3572 */
3573
3574void array_run_container_lazy_xor(const array_container_t *src_1,
3575 const run_container_t *src_2,
3576 run_container_t *dst);
3577
3578/* dst does not indicate a valid container initially. Eventually it
3579 * can become any kind of container.
3580 */
3581
3582int run_run_container_xor(const run_container_t *src_1,
3583 const run_container_t *src_2, void **dst);
3584
3585/* INPLACE versions (initial implementation may not exploit all inplace
3586 * opportunities (if any...)
3587 */
3588
3589/* Compute the xor of src_1 and src_2 and write the result to
3590 * dst (which has no container initially). It will modify src_1
3591 * to be dst if the result is a bitset. Otherwise, it will
3592 * free src_1 and dst will be a new array container. In both
3593 * cases, the caller is responsible for deallocating dst.
3594 * Returns true iff dst is a bitset */
3595
3596bool bitset_array_container_ixor(bitset_container_t *src_1,
3597 const array_container_t *src_2, void **dst);
3598
3599bool bitset_bitset_container_ixor(bitset_container_t *src_1,
3600 const bitset_container_t *src_2, void **dst);
3601
3602bool array_bitset_container_ixor(array_container_t *src_1,
3603 const bitset_container_t *src_2, void **dst);
3604
3605/* Compute the xor of src_1 and src_2 and write the result to
3606 * dst. Result may be either a bitset or an array container
3607 * (returns "result is bitset"). dst does not initially have
3608 * any container, but becomes either a bitset container (return
3609 * result true) or an array container.
3610 */
3611
3612bool run_bitset_container_ixor(run_container_t *src_1,
3613 const bitset_container_t *src_2, void **dst);
3614
3615bool bitset_run_container_ixor(bitset_container_t *src_1,
3616 const run_container_t *src_2, void **dst);
3617
3618/* dst does not indicate a valid container initially. Eventually it
3619 * can become any kind of container.
3620 */
3621
3622int array_run_container_ixor(array_container_t *src_1,
3623 const run_container_t *src_2, void **dst);
3624
3625int run_array_container_ixor(run_container_t *src_1,
3626 const array_container_t *src_2, void **dst);
3627
3628bool array_array_container_ixor(array_container_t *src_1,
3629 const array_container_t *src_2, void **dst);
3630
3631int run_run_container_ixor(run_container_t *src_1, const run_container_t *src_2,
3632 void **dst);
3633#endif
3634/* end file include/roaring/containers/mixed_xor.h */
3635/* begin file include/roaring/containers/containers.h */
3636#ifndef CONTAINERS_CONTAINERS_H
3637#define CONTAINERS_CONTAINERS_H
3638
3639#include <assert.h>
3640#include <stdbool.h>
3641#include <stdio.h>
3642
3643
3644// would enum be possible or better?
3645
3646/**
3647 * The switch case statements follow
3648 * BITSET_CONTAINER_TYPE_CODE -- ARRAY_CONTAINER_TYPE_CODE --
3649 * RUN_CONTAINER_TYPE_CODE
3650 * so it makes more sense to number them 1, 2, 3 (in the vague hope that the
3651 * compiler might exploit this ordering).
3652 */
3653
3654#define BITSET_CONTAINER_TYPE_CODE 1
3655#define ARRAY_CONTAINER_TYPE_CODE 2
3656#define RUN_CONTAINER_TYPE_CODE 3
3657#define SHARED_CONTAINER_TYPE_CODE 4
3658
3659// macro for pairing container type codes
3660#define CONTAINER_PAIR(c1, c2) (4 * (c1) + (c2))
3661
3662/**
3663 * A shared container is a wrapper around a container
3664 * with reference counting.
3665 */
3666
3667struct shared_container_s {
3668 void *container;
3669 uint8_t typecode;
3670 uint32_t counter; // to be managed atomically
3671};
3672
3673typedef struct shared_container_s shared_container_t;
3674
3675/*
3676 * With copy_on_write = true
3677 * Create a new shared container if the typecode is not SHARED_CONTAINER_TYPE,
3678 * otherwise, increase the count
3679 * If copy_on_write = false, then clone.
3680 * Return NULL in case of failure.
3681 **/
3682void *get_copy_of_container(void *container, uint8_t *typecode,
3683 bool copy_on_write);
3684
3685/* Frees a shared container (actually decrement its counter and only frees when
3686 * the counter falls to zero). */
3687void shared_container_free(shared_container_t *container);
3688
3689/* extract a copy from the shared container, freeing the shared container if
3690there is just one instance left,
3691clone instances when the counter is higher than one
3692*/
3693void *shared_container_extract_copy(shared_container_t *container,
3694 uint8_t *typecode);
3695
3696/* access to container underneath */
3697static inline const void *container_unwrap_shared(
3698 const void *candidate_shared_container, uint8_t *type) {
3699 if (*type == SHARED_CONTAINER_TYPE_CODE) {
3700 *type =
3701 ((const shared_container_t *)candidate_shared_container)->typecode;
3702 assert(*type != SHARED_CONTAINER_TYPE_CODE);
3703 return ((const shared_container_t *)candidate_shared_container)->container;
3704 } else {
3705 return candidate_shared_container;
3706 }
3707}
3708
3709
3710/* access to container underneath */
3711static inline void *container_mutable_unwrap_shared(
3712 void *candidate_shared_container, uint8_t *type) {
3713 if (*type == SHARED_CONTAINER_TYPE_CODE) {
3714 *type =
3715 ((shared_container_t *)candidate_shared_container)->typecode;
3716 assert(*type != SHARED_CONTAINER_TYPE_CODE);
3717 return ((shared_container_t *)candidate_shared_container)->container;
3718 } else {
3719 return candidate_shared_container;
3720 }
3721}
3722
3723/* access to container underneath and queries its type */
3724static inline uint8_t get_container_type(const void *container, uint8_t type) {
3725 if (type == SHARED_CONTAINER_TYPE_CODE) {
3726 return ((const shared_container_t *)container)->typecode;
3727 } else {
3728 return type;
3729 }
3730}
3731
3732/**
3733 * Copies a container, requires a typecode. This allocates new memory, caller
3734 * is responsible for deallocation. If the container is not shared, then it is
3735 * physically cloned. Shareable containers are not clonable.
3736 */
3737void *container_clone(const void *container, uint8_t typecode);
3738
3739/* access to container underneath, cloning it if needed */
3740static inline void *get_writable_copy_if_shared(
3741 void *candidate_shared_container, uint8_t *type) {
3742 if (*type == SHARED_CONTAINER_TYPE_CODE) {
3743 return shared_container_extract_copy(
3744 container: (shared_container_t *)candidate_shared_container, typecode: type);
3745 } else {
3746 return candidate_shared_container;
3747 }
3748}
3749
3750/**
3751 * End of shared container code
3752 */
3753
3754static const char *container_names[] = {"bitset", "array", "run", "shared"};
3755static const char *shared_container_names[] = {
3756 "bitset (shared)", "array (shared)", "run (shared)"};
3757
3758// no matter what the initial container was, convert it to a bitset
3759// if a new container is produced, caller responsible for freeing the previous
3760// one
3761// container should not be a shared container
3762static inline void *container_to_bitset(void *container, uint8_t typecode) {
3763 bitset_container_t *result = NULL;
3764 switch (typecode) {
3765 case BITSET_CONTAINER_TYPE_CODE:
3766 return container; // nothing to do
3767 case ARRAY_CONTAINER_TYPE_CODE:
3768 result =
3769 bitset_container_from_array(arr: (array_container_t *)container);
3770 return result;
3771 case RUN_CONTAINER_TYPE_CODE:
3772 result = bitset_container_from_run(arr: (run_container_t *)container);
3773 return result;
3774 case SHARED_CONTAINER_TYPE_CODE:
3775 default:
3776 assert(false);
3777 __builtin_unreachable();
3778 return 0; // unreached
3779 }
3780}
3781
3782/**
3783 * Get the container name from the typecode
3784 */
3785static inline const char *get_container_name(uint8_t typecode) {
3786 switch (typecode) {
3787 case BITSET_CONTAINER_TYPE_CODE:
3788 return container_names[0];
3789 case ARRAY_CONTAINER_TYPE_CODE:
3790 return container_names[1];
3791 case RUN_CONTAINER_TYPE_CODE:
3792 return container_names[2];
3793 case SHARED_CONTAINER_TYPE_CODE:
3794 return container_names[3];
3795 default:
3796 assert(false);
3797 __builtin_unreachable();
3798 return "unknown";
3799 }
3800}
3801
3802static inline const char *get_full_container_name(const void *container,
3803 uint8_t typecode) {
3804 switch (typecode) {
3805 case BITSET_CONTAINER_TYPE_CODE:
3806 return container_names[0];
3807 case ARRAY_CONTAINER_TYPE_CODE:
3808 return container_names[1];
3809 case RUN_CONTAINER_TYPE_CODE:
3810 return container_names[2];
3811 case SHARED_CONTAINER_TYPE_CODE:
3812 switch (((const shared_container_t *)container)->typecode) {
3813 case BITSET_CONTAINER_TYPE_CODE:
3814 return shared_container_names[0];
3815 case ARRAY_CONTAINER_TYPE_CODE:
3816 return shared_container_names[1];
3817 case RUN_CONTAINER_TYPE_CODE:
3818 return shared_container_names[2];
3819 default:
3820 assert(false);
3821 __builtin_unreachable();
3822 return "unknown";
3823 }
3824 break;
3825 default:
3826 assert(false);
3827 __builtin_unreachable();
3828 return "unknown";
3829 }
3830 __builtin_unreachable();
3831 return NULL;
3832}
3833
3834/**
3835 * Get the container cardinality (number of elements), requires a typecode
3836 */
3837static inline int container_get_cardinality(const void *container,
3838 uint8_t typecode) {
3839 container = container_unwrap_shared(candidate_shared_container: container, type: &typecode);
3840 switch (typecode) {
3841 case BITSET_CONTAINER_TYPE_CODE:
3842 return bitset_container_cardinality(
3843 bitset: (const bitset_container_t *)container);
3844 case ARRAY_CONTAINER_TYPE_CODE:
3845 return array_container_cardinality(
3846 array: (const array_container_t *)container);
3847 case RUN_CONTAINER_TYPE_CODE:
3848 return run_container_cardinality(
3849 run: (const run_container_t *)container);
3850 case SHARED_CONTAINER_TYPE_CODE:
3851 default:
3852 assert(false);
3853 __builtin_unreachable();
3854 return 0; // unreached
3855 }
3856}
3857
3858
3859
3860// returns true if a container is known to be full. Note that a lazy bitset
3861// container
3862// might be full without us knowing
3863static inline bool container_is_full(const void *container, uint8_t typecode) {
3864 container = container_unwrap_shared(candidate_shared_container: container, type: &typecode);
3865 switch (typecode) {
3866 case BITSET_CONTAINER_TYPE_CODE:
3867 return bitset_container_cardinality(
3868 bitset: (const bitset_container_t *)container) == (1 << 16);
3869 case ARRAY_CONTAINER_TYPE_CODE:
3870 return array_container_cardinality(
3871 array: (const array_container_t *)container) == (1 << 16);
3872 case RUN_CONTAINER_TYPE_CODE:
3873 return run_container_is_full(run: (const run_container_t *)container);
3874 case SHARED_CONTAINER_TYPE_CODE:
3875 default:
3876 assert(false);
3877 __builtin_unreachable();
3878 return 0; // unreached
3879 }
3880}
3881
3882static inline int container_shrink_to_fit(void *container, uint8_t typecode) {
3883 container = container_mutable_unwrap_shared(candidate_shared_container: container, type: &typecode);
3884 switch (typecode) {
3885 case BITSET_CONTAINER_TYPE_CODE:
3886 return 0; // no shrinking possible
3887 case ARRAY_CONTAINER_TYPE_CODE:
3888 return array_container_shrink_to_fit(
3889 src: (array_container_t *)container);
3890 case RUN_CONTAINER_TYPE_CODE:
3891 return run_container_shrink_to_fit(src: (run_container_t *)container);
3892 case SHARED_CONTAINER_TYPE_CODE:
3893 default:
3894 assert(false);
3895 __builtin_unreachable();
3896 return 0; // unreached
3897 }
3898}
3899
3900
3901/**
3902 * make a container with a run of ones
3903 */
3904/* initially always use a run container, even if an array might be
3905 * marginally
3906 * smaller */
3907static inline void *container_range_of_ones(uint32_t range_start,
3908 uint32_t range_end,
3909 uint8_t *result_type) {
3910 assert(range_end >= range_start);
3911 uint64_t cardinality = range_end - range_start + 1;
3912 if(cardinality <= 2) {
3913 *result_type = ARRAY_CONTAINER_TYPE_CODE;
3914 return array_container_create_range(min: range_start, max: range_end);
3915 } else {
3916 *result_type = RUN_CONTAINER_TYPE_CODE;
3917 return run_container_create_range(start: range_start, stop: range_end);
3918 }
3919}
3920
3921
3922/* Create a container with all the values between in [min,max) at a
3923 distance k*step from min. */
3924static inline void *container_from_range(uint8_t *type, uint32_t min,
3925 uint32_t max, uint16_t step) {
3926 if (step == 0) return NULL; // being paranoid
3927 if (step == 1) {
3928 return container_range_of_ones(range_start: min,range_end: max,result_type: type);
3929 // Note: the result is not always a run (need to check the cardinality)
3930 //*type = RUN_CONTAINER_TYPE_CODE;
3931 //return run_container_create_range(min, max);
3932 }
3933 int size = (max - min + step - 1) / step;
3934 if (size <= DEFAULT_MAX_SIZE) { // array container
3935 *type = ARRAY_CONTAINER_TYPE_CODE;
3936 array_container_t *array = array_container_create_given_capacity(size);
3937 array_container_add_from_range(arr: array, min, max, step);
3938 assert(array->cardinality == size);
3939 return array;
3940 } else { // bitset container
3941 *type = BITSET_CONTAINER_TYPE_CODE;
3942 bitset_container_t *bitset = bitset_container_create();
3943 bitset_container_add_from_range(bitset, min, max, step);
3944 assert(bitset->cardinality == size);
3945 return bitset;
3946 }
3947}
3948
3949/**
3950 * "repair" the container after lazy operations.
3951 */
3952static inline void *container_repair_after_lazy(void *container,
3953 uint8_t *typecode) {
3954 container = get_writable_copy_if_shared(
3955 candidate_shared_container: container, type: typecode); // TODO: this introduces unnecessary cloning
3956 void *result = NULL;
3957 switch (*typecode) {
3958 case BITSET_CONTAINER_TYPE_CODE:
3959 ((bitset_container_t *)container)->cardinality =
3960 bitset_container_compute_cardinality(
3961 bitset: (bitset_container_t *)container);
3962 if (((bitset_container_t *)container)->cardinality <=
3963 DEFAULT_MAX_SIZE) {
3964 result = array_container_from_bitset(
3965 bits: (const bitset_container_t *)container);
3966 bitset_container_free(bitset: (bitset_container_t *)container);
3967 *typecode = ARRAY_CONTAINER_TYPE_CODE;
3968 return result;
3969 }
3970 return container;
3971 case ARRAY_CONTAINER_TYPE_CODE:
3972 return container; // nothing to do
3973 case RUN_CONTAINER_TYPE_CODE:
3974 return convert_run_to_efficient_container_and_free(
3975 c: (run_container_t *)container, typecode_after: typecode);
3976 case SHARED_CONTAINER_TYPE_CODE:
3977 default:
3978 assert(false);
3979 __builtin_unreachable();
3980 return 0; // unreached
3981 }
3982}
3983
3984/**
3985 * Writes the underlying array to buf, outputs how many bytes were written.
3986 * This is meant to be byte-by-byte compatible with the Java and Go versions of
3987 * Roaring.
3988 * The number of bytes written should be
3989 * container_write(container, buf).
3990 *
3991 */
3992static inline int32_t container_write(const void *container, uint8_t typecode,
3993 char *buf) {
3994 container = container_unwrap_shared(candidate_shared_container: container, type: &typecode);
3995 switch (typecode) {
3996 case BITSET_CONTAINER_TYPE_CODE:
3997 return bitset_container_write(container: (const bitset_container_t *)container, buf);
3998 case ARRAY_CONTAINER_TYPE_CODE:
3999 return array_container_write(container: (const array_container_t *)container, buf);
4000 case RUN_CONTAINER_TYPE_CODE:
4001 return run_container_write(container: (const run_container_t *)container, buf);
4002 case SHARED_CONTAINER_TYPE_CODE:
4003 default:
4004 assert(false);
4005 __builtin_unreachable();
4006 return 0; // unreached
4007 }
4008}
4009
4010/**
4011 * Get the container size in bytes under portable serialization (see
4012 * container_write), requires a
4013 * typecode
4014 */
4015static inline int32_t container_size_in_bytes(const void *container,
4016 uint8_t typecode) {
4017 container = container_unwrap_shared(candidate_shared_container: container, type: &typecode);
4018 switch (typecode) {
4019 case BITSET_CONTAINER_TYPE_CODE:
4020 return bitset_container_size_in_bytes(
4021 container: (const bitset_container_t *)container);
4022 case ARRAY_CONTAINER_TYPE_CODE:
4023 return array_container_size_in_bytes(
4024 container: (const array_container_t *)container);
4025 case RUN_CONTAINER_TYPE_CODE:
4026 return run_container_size_in_bytes(container: (const run_container_t *)container);
4027 case SHARED_CONTAINER_TYPE_CODE:
4028 default:
4029 assert(false);
4030 __builtin_unreachable();
4031 return 0; // unreached
4032 }
4033}
4034
4035/**
4036 * print the container (useful for debugging), requires a typecode
4037 */
4038void container_printf(const void *container, uint8_t typecode);
4039
4040/**
4041 * print the content of the container as a comma-separated list of 32-bit values
4042 * starting at base, requires a typecode
4043 */
4044void container_printf_as_uint32_array(const void *container, uint8_t typecode,
4045 uint32_t base);
4046
4047/**
4048 * Checks whether a container is not empty, requires a typecode
4049 */
4050static inline bool container_nonzero_cardinality(const void *container,
4051 uint8_t typecode) {
4052 container = container_unwrap_shared(candidate_shared_container: container, type: &typecode);
4053 switch (typecode) {
4054 case BITSET_CONTAINER_TYPE_CODE:
4055 return bitset_container_const_nonzero_cardinality(
4056 bitset: (const bitset_container_t *)container);
4057 case ARRAY_CONTAINER_TYPE_CODE:
4058 return array_container_nonzero_cardinality(
4059 array: (const array_container_t *)container);
4060 case RUN_CONTAINER_TYPE_CODE:
4061 return run_container_nonzero_cardinality(
4062 run: (const run_container_t *)container);
4063 case SHARED_CONTAINER_TYPE_CODE:
4064 default:
4065 assert(false);
4066 __builtin_unreachable();
4067 return 0; // unreached
4068 }
4069}
4070
4071/**
4072 * Recover memory from a container, requires a typecode
4073 */
4074void container_free(void *container, uint8_t typecode);
4075
4076/**
4077 * Convert a container to an array of values, requires a typecode as well as a
4078 * "base" (most significant values)
4079 * Returns number of ints added.
4080 */
4081static inline int container_to_uint32_array(uint32_t *output,
4082 const void *container,
4083 uint8_t typecode, uint32_t base) {
4084 container = container_unwrap_shared(candidate_shared_container: container, type: &typecode);
4085 switch (typecode) {
4086 case BITSET_CONTAINER_TYPE_CODE:
4087 return bitset_container_to_uint32_array(
4088 out: output, cont: (const bitset_container_t *)container, base);
4089 case ARRAY_CONTAINER_TYPE_CODE:
4090 return array_container_to_uint32_array(
4091 vout: output, cont: (const array_container_t *)container, base);
4092 case RUN_CONTAINER_TYPE_CODE:
4093 return run_container_to_uint32_array(
4094 vout: output, cont: (const run_container_t *)container, base);
4095 case SHARED_CONTAINER_TYPE_CODE:
4096 default:
4097 assert(false);
4098 __builtin_unreachable();
4099 return 0; // unreached
4100 }
4101}
4102
4103/**
4104 * Add a value to a container, requires a typecode, fills in new_typecode and
4105 * return (possibly different) container.
4106 * This function may allocate a new container, and caller is responsible for
4107 * memory deallocation
4108 */
4109static inline void *container_add(void *container, uint16_t val,
4110 uint8_t typecode, uint8_t *new_typecode) {
4111 container = get_writable_copy_if_shared(candidate_shared_container: container, type: &typecode);
4112 switch (typecode) {
4113 case BITSET_CONTAINER_TYPE_CODE:
4114 bitset_container_set(bitset: (bitset_container_t *)container, pos: val);
4115 *new_typecode = BITSET_CONTAINER_TYPE_CODE;
4116 return container;
4117 case ARRAY_CONTAINER_TYPE_CODE: {
4118 array_container_t *ac = (array_container_t *)container;
4119 if (array_container_try_add(arr: ac, value: val, max_cardinality: DEFAULT_MAX_SIZE) != -1) {
4120 *new_typecode = ARRAY_CONTAINER_TYPE_CODE;
4121 return ac;
4122 } else {
4123 bitset_container_t* bitset = bitset_container_from_array(arr: ac);
4124 bitset_container_add(bitset, pos: val);
4125 *new_typecode = BITSET_CONTAINER_TYPE_CODE;
4126 return bitset;
4127 }
4128 } break;
4129 case RUN_CONTAINER_TYPE_CODE:
4130 // per Java, no container type adjustments are done (revisit?)
4131 run_container_add(run: (run_container_t *)container, pos: val);
4132 *new_typecode = RUN_CONTAINER_TYPE_CODE;
4133 return container;
4134 case SHARED_CONTAINER_TYPE_CODE:
4135 default:
4136 assert(false);
4137 __builtin_unreachable();
4138 return NULL;
4139 }
4140}
4141
4142/**
4143 * Remove a value from a container, requires a typecode, fills in new_typecode
4144 * and
4145 * return (possibly different) container.
4146 * This function may allocate a new container, and caller is responsible for
4147 * memory deallocation
4148 */
4149static inline void *container_remove(void *container, uint16_t val,
4150 uint8_t typecode, uint8_t *new_typecode) {
4151 container = get_writable_copy_if_shared(candidate_shared_container: container, type: &typecode);
4152 switch (typecode) {
4153 case BITSET_CONTAINER_TYPE_CODE:
4154 if (bitset_container_remove(bitset: (bitset_container_t *)container, pos: val)) {
4155 if (bitset_container_cardinality(
4156 bitset: (bitset_container_t *)container) <= DEFAULT_MAX_SIZE) {
4157 *new_typecode = ARRAY_CONTAINER_TYPE_CODE;
4158 return array_container_from_bitset(
4159 bits: (bitset_container_t *)container);
4160 }
4161 }
4162 *new_typecode = typecode;
4163 return container;
4164 case ARRAY_CONTAINER_TYPE_CODE:
4165 *new_typecode = typecode;
4166 array_container_remove(arr: (array_container_t *)container, pos: val);
4167 return container;
4168 case RUN_CONTAINER_TYPE_CODE:
4169 // per Java, no container type adjustments are done (revisit?)
4170 run_container_remove(run: (run_container_t *)container, pos: val);
4171 *new_typecode = RUN_CONTAINER_TYPE_CODE;
4172 return container;
4173 case SHARED_CONTAINER_TYPE_CODE:
4174 default:
4175 assert(false);
4176 __builtin_unreachable();
4177 return NULL;
4178 }
4179}
4180
4181/**
4182 * Check whether a value is in a container, requires a typecode
4183 */
4184static inline bool container_contains(const void *container, uint16_t val,
4185 uint8_t typecode) {
4186 container = container_unwrap_shared(candidate_shared_container: container, type: &typecode);
4187 switch (typecode) {
4188 case BITSET_CONTAINER_TYPE_CODE:
4189 return bitset_container_get(bitset: (const bitset_container_t *)container,
4190 pos: val);
4191 case ARRAY_CONTAINER_TYPE_CODE:
4192 return array_container_contains(
4193 arr: (const array_container_t *)container, pos: val);
4194 case RUN_CONTAINER_TYPE_CODE:
4195 return run_container_contains(run: (const run_container_t *)container,
4196 pos: val);
4197 case SHARED_CONTAINER_TYPE_CODE:
4198 default:
4199 assert(false);
4200 __builtin_unreachable();
4201 return false;
4202 }
4203}
4204
4205/**
4206 * Check whether a range of values from range_start (included) to range_end (excluded)
4207 * is in a container, requires a typecode
4208 */
4209static inline bool container_contains_range(const void *container, uint32_t range_start,
4210 uint32_t range_end, uint8_t typecode) {
4211 container = container_unwrap_shared(candidate_shared_container: container, type: &typecode);
4212 switch (typecode) {
4213 case BITSET_CONTAINER_TYPE_CODE:
4214 return bitset_container_get_range(bitset: (const bitset_container_t *)container,
4215 pos_start: range_start, pos_end: range_end);
4216 case ARRAY_CONTAINER_TYPE_CODE:
4217 return array_container_contains_range(arr: (const array_container_t *)container,
4218 range_start, range_end);
4219 case RUN_CONTAINER_TYPE_CODE:
4220 return run_container_contains_range(run: (const run_container_t *)container,
4221 pos_start: range_start, pos_end: range_end);
4222 case SHARED_CONTAINER_TYPE_CODE:
4223 default:
4224 assert(false);
4225 __builtin_unreachable();
4226 return false;
4227 }
4228}
4229
4230int32_t container_serialize(const void *container, uint8_t typecode,
4231 char *buf) WARN_UNUSED;
4232
4233uint32_t container_serialization_len(const void *container, uint8_t typecode);
4234
4235void *container_deserialize(uint8_t typecode, const char *buf, size_t buf_len);
4236
4237/**
4238 * Returns true if the two containers have the same content. Note that
4239 * two containers having different types can be "equal" in this sense.
4240 */
4241static inline bool container_equals(const void *c1, uint8_t type1,
4242 const void *c2, uint8_t type2) {
4243 c1 = container_unwrap_shared(candidate_shared_container: c1, type: &type1);
4244 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
4245 switch (CONTAINER_PAIR(type1, type2)) {
4246 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4247 BITSET_CONTAINER_TYPE_CODE):
4248 return bitset_container_equals(container1: (const bitset_container_t *)c1,
4249 container2: (const bitset_container_t *)c2);
4250 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4251 RUN_CONTAINER_TYPE_CODE):
4252 return run_container_equals_bitset(container1: (const run_container_t *)c2,
4253 container2: (const bitset_container_t *)c1);
4254 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
4255 BITSET_CONTAINER_TYPE_CODE):
4256 return run_container_equals_bitset(container1: (const run_container_t *)c1,
4257 container2: (const bitset_container_t *)c2);
4258 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4259 ARRAY_CONTAINER_TYPE_CODE):
4260 // java would always return false?
4261 return array_container_equal_bitset(container1: (const array_container_t *)c2,
4262 container2: (const bitset_container_t *)c1);
4263 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4264 BITSET_CONTAINER_TYPE_CODE):
4265 // java would always return false?
4266 return array_container_equal_bitset(container1: (const array_container_t *)c1,
4267 container2: (const bitset_container_t *)c2);
4268 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4269 return run_container_equals_array(container1: (const run_container_t *)c2,
4270 container2: (const array_container_t *)c1);
4271 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
4272 return run_container_equals_array(container1: (const run_container_t *)c1,
4273 container2: (const array_container_t *)c2);
4274 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4275 ARRAY_CONTAINER_TYPE_CODE):
4276 return array_container_equals(container1: (const array_container_t *)c1,
4277 container2: (const array_container_t *)c2);
4278 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4279 return run_container_equals(container1: (const run_container_t *)c1,
4280 container2: (const run_container_t *)c2);
4281 default:
4282 assert(false);
4283 __builtin_unreachable();
4284 return false;
4285 }
4286}
4287
4288/**
4289 * Returns true if the container c1 is a subset of the container c2. Note that
4290 * c1 can be a subset of c2 even if they have a different type.
4291 */
4292static inline bool container_is_subset(const void *c1, uint8_t type1,
4293 const void *c2, uint8_t type2) {
4294 c1 = container_unwrap_shared(candidate_shared_container: c1, type: &type1);
4295 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
4296 switch (CONTAINER_PAIR(type1, type2)) {
4297 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4298 BITSET_CONTAINER_TYPE_CODE):
4299 return bitset_container_is_subset(container1: (const bitset_container_t *)c1,
4300 container2: (const bitset_container_t *)c2);
4301 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4302 RUN_CONTAINER_TYPE_CODE):
4303 return bitset_container_is_subset_run(container1: (const bitset_container_t *)c1,
4304 container2: (const run_container_t *)c2);
4305 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
4306 BITSET_CONTAINER_TYPE_CODE):
4307 return run_container_is_subset_bitset(container1: (const run_container_t *)c1,
4308 container2: (const bitset_container_t *)c2);
4309 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4310 ARRAY_CONTAINER_TYPE_CODE):
4311 return false; // by construction, size(c1) > size(c2)
4312 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4313 BITSET_CONTAINER_TYPE_CODE):
4314 return array_container_is_subset_bitset(container1: (const array_container_t *)c1,
4315 container2: (const bitset_container_t *)c2);
4316 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4317 return array_container_is_subset_run(container1: (const array_container_t *)c1,
4318 container2: (const run_container_t *)c2);
4319 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
4320 return run_container_is_subset_array(container1: (const run_container_t *)c1,
4321 container2: (const array_container_t *)c2);
4322 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4323 ARRAY_CONTAINER_TYPE_CODE):
4324 return array_container_is_subset(container1: (const array_container_t *)c1,
4325 container2: (const array_container_t *)c2);
4326 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4327 return run_container_is_subset(container1: (const run_container_t *)c1,
4328 container2: (const run_container_t *)c2);
4329 default:
4330 assert(false);
4331 __builtin_unreachable();
4332 return false;
4333 }
4334}
4335
4336// macro-izations possibilities for generic non-inplace binary-op dispatch
4337
4338/**
4339 * Compute intersection between two containers, generate a new container (having
4340 * type result_type), requires a typecode. This allocates new memory, caller
4341 * is responsible for deallocation.
4342 */
4343static inline void *container_and(const void *c1, uint8_t type1, const void *c2,
4344 uint8_t type2, uint8_t *result_type) {
4345 c1 = container_unwrap_shared(candidate_shared_container: c1, type: &type1);
4346 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
4347 void *result = NULL;
4348 switch (CONTAINER_PAIR(type1, type2)) {
4349 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4350 BITSET_CONTAINER_TYPE_CODE):
4351 *result_type = bitset_bitset_container_intersection(
4352 src_1: (const bitset_container_t *)c1,
4353 src_2: (const bitset_container_t *)c2, dst: &result)
4354 ? BITSET_CONTAINER_TYPE_CODE
4355 : ARRAY_CONTAINER_TYPE_CODE;
4356 return result;
4357 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4358 ARRAY_CONTAINER_TYPE_CODE):
4359 result = array_container_create();
4360 array_container_intersection(src_1: (const array_container_t *)c1,
4361 src_2: (const array_container_t *)c2,
4362 dst: (array_container_t *)result);
4363 *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
4364 return result;
4365 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4366 result = run_container_create();
4367 run_container_intersection(src_1: (const run_container_t *)c1,
4368 src_2: (const run_container_t *)c2,
4369 dst: (run_container_t *)result);
4370 return convert_run_to_efficient_container_and_free(
4371 c: (run_container_t *)result, typecode_after: result_type);
4372 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4373 ARRAY_CONTAINER_TYPE_CODE):
4374 result = array_container_create();
4375 array_bitset_container_intersection(src_1: (const array_container_t *)c2,
4376 src_2: (const bitset_container_t *)c1,
4377 dst: (array_container_t *)result);
4378 *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
4379 return result;
4380 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4381 BITSET_CONTAINER_TYPE_CODE):
4382 result = array_container_create();
4383 *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
4384 array_bitset_container_intersection(src_1: (const array_container_t *)c1,
4385 src_2: (const bitset_container_t *)c2,
4386 dst: (array_container_t *)result);
4387 return result;
4388
4389 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4390 RUN_CONTAINER_TYPE_CODE):
4391 *result_type = run_bitset_container_intersection(
4392 src_1: (const run_container_t *)c2,
4393 src_2: (const bitset_container_t *)c1, dst: &result)
4394 ? BITSET_CONTAINER_TYPE_CODE
4395 : ARRAY_CONTAINER_TYPE_CODE;
4396 return result;
4397 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
4398 BITSET_CONTAINER_TYPE_CODE):
4399 *result_type = run_bitset_container_intersection(
4400 src_1: (const run_container_t *)c1,
4401 src_2: (const bitset_container_t *)c2, dst: &result)
4402 ? BITSET_CONTAINER_TYPE_CODE
4403 : ARRAY_CONTAINER_TYPE_CODE;
4404 return result;
4405 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4406 result = array_container_create();
4407 *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
4408 array_run_container_intersection(src_1: (const array_container_t *)c1,
4409 src_2: (const run_container_t *)c2,
4410 dst: (array_container_t *)result);
4411 return result;
4412
4413 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
4414 result = array_container_create();
4415 *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
4416 array_run_container_intersection(src_1: (const array_container_t *)c2,
4417 src_2: (const run_container_t *)c1,
4418 dst: (array_container_t *)result);
4419 return result;
4420 default:
4421 assert(false);
4422 __builtin_unreachable();
4423 return NULL;
4424 }
4425}
4426
4427/**
4428 * Compute the size of the intersection between two containers.
4429 */
4430static inline int container_and_cardinality(const void *c1, uint8_t type1,
4431 const void *c2, uint8_t type2) {
4432 c1 = container_unwrap_shared(candidate_shared_container: c1, type: &type1);
4433 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
4434 switch (CONTAINER_PAIR(type1, type2)) {
4435 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4436 BITSET_CONTAINER_TYPE_CODE):
4437 return bitset_container_and_justcard(
4438 src_1: (const bitset_container_t *)c1, src_2: (const bitset_container_t *)c2);
4439 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4440 ARRAY_CONTAINER_TYPE_CODE):
4441 return array_container_intersection_cardinality(
4442 src_1: (const array_container_t *)c1, src_2: (const array_container_t *)c2);
4443 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4444 return run_container_intersection_cardinality(
4445 src_1: (const run_container_t *)c1, src_2: (const run_container_t *)c2);
4446 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4447 ARRAY_CONTAINER_TYPE_CODE):
4448 return array_bitset_container_intersection_cardinality(
4449 src_1: (const array_container_t *)c2, src_2: (const bitset_container_t *)c1);
4450 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4451 BITSET_CONTAINER_TYPE_CODE):
4452 return array_bitset_container_intersection_cardinality(
4453 src_1: (const array_container_t *)c1, src_2: (const bitset_container_t *)c2);
4454 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4455 RUN_CONTAINER_TYPE_CODE):
4456 return run_bitset_container_intersection_cardinality(
4457 src_1: (const run_container_t *)c2, src_2: (const bitset_container_t *)c1);
4458 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
4459 BITSET_CONTAINER_TYPE_CODE):
4460 return run_bitset_container_intersection_cardinality(
4461 src_1: (const run_container_t *)c1, src_2: (const bitset_container_t *)c2);
4462 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4463 return array_run_container_intersection_cardinality(
4464 src_1: (const array_container_t *)c1, src_2: (const run_container_t *)c2);
4465 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
4466 return array_run_container_intersection_cardinality(
4467 src_1: (const array_container_t *)c2, src_2: (const run_container_t *)c1);
4468 default:
4469 assert(false);
4470 __builtin_unreachable();
4471 return 0;
4472 }
4473}
4474
4475/**
4476 * Check whether two containers intersect.
4477 */
4478static inline bool container_intersect(const void *c1, uint8_t type1, const void *c2,
4479 uint8_t type2) {
4480 c1 = container_unwrap_shared(candidate_shared_container: c1, type: &type1);
4481 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
4482 switch (CONTAINER_PAIR(type1, type2)) {
4483 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4484 BITSET_CONTAINER_TYPE_CODE):
4485 return bitset_container_intersect(
4486 src_1: (const bitset_container_t *)c1,
4487 src_2: (const bitset_container_t *)c2);
4488 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4489 ARRAY_CONTAINER_TYPE_CODE):
4490 return array_container_intersect(src_1: (const array_container_t *)c1,
4491 src_2: (const array_container_t *)c2);
4492 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4493 return run_container_intersect(src_1: (const run_container_t *)c1,
4494 src_2: (const run_container_t *)c2);
4495 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4496 ARRAY_CONTAINER_TYPE_CODE):
4497 return array_bitset_container_intersect(src_1: (const array_container_t *)c2,
4498 src_2: (const bitset_container_t *)c1);
4499 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4500 BITSET_CONTAINER_TYPE_CODE):
4501 return array_bitset_container_intersect(src_1: (const array_container_t *)c1,
4502 src_2: (const bitset_container_t *)c2);
4503 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4504 RUN_CONTAINER_TYPE_CODE):
4505 return run_bitset_container_intersect(
4506 src_1: (const run_container_t *)c2,
4507 src_2: (const bitset_container_t *)c1);
4508 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
4509 BITSET_CONTAINER_TYPE_CODE):
4510 return run_bitset_container_intersect(
4511 src_1: (const run_container_t *)c1,
4512 src_2: (const bitset_container_t *)c2);
4513 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4514 return array_run_container_intersect(src_1: (const array_container_t *)c1,
4515 src_2: (const run_container_t *)c2);
4516 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
4517 return array_run_container_intersect(src_1: (const array_container_t *)c2,
4518 src_2: (const run_container_t *)c1);
4519 default:
4520 assert(false);
4521 __builtin_unreachable();
4522 return 0;
4523 }
4524}
4525
4526/**
4527 * Compute intersection between two containers, with result in the first
4528 container if possible. If the returned pointer is identical to c1,
4529 then the container has been modified. If the returned pointer is different
4530 from c1, then a new container has been created and the caller is responsible
4531 for freeing it.
4532 The type of the first container may change. Returns the modified
4533 (and possibly new) container.
4534*/
4535static inline void *container_iand(void *c1, uint8_t type1, const void *c2,
4536 uint8_t type2, uint8_t *result_type) {
4537 c1 = get_writable_copy_if_shared(candidate_shared_container: c1, type: &type1);
4538 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
4539 void *result = NULL;
4540 switch (CONTAINER_PAIR(type1, type2)) {
4541 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4542 BITSET_CONTAINER_TYPE_CODE):
4543 *result_type =
4544 bitset_bitset_container_intersection_inplace(
4545 src_1: (bitset_container_t *)c1, src_2: (const bitset_container_t *)c2, dst: &result)
4546 ? BITSET_CONTAINER_TYPE_CODE
4547 : ARRAY_CONTAINER_TYPE_CODE;
4548 return result;
4549 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4550 ARRAY_CONTAINER_TYPE_CODE):
4551 array_container_intersection_inplace(src_1: (array_container_t *)c1,
4552 src_2: (const array_container_t *)c2);
4553 *result_type = ARRAY_CONTAINER_TYPE_CODE;
4554 return c1;
4555 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4556 result = run_container_create();
4557 run_container_intersection(src_1: (const run_container_t *)c1,
4558 src_2: (const run_container_t *)c2,
4559 dst: (run_container_t *)result);
4560 // as of January 2016, Java code used non-in-place intersection for
4561 // two runcontainers
4562 return convert_run_to_efficient_container_and_free(
4563 c: (run_container_t *)result, typecode_after: result_type);
4564 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4565 ARRAY_CONTAINER_TYPE_CODE):
4566 // c1 is a bitmap so no inplace possible
4567 result = array_container_create();
4568 array_bitset_container_intersection(src_1: (const array_container_t *)c2,
4569 src_2: (const bitset_container_t *)c1,
4570 dst: (array_container_t *)result);
4571 *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
4572 return result;
4573 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4574 BITSET_CONTAINER_TYPE_CODE):
4575 *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
4576 array_bitset_container_intersection(
4577 src_1: (const array_container_t *)c1, src_2: (const bitset_container_t *)c2,
4578 dst: (array_container_t *)c1); // allowed
4579 return c1;
4580
4581 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4582 RUN_CONTAINER_TYPE_CODE):
4583 // will attempt in-place computation
4584 *result_type = run_bitset_container_intersection(
4585 src_1: (const run_container_t *)c2,
4586 src_2: (const bitset_container_t *)c1, dst: &c1)
4587 ? BITSET_CONTAINER_TYPE_CODE
4588 : ARRAY_CONTAINER_TYPE_CODE;
4589 return c1;
4590 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
4591 BITSET_CONTAINER_TYPE_CODE):
4592 *result_type = run_bitset_container_intersection(
4593 src_1: (const run_container_t *)c1,
4594 src_2: (const bitset_container_t *)c2, dst: &result)
4595 ? BITSET_CONTAINER_TYPE_CODE
4596 : ARRAY_CONTAINER_TYPE_CODE;
4597 return result;
4598 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4599 result = array_container_create();
4600 *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
4601 array_run_container_intersection(src_1: (const array_container_t *)c1,
4602 src_2: (const run_container_t *)c2,
4603 dst: (array_container_t *)result);
4604 return result;
4605
4606 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
4607 result = array_container_create();
4608 *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
4609 array_run_container_intersection(src_1: (const array_container_t *)c2,
4610 src_2: (const run_container_t *)c1,
4611 dst: (array_container_t *)result);
4612 return result;
4613 default:
4614 assert(false);
4615 __builtin_unreachable();
4616 return NULL;
4617 }
4618}
4619
4620/**
4621 * Compute union between two containers, generate a new container (having type
4622 * result_type), requires a typecode. This allocates new memory, caller
4623 * is responsible for deallocation.
4624 */
4625static inline void *container_or(const void *c1, uint8_t type1, const void *c2,
4626 uint8_t type2, uint8_t *result_type) {
4627 c1 = container_unwrap_shared(candidate_shared_container: c1, type: &type1);
4628 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
4629 void *result = NULL;
4630 switch (CONTAINER_PAIR(type1, type2)) {
4631 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4632 BITSET_CONTAINER_TYPE_CODE):
4633 result = bitset_container_create();
4634 bitset_container_or(src_1: (const bitset_container_t *)c1,
4635 src_2: (const bitset_container_t *)c2,
4636 dst: (bitset_container_t *)result);
4637 *result_type = BITSET_CONTAINER_TYPE_CODE;
4638 return result;
4639 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4640 ARRAY_CONTAINER_TYPE_CODE):
4641 *result_type = array_array_container_union(
4642 src_1: (const array_container_t *)c1,
4643 src_2: (const array_container_t *)c2, dst: &result)
4644 ? BITSET_CONTAINER_TYPE_CODE
4645 : ARRAY_CONTAINER_TYPE_CODE;
4646 return result;
4647 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4648 result = run_container_create();
4649 run_container_union(src_1: (const run_container_t *)c1,
4650 src_2: (const run_container_t *)c2,
4651 dst: (run_container_t *)result);
4652 *result_type = RUN_CONTAINER_TYPE_CODE;
4653 // todo: could be optimized since will never convert to array
4654 result = convert_run_to_efficient_container_and_free(
4655 c: (run_container_t *)result, typecode_after: (uint8_t *)result_type);
4656 return result;
4657 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4658 ARRAY_CONTAINER_TYPE_CODE):
4659 result = bitset_container_create();
4660 array_bitset_container_union(src_1: (const array_container_t *)c2,
4661 src_2: (const bitset_container_t *)c1,
4662 dst: (bitset_container_t *)result);
4663 *result_type = BITSET_CONTAINER_TYPE_CODE;
4664 return result;
4665 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4666 BITSET_CONTAINER_TYPE_CODE):
4667 result = bitset_container_create();
4668 array_bitset_container_union(src_1: (const array_container_t *)c1,
4669 src_2: (const bitset_container_t *)c2,
4670 dst: (bitset_container_t *)result);
4671 *result_type = BITSET_CONTAINER_TYPE_CODE;
4672 return result;
4673 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4674 RUN_CONTAINER_TYPE_CODE):
4675 if (run_container_is_full(run: (const run_container_t *)c2)) {
4676 result = run_container_create();
4677 *result_type = RUN_CONTAINER_TYPE_CODE;
4678 run_container_copy(src: (const run_container_t *)c2,
4679 dst: (run_container_t *)result);
4680 return result;
4681 }
4682 result = bitset_container_create();
4683 run_bitset_container_union(src_1: (const run_container_t *)c2,
4684 src_2: (const bitset_container_t *)c1,
4685 dst: (bitset_container_t *)result);
4686 *result_type = BITSET_CONTAINER_TYPE_CODE;
4687 return result;
4688 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
4689 BITSET_CONTAINER_TYPE_CODE):
4690 if (run_container_is_full(run: (const run_container_t *)c1)) {
4691 result = run_container_create();
4692 *result_type = RUN_CONTAINER_TYPE_CODE;
4693 run_container_copy(src: (const run_container_t *)c1,
4694 dst: (run_container_t *)result);
4695 return result;
4696 }
4697 result = bitset_container_create();
4698 run_bitset_container_union(src_1: (const run_container_t *)c1,
4699 src_2: (const bitset_container_t *)c2,
4700 dst: (bitset_container_t *)result);
4701 *result_type = BITSET_CONTAINER_TYPE_CODE;
4702 return result;
4703 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4704 result = run_container_create();
4705 array_run_container_union(src_1: (const array_container_t *)c1,
4706 src_2: (const run_container_t *)c2,
4707 dst: (run_container_t *)result);
4708 result = convert_run_to_efficient_container_and_free(
4709 c: (run_container_t *)result, typecode_after: (uint8_t *)result_type);
4710 return result;
4711 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
4712 result = run_container_create();
4713 array_run_container_union(src_1: (const array_container_t *)c2,
4714 src_2: (const run_container_t *)c1,
4715 dst: (run_container_t *)result);
4716 result = convert_run_to_efficient_container_and_free(
4717 c: (run_container_t *)result, typecode_after: (uint8_t *)result_type);
4718 return result;
4719 default:
4720 assert(false);
4721 __builtin_unreachable();
4722 return NULL; // unreached
4723 }
4724}
4725
4726/**
4727 * Compute union between two containers, generate a new container (having type
4728 * result_type), requires a typecode. This allocates new memory, caller
4729 * is responsible for deallocation.
4730 *
4731 * This lazy version delays some operations such as the maintenance of the
4732 * cardinality. It requires repair later on the generated containers.
4733 */
4734static inline void *container_lazy_or(const void *c1, uint8_t type1,
4735 const void *c2, uint8_t type2,
4736 uint8_t *result_type) {
4737 c1 = container_unwrap_shared(candidate_shared_container: c1, type: &type1);
4738 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
4739 void *result = NULL;
4740 switch (CONTAINER_PAIR(type1, type2)) {
4741 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4742 BITSET_CONTAINER_TYPE_CODE):
4743 result = bitset_container_create();
4744 bitset_container_or_nocard(
4745 src_1: (const bitset_container_t *)c1, src_2: (const bitset_container_t *)c2,
4746 dst: (bitset_container_t *)result); // is lazy
4747 *result_type = BITSET_CONTAINER_TYPE_CODE;
4748 return result;
4749 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4750 ARRAY_CONTAINER_TYPE_CODE):
4751 *result_type = array_array_container_lazy_union(
4752 src_1: (const array_container_t *)c1,
4753 src_2: (const array_container_t *)c2, dst: &result)
4754 ? BITSET_CONTAINER_TYPE_CODE
4755 : ARRAY_CONTAINER_TYPE_CODE;
4756 return result;
4757 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4758 result = run_container_create();
4759 run_container_union(src_1: (const run_container_t *)c1,
4760 src_2: (const run_container_t *)c2,
4761 dst: (run_container_t *)result);
4762 *result_type = RUN_CONTAINER_TYPE_CODE;
4763 // we are being lazy
4764 result = convert_run_to_efficient_container(
4765 c: (run_container_t *)result, typecode_after: result_type);
4766 return result;
4767 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4768 ARRAY_CONTAINER_TYPE_CODE):
4769 result = bitset_container_create();
4770 array_bitset_container_lazy_union(
4771 src_1: (const array_container_t *)c2, src_2: (const bitset_container_t *)c1,
4772 dst: (bitset_container_t *)result); // is lazy
4773 *result_type = BITSET_CONTAINER_TYPE_CODE;
4774 return result;
4775 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4776 BITSET_CONTAINER_TYPE_CODE):
4777 result = bitset_container_create();
4778 array_bitset_container_lazy_union(
4779 src_1: (const array_container_t *)c1, src_2: (const bitset_container_t *)c2,
4780 dst: (bitset_container_t *)result); // is lazy
4781 *result_type = BITSET_CONTAINER_TYPE_CODE;
4782 return result;
4783 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4784 RUN_CONTAINER_TYPE_CODE):
4785 if (run_container_is_full(run: (const run_container_t *)c2)) {
4786 result = run_container_create();
4787 *result_type = RUN_CONTAINER_TYPE_CODE;
4788 run_container_copy(src: (const run_container_t *)c2,
4789 dst: (run_container_t *)result);
4790 return result;
4791 }
4792 result = bitset_container_create();
4793 run_bitset_container_lazy_union(
4794 src_1: (const run_container_t *)c2, src_2: (const bitset_container_t *)c1,
4795 dst: (bitset_container_t *)result); // is lazy
4796 *result_type = BITSET_CONTAINER_TYPE_CODE;
4797 return result;
4798 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
4799 BITSET_CONTAINER_TYPE_CODE):
4800 if (run_container_is_full(run: (const run_container_t *)c1)) {
4801 result = run_container_create();
4802 *result_type = RUN_CONTAINER_TYPE_CODE;
4803 run_container_copy(src: (const run_container_t *)c1,
4804 dst: (run_container_t *)result);
4805 return result;
4806 }
4807 result = bitset_container_create();
4808 run_bitset_container_lazy_union(
4809 src_1: (const run_container_t *)c1, src_2: (const bitset_container_t *)c2,
4810 dst: (bitset_container_t *)result); // is lazy
4811 *result_type = BITSET_CONTAINER_TYPE_CODE;
4812 return result;
4813 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4814 result = run_container_create();
4815 array_run_container_union(src_1: (const array_container_t *)c1,
4816 src_2: (const run_container_t *)c2,
4817 dst: (run_container_t *)result);
4818 *result_type = RUN_CONTAINER_TYPE_CODE;
4819 // next line skipped since we are lazy
4820 // result = convert_run_to_efficient_container(result, result_type);
4821 return result;
4822 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
4823 result = run_container_create();
4824 array_run_container_union(
4825 src_1: (const array_container_t *)c2, src_2: (const run_container_t *)c1,
4826 dst: (run_container_t *)result); // TODO make lazy
4827 *result_type = RUN_CONTAINER_TYPE_CODE;
4828 // next line skipped since we are lazy
4829 // result = convert_run_to_efficient_container(result, result_type);
4830 return result;
4831 default:
4832 assert(false);
4833 __builtin_unreachable();
4834 return NULL; // unreached
4835 }
4836}
4837
4838/**
4839 * Compute the union between two containers, with result in the first container.
4840 * If the returned pointer is identical to c1, then the container has been
4841 * modified.
4842 * If the returned pointer is different from c1, then a new container has been
4843 * created and the caller is responsible for freeing it.
4844 * The type of the first container may change. Returns the modified
4845 * (and possibly new) container
4846*/
4847static inline void *container_ior(void *c1, uint8_t type1, const void *c2,
4848 uint8_t type2, uint8_t *result_type) {
4849 c1 = get_writable_copy_if_shared(candidate_shared_container: c1, type: &type1);
4850 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
4851 void *result = NULL;
4852 switch (CONTAINER_PAIR(type1, type2)) {
4853 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4854 BITSET_CONTAINER_TYPE_CODE):
4855 bitset_container_or(src_1: (const bitset_container_t *)c1,
4856 src_2: (const bitset_container_t *)c2,
4857 dst: (bitset_container_t *)c1);
4858#ifdef OR_BITSET_CONVERSION_TO_FULL
4859 if (((bitset_container_t *)c1)->cardinality ==
4860 (1 << 16)) { // we convert
4861 result = run_container_create_range(start: 0, stop: (1 << 16));
4862 *result_type = RUN_CONTAINER_TYPE_CODE;
4863 return result;
4864 }
4865#endif
4866 *result_type = BITSET_CONTAINER_TYPE_CODE;
4867 return c1;
4868 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4869 ARRAY_CONTAINER_TYPE_CODE):
4870 *result_type = array_array_container_inplace_union(
4871 src_1: (array_container_t *)c1,
4872 src_2: (const array_container_t *)c2, dst: &result)
4873 ? BITSET_CONTAINER_TYPE_CODE
4874 : ARRAY_CONTAINER_TYPE_CODE;
4875 if((result == NULL)
4876 && (*result_type == ARRAY_CONTAINER_TYPE_CODE)) {
4877 return c1; // the computation was done in-place!
4878 }
4879 return result;
4880 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4881 run_container_union_inplace(src_1: (run_container_t *)c1,
4882 src_2: (const run_container_t *)c2);
4883 return convert_run_to_efficient_container(c: (run_container_t *)c1,
4884 typecode_after: result_type);
4885 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4886 ARRAY_CONTAINER_TYPE_CODE):
4887 array_bitset_container_union(src_1: (const array_container_t *)c2,
4888 src_2: (const bitset_container_t *)c1,
4889 dst: (bitset_container_t *)c1);
4890 *result_type = BITSET_CONTAINER_TYPE_CODE; // never array
4891 return c1;
4892 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4893 BITSET_CONTAINER_TYPE_CODE):
4894 // c1 is an array, so no in-place possible
4895 result = bitset_container_create();
4896 *result_type = BITSET_CONTAINER_TYPE_CODE;
4897 array_bitset_container_union(src_1: (const array_container_t *)c1,
4898 src_2: (const bitset_container_t *)c2,
4899 dst: (bitset_container_t *)result);
4900 return result;
4901 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4902 RUN_CONTAINER_TYPE_CODE):
4903 if (run_container_is_full(run: (const run_container_t *)c2)) {
4904 result = run_container_create();
4905 *result_type = RUN_CONTAINER_TYPE_CODE;
4906 run_container_copy(src: (const run_container_t *)c2,
4907 dst: (run_container_t *)result);
4908 return result;
4909 }
4910 run_bitset_container_union(src_1: (const run_container_t *)c2,
4911 src_2: (const bitset_container_t *)c1,
4912 dst: (bitset_container_t *)c1); // allowed
4913 *result_type = BITSET_CONTAINER_TYPE_CODE;
4914 return c1;
4915 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
4916 BITSET_CONTAINER_TYPE_CODE):
4917 if (run_container_is_full(run: (const run_container_t *)c1)) {
4918 *result_type = RUN_CONTAINER_TYPE_CODE;
4919
4920 return c1;
4921 }
4922 result = bitset_container_create();
4923 run_bitset_container_union(src_1: (const run_container_t *)c1,
4924 src_2: (const bitset_container_t *)c2,
4925 dst: (bitset_container_t *)result);
4926 *result_type = BITSET_CONTAINER_TYPE_CODE;
4927 return result;
4928 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
4929 result = run_container_create();
4930 array_run_container_union(src_1: (const array_container_t *)c1,
4931 src_2: (const run_container_t *)c2,
4932 dst: (run_container_t *)result);
4933 result = convert_run_to_efficient_container_and_free(
4934 c: (run_container_t *)result, typecode_after: result_type);
4935 return result;
4936 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
4937 array_run_container_inplace_union(src_1: (const array_container_t *)c2,
4938 src_2: (run_container_t *)c1);
4939 c1 = convert_run_to_efficient_container(c: (run_container_t *)c1,
4940 typecode_after: result_type);
4941 return c1;
4942 default:
4943 assert(false);
4944 __builtin_unreachable();
4945 return NULL;
4946 }
4947}
4948
4949/**
4950 * Compute the union between two containers, with result in the first container.
4951 * If the returned pointer is identical to c1, then the container has been
4952 * modified.
4953 * If the returned pointer is different from c1, then a new container has been
4954 * created and the caller is responsible for freeing it.
4955 * The type of the first container may change. Returns the modified
4956 * (and possibly new) container
4957 *
4958 * This lazy version delays some operations such as the maintenance of the
4959 * cardinality. It requires repair later on the generated containers.
4960*/
4961static inline void *container_lazy_ior(void *c1, uint8_t type1, const void *c2,
4962 uint8_t type2, uint8_t *result_type) {
4963 assert(type1 != SHARED_CONTAINER_TYPE_CODE);
4964 // c1 = get_writable_copy_if_shared(c1,&type1);
4965 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
4966 void *result = NULL;
4967 switch (CONTAINER_PAIR(type1, type2)) {
4968 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
4969 BITSET_CONTAINER_TYPE_CODE):
4970#ifdef LAZY_OR_BITSET_CONVERSION_TO_FULL
4971 // if we have two bitsets, we might as well compute the cardinality
4972 bitset_container_or(src_1: (const bitset_container_t *)c1,
4973 src_2: (const bitset_container_t *)c2,
4974 dst: (bitset_container_t *)c1);
4975 // it is possible that two bitsets can lead to a full container
4976 if (((bitset_container_t *)c1)->cardinality ==
4977 (1 << 16)) { // we convert
4978 result = run_container_create_range(start: 0, stop: (1 << 16));
4979 *result_type = RUN_CONTAINER_TYPE_CODE;
4980 return result;
4981 }
4982#else
4983 bitset_container_or_nocard((const bitset_container_t *)c1,
4984 (const bitset_container_t *)c2,
4985 (bitset_container_t *)c1);
4986
4987#endif
4988 *result_type = BITSET_CONTAINER_TYPE_CODE;
4989 return c1;
4990 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
4991 ARRAY_CONTAINER_TYPE_CODE):
4992 *result_type = array_array_container_lazy_inplace_union(
4993 src_1: (array_container_t *)c1,
4994 src_2: (const array_container_t *)c2, dst: &result)
4995 ? BITSET_CONTAINER_TYPE_CODE
4996 : ARRAY_CONTAINER_TYPE_CODE;
4997 if((result == NULL)
4998 && (*result_type == ARRAY_CONTAINER_TYPE_CODE)) {
4999 return c1; // the computation was done in-place!
5000 }
5001 return result;
5002 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
5003 run_container_union_inplace(src_1: (run_container_t *)c1,
5004 src_2: (const run_container_t *)c2);
5005 *result_type = RUN_CONTAINER_TYPE_CODE;
5006 return convert_run_to_efficient_container(c: (run_container_t *)c1,
5007 typecode_after: result_type);
5008 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5009 ARRAY_CONTAINER_TYPE_CODE):
5010 array_bitset_container_lazy_union(
5011 src_1: (const array_container_t *)c2, src_2: (const bitset_container_t *)c1,
5012 dst: (bitset_container_t *)c1); // is lazy
5013 *result_type = BITSET_CONTAINER_TYPE_CODE; // never array
5014 return c1;
5015 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
5016 BITSET_CONTAINER_TYPE_CODE):
5017 // c1 is an array, so no in-place possible
5018 result = bitset_container_create();
5019 *result_type = BITSET_CONTAINER_TYPE_CODE;
5020 array_bitset_container_lazy_union(
5021 src_1: (const array_container_t *)c1, src_2: (const bitset_container_t *)c2,
5022 dst: (bitset_container_t *)result); // is lazy
5023 return result;
5024 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5025 RUN_CONTAINER_TYPE_CODE):
5026 if (run_container_is_full(run: (const run_container_t *)c2)) {
5027 result = run_container_create();
5028 *result_type = RUN_CONTAINER_TYPE_CODE;
5029 run_container_copy(src: (const run_container_t *)c2,
5030 dst: (run_container_t *)result);
5031 return result;
5032 }
5033 run_bitset_container_lazy_union(
5034 src_1: (const run_container_t *)c2, src_2: (const bitset_container_t *)c1,
5035 dst: (bitset_container_t *)c1); // allowed // lazy
5036 *result_type = BITSET_CONTAINER_TYPE_CODE;
5037 return c1;
5038 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
5039 BITSET_CONTAINER_TYPE_CODE):
5040 if (run_container_is_full(run: (const run_container_t *)c1)) {
5041 *result_type = RUN_CONTAINER_TYPE_CODE;
5042 return c1;
5043 }
5044 result = bitset_container_create();
5045 run_bitset_container_lazy_union(
5046 src_1: (const run_container_t *)c1, src_2: (const bitset_container_t *)c2,
5047 dst: (bitset_container_t *)result); // lazy
5048 *result_type = BITSET_CONTAINER_TYPE_CODE;
5049 return result;
5050 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
5051 result = run_container_create();
5052 array_run_container_union(src_1: (const array_container_t *)c1,
5053 src_2: (const run_container_t *)c2,
5054 dst: (run_container_t *)result);
5055 *result_type = RUN_CONTAINER_TYPE_CODE;
5056 // next line skipped since we are lazy
5057 // result = convert_run_to_efficient_container_and_free(result,
5058 // result_type);
5059 return result;
5060 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
5061 array_run_container_inplace_union(src_1: (const array_container_t *)c2,
5062 src_2: (run_container_t *)c1);
5063 *result_type = RUN_CONTAINER_TYPE_CODE;
5064 // next line skipped since we are lazy
5065 // result = convert_run_to_efficient_container_and_free(result,
5066 // result_type);
5067 return c1;
5068 default:
5069 assert(false);
5070 __builtin_unreachable();
5071 return NULL;
5072 }
5073}
5074
5075/**
5076 * Compute symmetric difference (xor) between two containers, generate a new
5077 * container (having type result_type), requires a typecode. This allocates new
5078 * memory, caller is responsible for deallocation.
5079 */
5080static inline void *container_xor(const void *c1, uint8_t type1, const void *c2,
5081 uint8_t type2, uint8_t *result_type) {
5082 c1 = container_unwrap_shared(candidate_shared_container: c1, type: &type1);
5083 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
5084 void *result = NULL;
5085 switch (CONTAINER_PAIR(type1, type2)) {
5086 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5087 BITSET_CONTAINER_TYPE_CODE):
5088 *result_type = bitset_bitset_container_xor(
5089 src_1: (const bitset_container_t *)c1,
5090 src_2: (const bitset_container_t *)c2, dst: &result)
5091 ? BITSET_CONTAINER_TYPE_CODE
5092 : ARRAY_CONTAINER_TYPE_CODE;
5093 return result;
5094 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
5095 ARRAY_CONTAINER_TYPE_CODE):
5096 *result_type = array_array_container_xor(
5097 src_1: (const array_container_t *)c1,
5098 src_2: (const array_container_t *)c2, dst: &result)
5099 ? BITSET_CONTAINER_TYPE_CODE
5100 : ARRAY_CONTAINER_TYPE_CODE;
5101 return result;
5102 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
5103 *result_type =
5104 run_run_container_xor(src_1: (const run_container_t *)c1,
5105 src_2: (const run_container_t *)c2, dst: &result);
5106 return result;
5107
5108 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5109 ARRAY_CONTAINER_TYPE_CODE):
5110 *result_type = array_bitset_container_xor(
5111 src_1: (const array_container_t *)c2,
5112 src_2: (const bitset_container_t *)c1, dst: &result)
5113 ? BITSET_CONTAINER_TYPE_CODE
5114 : ARRAY_CONTAINER_TYPE_CODE;
5115 return result;
5116 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
5117 BITSET_CONTAINER_TYPE_CODE):
5118 *result_type = array_bitset_container_xor(
5119 src_1: (const array_container_t *)c1,
5120 src_2: (const bitset_container_t *)c2, dst: &result)
5121 ? BITSET_CONTAINER_TYPE_CODE
5122 : ARRAY_CONTAINER_TYPE_CODE;
5123 return result;
5124 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5125 RUN_CONTAINER_TYPE_CODE):
5126 *result_type = run_bitset_container_xor(
5127 src_1: (const run_container_t *)c2,
5128 src_2: (const bitset_container_t *)c1, dst: &result)
5129 ? BITSET_CONTAINER_TYPE_CODE
5130 : ARRAY_CONTAINER_TYPE_CODE;
5131 return result;
5132
5133 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
5134 BITSET_CONTAINER_TYPE_CODE):
5135
5136 *result_type = run_bitset_container_xor(
5137 src_1: (const run_container_t *)c1,
5138 src_2: (const bitset_container_t *)c2, dst: &result)
5139 ? BITSET_CONTAINER_TYPE_CODE
5140 : ARRAY_CONTAINER_TYPE_CODE;
5141 return result;
5142
5143 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
5144 *result_type =
5145 array_run_container_xor(src_1: (const array_container_t *)c1,
5146 src_2: (const run_container_t *)c2, dst: &result);
5147 return result;
5148
5149 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
5150 *result_type =
5151 array_run_container_xor(src_1: (const array_container_t *)c2,
5152 src_2: (const run_container_t *)c1, dst: &result);
5153 return result;
5154
5155 default:
5156 assert(false);
5157 __builtin_unreachable();
5158 return NULL; // unreached
5159 }
5160}
5161
5162/**
5163 * Compute xor between two containers, generate a new container (having type
5164 * result_type), requires a typecode. This allocates new memory, caller
5165 * is responsible for deallocation.
5166 *
5167 * This lazy version delays some operations such as the maintenance of the
5168 * cardinality. It requires repair later on the generated containers.
5169 */
5170static inline void *container_lazy_xor(const void *c1, uint8_t type1,
5171 const void *c2, uint8_t type2,
5172 uint8_t *result_type) {
5173 c1 = container_unwrap_shared(candidate_shared_container: c1, type: &type1);
5174 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
5175 void *result = NULL;
5176 switch (CONTAINER_PAIR(type1, type2)) {
5177 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5178 BITSET_CONTAINER_TYPE_CODE):
5179 result = bitset_container_create();
5180 bitset_container_xor_nocard(
5181 src_1: (const bitset_container_t *)c1, src_2: (const bitset_container_t *)c2,
5182 dst: (bitset_container_t *)result); // is lazy
5183 *result_type = BITSET_CONTAINER_TYPE_CODE;
5184 return result;
5185 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
5186 ARRAY_CONTAINER_TYPE_CODE):
5187 *result_type = array_array_container_lazy_xor(
5188 src_1: (const array_container_t *)c1,
5189 src_2: (const array_container_t *)c2, dst: &result)
5190 ? BITSET_CONTAINER_TYPE_CODE
5191 : ARRAY_CONTAINER_TYPE_CODE;
5192 return result;
5193 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
5194 // nothing special done yet.
5195 *result_type =
5196 run_run_container_xor(src_1: (const run_container_t *)c1,
5197 src_2: (const run_container_t *)c2, dst: &result);
5198 return result;
5199 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5200 ARRAY_CONTAINER_TYPE_CODE):
5201 result = bitset_container_create();
5202 *result_type = BITSET_CONTAINER_TYPE_CODE;
5203 array_bitset_container_lazy_xor(src_1: (const array_container_t *)c2,
5204 src_2: (const bitset_container_t *)c1,
5205 dst: (bitset_container_t *)result);
5206 return result;
5207 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
5208 BITSET_CONTAINER_TYPE_CODE):
5209 result = bitset_container_create();
5210 *result_type = BITSET_CONTAINER_TYPE_CODE;
5211 array_bitset_container_lazy_xor(src_1: (const array_container_t *)c1,
5212 src_2: (const bitset_container_t *)c2,
5213 dst: (bitset_container_t *)result);
5214 return result;
5215 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5216 RUN_CONTAINER_TYPE_CODE):
5217 result = bitset_container_create();
5218 run_bitset_container_lazy_xor(src_1: (const run_container_t *)c2,
5219 src_2: (const bitset_container_t *)c1,
5220 dst: (bitset_container_t *)result);
5221 *result_type = BITSET_CONTAINER_TYPE_CODE;
5222 return result;
5223 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
5224 BITSET_CONTAINER_TYPE_CODE):
5225 result = bitset_container_create();
5226 run_bitset_container_lazy_xor(src_1: (const run_container_t *)c1,
5227 src_2: (const bitset_container_t *)c2,
5228 dst: (bitset_container_t *)result);
5229 *result_type = BITSET_CONTAINER_TYPE_CODE;
5230 return result;
5231
5232 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
5233 result = run_container_create();
5234 array_run_container_lazy_xor(src_1: (const array_container_t *)c1,
5235 src_2: (const run_container_t *)c2,
5236 dst: (run_container_t *)result);
5237 *result_type = RUN_CONTAINER_TYPE_CODE;
5238 // next line skipped since we are lazy
5239 // result = convert_run_to_efficient_container(result, result_type);
5240 return result;
5241 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
5242 result = run_container_create();
5243 array_run_container_lazy_xor(src_1: (const array_container_t *)c2,
5244 src_2: (const run_container_t *)c1,
5245 dst: (run_container_t *)result);
5246 *result_type = RUN_CONTAINER_TYPE_CODE;
5247 // next line skipped since we are lazy
5248 // result = convert_run_to_efficient_container(result, result_type);
5249 return result;
5250 default:
5251 assert(false);
5252 __builtin_unreachable();
5253 return NULL; // unreached
5254 }
5255}
5256
5257/**
5258 * Compute the xor between two containers, with result in the first container.
5259 * If the returned pointer is identical to c1, then the container has been
5260 * modified.
5261 * If the returned pointer is different from c1, then a new container has been
5262 * created and the caller is responsible for freeing it.
5263 * The type of the first container may change. Returns the modified
5264 * (and possibly new) container
5265*/
5266static inline void *container_ixor(void *c1, uint8_t type1, const void *c2,
5267 uint8_t type2, uint8_t *result_type) {
5268 c1 = get_writable_copy_if_shared(candidate_shared_container: c1, type: &type1);
5269 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
5270 void *result = NULL;
5271 switch (CONTAINER_PAIR(type1, type2)) {
5272 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5273 BITSET_CONTAINER_TYPE_CODE):
5274 *result_type = bitset_bitset_container_ixor(
5275 src_1: (bitset_container_t *)c1,
5276 src_2: (const bitset_container_t *)c2, dst: &result)
5277 ? BITSET_CONTAINER_TYPE_CODE
5278 : ARRAY_CONTAINER_TYPE_CODE;
5279 return result;
5280 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
5281 ARRAY_CONTAINER_TYPE_CODE):
5282 *result_type = array_array_container_ixor(
5283 src_1: (array_container_t *)c1,
5284 src_2: (const array_container_t *)c2, dst: &result)
5285 ? BITSET_CONTAINER_TYPE_CODE
5286 : ARRAY_CONTAINER_TYPE_CODE;
5287 return result;
5288
5289 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
5290 *result_type = run_run_container_ixor(
5291 src_1: (run_container_t *)c1, src_2: (const run_container_t *)c2, dst: &result);
5292 return result;
5293
5294 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5295 ARRAY_CONTAINER_TYPE_CODE):
5296 *result_type = bitset_array_container_ixor(
5297 src_1: (bitset_container_t *)c1,
5298 src_2: (const array_container_t *)c2, dst: &result)
5299 ? BITSET_CONTAINER_TYPE_CODE
5300 : ARRAY_CONTAINER_TYPE_CODE;
5301 return result;
5302 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
5303 BITSET_CONTAINER_TYPE_CODE):
5304 *result_type = array_bitset_container_ixor(
5305 src_1: (array_container_t *)c1,
5306 src_2: (const bitset_container_t *)c2, dst: &result)
5307 ? BITSET_CONTAINER_TYPE_CODE
5308 : ARRAY_CONTAINER_TYPE_CODE;
5309
5310 return result;
5311
5312 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5313 RUN_CONTAINER_TYPE_CODE):
5314 *result_type =
5315 bitset_run_container_ixor(src_1: (bitset_container_t *)c1,
5316 src_2: (const run_container_t *)c2, dst: &result)
5317 ? BITSET_CONTAINER_TYPE_CODE
5318 : ARRAY_CONTAINER_TYPE_CODE;
5319
5320 return result;
5321
5322 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
5323 BITSET_CONTAINER_TYPE_CODE):
5324 *result_type = run_bitset_container_ixor(
5325 src_1: (run_container_t *)c1,
5326 src_2: (const bitset_container_t *)c2, dst: &result)
5327 ? BITSET_CONTAINER_TYPE_CODE
5328 : ARRAY_CONTAINER_TYPE_CODE;
5329
5330 return result;
5331
5332 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
5333 *result_type = array_run_container_ixor(
5334 src_1: (array_container_t *)c1, src_2: (const run_container_t *)c2, dst: &result);
5335 return result;
5336 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
5337 *result_type = run_array_container_ixor(
5338 src_1: (run_container_t *)c1, src_2: (const array_container_t *)c2, dst: &result);
5339 return result;
5340 default:
5341 assert(false);
5342 __builtin_unreachable();
5343 return NULL;
5344 }
5345}
5346
5347/**
5348 * Compute the xor between two containers, with result in the first container.
5349 * If the returned pointer is identical to c1, then the container has been
5350 * modified.
5351 * If the returned pointer is different from c1, then a new container has been
5352 * created and the caller is responsible for freeing it.
5353 * The type of the first container may change. Returns the modified
5354 * (and possibly new) container
5355 *
5356 * This lazy version delays some operations such as the maintenance of the
5357 * cardinality. It requires repair later on the generated containers.
5358*/
5359static inline void *container_lazy_ixor(void *c1, uint8_t type1, const void *c2,
5360 uint8_t type2, uint8_t *result_type) {
5361 assert(type1 != SHARED_CONTAINER_TYPE_CODE);
5362 // c1 = get_writable_copy_if_shared(c1,&type1);
5363 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
5364 switch (CONTAINER_PAIR(type1, type2)) {
5365 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5366 BITSET_CONTAINER_TYPE_CODE):
5367 bitset_container_xor_nocard(src_1: (bitset_container_t *)c1,
5368 src_2: (const bitset_container_t *)c2,
5369 dst: (bitset_container_t *)c1); // is lazy
5370 *result_type = BITSET_CONTAINER_TYPE_CODE;
5371 return c1;
5372 // TODO: other cases being lazy, esp. when we know inplace not likely
5373 // could see the corresponding code for union
5374 default:
5375 // we may have a dirty bitset (without a precomputed cardinality) and
5376 // calling container_ixor on it might be unsafe.
5377 if( (type1 == BITSET_CONTAINER_TYPE_CODE)
5378 && (((const bitset_container_t *)c1)->cardinality == BITSET_UNKNOWN_CARDINALITY)) {
5379 ((bitset_container_t *)c1)->cardinality = bitset_container_compute_cardinality(bitset: (bitset_container_t *)c1);
5380 }
5381 return container_ixor(c1, type1, c2, type2, result_type);
5382 }
5383}
5384
5385/**
5386 * Compute difference (andnot) between two containers, generate a new
5387 * container (having type result_type), requires a typecode. This allocates new
5388 * memory, caller is responsible for deallocation.
5389 */
5390static inline void *container_andnot(const void *c1, uint8_t type1,
5391 const void *c2, uint8_t type2,
5392 uint8_t *result_type) {
5393 c1 = container_unwrap_shared(candidate_shared_container: c1, type: &type1);
5394 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
5395 void *result = NULL;
5396 switch (CONTAINER_PAIR(type1, type2)) {
5397 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5398 BITSET_CONTAINER_TYPE_CODE):
5399 *result_type = bitset_bitset_container_andnot(
5400 src_1: (const bitset_container_t *)c1,
5401 src_2: (const bitset_container_t *)c2, dst: &result)
5402 ? BITSET_CONTAINER_TYPE_CODE
5403 : ARRAY_CONTAINER_TYPE_CODE;
5404 return result;
5405 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
5406 ARRAY_CONTAINER_TYPE_CODE):
5407 result = array_container_create();
5408 array_array_container_andnot(src_1: (const array_container_t *)c1,
5409 src_2: (const array_container_t *)c2,
5410 dst: (array_container_t *)result);
5411 *result_type = ARRAY_CONTAINER_TYPE_CODE;
5412 return result;
5413 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
5414 if (run_container_is_full(run: (const run_container_t *)c2)) {
5415 result = array_container_create();
5416 *result_type = ARRAY_CONTAINER_TYPE_CODE;
5417 return result;
5418 }
5419 *result_type =
5420 run_run_container_andnot(src_1: (const run_container_t *)c1,
5421 src_2: (const run_container_t *)c2, dst: &result);
5422 return result;
5423
5424 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5425 ARRAY_CONTAINER_TYPE_CODE):
5426 *result_type = bitset_array_container_andnot(
5427 src_1: (const bitset_container_t *)c1,
5428 src_2: (const array_container_t *)c2, dst: &result)
5429 ? BITSET_CONTAINER_TYPE_CODE
5430 : ARRAY_CONTAINER_TYPE_CODE;
5431 return result;
5432 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
5433 BITSET_CONTAINER_TYPE_CODE):
5434 result = array_container_create();
5435 array_bitset_container_andnot(src_1: (const array_container_t *)c1,
5436 src_2: (const bitset_container_t *)c2,
5437 dst: (array_container_t *)result);
5438 *result_type = ARRAY_CONTAINER_TYPE_CODE;
5439 return result;
5440 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5441 RUN_CONTAINER_TYPE_CODE):
5442 if (run_container_is_full(run: (const run_container_t *)c2)) {
5443 result = array_container_create();
5444 *result_type = ARRAY_CONTAINER_TYPE_CODE;
5445 return result;
5446 }
5447 *result_type = bitset_run_container_andnot(
5448 src_1: (const bitset_container_t *)c1,
5449 src_2: (const run_container_t *)c2, dst: &result)
5450 ? BITSET_CONTAINER_TYPE_CODE
5451 : ARRAY_CONTAINER_TYPE_CODE;
5452 return result;
5453 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
5454 BITSET_CONTAINER_TYPE_CODE):
5455
5456 *result_type = run_bitset_container_andnot(
5457 src_1: (const run_container_t *)c1,
5458 src_2: (const bitset_container_t *)c2, dst: &result)
5459 ? BITSET_CONTAINER_TYPE_CODE
5460 : ARRAY_CONTAINER_TYPE_CODE;
5461 return result;
5462
5463 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
5464 if (run_container_is_full(run: (const run_container_t *)c2)) {
5465 result = array_container_create();
5466 *result_type = ARRAY_CONTAINER_TYPE_CODE;
5467 return result;
5468 }
5469 result = array_container_create();
5470 array_run_container_andnot(src_1: (const array_container_t *)c1,
5471 src_2: (const run_container_t *)c2,
5472 dst: (array_container_t *)result);
5473 *result_type = ARRAY_CONTAINER_TYPE_CODE;
5474 return result;
5475
5476 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
5477 *result_type = run_array_container_andnot(
5478 src_1: (const run_container_t *)c1, src_2: (const array_container_t *)c2,
5479 dst: &result);
5480 return result;
5481
5482 default:
5483 assert(false);
5484 __builtin_unreachable();
5485 return NULL; // unreached
5486 }
5487}
5488
5489/**
5490 * Compute the andnot between two containers, with result in the first
5491 * container.
5492 * If the returned pointer is identical to c1, then the container has been
5493 * modified.
5494 * If the returned pointer is different from c1, then a new container has been
5495 * created and the caller is responsible for freeing it.
5496 * The type of the first container may change. Returns the modified
5497 * (and possibly new) container
5498*/
5499static inline void *container_iandnot(void *c1, uint8_t type1, const void *c2,
5500 uint8_t type2, uint8_t *result_type) {
5501 c1 = get_writable_copy_if_shared(candidate_shared_container: c1, type: &type1);
5502 c2 = container_unwrap_shared(candidate_shared_container: c2, type: &type2);
5503 void *result = NULL;
5504 switch (CONTAINER_PAIR(type1, type2)) {
5505 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5506 BITSET_CONTAINER_TYPE_CODE):
5507 *result_type = bitset_bitset_container_iandnot(
5508 src_1: (bitset_container_t *)c1,
5509 src_2: (const bitset_container_t *)c2, dst: &result)
5510 ? BITSET_CONTAINER_TYPE_CODE
5511 : ARRAY_CONTAINER_TYPE_CODE;
5512 return result;
5513 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
5514 ARRAY_CONTAINER_TYPE_CODE):
5515 array_array_container_iandnot(src_1: (array_container_t *)c1,
5516 src_2: (const array_container_t *)c2);
5517 *result_type = ARRAY_CONTAINER_TYPE_CODE;
5518 return c1;
5519
5520 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
5521 *result_type = run_run_container_iandnot(
5522 src_1: (run_container_t *)c1, src_2: (const run_container_t *)c2, dst: &result);
5523 return result;
5524
5525 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5526 ARRAY_CONTAINER_TYPE_CODE):
5527 *result_type = bitset_array_container_iandnot(
5528 src_1: (bitset_container_t *)c1,
5529 src_2: (const array_container_t *)c2, dst: &result)
5530 ? BITSET_CONTAINER_TYPE_CODE
5531 : ARRAY_CONTAINER_TYPE_CODE;
5532 return result;
5533 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
5534 BITSET_CONTAINER_TYPE_CODE):
5535 *result_type = ARRAY_CONTAINER_TYPE_CODE;
5536
5537 array_bitset_container_iandnot(src_1: (array_container_t *)c1,
5538 src_2: (const bitset_container_t *)c2);
5539 return c1;
5540
5541 case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
5542 RUN_CONTAINER_TYPE_CODE):
5543 *result_type = bitset_run_container_iandnot(
5544 src_1: (bitset_container_t *)c1,
5545 src_2: (const run_container_t *)c2, dst: &result)
5546 ? BITSET_CONTAINER_TYPE_CODE
5547 : ARRAY_CONTAINER_TYPE_CODE;
5548
5549 return result;
5550
5551 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
5552 BITSET_CONTAINER_TYPE_CODE):
5553 *result_type = run_bitset_container_iandnot(
5554 src_1: (run_container_t *)c1,
5555 src_2: (const bitset_container_t *)c2, dst: &result)
5556 ? BITSET_CONTAINER_TYPE_CODE
5557 : ARRAY_CONTAINER_TYPE_CODE;
5558
5559 return result;
5560
5561 case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
5562 *result_type = ARRAY_CONTAINER_TYPE_CODE;
5563 array_run_container_iandnot(src_1: (array_container_t *)c1,
5564 src_2: (const run_container_t *)c2);
5565 return c1;
5566 case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
5567 *result_type = run_array_container_iandnot(
5568 src_1: (run_container_t *)c1, src_2: (const array_container_t *)c2, dst: &result);
5569 return result;
5570 default:
5571 assert(false);
5572 __builtin_unreachable();
5573 return NULL;
5574 }
5575}
5576
5577/**
5578 * Visit all values x of the container once, passing (base+x,ptr)
5579 * to iterator. You need to specify a container and its type.
5580 * Returns true if the iteration should continue.
5581 */
5582static inline bool container_iterate(const void *container, uint8_t typecode,
5583 uint32_t base, roaring_iterator iterator,
5584 void *ptr) {
5585 container = container_unwrap_shared(candidate_shared_container: container, type: &typecode);
5586 switch (typecode) {
5587 case BITSET_CONTAINER_TYPE_CODE:
5588 return bitset_container_iterate(
5589 cont: (const bitset_container_t *)container, base, iterator, ptr);
5590 case ARRAY_CONTAINER_TYPE_CODE:
5591 return array_container_iterate(cont: (const array_container_t *)container,
5592 base, iterator, ptr);
5593 case RUN_CONTAINER_TYPE_CODE:
5594 return run_container_iterate(cont: (const run_container_t *)container,
5595 base, iterator, ptr);
5596 case SHARED_CONTAINER_TYPE_CODE:
5597 default:
5598 assert(false);
5599 __builtin_unreachable();
5600 return false;
5601 }
5602}
5603
5604static inline bool container_iterate64(const void *container, uint8_t typecode,
5605 uint32_t base,
5606 roaring_iterator64 iterator,
5607 uint64_t high_bits, void *ptr) {
5608 container = container_unwrap_shared(candidate_shared_container: container, type: &typecode);
5609 switch (typecode) {
5610 case BITSET_CONTAINER_TYPE_CODE:
5611 return bitset_container_iterate64(
5612 cont: (const bitset_container_t *)container, base, iterator,
5613 high_bits, ptr);
5614 case ARRAY_CONTAINER_TYPE_CODE:
5615 return array_container_iterate64(
5616 cont: (const array_container_t *)container, base, iterator, high_bits,
5617 ptr);
5618 case RUN_CONTAINER_TYPE_CODE:
5619 return run_container_iterate64(cont: (const run_container_t *)container,
5620 base, iterator, high_bits, ptr);
5621 case SHARED_CONTAINER_TYPE_CODE:
5622 default:
5623 assert(false);
5624 __builtin_unreachable();
5625 return false;
5626 }
5627}
5628
5629static inline void *container_not(const void *c, uint8_t typ,
5630 uint8_t *result_type) {
5631 c = container_unwrap_shared(candidate_shared_container: c, type: &typ);
5632 void *result = NULL;
5633 switch (typ) {
5634 case BITSET_CONTAINER_TYPE_CODE:
5635 *result_type = bitset_container_negation(
5636 src: (const bitset_container_t *)c, dst: &result)
5637 ? BITSET_CONTAINER_TYPE_CODE
5638 : ARRAY_CONTAINER_TYPE_CODE;
5639 return result;
5640 case ARRAY_CONTAINER_TYPE_CODE:
5641 result = bitset_container_create();
5642 *result_type = BITSET_CONTAINER_TYPE_CODE;
5643 array_container_negation(src: (const array_container_t *)c,
5644 dst: (bitset_container_t *)result);
5645 return result;
5646 case RUN_CONTAINER_TYPE_CODE:
5647 *result_type =
5648 run_container_negation(src: (const run_container_t *)c, dst: &result);
5649 return result;
5650
5651 case SHARED_CONTAINER_TYPE_CODE:
5652 default:
5653 assert(false);
5654 __builtin_unreachable();
5655 return NULL;
5656 }
5657}
5658
5659static inline void *container_not_range(const void *c, uint8_t typ,
5660 uint32_t range_start,
5661 uint32_t range_end,
5662 uint8_t *result_type) {
5663 c = container_unwrap_shared(candidate_shared_container: c, type: &typ);
5664 void *result = NULL;
5665 switch (typ) {
5666 case BITSET_CONTAINER_TYPE_CODE:
5667 *result_type =
5668 bitset_container_negation_range(src: (const bitset_container_t *)c,
5669 range_start, range_end, dst: &result)
5670 ? BITSET_CONTAINER_TYPE_CODE
5671 : ARRAY_CONTAINER_TYPE_CODE;
5672 return result;
5673 case ARRAY_CONTAINER_TYPE_CODE:
5674 *result_type =
5675 array_container_negation_range(src: (const array_container_t *)c,
5676 range_start, range_end, dst: &result)
5677 ? BITSET_CONTAINER_TYPE_CODE
5678 : ARRAY_CONTAINER_TYPE_CODE;
5679 return result;
5680 case RUN_CONTAINER_TYPE_CODE:
5681 *result_type = run_container_negation_range(
5682 src: (const run_container_t *)c, range_start, range_end, dst: &result);
5683 return result;
5684
5685 case SHARED_CONTAINER_TYPE_CODE:
5686 default:
5687 assert(false);
5688 __builtin_unreachable();
5689 return NULL;
5690 }
5691}
5692
5693static inline void *container_inot(void *c, uint8_t typ, uint8_t *result_type) {
5694 c = get_writable_copy_if_shared(candidate_shared_container: c, type: &typ);
5695 void *result = NULL;
5696 switch (typ) {
5697 case BITSET_CONTAINER_TYPE_CODE:
5698 *result_type = bitset_container_negation_inplace(
5699 src: (bitset_container_t *)c, dst: &result)
5700 ? BITSET_CONTAINER_TYPE_CODE
5701 : ARRAY_CONTAINER_TYPE_CODE;
5702 return result;
5703 case ARRAY_CONTAINER_TYPE_CODE:
5704 // will never be inplace
5705 result = bitset_container_create();
5706 *result_type = BITSET_CONTAINER_TYPE_CODE;
5707 array_container_negation(src: (array_container_t *)c,
5708 dst: (bitset_container_t *)result);
5709 array_container_free(array: (array_container_t *)c);
5710 return result;
5711 case RUN_CONTAINER_TYPE_CODE:
5712 *result_type =
5713 run_container_negation_inplace(src: (run_container_t *)c, dst: &result);
5714 return result;
5715
5716 case SHARED_CONTAINER_TYPE_CODE:
5717 default:
5718 assert(false);
5719 __builtin_unreachable();
5720 return NULL;
5721 }
5722}
5723
5724static inline void *container_inot_range(void *c, uint8_t typ,
5725 uint32_t range_start,
5726 uint32_t range_end,
5727 uint8_t *result_type) {
5728 c = get_writable_copy_if_shared(candidate_shared_container: c, type: &typ);
5729 void *result = NULL;
5730 switch (typ) {
5731 case BITSET_CONTAINER_TYPE_CODE:
5732 *result_type =
5733 bitset_container_negation_range_inplace(
5734 src: (bitset_container_t *)c, range_start, range_end, dst: &result)
5735 ? BITSET_CONTAINER_TYPE_CODE
5736 : ARRAY_CONTAINER_TYPE_CODE;
5737 return result;
5738 case ARRAY_CONTAINER_TYPE_CODE:
5739 *result_type =
5740 array_container_negation_range_inplace(
5741 src: (array_container_t *)c, range_start, range_end, dst: &result)
5742 ? BITSET_CONTAINER_TYPE_CODE
5743 : ARRAY_CONTAINER_TYPE_CODE;
5744 return result;
5745 case RUN_CONTAINER_TYPE_CODE:
5746 *result_type = run_container_negation_range_inplace(
5747 src: (run_container_t *)c, range_start, range_end, dst: &result);
5748 return result;
5749
5750 case SHARED_CONTAINER_TYPE_CODE:
5751 default:
5752 assert(false);
5753 __builtin_unreachable();
5754 return NULL;
5755 }
5756}
5757
5758/**
5759 * If the element of given rank is in this container, supposing that
5760 * the first
5761 * element has rank start_rank, then the function returns true and
5762 * sets element
5763 * accordingly.
5764 * Otherwise, it returns false and update start_rank.
5765 */
5766static inline bool container_select(const void *container, uint8_t typecode,
5767 uint32_t *start_rank, uint32_t rank,
5768 uint32_t *element) {
5769 container = container_unwrap_shared(candidate_shared_container: container, type: &typecode);
5770 switch (typecode) {
5771 case BITSET_CONTAINER_TYPE_CODE:
5772 return bitset_container_select(container: (const bitset_container_t *)container,
5773 start_rank, rank, element);
5774 case ARRAY_CONTAINER_TYPE_CODE:
5775 return array_container_select(container: (const array_container_t *)container,
5776 start_rank, rank, element);
5777 case RUN_CONTAINER_TYPE_CODE:
5778 return run_container_select(container: (const run_container_t *)container,
5779 start_rank, rank, element);
5780 case SHARED_CONTAINER_TYPE_CODE:
5781 default:
5782 assert(false);
5783 __builtin_unreachable();
5784 return false;
5785 }
5786}
5787
5788static inline uint16_t container_maximum(const void *container,
5789 uint8_t typecode) {
5790 container = container_unwrap_shared(candidate_shared_container: container, type: &typecode);
5791 switch (typecode) {
5792 case BITSET_CONTAINER_TYPE_CODE:
5793 return bitset_container_maximum(container: (const bitset_container_t *)container);
5794 case ARRAY_CONTAINER_TYPE_CODE:
5795 return array_container_maximum(arr: (const array_container_t *)container);
5796 case RUN_CONTAINER_TYPE_CODE:
5797 return run_container_maximum(run: (const run_container_t *)container);
5798 case SHARED_CONTAINER_TYPE_CODE:
5799 default:
5800 assert(false);
5801 __builtin_unreachable();
5802 return false;
5803 }
5804}
5805
5806static inline uint16_t container_minimum(const void *container,
5807 uint8_t typecode) {
5808 container = container_unwrap_shared(candidate_shared_container: container, type: &typecode);
5809 switch (typecode) {
5810 case BITSET_CONTAINER_TYPE_CODE:
5811 return bitset_container_minimum(container: (const bitset_container_t *)container);
5812 case ARRAY_CONTAINER_TYPE_CODE:
5813 return array_container_minimum(arr: (const array_container_t *)container);
5814 case RUN_CONTAINER_TYPE_CODE:
5815 return run_container_minimum(run: (const run_container_t *)container);
5816 case SHARED_CONTAINER_TYPE_CODE:
5817 default:
5818 assert(false);
5819 __builtin_unreachable();
5820 return false;
5821 }
5822}
5823
5824// number of values smaller or equal to x
5825static inline int container_rank(const void *container, uint8_t typecode,
5826 uint16_t x) {
5827 container = container_unwrap_shared(candidate_shared_container: container, type: &typecode);
5828 switch (typecode) {
5829 case BITSET_CONTAINER_TYPE_CODE:
5830 return bitset_container_rank(container: (const bitset_container_t *)container, x);
5831 case ARRAY_CONTAINER_TYPE_CODE:
5832 return array_container_rank(arr: (const array_container_t *)container, x);
5833 case RUN_CONTAINER_TYPE_CODE:
5834 return run_container_rank(arr: (const run_container_t *)container, x);
5835 case SHARED_CONTAINER_TYPE_CODE:
5836 default:
5837 assert(false);
5838 __builtin_unreachable();
5839 return false;
5840 }
5841}
5842
5843/**
5844 * Add all values in range [min, max] to a given container.
5845 *
5846 * If the returned pointer is different from $container, then a new container
5847 * has been created and the caller is responsible for freeing it.
5848 * The type of the first container may change. Returns the modified
5849 * (and possibly new) container.
5850 */
5851static inline void *container_add_range(void *container, uint8_t type,
5852 uint32_t min, uint32_t max,
5853 uint8_t *result_type) {
5854 // NB: when selecting new container type, we perform only inexpensive checks
5855 switch (type) {
5856 case BITSET_CONTAINER_TYPE_CODE: {
5857 bitset_container_t *bitset = (bitset_container_t *) container;
5858
5859 int32_t union_cardinality = 0;
5860 union_cardinality += bitset->cardinality;
5861 union_cardinality += max - min + 1;
5862 union_cardinality -= bitset_lenrange_cardinality(bitmap: bitset->array, start: min, lenminusone: max-min);
5863
5864 if (union_cardinality == INT32_C(0x10000)) {
5865 *result_type = RUN_CONTAINER_TYPE_CODE;
5866 return run_container_create_range(start: 0, INT32_C(0x10000));
5867 } else {
5868 *result_type = BITSET_CONTAINER_TYPE_CODE;
5869 bitset_set_lenrange(bitmap: bitset->array, start: min, lenminusone: max - min);
5870 bitset->cardinality = union_cardinality;
5871 return bitset;
5872 }
5873 }
5874 case ARRAY_CONTAINER_TYPE_CODE: {
5875 array_container_t *array = (array_container_t *) container;
5876
5877 int32_t nvals_greater = count_greater(array: array->array, lenarray: array->cardinality, ikey: max);
5878 int32_t nvals_less = count_less(array: array->array, lenarray: array->cardinality - nvals_greater, ikey: min);
5879 int32_t union_cardinality = nvals_less + (max - min + 1) + nvals_greater;
5880
5881 if (union_cardinality == INT32_C(0x10000)) {
5882 *result_type = RUN_CONTAINER_TYPE_CODE;
5883 return run_container_create_range(start: 0, INT32_C(0x10000));
5884 } else if (union_cardinality <= DEFAULT_MAX_SIZE) {
5885 *result_type = ARRAY_CONTAINER_TYPE_CODE;
5886 array_container_add_range_nvals(array, min, max, nvals_less, nvals_greater);
5887 return array;
5888 } else {
5889 *result_type = BITSET_CONTAINER_TYPE_CODE;
5890 bitset_container_t *bitset = bitset_container_from_array(arr: array);
5891 bitset_set_lenrange(bitmap: bitset->array, start: min, lenminusone: max - min);
5892 bitset->cardinality = union_cardinality;
5893 return bitset;
5894 }
5895 }
5896 case RUN_CONTAINER_TYPE_CODE: {
5897 run_container_t *run = (run_container_t *) container;
5898
5899 int32_t nruns_greater = rle16_count_greater(array: run->runs, lenarray: run->n_runs, key: max);
5900 int32_t nruns_less = rle16_count_less(array: run->runs, lenarray: run->n_runs - nruns_greater, key: min);
5901
5902 int32_t run_size_bytes = (nruns_less + 1 + nruns_greater) * sizeof(rle16_t);
5903 int32_t bitset_size_bytes = BITSET_CONTAINER_SIZE_IN_WORDS * sizeof(uint64_t);
5904
5905 if (run_size_bytes <= bitset_size_bytes) {
5906 run_container_add_range_nruns(run, min, max, nruns_less, nruns_greater);
5907 *result_type = RUN_CONTAINER_TYPE_CODE;
5908 return run;
5909 } else {
5910 *result_type = BITSET_CONTAINER_TYPE_CODE;
5911 return bitset_container_from_run_range(run, min, max);
5912 }
5913 }
5914 case SHARED_CONTAINER_TYPE_CODE:
5915 default:
5916 __builtin_unreachable();
5917 }
5918}
5919
5920/*
5921 * Removes all elements in range [min, max].
5922 * Returns one of:
5923 * - NULL if no elements left
5924 * - pointer to the original container
5925 * - pointer to a newly-allocated container (if it is more efficient)
5926 *
5927 * If the returned pointer is different from $container, then a new container
5928 * has been created and the caller is responsible for freeing the original container.
5929 */
5930static inline void *container_remove_range(void *container, uint8_t type,
5931 uint32_t min, uint32_t max,
5932 uint8_t *result_type) {
5933 switch (type) {
5934 case BITSET_CONTAINER_TYPE_CODE: {
5935 bitset_container_t *bitset = (bitset_container_t *) container;
5936
5937 int32_t result_cardinality = bitset->cardinality -
5938 bitset_lenrange_cardinality(bitmap: bitset->array, start: min, lenminusone: max-min);
5939
5940 if (result_cardinality == 0) {
5941 return NULL;
5942 } else if (result_cardinality < DEFAULT_MAX_SIZE) {
5943 *result_type = ARRAY_CONTAINER_TYPE_CODE;
5944 bitset_reset_range(bitmap: bitset->array, start: min, end: max+1);
5945 bitset->cardinality = result_cardinality;
5946 return array_container_from_bitset(bits: bitset);
5947 } else {
5948 *result_type = BITSET_CONTAINER_TYPE_CODE;
5949 bitset_reset_range(bitmap: bitset->array, start: min, end: max+1);
5950 bitset->cardinality = result_cardinality;
5951 return bitset;
5952 }
5953 }
5954 case ARRAY_CONTAINER_TYPE_CODE: {
5955 array_container_t *array = (array_container_t *) container;
5956
5957 int32_t nvals_greater = count_greater(array: array->array, lenarray: array->cardinality, ikey: max);
5958 int32_t nvals_less = count_less(array: array->array, lenarray: array->cardinality - nvals_greater, ikey: min);
5959 int32_t result_cardinality = nvals_less + nvals_greater;
5960
5961 if (result_cardinality == 0) {
5962 return NULL;
5963 } else {
5964 *result_type = ARRAY_CONTAINER_TYPE_CODE;
5965 array_container_remove_range(array, pos: nvals_less,
5966 count: array->cardinality - result_cardinality);
5967 return array;
5968 }
5969 }
5970 case RUN_CONTAINER_TYPE_CODE: {
5971 run_container_t *run = (run_container_t *) container;
5972
5973 if (run->n_runs == 0) {
5974 return NULL;
5975 }
5976 if (min <= run_container_minimum(run) && max >= run_container_maximum(run)) {
5977 return NULL;
5978 }
5979
5980 run_container_remove_range(run, min, max);
5981
5982 if (run_container_serialized_size_in_bytes(num_runs: run->n_runs) <=
5983 bitset_container_serialized_size_in_bytes()) {
5984 *result_type = RUN_CONTAINER_TYPE_CODE;
5985 return run;
5986 } else {
5987 *result_type = BITSET_CONTAINER_TYPE_CODE;
5988 return bitset_container_from_run(arr: run);
5989 }
5990 }
5991 case SHARED_CONTAINER_TYPE_CODE:
5992 default:
5993 __builtin_unreachable();
5994 }
5995}
5996
5997#endif
5998/* end file include/roaring/containers/containers.h */
5999/* begin file include/roaring/roaring_array.h */
6000#ifndef INCLUDE_ROARING_ARRAY_H
6001#define INCLUDE_ROARING_ARRAY_H
6002#ifdef __cplusplus
6003extern "C" {
6004#endif
6005
6006#include <assert.h>
6007#include <stdbool.h>
6008#include <stdint.h>
6009
6010#define MAX_CONTAINERS 65536
6011
6012#define SERIALIZATION_ARRAY_UINT32 1
6013#define SERIALIZATION_CONTAINER 2
6014
6015#define ROARING_FLAG_COW UINT8_C(0x1)
6016#define ROARING_FLAG_FROZEN UINT8_C(0x2)
6017
6018enum {
6019 SERIAL_COOKIE_NO_RUNCONTAINER = 12346,
6020 SERIAL_COOKIE = 12347,
6021 FROZEN_COOKIE = 13766,
6022 NO_OFFSET_THRESHOLD = 4
6023};
6024
6025/**
6026 * Roaring arrays are array-based key-value pairs having containers as values
6027 * and 16-bit integer keys. A roaring bitmap might be implemented as such.
6028 */
6029
6030// parallel arrays. Element sizes quite different.
6031// Alternative is array
6032// of structs. Which would have better
6033// cache performance through binary searches?
6034
6035typedef struct roaring_array_s {
6036 int32_t size;
6037 int32_t allocation_size;
6038 void **containers;
6039 uint16_t *keys;
6040 uint8_t *typecodes;
6041 uint8_t flags;
6042} roaring_array_t;
6043
6044/**
6045 * Create a new roaring array
6046 */
6047roaring_array_t *ra_create(void);
6048
6049/**
6050 * Initialize an existing roaring array with the specified capacity (in number
6051 * of containers)
6052 */
6053bool ra_init_with_capacity(roaring_array_t *new_ra, uint32_t cap);
6054
6055/**
6056 * Initialize with zero capacity
6057 */
6058void ra_init(roaring_array_t *t);
6059
6060/**
6061 * Copies this roaring array, we assume that dest is not initialized
6062 */
6063bool ra_copy(const roaring_array_t *source, roaring_array_t *dest,
6064 bool copy_on_write);
6065
6066/*
6067 * Shrinks the capacity, returns the number of bytes saved.
6068 */
6069int ra_shrink_to_fit(roaring_array_t *ra);
6070
6071/**
6072 * Copies this roaring array, we assume that dest is initialized
6073 */
6074bool ra_overwrite(const roaring_array_t *source, roaring_array_t *dest,
6075 bool copy_on_write);
6076
6077/**
6078 * Frees the memory used by a roaring array
6079 */
6080void ra_clear(roaring_array_t *r);
6081
6082/**
6083 * Frees the memory used by a roaring array, but does not free the containers
6084 */
6085void ra_clear_without_containers(roaring_array_t *r);
6086
6087/**
6088 * Frees just the containers
6089 */
6090void ra_clear_containers(roaring_array_t *ra);
6091
6092/**
6093 * Get the index corresponding to a 16-bit key
6094 */
6095static inline int32_t ra_get_index(const roaring_array_t *ra, uint16_t x) {
6096 if ((ra->size == 0) || ra->keys[ra->size - 1] == x) return ra->size - 1;
6097 return binarySearch(array: ra->keys, lenarray: (int32_t)ra->size, ikey: x);
6098}
6099
6100/**
6101 * Retrieves the container at index i, filling in the typecode
6102 */
6103static inline void *ra_get_container_at_index(const roaring_array_t *ra, uint16_t i,
6104 uint8_t *typecode) {
6105 *typecode = ra->typecodes[i];
6106 return ra->containers[i];
6107}
6108
6109/**
6110 * Retrieves the key at index i
6111 */
6112uint16_t ra_get_key_at_index(const roaring_array_t *ra, uint16_t i);
6113
6114/**
6115 * Add a new key-value pair at index i
6116 */
6117void ra_insert_new_key_value_at(roaring_array_t *ra, int32_t i, uint16_t key,
6118 void *container, uint8_t typecode);
6119
6120/**
6121 * Append a new key-value pair
6122 */
6123void ra_append(roaring_array_t *ra, uint16_t s, void *c, uint8_t typecode);
6124
6125/**
6126 * Append a new key-value pair to ra, cloning (in COW sense) a value from sa
6127 * at index index
6128 */
6129void ra_append_copy(roaring_array_t *ra, const roaring_array_t *sa,
6130 uint16_t index, bool copy_on_write);
6131
6132/**
6133 * Append new key-value pairs to ra, cloning (in COW sense) values from sa
6134 * at indexes
6135 * [start_index, end_index)
6136 */
6137void ra_append_copy_range(roaring_array_t *ra, const roaring_array_t *sa,
6138 int32_t start_index, int32_t end_index,
6139 bool copy_on_write);
6140
6141/** appends from sa to ra, ending with the greatest key that is
6142 * is less or equal stopping_key
6143 */
6144void ra_append_copies_until(roaring_array_t *ra, const roaring_array_t *sa,
6145 uint16_t stopping_key, bool copy_on_write);
6146
6147/** appends from sa to ra, starting with the smallest key that is
6148 * is strictly greater than before_start
6149 */
6150
6151void ra_append_copies_after(roaring_array_t *ra, const roaring_array_t *sa,
6152 uint16_t before_start, bool copy_on_write);
6153
6154/**
6155 * Move the key-value pairs to ra from sa at indexes
6156 * [start_index, end_index), old array should not be freed
6157 * (use ra_clear_without_containers)
6158 **/
6159void ra_append_move_range(roaring_array_t *ra, roaring_array_t *sa,
6160 int32_t start_index, int32_t end_index);
6161/**
6162 * Append new key-value pairs to ra, from sa at indexes
6163 * [start_index, end_index)
6164 */
6165void ra_append_range(roaring_array_t *ra, roaring_array_t *sa,
6166 int32_t start_index, int32_t end_index,
6167 bool copy_on_write);
6168
6169/**
6170 * Set the container at the corresponding index using the specified
6171 * typecode.
6172 */
6173static inline void ra_set_container_at_index(const roaring_array_t *ra, int32_t i,
6174 void *c, uint8_t typecode) {
6175 assert(i < ra->size);
6176 ra->containers[i] = c;
6177 ra->typecodes[i] = typecode;
6178}
6179
6180/**
6181 * If needed, increase the capacity of the array so that it can fit k values
6182 * (at
6183 * least);
6184 */
6185bool extend_array(roaring_array_t *ra, int32_t k);
6186
6187static inline int32_t ra_get_size(const roaring_array_t *ra) { return ra->size; }
6188
6189static inline int32_t ra_advance_until(const roaring_array_t *ra, uint16_t x,
6190 int32_t pos) {
6191 return advanceUntil(array: ra->keys, pos, length: ra->size, min: x);
6192}
6193
6194int32_t ra_advance_until_freeing(roaring_array_t *ra, uint16_t x, int32_t pos);
6195
6196void ra_downsize(roaring_array_t *ra, int32_t new_length);
6197
6198static inline void ra_replace_key_and_container_at_index(roaring_array_t *ra,
6199 int32_t i, uint16_t key,
6200 void *c, uint8_t typecode) {
6201 assert(i < ra->size);
6202
6203 ra->keys[i] = key;
6204 ra->containers[i] = c;
6205 ra->typecodes[i] = typecode;
6206}
6207
6208// write set bits to an array
6209void ra_to_uint32_array(const roaring_array_t *ra, uint32_t *ans);
6210
6211bool ra_range_uint32_array(const roaring_array_t *ra, size_t offset, size_t limit, uint32_t *ans);
6212
6213/**
6214 * write a bitmap to a buffer. This is meant to be compatible with
6215 * the
6216 * Java and Go versions. Return the size in bytes of the serialized
6217 * output (which should be ra_portable_size_in_bytes(ra)).
6218 */
6219size_t ra_portable_serialize(const roaring_array_t *ra, char *buf);
6220
6221/**
6222 * read a bitmap from a serialized version. This is meant to be compatible
6223 * with the Java and Go versions.
6224 * maxbytes indicates how many bytes available from buf.
6225 * When the function returns true, roaring_array_t is populated with the data
6226 * and *readbytes indicates how many bytes were read. In all cases, if the function
6227 * returns true, then maxbytes >= *readbytes.
6228 */
6229bool ra_portable_deserialize(roaring_array_t *ra, const char *buf, const size_t maxbytes, size_t * readbytes);
6230
6231/**
6232 * Quickly checks whether there is a serialized bitmap at the pointer,
6233 * not exceeding size "maxbytes" in bytes. This function does not allocate
6234 * memory dynamically.
6235 *
6236 * This function returns 0 if and only if no valid bitmap is found.
6237 * Otherwise, it returns how many bytes are occupied by the bitmap data.
6238 */
6239size_t ra_portable_deserialize_size(const char *buf, const size_t maxbytes);
6240
6241/**
6242 * How many bytes are required to serialize this bitmap (meant to be
6243 * compatible
6244 * with Java and Go versions)
6245 */
6246size_t ra_portable_size_in_bytes(const roaring_array_t *ra);
6247
6248/**
6249 * return true if it contains at least one run container.
6250 */
6251bool ra_has_run_container(const roaring_array_t *ra);
6252
6253/**
6254 * Size of the header when serializing (meant to be compatible
6255 * with Java and Go versions)
6256 */
6257uint32_t ra_portable_header_size(const roaring_array_t *ra);
6258
6259/**
6260 * If the container at the index i is share, unshare it (creating a local
6261 * copy if needed).
6262 */
6263static inline void ra_unshare_container_at_index(roaring_array_t *ra,
6264 uint16_t i) {
6265 assert(i < ra->size);
6266 ra->containers[i] =
6267 get_writable_copy_if_shared(candidate_shared_container: ra->containers[i], type: &ra->typecodes[i]);
6268}
6269
6270/**
6271 * remove at index i, sliding over all entries after i
6272 */
6273void ra_remove_at_index(roaring_array_t *ra, int32_t i);
6274
6275
6276/**
6277* clears all containers, sets the size at 0 and shrinks the memory usage.
6278*/
6279void ra_reset(roaring_array_t *ra);
6280
6281/**
6282 * remove at index i, sliding over all entries after i. Free removed container.
6283 */
6284void ra_remove_at_index_and_free(roaring_array_t *ra, int32_t i);
6285
6286/**
6287 * remove a chunk of indices, sliding over entries after it
6288 */
6289// void ra_remove_index_range(roaring_array_t *ra, int32_t begin, int32_t end);
6290
6291// used in inplace andNot only, to slide left the containers from
6292// the mutated RoaringBitmap that are after the largest container of
6293// the argument RoaringBitmap. It is followed by a call to resize.
6294//
6295void ra_copy_range(roaring_array_t *ra, uint32_t begin, uint32_t end,
6296 uint32_t new_begin);
6297
6298/**
6299 * Shifts rightmost $count containers to the left (distance < 0) or
6300 * to the right (distance > 0).
6301 * Allocates memory if necessary.
6302 * This function doesn't free or create new containers.
6303 * Caller is responsible for that.
6304 */
6305void ra_shift_tail(roaring_array_t *ra, int32_t count, int32_t distance);
6306
6307#ifdef __cplusplus
6308}
6309#endif
6310
6311#endif
6312/* end file include/roaring/roaring_array.h */
6313/* begin file include/roaring/roaring.h */
6314/*
6315An implementation of Roaring Bitmaps in C.
6316*/
6317
6318#ifndef ROARING_H
6319#define ROARING_H
6320#ifdef __cplusplus
6321extern "C" {
6322#endif
6323
6324#include <stdbool.h>
6325
6326typedef struct roaring_bitmap_s {
6327 roaring_array_t high_low_container;
6328} roaring_bitmap_t;
6329
6330/**
6331 * Creates a new bitmap (initially empty)
6332 */
6333roaring_bitmap_t *roaring_bitmap_create(void);
6334
6335/**
6336 * Add all the values between min (included) and max (excluded) that are at a
6337 * distance k*step from min.
6338*/
6339roaring_bitmap_t *roaring_bitmap_from_range(uint64_t min, uint64_t max,
6340 uint32_t step);
6341
6342/**
6343 * Creates a new bitmap (initially empty) with a provided
6344 * container-storage capacity (it is a performance hint).
6345 */
6346roaring_bitmap_t *roaring_bitmap_create_with_capacity(uint32_t cap);
6347
6348/**
6349 * Creates a new bitmap from a pointer of uint32_t integers
6350 */
6351roaring_bitmap_t *roaring_bitmap_of_ptr(size_t n_args, const uint32_t *vals);
6352
6353/*
6354 * Whether you want to use copy-on-write.
6355 * Saves memory and avoids copies but needs more care in a threaded context.
6356 * Most users should ignore this flag.
6357 * Note: if you do turn this flag to 'true', enabling COW,
6358 * then ensure that you do so for all of your bitmaps since
6359 * interactions between bitmaps with and without COW is unsafe.
6360 */
6361static inline bool roaring_bitmap_get_copy_on_write(const roaring_bitmap_t* r) {
6362 return r->high_low_container.flags & ROARING_FLAG_COW;
6363}
6364static inline void roaring_bitmap_set_copy_on_write(roaring_bitmap_t* r, bool cow) {
6365 if (cow) {
6366 r->high_low_container.flags |= ROARING_FLAG_COW;
6367 } else {
6368 r->high_low_container.flags &= ~ROARING_FLAG_COW;
6369 }
6370}
6371
6372/**
6373 * Describe the inner structure of the bitmap.
6374 */
6375void roaring_bitmap_printf_describe(const roaring_bitmap_t *ra);
6376
6377/**
6378 * Creates a new bitmap from a list of uint32_t integers
6379 */
6380roaring_bitmap_t *roaring_bitmap_of(size_t n, ...);
6381
6382/**
6383 * Copies a bitmap. This does memory allocation. The caller is responsible for
6384 * memory management.
6385 *
6386 */
6387roaring_bitmap_t *roaring_bitmap_copy(const roaring_bitmap_t *r);
6388
6389
6390/**
6391 * Copies a bitmap from src to dest. It is assumed that the pointer dest
6392 * is to an already allocated bitmap. The content of the dest bitmap is
6393 * freed/deleted.
6394 *
6395 * It might be preferable and simpler to call roaring_bitmap_copy except
6396 * that roaring_bitmap_overwrite can save on memory allocations.
6397 *
6398 */
6399bool roaring_bitmap_overwrite(roaring_bitmap_t *dest,
6400 const roaring_bitmap_t *src);
6401
6402/**
6403 * Print the content of the bitmap.
6404 */
6405void roaring_bitmap_printf(const roaring_bitmap_t *ra);
6406
6407/**
6408 * Computes the intersection between two bitmaps and returns new bitmap. The
6409 * caller is
6410 * responsible for memory management.
6411 *
6412 */
6413roaring_bitmap_t *roaring_bitmap_and(const roaring_bitmap_t *x1,
6414 const roaring_bitmap_t *x2);
6415
6416/**
6417 * Computes the size of the intersection between two bitmaps.
6418 *
6419 */
6420uint64_t roaring_bitmap_and_cardinality(const roaring_bitmap_t *x1,
6421 const roaring_bitmap_t *x2);
6422
6423
6424/**
6425 * Check whether two bitmaps intersect.
6426 *
6427 */
6428bool roaring_bitmap_intersect(const roaring_bitmap_t *x1,
6429 const roaring_bitmap_t *x2);
6430
6431/**
6432 * Computes the Jaccard index between two bitmaps. (Also known as the Tanimoto
6433 * distance,
6434 * or the Jaccard similarity coefficient)
6435 *
6436 * The Jaccard index is undefined if both bitmaps are empty.
6437 *
6438 */
6439double roaring_bitmap_jaccard_index(const roaring_bitmap_t *x1,
6440 const roaring_bitmap_t *x2);
6441
6442/**
6443 * Computes the size of the union between two bitmaps.
6444 *
6445 */
6446uint64_t roaring_bitmap_or_cardinality(const roaring_bitmap_t *x1,
6447 const roaring_bitmap_t *x2);
6448
6449/**
6450 * Computes the size of the difference (andnot) between two bitmaps.
6451 *
6452 */
6453uint64_t roaring_bitmap_andnot_cardinality(const roaring_bitmap_t *x1,
6454 const roaring_bitmap_t *x2);
6455
6456/**
6457 * Computes the size of the symmetric difference (andnot) between two bitmaps.
6458 *
6459 */
6460uint64_t roaring_bitmap_xor_cardinality(const roaring_bitmap_t *x1,
6461 const roaring_bitmap_t *x2);
6462
6463/**
6464 * Inplace version modifies x1, x1 == x2 is allowed
6465 */
6466void roaring_bitmap_and_inplace(roaring_bitmap_t *x1,
6467 const roaring_bitmap_t *x2);
6468
6469/**
6470 * Computes the union between two bitmaps and returns new bitmap. The caller is
6471 * responsible for memory management.
6472 */
6473roaring_bitmap_t *roaring_bitmap_or(const roaring_bitmap_t *x1,
6474 const roaring_bitmap_t *x2);
6475
6476/**
6477 * Inplace version of roaring_bitmap_or, modifies x1. TDOO: decide whether x1 ==
6478 *x2 ok
6479 *
6480 */
6481void roaring_bitmap_or_inplace(roaring_bitmap_t *x1,
6482 const roaring_bitmap_t *x2);
6483
6484/**
6485 * Compute the union of 'number' bitmaps. See also roaring_bitmap_or_many_heap.
6486 * Caller is responsible for freeing the
6487 * result.
6488 *
6489 */
6490roaring_bitmap_t *roaring_bitmap_or_many(size_t number,
6491 const roaring_bitmap_t **x);
6492
6493/**
6494 * Compute the union of 'number' bitmaps using a heap. This can
6495 * sometimes be faster than roaring_bitmap_or_many which uses
6496 * a naive algorithm. Caller is responsible for freeing the
6497 * result.
6498 *
6499 */
6500roaring_bitmap_t *roaring_bitmap_or_many_heap(uint32_t number,
6501 const roaring_bitmap_t **x);
6502
6503/**
6504 * Computes the symmetric difference (xor) between two bitmaps
6505 * and returns new bitmap. The caller is responsible for memory management.
6506 */
6507roaring_bitmap_t *roaring_bitmap_xor(const roaring_bitmap_t *x1,
6508 const roaring_bitmap_t *x2);
6509
6510/**
6511 * Inplace version of roaring_bitmap_xor, modifies x1. x1 != x2.
6512 *
6513 */
6514void roaring_bitmap_xor_inplace(roaring_bitmap_t *x1,
6515 const roaring_bitmap_t *x2);
6516
6517/**
6518 * Compute the xor of 'number' bitmaps.
6519 * Caller is responsible for freeing the
6520 * result.
6521 *
6522 */
6523roaring_bitmap_t *roaring_bitmap_xor_many(size_t number,
6524 const roaring_bitmap_t **x);
6525
6526/**
6527 * Computes the difference (andnot) between two bitmaps
6528 * and returns new bitmap. The caller is responsible for memory management.
6529 */
6530roaring_bitmap_t *roaring_bitmap_andnot(const roaring_bitmap_t *x1,
6531 const roaring_bitmap_t *x2);
6532
6533/**
6534 * Inplace version of roaring_bitmap_andnot, modifies x1. x1 != x2.
6535 *
6536 */
6537void roaring_bitmap_andnot_inplace(roaring_bitmap_t *x1,
6538 const roaring_bitmap_t *x2);
6539
6540/**
6541 * TODO: consider implementing:
6542 * Compute the xor of 'number' bitmaps using a heap. This can
6543 * sometimes be faster than roaring_bitmap_xor_many which uses
6544 * a naive algorithm. Caller is responsible for freeing the
6545 * result.
6546 *
6547 * roaring_bitmap_t *roaring_bitmap_xor_many_heap(uint32_t number,
6548 * const roaring_bitmap_t **x);
6549 */
6550
6551/**
6552 * Frees the memory.
6553 */
6554void roaring_bitmap_free(const roaring_bitmap_t *r);
6555
6556/**
6557 * Add value n_args from pointer vals, faster than repeatedly calling
6558 * roaring_bitmap_add
6559 *
6560 */
6561void roaring_bitmap_add_many(roaring_bitmap_t *r, size_t n_args,
6562 const uint32_t *vals);
6563
6564/**
6565 * Add value x
6566 *
6567 */
6568void roaring_bitmap_add(roaring_bitmap_t *r, uint32_t x);
6569
6570/**
6571 * Add value x
6572 * Returns true if a new value was added, false if the value was already existing.
6573 */
6574bool roaring_bitmap_add_checked(roaring_bitmap_t *r, uint32_t x);
6575
6576/**
6577 * Add all values in range [min, max]
6578 */
6579void roaring_bitmap_add_range_closed(roaring_bitmap_t *ra, uint32_t min, uint32_t max);
6580
6581/**
6582 * Add all values in range [min, max)
6583 */
6584static inline void roaring_bitmap_add_range(roaring_bitmap_t *ra, uint64_t min, uint64_t max) {
6585 if(max == min) return;
6586 roaring_bitmap_add_range_closed(ra, min: (uint32_t)min, max: (uint32_t)(max - 1));
6587}
6588
6589/**
6590 * Remove value x
6591 *
6592 */
6593void roaring_bitmap_remove(roaring_bitmap_t *r, uint32_t x);
6594
6595/** Remove all values in range [min, max] */
6596void roaring_bitmap_remove_range_closed(roaring_bitmap_t *ra, uint32_t min, uint32_t max);
6597
6598/** Remove all values in range [min, max) */
6599static inline void roaring_bitmap_remove_range(roaring_bitmap_t *ra, uint64_t min, uint64_t max) {
6600 if(max == min) return;
6601 roaring_bitmap_remove_range_closed(ra, min: (uint32_t)min, max: (uint32_t)(max - 1));
6602}
6603
6604/** Remove multiple values */
6605void roaring_bitmap_remove_many(roaring_bitmap_t *r, size_t n_args,
6606 const uint32_t *vals);
6607
6608/**
6609 * Remove value x
6610 * Returns true if a new value was removed, false if the value was not existing.
6611 */
6612bool roaring_bitmap_remove_checked(roaring_bitmap_t *r, uint32_t x);
6613
6614/**
6615 * Check if value x is present
6616 */
6617static inline bool roaring_bitmap_contains(const roaring_bitmap_t *r, uint32_t val) {
6618 const uint16_t hb = val >> 16;
6619 /*
6620 * the next function call involves a binary search and lots of branching.
6621 */
6622 int32_t i = ra_get_index(ra: &r->high_low_container, x: hb);
6623 if (i < 0) return false;
6624
6625 uint8_t typecode;
6626 // next call ought to be cheap
6627 void *container =
6628 ra_get_container_at_index(ra: &r->high_low_container, i, typecode: &typecode);
6629 // rest might be a tad expensive, possibly involving another round of binary search
6630 return container_contains(container, val: val & 0xFFFF, typecode);
6631}
6632
6633/**
6634 * Check whether a range of values from range_start (included) to range_end (excluded) is present
6635 */
6636bool roaring_bitmap_contains_range(const roaring_bitmap_t *r, uint64_t range_start, uint64_t range_end);
6637
6638/**
6639 * Get the cardinality of the bitmap (number of elements).
6640 */
6641uint64_t roaring_bitmap_get_cardinality(const roaring_bitmap_t *ra);
6642
6643/**
6644 * Returns the number of elements in the range [range_start, range_end).
6645 */
6646uint64_t roaring_bitmap_range_cardinality(const roaring_bitmap_t *ra,
6647 uint64_t range_start, uint64_t range_end);
6648
6649/**
6650* Returns true if the bitmap is empty (cardinality is zero).
6651*/
6652bool roaring_bitmap_is_empty(const roaring_bitmap_t *ra);
6653
6654
6655/**
6656* Empties the bitmap
6657*/
6658void roaring_bitmap_clear(roaring_bitmap_t *ra);
6659
6660/**
6661 * Convert the bitmap to an array. Write the output to "ans",
6662 * caller is responsible to ensure that there is enough memory
6663 * allocated
6664 * (e.g., ans = malloc(roaring_bitmap_get_cardinality(mybitmap)
6665 * * sizeof(uint32_t))
6666 */
6667void roaring_bitmap_to_uint32_array(const roaring_bitmap_t *ra, uint32_t *ans);
6668
6669
6670/**
6671 * Convert the bitmap to an array from "offset" by "limit". Write the output to "ans".
6672 * so, you can get data in paging.
6673 * caller is responsible to ensure that there is enough memory
6674 * allocated
6675 * (e.g., ans = malloc(roaring_bitmap_get_cardinality(limit)
6676 * * sizeof(uint32_t))
6677 * Return false in case of failure (e.g., insufficient memory)
6678 */
6679bool roaring_bitmap_range_uint32_array(const roaring_bitmap_t *ra, size_t offset, size_t limit, uint32_t *ans);
6680
6681/**
6682 * Remove run-length encoding even when it is more space efficient
6683 * return whether a change was applied
6684 */
6685bool roaring_bitmap_remove_run_compression(roaring_bitmap_t *r);
6686
6687/** convert array and bitmap containers to run containers when it is more
6688 * efficient;
6689 * also convert from run containers when more space efficient. Returns
6690 * true if the result has at least one run container.
6691 * Additional savings might be possible by calling shrinkToFit().
6692 */
6693bool roaring_bitmap_run_optimize(roaring_bitmap_t *r);
6694
6695/**
6696 * If needed, reallocate memory to shrink the memory usage. Returns
6697 * the number of bytes saved.
6698*/
6699size_t roaring_bitmap_shrink_to_fit(roaring_bitmap_t *r);
6700
6701/**
6702* write the bitmap to an output pointer, this output buffer should refer to
6703* at least roaring_bitmap_size_in_bytes(ra) allocated bytes.
6704*
6705* see roaring_bitmap_portable_serialize if you want a format that's compatible
6706* with Java and Go implementations
6707*
6708* this format has the benefit of being sometimes more space efficient than
6709* roaring_bitmap_portable_serialize
6710* e.g., when the data is sparse.
6711*
6712* Returns how many bytes were written which should be
6713* roaring_bitmap_size_in_bytes(ra).
6714*/
6715size_t roaring_bitmap_serialize(const roaring_bitmap_t *ra, char *buf);
6716
6717/** use with roaring_bitmap_serialize
6718* see roaring_bitmap_portable_deserialize if you want a format that's
6719* compatible with Java and Go implementations
6720*/
6721roaring_bitmap_t *roaring_bitmap_deserialize(const void *buf);
6722
6723/**
6724 * How many bytes are required to serialize this bitmap (NOT compatible
6725 * with Java and Go versions)
6726 */
6727size_t roaring_bitmap_size_in_bytes(const roaring_bitmap_t *ra);
6728
6729/**
6730 * read a bitmap from a serialized version. This is meant to be compatible with
6731 * the Java and Go versions. See format specification at
6732 * https://github.com/RoaringBitmap/RoaringFormatSpec
6733 * In case of failure, a null pointer is returned.
6734 * This function is unsafe in the sense that if there is no valid serialized
6735 * bitmap at the pointer, then many bytes could be read, possibly causing a buffer
6736 * overflow. For a safer approach,
6737 * call roaring_bitmap_portable_deserialize_safe.
6738 */
6739roaring_bitmap_t *roaring_bitmap_portable_deserialize(const char *buf);
6740
6741/**
6742 * read a bitmap from a serialized version in a safe manner (reading up to maxbytes).
6743 * This is meant to be compatible with
6744 * the Java and Go versions. See format specification at
6745 * https://github.com/RoaringBitmap/RoaringFormatSpec
6746 * In case of failure, a null pointer is returned.
6747 */
6748roaring_bitmap_t *roaring_bitmap_portable_deserialize_safe(const char *buf, size_t maxbytes);
6749
6750/**
6751 * Check how many bytes would be read (up to maxbytes) at this pointer if there
6752 * is a bitmap, returns zero if there is no valid bitmap.
6753 * This is meant to be compatible with
6754 * the Java and Go versions. See format specification at
6755 * https://github.com/RoaringBitmap/RoaringFormatSpec
6756 */
6757size_t roaring_bitmap_portable_deserialize_size(const char *buf, size_t maxbytes);
6758
6759
6760/**
6761 * How many bytes are required to serialize this bitmap (meant to be compatible
6762 * with Java and Go versions). See format specification at
6763 * https://github.com/RoaringBitmap/RoaringFormatSpec
6764 */
6765size_t roaring_bitmap_portable_size_in_bytes(const roaring_bitmap_t *ra);
6766
6767/**
6768 * write a bitmap to a char buffer. The output buffer should refer to at least
6769 * roaring_bitmap_portable_size_in_bytes(ra) bytes of allocated memory.
6770 * This is meant to be compatible with
6771 * the
6772 * Java and Go versions. Returns how many bytes were written which should be
6773 * roaring_bitmap_portable_size_in_bytes(ra). See format specification at
6774 * https://github.com/RoaringBitmap/RoaringFormatSpec
6775 */
6776size_t roaring_bitmap_portable_serialize(const roaring_bitmap_t *ra, char *buf);
6777
6778/*
6779 * "Frozen" serialization format imitates memory layout of roaring_bitmap_t.
6780 * Deserialized bitmap is a constant view of the underlying buffer.
6781 * This significantly reduces amount of allocations and copying required during
6782 * deserialization.
6783 * It can be used with memory mapped files.
6784 * Example can be found in benchmarks/frozen_benchmark.c
6785 *
6786 * [#####] const roaring_bitmap_t *
6787 * | | |
6788 * +----+ | +-+
6789 * | | |
6790 * [#####################################] underlying buffer
6791 *
6792 * Note that because frozen serialization format imitates C memory layout
6793 * of roaring_bitmap_t, it is not fixed. It is different on big/little endian
6794 * platforms and can be changed in future.
6795 */
6796
6797/**
6798 * Returns number of bytes required to serialize bitmap using frozen format.
6799 */
6800size_t roaring_bitmap_frozen_size_in_bytes(const roaring_bitmap_t *ra);
6801
6802/**
6803 * Serializes bitmap using frozen format.
6804 * Buffer size must be at least roaring_bitmap_frozen_size_in_bytes().
6805 */
6806void roaring_bitmap_frozen_serialize(const roaring_bitmap_t *ra, char *buf);
6807
6808/**
6809 * Creates constant bitmap that is a view of a given buffer.
6810 * Buffer must contain data previously written by roaring_bitmap_frozen_serialize(),
6811 * and additionally its beginning must be aligned by 32 bytes.
6812 * Length must be equal exactly to roaring_bitmap_frozen_size_in_bytes().
6813 *
6814 * On error, NULL is returned.
6815 *
6816 * Bitmap returned by this function can be used in all readonly contexts.
6817 * Bitmap must be freed as usual, by calling roaring_bitmap_free().
6818 * Underlying buffer must not be freed or modified while it backs any bitmaps.
6819 */
6820const roaring_bitmap_t *roaring_bitmap_frozen_view(const char *buf, size_t length);
6821
6822
6823/**
6824 * Iterate over the bitmap elements. The function iterator is called once for
6825 * all the values with ptr (can be NULL) as the second parameter of each call.
6826 *
6827 * roaring_iterator is simply a pointer to a function that returns bool
6828 * (true means that the iteration should continue while false means that it
6829 * should stop),
6830 * and takes (uint32_t,void*) as inputs.
6831 *
6832 * Returns true if the roaring_iterator returned true throughout (so that
6833 * all data points were necessarily visited).
6834 */
6835bool roaring_iterate(const roaring_bitmap_t *ra, roaring_iterator iterator,
6836 void *ptr);
6837
6838bool roaring_iterate64(const roaring_bitmap_t *ra, roaring_iterator64 iterator,
6839 uint64_t high_bits, void *ptr);
6840
6841/**
6842 * Return true if the two bitmaps contain the same elements.
6843 */
6844bool roaring_bitmap_equals(const roaring_bitmap_t *ra1,
6845 const roaring_bitmap_t *ra2);
6846
6847/**
6848 * Return true if all the elements of ra1 are also in ra2.
6849 */
6850bool roaring_bitmap_is_subset(const roaring_bitmap_t *ra1,
6851 const roaring_bitmap_t *ra2);
6852
6853/**
6854 * Return true if all the elements of ra1 are also in ra2 and ra2 is strictly
6855 * greater
6856 * than ra1.
6857 */
6858bool roaring_bitmap_is_strict_subset(const roaring_bitmap_t *ra1,
6859 const roaring_bitmap_t *ra2);
6860
6861/**
6862 * (For expert users who seek high performance.)
6863 *
6864 * Computes the union between two bitmaps and returns new bitmap. The caller is
6865 * responsible for memory management.
6866 *
6867 * The lazy version defers some computations such as the maintenance of the
6868 * cardinality counts. Thus you need
6869 * to call roaring_bitmap_repair_after_lazy after executing "lazy" computations.
6870 * It is safe to repeatedly call roaring_bitmap_lazy_or_inplace on the result.
6871 * The bitsetconversion conversion is a flag which determines
6872 * whether container-container operations force a bitset conversion.
6873 **/
6874roaring_bitmap_t *roaring_bitmap_lazy_or(const roaring_bitmap_t *x1,
6875 const roaring_bitmap_t *x2,
6876 const bool bitsetconversion);
6877
6878/**
6879 * (For expert users who seek high performance.)
6880 * Inplace version of roaring_bitmap_lazy_or, modifies x1
6881 * The bitsetconversion conversion is a flag which determines
6882 * whether container-container operations force a bitset conversion.
6883 */
6884void roaring_bitmap_lazy_or_inplace(roaring_bitmap_t *x1,
6885 const roaring_bitmap_t *x2,
6886 const bool bitsetconversion);
6887
6888/**
6889 * (For expert users who seek high performance.)
6890 *
6891 * Execute maintenance operations on a bitmap created from
6892 * roaring_bitmap_lazy_or
6893 * or modified with roaring_bitmap_lazy_or_inplace.
6894 */
6895void roaring_bitmap_repair_after_lazy(roaring_bitmap_t *x1);
6896
6897/**
6898 * Computes the symmetric difference between two bitmaps and returns new bitmap.
6899 *The caller is
6900 * responsible for memory management.
6901 *
6902 * The lazy version defers some computations such as the maintenance of the
6903 * cardinality counts. Thus you need
6904 * to call roaring_bitmap_repair_after_lazy after executing "lazy" computations.
6905 * It is safe to repeatedly call roaring_bitmap_lazy_xor_inplace on the result.
6906 *
6907 */
6908roaring_bitmap_t *roaring_bitmap_lazy_xor(const roaring_bitmap_t *x1,
6909 const roaring_bitmap_t *x2);
6910
6911/**
6912 * (For expert users who seek high performance.)
6913 * Inplace version of roaring_bitmap_lazy_xor, modifies x1. x1 != x2
6914 *
6915 */
6916void roaring_bitmap_lazy_xor_inplace(roaring_bitmap_t *x1,
6917 const roaring_bitmap_t *x2);
6918
6919/**
6920 * compute the negation of the roaring bitmap within a specified
6921 * interval: [range_start, range_end). The number of negated values is
6922 * range_end - range_start.
6923 * Areas outside the range are passed through unchanged.
6924 */
6925
6926roaring_bitmap_t *roaring_bitmap_flip(const roaring_bitmap_t *x1,
6927 uint64_t range_start, uint64_t range_end);
6928
6929/**
6930 * compute (in place) the negation of the roaring bitmap within a specified
6931 * interval: [range_start, range_end). The number of negated values is
6932 * range_end - range_start.
6933 * Areas outside the range are passed through unchanged.
6934 */
6935
6936void roaring_bitmap_flip_inplace(roaring_bitmap_t *x1, uint64_t range_start,
6937 uint64_t range_end);
6938
6939/**
6940 * Selects the element at index 'rank' where the smallest element is at index 0.
6941 * If the size of the roaring bitmap is strictly greater than rank, then this
6942 function returns true and sets element to the element of given rank.
6943 Otherwise, it returns false.
6944 */
6945bool roaring_bitmap_select(const roaring_bitmap_t *ra, uint32_t rank,
6946 uint32_t *element);
6947/**
6948* roaring_bitmap_rank returns the number of integers that are smaller or equal
6949* to x. Thus if x is the first element, this function will return 1. If
6950* x is smaller than the smallest element, this function will return 0.
6951*
6952* The indexing convention differs between roaring_bitmap_select and
6953* roaring_bitmap_rank: roaring_bitmap_select refers to the smallest value
6954* as having index 0, whereas roaring_bitmap_rank returns 1 when ranking
6955* the smallest value.
6956*/
6957uint64_t roaring_bitmap_rank(const roaring_bitmap_t *bm, uint32_t x);
6958
6959/**
6960* roaring_bitmap_smallest returns the smallest value in the set.
6961* Returns UINT32_MAX if the set is empty.
6962*/
6963uint32_t roaring_bitmap_minimum(const roaring_bitmap_t *bm);
6964
6965/**
6966* roaring_bitmap_smallest returns the greatest value in the set.
6967* Returns 0 if the set is empty.
6968*/
6969uint32_t roaring_bitmap_maximum(const roaring_bitmap_t *bm);
6970
6971/**
6972* (For advanced users.)
6973* Collect statistics about the bitmap, see roaring_types.h for
6974* a description of roaring_statistics_t
6975*/
6976void roaring_bitmap_statistics(const roaring_bitmap_t *ra,
6977 roaring_statistics_t *stat);
6978
6979/*********************
6980* What follows is code use to iterate through values in a roaring bitmap
6981
6982roaring_bitmap_t *ra =...
6983roaring_uint32_iterator_t i;
6984roaring_create_iterator(ra, &i);
6985while(i.has_value) {
6986 printf("value = %d\n", i.current_value);
6987 roaring_advance_uint32_iterator(&i);
6988}
6989
6990Obviously, if you modify the underlying bitmap, the iterator
6991becomes invalid. So don't.
6992*/
6993
6994typedef struct roaring_uint32_iterator_s {
6995 const roaring_bitmap_t *parent; // owner
6996 int32_t container_index; // point to the current container index
6997 int32_t in_container_index; // for bitset and array container, this is out
6998 // index
6999 int32_t run_index; // for run container, this points at the run
7000
7001 uint32_t current_value;
7002 bool has_value;
7003
7004 const void
7005 *container; // should be:
7006 // parent->high_low_container.containers[container_index];
7007 uint8_t typecode; // should be:
7008 // parent->high_low_container.typecodes[container_index];
7009 uint32_t highbits; // should be:
7010 // parent->high_low_container.keys[container_index]) <<
7011 // 16;
7012
7013} roaring_uint32_iterator_t;
7014
7015/**
7016* Initialize an iterator object that can be used to iterate through the
7017* values. If there is a value, then this iterator points to the first value
7018* and it->has_value is true. The value is in it->current_value.
7019*/
7020void roaring_init_iterator(const roaring_bitmap_t *ra,
7021 roaring_uint32_iterator_t *newit);
7022
7023/**
7024* Initialize an iterator object that can be used to iterate through the
7025* values. If there is a value, then this iterator points to the last value
7026* and it->has_value is true. The value is in it->current_value.
7027*/
7028void roaring_init_iterator_last(const roaring_bitmap_t *ra,
7029 roaring_uint32_iterator_t *newit);
7030
7031/**
7032* Create an iterator object that can be used to iterate through the
7033* values. Caller is responsible for calling roaring_free_iterator.
7034* The iterator is initialized. If there is a value, then this iterator
7035* points to the first value and it->has_value is true.
7036* The value is in it->current_value.
7037*
7038* This function calls roaring_init_iterator.
7039*/
7040roaring_uint32_iterator_t *roaring_create_iterator(const roaring_bitmap_t *ra);
7041
7042/**
7043* Advance the iterator. If there is a new value, then it->has_value is true.
7044* The new value is in it->current_value. Values are traversed in increasing
7045* orders. For convenience, returns it->has_value.
7046*/
7047bool roaring_advance_uint32_iterator(roaring_uint32_iterator_t *it);
7048
7049/**
7050* Decrement the iterator. If there is a new value, then it->has_value is true.
7051* The new value is in it->current_value. Values are traversed in decreasing
7052* orders. For convenience, returns it->has_value.
7053*/
7054bool roaring_previous_uint32_iterator(roaring_uint32_iterator_t *it);
7055
7056/**
7057* Move the iterator to the first value >= val. If there is a such a value, then it->has_value is true.
7058* The new value is in it->current_value. For convenience, returns it->has_value.
7059*/
7060bool roaring_move_uint32_iterator_equalorlarger(roaring_uint32_iterator_t *it, uint32_t val) ;
7061/**
7062* Creates a copy of an iterator.
7063* Caller must free it.
7064*/
7065roaring_uint32_iterator_t *roaring_copy_uint32_iterator(
7066 const roaring_uint32_iterator_t *it);
7067
7068/**
7069* Free memory following roaring_create_iterator
7070*/
7071void roaring_free_uint32_iterator(roaring_uint32_iterator_t *it);
7072
7073/*
7074 * Reads next ${count} values from iterator into user-supplied ${buf}.
7075 * Returns the number of read elements.
7076 * This number can be smaller than ${count}, which means that iterator is drained.
7077 *
7078 * This function satisfies semantics of iteration and can be used together with
7079 * other iterator functions.
7080 * - first value is copied from ${it}->current_value
7081 * - after function returns, iterator is positioned at the next element
7082 */
7083uint32_t roaring_read_uint32_iterator(roaring_uint32_iterator_t *it, uint32_t* buf, uint32_t count);
7084
7085#ifdef __cplusplus
7086}
7087#endif
7088
7089#endif
7090/* end file include/roaring/roaring.h */
7091

source code of gtk/gtk/roaring/roaring.h