/src/croaring/include/roaring/array_util.h
Line | Count | Source |
1 | | /* |
2 | | * array_util.h |
3 | | * |
4 | | * This header provides low-level utility routines for sorted arrays of |
5 | | * 16-bit integers, which are used heavily by CRoaring's array-based |
6 | | * containers and set-operation kernels. It includes search helpers, counting |
7 | | * helpers, and array intersection/difference primitives. |
8 | | * |
9 | | * Some of the routines also have SIMD-accelerated implementations on supported |
10 | | * platforms, allowing efficient operations on sorted integer arrays that form |
11 | | * the basis of sparse container processing. |
12 | | */ |
13 | | #ifndef CROARING_ARRAY_UTIL_H |
14 | | #define CROARING_ARRAY_UTIL_H |
15 | | |
16 | | #include <stddef.h> // for size_t |
17 | | #include <stdint.h> |
18 | | |
19 | | #include <roaring/portability.h> |
20 | | |
21 | | #if CROARING_IS_X64 |
22 | | #ifndef CROARING_COMPILER_SUPPORTS_AVX512 |
23 | | #error "CROARING_COMPILER_SUPPORTS_AVX512 needs to be defined." |
24 | | #endif // CROARING_COMPILER_SUPPORTS_AVX512 |
25 | | #endif |
26 | | #if defined(__GNUC__) && !defined(__clang__) |
27 | | #pragma GCC diagnostic push |
28 | | #pragma GCC diagnostic ignored "-Wuninitialized" |
29 | | #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" |
30 | | #endif |
31 | | #ifdef __cplusplus |
32 | | extern "C" { |
33 | | namespace roaring { |
34 | | namespace internal { |
35 | | #endif |
36 | | |
37 | | /* |
38 | | * Sorted-array search. |
39 | | * Assumes that array is sorted, has logarithmic complexity. |
40 | | * if the result is x, then: |
41 | | * if ( x>0 ) you have array[x] = ikey |
42 | | * if ( x<0 ) then inserting ikey at position -x-1 in array (insuring that |
43 | | * array[-x-1]=ikey) keys the array sorted. |
44 | | * |
45 | | * Adapted from array_container_contains: a SIMD-quad block-narrowing |
46 | | * search at gap=16 (Daniel Lemire, |
47 | | * https://lemire.me/blog/2026/04/27/you-can-beat-the-binary-search/) |
48 | | * followed by a scalar in-block scan that recovers the exact insertion |
49 | | * point required by the binarySearch contract. |
50 | | */ |
51 | | inline int32_t binarySearch(const uint16_t *array, int32_t lenarray, |
52 | 7.04M | uint16_t ikey) { |
53 | 7.04M | const int32_t gap = 16; |
54 | 7.04M | if (lenarray < gap) { |
55 | 4.21M | for (int32_t j = 0; j < lenarray; j++) { |
56 | 4.20M | if (array[j] >= ikey) { |
57 | 2.76M | return (array[j] == ikey) ? j : -(j + 1); |
58 | 2.76M | } |
59 | 4.20M | } |
60 | 7.25k | return -(lenarray + 1); |
61 | 2.77M | } |
62 | 4.27M | const int32_t num_blocks = lenarray / gap; |
63 | 4.27M | int32_t base = 0; |
64 | 4.27M | int32_t n = num_blocks; |
65 | 8.56M | while (n > 3) { |
66 | 4.28M | int32_t quarter = n >> 2; |
67 | | |
68 | 4.28M | int32_t k1 = array[(base + quarter + 1) * gap - 1]; |
69 | 4.28M | int32_t k2 = array[(base + 2 * quarter + 1) * gap - 1]; |
70 | 4.28M | int32_t k3 = array[(base + 3 * quarter + 1) * gap - 1]; |
71 | | |
72 | 4.28M | int32_t c1 = (k1 < ikey); |
73 | 4.28M | int32_t c2 = (k2 < ikey); |
74 | 4.28M | int32_t c3 = (k3 < ikey); |
75 | | |
76 | 4.28M | base += (c1 + c2 + c3) * quarter; |
77 | 4.28M | n -= 3 * quarter; |
78 | 4.28M | } |
79 | 7.91M | while (n > 1) { |
80 | 3.63M | int32_t half = n >> 1; |
81 | 3.63M | base = (array[(base + half + 1) * gap - 1] < ikey) ? base + half : base; |
82 | 3.63M | n -= half; |
83 | 3.63M | } |
84 | 4.27M | int32_t lo = (array[(base + 1) * gap - 1] < ikey) ? base + 1 : base; |
85 | | |
86 | 4.27M | if (lo < num_blocks) { |
87 | 3.97M | const int32_t start = lo * gap; |
88 | 3.97M | #if defined(CROARING_IS_X64) |
89 | | // SSE2: subs_epu16 yields zero where lane >= ikey. movemask of an |
90 | | // epi16 compare gives 2 bits per lane; ctz>>1 = lane index. Scan |
91 | | // the first 8 lanes first and exit early when they contain the |
92 | | // answer; otherwise the block-narrowing invariant guarantees the |
93 | | // second-half mask is non-zero. |
94 | 3.97M | __m128i needle = _mm_set1_epi16((short)ikey); |
95 | 3.97M | __m128i zero = _mm_setzero_si128(); |
96 | 3.97M | __m128i v0 = _mm_loadu_si128((const __m128i *)(array + start)); |
97 | 3.97M | __m128i ge0 = _mm_cmpeq_epi16(_mm_subs_epu16(needle, v0), zero); |
98 | 3.97M | unsigned m0 = (unsigned)_mm_movemask_epi8(ge0); |
99 | 3.97M | if (m0 != 0) { |
100 | 2.82M | int32_t j = start + (int32_t)(roaring_trailing_zeroes(m0) >> 1); |
101 | 2.82M | return (array[j] == ikey) ? j : -(j + 1); |
102 | 2.82M | } |
103 | 1.14M | __m128i v1 = _mm_loadu_si128((const __m128i *)(array + start + 8)); |
104 | 1.14M | __m128i ge1 = _mm_cmpeq_epi16(_mm_subs_epu16(needle, v1), zero); |
105 | 1.14M | unsigned m1 = (unsigned)_mm_movemask_epi8(ge1); |
106 | 1.14M | int32_t j = start + 8 + (int32_t)(roaring_trailing_zeroes(m1) >> 1); |
107 | 1.14M | return (array[j] == ikey) ? j : -(j + 1); |
108 | | #else |
109 | | const int32_t end = start + gap; |
110 | | for (int32_t j = start; j < end; j++) { |
111 | | if (array[j] >= ikey) { |
112 | | return (array[j] == ikey) ? j : -(j + 1); |
113 | | } |
114 | | } |
115 | | // Unreachable: the narrowing guarantees the last element of the |
116 | | // selected block is >= ikey. |
117 | | return -(end + 1); |
118 | | #endif |
119 | 3.97M | } |
120 | | |
121 | 1.74M | for (int32_t j = num_blocks * gap; j < lenarray; j++) { |
122 | 1.73M | if (array[j] >= ikey) { |
123 | 294k | return (array[j] == ikey) ? j : -(j + 1); |
124 | 294k | } |
125 | 1.73M | } |
126 | 10.6k | return -(lenarray + 1); |
127 | 305k | } |
128 | | |
129 | | /** |
130 | | * Galloping search |
131 | | * Assumes that array is sorted, has logarithmic complexity. |
132 | | * if the result is x, then if x = length, you have that all values in array |
133 | | * between pos and length are smaller than min. otherwise returns the first |
134 | | * index x such that array[x] >= min. |
135 | | */ |
136 | | static inline int32_t advanceUntil(const uint16_t *array, int32_t pos, |
137 | 236k | int32_t length, uint16_t min) { |
138 | 236k | int32_t lower = pos + 1; |
139 | | |
140 | 236k | if ((lower >= length) || (array[lower] >= min)) { |
141 | 156k | return lower; |
142 | 156k | } |
143 | | |
144 | 79.4k | int32_t spansize = 1; |
145 | | |
146 | 206k | while ((lower + spansize < length) && (array[lower + spansize] < min)) { |
147 | 127k | spansize <<= 1; |
148 | 127k | } |
149 | 79.4k | int32_t upper = (lower + spansize < length) ? lower + spansize : length - 1; |
150 | | |
151 | 79.4k | if (array[upper] == min) { |
152 | 35.8k | return upper; |
153 | 35.8k | } |
154 | 43.6k | if (array[upper] < min) { |
155 | | // means |
156 | | // array |
157 | | // has no |
158 | | // item |
159 | | // >= min |
160 | | // pos = array.length; |
161 | 1.15k | return length; |
162 | 1.15k | } |
163 | | |
164 | | // we know that the next-smallest span was too small |
165 | 42.5k | lower += (spansize >> 1); |
166 | | |
167 | 42.5k | int32_t mid = 0; |
168 | 86.0k | while (lower + 1 != upper) { |
169 | 62.1k | mid = (lower + upper) >> 1; |
170 | 62.1k | if (array[mid] == min) { |
171 | 18.6k | return mid; |
172 | 43.5k | } else if (array[mid] < min) { |
173 | 18.7k | lower = mid; |
174 | 24.7k | } else { |
175 | 24.7k | upper = mid; |
176 | 24.7k | } |
177 | 62.1k | } |
178 | 23.9k | return upper; |
179 | 42.5k | } Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::advanceUntil(unsigned short const*, int, int, unsigned short) Line | Count | Source | 137 | 518 | int32_t length, uint16_t min) { | 138 | 518 | int32_t lower = pos + 1; | 139 | | | 140 | 518 | if ((lower >= length) || (array[lower] >= min)) { | 141 | 518 | return lower; | 142 | 518 | } | 143 | | | 144 | 0 | int32_t spansize = 1; | 145 | |
| 146 | 0 | while ((lower + spansize < length) && (array[lower + spansize] < min)) { | 147 | 0 | spansize <<= 1; | 148 | 0 | } | 149 | 0 | int32_t upper = (lower + spansize < length) ? lower + spansize : length - 1; | 150 | |
| 151 | 0 | if (array[upper] == min) { | 152 | 0 | return upper; | 153 | 0 | } | 154 | 0 | if (array[upper] < min) { | 155 | | // means | 156 | | // array | 157 | | // has no | 158 | | // item | 159 | | // >= min | 160 | | // pos = array.length; | 161 | 0 | return length; | 162 | 0 | } | 163 | | | 164 | | // we know that the next-smallest span was too small | 165 | 0 | lower += (spansize >> 1); | 166 | |
| 167 | 0 | int32_t mid = 0; | 168 | 0 | while (lower + 1 != upper) { | 169 | 0 | mid = (lower + upper) >> 1; | 170 | 0 | if (array[mid] == min) { | 171 | 0 | return mid; | 172 | 0 | } else if (array[mid] < min) { | 173 | 0 | lower = mid; | 174 | 0 | } else { | 175 | 0 | upper = mid; | 176 | 0 | } | 177 | 0 | } | 178 | 0 | return upper; | 179 | 0 | } |
Unexecuted instantiation: roaring_array.c:advanceUntil array_util.c:advanceUntil Line | Count | Source | 137 | 17.2k | int32_t length, uint16_t min) { | 138 | 17.2k | int32_t lower = pos + 1; | 139 | | | 140 | 17.2k | if ((lower >= length) || (array[lower] >= min)) { | 141 | 6.21k | return lower; | 142 | 6.21k | } | 143 | | | 144 | 11.0k | int32_t spansize = 1; | 145 | | | 146 | 48.2k | while ((lower + spansize < length) && (array[lower + spansize] < min)) { | 147 | 37.1k | spansize <<= 1; | 148 | 37.1k | } | 149 | 11.0k | int32_t upper = (lower + spansize < length) ? lower + spansize : length - 1; | 150 | | | 151 | 11.0k | if (array[upper] == min) { | 152 | 2.56k | return upper; | 153 | 2.56k | } | 154 | 8.51k | if (array[upper] < min) { | 155 | | // means | 156 | | // array | 157 | | // has no | 158 | | // item | 159 | | // >= min | 160 | | // pos = array.length; | 161 | 165 | return length; | 162 | 165 | } | 163 | | | 164 | | // we know that the next-smallest span was too small | 165 | 8.34k | lower += (spansize >> 1); | 166 | | | 167 | 8.34k | int32_t mid = 0; | 168 | 26.5k | while (lower + 1 != upper) { | 169 | 22.5k | mid = (lower + upper) >> 1; | 170 | 22.5k | if (array[mid] == min) { | 171 | 4.33k | return mid; | 172 | 18.2k | } else if (array[mid] < min) { | 173 | 9.19k | lower = mid; | 174 | 9.19k | } else { | 175 | 9.03k | upper = mid; | 176 | 9.03k | } | 177 | 22.5k | } | 178 | 4.01k | return upper; | 179 | 8.34k | } |
Unexecuted instantiation: array.c:advanceUntil Unexecuted instantiation: bitset.c:advanceUntil Unexecuted instantiation: containers.c:advanceUntil Unexecuted instantiation: convert.c:advanceUntil mixed_intersection.c:advanceUntil Line | Count | Source | 137 | 128k | int32_t length, uint16_t min) { | 138 | 128k | int32_t lower = pos + 1; | 139 | | | 140 | 128k | if ((lower >= length) || (array[lower] >= min)) { | 141 | 72.8k | return lower; | 142 | 72.8k | } | 143 | | | 144 | 55.3k | int32_t spansize = 1; | 145 | | | 146 | 131k | while ((lower + spansize < length) && (array[lower + spansize] < min)) { | 147 | 76.1k | spansize <<= 1; | 148 | 76.1k | } | 149 | 55.3k | int32_t upper = (lower + spansize < length) ? lower + spansize : length - 1; | 150 | | | 151 | 55.3k | if (array[upper] == min) { | 152 | 26.8k | return upper; | 153 | 26.8k | } | 154 | 28.4k | if (array[upper] < min) { | 155 | | // means | 156 | | // array | 157 | | // has no | 158 | | // item | 159 | | // >= min | 160 | | // pos = array.length; | 161 | 538 | return length; | 162 | 538 | } | 163 | | | 164 | | // we know that the next-smallest span was too small | 165 | 27.9k | lower += (spansize >> 1); | 166 | | | 167 | 27.9k | int32_t mid = 0; | 168 | 49.4k | while (lower + 1 != upper) { | 169 | 33.6k | mid = (lower + upper) >> 1; | 170 | 33.6k | if (array[mid] == min) { | 171 | 12.1k | return mid; | 172 | 21.5k | } else if (array[mid] < min) { | 173 | 8.12k | lower = mid; | 174 | 13.4k | } else { | 175 | 13.4k | upper = mid; | 176 | 13.4k | } | 177 | 33.6k | } | 178 | 15.8k | return upper; | 179 | 27.9k | } |
Unexecuted instantiation: mixed_union.c:advanceUntil Unexecuted instantiation: mixed_equal.c:advanceUntil mixed_subset.c:advanceUntil Line | Count | Source | 137 | 380 | int32_t length, uint16_t min) { | 138 | 380 | int32_t lower = pos + 1; | 139 | | | 140 | 380 | if ((lower >= length) || (array[lower] >= min)) { | 141 | 192 | return lower; | 142 | 192 | } | 143 | | | 144 | 188 | int32_t spansize = 1; | 145 | | | 146 | 922 | while ((lower + spansize < length) && (array[lower + spansize] < min)) { | 147 | 734 | spansize <<= 1; | 148 | 734 | } | 149 | 188 | int32_t upper = (lower + spansize < length) ? lower + spansize : length - 1; | 150 | | | 151 | 188 | if (array[upper] == min) { | 152 | 0 | return upper; | 153 | 0 | } | 154 | 188 | if (array[upper] < min) { | 155 | | // means | 156 | | // array | 157 | | // has no | 158 | | // item | 159 | | // >= min | 160 | | // pos = array.length; | 161 | 10 | return length; | 162 | 10 | } | 163 | | | 164 | | // we know that the next-smallest span was too small | 165 | 178 | lower += (spansize >> 1); | 166 | | | 167 | 178 | int32_t mid = 0; | 168 | 638 | while (lower + 1 != upper) { | 169 | 460 | mid = (lower + upper) >> 1; | 170 | 460 | if (array[mid] == min) { | 171 | 0 | return mid; | 172 | 460 | } else if (array[mid] < min) { | 173 | 270 | lower = mid; | 174 | 270 | } else { | 175 | 190 | upper = mid; | 176 | 190 | } | 177 | 460 | } | 178 | 178 | return upper; | 179 | 178 | } |
Unexecuted instantiation: mixed_negation.c:advanceUntil Unexecuted instantiation: mixed_xor.c:advanceUntil mixed_andnot.c:advanceUntil Line | Count | Source | 137 | 89.9k | int32_t length, uint16_t min) { | 138 | 89.9k | int32_t lower = pos + 1; | 139 | | | 140 | 89.9k | if ((lower >= length) || (array[lower] >= min)) { | 141 | 77.0k | return lower; | 142 | 77.0k | } | 143 | | | 144 | 12.8k | int32_t spansize = 1; | 145 | | | 146 | 25.9k | while ((lower + spansize < length) && (array[lower + spansize] < min)) { | 147 | 13.0k | spansize <<= 1; | 148 | 13.0k | } | 149 | 12.8k | int32_t upper = (lower + spansize < length) ? lower + spansize : length - 1; | 150 | | | 151 | 12.8k | if (array[upper] == min) { | 152 | 6.37k | return upper; | 153 | 6.37k | } | 154 | 6.48k | if (array[upper] < min) { | 155 | | // means | 156 | | // array | 157 | | // has no | 158 | | // item | 159 | | // >= min | 160 | | // pos = array.length; | 161 | 446 | return length; | 162 | 446 | } | 163 | | | 164 | | // we know that the next-smallest span was too small | 165 | 6.04k | lower += (spansize >> 1); | 166 | | | 167 | 6.04k | int32_t mid = 0; | 168 | 9.31k | while (lower + 1 != upper) { | 169 | 5.41k | mid = (lower + upper) >> 1; | 170 | 5.41k | if (array[mid] == min) { | 171 | 2.14k | return mid; | 172 | 3.27k | } else if (array[mid] < min) { | 173 | 1.15k | lower = mid; | 174 | 2.11k | } else { | 175 | 2.11k | upper = mid; | 176 | 2.11k | } | 177 | 5.41k | } | 178 | 3.90k | return upper; | 179 | 6.04k | } |
Unexecuted instantiation: run.c:advanceUntil Unexecuted instantiation: croaring_fuzzer.c:advanceUntil Unexecuted instantiation: roaring64.c:advanceUntil |
180 | | |
181 | | /** |
182 | | * Returns number of elements which are less than ikey. |
183 | | * Array elements must be unique and sorted. |
184 | | */ |
185 | | static inline int32_t count_less(const uint16_t *array, int32_t lenarray, |
186 | 15.2k | uint16_t ikey) { |
187 | 15.2k | if (lenarray == 0) return 0; |
188 | 12.2k | int32_t pos = binarySearch(array, lenarray, ikey); |
189 | 12.2k | return pos >= 0 ? pos : -(pos + 1); |
190 | 15.2k | } Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::count_less(unsigned short const*, int, unsigned short) Line | Count | Source | 186 | 15.2k | uint16_t ikey) { | 187 | 15.2k | if (lenarray == 0) return 0; | 188 | 12.2k | int32_t pos = binarySearch(array, lenarray, ikey); | 189 | 12.2k | return pos >= 0 ? pos : -(pos + 1); | 190 | 15.2k | } |
Unexecuted instantiation: roaring_array.c:count_less Unexecuted instantiation: array_util.c:count_less Unexecuted instantiation: array.c:count_less Unexecuted instantiation: bitset.c:count_less Unexecuted instantiation: containers.c:count_less Unexecuted instantiation: convert.c:count_less Unexecuted instantiation: mixed_intersection.c:count_less Unexecuted instantiation: mixed_union.c:count_less Unexecuted instantiation: mixed_equal.c:count_less Unexecuted instantiation: mixed_subset.c:count_less Unexecuted instantiation: mixed_negation.c:count_less Unexecuted instantiation: mixed_xor.c:count_less Unexecuted instantiation: mixed_andnot.c:count_less Unexecuted instantiation: run.c:count_less Unexecuted instantiation: croaring_fuzzer.c:count_less Unexecuted instantiation: roaring64.c:count_less |
191 | | |
192 | | /** |
193 | | * Returns number of elements which are greater than ikey. |
194 | | * Array elements must be unique and sorted. |
195 | | */ |
196 | | static inline int32_t count_greater(const uint16_t *array, int32_t lenarray, |
197 | 8.80k | uint16_t ikey) { |
198 | 8.80k | if (lenarray == 0) return 0; |
199 | 8.80k | int32_t pos = binarySearch(array, lenarray, ikey); |
200 | 8.80k | if (pos >= 0) { |
201 | 1.92k | return lenarray - (pos + 1); |
202 | 6.88k | } else { |
203 | 6.88k | return lenarray - (-pos - 1); |
204 | 6.88k | } |
205 | 8.80k | } Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::count_greater(unsigned short const*, int, unsigned short) Line | Count | Source | 197 | 8.80k | uint16_t ikey) { | 198 | 8.80k | if (lenarray == 0) return 0; | 199 | 8.80k | int32_t pos = binarySearch(array, lenarray, ikey); | 200 | 8.80k | if (pos >= 0) { | 201 | 1.92k | return lenarray - (pos + 1); | 202 | 6.88k | } else { | 203 | 6.88k | return lenarray - (-pos - 1); | 204 | 6.88k | } | 205 | 8.80k | } |
Unexecuted instantiation: roaring_array.c:count_greater Unexecuted instantiation: array_util.c:count_greater Unexecuted instantiation: array.c:count_greater Unexecuted instantiation: bitset.c:count_greater Unexecuted instantiation: containers.c:count_greater Unexecuted instantiation: convert.c:count_greater Unexecuted instantiation: mixed_intersection.c:count_greater Unexecuted instantiation: mixed_union.c:count_greater Unexecuted instantiation: mixed_equal.c:count_greater Unexecuted instantiation: mixed_subset.c:count_greater Unexecuted instantiation: mixed_negation.c:count_greater Unexecuted instantiation: mixed_xor.c:count_greater Unexecuted instantiation: mixed_andnot.c:count_greater Unexecuted instantiation: run.c:count_greater Unexecuted instantiation: croaring_fuzzer.c:count_greater Unexecuted instantiation: roaring64.c:count_greater |
206 | | |
207 | | /** |
208 | | * From Schlegel et al., Fast Sorted-Set Intersection using SIMD Instructions |
209 | | * Optimized by D. Lemire on May 3rd 2013 |
210 | | * |
211 | | * C should have capacity greater than the minimum of s_1 and s_b + 8 |
212 | | * where 8 is sizeof(__m128i)/sizeof(uint16_t). |
213 | | */ |
214 | | int32_t intersect_vector16(const uint16_t *A, size_t s_a, const uint16_t *B, |
215 | | size_t s_b, uint16_t *C); |
216 | | |
217 | | int32_t intersect_vector16_inplace(uint16_t *A, size_t s_a, const uint16_t *B, |
218 | | size_t s_b); |
219 | | |
220 | | /** |
221 | | * Take an array container and write it out to a 32-bit array, using base |
222 | | * as the offset. |
223 | | */ |
224 | | int array_container_to_uint32_array_vector16(void *vout, const uint16_t *array, |
225 | | size_t cardinality, uint32_t base); |
226 | | #if CROARING_COMPILER_SUPPORTS_AVX512 |
227 | | int avx512_array_container_to_uint32_array(void *vout, const uint16_t *array, |
228 | | size_t cardinality, uint32_t base); |
229 | | #endif |
230 | | /** |
231 | | * Compute the cardinality of the intersection using SSE4 instructions |
232 | | */ |
233 | | int32_t intersect_vector16_cardinality(const uint16_t *A, size_t s_a, |
234 | | const uint16_t *B, size_t s_b); |
235 | | |
236 | | /* Computes the intersection between one small and one large set of uint16_t. |
237 | | * Stores the result into buffer and return the number of elements. */ |
238 | | int32_t intersect_skewed_uint16(const uint16_t *smallarray, size_t size_s, |
239 | | const uint16_t *largearray, size_t size_l, |
240 | | uint16_t *buffer); |
241 | | |
242 | | /* Computes the size of the intersection between one small and one large set of |
243 | | * uint16_t. */ |
244 | | int32_t intersect_skewed_uint16_cardinality(const uint16_t *smallarray, |
245 | | size_t size_s, |
246 | | const uint16_t *largearray, |
247 | | size_t size_l); |
248 | | |
249 | | /* Check whether the size of the intersection between one small and one large |
250 | | * set of uint16_t is non-zero. */ |
251 | | bool intersect_skewed_uint16_nonempty(const uint16_t *smallarray, size_t size_s, |
252 | | const uint16_t *largearray, |
253 | | size_t size_l); |
254 | | /** |
255 | | * Generic intersection function. |
256 | | */ |
257 | | int32_t intersect_uint16(const uint16_t *A, const size_t lenA, |
258 | | const uint16_t *B, const size_t lenB, uint16_t *out); |
259 | | /** |
260 | | * Compute the size of the intersection (generic). |
261 | | */ |
262 | | int32_t intersect_uint16_cardinality(const uint16_t *A, const size_t lenA, |
263 | | const uint16_t *B, const size_t lenB); |
264 | | |
265 | | /** |
266 | | * Checking whether the size of the intersection is non-zero. |
267 | | */ |
268 | | bool intersect_uint16_nonempty(const uint16_t *A, const size_t lenA, |
269 | | const uint16_t *B, const size_t lenB); |
270 | | /** |
271 | | * Generic union function. |
272 | | */ |
273 | | size_t union_uint16(const uint16_t *set_1, size_t size_1, const uint16_t *set_2, |
274 | | size_t size_2, uint16_t *buffer); |
275 | | |
276 | | /** |
277 | | * Generic XOR function. |
278 | | */ |
279 | | int32_t xor_uint16(const uint16_t *array_1, int32_t card_1, |
280 | | const uint16_t *array_2, int32_t card_2, uint16_t *out); |
281 | | |
282 | | /** |
283 | | * Generic difference function (ANDNOT). |
284 | | */ |
285 | | int difference_uint16(const uint16_t *a1, int length1, const uint16_t *a2, |
286 | | int length2, uint16_t *a_out); |
287 | | |
288 | | /** |
289 | | * Generic intersection function. |
290 | | */ |
291 | | size_t intersection_uint32(const uint32_t *A, const size_t lenA, |
292 | | const uint32_t *B, const size_t lenB, uint32_t *out); |
293 | | |
294 | | /** |
295 | | * Generic intersection function, returns just the cardinality. |
296 | | */ |
297 | | size_t intersection_uint32_card(const uint32_t *A, const size_t lenA, |
298 | | const uint32_t *B, const size_t lenB); |
299 | | |
300 | | /** |
301 | | * Generic union function. |
302 | | */ |
303 | | size_t union_uint32(const uint32_t *set_1, size_t size_1, const uint32_t *set_2, |
304 | | size_t size_2, uint32_t *buffer); |
305 | | |
306 | | /** |
307 | | * A fast SSE-based union function. |
308 | | */ |
309 | | uint32_t union_vector16(const uint16_t *set_1, uint32_t size_1, |
310 | | const uint16_t *set_2, uint32_t size_2, |
311 | | uint16_t *buffer); |
312 | | /** |
313 | | * A fast SSE-based XOR function. |
314 | | */ |
315 | | uint32_t xor_vector16(const uint16_t *array1, uint32_t length1, |
316 | | const uint16_t *array2, uint32_t length2, |
317 | | uint16_t *output); |
318 | | |
319 | | /** |
320 | | * A fast SSE-based difference function. |
321 | | */ |
322 | | int32_t difference_vector16(const uint16_t *A, size_t s_a, const uint16_t *B, |
323 | | size_t s_b, uint16_t *C); |
324 | | |
325 | | /** |
326 | | * Generic union function, returns just the cardinality. |
327 | | */ |
328 | | size_t union_uint32_card(const uint32_t *set_1, size_t size_1, |
329 | | const uint32_t *set_2, size_t size_2); |
330 | | |
331 | | /** |
332 | | * combines union_uint16 and union_vector16 optimally |
333 | | */ |
334 | | size_t fast_union_uint16(const uint16_t *set_1, size_t size_1, |
335 | | const uint16_t *set_2, size_t size_2, |
336 | | uint16_t *buffer); |
337 | | |
338 | | bool memequals(const void *s1, const void *s2, size_t n); |
339 | | |
340 | | #ifdef __cplusplus |
341 | | } |
342 | | } |
343 | | } // extern "C" { namespace roaring { namespace internal { |
344 | | #endif |
345 | | #if defined(__GNUC__) && !defined(__clang__) |
346 | | #pragma GCC diagnostic pop |
347 | | #endif |
348 | | #endif |