• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aviggiano / redis-roaring / 20555685283

28 Dec 2025 03:17PM UTC coverage: 50.0%. First build
20555685283

Pull #137

github

aviggiano
Fix range int array pagination
Pull Request #137: Fix R.RANGEINTARRAY paging for sparse bitmaps

9 of 10 new or added lines in 1 file covered. (90.0%)

507 of 1014 relevant lines covered (50.0%)

3417.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.73
/src/data-structure.c
1
#include <limits.h>
2
#include <math.h>
3
#include "data-structure.h"
4

5
#include "roaring.h"
6
#include "rmalloc.h"
7

8
/* === Internal data structure === */
9

10
Bitmap* bitmap_alloc() {
221✔
11
  return roaring_bitmap_create();
221✔
12
}
13

14
Bitmap64* bitmap64_alloc() {
35✔
15
  return roaring64_bitmap_create();
35✔
16
}
17

18
void bitmap_free(Bitmap* bitmap) {
225✔
19
  roaring_bitmap_free(bitmap);
225✔
20
}
225✔
21

22
void bitmap64_free(Bitmap64* bitmap) {
29✔
23
  roaring64_bitmap_free(bitmap);
29✔
24
}
29✔
25

26
uint64_t bitmap_get_cardinality(const Bitmap* bitmap) {
×
27
  return roaring_bitmap_get_cardinality(bitmap);
×
28
}
29

30
uint64_t bitmap64_get_cardinality(const Bitmap64* bitmap) {
16✔
31
  return roaring64_bitmap_get_cardinality(bitmap);
16✔
32
}
33

34
bool bitmap_setbit(Bitmap* bitmap, uint32_t offset, bool value) {
284✔
35
  if (!value) {
284✔
36
    return roaring_bitmap_remove_checked(bitmap, offset);
100✔
37
  } else {
38
    return !roaring_bitmap_add_checked(bitmap, offset);
184✔
39
  }
40
}
41

42
bool bitmap64_setbit(Bitmap64* bitmap, uint64_t offset, bool value) {
98✔
43
  if (!value) {
98✔
44
    return roaring64_bitmap_remove_checked(bitmap, offset);
9✔
45
  } else {
46
    return !roaring64_bitmap_add_checked(bitmap, offset);
89✔
47
  }
48
}
49

50
bool bitmap_getbit(const Bitmap* bitmap, uint32_t offset) {
216✔
51
  return roaring_bitmap_contains(bitmap, offset);
216✔
52
}
53

54
bool bitmap64_getbit(const Bitmap64* bitmap, uint64_t offset) {
13✔
55
  return roaring64_bitmap_contains(bitmap, offset);
13✔
56
}
57

58
bool* bitmap_getbits(const Bitmap* bitmap, size_t n_offsets, const uint32_t* offsets) {
10✔
59
  if (bitmap == NULL) return NULL;
10✔
60

61
  roaring_bulk_context_t context = CROARING_ZERO_INITIALIZER;
9✔
62

63
  bool* results = rm_malloc(sizeof(bool) * n_offsets);
9✔
64

65
  for (size_t i = 0; i < n_offsets; i++) {
40✔
66
    results[i] = roaring_bitmap_contains_bulk(bitmap, &context, offsets[i]);
31✔
67
  }
68

69
  return results;
9✔
70
}
71

72
bool* bitmap64_getbits(const Bitmap64* bitmap, size_t n_offsets, const uint64_t* offsets) {
10✔
73
  if (bitmap == NULL) return NULL;
10✔
74

75
  roaring64_bulk_context_t context = CROARING_ZERO_INITIALIZER;
9✔
76

77
  bool* results = rm_malloc(sizeof(bool) * n_offsets);
9✔
78

79
  for (size_t i = 0; i < n_offsets; i++) {
40✔
80
    results[i] = roaring64_bitmap_contains_bulk(bitmap, &context, offsets[i]);
31✔
81
  }
82

83
  return results;
9✔
84
}
85

86
bool bitmap_clearbits(Bitmap* bitmap, size_t n_offsets, const uint32_t* offsets) {
6✔
87
  if (bitmap == NULL) return false;
6✔
88
  if (offsets == NULL) return true;
5✔
89

90
  roaring_bitmap_remove_many(bitmap, n_offsets, offsets);
4✔
91

92
  return true;
4✔
93
}
94

95
bool bitmap64_clearbits(Bitmap64* bitmap, size_t n_offsets, const uint64_t* offsets) {
6✔
96
  if (bitmap == NULL) return false;
6✔
97
  if (offsets == NULL) return true;
5✔
98

99
  roaring64_bitmap_remove_many(bitmap, n_offsets, offsets);
4✔
100

101
  return true;
4✔
102
}
103

104
size_t bitmap_clearbits_count(Bitmap* bitmap, size_t n_offsets, const uint32_t* offsets) {
9✔
105
  if (bitmap == NULL || offsets == NULL) return 0;
9✔
106

107
  size_t count = 0;
7✔
108

109
  for (size_t i = 0; i < n_offsets; i++) {
26✔
110
    if (roaring_bitmap_remove_checked(bitmap, offsets[i])) {
19✔
111
      count++;
9✔
112
    }
113
  }
114

115
  return count++;
7✔
116
}
117

118
size_t bitmap64_clearbits_count(Bitmap64* bitmap, size_t n_offsets, const uint64_t* offsets) {
9✔
119
  if (bitmap == NULL || offsets == NULL) return 0;
9✔
120

121
  size_t count = 0;
7✔
122

123
  for (size_t i = 0; i < n_offsets; i++) {
26✔
124
    if (roaring64_bitmap_remove_checked(bitmap, offsets[i])) {
19✔
125
      count++;
9✔
126
    }
127
  }
128

129
  return count++;
7✔
130
}
131

132
bool bitmap_intersect(const Bitmap* b1, const Bitmap* b2, uint32_t mode) {
18✔
133
  if (b1 == NULL || b2 == NULL) return false;
18✔
134

135
  switch (mode) {
15✔
136
  case BITMAP_INTERSECT_MODE_NONE:
4✔
137
    return roaring_bitmap_intersect(b1, b2);
4✔
138

139
  case BITMAP_INTERSECT_MODE_ALL:
4✔
140
    return roaring_bitmap_is_subset(b2, b1);
4✔
141

142
  case BITMAP_INTERSECT_MODE_ALL_STRICT:
4✔
143
    return roaring_bitmap_is_strict_subset(b2, b1);
4✔
144

145
  case BITMAP_INTERSECT_MODE_EQ:
2✔
146
    return roaring_bitmap_equals(b1, b2);
2✔
147

148
  default:
1✔
149
    return false;
1✔
150
  }
151
}
152

153
bool bitmap64_intersect(const Bitmap64* b1, const Bitmap64* b2, uint32_t mode) {
18✔
154
  if (b1 == NULL || b2 == NULL) return false;
18✔
155

156
  switch (mode) {
15✔
157
  case BITMAP_INTERSECT_MODE_NONE:
4✔
158
    return roaring64_bitmap_intersect(b1, b2);
4✔
159

160
  case BITMAP_INTERSECT_MODE_ALL:
4✔
161
    return roaring64_bitmap_is_subset(b2, b1);
4✔
162

163
  case BITMAP_INTERSECT_MODE_ALL_STRICT:
4✔
164
    return roaring64_bitmap_is_strict_subset(b2, b1);
4✔
165

166
  case BITMAP_INTERSECT_MODE_EQ:
2✔
167
    return roaring64_bitmap_equals(b1, b2);
2✔
168

169
  default:
1✔
170
    return false;
1✔
171
  }
172
}
173

174
double bitmap_jaccard(const Bitmap* b1, const Bitmap* b2) {
10✔
175
  if (b1 == NULL || b2 == NULL) return 0;
10✔
176
  if (b1 == b2) return 1;
7✔
177

178
  double res = roaring_bitmap_jaccard_index(b1, b2);
6✔
179

180
  // both bitmaps are empty
181
  if (isnan(res)) res = -1;
6✔
182

183
  return res;
6✔
184
}
185

186
double bitmap64_jaccard(const Bitmap64* b1, const Bitmap64* b2) {
10✔
187
  if (b1 == NULL || b2 == NULL) return 0;
10✔
188
  if (b1 == b2) return 1;
7✔
189

190
  double res = roaring64_bitmap_jaccard_index(b1, b2);
6✔
191

192
  // both bitmaps are empty
193
  if (isnan(res)) res = -1;
6✔
194

195
  return res;
6✔
196
}
197

198
int64_t bitmap_get_nth_element_present(const Bitmap* bitmap, uint64_t n) {
1,030✔
199
  roaring_uint32_iterator_t* iterator = roaring_iterator_create(bitmap);
1,030✔
200
  int64_t element = -1;
1,030✔
201
  for (uint64_t i = 1; iterator->has_value; i++) {
500,964✔
202
    if (i == n) {
500,962✔
203
      element = iterator->current_value;
1,028✔
204
      break;
1,028✔
205
    }
206
    roaring_uint32_iterator_advance(iterator);
499,934✔
207
  }
208
  roaring_uint32_iterator_free(iterator);
1,030✔
209
  return element;
1,030✔
210
}
211

212
uint64_t bitmap64_get_nth_element_present(const Bitmap64* bitmap, uint64_t n, bool* found) {
1,030✔
213
  roaring64_iterator_t* iterator = roaring64_iterator_create(bitmap);
1,030✔
214
  uint64_t element = 0;
1,030✔
215
  for (uint64_t i = 1; roaring64_iterator_has_value(iterator); i++) {
500,964✔
216
    if (i == n) {
500,962✔
217
      element = roaring64_iterator_value(iterator);
1,028✔
218
      *found = true;
1,028✔
219
      break;
1,028✔
220
    }
221
    roaring64_iterator_advance(iterator);
499,934✔
222
  }
223
  roaring64_iterator_free(iterator);
1,030✔
224
  return element;
1,030✔
225
}
226

227
int64_t bitmap_get_nth_element_not_present(const Bitmap* bitmap, uint64_t n) {
1,002✔
228
  roaring_uint32_iterator_t* iterator = roaring_iterator_create(bitmap);
1,002✔
229
  int64_t element = -1;
1,002✔
230
  int64_t last = -1;
1,002✔
231
  for (uint64_t i = 1; iterator->has_value; i++) {
14,568✔
232
    int64_t current = iterator->current_value;
14,567✔
233
    int64_t step = current - last;
14,567✔
234
    if (n < step) {
14,567✔
235
      element = last + n;
1,001✔
236
      break;
1,001✔
237
    } else {
238
      n -= (step - 1);
13,566✔
239
    }
240
    last = current;
13,566✔
241
    roaring_uint32_iterator_advance(iterator);
13,566✔
242
  }
243
  roaring_uint32_iterator_free(iterator);
1,002✔
244
  return element;
1,002✔
245
}
246

247
uint64_t bitmap64_get_nth_element_not_present(const Bitmap64* bitmap, uint64_t n, bool* found) {
1,002✔
248
  roaring64_iterator_t* iterator = roaring64_iterator_create(bitmap);
1,002✔
249
  uint64_t element = 0;
1,002✔
250
  uint64_t last = UINT64_MAX;
1,002✔
251

252
  for (uint64_t i = 1; roaring64_iterator_has_value(iterator); i++) {
14,568✔
253
    uint64_t current = roaring64_iterator_value(iterator);
14,567✔
254
    uint64_t step = (last == UINT64_MAX) ? current + 1 : current - last;
14,567✔
255

256
    if (n < step) {
14,567✔
257
      element = (last == UINT64_MAX) ? n : last + n;
1,001✔
258
      *found = true;
1,001✔
259
      break;
1,001✔
260
    } else {
261
      n -= (step - 1);
13,566✔
262
    }
263
    last = current;
13,566✔
264
    roaring64_iterator_advance(iterator);
13,566✔
265
  }
266

267
  roaring64_iterator_free(iterator);
1,002✔
268
  return element;
1,002✔
269
}
270

271
int64_t bitmap_get_nth_element_not_present_slow(const Bitmap* bitmap, uint64_t n) {
1,000✔
272
  roaring_bitmap_t* inverted_bitmap = bitmap_not(bitmap);
1,000✔
273
  int64_t element = bitmap_get_nth_element_present(inverted_bitmap, n);
1,000✔
274
  roaring_bitmap_free(inverted_bitmap);
1,000✔
275
  return element;
1,000✔
276
}
277

278
uint64_t bitmap64_get_nth_element_not_present_slow(const Bitmap64* bitmap, uint64_t n, bool* found) {
1,000✔
279
  roaring64_bitmap_t* inverted_bitmap = bitmap64_not(bitmap);
1,000✔
280
  uint64_t element = bitmap64_get_nth_element_present(inverted_bitmap, n, found);
1,000✔
281
  roaring64_bitmap_free(inverted_bitmap);
1,000✔
282
  return element;
1,000✔
283
}
284

285
// [TODO] Replace with roaring64_bitmap_overwrite in next CRoaring release 
286
static void _roaring64_bitmap_overwrite(Bitmap64* dest, const Bitmap64* src) {
121✔
287
  if (!roaring64_bitmap_is_empty(dest)) {
121✔
288
    roaring64_bitmap_clear(dest);
78✔
289
  }
290

291
  roaring64_bitmap_or_inplace(dest, src);
121✔
292
}
121✔
293

294
void bitmap_or(Bitmap* r, uint32_t n, const Bitmap** bitmaps) {
3✔
295
  if (n == 0) {
3✔
296
    return roaring_bitmap_clear(r);
1✔
297
  }
298
  if (n == 1) {
2✔
299
    roaring_bitmap_overwrite(r, bitmaps[0]);
×
300
    return;
×
301
  }
302

303
  // Only overwrite if r != bitmaps[0], otherwise r would be cleared and then copied from itself (resulting in empty)
304
  if (r != bitmaps[0]) {
2✔
305
    roaring_bitmap_overwrite(r, bitmaps[0]);
1✔
306
  }
307

308
  for (size_t i = 1; i < n; i++) {
5✔
309
    if (bitmaps[i] != r) {  // Skip if same pointer to avoid memcpy overlap
3✔
310
      // Use non-inplace operation to avoid memcpy overlap in shared containers
311
      Bitmap* temp = roaring_bitmap_lazy_or(r, bitmaps[i], false);
3✔
312
      roaring_bitmap_overwrite(r, temp);
3✔
313
      roaring_bitmap_free(temp);
3✔
314
    }
315
  }
316

317
  roaring_bitmap_repair_after_lazy(r);
2✔
318
}
319

320
void bitmap64_or(Bitmap64* r, uint32_t n, const Bitmap64** bitmaps) {
2✔
321
  if (n == 0) {
2✔
322
    return roaring64_bitmap_clear(r);
1✔
323
  }
324
  if (n == 1) {
1✔
325
    _roaring64_bitmap_overwrite(r, bitmaps[0]);
×
326
    return;
×
327
  }
328

329
  // Only overwrite if r != bitmaps[0], otherwise r would be cleared and then copied from itself (resulting in empty)
330
  if (r != bitmaps[0]) {
1✔
331
  _roaring64_bitmap_overwrite(r, bitmaps[0]);
1✔
332
  }
333

334
  for (uint32_t i = 1; i < n; i++) {
3✔
335
    if (bitmaps[i] != r) {  // Skip if same pointer to avoid memcpy overlap
2✔
336
      // Use non-inplace operation to avoid memcpy overlap in shared containers
337
      Bitmap64* temp = roaring64_bitmap_or(r, bitmaps[i]);
2✔
338
      _roaring64_bitmap_overwrite(r, temp);
2✔
339
      roaring64_bitmap_free(temp);
2✔
340
    }
341
  }
342
}
343

344
void bitmap_and(Bitmap* r, uint32_t n, const Bitmap** bitmaps) {
3✔
345
  if (n == 0) {
3✔
346
    return roaring_bitmap_clear(r);
1✔
347
  }
348
  if (n == 1) {
2✔
349
    roaring_bitmap_overwrite(r, bitmaps[0]);
×
350
    return;
×
351
  }
352

353
  // Only overwrite if r != bitmaps[0], otherwise r would be cleared and then copied from itself (resulting in empty)
354
  if (r != bitmaps[0]) {
2✔
355
    roaring_bitmap_overwrite(r, bitmaps[0]);
1✔
356
  }
357

358
  for (uint32_t i = 1; i < n; i++) {
5✔
359
    if (bitmaps[i] != r) {  // Skip if same pointer to avoid memcpy overlap
3✔
360
      // Use non-inplace operation to avoid memcpy overlap in shared containers
361
      Bitmap* temp = roaring_bitmap_and(r, bitmaps[i]);
3✔
362
      roaring_bitmap_overwrite(r, temp);
3✔
363
      roaring_bitmap_free(temp);
3✔
364
    }
365
  }
366
}
367

368
void bitmap64_and(Bitmap64* r, uint32_t n, const Bitmap64** bitmaps) {
2✔
369
  if (n == 0) {
2✔
370
    return roaring64_bitmap_clear(r);
1✔
371
  }
372
  if (n == 1) {
1✔
373
    _roaring64_bitmap_overwrite(r, bitmaps[0]);
×
374
    return;
×
375
  }
376

377
  // Only overwrite if r != bitmaps[0], otherwise r would be cleared and then copied from itself (resulting in empty)
378
  if (r != bitmaps[0]) {
1✔
379
  _roaring64_bitmap_overwrite(r, bitmaps[0]);
1✔
380
  }
381

382
  for (uint32_t i = 1; i < n; i++) {
3✔
383
    if (bitmaps[i] != r) {  // Skip if same pointer to avoid memcpy overlap
2✔
384
      // Use non-inplace operation to avoid memcpy overlap in shared containers
385
      Bitmap64* temp = roaring64_bitmap_and(r, bitmaps[i]);
2✔
386
      _roaring64_bitmap_overwrite(r, temp);
2✔
387
      roaring64_bitmap_free(temp);
2✔
388
    }
389
  }
390
}
391

392
void bitmap_xor(Bitmap* r, uint32_t n, const Bitmap** bitmaps) {
2✔
393
  if (n == 0) {
2✔
394
    return roaring_bitmap_clear(r);
1✔
395
  }
396
  if (n == 1) {
1✔
397
    roaring_bitmap_overwrite(r, bitmaps[0]);
×
398
    return;
×
399
  }
400

401
  // Only overwrite if r != bitmaps[0], otherwise r would be cleared and then copied from itself (resulting in empty)
402
  if (r != bitmaps[0]) {
1✔
403
  roaring_bitmap_overwrite(r, bitmaps[0]);
1✔
404
  }
405

406
  for (uint32_t i = 1; i < n; i++) {
3✔
407
    if (bitmaps[i] != r) {  // Skip if same pointer to avoid memcpy overlap
2✔
408
      // Use non-inplace operation to avoid memcpy overlap in shared containers
409
      Bitmap* temp = roaring_bitmap_lazy_xor(r, bitmaps[i]);
2✔
410
      roaring_bitmap_overwrite(r, temp);
2✔
411
      roaring_bitmap_free(temp);
2✔
412
    }
413
  }
414

415
  roaring_bitmap_repair_after_lazy(r);
1✔
416
}
417

418
void bitmap64_xor(Bitmap64* r, uint32_t n, const Bitmap64** bitmaps) {
2✔
419
  if (n == 0) {
2✔
420
    return roaring64_bitmap_clear(r);
1✔
421
  }
422
  if (n == 1) {
1✔
423
    _roaring64_bitmap_overwrite(r, bitmaps[0]);
×
424
    return;
×
425
  }
426

427
  // Only overwrite if r != bitmaps[0], otherwise r would be cleared and then copied from itself (resulting in empty)
428
  if (r != bitmaps[0]) {
1✔
429
  _roaring64_bitmap_overwrite(r, bitmaps[0]);
1✔
430
  }
431

432
  for (uint32_t i = 1; i < n; i++) {
3✔
433
    if (bitmaps[i] != r) {  // Skip if same pointer to avoid memcpy overlap
2✔
434
      // Use non-inplace operation to avoid memcpy overlap in shared containers
435
      Bitmap64* temp = roaring64_bitmap_xor(r, bitmaps[i]);
2✔
436
      _roaring64_bitmap_overwrite(r, temp);
2✔
437
      roaring64_bitmap_free(temp);
2✔
438
    }
439
  }
440
}
441

442
void bitmap_andor(Bitmap* r, uint32_t n, const Bitmap** bitmaps) {
11✔
443
  if (n == 0) {
11✔
444
    return roaring_bitmap_clear(r);
2✔
445
  }
446
  if (n == 1) {
9✔
447
    roaring_bitmap_overwrite(r, bitmaps[0]);
1✔
448
    return;
1✔
449
  }
450
  if (n < 2) {
8✔
451
    return bitmap_and(r, n, bitmaps);
×
452
  }
453

454
  // If r == bitmaps[0], we need to make a copy because we'll overwrite r
455
  Bitmap* x_copy = NULL;
8✔
456
  const Bitmap* x = bitmaps[0];
8✔
457
  if (r == bitmaps[0]) {
8✔
458
    x_copy = roaring_bitmap_copy(bitmaps[0]);
1✔
459
    x = x_copy;
1✔
460
  }
461

462
  // Only overwrite if r != bitmaps[1], otherwise r would be cleared and then copied from itself
463
  if (r != bitmaps[1]) {
8✔
464
    roaring_bitmap_overwrite(r, bitmaps[1]);
8✔
465
  }
466

467
  for (size_t i = 2; i < n; i++) {
21✔
468
    if (bitmaps[i] != r) {  // Skip if same pointer to avoid memcpy overlap
13✔
469
      // Use non-inplace operation to avoid memcpy overlap in shared containers
470
      Bitmap* temp = roaring_bitmap_lazy_or(r, bitmaps[i], false);
13✔
471
      roaring_bitmap_overwrite(r, temp);
13✔
472
      roaring_bitmap_free(temp);
13✔
473
    }
474
  }
475

476
  roaring_bitmap_repair_after_lazy(r);
8✔
477

478
  // Now AND with x (either bitmaps[0] or our copy if r was bitmaps[0])
479
  Bitmap* temp = roaring_bitmap_and(r, x);
8✔
480
  roaring_bitmap_overwrite(r, temp);
8✔
481
  roaring_bitmap_free(temp);
8✔
482

483
  // Clean up copy if we made one
484
  if (x_copy) {
8✔
485
    roaring_bitmap_free(x_copy);
1✔
486
  }
487
}
488

489
void bitmap_andnot(Bitmap* r, uint32_t n, const Bitmap** bitmaps) {
8✔
490
  if (n == 0) {
8✔
491
    return roaring_bitmap_clear(r);
1✔
492
  }
493
  if (n == 1) {
7✔
494
    roaring_bitmap_overwrite(r, bitmaps[0]);
1✔
495
    return;
1✔
496
  }
497
  if (n == 2) {
6✔
498
    roaring_bitmap_overwrite(r, bitmaps[0]);
3✔
499
    if (bitmaps[1] != r) {  // Skip if same pointer to avoid memcpy overlap
3✔
500
      Bitmap* temp = roaring_bitmap_andnot(r, bitmaps[1]);
3✔
501
      roaring_bitmap_overwrite(r, temp);
3✔
502
      roaring_bitmap_free(temp);
3✔
503
    }
504
    return;
3✔
505
  }
506

507
  const Bitmap* x = bitmaps[0];
3✔
508

509
  roaring_bitmap_overwrite(r, x);
3✔
510

511
  for (uint32_t i = 1; i < n; i++) {
18✔
512
    if (bitmaps[i] != r) {  // Skip if same pointer to avoid memcpy overlap
15✔
513
      // Use non-inplace operation to avoid memcpy overlap in shared containers
514
      Bitmap* temp = roaring_bitmap_andnot(r, bitmaps[i]);
15✔
515
      roaring_bitmap_overwrite(r, temp);
15✔
516
      roaring_bitmap_free(temp);
15✔
517
    }
518
  }
519
}
520

521
void bitmap64_andnot(Bitmap64* r, uint32_t n, const Bitmap64** bitmaps) {
8✔
522
  if (n == 0) {
8✔
523
    return roaring64_bitmap_clear(r);
1✔
524
  }
525
  if (n == 1) {
7✔
526
    _roaring64_bitmap_overwrite(r, bitmaps[0]);
1✔
527
    return;
1✔
528
  }
529
  if (n == 2) {
6✔
530
    _roaring64_bitmap_overwrite(r, bitmaps[0]);
3✔
531
    if (bitmaps[1] != r) {  // Skip if same pointer to avoid memcpy overlap
3✔
532
      Bitmap64* temp = roaring64_bitmap_andnot(r, bitmaps[1]);
3✔
533
      _roaring64_bitmap_overwrite(r, temp);
3✔
534
      roaring64_bitmap_free(temp);
3✔
535
    }
536
    return;
3✔
537
  }
538

539
  const Bitmap64* x = bitmaps[0];
3✔
540

541
  _roaring64_bitmap_overwrite(r, x);
3✔
542

543
  for (uint32_t i = 1; i < n; i++) {
18✔
544
    if (bitmaps[i] != r) {  // Skip if same pointer to avoid memcpy overlap
15✔
545
      Bitmap64* temp = roaring64_bitmap_andnot(r, bitmaps[i]);
15✔
546
      _roaring64_bitmap_overwrite(r, temp);
15✔
547
      roaring64_bitmap_free(temp);
15✔
548
    }
549
  }
550
}
551

552
void bitmap_ornot(Bitmap* r, uint32_t n, const Bitmap** bitmaps) {
7✔
553
  if (n == 0) {
7✔
554
    return roaring_bitmap_clear(r);
1✔
555
  }
556
  if (n == 1) {
6✔
557
    return roaring_bitmap_clear(r);
1✔
558
  }
559
  if (n == 2) {
5✔
560
    roaring_bitmap_overwrite(r, bitmaps[1]);
4✔
561
    if (bitmaps[0] != r) {  // Skip if same pointer to avoid memcpy overlap
4✔
562
      Bitmap* temp = roaring_bitmap_andnot(r, bitmaps[0]);
4✔
563
      roaring_bitmap_overwrite(r, temp);
4✔
564
      roaring_bitmap_free(temp);
4✔
565
    }
566
    return;
4✔
567
  }
568

569
  const Bitmap* x = bitmaps[0];
1✔
570

571
  roaring_bitmap_overwrite(r, bitmaps[1]);
1✔
572

573
  for (uint32_t i = 2; i < n; i++) {
3✔
574
    if (bitmaps[i] != r) {  // Skip if same pointer to avoid memcpy overlap
2✔
575
      // Use non-inplace operation to avoid memcpy overlap in shared containers
576
      Bitmap* temp = roaring_bitmap_or(r, bitmaps[i]);
2✔
577
      roaring_bitmap_overwrite(r, temp);
2✔
578
      roaring_bitmap_free(temp);
2✔
579
    }
580
  }
581

582
  if (x != r) {  // Skip if same pointer to avoid memcpy overlap
1✔
583
    Bitmap* temp = roaring_bitmap_andnot(r, x);
1✔
584
    roaring_bitmap_overwrite(r, temp);
1✔
585
    roaring_bitmap_free(temp);
1✔
586
  }
587
}
588

589
void bitmap64_ornot(Bitmap64* r, uint32_t n, const Bitmap64** bitmaps) {
7✔
590
  if (n == 0) {
7✔
591
    return roaring64_bitmap_clear(r);
1✔
592
  }
593
  if (n == 1) {
6✔
594
    return roaring64_bitmap_clear(r);
1✔
595
  }
596
  if (n == 2) {
5✔
597
    _roaring64_bitmap_overwrite(r, bitmaps[1]);
4✔
598
    if (bitmaps[0] != r) {  // Skip if same pointer to avoid memcpy overlap
4✔
599
      Bitmap64* temp = roaring64_bitmap_andnot(r, bitmaps[0]);
4✔
600
      _roaring64_bitmap_overwrite(r, temp);
4✔
601
      roaring64_bitmap_free(temp);
4✔
602
    }
603
    return;
4✔
604
  }
605

606
  const Bitmap64* x = bitmaps[0];
1✔
607

608
  _roaring64_bitmap_overwrite(r, bitmaps[1]);
1✔
609

610
  for (uint32_t i = 2; i < n; i++) {
3✔
611
    if (bitmaps[i] != r) {  // Skip if same pointer to avoid memcpy overlap
2✔
612
      Bitmap64* temp = roaring64_bitmap_or(r, bitmaps[i]);
2✔
613
      _roaring64_bitmap_overwrite(r, temp);
2✔
614
      roaring64_bitmap_free(temp);
2✔
615
    }
616
  }
617

618
  if (x != r) {  // Skip if same pointer to avoid memcpy overlap
1✔
619
    Bitmap64* temp = roaring64_bitmap_andnot(r, x);
1✔
620
    _roaring64_bitmap_overwrite(r, temp);
1✔
621
    roaring64_bitmap_free(temp);
1✔
622
  }
623
}
624

625
void bitmap64_andor(Bitmap64* r, uint32_t n, const Bitmap64** bitmaps) {
10✔
626
  if (n == 0) {
10✔
627
    return roaring64_bitmap_clear(r);
2✔
628
  }
629
  if (n == 1) {
8✔
630
    _roaring64_bitmap_overwrite(r, bitmaps[0]);
1✔
631
    return;
1✔
632
  }
633
  if (n < 2) {
7✔
634
    return bitmap64_and(r, n, bitmaps);
×
635
  }
636

637
  // If r == bitmaps[0], we need to make a copy because we'll overwrite r
638
  Bitmap64* x_copy = NULL;
7✔
639
  const Bitmap64* x = bitmaps[0];
7✔
640
  if (r == bitmaps[0]) {
7✔
641
    x_copy = roaring64_bitmap_copy(bitmaps[0]);
×
642
    x = x_copy;
×
643
  }
644

645
  // Only overwrite if r != bitmaps[1], otherwise r would be cleared and then copied from itself
646
  if (r != bitmaps[1]) {
7✔
647
    _roaring64_bitmap_overwrite(r, bitmaps[1]);
7✔
648
  }
649

650
  for (size_t i = 2; i < n; i++) {
19✔
651
    if (bitmaps[i] != r) {  // Skip if same pointer to avoid memcpy overlap
12✔
652
      Bitmap64* temp = roaring64_bitmap_or(r, bitmaps[i]);
12✔
653
      _roaring64_bitmap_overwrite(r, temp);
12✔
654
      roaring64_bitmap_free(temp);
12✔
655
    }
656
  }
657

658
  // Now AND with x (either bitmaps[0] or our copy if r was bitmaps[0])
659
  Bitmap64* temp = roaring64_bitmap_and(r, x);
7✔
660
  _roaring64_bitmap_overwrite(r, temp);
7✔
661
  roaring64_bitmap_free(temp);
7✔
662

663
  // Clean up copy if we made one
664
  if (x_copy) {
7✔
665
    roaring64_bitmap_free(x_copy);
×
666
  }
667
}
668

669
void bitmap_one(Bitmap* r, uint32_t n, const Bitmap** bitmaps) {
11✔
670
  if (n == 0) {
11✔
671
    return roaring_bitmap_clear(r);
2✔
672
  }
673
  if (n == 1) {
9✔
674
    roaring_bitmap_overwrite(r, bitmaps[0]);
1✔
675
    return;
1✔
676
  }
677
  // Do simple xor for two bitmaps
678
  if (n < 2) {
8✔
679
    return bitmap_xor(r, n, bitmaps);
×
680
  }
681

682
  // Helper bitmap to track bits seen in more than one key
683
  Bitmap* helper = roaring_bitmap_create();
8✔
684

685
  // Start with the first bitmap
686
  roaring_bitmap_overwrite(r, bitmaps[0]);
8✔
687

688
  for (uint32_t i = 1; i < n; i++) {
21✔
689
    if (bitmaps[i] != r) {  // Skip if same pointer to avoid memcpy overlap
13✔
690
      // Track bits that appear in both current result and new bitmap
691
      // These are bits that now appear in more than one key
692
      Bitmap* intersection = roaring_bitmap_and(r, bitmaps[i]);
13✔
693
      Bitmap* helper_temp = roaring_bitmap_or(helper, intersection);
13✔
694
      roaring_bitmap_overwrite(helper, helper_temp);
13✔
695
      roaring_bitmap_free(helper_temp);
13✔
696
      roaring_bitmap_free(intersection);
13✔
697

698
      // XOR the new bitmap with current result
699
      Bitmap* xor_temp = roaring_bitmap_xor(r, bitmaps[i]);
13✔
700
      roaring_bitmap_overwrite(r, xor_temp);
13✔
701
      roaring_bitmap_free(xor_temp);
13✔
702

703
      // Remove bits that have been seen in more than one key
704
      Bitmap* andnot_temp = roaring_bitmap_andnot(r, helper);
13✔
705
      roaring_bitmap_overwrite(r, andnot_temp);
13✔
706
      roaring_bitmap_free(andnot_temp);
13✔
707
    }
708
  }
709

710
  roaring_bitmap_free(helper);
8✔
711
}
712

713
void bitmap64_one(Bitmap64* r, uint32_t n, const Bitmap64** bitmaps) {
11✔
714
  if (n == 0) {
11✔
715
    return roaring64_bitmap_clear(r);
2✔
716
  }
717
  if (n == 1) {
9✔
718
    return _roaring64_bitmap_overwrite(r, bitmaps[0]);
1✔
719
  }
720
  // Do simple xor for two bitmaps
721
  if (n < 2) {
8✔
722
    return bitmap64_xor(r, n, bitmaps);
×
723
  }
724

725
  // Helper bitmap to track bits seen in more than one key
726
  Bitmap64* helper = roaring64_bitmap_create();
8✔
727

728
  // Start with the first bitmap
729
  _roaring64_bitmap_overwrite(r, bitmaps[0]);
8✔
730

731
  for (uint32_t i = 1; i < n; i++) {
21✔
732
    if (bitmaps[i] != r) {  // Skip if same pointer to avoid memcpy overlap
13✔
733
      // Track bits that appear in both current result and new bitmap
734
      // These are bits that now appear in more than one key
735
      Bitmap64* intersection = roaring64_bitmap_and(r, bitmaps[i]);
13✔
736
      Bitmap64* helper_temp = roaring64_bitmap_or(helper, intersection);
13✔
737
      _roaring64_bitmap_overwrite(helper, helper_temp);
13✔
738
      roaring64_bitmap_free(helper_temp);
13✔
739
      roaring64_bitmap_free(intersection);
13✔
740

741
      // XOR the new bitmap with current result
742
      Bitmap64* xor_temp = roaring64_bitmap_xor(r, bitmaps[i]);
13✔
743
      _roaring64_bitmap_overwrite(r, xor_temp);
13✔
744
      roaring64_bitmap_free(xor_temp);
13✔
745

746
      // Remove bits that have been seen in more than one key
747
      Bitmap64* andnot_temp = roaring64_bitmap_andnot(r, helper);
13✔
748
      _roaring64_bitmap_overwrite(r, andnot_temp);
13✔
749
      roaring64_bitmap_free(andnot_temp);
13✔
750
    }
751
  }
752

753
  roaring64_bitmap_free(helper);
8✔
754
}
755

756
Bitmap* bitmap_not_array(uint32_t unused, const Bitmap** bitmaps) {
1,002✔
757
  (void) (unused);
758
  uint32_t last = roaring_bitmap_maximum(bitmaps[0]);
1,002✔
759
  return roaring_bitmap_flip(bitmaps[0], 0, last + 1);
1,002✔
760
}
761

762
Bitmap64* bitmap64_not_array(uint64_t unused, const Bitmap64** bitmaps) {
1,002✔
763
  (void) (unused);
764
  uint64_t last = roaring64_bitmap_maximum(bitmaps[0]);
1,002✔
765
  return roaring64_bitmap_flip(bitmaps[0], 0, last + 1);
1,002✔
766
}
767

768
Bitmap* bitmap_flip(const Bitmap* bitmap, uint32_t end) {
×
769
  return roaring_bitmap_flip(bitmap, 0, end);
×
770
}
771

772
Bitmap64* bitmap64_flip(const Bitmap64* bitmap, uint64_t end) {
×
773
  return roaring64_bitmap_flip(bitmap, 0, end);
×
774
}
775

776
Bitmap* bitmap_not(const Bitmap* bitmap) {
1,001✔
777
  const Bitmap* bitmaps[] = { bitmap };
1,001✔
778
  return bitmap_not_array(1, bitmaps);
1,001✔
779
}
780

781
Bitmap64* bitmap64_not(const Bitmap64* bitmap) {
1,001✔
782
  const Bitmap64* bitmaps[] = { bitmap };
1,001✔
783
  return bitmap64_not_array(1, bitmaps);
1,001✔
784
}
785

786
Bitmap* bitmap_from_int_array(size_t n, const uint32_t* array) {
2✔
787
  return roaring_bitmap_of_ptr(n, array);
2✔
788
}
789

790
Bitmap64* bitmap64_from_int_array(size_t n, const uint64_t* array) {
2✔
791
  return roaring64_bitmap_of_ptr(n, array);
2✔
792
}
793

794
uint32_t* bitmap_get_int_array(const Bitmap* bitmap, size_t* n) {
30✔
795
  *n = roaring_bitmap_get_cardinality(bitmap);
30✔
796
  uint32_t* ans = rm_malloc(sizeof(*ans) * (*n));
30✔
797
  roaring_bitmap_to_uint32_array(bitmap, ans);
30✔
798
  return ans;
30✔
799
}
800

801
uint64_t* bitmap64_get_int_array(const Bitmap64* bitmap, uint64_t* n) {
30✔
802
  *n = roaring64_bitmap_get_cardinality(bitmap);
30✔
803
  uint64_t* ans = rm_malloc(sizeof(*ans) * (*n));
30✔
804
  roaring64_bitmap_to_uint64_array(bitmap, ans);
30✔
805
  return ans;
30✔
806
}
807

808
uint32_t* bitmap_range_int_array(const Bitmap* bitmap, size_t start_offset, size_t end_offset, size_t* result_count) {
12✔
809
  if (result_count) *result_count = 0;
12✔
810

811
  if (bitmap == NULL) {
12✔
812
    return NULL;
×
813
  }
814

815
  if (start_offset > end_offset) {
12✔
816
    return NULL;
1✔
817
  }
818

819
  size_t range_size = (end_offset - start_offset) + 1;
11✔
820
  if (range_size == 0 || range_size > (SIZE_MAX / sizeof(uint32_t))) {
11✔
821
    return NULL;
×
822
  }
823

824
  uint32_t* ans = rm_calloc_try(range_size, sizeof(uint32_t));
11✔
825
  if (ans == NULL) {
11✔
NEW
826
    return NULL;
×
827
  }
828

829
  size_t i = 0;
11✔
830
  while (i < range_size) {
44✔
831
    if (!roaring_bitmap_select(bitmap, start_offset + i, &ans[i])) {
40✔
832
      break;
7✔
833
    }
834
    i++;
33✔
835
  }
836

837
  if (result_count) *result_count = i;
11✔
838

839
  return ans;
11✔
840
}
841

842
uint64_t* bitmap64_range_int_array(const Bitmap64* bitmap, uint64_t start_offset, uint64_t end_offset, uint64_t* result_count) {
11✔
843
  if (result_count) *result_count = 0;
11✔
844

845
  // Validate input parameters
846
  if (bitmap == NULL) {
11✔
847
    return NULL;
×
848
  }
849

850
  // Validate range parameters
851
  if (start_offset > end_offset) {
11✔
852
    return NULL;
1✔
853
  }
854

855
  uint64_t range_size = (end_offset - start_offset) + 1;
10✔
856

857
  // Check for overflow
858
  if (range_size < (end_offset - start_offset)) {
10✔
859
    return NULL;
×
860
  }
861

862
  uint64_t* ans = rm_calloc_try(range_size, sizeof(uint64_t));
10✔
863

864
  if (ans == NULL) {
10✔
865
    return NULL;
×
866
  }
867

868
  uint64_t i = 0;
10✔
869

870
  // [TODO] replace with roaring64_bitmap_range_uint64_array in next version of CRoaring
871
  while (i < range_size) {
40✔
872
    if (!roaring64_bitmap_select(bitmap, start_offset + i, &ans[i])) {
37✔
873
      break;
7✔
874
    }
875

876
    i++;
30✔
877
  }
878

879
  if (result_count) *result_count = i;
10✔
880

881
  return ans;
10✔
882
}
883

884
Bitmap* bitmap_from_bit_array(size_t size, const char* array) {
1✔
885
  Bitmap* bitmap = bitmap_alloc();
1✔
886
  for (size_t i = 0; i < size; i++) {
73✔
887
    if (array[i] == '1') {
72✔
888
      roaring_bitmap_add(bitmap, (int32_t) i);
34✔
889
    }
890
  }
891
  return bitmap;
1✔
892
}
893

894
Bitmap64* bitmap64_from_bit_array(size_t size, const char* array) {
10✔
895
  Bitmap64* bitmap = bitmap64_alloc();
10✔
896
  for (size_t i = 0; i < size; i++) {
101,044✔
897
    if (array[i] == '1') {
101,034✔
898
      roaring64_bitmap_add(bitmap, (uint64_t) i);
350✔
899
    }
900
  }
901
  return bitmap;
10✔
902
}
903

904
char* bitmap_get_bit_array(const Bitmap* bitmap, size_t* size) {
1✔
905
  *size = roaring_bitmap_maximum(bitmap) + 1;
1✔
906
  char* ans = rm_malloc(*size + 1);
1✔
907
  memset(ans, '0', *size);
1✔
908
  ans[*size] = '\0';
1✔
909

910
  roaring_uint32_iterator_t* iterator = roaring_iterator_create(bitmap);
1✔
911
  while (iterator->has_value) {
35✔
912
    ans[iterator->current_value] = '1';
34✔
913
    roaring_uint32_iterator_advance(iterator);
34✔
914
  }
915
  roaring_uint32_iterator_free(iterator);
1✔
916

917
  return ans;
1✔
918
}
919

920
char* bitmap64_get_bit_array(const Bitmap64* bitmap, uint64_t* size) {
9✔
921
  *size = roaring64_bitmap_maximum(bitmap) + 1;
9✔
922
  char* ans = rm_malloc(*size + 1);
9✔
923
  memset(ans, '0', *size);
9✔
924
  ans[*size] = '\0';
9✔
925

926
  roaring64_iterator_t* iterator = roaring64_iterator_create(bitmap);
9✔
927
  while (roaring64_iterator_has_value(iterator)) {
23✔
928
    ans[roaring64_iterator_value(iterator)] = '1';
14✔
929
    roaring64_iterator_advance(iterator);
14✔
930
  }
931
  roaring64_iterator_free(iterator);
9✔
932

933
  return ans;
9✔
934
}
935

936
void bitmap_free_bit_array(char* array) {
1✔
937
  rm_free(array);
1✔
938
}
1✔
939

940
Bitmap* bitmap_from_range(uint64_t from, uint64_t to) {
×
941
  // allocate empty bitmap when invalid range
942
  if (from == to) {
×
943
    return bitmap_alloc();
×
944
  }
945

946
  return roaring_bitmap_from_range(from, to, 1);
×
947
}
948

949
Bitmap64* bitmap64_from_range(uint64_t from, uint64_t to) {
×
950
  // allocate empty bitmap when invalid range
951
  if (from == to) {
×
952
    return bitmap64_alloc();
×
953
  }
954

955
  return roaring64_bitmap_from_range(from, to, 1);
×
956
}
957

958
bool bitmap_is_empty(const Bitmap* bitmap) {
×
959
  return roaring_bitmap_is_empty(bitmap);
×
960
}
961

962
bool bitmap64_is_empty(const Bitmap64* bitmap) {
×
963
  return roaring64_bitmap_is_empty(bitmap);
×
964
}
965

966
uint32_t bitmap_min(const Bitmap* bitmap) {
×
967
  return roaring_bitmap_minimum(bitmap);
×
968
}
969

970
uint64_t bitmap64_min(const Bitmap64* bitmap) {
×
971
  return roaring64_bitmap_minimum(bitmap);
×
972
}
973

974
uint32_t bitmap_max(const Bitmap* bitmap) {
×
975
  return roaring_bitmap_maximum(bitmap);
×
976
}
977

978
uint64_t bitmap64_max(const Bitmap64* bitmap) {
×
979
  return roaring64_bitmap_maximum(bitmap);
×
980
}
981

982
bool bitmap_optimize(Bitmap* bitmap, int shrink_to_fit) {
×
983
  bool was_modified = roaring_bitmap_run_optimize(bitmap);
×
984
  if (shrink_to_fit && was_modified) {
×
985
    roaring_bitmap_shrink_to_fit(bitmap);
×
986
  }
987
  return was_modified;
×
988
}
989

990
bool bitmap64_optimize(Bitmap64* bitmap, int shrink_to_fit) {
×
991
  bool was_modified = roaring64_bitmap_run_optimize(bitmap);
×
992
  if (shrink_to_fit && was_modified) {
×
993
    roaring64_bitmap_shrink_to_fit(bitmap);
×
994
  }
995
  return was_modified;
×
996
}
997

998
void bitmap_statistics(const Bitmap* bitmap, Bitmap_statistics* stat) {
×
999
  roaring_bitmap_statistics(bitmap, stat);
×
1000
}
×
1001

1002
void bitmap64_statistics(const Bitmap64* bitmap, Bitmap64_statistics* stat) {
×
1003
  roaring64_bitmap_statistics(bitmap, stat);
×
1004
}
×
1005

1006
static inline int bitmap_stat_json(const Bitmap* bitmap, char** result) {
×
1007
  roaring_statistics_t stats;
1008
  roaring_bitmap_statistics(bitmap, &stats);
×
1009

1010
  return asprintf(result,
×
1011
    "{"
1012
    "\"type\":\"bitmap\","
1013
    "\"cardinality\":\"%llu\","
1014
    "\"number_of_containers\":\"%u\","
1015
    "\"max_value\":\"%u\","
1016
    "\"min_value\":\"%u\","
1017
    "\"array_container\":{"
1018
    "\"number_of_containers\":\"%u\","
1019
    "\"container_cardinality\":\"%u\","
1020
    "\"container_allocated_bytes\":\"%u\"},"
1021
    "\"bitset_container\":{"
1022
    "\"number_of_containers\":\"%u\","
1023
    "\"container_cardinality\":\"%u\","
1024
    "\"container_allocated_bytes\":\"%u\"},"
1025
    "\"run_container\":{"
1026
    "\"number_of_containers\":\"%u\","
1027
    "\"container_cardinality\":\"%u\","
1028
    "\"container_allocated_bytes\":\"%u\"}"
1029
    "}",
1030
    roaring_bitmap_get_cardinality(bitmap),
1031
    stats.n_containers,
1032
    roaring_bitmap_maximum(bitmap),
1033
    roaring_bitmap_minimum(bitmap),
1034
    stats.n_array_containers,
1035
    stats.n_values_array_containers,
1036
    stats.n_bytes_array_containers,
1037
    stats.n_bitset_containers,
1038
    stats.n_values_bitset_containers,
1039
    stats.n_bytes_bitset_containers,
1040
    stats.n_run_containers,
1041
    stats.n_values_run_containers,
1042
    stats.n_bytes_run_containers
1043
  );
1044
}
1045

1046
static inline int bitmap_stat_plain(const Bitmap* bitmap, char** result) {
×
1047
  roaring_statistics_t stats;
1048
  roaring_bitmap_statistics(bitmap, &stats);
×
1049

1050
  return asprintf(result,
×
1051
    "type: bitmap\n"
1052
    "cardinality: %llu\n"
1053
    "number of containers: %u\n"
1054
    "max value: %u\n"
1055
    "min value: %u\n"
1056
    "number of array containers: %u\n"
1057
    "\tarray container values: %u\n"
1058
    "\tarray container bytes: %u\n"
1059
    "bitset  containers: %u\n"
1060
    "\tbitset  container values: %u\n"
1061
    "\tbitset  container bytes: %u\n"
1062
    "run containers: %u\n"
1063
    "\trun container values: %u\n"
1064
    "\trun container bytes: %u\n"
1065
    ,
1066
    roaring_bitmap_get_cardinality(bitmap),
1067
    stats.n_containers,
1068
    roaring_bitmap_maximum(bitmap),
1069
    roaring_bitmap_minimum(bitmap),
1070
    stats.n_array_containers,
1071
    stats.n_values_array_containers,
1072
    stats.n_bytes_array_containers,
1073
    stats.n_bitset_containers,
1074
    stats.n_values_bitset_containers,
1075
    stats.n_bytes_bitset_containers,
1076
    stats.n_run_containers,
1077
    stats.n_values_run_containers,
1078
    stats.n_bytes_run_containers
1079
  );
1080
}
1081

1082
/**
1083
 * Computes string statistics of roaring bitmap
1084
 * Returns `NULL` when failed.
1085
 * You is responsible for calling `free()`
1086
 */
1087
char* bitmap_statistics_str(const Bitmap* bitmap, int format, int* size) {
×
1088
  if (!bitmap) {
×
1089
    return NULL;
×
1090
  }
1091

1092
  char* result = NULL;
×
1093
  int result_size = -1;
×
1094

1095
  switch (format) {
×
1096
  case BITMAP_STATISTICS_FORMAT_JSON:
×
1097
    result_size = bitmap_stat_json(bitmap, &result);
×
1098
    break;
×
1099
  case BITMAP_STATISTICS_FORMAT_PLAIN_TEXT:
×
1100
    result_size = bitmap_stat_plain(bitmap, &result);
×
1101
    break;
×
1102
  default:
×
1103
    return NULL;
×
1104
  }
1105

1106
  if (result_size == -1) {
×
1107
    if (result) {
×
1108
      rm_free(result);
×
1109
      result = NULL;
×
1110
    }
1111
  }
1112

1113
  if (size) {
×
1114
    *size = result_size;
×
1115
  }
1116

1117
  return result;
×
1118
}
1119

1120
static inline int bitmap64_stat_json(const Bitmap64* bitmap, char** result) {
×
1121
  roaring64_statistics_t stats;
1122
  roaring64_bitmap_statistics(bitmap, &stats);
×
1123

1124
  return asprintf(result,
×
1125
    "{"
1126
    "\"type\":\"bitmap64\","
1127
    "\"cardinality\":\"%llu\","
1128
    "\"number_of_containers\":\"%llu\","
1129
    "\"max_value\":\"%llu\","
1130
    "\"min_value\":\"%llu\","
1131
    "\"array_container\":{"
1132
    "\"number_of_containers\":\"%llu\","
1133
    "\"container_cardinality\":\"%llu\","
1134
    "\"container_allocated_bytes\":\"%llu\"},"
1135
    "\"bitset_container\":{"
1136
    "\"number_of_containers\":\"%llu\","
1137
    "\"container_cardinality\":\"%llu\","
1138
    "\"container_allocated_bytes\":\"%llu\"},"
1139
    "\"run_container\":{"
1140
    "\"number_of_containers\":\"%llu\","
1141
    "\"container_cardinality\":\"%llu\","
1142
    "\"container_allocated_bytes\":\"%llu\"}"
1143
    "}",
1144
    roaring64_bitmap_get_cardinality(bitmap),
1145
    stats.n_containers,
1146
    roaring64_bitmap_maximum(bitmap),
1147
    roaring64_bitmap_minimum(bitmap),
1148
    stats.n_array_containers,
1149
    stats.n_values_array_containers,
1150
    stats.n_bytes_array_containers,
1151
    stats.n_bitset_containers,
1152
    stats.n_values_bitset_containers,
1153
    stats.n_bytes_bitset_containers,
1154
    stats.n_run_containers,
1155
    stats.n_values_run_containers,
1156
    stats.n_bytes_run_containers
1157
  );
1158
}
1159

1160
static inline int bitmap64_stat_plain(const Bitmap64* bitmap, char** result) {
×
1161
  roaring64_statistics_t stats;
1162
  roaring64_bitmap_statistics(bitmap, &stats);
×
1163

1164
  return asprintf(result,
×
1165
    "type: bitmap64\n"
1166
    "cardinality: %llu\n"
1167
    "number of containers: %llu\n"
1168
    "max value: %llu\n"
1169
    "min value: %llu\n"
1170
    "number of array containers: %llu\n"
1171
    "\tarray container values: %llu\n"
1172
    "\tarray container bytes: %llu\n"
1173
    "bitset  containers: %llu\n"
1174
    "\tbitset  container values: %llu\n"
1175
    "\tbitset  container bytes: %llu\n"
1176
    "run containers: %llu\n"
1177
    "\trun container values: %llu\n"
1178
    "\trun container bytes: %llu\n"
1179
    ,
1180
    roaring64_bitmap_get_cardinality(bitmap),
1181
    stats.n_containers,
1182
    roaring64_bitmap_maximum(bitmap),
1183
    roaring64_bitmap_minimum(bitmap),
1184
    stats.n_array_containers,
1185
    stats.n_values_array_containers,
1186
    stats.n_bytes_array_containers,
1187
    stats.n_bitset_containers,
1188
    stats.n_values_bitset_containers,
1189
    stats.n_bytes_bitset_containers,
1190
    stats.n_run_containers,
1191
    stats.n_values_run_containers,
1192
    stats.n_bytes_run_containers
1193
  );
1194
}
1195

1196
/**
1197
 * Computes string statistics of roaring bitmap64
1198
 * Returns `NULL` when failed.
1199
 * You is responsible for calling `free()`
1200
 */
1201
char* bitmap64_statistics_str(const Bitmap64* bitmap, int format, int* size) {
×
1202
  if (!bitmap) {
×
1203
    return NULL;
×
1204
  }
1205

1206
  char* result = NULL;
×
1207
  int result_size = -1;
×
1208

1209
  switch (format) {
×
1210
  case BITMAP_STATISTICS_FORMAT_JSON:
×
1211
    result_size = bitmap64_stat_json(bitmap, &result);
×
1212
    break;
×
1213
  case BITMAP_STATISTICS_FORMAT_PLAIN_TEXT:
×
1214
    result_size = bitmap64_stat_plain(bitmap, &result);
×
1215
    break;
×
1216
  default:
×
1217
    return NULL;
×
1218
  }
1219

1220
  if (result_size == -1) {
×
1221
    if (result) {
×
1222
      rm_free(result);
×
1223
      result = NULL;
×
1224
    }
1225
  }
1226

1227
  if (size) {
×
1228
    *size = result_size;
×
1229
  }
1230

1231
  return result;
×
1232
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc