Coverage Report

Created: 2026-05-30 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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)
roaring.c:advanceUntil
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)
roaring.c:count_less
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)
roaring.c:count_greater
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