Coverage Report

Created: 2026-10-28 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/croaring/src/containers/array.c
Line
Count
Source
1
/*
2
 * array.c
3
 *
4
 */
5
6
#include <assert.h>
7
#include <stdio.h>
8
#include <stdlib.h>
9
10
#include <roaring/containers/array.h>
11
#include <roaring/memory.h>
12
13
#if CROARING_IS_X64
14
#ifndef CROARING_COMPILER_SUPPORTS_AVX512
15
#error "CROARING_COMPILER_SUPPORTS_AVX512 needs to be defined."
16
#endif  // CROARING_COMPILER_SUPPORTS_AVX512
17
#endif
18
19
#ifdef __cplusplus
20
extern "C" {
21
namespace roaring {
22
namespace internal {
23
#endif
24
25
extern inline uint16_t array_container_minimum(const array_container_t *arr);
26
extern inline uint16_t array_container_maximum(const array_container_t *arr);
27
extern inline int array_container_index_equalorlarger(
28
    const array_container_t *arr, uint16_t x);
29
30
extern inline int array_container_rank(const array_container_t *arr,
31
                                       uint16_t x);
32
extern inline uint32_t array_container_rank_many(const array_container_t *arr,
33
                                                 uint64_t start_rank,
34
                                                 const uint32_t *begin,
35
                                                 const uint32_t *end,
36
                                                 uint64_t *ans);
37
extern inline int array_container_get_index(const array_container_t *arr,
38
                                            uint16_t x);
39
extern inline bool array_container_contains(const array_container_t *arr,
40
                                            uint16_t pos);
41
extern inline int array_container_cardinality(const array_container_t *array);
42
extern inline bool array_container_nonzero_cardinality(
43
    const array_container_t *array);
44
extern inline int32_t array_container_serialized_size_in_bytes(int32_t card);
45
extern inline bool array_container_empty(const array_container_t *array);
46
extern inline bool array_container_full(const array_container_t *array);
47
48
/* Create a new array with capacity size. Return NULL in case of failure. */
49
149k
array_container_t *array_container_create_given_capacity(int32_t size) {
50
149k
    array_container_t *container;
51
52
149k
    if ((container = (array_container_t *)roaring_malloc(
53
149k
             sizeof(array_container_t))) == NULL) {
54
0
        return NULL;
55
0
    }
56
57
149k
    if (size <= 0) {  // we don't want to rely on malloc(0)
58
88.4k
        container->array = NULL;
59
88.4k
    } else if ((container->array = (uint16_t *)roaring_malloc(sizeof(uint16_t) *
60
61.5k
                                                              size)) == NULL) {
61
0
        roaring_free(container);
62
0
        return NULL;
63
0
    }
64
65
149k
    container->capacity = size;
66
149k
    container->cardinality = 0;
67
68
149k
    return container;
69
149k
}
70
71
/* Create a new array. Return NULL in case of failure. */
72
28.9k
array_container_t *array_container_create(void) {
73
28.9k
    return array_container_create_given_capacity(ARRAY_DEFAULT_INIT_SIZE);
74
28.9k
}
75
76
/* Create a new array containing all values in [min,max). */
77
124
array_container_t *array_container_create_range(uint32_t min, uint32_t max) {
78
124
    array_container_t *answer =
79
124
        array_container_create_given_capacity(max - min + 1);
80
124
    if (answer == NULL) return answer;
81
124
    answer->cardinality = 0;
82
248
    for (uint32_t k = min; k < max; k++) {
83
124
        answer->array[answer->cardinality++] = k;
84
124
    }
85
124
    return answer;
86
124
}
87
88
/* Duplicate container */
89
CROARING_ALLOW_UNALIGNED
90
23.5k
array_container_t *array_container_clone(const array_container_t *src) {
91
23.5k
    array_container_t *newcontainer =
92
23.5k
        array_container_create_given_capacity(src->capacity);
93
23.5k
    if (newcontainer == NULL) return NULL;
94
95
23.5k
    newcontainer->cardinality = src->cardinality;
96
97
23.5k
    memcpy(newcontainer->array, src->array,
98
23.5k
           src->cardinality * sizeof(uint16_t));
99
100
23.5k
    return newcontainer;
101
23.5k
}
102
103
void array_container_offset(const array_container_t *c, container_t **loc,
104
0
                            container_t **hic, uint16_t offset) {
105
0
    array_container_t *lo = NULL, *hi = NULL;
106
0
    int top, lo_cap, hi_cap;
107
108
0
    top = (1 << 16) - offset;
109
110
0
    const uint16_t *array = c->array;
111
0
    lo_cap = count_less(array, c->cardinality, top);
112
0
    if (loc && lo_cap) {
113
0
        lo = array_container_create_given_capacity(lo_cap);
114
0
        uint16_t *out = lo->array;
115
0
        for (int i = 0; i < lo_cap; ++i) {
116
0
            out[i] = array[i] + offset;
117
0
        }
118
0
        lo->cardinality = lo_cap;
119
0
        *loc = (container_t *)lo;
120
0
    }
121
122
0
    hi_cap = c->cardinality - lo_cap;
123
0
    if (hic && hi_cap) {
124
0
        hi = array_container_create_given_capacity(hi_cap);
125
0
        uint16_t *out = hi->array;
126
0
        for (int i = 0; i < hi_cap; ++i) {
127
0
            out[i] = array[lo_cap + i] + offset;
128
0
        }
129
0
        hi->cardinality = hi_cap;
130
0
        *hic = (container_t *)hi;
131
0
    }
132
0
}
133
134
4.76k
int array_container_shrink_to_fit(array_container_t *src) {
135
4.76k
    if (src->cardinality == src->capacity) return 0;  // nothing to do
136
4.21k
    int savings = src->capacity - src->cardinality;
137
4.21k
    src->capacity = src->cardinality;
138
4.21k
    if (src->capacity ==
139
4.21k
        0) {  // we do not want to rely on realloc for zero allocs
140
0
        roaring_free(src->array);
141
0
        src->array = NULL;
142
4.21k
    } else {
143
4.21k
        uint16_t *oldarray = src->array;
144
4.21k
        src->array = (uint16_t *)roaring_realloc(
145
4.21k
            oldarray, src->capacity * sizeof(uint16_t));
146
4.21k
        if (src->array == NULL) roaring_free(oldarray);  // should never happen?
147
4.21k
    }
148
4.21k
    return savings;
149
4.76k
}
150
151
/* Free memory. */
152
149k
void array_container_free(array_container_t *arr) {
153
149k
    if (arr == NULL) return;
154
149k
    roaring_free(arr->array);
155
149k
    roaring_free(arr);
156
149k
}
157
158
127k
static inline int32_t grow_capacity(int32_t capacity) {
159
127k
    return (capacity <= 0)   ? ARRAY_DEFAULT_INIT_SIZE
160
127k
           : capacity < 64   ? capacity * 2
161
98.3k
           : capacity < 1024 ? capacity * 3 / 2
162
23.9k
                             : capacity * 5 / 4;
163
127k
}
164
165
127k
static inline int32_t clamp(int32_t val, int32_t min, int32_t max) {
166
127k
    return ((val < min) ? min : (val > max) ? max : val);
167
127k
}
168
169
void array_container_grow(array_container_t *container, int32_t min,
170
127k
                          bool preserve) {
171
127k
    int32_t max = (min <= DEFAULT_MAX_SIZE ? DEFAULT_MAX_SIZE : 65536);
172
127k
    int32_t new_capacity = clamp(grow_capacity(container->capacity), min, max);
173
174
127k
    container->capacity = new_capacity;
175
127k
    uint16_t *array = container->array;
176
177
127k
    if (preserve) {
178
115k
        container->array =
179
115k
            (uint16_t *)roaring_realloc(array, new_capacity * sizeof(uint16_t));
180
115k
        if (container->array == NULL) roaring_free(array);
181
115k
    } else {
182
11.6k
        roaring_free(array);
183
11.6k
        container->array =
184
11.6k
            (uint16_t *)roaring_malloc(new_capacity * sizeof(uint16_t));
185
11.6k
    }
186
187
    // if realloc fails, we have container->array == NULL.
188
127k
}
189
190
/* Copy one container into another. We assume that they are distinct. */
191
void array_container_copy(const array_container_t *src,
192
16
                          array_container_t *dst) {
193
16
    const int32_t cardinality = src->cardinality;
194
16
    if (cardinality > dst->capacity) {
195
16
        array_container_grow(dst, cardinality, false);
196
16
    }
197
198
16
    dst->cardinality = cardinality;
199
16
    memcpy(dst->array, src->array, cardinality * sizeof(uint16_t));
200
16
}
201
202
void array_container_add_from_range(array_container_t *arr, uint32_t min,
203
0
                                    uint32_t max, uint16_t step) {
204
0
    for (uint32_t value = min; value < max; value += step) {
205
0
        array_container_append(arr, value);
206
0
    }
207
0
}
208
209
/* Computes the union of array1 and array2 and write the result to arrayout.
210
 * It is assumed that arrayout is distinct from both array1 and array2.
211
 */
212
void array_container_union(const array_container_t *array_1,
213
                           const array_container_t *array_2,
214
6.89k
                           array_container_t *out) {
215
6.89k
    const int32_t card_1 = array_1->cardinality, card_2 = array_2->cardinality;
216
6.89k
    const int32_t max_cardinality = card_1 + card_2;
217
218
6.89k
    if (out->capacity < max_cardinality) {
219
0
        array_container_grow(out, max_cardinality, false);
220
0
    }
221
6.89k
    out->cardinality = (int32_t)fast_union_uint16(
222
6.89k
        array_1->array, card_1, array_2->array, card_2, out->array);
223
6.89k
}
224
225
/* Computes the  difference of array1 and array2 and write the result
226
 * to array out.
227
 * Array out does not need to be distinct from array_1
228
 */
229
void array_container_andnot(const array_container_t *array_1,
230
                            const array_container_t *array_2,
231
7.92k
                            array_container_t *out) {
232
7.92k
    if (out->capacity < array_1->cardinality)
233
3.45k
        array_container_grow(out, array_1->cardinality, false);
234
7.92k
#if CROARING_IS_X64
235
    // difference_vector16 only vectorizes while 8 values remain on each
236
    // side, and loses to the galloping scalar code when one side is
237
    // much shorter.
238
7.92k
    const int32_t card_1 = array_1->cardinality, card_2 = array_2->cardinality;
239
7.92k
    const int32_t card_min = card_1 < card_2 ? card_1 : card_2;
240
7.92k
    const int32_t card_max = card_1 < card_2 ? card_2 : card_1;
241
7.92k
    const bool skewed = card_min < 8 || card_min * 128 < card_max;
242
7.92k
    if (!skewed && (croaring_hardware_support() & ROARING_SUPPORTS_AVX2) &&
243
5.03k
        (out != array_1) && (out != array_2)) {
244
2.18k
        out->cardinality = difference_vector16(
245
2.18k
            array_1->array, array_1->cardinality, array_2->array,
246
2.18k
            array_2->cardinality, out->array);
247
5.74k
    } else {
248
5.74k
        out->cardinality =
249
5.74k
            difference_uint16(array_1->array, array_1->cardinality,
250
5.74k
                              array_2->array, array_2->cardinality, out->array);
251
5.74k
    }
252
#else
253
    out->cardinality =
254
        difference_uint16(array_1->array, array_1->cardinality, array_2->array,
255
                          array_2->cardinality, out->array);
256
#endif
257
7.92k
}
258
259
/* Computes the symmetric difference of array1 and array2 and write the
260
 * result
261
 * to arrayout.
262
 * It is assumed that arrayout is distinct from both array1 and array2.
263
 */
264
void array_container_xor(const array_container_t *array_1,
265
                         const array_container_t *array_2,
266
9.28k
                         array_container_t *out) {
267
9.28k
    const int32_t card_1 = array_1->cardinality, card_2 = array_2->cardinality;
268
9.28k
    const int32_t max_cardinality = card_1 + card_2;
269
9.28k
    if (out->capacity < max_cardinality) {
270
0
        array_container_grow(out, max_cardinality, false);
271
0
    }
272
273
9.28k
#if CROARING_IS_X64
274
9.28k
    if (!(card_1 * CROARING_SKEWED_VECTOR_MERGE_RATIO < card_2 ||
275
8.60k
          card_2 * CROARING_SKEWED_VECTOR_MERGE_RATIO < card_1) &&
276
8.29k
        (croaring_hardware_support() & ROARING_SUPPORTS_AVX2)) {
277
8.29k
        out->cardinality =
278
8.29k
            xor_vector16(array_1->array, array_1->cardinality, array_2->array,
279
8.29k
                         array_2->cardinality, out->array);
280
8.29k
    } else {
281
992
        out->cardinality =
282
992
            xor_uint16(array_1->array, array_1->cardinality, array_2->array,
283
992
                       array_2->cardinality, out->array);
284
992
    }
285
#else
286
    out->cardinality =
287
        xor_uint16(array_1->array, array_1->cardinality, array_2->array,
288
                   array_2->cardinality, out->array);
289
#endif
290
9.28k
}
291
292
3.45k
static inline int32_t minimum_int32(int32_t a, int32_t b) {
293
3.45k
    return (a < b) ? a : b;
294
3.45k
}
295
296
/* computes the intersection of array1 and array2 and write the result to
297
 * arrayout.
298
 * It is assumed that arrayout is distinct from both array1 and array2.
299
 * */
300
void array_container_intersection(const array_container_t *array1,
301
                                  const array_container_t *array2,
302
3.45k
                                  array_container_t *out) {
303
3.45k
    int32_t card_1 = array1->cardinality, card_2 = array2->cardinality,
304
3.45k
            min_card = minimum_int32(card_1, card_2);
305
3.45k
    const int threshold = 64;  // subject to tuning
306
3.45k
#if CROARING_IS_X64
307
3.45k
    if (out->capacity < min_card) {
308
3.45k
        array_container_grow(out, min_card + sizeof(__m128i) / sizeof(uint16_t),
309
3.45k
                             false);
310
3.45k
    }
311
#else
312
    if (out->capacity < min_card) {
313
        array_container_grow(out, min_card, false);
314
    }
315
#endif
316
317
3.45k
    if (card_1 * threshold < card_2) {
318
314
        out->cardinality = intersect_skewed_uint16(
319
314
            array1->array, card_1, array2->array, card_2, out->array);
320
3.14k
    } else if (card_2 * threshold < card_1) {
321
192
        out->cardinality = intersect_skewed_uint16(
322
192
            array2->array, card_2, array1->array, card_1, out->array);
323
2.94k
    } else {
324
2.94k
#if CROARING_IS_X64
325
2.94k
        if (croaring_hardware_support() & ROARING_SUPPORTS_AVX2) {
326
2.94k
            out->cardinality = intersect_vector16(
327
2.94k
                array1->array, card_1, array2->array, card_2, out->array);
328
2.94k
        } else {
329
0
            out->cardinality = intersect_uint16(
330
0
                array1->array, card_1, array2->array, card_2, out->array);
331
0
        }
332
#else
333
        out->cardinality = intersect_uint16(array1->array, card_1,
334
                                            array2->array, card_2, out->array);
335
#endif
336
2.94k
    }
337
3.45k
}
338
339
/* computes the size of the intersection of array1 and array2
340
 * */
341
int array_container_intersection_cardinality(const array_container_t *array1,
342
13.8k
                                             const array_container_t *array2) {
343
13.8k
    int32_t card_1 = array1->cardinality, card_2 = array2->cardinality;
344
13.8k
    const int threshold = 64;  // subject to tuning
345
13.8k
    if (card_1 * threshold < card_2) {
346
1.25k
        return intersect_skewed_uint16_cardinality(array1->array, card_1,
347
1.25k
                                                   array2->array, card_2);
348
12.5k
    } else if (card_2 * threshold < card_1) {
349
768
        return intersect_skewed_uint16_cardinality(array2->array, card_2,
350
768
                                                   array1->array, card_1);
351
11.7k
    } else {
352
11.7k
#if CROARING_IS_X64
353
11.7k
        if (croaring_hardware_support() & ROARING_SUPPORTS_AVX2) {
354
11.7k
            return intersect_vector16_cardinality(array1->array, card_1,
355
11.7k
                                                  array2->array, card_2);
356
11.7k
        } else {
357
0
            return intersect_uint16_cardinality(array1->array, card_1,
358
0
                                                array2->array, card_2);
359
0
        }
360
#else
361
        return intersect_uint16_cardinality(array1->array, card_1,
362
                                            array2->array, card_2);
363
#endif
364
11.7k
    }
365
13.8k
}
366
367
bool array_container_intersect(const array_container_t *array1,
368
3.45k
                               const array_container_t *array2) {
369
3.45k
    int32_t card_1 = array1->cardinality, card_2 = array2->cardinality;
370
3.45k
    const int threshold = 64;  // subject to tuning
371
3.45k
    if (card_1 * threshold < card_2) {
372
314
        return intersect_skewed_uint16_nonempty(array1->array, card_1,
373
314
                                                array2->array, card_2);
374
3.14k
    } else if (card_2 * threshold < card_1) {
375
192
        return intersect_skewed_uint16_nonempty(array2->array, card_2,
376
192
                                                array1->array, card_1);
377
2.94k
    } else {
378
        // we do not bother vectorizing
379
2.94k
        return intersect_uint16_nonempty(array1->array, card_1, array2->array,
380
2.94k
                                         card_2);
381
2.94k
    }
382
3.45k
}
383
384
/* computes the intersection of array1 and array2 and write the result to
385
 * array1.
386
 * */
387
void array_container_intersection_inplace(array_container_t *src_1,
388
5.67k
                                          const array_container_t *src_2) {
389
5.67k
    int32_t card_1 = src_1->cardinality, card_2 = src_2->cardinality;
390
5.67k
    const int threshold = 64;  // subject to tuning
391
5.67k
    if (card_1 * threshold < card_2) {
392
0
        src_1->cardinality = intersect_skewed_uint16(
393
0
            src_1->array, card_1, src_2->array, card_2, src_1->array);
394
5.67k
    } else if (card_2 * threshold < card_1) {
395
198
        src_1->cardinality = intersect_skewed_uint16(
396
198
            src_2->array, card_2, src_1->array, card_1, src_1->array);
397
5.47k
    } else {
398
5.47k
#if CROARING_IS_X64
399
5.47k
        if (croaring_hardware_support() & ROARING_SUPPORTS_AVX2) {
400
5.47k
            src_1->cardinality = intersect_vector16_inplace(
401
5.47k
                src_1->array, card_1, src_2->array, card_2);
402
5.47k
        } else {
403
0
            src_1->cardinality = intersect_uint16(
404
0
                src_1->array, card_1, src_2->array, card_2, src_1->array);
405
0
        }
406
#else
407
        src_1->cardinality = intersect_uint16(
408
            src_1->array, card_1, src_2->array, card_2, src_1->array);
409
#endif
410
5.47k
    }
411
5.67k
}
412
413
/* Constant n: one or two vector operations on every compiler. */
414
CROARING_ALLOW_UNALIGNED
415
static inline void array_put(uint32_t *out, const uint16_t *array,
416
0
                             uint32_t base, size_t n) {
417
0
    for (size_t k = 0; k < n; ++k) {
418
0
        out[k] = base + array[k];
419
0
    }
420
0
}
421
422
CROARING_ALLOW_UNALIGNED
423
int array_container_to_uint32_array(void *vout, const array_container_t *cont,
424
6.59k
                                    uint32_t base) {
425
6.59k
#if CROARING_IS_X64
426
6.59k
    int support = croaring_hardware_support();
427
6.59k
#if CROARING_COMPILER_SUPPORTS_AVX512
428
6.59k
    if (support & ROARING_SUPPORTS_AVX512) {
429
0
        return avx512_array_container_to_uint32_array(vout, cont->array,
430
0
                                                      cont->cardinality, base);
431
0
    }
432
6.59k
#endif
433
6.59k
    if (support & ROARING_SUPPORTS_AVX2) {
434
6.59k
        return array_container_to_uint32_array_vector16(
435
6.59k
            vout, cont->array, cont->cardinality, base);
436
6.59k
    }
437
0
#endif  // CROARING_IS_X64
438
0
    const size_t cardinality = (size_t)cont->cardinality;
439
0
    const uint16_t *array = cont->array;
440
    // Typed stores vectorize on every compiler; all callers but
441
    // roaring_bitmap_serialize pass an aligned vout.
442
0
    if (cardinality >= 4 && ((uintptr_t)vout & 3) == 0) {
443
0
        uint32_t *out = (uint32_t *)vout;
444
0
        uint32_t *out_end = out + cardinality;
445
0
        const uint16_t *array_end = array + cardinality;
446
0
        if (cardinality < 8) {  // overlapping writes end at cardinality
447
0
            array_put(out, array, base, 4);
448
0
            array_put(out_end - 4, array_end - 4, base, 4);
449
0
            return (int)cardinality;
450
0
        }
451
0
        const size_t full = cardinality & ~(size_t)15;
452
0
        for (size_t i = 0; i < full; i += 16) {
453
0
            array_put(out + i, array + i, base, 16);
454
0
        }
455
0
        if (cardinality - full > 8) {
456
0
            array_put(out + full, array + full, base, 8);
457
0
        }
458
0
        if (full != cardinality) {
459
0
            array_put(out_end - 8, array_end - 8, base, 8);
460
0
        }
461
0
        return (int)cardinality;
462
0
    }
463
0
    int outpos = 0;
464
0
    uint32_t *out = (uint32_t *)vout;
465
0
    size_t i = 0;
466
0
    for (; i < (size_t)cont->cardinality; ++i) {
467
0
        const uint32_t val = base + cont->array[i];
468
0
        memcpy(out + outpos, &val,
469
0
               sizeof(uint32_t));  // should be compiled as a MOV on x64
470
0
        outpos++;
471
0
    }
472
0
    return outpos;
473
0
}
474
475
0
void array_container_printf(const array_container_t *v) {
476
0
    if (v->cardinality == 0) {
477
0
        printf("{}");
478
0
        return;
479
0
    }
480
0
    printf("{");
481
0
    printf("%d", v->array[0]);
482
0
    for (int i = 1; i < v->cardinality; ++i) {
483
0
        printf(",%d", v->array[i]);
484
0
    }
485
0
    printf("}");
486
0
}
487
488
void array_container_printf_as_uint32_array(const array_container_t *v,
489
0
                                            uint32_t base) {
490
0
    if (v->cardinality == 0) {
491
0
        return;
492
0
    }
493
0
    printf("%u", v->array[0] + base);
494
0
    for (int i = 1; i < v->cardinality; ++i) {
495
0
        printf(",%u", v->array[i] + base);
496
0
    }
497
0
}
498
499
/*
500
 * Validate the container. Returns true if valid.
501
 */
502
CROARING_ALLOW_UNALIGNED
503
0
bool array_container_validate(const array_container_t *v, const char **reason) {
504
0
    if (v->capacity < 0) {
505
0
        *reason = "negative capacity";
506
0
        return false;
507
0
    }
508
0
    if (v->cardinality < 0) {
509
0
        *reason = "negative cardinality";
510
0
        return false;
511
0
    }
512
0
    if (v->cardinality > v->capacity) {
513
0
        *reason = "cardinality exceeds capacity";
514
0
        return false;
515
0
    }
516
0
    if (v->cardinality > DEFAULT_MAX_SIZE) {
517
0
        *reason = "cardinality exceeds DEFAULT_MAX_SIZE";
518
0
        return false;
519
0
    }
520
0
    if (v->cardinality == 0) {
521
0
        *reason = "zero cardinality";
522
0
        return false;
523
0
    }
524
525
0
    if (v->array == NULL) {
526
0
        *reason = "NULL array pointer";
527
0
        return false;
528
0
    }
529
0
    uint16_t prev = v->array[0];
530
0
    for (int i = 1; i < v->cardinality; ++i) {
531
0
        if (v->array[i] <= prev) {
532
0
            *reason = "array elements not strictly increasing";
533
0
            return false;
534
0
        }
535
0
        prev = v->array[i];
536
0
    }
537
538
0
    return true;
539
0
}
540
541
/* Compute the number of runs */
542
14.3k
int32_t array_container_number_of_runs(const array_container_t *ac) {
543
14.3k
    const uint16_t *array = ac->array;
544
14.3k
    const int32_t card = ac->cardinality;
545
14.3k
    if (card == 0) return 0;
546
    // Every value starts a run unless it follows its predecessor. The values
547
    // are strictly increasing, so array[i - 1] + 1 cannot wrap around to a
548
    // match. The loop has no branch on the data and compilers vectorize it.
549
14.3k
    int32_t continuing = 0;
550
1.54M
    for (int32_t i = 1; i < card; ++i) {
551
1.53M
        continuing += (array[i] == (uint16_t)(array[i - 1] + 1));
552
1.53M
    }
553
14.3k
    return card - continuing;
554
14.3k
}
555
556
/**
557
 * Writes the underlying array to buf, outputs how many bytes were written.
558
 * The number of bytes written should be
559
 * array_container_size_in_bytes(container).
560
 *
561
 */
562
7.66k
int32_t array_container_write(const array_container_t *container, char *buf) {
563
#if CROARING_IS_BIG_ENDIAN
564
    for (int32_t i = 0; i < container->cardinality; ++i) {
565
        uint16_t v_le = croaring_htole16(container->array[i]);
566
        memcpy(buf + i * sizeof(uint16_t), &v_le, sizeof(uint16_t));
567
    }
568
#else
569
7.66k
    memcpy(buf, container->array, container->cardinality * sizeof(uint16_t));
570
7.66k
#endif
571
7.66k
    return array_container_size_in_bytes(container);
572
7.66k
}
573
574
CROARING_ALLOW_UNALIGNED
575
bool array_container_is_subset(const array_container_t *container1,
576
7.18k
                               const array_container_t *container2) {
577
7.18k
    if (container1->cardinality > container2->cardinality) {
578
1.20k
        return false;
579
1.20k
    }
580
5.98k
    int i1 = 0, i2 = 0;
581
45.6k
    while (i1 < container1->cardinality && i2 < container2->cardinality) {
582
45.5k
        if (container1->array[i1] == container2->array[i2]) {
583
0
            i1++;
584
0
            i2++;
585
45.5k
        } else if (container1->array[i1] > container2->array[i2]) {
586
39.6k
            i2++;
587
39.6k
        } else {  // container1->array[i1] < container2->array[i2]
588
5.95k
            return false;
589
5.95k
        }
590
45.5k
    }
591
30
    if (i1 == container1->cardinality) {
592
0
        return true;
593
30
    } else {
594
30
        return false;
595
30
    }
596
30
}
597
598
int32_t array_container_read(int32_t cardinality, array_container_t *container,
599
7.71k
                             const char *buf) {
600
7.71k
    if (container->capacity < cardinality) {
601
0
        array_container_grow(container, cardinality, false);
602
0
    }
603
7.71k
    container->cardinality = cardinality;
604
#if CROARING_IS_BIG_ENDIAN
605
    for (int32_t i = 0; i < cardinality; ++i) {
606
        uint16_t v_le;
607
        memcpy(&v_le, buf + i * sizeof(uint16_t), sizeof(uint16_t));
608
        container->array[i] = croaring_letoh16(v_le);
609
    }
610
#else
611
7.71k
    memcpy(container->array, buf, container->cardinality * sizeof(uint16_t));
612
7.71k
#endif
613
614
7.71k
    return array_container_size_in_bytes(container);
615
7.71k
}
616
617
CROARING_ALLOW_UNALIGNED
618
bool array_container_iterate(const array_container_t *cont, uint32_t base,
619
7.26k
                             roaring_iterator iterator, void *ptr) {
620
2.37M
    for (int i = 0; i < cont->cardinality; i++)
621
2.36M
        if (!iterator(cont->array[i] + base, ptr)) return false;
622
7.26k
    return true;
623
7.26k
}
624
625
CROARING_ALLOW_UNALIGNED
626
bool array_container_iterate64(const array_container_t *cont, uint32_t base,
627
                               roaring_iterator64 iterator, uint64_t high_bits,
628
0
                               void *ptr) {
629
0
    for (int i = 0; i < cont->cardinality; i++)
630
0
        if (!iterator(high_bits | (uint64_t)(cont->array[i] + base), ptr))
631
0
            return false;
632
0
    return true;
633
0
}
634
635
#ifdef __cplusplus
636
}
637
}
638
}  // extern "C" { namespace roaring { namespace internal {
639
#endif