Coverage Report

Created: 2025-12-14 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/croaring/include/roaring/portability.h
Line
Count
Source
1
/*
2
 * portability.h
3
 *
4
 */
5
6
/**
7
 * All macros should be prefixed with either CROARING or ROARING.
8
 * The library uses both ROARING_...
9
 * as well as CROAIRING_ as prefixes. The ROARING_ prefix is for
10
 * macros that are provided by the build system or that are closely
11
 * related to the format. The header macros may also use ROARING_.
12
 * The CROARING_ prefix is for internal macros that a user is unlikely
13
 * to ever interact with.
14
 */
15
16
#ifndef CROARING_INCLUDE_PORTABILITY_H_
17
#define CROARING_INCLUDE_PORTABILITY_H_
18
19
// Users who need _GNU_SOURCE should define it?
20
// #ifndef _GNU_SOURCE
21
// #define _GNU_SOURCE 1
22
// #endif  // _GNU_SOURCE
23
#ifndef __STDC_FORMAT_MACROS
24
#define __STDC_FORMAT_MACROS 1
25
#endif  // __STDC_FORMAT_MACROS
26
27
#ifdef _MSC_VER
28
#define CROARING_VISUAL_STUDIO 1
29
/**
30
 * We want to differentiate carefully between
31
 * clang under visual studio and regular visual
32
 * studio.
33
 */
34
#ifdef __clang__
35
// clang under visual studio
36
#define CROARING_CLANG_VISUAL_STUDIO 1
37
#else
38
// just regular visual studio (best guess)
39
#define CROARING_REGULAR_VISUAL_STUDIO 1
40
#endif  // __clang__
41
#endif  // _MSC_VER
42
#ifndef CROARING_VISUAL_STUDIO
43
#define CROARING_VISUAL_STUDIO 0
44
#endif
45
#ifndef CROARING_CLANG_VISUAL_STUDIO
46
#define CROARING_CLANG_VISUAL_STUDIO 0
47
#endif
48
#ifndef CROARING_REGULAR_VISUAL_STUDIO
49
#define CROARING_REGULAR_VISUAL_STUDIO 0
50
#endif
51
52
#include <stdbool.h>
53
#include <stdint.h>
54
#include <stdlib.h>  // will provide posix_memalign with _POSIX_C_SOURCE as defined above
55
#ifdef __GLIBC__
56
#include <malloc.h>  // this should never be needed but there are some reports that it is needed.
57
#endif
58
59
#ifdef __cplusplus
60
extern "C" {  // portability definitions are in global scope, not a namespace
61
#endif
62
63
#if defined(__SIZEOF_LONG_LONG__) && __SIZEOF_LONG_LONG__ != 8
64
#error This code assumes  64-bit long longs (by use of the GCC intrinsics). Your system is not currently supported.
65
#endif
66
67
#if CROARING_REGULAR_VISUAL_STUDIO
68
#ifndef __restrict__
69
#define __restrict__ __restrict
70
#endif  // __restrict__
71
#endif  // CROARING_REGULAR_VISUAL_STUDIO
72
73
#if defined(__x86_64__) || defined(_M_X64)
74
// we have an x64 processor
75
#define CROARING_IS_X64 1
76
77
#if defined(_MSC_VER) && (_MSC_VER < 1910)
78
// Old visual studio systems won't support AVX2 well.
79
#undef CROARING_IS_X64
80
#endif
81
82
#if defined(__clang_major__) && (__clang_major__ <= 8) && !defined(__AVX2__)
83
// Older versions of clang have a bug affecting us
84
// https://stackoverflow.com/questions/57228537/how-does-one-use-pragma-clang-attribute-push-with-c-namespaces
85
#undef CROARING_IS_X64
86
#endif
87
88
#ifdef ROARING_DISABLE_X64
89
#undef CROARING_IS_X64
90
#endif
91
// we include the intrinsic header
92
#if !CROARING_REGULAR_VISUAL_STUDIO
93
/* Non-Microsoft C/C++-compatible compiler */
94
#include <x86intrin.h>  // on some recent GCC, this will declare posix_memalign
95
96
#if CROARING_CLANG_VISUAL_STUDIO
97
98
/**
99
 * You are not supposed, normally, to include these
100
 * headers directly. Instead you should either include intrin.h
101
 * or x86intrin.h. However, when compiling with clang
102
 * under Windows (i.e., when _MSC_VER is set), these headers
103
 * only get included *if* the corresponding features are detected
104
 * from macros:
105
 * e.g., if __AVX2__ is set... in turn,  we normally set these
106
 * macros by compiling against the corresponding architecture
107
 * (e.g., arch:AVX2, -mavx2, etc.) which compiles the whole
108
 * software with these advanced instructions. These headers would
109
 * normally guard against such usage, but we carefully included
110
 * <x86intrin.h>  (or <intrin.h>) before, so the headers
111
 * are fooled.
112
 */
113
// To avoid reordering imports:
114
// clang-format off
115
#include <bmiintrin.h>   // for _blsr_u64
116
#include <lzcntintrin.h> // for  __lzcnt64
117
#include <immintrin.h>   // for most things (AVX2, AVX512, _popcnt64)
118
#include <smmintrin.h>
119
#include <tmmintrin.h>
120
#include <avxintrin.h>
121
#include <avx2intrin.h>
122
#include <wmmintrin.h>
123
#if _MSC_VER >= 1920
124
// Important: we need the AVX-512 headers:
125
#include <avx512fintrin.h>
126
#include <avx512dqintrin.h>
127
#include <avx512cdintrin.h>
128
#include <avx512bwintrin.h>
129
#include <avx512vlintrin.h>
130
#include <avx512vbmiintrin.h>
131
#include <avx512vbmi2intrin.h>
132
#include <avx512vpopcntdqintrin.h>
133
// clang-format on
134
#endif  // _MSC_VER >= 1920
135
// unfortunately, we may not get _blsr_u64, but, thankfully, clang
136
// has it as a macro.
137
#ifndef _blsr_u64
138
// we roll our own
139
#define _blsr_u64(n) ((n - 1) & n)
140
#endif  //  _blsr_u64
141
#endif  // SIMDJSON_CLANG_VISUAL_STUDIO
142
143
#endif  // CROARING_REGULAR_VISUAL_STUDIO
144
#endif  // defined(__x86_64__) || defined(_M_X64)
145
146
#if !defined(CROARING_USENEON) && !defined(DISABLENEON) && defined(__ARM_NEON)
147
#define CROARING_USENEON
148
#endif
149
#if defined(CROARING_USENEON)
150
#include <arm_neon.h>
151
#endif
152
153
#if defined(__e2k__)
154
// we have an e2k (Elbrus-2000) processor
155
#define CROARING_IS_E2K 1
156
#endif
157
158
#if !CROARING_REGULAR_VISUAL_STUDIO && !defined(CROARING_IS_E2K)
159
/* Non-Microsoft C/C++-compatible compiler, assumes that it supports inline
160
 * assembly */
161
#define CROARING_INLINE_ASM 1
162
#endif  // _MSC_VER
163
164
#if CROARING_REGULAR_VISUAL_STUDIO
165
/* Microsoft C/C++-compatible compiler */
166
#include <intrin.h>
167
168
#ifndef __clang__  // if one compiles with MSVC *with* clang, then these
169
                   // intrinsics are defined!!!
170
#define CROARING_INTRINSICS 1
171
// sadly there is no way to check whether we are missing these intrinsics
172
// specifically.
173
174
/* wrappers for Visual Studio built-ins that look like gcc built-ins
175
 * __builtin_ctzll */
176
/** result might be undefined when input_num is zero */
177
inline int roaring_trailing_zeroes(unsigned long long input_num) {
178
    unsigned long index;
179
#ifdef _WIN64  // highly recommended!!!
180
    _BitScanForward64(&index, input_num);
181
#else   // if we must support 32-bit Windows
182
    if ((uint32_t)input_num != 0) {
183
        _BitScanForward(&index, (uint32_t)input_num);
184
    } else {
185
        _BitScanForward(&index, (uint32_t)(input_num >> 32));
186
        index += 32;
187
    }
188
#endif  // _WIN64
189
    return index;
190
}
191
192
/* wrappers for Visual Studio built-ins that look like gcc built-ins
193
 * __builtin_clzll */
194
/** result might be undefined when input_num is zero */
195
inline int roaring_leading_zeroes(unsigned long long input_num) {
196
    unsigned long index;
197
#ifdef _WIN64  // highly recommended!!!
198
    _BitScanReverse64(&index, input_num);
199
#else   // if we must support 32-bit Windows
200
    if (input_num > 0xFFFFFFFF) {
201
        _BitScanReverse(&index, (uint32_t)(input_num >> 32));
202
        index += 32;
203
    } else {
204
        _BitScanReverse(&index, (uint32_t)(input_num));
205
    }
206
#endif  // _WIN64
207
    return 63 - index;
208
}
209
210
/* Use #define so this is effective even under /Ob0 (no inline) */
211
#define roaring_unreachable __assume(0)
212
#endif  // __clang__
213
214
#endif  // CROARING_REGULAR_VISUAL_STUDIO
215
216
#ifndef CROARING_INTRINSICS
217
#define CROARING_INTRINSICS 1
218
0
#define roaring_unreachable __builtin_unreachable()
219
/** result might be undefined when input_num is zero */
220
190k
inline int roaring_trailing_zeroes(unsigned long long input_num) {
221
190k
    return __builtin_ctzll(input_num);
222
190k
}
223
/** result might be undefined when input_num is zero */
224
0
inline int roaring_leading_zeroes(unsigned long long input_num) {
225
0
    return __builtin_clzll(input_num);
226
0
}
227
#endif
228
229
#if CROARING_REGULAR_VISUAL_STUDIO
230
#define ALIGNED(x) __declspec(align(x))
231
#elif defined(__GNUC__) || defined(__clang__)
232
#define ALIGNED(x) __attribute__((aligned(x)))
233
#else
234
#warning "Warning. Unrecognized compiler."
235
#define ALIGNED(x)
236
#endif
237
238
#if defined(__GNUC__) || defined(__clang__)
239
#define CROARING_WARN_UNUSED __attribute__((warn_unused_result))
240
#else
241
#define CROARING_WARN_UNUSED
242
#endif
243
244
#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100)
245
246
#ifdef CROARING_USENEON
247
// we can always compute the popcount fast.
248
#elif (defined(_M_ARM) || defined(_M_ARM64)) && \
249
    ((defined(_WIN64) || defined(_WIN32)) &&    \
250
     defined(CROARING_REGULAR_VISUAL_STUDIO) && \
251
     CROARING_REGULAR_VISUAL_STUDIO)
252
// we will need this function:
253
static inline int roaring_hamming_backup(uint64_t x) {
254
    uint64_t c1 = UINT64_C(0x5555555555555555);
255
    uint64_t c2 = UINT64_C(0x3333333333333333);
256
    uint64_t c4 = UINT64_C(0x0F0F0F0F0F0F0F0F);
257
    x -= (x >> 1) & c1;
258
    x = ((x >> 2) & c2) + (x & c2);
259
    x = (x + (x >> 4)) & c4;
260
    x *= UINT64_C(0x0101010101010101);
261
    return x >> 56;
262
}
263
#endif
264
265
0
static inline int roaring_hamming(uint64_t x) {
266
#if defined(_WIN64) && defined(CROARING_REGULAR_VISUAL_STUDIO) && \
267
    CROARING_REGULAR_VISUAL_STUDIO
268
#ifdef CROARING_USENEON
269
    return vaddv_u8(vcnt_u8(vcreate_u8(input_num)));
270
#elif defined(_M_ARM64)
271
    return roaring_hamming_backup(x);
272
    // (int) _CountOneBits64(x); is unavailable
273
#else   // _M_ARM64
274
    return (int)__popcnt64(x);
275
#endif  // _M_ARM64
276
#elif defined(_WIN32) && defined(CROARING_REGULAR_VISUAL_STUDIO) && \
277
    CROARING_REGULAR_VISUAL_STUDIO
278
#ifdef _M_ARM
279
    return roaring_hamming_backup(x);
280
    // _CountOneBits is unavailable
281
#else   // _M_ARM
282
    return (int)__popcnt((unsigned int)x) +
283
           (int)__popcnt((unsigned int)(x >> 32));
284
#endif  // _M_ARM
285
#else
286
0
    return __builtin_popcountll(x);
287
0
#endif
288
0
}
Unexecuted instantiation: croaring_fuzzer.c:roaring_hamming
Unexecuted instantiation: roaring.c:roaring_hamming
Unexecuted instantiation: roaring64.c:roaring_hamming
Unexecuted instantiation: roaring_array.c:roaring_hamming
Unexecuted instantiation: array_util.c:roaring_hamming
Unexecuted instantiation: bitset_util.c:roaring_hamming
Unexecuted instantiation: art.c:roaring_hamming
Unexecuted instantiation: bitset.c:roaring_hamming
Unexecuted instantiation: array.c:roaring_hamming
Unexecuted instantiation: containers.c:roaring_hamming
Unexecuted instantiation: convert.c:roaring_hamming
Unexecuted instantiation: mixed_intersection.c:roaring_hamming
Unexecuted instantiation: mixed_union.c:roaring_hamming
Unexecuted instantiation: mixed_equal.c:roaring_hamming
Unexecuted instantiation: mixed_subset.c:roaring_hamming
Unexecuted instantiation: mixed_negation.c:roaring_hamming
Unexecuted instantiation: mixed_xor.c:roaring_hamming
Unexecuted instantiation: mixed_andnot.c:roaring_hamming
Unexecuted instantiation: run.c:roaring_hamming
Unexecuted instantiation: isadetection.c:roaring_hamming
289
290
#ifndef UINT64_C
291
#define UINT64_C(c) (c##ULL)
292
#endif  // UINT64_C
293
294
#ifndef UINT32_C
295
#define UINT32_C(c) (c##UL)
296
#endif  // UINT32_C
297
298
#ifdef __cplusplus
299
}  // extern "C" {
300
#endif  // __cplusplus
301
302
// this is almost standard?
303
#undef STRINGIFY_IMPLEMENTATION_
304
#undef STRINGIFY
305
#define STRINGIFY_IMPLEMENTATION_(a) #a
306
#define STRINGIFY(a) STRINGIFY_IMPLEMENTATION_(a)
307
308
// Our fast kernels require 64-bit systems.
309
//
310
// On 32-bit x86, we lack 64-bit popcnt, lzcnt, blsr instructions.
311
// Furthermore, the number of SIMD registers is reduced.
312
//
313
// On 32-bit ARM, we would have smaller registers.
314
//
315
// The library should still have the fallback kernel. It is
316
// slower, but it should run everywhere.
317
318
//
319
// Enable valid runtime implementations, and select
320
// CROARING_BUILTIN_IMPLEMENTATION
321
//
322
323
// We are going to use runtime dispatch.
324
#if CROARING_IS_X64
325
#ifdef __clang__
326
// clang does not have GCC push pop
327
// warning: clang attribute push can't be used within a namespace in clang up
328
// til 8.0 so CROARING_TARGET_REGION and CROARING_UNTARGET_REGION must be
329
// *outside* of a namespace.
330
#define CROARING_TARGET_REGION(T)                                      \
331
    _Pragma(STRINGIFY(clang attribute push(__attribute__((target(T))), \
332
                                           apply_to = function)))
333
#define CROARING_UNTARGET_REGION _Pragma("clang attribute pop")
334
#elif defined(__GNUC__)
335
// GCC is easier
336
#define CROARING_TARGET_REGION(T) \
337
    _Pragma("GCC push_options") _Pragma(STRINGIFY(GCC target(T)))
338
#define CROARING_UNTARGET_REGION _Pragma("GCC pop_options")
339
#endif  // clang then gcc
340
341
#endif  // CROARING_IS_X64
342
343
// Default target region macros don't do anything.
344
#ifndef CROARING_TARGET_REGION
345
#define CROARING_TARGET_REGION(T)
346
#define CROARING_UNTARGET_REGION
347
#endif
348
349
#define CROARING_TARGET_AVX2 \
350
    CROARING_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
351
#define CROARING_TARGET_AVX512                                         \
352
    CROARING_TARGET_REGION(                                            \
353
        "avx2,bmi,bmi2,pclmul,lzcnt,popcnt,avx512f,avx512dq,avx512bw," \
354
        "avx512vbmi2,avx512bitalg,avx512vpopcntdq")
355
#define CROARING_UNTARGET_AVX2 CROARING_UNTARGET_REGION
356
#define CROARING_UNTARGET_AVX512 CROARING_UNTARGET_REGION
357
358
#ifdef __AVX2__
359
// No need for runtime dispatching.
360
// It is unnecessary and harmful to old clang to tag regions.
361
#undef CROARING_TARGET_AVX2
362
#define CROARING_TARGET_AVX2
363
#undef CROARING_UNTARGET_AVX2
364
#define CROARING_UNTARGET_AVX2
365
#endif
366
367
#if defined(__AVX512F__) && defined(__AVX512DQ__) && defined(__AVX512BW__) && \
368
    defined(__AVX512VBMI2__) && defined(__AVX512BITALG__) &&                  \
369
    defined(__AVX512VPOPCNTDQ__)
370
// No need for runtime dispatching.
371
// It is unnecessary and harmful to old clang to tag regions.
372
#undef CROARING_TARGET_AVX512
373
#define CROARING_TARGET_AVX512
374
#undef CROARING_UNTARGET_AVX512
375
#define CROARING_UNTARGET_AVX512
376
#endif
377
378
// Allow unaligned memory access
379
#if defined(__GNUC__) || defined(__clang__)
380
#define CROARING_ALLOW_UNALIGNED __attribute__((no_sanitize("alignment")))
381
#else
382
#define CROARING_ALLOW_UNALIGNED
383
#endif
384
385
#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
386
#define CROARING_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
387
#elif defined(_WIN32)
388
#define CROARING_IS_BIG_ENDIAN 0
389
#else
390
#if defined(__APPLE__) || \
391
    defined(__FreeBSD__)  // defined __BYTE_ORDER__ && defined
392
                          // __ORDER_BIG_ENDIAN__
393
#include <machine/endian.h>
394
#elif defined(sun) || \
395
    defined(__sun)  // defined(__APPLE__) || defined(__FreeBSD__)
396
#include <sys/byteorder.h>
397
#else  // defined(__APPLE__) || defined(__FreeBSD__)
398
399
#ifdef __has_include
400
#if __has_include(<endian.h>)
401
#include <endian.h>
402
#endif  //__has_include(<endian.h>)
403
#endif  //__has_include
404
405
#endif  // defined(__APPLE__) || defined(__FreeBSD__)
406
407
#ifndef !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__)
408
#define CROARING_IS_BIG_ENDIAN 0
409
#endif
410
411
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
412
#define CROARING_IS_BIG_ENDIAN 0
413
#else  // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
414
#define CROARING_IS_BIG_ENDIAN 1
415
#endif  // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
416
#endif
417
418
// Host <-> big endian conversion.
419
#if CROARING_IS_BIG_ENDIAN
420
#define croaring_htobe64(x) (x)
421
422
#elif defined(_WIN32) || defined(_WIN64)  // CROARING_IS_BIG_ENDIAN
423
#include <stdlib.h>
424
#define croaring_htobe64(x) _byteswap_uint64(x)
425
426
#elif defined(__APPLE__)  // CROARING_IS_BIG_ENDIAN
427
#include <libkern/OSByteOrder.h>
428
#define croaring_htobe64(x) OSSwapInt64(x)
429
430
#elif defined(__has_include) && \
431
    __has_include(              \
432
        <byteswap.h>)  && (defined(__linux__) || defined(__FreeBSD__))  // CROARING_IS_BIG_ENDIAN
433
#include <byteswap.h>
434
#if defined(__linux__)
435
1.15M
#define croaring_htobe64(x) bswap_64(x)
436
#elif defined(__FreeBSD__)
437
#define croaring_htobe64(x) bswap64(x)
438
#else
439
#warning "Unknown platform, report as an error"
440
#endif
441
442
#else  // CROARING_IS_BIG_ENDIAN
443
// Gets compiled to bswap or equivalent on most compilers.
444
#define croaring_htobe64(x)                                                    \
445
    (((x & 0x00000000000000FFULL) << 56) |                                     \
446
     ((x & 0x000000000000FF00ULL) << 40) |                                     \
447
     ((x & 0x0000000000FF0000ULL) << 24) |                                     \
448
     ((x & 0x00000000FF000000ULL) << 8) | ((x & 0x000000FF00000000ULL) >> 8) | \
449
     ((x & 0x0000FF0000000000ULL) >> 24) |                                     \
450
     ((x & 0x00FF000000000000ULL) >> 40) |                                     \
451
     ((x & 0xFF00000000000000ULL) >> 56))
452
#endif  // CROARING_IS_BIG_ENDIAN
453
0
#define croaring_be64toh(x) croaring_htobe64(x)
454
// End of host <-> big endian conversion.
455
456
// Defines for the possible CROARING atomic implementations
457
#define CROARING_ATOMIC_IMPL_NONE 1
458
#define CROARING_ATOMIC_IMPL_CPP 2
459
#define CROARING_ATOMIC_IMPL_C 3
460
#define CROARING_ATOMIC_IMPL_C_WINDOWS 4
461
462
// If the use has forced a specific implementation, use that, otherwise,
463
// figure out the best implementation we can use.
464
#if !defined(CROARING_ATOMIC_IMPL)
465
#if defined(__cplusplus) && __cplusplus >= 201103L
466
#ifdef __has_include
467
#if __has_include(<atomic>)
468
#define CROARING_ATOMIC_IMPL CROARING_ATOMIC_IMPL_CPP
469
#endif  //__has_include(<atomic>)
470
#else
471
   // We lack __has_include to check:
472
#define CROARING_ATOMIC_IMPL CROARING_ATOMIC_IMPL_CPP
473
#endif  //__has_include
474
#elif __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
475
#define CROARING_ATOMIC_IMPL CROARING_ATOMIC_IMPL_C
476
#elif CROARING_REGULAR_VISUAL_STUDIO
477
   // https://www.technetworkhub.com/c11-atomics-in-visual-studio-2022-version-17/
478
#define CROARING_ATOMIC_IMPL CROARING_ATOMIC_IMPL_C_WINDOWS
479
#endif
480
#endif  // !defined(CROARING_ATOMIC_IMPL)
481
482
#if CROARING_ATOMIC_IMPL == CROARING_ATOMIC_IMPL_C
483
#include <stdatomic.h>
484
typedef _Atomic(uint32_t) croaring_refcount_t;
485
486
0
static inline void croaring_refcount_inc(croaring_refcount_t *val) {
487
    // Increasing the reference counter can always be done with
488
    // memory_order_relaxed: New references to an object can only be formed from
489
    // an existing reference, and passing an existing reference from one thread
490
    // to another must already provide any required synchronization.
491
0
    atomic_fetch_add_explicit(val, 1, memory_order_relaxed);
492
0
}
Unexecuted instantiation: croaring_fuzzer.c:croaring_refcount_inc
Unexecuted instantiation: roaring.c:croaring_refcount_inc
Unexecuted instantiation: roaring64.c:croaring_refcount_inc
Unexecuted instantiation: roaring_array.c:croaring_refcount_inc
Unexecuted instantiation: array_util.c:croaring_refcount_inc
Unexecuted instantiation: bitset_util.c:croaring_refcount_inc
Unexecuted instantiation: art.c:croaring_refcount_inc
Unexecuted instantiation: bitset.c:croaring_refcount_inc
Unexecuted instantiation: array.c:croaring_refcount_inc
Unexecuted instantiation: containers.c:croaring_refcount_inc
Unexecuted instantiation: convert.c:croaring_refcount_inc
Unexecuted instantiation: mixed_intersection.c:croaring_refcount_inc
Unexecuted instantiation: mixed_union.c:croaring_refcount_inc
Unexecuted instantiation: mixed_equal.c:croaring_refcount_inc
Unexecuted instantiation: mixed_subset.c:croaring_refcount_inc
Unexecuted instantiation: mixed_negation.c:croaring_refcount_inc
Unexecuted instantiation: mixed_xor.c:croaring_refcount_inc
Unexecuted instantiation: mixed_andnot.c:croaring_refcount_inc
Unexecuted instantiation: run.c:croaring_refcount_inc
Unexecuted instantiation: isadetection.c:croaring_refcount_inc
493
494
0
static inline bool croaring_refcount_dec(croaring_refcount_t *val) {
495
    // It is important to enforce any possible access to the object in one
496
    // thread (through an existing reference) to happen before deleting the
497
    // object in a different thread. This is achieved by a "release" operation
498
    // after dropping a reference (any access to the object through this
499
    // reference must obviously happened before), and an "acquire" operation
500
    // before deleting the object.
501
0
    bool is_zero = atomic_fetch_sub_explicit(val, 1, memory_order_release) == 1;
502
0
    if (is_zero) {
503
0
        atomic_thread_fence(memory_order_acquire);
504
0
    }
505
0
    return is_zero;
506
0
}
Unexecuted instantiation: croaring_fuzzer.c:croaring_refcount_dec
Unexecuted instantiation: roaring.c:croaring_refcount_dec
Unexecuted instantiation: roaring64.c:croaring_refcount_dec
Unexecuted instantiation: roaring_array.c:croaring_refcount_dec
Unexecuted instantiation: array_util.c:croaring_refcount_dec
Unexecuted instantiation: bitset_util.c:croaring_refcount_dec
Unexecuted instantiation: art.c:croaring_refcount_dec
Unexecuted instantiation: bitset.c:croaring_refcount_dec
Unexecuted instantiation: array.c:croaring_refcount_dec
Unexecuted instantiation: containers.c:croaring_refcount_dec
Unexecuted instantiation: convert.c:croaring_refcount_dec
Unexecuted instantiation: mixed_intersection.c:croaring_refcount_dec
Unexecuted instantiation: mixed_union.c:croaring_refcount_dec
Unexecuted instantiation: mixed_equal.c:croaring_refcount_dec
Unexecuted instantiation: mixed_subset.c:croaring_refcount_dec
Unexecuted instantiation: mixed_negation.c:croaring_refcount_dec
Unexecuted instantiation: mixed_xor.c:croaring_refcount_dec
Unexecuted instantiation: mixed_andnot.c:croaring_refcount_dec
Unexecuted instantiation: run.c:croaring_refcount_dec
Unexecuted instantiation: isadetection.c:croaring_refcount_dec
507
508
0
static inline uint32_t croaring_refcount_get(const croaring_refcount_t *val) {
509
0
    return atomic_load_explicit(val, memory_order_relaxed);
510
0
}
Unexecuted instantiation: croaring_fuzzer.c:croaring_refcount_get
Unexecuted instantiation: roaring.c:croaring_refcount_get
Unexecuted instantiation: roaring64.c:croaring_refcount_get
Unexecuted instantiation: roaring_array.c:croaring_refcount_get
Unexecuted instantiation: array_util.c:croaring_refcount_get
Unexecuted instantiation: bitset_util.c:croaring_refcount_get
Unexecuted instantiation: art.c:croaring_refcount_get
Unexecuted instantiation: bitset.c:croaring_refcount_get
Unexecuted instantiation: array.c:croaring_refcount_get
Unexecuted instantiation: containers.c:croaring_refcount_get
Unexecuted instantiation: convert.c:croaring_refcount_get
Unexecuted instantiation: mixed_intersection.c:croaring_refcount_get
Unexecuted instantiation: mixed_union.c:croaring_refcount_get
Unexecuted instantiation: mixed_equal.c:croaring_refcount_get
Unexecuted instantiation: mixed_subset.c:croaring_refcount_get
Unexecuted instantiation: mixed_negation.c:croaring_refcount_get
Unexecuted instantiation: mixed_xor.c:croaring_refcount_get
Unexecuted instantiation: mixed_andnot.c:croaring_refcount_get
Unexecuted instantiation: run.c:croaring_refcount_get
Unexecuted instantiation: isadetection.c:croaring_refcount_get
511
#elif CROARING_ATOMIC_IMPL == CROARING_ATOMIC_IMPL_CPP
512
#include <atomic>
513
typedef std::atomic<uint32_t> croaring_refcount_t;
514
515
static inline void croaring_refcount_inc(croaring_refcount_t *val) {
516
    val->fetch_add(1, std::memory_order_relaxed);
517
}
518
519
static inline bool croaring_refcount_dec(croaring_refcount_t *val) {
520
    // See above comments on the c11 atomic implementation for memory ordering
521
    bool is_zero = val->fetch_sub(1, std::memory_order_release) == 1;
522
    if (is_zero) {
523
        std::atomic_thread_fence(std::memory_order_acquire);
524
    }
525
    return is_zero;
526
}
527
528
static inline uint32_t croaring_refcount_get(const croaring_refcount_t *val) {
529
    return val->load(std::memory_order_relaxed);
530
}
531
#elif CROARING_ATOMIC_IMPL == CROARING_ATOMIC_IMPL_C_WINDOWS
532
#include <intrin.h>
533
#pragma intrinsic(_InterlockedIncrement)
534
#pragma intrinsic(_InterlockedDecrement)
535
536
// _InterlockedIncrement and _InterlockedDecrement take a (signed) long, and
537
// overflow is defined to wrap, so we can pretend it is a uint32_t for our case
538
typedef volatile long croaring_refcount_t;
539
540
static inline void croaring_refcount_inc(croaring_refcount_t *val) {
541
    _InterlockedIncrement(val);
542
}
543
544
static inline bool croaring_refcount_dec(croaring_refcount_t *val) {
545
    return _InterlockedDecrement(val) == 0;
546
}
547
548
static inline uint32_t croaring_refcount_get(const croaring_refcount_t *val) {
549
    // Per
550
    // https://learn.microsoft.com/en-us/windows/win32/sync/interlocked-variable-access
551
    // > Simple reads and writes to properly-aligned 32-bit variables are atomic
552
    // > operations. In other words, you will not end up with only one portion
553
    // > of the variable updated; all bits are updated in an atomic fashion.
554
    return *val;
555
}
556
#elif CROARING_ATOMIC_IMPL == CROARING_ATOMIC_IMPL_NONE
557
#include <assert.h>
558
typedef uint32_t croaring_refcount_t;
559
560
static inline void croaring_refcount_inc(croaring_refcount_t *val) {
561
    *val += 1;
562
}
563
564
static inline bool croaring_refcount_dec(croaring_refcount_t *val) {
565
    assert(*val > 0);
566
    *val -= 1;
567
    return val == 0;
568
}
569
570
static inline uint32_t croaring_refcount_get(const croaring_refcount_t *val) {
571
    return *val;
572
}
573
#else
574
#error "Unknown atomic implementation"
575
#endif
576
577
#if defined(__GNUC__) || defined(__clang__)
578
#define CROARING_DEPRECATED __attribute__((deprecated))
579
#elif defined(_MSC_VER)
580
#define CROARING_DEPRECATED __declspec(deprecated)
581
#else
582
#define CROARING_DEPRECATED
583
#endif  // defined(__GNUC__) || defined(__clang__)
584
585
// We want to initialize structs to zero portably (C and C++), without
586
// warnings. We can do mystruct s = CROARING_ZERO_INITIALIZER;
587
#if __cplusplus
588
#define CROARING_ZERO_INITIALIZER \
589
    {}
590
#else
591
#define CROARING_ZERO_INITIALIZER \
592
3.83k
    { 0 }
593
#endif
594
595
#if defined(__cplusplus)
596
#define CROARING_STATIC_ASSERT(x, y) static_assert(x, y)
597
#else
598
0
#define CROARING_STATIC_ASSERT(x, y) _Static_assert(x, y)
599
#endif
600
601
// We need portability.h to be included first,
602
// but we also always want isadetection.h to be
603
// included (right after).
604
// See https://github.com/RoaringBitmap/CRoaring/issues/394
605
// There is no scenario where we want portability.h to
606
// be included, but not isadetection.h: the latter is a
607
// strict requirement.
608
#include <roaring/isadetection.h>  // include it last!
609
#endif                             /* INCLUDE_PORTABILITY_H_ */