Coverage Report

Created: 2025-07-23 06:32

/src/croaring/include/roaring/portability.h
Line
Count
Source (jump to first uncovered line)
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 !CROARING_REGULAR_VISUAL_STUDIO
154
/* Non-Microsoft C/C++-compatible compiler, assumes that it supports inline
155
 * assembly */
156
#define CROARING_INLINE_ASM 1
157
#endif  // _MSC_VER
158
159
#if CROARING_REGULAR_VISUAL_STUDIO
160
/* Microsoft C/C++-compatible compiler */
161
#include <intrin.h>
162
163
#ifndef __clang__  // if one compiles with MSVC *with* clang, then these
164
                   // intrinsics are defined!!!
165
#define CROARING_INTRINSICS 1
166
// sadly there is no way to check whether we are missing these intrinsics
167
// specifically.
168
169
/* wrappers for Visual Studio built-ins that look like gcc built-ins
170
 * __builtin_ctzll */
171
/** result might be undefined when input_num is zero */
172
inline int roaring_trailing_zeroes(unsigned long long input_num) {
173
    unsigned long index;
174
#ifdef _WIN64  // highly recommended!!!
175
    _BitScanForward64(&index, input_num);
176
#else   // if we must support 32-bit Windows
177
    if ((uint32_t)input_num != 0) {
178
        _BitScanForward(&index, (uint32_t)input_num);
179
    } else {
180
        _BitScanForward(&index, (uint32_t)(input_num >> 32));
181
        index += 32;
182
    }
183
#endif  // _WIN64
184
    return index;
185
}
186
187
/* wrappers for Visual Studio built-ins that look like gcc built-ins
188
 * __builtin_clzll */
189
/** result might be undefined when input_num is zero */
190
inline int roaring_leading_zeroes(unsigned long long input_num) {
191
    unsigned long index;
192
#ifdef _WIN64  // highly recommended!!!
193
    _BitScanReverse64(&index, input_num);
194
#else   // if we must support 32-bit Windows
195
    if (input_num > 0xFFFFFFFF) {
196
        _BitScanReverse(&index, (uint32_t)(input_num >> 32));
197
        index += 32;
198
    } else {
199
        _BitScanReverse(&index, (uint32_t)(input_num));
200
    }
201
#endif  // _WIN64
202
    return 63 - index;
203
}
204
205
/* Use #define so this is effective even under /Ob0 (no inline) */
206
#define roaring_unreachable __assume(0)
207
#endif  // __clang__
208
209
#endif  // CROARING_REGULAR_VISUAL_STUDIO
210
211
#ifndef CROARING_INTRINSICS
212
#define CROARING_INTRINSICS 1
213
0
#define roaring_unreachable __builtin_unreachable()
214
/** result might be undefined when input_num is zero */
215
174k
inline int roaring_trailing_zeroes(unsigned long long input_num) {
216
174k
    return __builtin_ctzll(input_num);
217
174k
}
218
/** result might be undefined when input_num is zero */
219
0
inline int roaring_leading_zeroes(unsigned long long input_num) {
220
0
    return __builtin_clzll(input_num);
221
0
}
222
#endif
223
224
#if CROARING_REGULAR_VISUAL_STUDIO
225
#define ALIGNED(x) __declspec(align(x))
226
#elif defined(__GNUC__) || defined(__clang__)
227
#define ALIGNED(x) __attribute__((aligned(x)))
228
#else
229
#warning "Warning. Unrecognized compiler."
230
#define ALIGNED(x)
231
#endif
232
233
#if defined(__GNUC__) || defined(__clang__)
234
#define CROARING_WARN_UNUSED __attribute__((warn_unused_result))
235
#else
236
#define CROARING_WARN_UNUSED
237
#endif
238
239
#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100)
240
241
#ifdef CROARING_USENEON
242
// we can always compute the popcount fast.
243
#elif (defined(_M_ARM) || defined(_M_ARM64)) && \
244
    ((defined(_WIN64) || defined(_WIN32)) &&    \
245
     defined(CROARING_REGULAR_VISUAL_STUDIO) && \
246
     CROARING_REGULAR_VISUAL_STUDIO)
247
// we will need this function:
248
static inline int roaring_hamming_backup(uint64_t x) {
249
    uint64_t c1 = UINT64_C(0x5555555555555555);
250
    uint64_t c2 = UINT64_C(0x3333333333333333);
251
    uint64_t c4 = UINT64_C(0x0F0F0F0F0F0F0F0F);
252
    x -= (x >> 1) & c1;
253
    x = ((x >> 2) & c2) + (x & c2);
254
    x = (x + (x >> 4)) & c4;
255
    x *= UINT64_C(0x0101010101010101);
256
    return x >> 56;
257
}
258
#endif
259
260
0
static inline int roaring_hamming(uint64_t x) {
261
#if defined(_WIN64) && defined(CROARING_REGULAR_VISUAL_STUDIO) && \
262
    CROARING_REGULAR_VISUAL_STUDIO
263
#ifdef CROARING_USENEON
264
    return vaddv_u8(vcnt_u8(vcreate_u8(input_num)));
265
#elif defined(_M_ARM64)
266
    return roaring_hamming_backup(x);
267
    // (int) _CountOneBits64(x); is unavailable
268
#else   // _M_ARM64
269
    return (int)__popcnt64(x);
270
#endif  // _M_ARM64
271
#elif defined(_WIN32) && defined(CROARING_REGULAR_VISUAL_STUDIO) && \
272
    CROARING_REGULAR_VISUAL_STUDIO
273
#ifdef _M_ARM
274
    return roaring_hamming_backup(x);
275
    // _CountOneBits is unavailable
276
#else   // _M_ARM
277
    return (int)__popcnt((unsigned int)x) +
278
           (int)__popcnt((unsigned int)(x >> 32));
279
#endif  // _M_ARM
280
#else
281
0
    return __builtin_popcountll(x);
282
0
#endif
283
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
284
285
#ifndef UINT64_C
286
#define UINT64_C(c) (c##ULL)
287
#endif  // UINT64_C
288
289
#ifndef UINT32_C
290
#define UINT32_C(c) (c##UL)
291
#endif  // UINT32_C
292
293
#ifdef __cplusplus
294
}  // extern "C" {
295
#endif  // __cplusplus
296
297
// this is almost standard?
298
#undef STRINGIFY_IMPLEMENTATION_
299
#undef STRINGIFY
300
#define STRINGIFY_IMPLEMENTATION_(a) #a
301
#define STRINGIFY(a) STRINGIFY_IMPLEMENTATION_(a)
302
303
// Our fast kernels require 64-bit systems.
304
//
305
// On 32-bit x86, we lack 64-bit popcnt, lzcnt, blsr instructions.
306
// Furthermore, the number of SIMD registers is reduced.
307
//
308
// On 32-bit ARM, we would have smaller registers.
309
//
310
// The library should still have the fallback kernel. It is
311
// slower, but it should run everywhere.
312
313
//
314
// Enable valid runtime implementations, and select
315
// CROARING_BUILTIN_IMPLEMENTATION
316
//
317
318
// We are going to use runtime dispatch.
319
#if CROARING_IS_X64
320
#ifdef __clang__
321
// clang does not have GCC push pop
322
// warning: clang attribute push can't be used within a namespace in clang up
323
// til 8.0 so CROARING_TARGET_REGION and CROARING_UNTARGET_REGION must be
324
// *outside* of a namespace.
325
#define CROARING_TARGET_REGION(T)                                      \
326
    _Pragma(STRINGIFY(clang attribute push(__attribute__((target(T))), \
327
                                           apply_to = function)))
328
#define CROARING_UNTARGET_REGION _Pragma("clang attribute pop")
329
#elif defined(__GNUC__)
330
// GCC is easier
331
#define CROARING_TARGET_REGION(T) \
332
    _Pragma("GCC push_options") _Pragma(STRINGIFY(GCC target(T)))
333
#define CROARING_UNTARGET_REGION _Pragma("GCC pop_options")
334
#endif  // clang then gcc
335
336
#endif  // CROARING_IS_X64
337
338
// Default target region macros don't do anything.
339
#ifndef CROARING_TARGET_REGION
340
#define CROARING_TARGET_REGION(T)
341
#define CROARING_UNTARGET_REGION
342
#endif
343
344
#define CROARING_TARGET_AVX2 \
345
    CROARING_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
346
#define CROARING_TARGET_AVX512                                         \
347
    CROARING_TARGET_REGION(                                            \
348
        "avx2,bmi,bmi2,pclmul,lzcnt,popcnt,avx512f,avx512dq,avx512bw," \
349
        "avx512vbmi2,avx512bitalg,avx512vpopcntdq")
350
#define CROARING_UNTARGET_AVX2 CROARING_UNTARGET_REGION
351
#define CROARING_UNTARGET_AVX512 CROARING_UNTARGET_REGION
352
353
#ifdef __AVX2__
354
// No need for runtime dispatching.
355
// It is unnecessary and harmful to old clang to tag regions.
356
#undef CROARING_TARGET_AVX2
357
#define CROARING_TARGET_AVX2
358
#undef CROARING_UNTARGET_AVX2
359
#define CROARING_UNTARGET_AVX2
360
#endif
361
362
#if defined(__AVX512F__) && defined(__AVX512DQ__) && defined(__AVX512BW__) && \
363
    defined(__AVX512VBMI2__) && defined(__AVX512BITALG__) &&                  \
364
    defined(__AVX512VPOPCNTDQ__)
365
// No need for runtime dispatching.
366
// It is unnecessary and harmful to old clang to tag regions.
367
#undef CROARING_TARGET_AVX512
368
#define CROARING_TARGET_AVX512
369
#undef CROARING_UNTARGET_AVX512
370
#define CROARING_UNTARGET_AVX512
371
#endif
372
373
// Allow unaligned memory access
374
#if defined(__GNUC__) || defined(__clang__)
375
#define ALLOW_UNALIGNED __attribute__((no_sanitize("alignment")))
376
#else
377
#define ALLOW_UNALIGNED
378
#endif
379
380
#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
381
#define CROARING_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
382
#elif defined(_WIN32)
383
#define CROARING_IS_BIG_ENDIAN 0
384
#else
385
#if defined(__APPLE__) || \
386
    defined(__FreeBSD__)  // defined __BYTE_ORDER__ && defined
387
                          // __ORDER_BIG_ENDIAN__
388
#include <machine/endian.h>
389
#elif defined(sun) || \
390
    defined(__sun)  // defined(__APPLE__) || defined(__FreeBSD__)
391
#include <sys/byteorder.h>
392
#else  // defined(__APPLE__) || defined(__FreeBSD__)
393
394
#ifdef __has_include
395
#if __has_include(<endian.h>)
396
#include <endian.h>
397
#endif  //__has_include(<endian.h>)
398
#endif  //__has_include
399
400
#endif  // defined(__APPLE__) || defined(__FreeBSD__)
401
402
#ifndef !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__)
403
#define CROARING_IS_BIG_ENDIAN 0
404
#endif
405
406
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
407
#define CROARING_IS_BIG_ENDIAN 0
408
#else  // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
409
#define CROARING_IS_BIG_ENDIAN 1
410
#endif  // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
411
#endif
412
413
// Host <-> big endian conversion.
414
#if CROARING_IS_BIG_ENDIAN
415
#define croaring_htobe64(x) (x)
416
417
#elif defined(_WIN32) || defined(_WIN64)  // CROARING_IS_BIG_ENDIAN
418
#include <stdlib.h>
419
#define croaring_htobe64(x) _byteswap_uint64(x)
420
421
#elif defined(__APPLE__)  // CROARING_IS_BIG_ENDIAN
422
#include <libkern/OSByteOrder.h>
423
#define croaring_htobe64(x) OSSwapInt64(x)
424
425
#elif defined(__has_include) && \
426
    __has_include(              \
427
        <byteswap.h>)  && (defined(__linux__) || defined(__FreeBSD__))  // CROARING_IS_BIG_ENDIAN
428
#include <byteswap.h>
429
#if defined(__linux__)
430
1.10M
#define croaring_htobe64(x) bswap_64(x)
431
#elif defined(__FreeBSD__)
432
#define croaring_htobe64(x) bswap64(x)
433
#else
434
#warning "Unknown platform, report as an error"
435
#endif
436
437
#else  // CROARING_IS_BIG_ENDIAN
438
// Gets compiled to bswap or equivalent on most compilers.
439
#define croaring_htobe64(x)                                                    \
440
    (((x & 0x00000000000000FFULL) << 56) |                                     \
441
     ((x & 0x000000000000FF00ULL) << 40) |                                     \
442
     ((x & 0x0000000000FF0000ULL) << 24) |                                     \
443
     ((x & 0x00000000FF000000ULL) << 8) | ((x & 0x000000FF00000000ULL) >> 8) | \
444
     ((x & 0x0000FF0000000000ULL) >> 24) |                                     \
445
     ((x & 0x00FF000000000000ULL) >> 40) |                                     \
446
     ((x & 0xFF00000000000000ULL) >> 56))
447
#endif  // CROARING_IS_BIG_ENDIAN
448
0
#define croaring_be64toh(x) croaring_htobe64(x)
449
// End of host <-> big endian conversion.
450
451
// Defines for the possible CROARING atomic implementations
452
#define CROARING_ATOMIC_IMPL_NONE 1
453
#define CROARING_ATOMIC_IMPL_CPP 2
454
#define CROARING_ATOMIC_IMPL_C 3
455
#define CROARING_ATOMIC_IMPL_C_WINDOWS 4
456
457
// If the use has forced a specific implementation, use that, otherwise,
458
// figure out the best implementation we can use.
459
#if !defined(CROARING_ATOMIC_IMPL)
460
#if defined(__cplusplus) && __cplusplus >= 201103L
461
#ifdef __has_include
462
#if __has_include(<atomic>)
463
#define CROARING_ATOMIC_IMPL CROARING_ATOMIC_IMPL_CPP
464
#endif  //__has_include(<atomic>)
465
#else
466
   // We lack __has_include to check:
467
#define CROARING_ATOMIC_IMPL CROARING_ATOMIC_IMPL_CPP
468
#endif  //__has_include
469
#elif __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
470
#define CROARING_ATOMIC_IMPL CROARING_ATOMIC_IMPL_C
471
#elif CROARING_REGULAR_VISUAL_STUDIO
472
   // https://www.technetworkhub.com/c11-atomics-in-visual-studio-2022-version-17/
473
#define CROARING_ATOMIC_IMPL CROARING_ATOMIC_IMPL_C_WINDOWS
474
#endif
475
#endif  // !defined(CROARING_ATOMIC_IMPL)
476
477
#if CROARING_ATOMIC_IMPL == CROARING_ATOMIC_IMPL_C
478
#include <stdatomic.h>
479
typedef _Atomic(uint32_t) croaring_refcount_t;
480
481
0
static inline void croaring_refcount_inc(croaring_refcount_t *val) {
482
    // Increasing the reference counter can always be done with
483
    // memory_order_relaxed: New references to an object can only be formed from
484
    // an existing reference, and passing an existing reference from one thread
485
    // to another must already provide any required synchronization.
486
0
    atomic_fetch_add_explicit(val, 1, memory_order_relaxed);
487
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
488
489
0
static inline bool croaring_refcount_dec(croaring_refcount_t *val) {
490
    // It is important to enforce any possible access to the object in one
491
    // thread (through an existing reference) to happen before deleting the
492
    // object in a different thread. This is achieved by a "release" operation
493
    // after dropping a reference (any access to the object through this
494
    // reference must obviously happened before), and an "acquire" operation
495
    // before deleting the object.
496
0
    bool is_zero = atomic_fetch_sub_explicit(val, 1, memory_order_release) == 1;
497
0
    if (is_zero) {
498
0
        atomic_thread_fence(memory_order_acquire);
499
0
    }
500
0
    return is_zero;
501
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
502
503
0
static inline uint32_t croaring_refcount_get(const croaring_refcount_t *val) {
504
0
    return atomic_load_explicit(val, memory_order_relaxed);
505
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
506
#elif CROARING_ATOMIC_IMPL == CROARING_ATOMIC_IMPL_CPP
507
#include <atomic>
508
typedef std::atomic<uint32_t> croaring_refcount_t;
509
510
static inline void croaring_refcount_inc(croaring_refcount_t *val) {
511
    val->fetch_add(1, std::memory_order_relaxed);
512
}
513
514
static inline bool croaring_refcount_dec(croaring_refcount_t *val) {
515
    // See above comments on the c11 atomic implementation for memory ordering
516
    bool is_zero = val->fetch_sub(1, std::memory_order_release) == 1;
517
    if (is_zero) {
518
        std::atomic_thread_fence(std::memory_order_acquire);
519
    }
520
    return is_zero;
521
}
522
523
static inline uint32_t croaring_refcount_get(const croaring_refcount_t *val) {
524
    return val->load(std::memory_order_relaxed);
525
}
526
#elif CROARING_ATOMIC_IMPL == CROARING_ATOMIC_IMPL_C_WINDOWS
527
#include <intrin.h>
528
#pragma intrinsic(_InterlockedIncrement)
529
#pragma intrinsic(_InterlockedDecrement)
530
531
// _InterlockedIncrement and _InterlockedDecrement take a (signed) long, and
532
// overflow is defined to wrap, so we can pretend it is a uint32_t for our case
533
typedef volatile long croaring_refcount_t;
534
535
static inline void croaring_refcount_inc(croaring_refcount_t *val) {
536
    _InterlockedIncrement(val);
537
}
538
539
static inline bool croaring_refcount_dec(croaring_refcount_t *val) {
540
    return _InterlockedDecrement(val) == 0;
541
}
542
543
static inline uint32_t croaring_refcount_get(const croaring_refcount_t *val) {
544
    // Per
545
    // https://learn.microsoft.com/en-us/windows/win32/sync/interlocked-variable-access
546
    // > Simple reads and writes to properly-aligned 32-bit variables are atomic
547
    // > operations. In other words, you will not end up with only one portion
548
    // > of the variable updated; all bits are updated in an atomic fashion.
549
    return *val;
550
}
551
#elif CROARING_ATOMIC_IMPL == CROARING_ATOMIC_IMPL_NONE
552
#include <assert.h>
553
typedef uint32_t croaring_refcount_t;
554
555
static inline void croaring_refcount_inc(croaring_refcount_t *val) {
556
    *val += 1;
557
}
558
559
static inline bool croaring_refcount_dec(croaring_refcount_t *val) {
560
    assert(*val > 0);
561
    *val -= 1;
562
    return val == 0;
563
}
564
565
static inline uint32_t croaring_refcount_get(const croaring_refcount_t *val) {
566
    return *val;
567
}
568
#else
569
#error "Unknown atomic implementation"
570
#endif
571
572
#if defined(__GNUC__) || defined(__clang__)
573
#define CROARING_DEPRECATED __attribute__((deprecated))
574
#elif defined(_MSC_VER)
575
#define CROARING_DEPRECATED __declspec(deprecated)
576
#else
577
#define CROARING_DEPRECATED
578
#endif  // defined(__GNUC__) || defined(__clang__)
579
580
// We want to initialize structs to zero portably (C and C++), without
581
// warnings. We can do mystruct s = CROARING_ZERO_INITIALIZER;
582
#if __cplusplus
583
#define CROARING_ZERO_INITIALIZER \
584
    {}
585
#else
586
#define CROARING_ZERO_INITIALIZER \
587
3.72k
    { 0 }
588
#endif
589
590
#if defined(__cplusplus)
591
#define CROARING_STATIC_ASSERT(x, y) static_assert(x, y)
592
#else
593
0
#define CROARING_STATIC_ASSERT(x, y) _Static_assert(x, y)
594
#endif
595
596
// We need portability.h to be included first,
597
// but we also always want isadetection.h to be
598
// included (right after).
599
// See https://github.com/RoaringBitmap/CRoaring/issues/394
600
// There is no scenario where we want portability.h to
601
// be included, but not isadetection.h: the latter is a
602
// strict requirement.
603
#include <roaring/isadetection.h>  // include it last!
604
#endif                             /* INCLUDE_PORTABILITY_H_ */