Coverage Report

Created: 2026-01-09 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/croaring/include/roaring/array_util.h
Line
Count
Source
1
#ifndef CROARING_ARRAY_UTIL_H
2
#define CROARING_ARRAY_UTIL_H
3
4
#include <stddef.h>  // for size_t
5
#include <stdint.h>
6
7
#include <roaring/portability.h>
8
9
#if CROARING_IS_X64
10
#ifndef CROARING_COMPILER_SUPPORTS_AVX512
11
#error "CROARING_COMPILER_SUPPORTS_AVX512 needs to be defined."
12
#endif  // CROARING_COMPILER_SUPPORTS_AVX512
13
#endif
14
#if defined(__GNUC__) && !defined(__clang__)
15
#pragma GCC diagnostic push
16
#pragma GCC diagnostic ignored "-Wuninitialized"
17
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
18
#endif
19
#ifdef __cplusplus
20
extern "C" {
21
namespace roaring {
22
namespace internal {
23
#endif
24
25
/*
26
 *  Good old binary search.
27
 *  Assumes that array is sorted, has logarithmic complexity.
28
 *  if the result is x, then:
29
 *     if ( x>0 )  you have array[x] = ikey
30
 *     if ( x<0 ) then inserting ikey at position -x-1 in array (insuring that
31
 * array[-x-1]=ikey) keys the array sorted.
32
 */
33
inline int32_t binarySearch(const uint16_t *array, int32_t lenarray,
34
7.05M
                            uint16_t ikey) {
35
7.05M
    int32_t low = 0;
36
7.05M
    int32_t high = lenarray - 1;
37
33.8M
    while (low <= high) {
38
32.0M
        int32_t middleIndex = (low + high) >> 1;
39
32.0M
        uint16_t middleValue = array[middleIndex];
40
32.0M
        if (middleValue < ikey) {
41
10.0M
            low = middleIndex + 1;
42
21.9M
        } else if (middleValue > ikey) {
43
16.7M
            high = middleIndex - 1;
44
16.7M
        } else {
45
5.24M
            return middleIndex;
46
5.24M
        }
47
32.0M
    }
48
1.81M
    return -(low + 1);
49
7.05M
}
50
51
/**
52
 * Galloping search
53
 * Assumes that array is sorted, has logarithmic complexity.
54
 * if the result is x, then if x = length, you have that all values in array
55
 * between pos and length are smaller than min. otherwise returns the first
56
 * index x such that array[x] >= min.
57
 */
58
static inline int32_t advanceUntil(const uint16_t *array, int32_t pos,
59
233k
                                   int32_t length, uint16_t min) {
60
233k
    int32_t lower = pos + 1;
61
62
233k
    if ((lower >= length) || (array[lower] >= min)) {
63
152k
        return lower;
64
152k
    }
65
66
81.1k
    int32_t spansize = 1;
67
68
214k
    while ((lower + spansize < length) && (array[lower + spansize] < min)) {
69
133k
        spansize <<= 1;
70
133k
    }
71
81.1k
    int32_t upper = (lower + spansize < length) ? lower + spansize : length - 1;
72
73
81.1k
    if (array[upper] == min) {
74
35.1k
        return upper;
75
35.1k
    }
76
45.9k
    if (array[upper] < min) {
77
        // means
78
        // array
79
        // has no
80
        // item
81
        // >= min
82
        // pos = array.length;
83
1.13k
        return length;
84
1.13k
    }
85
86
    // we know that the next-smallest span was too small
87
44.8k
    lower += (spansize >> 1);
88
89
44.8k
    int32_t mid = 0;
90
89.1k
    while (lower + 1 != upper) {
91
64.4k
        mid = (lower + upper) >> 1;
92
64.4k
        if (array[mid] == min) {
93
20.2k
            return mid;
94
44.2k
        } else if (array[mid] < min) {
95
18.6k
            lower = mid;
96
25.6k
        } else {
97
25.6k
            upper = mid;
98
25.6k
        }
99
64.4k
    }
100
24.6k
    return upper;
101
44.8k
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::advanceUntil(unsigned short const*, int, int, unsigned short)
roaring.c:advanceUntil
Line
Count
Source
59
490
                                   int32_t length, uint16_t min) {
60
490
    int32_t lower = pos + 1;
61
62
490
    if ((lower >= length) || (array[lower] >= min)) {
63
490
        return lower;
64
490
    }
65
66
0
    int32_t spansize = 1;
67
68
0
    while ((lower + spansize < length) && (array[lower + spansize] < min)) {
69
0
        spansize <<= 1;
70
0
    }
71
0
    int32_t upper = (lower + spansize < length) ? lower + spansize : length - 1;
72
73
0
    if (array[upper] == min) {
74
0
        return upper;
75
0
    }
76
0
    if (array[upper] < min) {
77
        // means
78
        // array
79
        // has no
80
        // item
81
        // >= min
82
        // pos = array.length;
83
0
        return length;
84
0
    }
85
86
    // we know that the next-smallest span was too small
87
0
    lower += (spansize >> 1);
88
89
0
    int32_t mid = 0;
90
0
    while (lower + 1 != upper) {
91
0
        mid = (lower + upper) >> 1;
92
0
        if (array[mid] == min) {
93
0
            return mid;
94
0
        } else if (array[mid] < min) {
95
0
            lower = mid;
96
0
        } else {
97
0
            upper = mid;
98
0
        }
99
0
    }
100
0
    return upper;
101
0
}
Unexecuted instantiation: roaring_array.c:advanceUntil
array_util.c:advanceUntil
Line
Count
Source
59
16.7k
                                   int32_t length, uint16_t min) {
60
16.7k
    int32_t lower = pos + 1;
61
62
16.7k
    if ((lower >= length) || (array[lower] >= min)) {
63
5.49k
        return lower;
64
5.49k
    }
65
66
11.2k
    int32_t spansize = 1;
67
68
50.2k
    while ((lower + spansize < length) && (array[lower + spansize] < min)) {
69
38.9k
        spansize <<= 1;
70
38.9k
    }
71
11.2k
    int32_t upper = (lower + spansize < length) ? lower + spansize : length - 1;
72
73
11.2k
    if (array[upper] == min) {
74
2.70k
        return upper;
75
2.70k
    }
76
8.56k
    if (array[upper] < min) {
77
        // means
78
        // array
79
        // has no
80
        // item
81
        // >= min
82
        // pos = array.length;
83
214
        return length;
84
214
    }
85
86
    // we know that the next-smallest span was too small
87
8.35k
    lower += (spansize >> 1);
88
89
8.35k
    int32_t mid = 0;
90
26.8k
    while (lower + 1 != upper) {
91
23.1k
        mid = (lower + upper) >> 1;
92
23.1k
        if (array[mid] == min) {
93
4.63k
            return mid;
94
18.5k
        } else if (array[mid] < min) {
95
9.22k
            lower = mid;
96
9.30k
        } else {
97
9.30k
            upper = mid;
98
9.30k
        }
99
23.1k
    }
100
3.71k
    return upper;
101
8.35k
}
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
59
128k
                                   int32_t length, uint16_t min) {
60
128k
    int32_t lower = pos + 1;
61
62
128k
    if ((lower >= length) || (array[lower] >= min)) {
63
71.7k
        return lower;
64
71.7k
    }
65
66
56.7k
    int32_t spansize = 1;
67
68
136k
    while ((lower + spansize < length) && (array[lower + spansize] < min)) {
69
80.1k
        spansize <<= 1;
70
80.1k
    }
71
56.7k
    int32_t upper = (lower + spansize < length) ? lower + spansize : length - 1;
72
73
56.7k
    if (array[upper] == min) {
74
26.1k
        return upper;
75
26.1k
    }
76
30.5k
    if (array[upper] < min) {
77
        // means
78
        // array
79
        // has no
80
        // item
81
        // >= min
82
        // pos = array.length;
83
516
        return length;
84
516
    }
85
86
    // we know that the next-smallest span was too small
87
30.0k
    lower += (spansize >> 1);
88
89
30.0k
    int32_t mid = 0;
90
51.9k
    while (lower + 1 != upper) {
91
35.3k
        mid = (lower + upper) >> 1;
92
35.3k
        if (array[mid] == min) {
93
13.4k
            return mid;
94
21.8k
        } else if (array[mid] < min) {
95
8.00k
            lower = mid;
96
13.8k
        } else {
97
13.8k
            upper = mid;
98
13.8k
        }
99
35.3k
    }
100
16.5k
    return upper;
101
30.0k
}
Unexecuted instantiation: mixed_union.c:advanceUntil
Unexecuted instantiation: mixed_equal.c:advanceUntil
mixed_subset.c:advanceUntil
Line
Count
Source
59
438
                                   int32_t length, uint16_t min) {
60
438
    int32_t lower = pos + 1;
61
62
438
    if ((lower >= length) || (array[lower] >= min)) {
63
224
        return lower;
64
224
    }
65
66
214
    int32_t spansize = 1;
67
68
1.05k
    while ((lower + spansize < length) && (array[lower + spansize] < min)) {
69
840
        spansize <<= 1;
70
840
    }
71
214
    int32_t upper = (lower + spansize < length) ? lower + spansize : length - 1;
72
73
214
    if (array[upper] == min) {
74
0
        return upper;
75
0
    }
76
214
    if (array[upper] < min) {
77
        // means
78
        // array
79
        // has no
80
        // item
81
        // >= min
82
        // pos = array.length;
83
6
        return length;
84
6
    }
85
86
    // we know that the next-smallest span was too small
87
208
    lower += (spansize >> 1);
88
89
208
    int32_t mid = 0;
90
770
    while (lower + 1 != upper) {
91
562
        mid = (lower + upper) >> 1;
92
562
        if (array[mid] == min) {
93
0
            return mid;
94
562
        } else if (array[mid] < min) {
95
288
            lower = mid;
96
288
        } else {
97
274
            upper = mid;
98
274
        }
99
562
    }
100
208
    return upper;
101
208
}
Unexecuted instantiation: mixed_negation.c:advanceUntil
Unexecuted instantiation: mixed_xor.c:advanceUntil
mixed_andnot.c:advanceUntil
Line
Count
Source
59
87.1k
                                   int32_t length, uint16_t min) {
60
87.1k
    int32_t lower = pos + 1;
61
62
87.1k
    if ((lower >= length) || (array[lower] >= min)) {
63
74.2k
        return lower;
64
74.2k
    }
65
66
12.9k
    int32_t spansize = 1;
67
68
26.1k
    while ((lower + spansize < length) && (array[lower + spansize] < min)) {
69
13.2k
        spansize <<= 1;
70
13.2k
    }
71
12.9k
    int32_t upper = (lower + spansize < length) ? lower + spansize : length - 1;
72
73
12.9k
    if (array[upper] == min) {
74
6.28k
        return upper;
75
6.28k
    }
76
6.66k
    if (array[upper] < min) {
77
        // means
78
        // array
79
        // has no
80
        // item
81
        // >= min
82
        // pos = array.length;
83
403
        return length;
84
403
    }
85
86
    // we know that the next-smallest span was too small
87
6.26k
    lower += (spansize >> 1);
88
89
6.26k
    int32_t mid = 0;
90
9.57k
    while (lower + 1 != upper) {
91
5.46k
        mid = (lower + upper) >> 1;
92
5.46k
        if (array[mid] == min) {
93
2.15k
            return mid;
94
3.31k
        } else if (array[mid] < min) {
95
1.13k
            lower = mid;
96
2.17k
        } else {
97
2.17k
            upper = mid;
98
2.17k
        }
99
5.46k
    }
100
4.10k
    return upper;
101
6.26k
}
Unexecuted instantiation: run.c:advanceUntil
Unexecuted instantiation: croaring_fuzzer.c:advanceUntil
Unexecuted instantiation: roaring64.c:advanceUntil
102
103
/**
104
 * Returns number of elements which are less than ikey.
105
 * Array elements must be unique and sorted.
106
 */
107
static inline int32_t count_less(const uint16_t *array, int32_t lenarray,
108
14.6k
                                 uint16_t ikey) {
109
14.6k
    if (lenarray == 0) return 0;
110
11.9k
    int32_t pos = binarySearch(array, lenarray, ikey);
111
11.9k
    return pos >= 0 ? pos : -(pos + 1);
112
14.6k
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::count_less(unsigned short const*, int, unsigned short)
roaring.c:count_less
Line
Count
Source
108
14.6k
                                 uint16_t ikey) {
109
14.6k
    if (lenarray == 0) return 0;
110
11.9k
    int32_t pos = binarySearch(array, lenarray, ikey);
111
11.9k
    return pos >= 0 ? pos : -(pos + 1);
112
14.6k
}
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
113
114
/**
115
 * Returns number of elements which are greater than ikey.
116
 * Array elements must be unique and sorted.
117
 */
118
static inline int32_t count_greater(const uint16_t *array, int32_t lenarray,
119
8.62k
                                    uint16_t ikey) {
120
8.62k
    if (lenarray == 0) return 0;
121
8.62k
    int32_t pos = binarySearch(array, lenarray, ikey);
122
8.62k
    if (pos >= 0) {
123
1.86k
        return lenarray - (pos + 1);
124
6.76k
    } else {
125
6.76k
        return lenarray - (-pos - 1);
126
6.76k
    }
127
8.62k
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::count_greater(unsigned short const*, int, unsigned short)
roaring.c:count_greater
Line
Count
Source
119
8.62k
                                    uint16_t ikey) {
120
8.62k
    if (lenarray == 0) return 0;
121
8.62k
    int32_t pos = binarySearch(array, lenarray, ikey);
122
8.62k
    if (pos >= 0) {
123
1.86k
        return lenarray - (pos + 1);
124
6.76k
    } else {
125
6.76k
        return lenarray - (-pos - 1);
126
6.76k
    }
127
8.62k
}
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
128
129
/**
130
 * From Schlegel et al., Fast Sorted-Set Intersection using SIMD Instructions
131
 * Optimized by D. Lemire on May 3rd 2013
132
 *
133
 * C should have capacity greater than the minimum of s_1 and s_b + 8
134
 * where 8 is sizeof(__m128i)/sizeof(uint16_t).
135
 */
136
int32_t intersect_vector16(const uint16_t *__restrict__ A, size_t s_a,
137
                           const uint16_t *__restrict__ B, size_t s_b,
138
                           uint16_t *C);
139
140
int32_t intersect_vector16_inplace(uint16_t *__restrict__ A, size_t s_a,
141
                                   const uint16_t *__restrict__ B, size_t s_b);
142
143
/**
144
 * Take an array container and write it out to a 32-bit array, using base
145
 * as the offset.
146
 */
147
int array_container_to_uint32_array_vector16(void *vout, const uint16_t *array,
148
                                             size_t cardinality, uint32_t base);
149
#if CROARING_COMPILER_SUPPORTS_AVX512
150
int avx512_array_container_to_uint32_array(void *vout, const uint16_t *array,
151
                                           size_t cardinality, uint32_t base);
152
#endif
153
/**
154
 * Compute the cardinality of the intersection using SSE4 instructions
155
 */
156
int32_t intersect_vector16_cardinality(const uint16_t *__restrict__ A,
157
                                       size_t s_a,
158
                                       const uint16_t *__restrict__ B,
159
                                       size_t s_b);
160
161
/* Computes the intersection between one small and one large set of uint16_t.
162
 * Stores the result into buffer and return the number of elements. */
163
int32_t intersect_skewed_uint16(const uint16_t *smallarray, size_t size_s,
164
                                const uint16_t *largearray, size_t size_l,
165
                                uint16_t *buffer);
166
167
/* Computes the size of the intersection between one small and one large set of
168
 * uint16_t. */
169
int32_t intersect_skewed_uint16_cardinality(const uint16_t *smallarray,
170
                                            size_t size_s,
171
                                            const uint16_t *largearray,
172
                                            size_t size_l);
173
174
/* Check whether the size of the intersection between one small and one large
175
 * set of uint16_t is non-zero. */
176
bool intersect_skewed_uint16_nonempty(const uint16_t *smallarray, size_t size_s,
177
                                      const uint16_t *largearray,
178
                                      size_t size_l);
179
/**
180
 * Generic intersection function.
181
 */
182
int32_t intersect_uint16(const uint16_t *A, const size_t lenA,
183
                         const uint16_t *B, const size_t lenB, uint16_t *out);
184
/**
185
 * Compute the size of the intersection (generic).
186
 */
187
int32_t intersect_uint16_cardinality(const uint16_t *A, const size_t lenA,
188
                                     const uint16_t *B, const size_t lenB);
189
190
/**
191
 * Checking whether the size of the intersection  is non-zero.
192
 */
193
bool intersect_uint16_nonempty(const uint16_t *A, const size_t lenA,
194
                               const uint16_t *B, const size_t lenB);
195
/**
196
 * Generic union function.
197
 */
198
size_t union_uint16(const uint16_t *set_1, size_t size_1, const uint16_t *set_2,
199
                    size_t size_2, uint16_t *buffer);
200
201
/**
202
 * Generic XOR function.
203
 */
204
int32_t xor_uint16(const uint16_t *array_1, int32_t card_1,
205
                   const uint16_t *array_2, int32_t card_2, uint16_t *out);
206
207
/**
208
 * Generic difference function (ANDNOT).
209
 */
210
int difference_uint16(const uint16_t *a1, int length1, const uint16_t *a2,
211
                      int length2, uint16_t *a_out);
212
213
/**
214
 * Generic intersection function.
215
 */
216
size_t intersection_uint32(const uint32_t *A, const size_t lenA,
217
                           const uint32_t *B, const size_t lenB, uint32_t *out);
218
219
/**
220
 * Generic intersection function, returns just the cardinality.
221
 */
222
size_t intersection_uint32_card(const uint32_t *A, const size_t lenA,
223
                                const uint32_t *B, const size_t lenB);
224
225
/**
226
 * Generic union function.
227
 */
228
size_t union_uint32(const uint32_t *set_1, size_t size_1, const uint32_t *set_2,
229
                    size_t size_2, uint32_t *buffer);
230
231
/**
232
 * A fast SSE-based union function.
233
 */
234
uint32_t union_vector16(const uint16_t *__restrict__ set_1, uint32_t size_1,
235
                        const uint16_t *__restrict__ set_2, uint32_t size_2,
236
                        uint16_t *__restrict__ buffer);
237
/**
238
 * A fast SSE-based XOR function.
239
 */
240
uint32_t xor_vector16(const uint16_t *__restrict__ array1, uint32_t length1,
241
                      const uint16_t *__restrict__ array2, uint32_t length2,
242
                      uint16_t *__restrict__ output);
243
244
/**
245
 * A fast SSE-based difference function.
246
 */
247
int32_t difference_vector16(const uint16_t *__restrict__ A, size_t s_a,
248
                            const uint16_t *__restrict__ B, size_t s_b,
249
                            uint16_t *C);
250
251
/**
252
 * Generic union function, returns just the cardinality.
253
 */
254
size_t union_uint32_card(const uint32_t *set_1, size_t size_1,
255
                         const uint32_t *set_2, size_t size_2);
256
257
/**
258
 * combines union_uint16 and  union_vector16 optimally
259
 */
260
size_t fast_union_uint16(const uint16_t *set_1, size_t size_1,
261
                         const uint16_t *set_2, size_t size_2,
262
                         uint16_t *buffer);
263
264
bool memequals(const void *s1, const void *s2, size_t n);
265
266
#ifdef __cplusplus
267
}
268
}
269
}  // extern "C" { namespace roaring { namespace internal {
270
#endif
271
#if defined(__GNUC__) && !defined(__clang__)
272
#pragma GCC diagnostic pop
273
#endif
274
#endif