Coverage Report

Created: 2026-06-10 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/croaring/include/roaring/containers/array.h
Line
Count
Source
1
/*
2
 * array.h
3
 *
4
 * Array containers store a sparse set of 16-bit integers as a sorted dynamic
5
 * array. The cardinality field tracks how many values are present, capacity
6
 * tracks the allocated length, and array points to the sorted values.
7
 *
8
 * This representation is used for low-cardinality containers because it is
9
 * compact and supports fast iteration and binary-search-based membership
10
 * tests. When the number of stored values grows beyond DEFAULT_MAX_SIZE,
11
 * CRoaring will typically switch to a denser container representation.
12
 */
13
14
#ifndef INCLUDE_CONTAINERS_ARRAY_H_
15
#define INCLUDE_CONTAINERS_ARRAY_H_
16
17
#include <string.h>
18
19
#include <roaring/roaring_types.h>  // roaring_iterator
20
21
// Include other headers after roaring_types.h
22
#include <roaring/array_util.h>  // binarySearch()/memequals() for inlining
23
#include <roaring/containers/container_defs.h>  // container_t, perfparameters
24
#include <roaring/portability.h>
25
26
#ifdef __cplusplus
27
extern "C" {
28
namespace roaring {
29
30
// Note: in pure C++ code, you should avoid putting `using` in header files
31
using api::roaring_iterator;
32
using api::roaring_iterator64;
33
34
namespace internal {
35
#endif
36
37
/* Containers with DEFAULT_MAX_SIZE or less integers should be arrays */
38
enum { DEFAULT_MAX_SIZE = 4096 };
39
40
/* struct array_container - sparse representation of a bitmap
41
 *
42
 * @cardinality: number of indices in `array` (and the bitmap)
43
 * @capacity:    allocated size of `array`
44
 * @array:       sorted list of integers
45
 */
46
STRUCT_CONTAINER(array_container_s) {
47
    int32_t cardinality;
48
    int32_t capacity;
49
    uint16_t *array;
50
};
51
52
typedef struct array_container_s array_container_t;
53
54
7.48M
#define CAST_array(c) CAST(array_container_t *, c)  // safer downcast
55
700k
#define const_CAST_array(c) CAST(const array_container_t *, c)
56
#define movable_CAST_array(c) movable_CAST(array_container_t **, c)
57
58
/* Create a new array with default. Return NULL in case of failure. See also
59
 * array_container_create_given_capacity. */
60
array_container_t *array_container_create(void);
61
62
/* Create a new array with a specified capacity size. Return NULL in case of
63
 * failure. */
64
array_container_t *array_container_create_given_capacity(int32_t size);
65
66
/* Create a new array containing all values in [min,max). */
67
array_container_t *array_container_create_range(uint32_t min, uint32_t max);
68
69
/*
70
 * Shrink the capacity to the actual size, return the number of bytes saved.
71
 */
72
int array_container_shrink_to_fit(array_container_t *src);
73
74
/* Free memory owned by `array'. */
75
void array_container_free(array_container_t *array);
76
77
/* Duplicate container */
78
array_container_t *array_container_clone(const array_container_t *src);
79
80
/* Get the cardinality of `array'. */
81
CROARING_ALLOW_UNALIGNED
82
94.3k
static inline int array_container_cardinality(const array_container_t *array) {
83
94.3k
    return array->cardinality;
84
94.3k
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_cardinality(roaring::internal::array_container_s const*)
roaring.c:array_container_cardinality
Line
Count
Source
82
71.7k
static inline int array_container_cardinality(const array_container_t *array) {
83
71.7k
    return array->cardinality;
84
71.7k
}
roaring_array.c:array_container_cardinality
Line
Count
Source
82
7.20k
static inline int array_container_cardinality(const array_container_t *array) {
83
7.20k
    return array->cardinality;
84
7.20k
}
Unexecuted instantiation: array.c:array_container_cardinality
Unexecuted instantiation: bitset.c:array_container_cardinality
Unexecuted instantiation: containers.c:array_container_cardinality
convert.c:array_container_cardinality
Line
Count
Source
82
15.0k
static inline int array_container_cardinality(const array_container_t *array) {
83
15.0k
    return array->cardinality;
84
15.0k
}
Unexecuted instantiation: mixed_intersection.c:array_container_cardinality
Unexecuted instantiation: mixed_union.c:array_container_cardinality
Unexecuted instantiation: mixed_equal.c:array_container_cardinality
Unexecuted instantiation: mixed_subset.c:array_container_cardinality
Unexecuted instantiation: mixed_negation.c:array_container_cardinality
Unexecuted instantiation: mixed_xor.c:array_container_cardinality
mixed_andnot.c:array_container_cardinality
Line
Count
Source
82
368
static inline int array_container_cardinality(const array_container_t *array) {
83
368
    return array->cardinality;
84
368
}
Unexecuted instantiation: croaring_fuzzer.c:array_container_cardinality
Unexecuted instantiation: roaring64.c:array_container_cardinality
85
86
static inline bool array_container_nonzero_cardinality(
87
104k
    const array_container_t *array) {
88
104k
    return array->cardinality > 0;
89
104k
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_nonzero_cardinality(roaring::internal::array_container_s const*)
roaring.c:array_container_nonzero_cardinality
Line
Count
Source
87
104k
    const array_container_t *array) {
88
104k
    return array->cardinality > 0;
89
104k
}
Unexecuted instantiation: roaring_array.c:array_container_nonzero_cardinality
Unexecuted instantiation: array.c:array_container_nonzero_cardinality
Unexecuted instantiation: bitset.c:array_container_nonzero_cardinality
Unexecuted instantiation: containers.c:array_container_nonzero_cardinality
Unexecuted instantiation: convert.c:array_container_nonzero_cardinality
Unexecuted instantiation: mixed_intersection.c:array_container_nonzero_cardinality
Unexecuted instantiation: mixed_union.c:array_container_nonzero_cardinality
Unexecuted instantiation: mixed_equal.c:array_container_nonzero_cardinality
Unexecuted instantiation: mixed_subset.c:array_container_nonzero_cardinality
Unexecuted instantiation: mixed_negation.c:array_container_nonzero_cardinality
Unexecuted instantiation: mixed_xor.c:array_container_nonzero_cardinality
Unexecuted instantiation: mixed_andnot.c:array_container_nonzero_cardinality
Unexecuted instantiation: croaring_fuzzer.c:array_container_nonzero_cardinality
Unexecuted instantiation: roaring64.c:array_container_nonzero_cardinality
90
91
/* Copy one container into another. We assume that they are distinct. */
92
void array_container_copy(const array_container_t *src, array_container_t *dst);
93
94
/*  Add all the values in [min,max) (included) at a distance k*step from min.
95
    The container must have a size less or equal to DEFAULT_MAX_SIZE after this
96
   addition. */
97
void array_container_add_from_range(array_container_t *arr, uint32_t min,
98
                                    uint32_t max, uint16_t step);
99
100
7.28M
static inline bool array_container_empty(const array_container_t *array) {
101
7.28M
    return array->cardinality == 0;
102
7.28M
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_empty(roaring::internal::array_container_s const*)
roaring.c:array_container_empty
Line
Count
Source
100
7.28M
static inline bool array_container_empty(const array_container_t *array) {
101
7.28M
    return array->cardinality == 0;
102
7.28M
}
Unexecuted instantiation: roaring_array.c:array_container_empty
Unexecuted instantiation: array.c:array_container_empty
Unexecuted instantiation: bitset.c:array_container_empty
Unexecuted instantiation: containers.c:array_container_empty
Unexecuted instantiation: convert.c:array_container_empty
mixed_intersection.c:array_container_empty
Line
Count
Source
100
31
static inline bool array_container_empty(const array_container_t *array) {
101
31
    return array->cardinality == 0;
102
31
}
Unexecuted instantiation: mixed_union.c:array_container_empty
Unexecuted instantiation: mixed_equal.c:array_container_empty
Unexecuted instantiation: mixed_subset.c:array_container_empty
Unexecuted instantiation: mixed_negation.c:array_container_empty
Unexecuted instantiation: mixed_xor.c:array_container_empty
Unexecuted instantiation: mixed_andnot.c:array_container_empty
Unexecuted instantiation: croaring_fuzzer.c:array_container_empty
Unexecuted instantiation: roaring64.c:array_container_empty
103
104
/* check whether the cardinality is equal to the capacity (this does not mean
105
 * that it contains 1<<16 elements) */
106
1.76M
static inline bool array_container_full(const array_container_t *array) {
107
1.76M
    return array->cardinality == array->capacity;
108
1.76M
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_full(roaring::internal::array_container_s const*)
roaring.c:array_container_full
Line
Count
Source
106
1.76M
static inline bool array_container_full(const array_container_t *array) {
107
1.76M
    return array->cardinality == array->capacity;
108
1.76M
}
Unexecuted instantiation: roaring_array.c:array_container_full
Unexecuted instantiation: array.c:array_container_full
Unexecuted instantiation: bitset.c:array_container_full
Unexecuted instantiation: containers.c:array_container_full
Unexecuted instantiation: convert.c:array_container_full
Unexecuted instantiation: mixed_intersection.c:array_container_full
Unexecuted instantiation: mixed_union.c:array_container_full
Unexecuted instantiation: mixed_equal.c:array_container_full
Unexecuted instantiation: mixed_subset.c:array_container_full
Unexecuted instantiation: mixed_negation.c:array_container_full
Unexecuted instantiation: mixed_xor.c:array_container_full
Unexecuted instantiation: mixed_andnot.c:array_container_full
Unexecuted instantiation: croaring_fuzzer.c:array_container_full
Unexecuted instantiation: roaring64.c:array_container_full
109
110
/* Compute the union of `src_1' and `src_2' and write the result to `dst'
111
 * It is assumed that `dst' is distinct from both `src_1' and `src_2'. */
112
void array_container_union(const array_container_t *src_1,
113
                           const array_container_t *src_2,
114
                           array_container_t *dst);
115
116
/* symmetric difference, see array_container_union */
117
void array_container_xor(const array_container_t *array_1,
118
                         const array_container_t *array_2,
119
                         array_container_t *out);
120
121
/* Computes the intersection of src_1 and src_2 and write the result to
122
 * dst. It is assumed that dst is distinct from both src_1 and src_2. */
123
void array_container_intersection(const array_container_t *src_1,
124
                                  const array_container_t *src_2,
125
                                  array_container_t *dst);
126
127
/* Check whether src_1 and src_2 intersect. */
128
bool array_container_intersect(const array_container_t *src_1,
129
                               const array_container_t *src_2);
130
131
/* computers the size of the intersection between two arrays.
132
 */
133
int array_container_intersection_cardinality(const array_container_t *src_1,
134
                                             const array_container_t *src_2);
135
136
/* computes the intersection of array1 and array2 and write the result to
137
 * array1.
138
 * */
139
void array_container_intersection_inplace(array_container_t *src_1,
140
                                          const array_container_t *src_2);
141
142
/*
143
 * Write out the 16-bit integers contained in this container as a list of 32-bit
144
 * integers using base
145
 * as the starting value (it might be expected that base has zeros in its 16
146
 * least significant bits).
147
 * The function returns the number of values written.
148
 * The caller is responsible for allocating enough memory in out.
149
 */
150
int array_container_to_uint32_array(void *vout, const array_container_t *cont,
151
                                    uint32_t base);
152
153
/* Compute the number of runs */
154
int32_t array_container_number_of_runs(const array_container_t *ac);
155
156
/*
157
 * Print this container using printf (useful for debugging).
158
 */
159
void array_container_printf(const array_container_t *v);
160
161
/*
162
 * Print this container using printf as a comma-separated list of 32-bit
163
 * integers starting at base.
164
 */
165
void array_container_printf_as_uint32_array(const array_container_t *v,
166
                                            uint32_t base);
167
168
bool array_container_validate(const array_container_t *v, const char **reason);
169
170
/**
171
 * Return the serialized size in bytes of a container having cardinality "card".
172
 */
173
151k
static inline int32_t array_container_serialized_size_in_bytes(int32_t card) {
174
151k
    return card * sizeof(uint16_t);
175
151k
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_serialized_size_in_bytes(int)
Unexecuted instantiation: roaring.c:array_container_serialized_size_in_bytes
Unexecuted instantiation: roaring_array.c:array_container_serialized_size_in_bytes
Unexecuted instantiation: array.c:array_container_serialized_size_in_bytes
Unexecuted instantiation: bitset.c:array_container_serialized_size_in_bytes
Unexecuted instantiation: containers.c:array_container_serialized_size_in_bytes
convert.c:array_container_serialized_size_in_bytes
Line
Count
Source
173
151k
static inline int32_t array_container_serialized_size_in_bytes(int32_t card) {
174
151k
    return card * sizeof(uint16_t);
175
151k
}
Unexecuted instantiation: mixed_intersection.c:array_container_serialized_size_in_bytes
Unexecuted instantiation: mixed_union.c:array_container_serialized_size_in_bytes
Unexecuted instantiation: mixed_equal.c:array_container_serialized_size_in_bytes
Unexecuted instantiation: mixed_subset.c:array_container_serialized_size_in_bytes
Unexecuted instantiation: mixed_negation.c:array_container_serialized_size_in_bytes
Unexecuted instantiation: mixed_xor.c:array_container_serialized_size_in_bytes
Unexecuted instantiation: mixed_andnot.c:array_container_serialized_size_in_bytes
Unexecuted instantiation: croaring_fuzzer.c:array_container_serialized_size_in_bytes
Unexecuted instantiation: roaring64.c:array_container_serialized_size_in_bytes
176
177
/**
178
 * Increase capacity to at least min.
179
 * Whether the existing data needs to be copied over depends on the "preserve"
180
 * parameter. If preserve is false, then the new content will be uninitialized,
181
 * otherwise the old content is copied.
182
 */
183
void array_container_grow(array_container_t *container, int32_t min,
184
                          bool preserve);
185
186
bool array_container_iterate(const array_container_t *cont, uint32_t base,
187
                             roaring_iterator iterator, void *ptr);
188
bool array_container_iterate64(const array_container_t *cont, uint32_t base,
189
                               roaring_iterator64 iterator, uint64_t high_bits,
190
                               void *ptr);
191
192
/**
193
 * Writes the underlying array to buf, outputs how many bytes were written.
194
 * This is meant to be byte-by-byte compatible with the Java and Go versions of
195
 * Roaring.
196
 * The number of bytes written should be
197
 * array_container_size_in_bytes(container).
198
 *
199
 */
200
int32_t array_container_write(const array_container_t *container, char *buf);
201
/**
202
 * Reads the instance from buf, outputs how many bytes were read.
203
 * This is meant to be byte-by-byte compatible with the Java and Go versions of
204
 * Roaring.
205
 * The number of bytes read should be array_container_size_in_bytes(container).
206
 * You need to provide the (known) cardinality.
207
 */
208
int32_t array_container_read(int32_t cardinality, array_container_t *container,
209
                             const char *buf);
210
211
/**
212
 * Return the serialized size in bytes of a container (see
213
 * bitset_container_write)
214
 * This is meant to be compatible with the Java and Go versions of Roaring and
215
 * assumes
216
 * that the cardinality of the container is already known.
217
 *
218
 */
219
CROARING_ALLOW_UNALIGNED
220
static inline int32_t array_container_size_in_bytes(
221
32.6k
    const array_container_t *container) {
222
32.6k
    return container->cardinality * sizeof(uint16_t);
223
32.6k
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_size_in_bytes(roaring::internal::array_container_s const*)
Unexecuted instantiation: roaring.c:array_container_size_in_bytes
roaring_array.c:array_container_size_in_bytes
Line
Count
Source
221
18.1k
    const array_container_t *container) {
222
18.1k
    return container->cardinality * sizeof(uint16_t);
223
18.1k
}
array.c:array_container_size_in_bytes
Line
Count
Source
221
14.4k
    const array_container_t *container) {
222
14.4k
    return container->cardinality * sizeof(uint16_t);
223
14.4k
}
Unexecuted instantiation: bitset.c:array_container_size_in_bytes
Unexecuted instantiation: containers.c:array_container_size_in_bytes
Unexecuted instantiation: convert.c:array_container_size_in_bytes
Unexecuted instantiation: mixed_intersection.c:array_container_size_in_bytes
Unexecuted instantiation: mixed_union.c:array_container_size_in_bytes
Unexecuted instantiation: mixed_equal.c:array_container_size_in_bytes
Unexecuted instantiation: mixed_subset.c:array_container_size_in_bytes
Unexecuted instantiation: mixed_negation.c:array_container_size_in_bytes
Unexecuted instantiation: mixed_xor.c:array_container_size_in_bytes
Unexecuted instantiation: mixed_andnot.c:array_container_size_in_bytes
Unexecuted instantiation: croaring_fuzzer.c:array_container_size_in_bytes
Unexecuted instantiation: roaring64.c:array_container_size_in_bytes
224
225
/**
226
 * Return true if the two arrays have the same content.
227
 */
228
CROARING_ALLOW_UNALIGNED
229
static inline bool array_container_equals(const array_container_t *container1,
230
9.64k
                                          const array_container_t *container2) {
231
9.64k
    if (container1->cardinality != container2->cardinality) {
232
2.29k
        return false;
233
2.29k
    }
234
7.35k
    return memequals(container1->array, container2->array,
235
7.35k
                     container1->cardinality * 2);
236
9.64k
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_equals(roaring::internal::array_container_s const*, roaring::internal::array_container_s const*)
roaring.c:array_container_equals
Line
Count
Source
230
9.64k
                                          const array_container_t *container2) {
231
9.64k
    if (container1->cardinality != container2->cardinality) {
232
2.29k
        return false;
233
2.29k
    }
234
7.35k
    return memequals(container1->array, container2->array,
235
7.35k
                     container1->cardinality * 2);
236
9.64k
}
Unexecuted instantiation: roaring_array.c:array_container_equals
Unexecuted instantiation: array.c:array_container_equals
Unexecuted instantiation: bitset.c:array_container_equals
Unexecuted instantiation: containers.c:array_container_equals
Unexecuted instantiation: convert.c:array_container_equals
Unexecuted instantiation: mixed_intersection.c:array_container_equals
Unexecuted instantiation: mixed_union.c:array_container_equals
Unexecuted instantiation: mixed_equal.c:array_container_equals
Unexecuted instantiation: mixed_subset.c:array_container_equals
Unexecuted instantiation: mixed_negation.c:array_container_equals
Unexecuted instantiation: mixed_xor.c:array_container_equals
Unexecuted instantiation: mixed_andnot.c:array_container_equals
Unexecuted instantiation: croaring_fuzzer.c:array_container_equals
Unexecuted instantiation: roaring64.c:array_container_equals
237
238
/**
239
 * Return true if container1 is a subset of container2.
240
 */
241
bool array_container_is_subset(const array_container_t *container1,
242
                               const array_container_t *container2);
243
244
/**
245
 * If the element of given rank is in this container, supposing that the first
246
 * element has rank start_rank, then the function returns true and sets element
247
 * accordingly.
248
 * Otherwise, it returns false and update start_rank.
249
 */
250
static inline bool array_container_select(const array_container_t *container,
251
                                          uint32_t *start_rank, uint32_t rank,
252
3.77k
                                          uint32_t *element) {
253
3.77k
    int card = array_container_cardinality(container);
254
3.77k
    if (*start_rank + card <= rank) {
255
324
        *start_rank += card;
256
324
        return false;
257
3.44k
    } else {
258
3.44k
        *element = container->array[rank - *start_rank];
259
3.44k
        return true;
260
3.44k
    }
261
3.77k
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_select(roaring::internal::array_container_s const*, unsigned int*, unsigned int, unsigned int*)
roaring.c:array_container_select
Line
Count
Source
252
3.77k
                                          uint32_t *element) {
253
3.77k
    int card = array_container_cardinality(container);
254
3.77k
    if (*start_rank + card <= rank) {
255
324
        *start_rank += card;
256
324
        return false;
257
3.44k
    } else {
258
3.44k
        *element = container->array[rank - *start_rank];
259
        return true;
260
3.44k
    }
261
3.77k
}
Unexecuted instantiation: roaring_array.c:array_container_select
Unexecuted instantiation: array.c:array_container_select
Unexecuted instantiation: bitset.c:array_container_select
Unexecuted instantiation: containers.c:array_container_select
Unexecuted instantiation: convert.c:array_container_select
Unexecuted instantiation: mixed_intersection.c:array_container_select
Unexecuted instantiation: mixed_union.c:array_container_select
Unexecuted instantiation: mixed_equal.c:array_container_select
Unexecuted instantiation: mixed_subset.c:array_container_select
Unexecuted instantiation: mixed_negation.c:array_container_select
Unexecuted instantiation: mixed_xor.c:array_container_select
Unexecuted instantiation: mixed_andnot.c:array_container_select
Unexecuted instantiation: croaring_fuzzer.c:array_container_select
Unexecuted instantiation: roaring64.c:array_container_select
262
263
/* Computes the  difference of array1 and array2 and write the result
264
 * to array out.
265
 * Array out does not need to be distinct from array_1
266
 */
267
void array_container_andnot(const array_container_t *array_1,
268
                            const array_container_t *array_2,
269
                            array_container_t *out);
270
271
/* Append x to the set. Assumes that the value is larger than any preceding
272
 * values.  */
273
static inline void array_container_append(array_container_t *arr,
274
67.9k
                                          uint16_t pos) {
275
67.9k
    const int32_t capacity = arr->capacity;
276
277
67.9k
    if (array_container_full(arr)) {
278
32.5k
        array_container_grow(arr, capacity + 1, true);
279
32.5k
    }
280
281
67.9k
    arr->array[arr->cardinality++] = pos;
282
67.9k
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_append(roaring::internal::array_container_s*, unsigned short)
roaring.c:array_container_append
Line
Count
Source
274
67.9k
                                          uint16_t pos) {
275
67.9k
    const int32_t capacity = arr->capacity;
276
277
67.9k
    if (array_container_full(arr)) {
278
32.5k
        array_container_grow(arr, capacity + 1, true);
279
32.5k
    }
280
281
67.9k
    arr->array[arr->cardinality++] = pos;
282
67.9k
}
Unexecuted instantiation: roaring_array.c:array_container_append
Unexecuted instantiation: array.c:array_container_append
Unexecuted instantiation: bitset.c:array_container_append
Unexecuted instantiation: containers.c:array_container_append
Unexecuted instantiation: convert.c:array_container_append
Unexecuted instantiation: mixed_intersection.c:array_container_append
Unexecuted instantiation: mixed_union.c:array_container_append
Unexecuted instantiation: mixed_equal.c:array_container_append
Unexecuted instantiation: mixed_subset.c:array_container_append
Unexecuted instantiation: mixed_negation.c:array_container_append
Unexecuted instantiation: mixed_xor.c:array_container_append
Unexecuted instantiation: mixed_andnot.c:array_container_append
Unexecuted instantiation: croaring_fuzzer.c:array_container_append
Unexecuted instantiation: roaring64.c:array_container_append
283
284
/**
285
 * Add value to the set if final cardinality doesn't exceed max_cardinality.
286
 * Return code:
287
 * 1  -- value was added
288
 * 0  -- value was already present
289
 * -1 -- value was not added because cardinality would exceed max_cardinality
290
 */
291
static inline int array_container_try_add(array_container_t *arr,
292
                                          uint16_t value,
293
7.28M
                                          int32_t max_cardinality) {
294
7.28M
    const int32_t cardinality = arr->cardinality;
295
296
    // best case, we can append.
297
7.28M
    if ((array_container_empty(arr) || arr->array[cardinality - 1] < value) &&
298
67.9k
        cardinality < max_cardinality) {
299
67.9k
        array_container_append(arr, value);
300
67.9k
        return 1;
301
67.9k
    }
302
303
7.21M
    const int32_t loc = binarySearch(arr->array, cardinality, value);
304
305
7.21M
    if (loc >= 0) {
306
5.51M
        return 0;
307
5.51M
    } else if (cardinality < max_cardinality) {
308
1.69M
        if (array_container_full(arr)) {
309
76.2k
            array_container_grow(arr, arr->capacity + 1, true);
310
76.2k
        }
311
1.69M
        const int32_t insert_idx = -loc - 1;
312
1.69M
        memmove(arr->array + insert_idx + 1, arr->array + insert_idx,
313
1.69M
                (cardinality - insert_idx) * sizeof(uint16_t));
314
1.69M
        arr->array[insert_idx] = value;
315
1.69M
        arr->cardinality++;
316
1.69M
        return 1;
317
1.69M
    } else {
318
130
        return -1;
319
130
    }
320
7.21M
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_try_add(roaring::internal::array_container_s*, unsigned short, int)
roaring.c:array_container_try_add
Line
Count
Source
293
7.28M
                                          int32_t max_cardinality) {
294
7.28M
    const int32_t cardinality = arr->cardinality;
295
296
    // best case, we can append.
297
7.28M
    if ((array_container_empty(arr) || arr->array[cardinality - 1] < value) &&
298
67.9k
        cardinality < max_cardinality) {
299
67.9k
        array_container_append(arr, value);
300
67.9k
        return 1;
301
67.9k
    }
302
303
7.21M
    const int32_t loc = binarySearch(arr->array, cardinality, value);
304
305
7.21M
    if (loc >= 0) {
306
5.51M
        return 0;
307
5.51M
    } else if (cardinality < max_cardinality) {
308
1.69M
        if (array_container_full(arr)) {
309
76.2k
            array_container_grow(arr, arr->capacity + 1, true);
310
76.2k
        }
311
1.69M
        const int32_t insert_idx = -loc - 1;
312
1.69M
        memmove(arr->array + insert_idx + 1, arr->array + insert_idx,
313
1.69M
                (cardinality - insert_idx) * sizeof(uint16_t));
314
1.69M
        arr->array[insert_idx] = value;
315
1.69M
        arr->cardinality++;
316
1.69M
        return 1;
317
1.69M
    } else {
318
130
        return -1;
319
130
    }
320
7.21M
}
Unexecuted instantiation: roaring_array.c:array_container_try_add
Unexecuted instantiation: array.c:array_container_try_add
Unexecuted instantiation: bitset.c:array_container_try_add
Unexecuted instantiation: containers.c:array_container_try_add
Unexecuted instantiation: convert.c:array_container_try_add
Unexecuted instantiation: mixed_intersection.c:array_container_try_add
Unexecuted instantiation: mixed_union.c:array_container_try_add
Unexecuted instantiation: mixed_equal.c:array_container_try_add
Unexecuted instantiation: mixed_subset.c:array_container_try_add
Unexecuted instantiation: mixed_negation.c:array_container_try_add
Unexecuted instantiation: mixed_xor.c:array_container_try_add
Unexecuted instantiation: mixed_andnot.c:array_container_try_add
Unexecuted instantiation: croaring_fuzzer.c:array_container_try_add
Unexecuted instantiation: roaring64.c:array_container_try_add
321
322
/* Add value to the set. Returns true if x was not already present.  */
323
0
static inline bool array_container_add(array_container_t *arr, uint16_t value) {
324
0
    return array_container_try_add(arr, value, INT32_MAX) == 1;
325
0
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_add(roaring::internal::array_container_s*, unsigned short)
Unexecuted instantiation: roaring.c:array_container_add
Unexecuted instantiation: roaring_array.c:array_container_add
Unexecuted instantiation: array.c:array_container_add
Unexecuted instantiation: bitset.c:array_container_add
Unexecuted instantiation: containers.c:array_container_add
Unexecuted instantiation: convert.c:array_container_add
Unexecuted instantiation: mixed_intersection.c:array_container_add
Unexecuted instantiation: mixed_union.c:array_container_add
Unexecuted instantiation: mixed_equal.c:array_container_add
Unexecuted instantiation: mixed_subset.c:array_container_add
Unexecuted instantiation: mixed_negation.c:array_container_add
Unexecuted instantiation: mixed_xor.c:array_container_add
Unexecuted instantiation: mixed_andnot.c:array_container_add
Unexecuted instantiation: croaring_fuzzer.c:array_container_add
Unexecuted instantiation: roaring64.c:array_container_add
326
327
/* Remove x from the set. Returns true if x was present.  */
328
static inline bool array_container_remove(array_container_t *arr,
329
6.10k
                                          uint16_t pos) {
330
6.10k
    const int32_t idx = binarySearch(arr->array, arr->cardinality, pos);
331
6.10k
    const bool is_present = idx >= 0;
332
6.10k
    if (is_present) {
333
3.07k
        memmove(arr->array + idx, arr->array + idx + 1,
334
3.07k
                (arr->cardinality - idx - 1) * sizeof(uint16_t));
335
3.07k
        arr->cardinality--;
336
3.07k
    }
337
338
6.10k
    return is_present;
339
6.10k
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_remove(roaring::internal::array_container_s*, unsigned short)
roaring.c:array_container_remove
Line
Count
Source
329
6.10k
                                          uint16_t pos) {
330
6.10k
    const int32_t idx = binarySearch(arr->array, arr->cardinality, pos);
331
6.10k
    const bool is_present = idx >= 0;
332
6.10k
    if (is_present) {
333
3.07k
        memmove(arr->array + idx, arr->array + idx + 1,
334
3.07k
                (arr->cardinality - idx - 1) * sizeof(uint16_t));
335
3.07k
        arr->cardinality--;
336
3.07k
    }
337
338
6.10k
    return is_present;
339
6.10k
}
Unexecuted instantiation: roaring_array.c:array_container_remove
Unexecuted instantiation: array.c:array_container_remove
Unexecuted instantiation: bitset.c:array_container_remove
Unexecuted instantiation: containers.c:array_container_remove
Unexecuted instantiation: convert.c:array_container_remove
Unexecuted instantiation: mixed_intersection.c:array_container_remove
Unexecuted instantiation: mixed_union.c:array_container_remove
Unexecuted instantiation: mixed_equal.c:array_container_remove
Unexecuted instantiation: mixed_subset.c:array_container_remove
Unexecuted instantiation: mixed_negation.c:array_container_remove
Unexecuted instantiation: mixed_xor.c:array_container_remove
Unexecuted instantiation: mixed_andnot.c:array_container_remove
Unexecuted instantiation: croaring_fuzzer.c:array_container_remove
Unexecuted instantiation: roaring64.c:array_container_remove
340
341
/* Check whether x is present.  */
342
inline bool array_container_contains(const array_container_t *arr,
343
3.33k
                                     uint16_t pos) {
344
    /**
345
     * SIMD Quad algorithm
346
     * Daniel Lemire, "You can beat the binary search," in Daniel Lemire's blog,
347
     *  April 27, 2026,
348
     * https://lemire.me/blog/2026/04/27/you-can-beat-the-binary-search/.
349
     */
350
3.33k
    const int32_t gap = 16;
351
3.33k
    const uint16_t *carr = arr->array;
352
3.33k
    int32_t cardinality = arr->cardinality;
353
3.33k
    if (cardinality < gap) {
354
1.04k
        for (int32_t j = 0; j < cardinality; j++) {
355
1.01k
            if (carr[j] >= pos) return carr[j] == pos;
356
1.01k
        }
357
29
        return false;
358
948
    }
359
2.38k
    int32_t num_blocks = cardinality / gap;
360
2.38k
    int32_t base = 0;
361
2.38k
    int32_t n = num_blocks;
362
5.48k
    while (n > 3) {
363
3.09k
        int32_t quarter = n >> 2;
364
365
3.09k
        int32_t k1 = carr[(base + quarter + 1) * gap - 1];
366
3.09k
        int32_t k2 = carr[(base + 2 * quarter + 1) * gap - 1];
367
3.09k
        int32_t k3 = carr[(base + 3 * quarter + 1) * gap - 1];
368
369
3.09k
        int32_t c1 = (k1 < pos);
370
3.09k
        int32_t c2 = (k2 < pos);
371
3.09k
        int32_t c3 = (k3 < pos);
372
373
3.09k
        base += (c1 + c2 + c3) * quarter;
374
3.09k
        n -= 3 * quarter;
375
3.09k
    }
376
4.22k
    while (n > 1) {
377
1.84k
        int32_t half = n >> 1;
378
1.84k
        base = (carr[(base + half + 1) * gap - 1] < pos) ? base + half : base;
379
1.84k
        n -= half;
380
1.84k
    }
381
2.38k
    int32_t lo = (carr[(base + 1) * gap - 1] < pos) ? base + 1 : base;
382
383
2.38k
    if (lo < num_blocks) {
384
2.30k
        const uint16_t *blk = carr + lo * gap;
385
#ifdef CROARING_USENEON
386
        uint16x8_t needle = vdupq_n_u16(pos);
387
        uint16x8_t v0 = vld1q_u16(blk);
388
        uint16x8_t v1 = vld1q_u16(blk + 8);
389
        uint16x8_t hit =
390
            vorrq_u16(vceqq_u16(v0, needle), vceqq_u16(v1, needle));
391
        return vmaxvq_u16(hit) != 0;
392
#elif defined(CROARING_IS_X64)
393
        __m128i needle = _mm_set1_epi16((short)pos);
394
2.30k
        __m128i v0 = _mm_loadu_si128((const __m128i *)blk);
395
2.30k
        __m128i v1 = _mm_loadu_si128((const __m128i *)(blk + 8));
396
2.30k
        __m128i hit = _mm_or_si128(_mm_cmpeq_epi16(v0, needle),
397
2.30k
                                   _mm_cmpeq_epi16(v1, needle));
398
2.30k
        return _mm_movemask_epi8(hit) != 0;
399
#else
400
        for (int32_t j = 0; j < gap; j++) {
401
            if (blk[j] >= pos) return blk[j] == pos;
402
        }
403
        return false;
404
#endif
405
2.30k
    }
406
407
603
    for (int32_t j = num_blocks * gap; j < cardinality; j++) {
408
554
        uint16_t v = carr[j];
409
554
        if (v >= pos) return (v == pos);
410
554
    }
411
49
    return false;
412
80
}
413
414
void array_container_offset(const array_container_t *c, container_t **loc,
415
                            container_t **hic, uint16_t offset);
416
417
//* Check whether a range of values from range_start (included) to range_end
418
//(excluded) is present. */
419
static inline bool array_container_contains_range(const array_container_t *arr,
420
                                                  uint32_t range_start,
421
102
                                                  uint32_t range_end) {
422
102
    const int32_t range_count = range_end - range_start;
423
102
    const uint16_t rs_included = (uint16_t)range_start;
424
102
    const uint16_t re_included = (uint16_t)(range_end - 1);
425
426
    // Empty range is always included
427
102
    if (range_count <= 0) {
428
0
        return true;
429
0
    }
430
102
    if (range_count > arr->cardinality) {
431
47
        return false;
432
47
    }
433
434
55
    const int32_t start =
435
55
        binarySearch(arr->array, arr->cardinality, rs_included);
436
    // If this sorted array contains all items in the range:
437
    // * the start item must be found
438
    // * the last item in range range_count must exist, and be the expected end
439
    // value
440
55
    return (start >= 0) && (arr->cardinality >= start + range_count) &&
441
30
           (arr->array[start + range_count - 1] == re_included);
442
102
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_contains_range(roaring::internal::array_container_s const*, unsigned int, unsigned int)
roaring.c:array_container_contains_range
Line
Count
Source
421
102
                                                  uint32_t range_end) {
422
102
    const int32_t range_count = range_end - range_start;
423
102
    const uint16_t rs_included = (uint16_t)range_start;
424
102
    const uint16_t re_included = (uint16_t)(range_end - 1);
425
426
    // Empty range is always included
427
102
    if (range_count <= 0) {
428
0
        return true;
429
0
    }
430
102
    if (range_count > arr->cardinality) {
431
47
        return false;
432
47
    }
433
434
55
    const int32_t start =
435
55
        binarySearch(arr->array, arr->cardinality, rs_included);
436
    // If this sorted array contains all items in the range:
437
    // * the start item must be found
438
    // * the last item in range range_count must exist, and be the expected end
439
    // value
440
55
    return (start >= 0) && (arr->cardinality >= start + range_count) &&
441
30
           (arr->array[start + range_count - 1] == re_included);
442
102
}
Unexecuted instantiation: roaring_array.c:array_container_contains_range
Unexecuted instantiation: array.c:array_container_contains_range
Unexecuted instantiation: bitset.c:array_container_contains_range
Unexecuted instantiation: containers.c:array_container_contains_range
Unexecuted instantiation: convert.c:array_container_contains_range
Unexecuted instantiation: mixed_intersection.c:array_container_contains_range
Unexecuted instantiation: mixed_union.c:array_container_contains_range
Unexecuted instantiation: mixed_equal.c:array_container_contains_range
Unexecuted instantiation: mixed_subset.c:array_container_contains_range
Unexecuted instantiation: mixed_negation.c:array_container_contains_range
Unexecuted instantiation: mixed_xor.c:array_container_contains_range
Unexecuted instantiation: mixed_andnot.c:array_container_contains_range
Unexecuted instantiation: croaring_fuzzer.c:array_container_contains_range
Unexecuted instantiation: roaring64.c:array_container_contains_range
443
444
/* Returns the smallest value (assumes not empty) */
445
3.62k
inline uint16_t array_container_minimum(const array_container_t *arr) {
446
3.62k
    if (arr->cardinality == 0) return 0;
447
3.62k
    return arr->array[0];
448
3.62k
}
449
450
/* Returns the largest value (assumes not empty) */
451
13.3k
inline uint16_t array_container_maximum(const array_container_t *arr) {
452
13.3k
    if (arr->cardinality == 0) return 0;
453
13.3k
    return arr->array[arr->cardinality - 1];
454
13.3k
}
455
456
/* Returns the number of values equal or smaller than x */
457
3.77k
inline int array_container_rank(const array_container_t *arr, uint16_t x) {
458
3.77k
    const int32_t idx = binarySearch(arr->array, arr->cardinality, x);
459
3.77k
    const bool is_present = idx >= 0;
460
3.77k
    if (is_present) {
461
3.18k
        return idx + 1;
462
3.18k
    } else {
463
590
        return -idx - 1;
464
590
    }
465
3.77k
}
466
467
/*  bulk version of array_container_rank(); return number of consumed elements
468
 */
469
inline uint32_t array_container_rank_many(const array_container_t *arr,
470
                                          uint64_t start_rank,
471
                                          const uint32_t *begin,
472
0
                                          const uint32_t *end, uint64_t *ans) {
473
0
    const uint16_t high = (uint16_t)((*begin) >> 16);
474
0
    uint32_t pos = 0;
475
0
    const uint32_t *iter = begin;
476
0
    for (; iter != end; iter++) {
477
0
        uint32_t x = *iter;
478
0
        uint16_t xhigh = (uint16_t)(x >> 16);
479
0
        if (xhigh != high) return iter - begin;  // stop at next container
480
481
0
        const int32_t idx =
482
0
            binarySearch(arr->array + pos, arr->cardinality - pos, (uint16_t)x);
483
0
        const bool is_present = idx >= 0;
484
0
        if (is_present) {
485
0
            *(ans++) = start_rank + pos + (idx + 1);
486
0
            pos = idx + 1;
487
0
        } else {
488
0
            *(ans++) = start_rank + pos + (-idx - 1);
489
0
        }
490
0
    }
491
0
    return iter - begin;
492
0
}
493
494
/* Returns the index of x , if not exsist return -1 */
495
0
inline int array_container_get_index(const array_container_t *arr, uint16_t x) {
496
0
    const int32_t idx = binarySearch(arr->array, arr->cardinality, x);
497
0
    const bool is_present = idx >= 0;
498
0
    if (is_present) {
499
0
        return idx;
500
0
    } else {
501
0
        return -1;
502
0
    }
503
0
}
504
505
/* Returns the index of the first value equal or larger than x, or -1 */
506
inline int array_container_index_equalorlarger(const array_container_t *arr,
507
4.46k
                                               uint16_t x) {
508
4.46k
    const int32_t idx = binarySearch(arr->array, arr->cardinality, x);
509
4.46k
    const bool is_present = idx >= 0;
510
4.46k
    if (is_present) {
511
4.09k
        return idx;
512
4.09k
    } else {
513
373
        int32_t candidate = -idx - 1;
514
373
        if (candidate < arr->cardinality) return candidate;
515
0
        return -1;
516
373
    }
517
4.46k
}
518
519
/*
520
 * Adds all values in range [min,max] using hint:
521
 *   nvals_less is the number of array values less than $min
522
 *   nvals_greater is the number of array values greater than $max
523
 */
524
static inline void array_container_add_range_nvals(array_container_t *array,
525
                                                   uint32_t min, uint32_t max,
526
                                                   int32_t nvals_less,
527
607
                                                   int32_t nvals_greater) {
528
607
    int32_t union_cardinality = nvals_less + (max - min + 1) + nvals_greater;
529
607
    if (union_cardinality > array->capacity) {
530
566
        array_container_grow(array, union_cardinality, true);
531
566
    }
532
607
    memmove(&(array->array[union_cardinality - nvals_greater]),
533
607
            &(array->array[array->cardinality - nvals_greater]),
534
607
            nvals_greater * sizeof(uint16_t));
535
1.49M
    for (uint32_t i = 0; i <= max - min; i++) {
536
1.49M
        array->array[nvals_less + i] = (uint16_t)(min + i);
537
1.49M
    }
538
607
    array->cardinality = union_cardinality;
539
607
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_add_range_nvals(roaring::internal::array_container_s*, unsigned int, unsigned int, int, int)
roaring.c:array_container_add_range_nvals
Line
Count
Source
527
607
                                                   int32_t nvals_greater) {
528
607
    int32_t union_cardinality = nvals_less + (max - min + 1) + nvals_greater;
529
607
    if (union_cardinality > array->capacity) {
530
566
        array_container_grow(array, union_cardinality, true);
531
566
    }
532
607
    memmove(&(array->array[union_cardinality - nvals_greater]),
533
607
            &(array->array[array->cardinality - nvals_greater]),
534
607
            nvals_greater * sizeof(uint16_t));
535
1.49M
    for (uint32_t i = 0; i <= max - min; i++) {
536
1.49M
        array->array[nvals_less + i] = (uint16_t)(min + i);
537
1.49M
    }
538
607
    array->cardinality = union_cardinality;
539
607
}
Unexecuted instantiation: roaring_array.c:array_container_add_range_nvals
Unexecuted instantiation: array.c:array_container_add_range_nvals
Unexecuted instantiation: bitset.c:array_container_add_range_nvals
Unexecuted instantiation: containers.c:array_container_add_range_nvals
Unexecuted instantiation: convert.c:array_container_add_range_nvals
Unexecuted instantiation: mixed_intersection.c:array_container_add_range_nvals
Unexecuted instantiation: mixed_union.c:array_container_add_range_nvals
Unexecuted instantiation: mixed_equal.c:array_container_add_range_nvals
Unexecuted instantiation: mixed_subset.c:array_container_add_range_nvals
Unexecuted instantiation: mixed_negation.c:array_container_add_range_nvals
Unexecuted instantiation: mixed_xor.c:array_container_add_range_nvals
Unexecuted instantiation: mixed_andnot.c:array_container_add_range_nvals
Unexecuted instantiation: croaring_fuzzer.c:array_container_add_range_nvals
Unexecuted instantiation: roaring64.c:array_container_add_range_nvals
540
541
/**
542
 * Adds all values in range [min,max]. This function is currently unused
543
 * and left as a documentation.
544
 */
545
/*static inline void array_container_add_range(array_container_t *array,
546
                                             uint32_t min, uint32_t max) {
547
    int32_t nvals_greater = count_greater(array->array, array->cardinality,
548
max); int32_t nvals_less = count_less(array->array, array->cardinality -
549
nvals_greater, min); array_container_add_range_nvals(array, min, max,
550
nvals_less, nvals_greater);
551
}*/
552
553
/*
554
 * Removes all elements array[pos] .. array[pos+count-1]
555
 */
556
static inline void array_container_remove_range(array_container_t *array,
557
3.23k
                                                uint32_t pos, uint32_t count) {
558
3.23k
    if (count != 0) {
559
336
        memmove(&(array->array[pos]), &(array->array[pos + count]),
560
336
                (array->cardinality - pos - count) * sizeof(uint16_t));
561
336
        array->cardinality -= count;
562
336
    }
563
3.23k
}
Unexecuted instantiation: croaring_fuzzer_cc.cc:roaring::internal::array_container_remove_range(roaring::internal::array_container_s*, unsigned int, unsigned int)
roaring.c:array_container_remove_range
Line
Count
Source
557
3.23k
                                                uint32_t pos, uint32_t count) {
558
3.23k
    if (count != 0) {
559
336
        memmove(&(array->array[pos]), &(array->array[pos + count]),
560
336
                (array->cardinality - pos - count) * sizeof(uint16_t));
561
336
        array->cardinality -= count;
562
336
    }
563
3.23k
}
Unexecuted instantiation: roaring_array.c:array_container_remove_range
Unexecuted instantiation: array.c:array_container_remove_range
Unexecuted instantiation: bitset.c:array_container_remove_range
Unexecuted instantiation: containers.c:array_container_remove_range
Unexecuted instantiation: convert.c:array_container_remove_range
Unexecuted instantiation: mixed_intersection.c:array_container_remove_range
Unexecuted instantiation: mixed_union.c:array_container_remove_range
Unexecuted instantiation: mixed_equal.c:array_container_remove_range
Unexecuted instantiation: mixed_subset.c:array_container_remove_range
Unexecuted instantiation: mixed_negation.c:array_container_remove_range
Unexecuted instantiation: mixed_xor.c:array_container_remove_range
Unexecuted instantiation: mixed_andnot.c:array_container_remove_range
Unexecuted instantiation: croaring_fuzzer.c:array_container_remove_range
Unexecuted instantiation: roaring64.c:array_container_remove_range
564
565
#ifdef __cplusplus
566
}
567
}
568
}  // extern "C" { namespace roaring { namespace internal {
569
#endif
570
571
#endif /* INCLUDE_CONTAINERS_ARRAY_H_ */