Coverage Report

Created: 2026-08-13 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/igraph/src/core/bitset.c
Line
Count
Source
1
/*
2
   igraph library.
3
   Copyright (C) 2024  The igraph development team <igraph@igraph.org>
4
5
   This program is free software; you can redistribute it and/or modify
6
   it under the terms of the GNU General Public License as published by
7
   the Free Software Foundation; either version 2 of the License, or
8
   (at your option) any later version.
9
10
   This program is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
   GNU General Public License for more details.
14
15
   You should have received a copy of the GNU General Public License
16
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
*/
18
19
#include "string.h"
20
21
#include "igraph_bitset.h"
22
#include "igraph_memory.h"
23
24
0
igraph_int_t igraph_i_ctz32(igraph_uint_t x) {
25
#ifdef HAVE__BITSCANFORWARD
26
    unsigned long index;
27
    return _BitScanForward(&index, x) ? index : 32;
28
#else
29
0
    for (igraph_int_t i = 0; i < 32; ++i) {
30
0
        if (IGRAPH_BIT_MASK(i) & x) {
31
0
            return i;
32
0
        }
33
0
    }
34
0
    return 32;
35
0
#endif
36
0
}
37
38
0
igraph_int_t igraph_i_clz32(igraph_uint_t x) {
39
#ifdef HAVE_BITSCANREVERSE
40
    unsigned long index;
41
    return _BitScanReverse(&index, x) ? 31 - index : 32;
42
#else
43
0
    for (igraph_int_t i = 31; i >= 0; --i) {
44
0
        if (IGRAPH_BIT_MASK(i) & x) {
45
0
            return 31 - i;
46
0
        }
47
0
    }
48
0
    return 32;
49
0
#endif
50
0
}
51
52
0
igraph_int_t igraph_i_popcnt(igraph_uint_t x) {
53
0
    igraph_int_t result = 0;
54
0
    while (x) {
55
0
        result++;
56
0
        x = x & (x - 1);
57
0
    }
58
0
    return result;
59
0
}
60
61
/* Fallbacks for 64-bit word (and igraph_int_t/igraph_uint_t) size */
62
#if IGRAPH_INTEGER_SIZE == 64
63
0
igraph_int_t igraph_i_ctz64(igraph_uint_t x) {
64
#ifdef HAVE_BITSCANFORWARD64
65
    unsigned long index;
66
    return _BitScanForward64(&index, x) ? index : 64;
67
#else
68
0
    for (igraph_int_t i = 0; i < 64; ++i) {
69
0
        if (IGRAPH_BIT_MASK(i) & x) {
70
0
            return i;
71
0
        }
72
0
    }
73
0
    return 64;
74
0
#endif
75
0
}
76
77
0
igraph_int_t igraph_i_clz64(igraph_uint_t x) {
78
#ifdef HAVE_BITSCANREVERSE64
79
    unsigned long index;
80
    return _BitScanReverse64(&index, x) ? 63 - index : 64;
81
#else
82
0
    for (igraph_int_t i = 63; i >= 0; --i) {
83
0
        if (IGRAPH_BIT_MASK(i) & x) {
84
0
            return 63 - i;
85
0
        }
86
0
    }
87
0
    return 64;
88
0
#endif
89
0
}
90
#endif /* IGRAPH_INTEGER_SIZE == 64 */
91
92
/**
93
 * \ingroup bitset
94
 * \section about_igraph_bitset_t_objects About \type igraph_bitset_t objects
95
 *
96
 * <para>The \type igraph_bitset_t data type is a simple and efficient
97
 * interface to arrays containing boolean values. It is similar to
98
 * the \type bitset template in the C++ standard library, although the main
99
 * difference being the C++ version's size is initialized at compile time.</para>
100
 *
101
 * <para>The \type igraph_bitset_t type and use O(n/w) space
102
 * to store n elements, where w is the bit width of \type igraph_int_t,
103
 * the integer type used throughout the library (either 32 or 64).
104
 * Sometimes they use more, this is because bitsets can
105
 * shrink, but even if they shrink, the current implementation does not free a
106
 * single bit of memory.</para>
107
 *
108
 * <para>The elements in an \type igraph_bitset_t object and its variants are
109
 * indexed from zero, we follow the usual C convention here. Bitsets are indexed
110
 * from right to left, meaning index 0 is the least significant bit and index
111
 * <code>n - 1</code> is the most significant bit.</para>
112
 *
113
 * <para>The elements of a bitset always occupy a single block of
114
 * memory, the starting address of this memory block can be queried
115
 * with the \ref VECTOR() macro. This way, bitset objects can be used
116
 * with standard mathematical libraries, like the GNU Scientific
117
 * Library.</para>
118
 *
119
 * <para>Note that while the interface of bitset functions is similar to
120
 * igraph's vector functions, there is one major difference: bitset functions
121
 * such as \ref igraph_bitset_and() do not verify that that sizes of input
122
 * parameters are compatible, and do not automatically resize the output
123
 * parameter. Doing so is the responsibility of the user.</para>
124
 */
125
126
/**
127
 * \ingroup bitset
128
 * \section igraph_bitset_constructors_and_destructors Constructors and
129
 * destructors
130
 *
131
 * <para>\type igraph_bitset_t objects have to be initialized before using
132
 * them, this is analogous to calling a constructor on them. There are two
133
 * \type igraph_bitset_t constructors, for your convenience.
134
 * \ref igraph_bitset_init() is the basic constructor, it
135
 * creates a bitset of the given length, filled with zeros.
136
 * \ref igraph_bitset_init_copy() creates a new identical copy
137
 * of an already existing and initialized bitset.</para>
138
 *
139
 * <para>If a \type igraph_bitset_t object is not needed any more, it
140
 * should be destroyed to free its allocated memory by calling the
141
 * \type igraph_bitset_t destructor, \ref igraph_bitset_destroy().</para>
142
 */
143
144
/**
145
 * \ingroup bitset
146
 * \function igraph_bitset_init
147
 * \brief Initializes a bitset object (constructor).
148
 *
149
 * </para><para>
150
 * Every bitset needs to be initialized before it can be used, and
151
 * there are a number of initialization functions or otherwise called
152
 * constructors. This function constructs a bitset of the given size and
153
 * initializes each entry to 0.
154
 *
155
 * </para><para>
156
 * Every bitset object initialized by this function should be
157
 * destroyed (ie. the memory allocated for it should be freed) when it
158
 * is not needed anymore, the \ref igraph_bitset_destroy() function is
159
 * responsible for this.
160
 *
161
 * \param bitset Pointer to a not yet initialized bitset object.
162
 * \param size The size of the bitset.
163
 * \return error code:
164
 *       \c IGRAPH_ENOMEM if there is not enough memory.
165
 *
166
 * Time complexity: operating system dependent, the amount of
167
 * \quote time \endquote required to allocate
168
 * O(n/w) elements,
169
 * n is the number of elements.
170
 * w is the word size of the machine (32 or 64).
171
 */
172
173
1.73M
igraph_error_t igraph_bitset_init(igraph_bitset_t *bitset, igraph_int_t size) {
174
1.73M
    igraph_int_t alloc_size = IGRAPH_BIT_NSLOTS(size);
175
1.73M
    bitset->stor_begin = IGRAPH_CALLOC(alloc_size, igraph_uint_t);
176
1.73M
    IGRAPH_CHECK_OOM(bitset->stor_begin, "Cannot initialize bitset.");
177
1.73M
    bitset->size = size;
178
1.73M
    bitset->stor_end = bitset->stor_begin + alloc_size;
179
1.73M
    return IGRAPH_SUCCESS;
180
1.73M
}
181
182
/**
183
 * \ingroup bitset
184
 * \function igraph_bitset_destroy
185
 * \brief Destroys a bitset object.
186
 *
187
 * All bitsets initialized by \ref igraph_bitset_init() should be properly
188
 * destroyed by this function. A destroyed bitset needs to be
189
 * reinitialized by \ref igraph_bitset_init() or
190
 * another constructor.
191
 *
192
 * \param bitset Pointer to the (previously initialized) bitset object to
193
 *        destroy.
194
 *
195
 * Time complexity: operating system dependent.
196
 */
197
198
1.73M
void igraph_bitset_destroy(igraph_bitset_t *bitset) {
199
1.73M
    IGRAPH_ASSERT(bitset != NULL);
200
1.73M
    IGRAPH_FREE(bitset->stor_begin);
201
1.73M
    bitset->size = 0;
202
1.73M
}
203
204
/**
205
 * \ingroup bitset
206
 * \function igraph_bitset_init_copy
207
 * \brief Initializes a bitset from another bitset object (constructor).
208
 *
209
 * The contents of the existing bitset object will be copied to
210
 * the new one.
211
 *
212
 * \param dest Pointer to a not yet initialized bitset object.
213
 * \param src The original bitset object to copy.
214
 * \return Error code:
215
 *         \c IGRAPH_ENOMEM if there is not enough memory.
216
 *
217
 * Time complexity: operating system dependent, usually
218
 * O(n/w),
219
 * n is the size of the bitset,
220
 * w is the word size of the machine (32 or 64).
221
 */
222
223
0
igraph_error_t igraph_bitset_init_copy(igraph_bitset_t *dest, const igraph_bitset_t *src) {
224
0
    IGRAPH_ASSERT(src != NULL);
225
0
    IGRAPH_ASSERT(src->stor_begin != NULL);
226
0
    IGRAPH_CHECK(igraph_bitset_init(dest, src->size));
227
0
    for (igraph_int_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) {
228
0
        VECTOR(*dest)[i] = VECTOR(*src)[i];
229
0
    }
230
0
    return IGRAPH_SUCCESS;
231
0
}
232
233
/**
234
 * \ingroup bitset
235
 * \function igraph_bitset_update
236
 * \brief Update a bitset from another one.
237
 *
238
 * The size and contents of \p dest will be identical to that of \p src.
239
 *
240
 * \param dest Pointer to an initialized bitset object. This will be updated.
241
 * \param src The bitset to update from.
242
 * \return Error code:
243
 *         \c IGRAPH_ENOMEM if there is not enough memory.
244
 *
245
 * Time complexity: operating system dependent, usually
246
 * O(n/w),
247
 * n is the size of the bitset,
248
 * w is the word size of the machine (32 or 64).
249
 */
250
251
0
igraph_error_t igraph_bitset_update(igraph_bitset_t *dest, const igraph_bitset_t *src) {
252
0
    IGRAPH_ASSERT(src != NULL);
253
0
    IGRAPH_ASSERT(src->stor_begin != NULL);
254
0
    IGRAPH_CHECK(igraph_bitset_reserve(dest, src->size));
255
0
    dest->size = src->size;
256
0
    for (igraph_int_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) {
257
0
        VECTOR(*dest)[i] = VECTOR(*src)[i];
258
0
    }
259
0
    return IGRAPH_SUCCESS;
260
0
}
261
262
/**
263
 * \ingroup bitset
264
 * \function igraph_bitset_capacity
265
 * \brief Returns the allocated capacity of the bitset.
266
 *
267
 * Note that this might be different from the size of the bitset (as
268
 * queried by \ref igraph_bitset_size()), and specifies how many elements
269
 * the bitset can hold, without reallocation.
270
 *
271
 * \param bitset Pointer to the (previously initialized) bitset object
272
 *          to query.
273
 * \return The allocated capacity.
274
 *
275
 * \sa \ref igraph_bitset_size().
276
 *
277
 * Time complexity: O(1).
278
 */
279
280
730k
igraph_int_t igraph_bitset_capacity(const igraph_bitset_t *bitset) {
281
730k
    return IGRAPH_INTEGER_SIZE * (bitset->stor_end - bitset->stor_begin);
282
730k
}
283
284
/**
285
 * \ingroup bitset
286
 * \function igraph_bitset_size
287
 * \brief Returns the length of the bitset.
288
 *
289
 * \param bitset The bitset object
290
 * \return The size of the bitset.
291
 *
292
 * Time complexity: O(1).
293
 */
294
295
0
igraph_int_t igraph_bitset_size(const igraph_bitset_t *bitset) {
296
0
    return bitset->size;
297
0
}
298
299
/**
300
 * \ingroup bitset
301
 * \function igraph_bitset_reserve
302
 * \brief Reserves memory for a bitset.
303
 *
304
 * \a igraph bitsets are flexible, they can grow and
305
 * shrink. Growing
306
 * however occasionally needs the data in the bitset to be copied.
307
 * In order to avoid this, you can call this function to reserve space for
308
 * future growth of the bitset.
309
 *
310
 * </para><para>
311
 * Note that this function does \em not change the size of the
312
 * bitset. Let us see a small example to clarify things: if you
313
 * reserve space for 100 elements and the size of your
314
 * bitset was (and still is) 60, then you can surely add additional 40
315
 * elements to your bitset before it will be copied.
316
 *
317
 * \param bitset The bitset object.
318
 * \param capacity The new \em allocated size of the bitset.
319
 * \return Error code:
320
 *         \c IGRAPH_ENOMEM if there is not enough memory.
321
 *
322
 * Time complexity: operating system dependent, should be around
323
 * O(n/w),
324
 * n is the new allocated size of the bitset,
325
 * w is the word size of the machine (32 or 64).
326
 */
327
328
730k
igraph_error_t igraph_bitset_reserve(igraph_bitset_t *bitset, igraph_int_t capacity) {
329
730k
    igraph_int_t current_capacity;
330
730k
    igraph_uint_t *tmp;
331
332
730k
    IGRAPH_ASSERT(bitset != NULL);
333
730k
    IGRAPH_ASSERT(bitset->stor_begin != NULL);
334
730k
    IGRAPH_ASSERT(capacity >= 0);
335
336
730k
    current_capacity = igraph_bitset_capacity(bitset);
337
338
730k
    if (IGRAPH_BIT_NSLOTS(capacity) <= IGRAPH_BIT_NSLOTS(current_capacity)) {
339
156
        return IGRAPH_SUCCESS;
340
156
    }
341
342
729k
    tmp = IGRAPH_REALLOC(bitset->stor_begin, IGRAPH_BIT_NSLOTS(capacity), igraph_uint_t);
343
729k
    IGRAPH_CHECK_OOM(tmp, "Cannot reserve space for bitset.");
344
345
729k
    bitset->stor_begin = tmp;
346
729k
    bitset->stor_end = bitset->stor_begin + IGRAPH_BIT_NSLOTS(capacity);
347
348
729k
    return IGRAPH_SUCCESS;
349
729k
}
350
351
/**
352
 * \ingroup bitset
353
 * \function igraph_bitset_resize
354
 * \brief Resizes the bitset.
355
 *
356
 * Note that this function does not free any memory, just sets the
357
 * size of the bitset to the given one. It may, on the other hand,
358
 * allocate more memory if the new size is larger than the previous
359
 * one. In this case the newly appeared elements in the bitset are
360
 * set to zero.
361
 *
362
 * \param bitset The bitset object
363
 * \param new_size The new size of the bitset.
364
 * \return Error code,
365
 *         \c IGRAPH_ENOMEM if there is not enough
366
 *         memory. Note that this function \em never returns an error
367
 *         if the bitset is made smaller.
368
 * \sa \ref igraph_bitset_reserve() for allocating memory for future
369
 * extensions of a bitset.
370
 *
371
 * Time complexity: O(1) if the new
372
 * size is smaller, operating system dependent if it is larger. In the
373
 * latter case it is usually around
374
 * O(n/w),
375
 * n is the new size of the bitset,
376
 * w is the word size of the machine (32 or 64).
377
 */
378
379
730k
igraph_error_t igraph_bitset_resize(igraph_bitset_t *bitset, igraph_int_t new_size) {
380
730k
    IGRAPH_ASSERT(bitset != NULL);
381
730k
    IGRAPH_ASSERT(bitset->stor_begin != NULL);
382
730k
    IGRAPH_CHECK(igraph_bitset_reserve(bitset, new_size));
383
384
730k
    if (new_size > bitset->size) {
385
729k
        for (igraph_int_t i = bitset->size; i % IGRAPH_INTEGER_SIZE != 0; ++i) {
386
0
            IGRAPH_BIT_CLEAR(*bitset, i);
387
0
        }
388
729k
        memset(bitset->stor_begin + IGRAPH_BIT_NSLOTS(bitset->size), 0,
389
729k
               sizeof(igraph_uint_t) * (IGRAPH_BIT_NSLOTS(new_size) - IGRAPH_BIT_NSLOTS(bitset->size)));
390
729k
    }
391
730k
    bitset->size = new_size;
392
393
730k
    return IGRAPH_SUCCESS;
394
730k
}
395
396
/**
397
 * \ingroup bitset
398
 * \function igraph_bitset_popcount
399
 * \brief The population count of the bitset.
400
 *
401
 * Returns the number of set bits, also called the population count,
402
 * of the bitset.
403
 *
404
 * \param bitset The bitset object
405
 * \return The population count of the bitset.
406
 *
407
 * Time complexity: O(n/w).
408
 */
409
410
376k
igraph_int_t igraph_bitset_popcount(const igraph_bitset_t *bitset) {
411
376k
    const igraph_int_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE;
412
376k
    const igraph_int_t slots = IGRAPH_BIT_NSLOTS(bitset->size);
413
376k
    const igraph_uint_t one = 1, zero = 0; /* to avoid the need to cast 1 and 0 to igraph_uint_t below */
414
376k
    const igraph_uint_t mask = final_block_size == IGRAPH_INTEGER_SIZE ? ~zero : ((one << final_block_size) - 1);
415
376k
    igraph_int_t count = 0;
416
417
1.43M
    for (igraph_int_t i = 0; i + 1 < slots; ++i) {
418
1.06M
        count += IGRAPH_POPCOUNT(VECTOR(*bitset)[i]);
419
1.06M
    }
420
376k
    if (bitset->size) {
421
376k
        count += IGRAPH_POPCOUNT(mask & VECTOR(*bitset)[slots - 1]);
422
376k
    }
423
424
376k
    return count;
425
376k
}
426
427
/**
428
 * \ingroup bitset
429
 * \function igraph_bitset_countl_zero
430
 * \brief The number of leading zeros in the bitset.
431
 *
432
 * Returns the number of leading (starting at the most significant bit)
433
 * zeros in the bitset before the first one is encountered. If the bitset
434
 * is all zeros, then its size is returned.
435
 *
436
 * \param bitset The bitset object
437
 * \return The number of leading zeros in the bitset.
438
 *
439
 * Time complexity: O(n/w).
440
 */
441
442
0
igraph_int_t igraph_bitset_countl_zero(const igraph_bitset_t *bitset) {
443
0
    const igraph_int_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE;
444
0
    const igraph_int_t padding = IGRAPH_INTEGER_SIZE - final_block_size;
445
0
    const igraph_int_t slots = IGRAPH_BIT_NSLOTS(bitset->size);
446
0
    const igraph_uint_t one = 1, zero = 0;
447
0
    const igraph_uint_t mask = final_block_size == IGRAPH_INTEGER_SIZE ? ~zero : ((one << final_block_size) - one);
448
449
0
    if (bitset->size && (mask & VECTOR(*bitset)[slots - 1]) != 0) {
450
0
        return IGRAPH_CLZ(mask & VECTOR(*bitset)[slots - 1]) - padding;
451
0
    }
452
0
    for (igraph_int_t i = 1; i < slots; ++i) {
453
0
        if (VECTOR(*bitset)[slots - i - 1] != 0) {
454
0
            return IGRAPH_INTEGER_SIZE * i + IGRAPH_CLZ(VECTOR(*bitset)[slots - i - 1]) - padding;
455
0
        }
456
0
    }
457
458
0
    return bitset->size;
459
0
}
460
461
/**
462
 * \ingroup bitset
463
 * \function igraph_bitset_countl_one
464
 * \brief The number of leading ones in the bitset.
465
 *
466
 * Returns the number of leading ones (starting at the most significant bit)
467
 * in the bitset before the first zero is encountered.
468
 * If the bitset is all ones, then its size is returned.
469
 *
470
 * \param bitset The bitset object
471
 * \return The number of leading ones in the bitset.
472
 *
473
 * Time complexity: O(n/w).
474
 */
475
476
0
igraph_int_t igraph_bitset_countl_one(const igraph_bitset_t *bitset) {
477
0
    const igraph_int_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE;
478
0
    const igraph_int_t padding = IGRAPH_INTEGER_SIZE - final_block_size;
479
0
    const igraph_int_t slots = IGRAPH_BIT_NSLOTS(bitset->size);
480
0
    const igraph_uint_t one = 1, zero = 0; /* to avoid the need to cast 1 and 0 to igraph_uint_t below */
481
0
    const igraph_uint_t mask = final_block_size == IGRAPH_INTEGER_SIZE ? zero : ~((one << final_block_size) - one);
482
483
0
    if (bitset->size && (mask | VECTOR(*bitset)[slots - 1]) != ~zero) {
484
0
        return IGRAPH_CLO(mask | VECTOR(*bitset)[slots - 1]) - padding;
485
0
    }
486
0
    for (igraph_int_t i = 1; i < slots; ++i) {
487
0
        if (VECTOR(*bitset)[slots - i - 1] != ~zero) {
488
0
            return IGRAPH_INTEGER_SIZE * i + IGRAPH_CLO(VECTOR(*bitset)[slots - i - 1]) - padding;
489
0
        }
490
0
    }
491
492
0
    return bitset->size;
493
0
}
494
495
/**
496
 * \ingroup bitset
497
 * \function igraph_bitset_countr_zero
498
 * \brief The number of trailing zeros in the bitset.
499
 *
500
 * Returns the number of trailing (starting at the least significant bit)
501
 * zeros in the bitset before the first one is encountered.
502
 * If the bitset is all zeros, then its size is returned.
503
 *
504
 * \param bitset The bitset object
505
 * \return The number of trailing zeros in the bitset.
506
 *
507
 * Time complexity: O(n/w).
508
 */
509
510
0
igraph_int_t igraph_bitset_countr_zero(const igraph_bitset_t *bitset) {
511
0
    const igraph_int_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE;
512
0
    const igraph_int_t slots = IGRAPH_BIT_NSLOTS(bitset->size);
513
0
    const igraph_uint_t one = 1, zero = 0; /* to avoid the need to cast 1 and 0 to igraph_uint_t below */
514
0
    const igraph_uint_t mask = final_block_size == IGRAPH_INTEGER_SIZE ? ~zero : ((one << final_block_size) - one);
515
516
0
    for (igraph_int_t i = 0; i + 1 < slots; ++i) {
517
0
        if (VECTOR(*bitset)[i] != zero) {
518
0
            return IGRAPH_INTEGER_SIZE * i + IGRAPH_CTZ(VECTOR(*bitset)[i]);
519
0
        }
520
0
    }
521
0
    if (bitset->size && (mask & VECTOR(*bitset)[slots - 1]) != zero) {
522
0
        return IGRAPH_INTEGER_SIZE * (slots - 1) + IGRAPH_CTZ(mask & VECTOR(*bitset)[slots - 1]);
523
0
    }
524
525
0
    return bitset->size;
526
0
}
527
528
/**
529
 * \ingroup bitset
530
 * \function igraph_bitset_countr_one
531
 * \brief The number of trailing ones in the bitset.
532
 *
533
 * Returns the number of trailing ones (starting at the least significant bit)
534
 * in the bitset before the first zero is encountered.
535
 * If the bitset is all ones, then its size is returned.
536
 *
537
 * \param bitset The bitset object
538
 * \return The number of trailing ones in the bitset.
539
 *
540
 * Time complexity: O(n/w).
541
 */
542
543
201k
igraph_int_t igraph_bitset_countr_one(const igraph_bitset_t *bitset) {
544
201k
    const igraph_int_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE;
545
201k
    const igraph_int_t slots = IGRAPH_BIT_NSLOTS(bitset->size);
546
201k
    const igraph_uint_t one = 1, zero = 0; /* to avoid the need to cast 1 and 0 to igraph_uint_t below */
547
201k
    const igraph_uint_t mask = final_block_size == IGRAPH_INTEGER_SIZE ? zero : ~((one << final_block_size) - one);
548
549
221k
    for (igraph_int_t i = 0; i + 1 < slots; ++i) {
550
119k
        if (VECTOR(*bitset)[i] != ~zero) {
551
100k
            return IGRAPH_INTEGER_SIZE * i + IGRAPH_CTO(VECTOR(*bitset)[i]);
552
100k
        }
553
119k
    }
554
101k
    if (bitset->size && (mask | VECTOR(*bitset)[slots - 1]) != ~zero) {
555
101k
        return IGRAPH_INTEGER_SIZE * (slots - 1) + IGRAPH_CTO(mask | VECTOR(*bitset)[slots - 1]);
556
101k
    }
557
558
0
    return bitset->size;
559
101k
}
560
561
/**
562
 * \ingroup bitset
563
 * \function igraph_bitset_is_all_zero
564
 * \brief Are all bits zeros?
565
 *
566
 * \param bitset The bitset object to test.
567
 * \return True if none of the bits are set.
568
 *
569
 * Time complexity: O(n/w).
570
 */
571
572
0
igraph_bool_t igraph_bitset_is_all_zero(const igraph_bitset_t *bitset) {
573
0
    const igraph_int_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE;
574
0
    const igraph_int_t slots = IGRAPH_BIT_NSLOTS(bitset->size);
575
0
    const igraph_uint_t one = 1, zero = 0; /* to avoid the need to cast 1 and 0 to igraph_uint_t below */
576
0
    const igraph_uint_t mask = final_block_size == IGRAPH_INTEGER_SIZE ? ~zero : ((one << final_block_size) - one);
577
578
0
    for (igraph_int_t i = 0; i < slots - 1; i++) {
579
0
        if (VECTOR(*bitset)[i] != zero) {
580
0
            return false;
581
0
        }
582
0
    }
583
0
    if (bitset->size && (mask & VECTOR(*bitset)[slots - 1]) != zero) {
584
0
        return false;
585
0
    }
586
0
    return true;
587
0
}
588
589
/**
590
 * \ingroup bitset
591
 * \function igraph_bitset_is_all_one
592
 * \brief Are all bits ones?
593
 *
594
 * \param bitset The bitset object to test.
595
 * \return True if all of the bits are set.
596
 *
597
 * Time complexity: O(n/w).
598
 */
599
600
0
igraph_bool_t igraph_bitset_is_all_one(const igraph_bitset_t *bitset) {
601
0
    const igraph_int_t final_block_size = bitset->size % IGRAPH_INTEGER_SIZE ? bitset->size % IGRAPH_INTEGER_SIZE : IGRAPH_INTEGER_SIZE;
602
0
    const igraph_int_t slots = IGRAPH_BIT_NSLOTS(bitset->size);
603
0
    const igraph_uint_t one = 1, zero = 0; /* to avoid the need to cast 1 and 0 to igraph_uint_t below */
604
0
    const igraph_uint_t mask = final_block_size == IGRAPH_INTEGER_SIZE ? zero : ~((one << final_block_size) - one);
605
606
0
    for (igraph_int_t i = 0; i < slots - 1; i++) {
607
0
        if (VECTOR(*bitset)[i] != ~zero) {
608
0
            return false;
609
0
        }
610
0
    }
611
0
    if (bitset->size && (mask | VECTOR(*bitset)[slots - 1]) != ~zero) {
612
0
        return false;
613
0
    }
614
0
    return true;
615
0
}
616
617
/**
618
 * \ingroup bitset
619
 * \function igraph_bitset_is_any_zero
620
 * \brief Are any bits zeros?
621
 *
622
 * \param bitset The bitset object to test.
623
 * \return True if at least one bit is zero.
624
 *
625
 * Time complexity: O(n/w).
626
 */
627
628
0
igraph_bool_t igraph_bitset_is_any_zero(const igraph_bitset_t *bitset) {
629
0
    return ! igraph_bitset_is_all_one(bitset);
630
0
}
631
632
/**
633
 * \ingroup bitset
634
 * \function igraph_bitset_is_any_one
635
 * \brief Are any bits ones?
636
 *
637
 * \param bitset The bitset object to test.
638
 * \return True if at least one bit is one.
639
 *
640
 * Time complexity: O(n/w).
641
 */
642
643
0
igraph_bool_t igraph_bitset_is_any_one(const igraph_bitset_t *bitset) {
644
0
    return ! igraph_bitset_is_all_zero(bitset);
645
0
}
646
647
/**
648
 * \ingroup bitset
649
 * \function igraph_bitset_or
650
 * \brief Bitwise OR of two bitsets.
651
 *
652
 * Applies a bitwise or to the contents of two bitsets and stores it in an
653
 * already initialized bitset. The destination bitset may be equal to one
654
 * (or even both) of the sources. When working with bitsets, it is common
655
 * that those created are of the same size fixed size. Therefore, this
656
 * function does not check the sizes of the bitsets passed to it, the caller
657
 * must do so if necessary.
658
 *
659
 * \param dest The bitset object where the result is stored
660
 * \param src1 A bitset. Must have have same size as \p dest.
661
 * \param src2 A bitset. Must have have same size as \p dest.
662
 *
663
 * Time complexity: O(n/w).
664
 */
665
666
void igraph_bitset_or(igraph_bitset_t *dest,
667
63.1k
                      const igraph_bitset_t *src1, const igraph_bitset_t *src2) {
668
298k
    for (igraph_int_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) {
669
235k
        VECTOR(*dest)[i] = VECTOR(*src1)[i] | VECTOR(*src2)[i];
670
235k
    }
671
63.1k
}
672
673
/**
674
 * \ingroup bitset
675
 * \function igraph_bitset_and
676
 * \brief Bitwise AND of two bitsets.
677
 *
678
 * Applies a bitwise and to the contents of two bitsets and stores it in an
679
 * already initialized bitset. The destination bitset may be equal to one
680
 * (or even both) of the sources. When working with bitsets, it is common
681
 * that those created are of the same size fixed size. Therefore, this
682
 * function does not check the sizes of the bitsets passed to it, the caller
683
 * must do so if necessary.
684
 *
685
 * \param dest The bitset object where the result is stored
686
 * \param src1 A bitset. Must have have same size as \p dest.
687
 * \param src2 A bitset. Must have have same size as \p dest.
688
 *
689
 * Time complexity: O(n/w).
690
 */
691
692
0
void igraph_bitset_and(igraph_bitset_t *dest, const igraph_bitset_t *src1, const igraph_bitset_t *src2) {
693
0
    for (igraph_int_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) {
694
0
        VECTOR(*dest)[i] = VECTOR(*src1)[i] & VECTOR(*src2)[i];
695
0
    }
696
0
}
697
698
/**
699
 * \ingroup bitset
700
 * \function igraph_bitset_xor
701
 * \brief Bitwise XOR of two bitsets.
702
 *
703
 * Applies a bitwise xor to the contents of two bitsets and stores it in
704
 * an already initialized bitset. The destination bitset may be equal to
705
 * one (or even both) of the sources. When working with bitsets, it is common
706
 * that those created are of the same size fixed size. Therefore, this
707
 * function does not check the sizes of the bitsets passed to it, the caller
708
 * must do so if necessary.
709
 *
710
 * \param dest The bitset object where the result is stored
711
 * \param src1 A bitset. Must have have same size as \p dest.
712
 * \param src2 A bitset. Must have have same size as \p dest.
713
 *
714
 * Time complexity: O(n/w).
715
 */
716
717
void igraph_bitset_xor(igraph_bitset_t *dest,
718
0
                       const igraph_bitset_t *src1, const igraph_bitset_t *src2) {
719
0
    for (igraph_int_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) {
720
0
        VECTOR(*dest)[i] = VECTOR(*src1)[i] ^ VECTOR(*src2)[i];
721
0
    }
722
0
}
723
724
/**
725
 * \ingroup bitset
726
 * \function igraph_bitset_not
727
 * \brief Bitwise negation of a bitset.
728
 *
729
 * Applies a bitwise not to the contents of a bitset and stores it in an
730
 * already initialized bitset. The destination bitset may be equal to the
731
 * source. When working with bitsets, it is common that those created are
732
 * of the same size fixed size. Therefore, this function does not check the
733
 * sizes of the bitsets passed to it, the caller must do so if necessary.
734
 *
735
 * \param dest The bitset object where the result is stored
736
 * \param src A bitset. Must have have same size as \p dest.
737
 *
738
 * Time complexity: O(n/w).
739
 */
740
741
0
void igraph_bitset_not(igraph_bitset_t *dest, const igraph_bitset_t *src) {
742
0
    for (igraph_int_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) {
743
0
        VECTOR(*dest)[i] = ~VECTOR(*src)[i];
744
0
    }
745
0
}
746
747
/**
748
 * \ingroup bitset
749
 * \function igraph_bitset_fill
750
 * \brief Fills a bitset with a constant value.
751
 *
752
 * Sets all bits of a bitset to the same value.
753
 *
754
 * \param bitset The bitset object to modify.
755
 * \param value The value to set for all bits.
756
 *
757
 * \sa \ref igraph_bitset_null()
758
 *
759
 * Time complexity: O(n/w).
760
 */
761
762
38.7k
void igraph_bitset_fill(igraph_bitset_t *bitset, igraph_bool_t value) {
763
38.7k
    memset(bitset->stor_begin,
764
38.7k
           value ? ~ (unsigned char) 0 : 0,
765
38.7k
           sizeof(igraph_uint_t) * IGRAPH_BIT_NSLOTS(bitset->size));
766
38.7k
}
767
768
/**
769
 * \ingroup bitset
770
 * \function igraph_bitset_null
771
 * \brief Clears all bits in a bitset.
772
 *
773
 * \param bitset The bitset object to clear all bits in.
774
 *
775
 * \sa \ref igraph_bitset_fill()
776
 *
777
 * Time complexity: O(n/w).
778
 */
779
780
6.23k
void igraph_bitset_null(igraph_bitset_t *bitset) {
781
6.23k
    igraph_bitset_fill(bitset, false);
782
6.23k
}
783
784
/**
785
 * \ingroup bitset
786
 * \function igraph_bitset_fprint
787
 * \brief Prints the bits of a bitset.
788
 *
789
 * Outputs the contents of a bitset to a file.
790
 * The bitset is written from index n-1 to index 0, left to right,
791
 * such that index 0 is the least significant bit and index n-1 is
792
 * the most significant bit, where n is the size of the bitset.
793
 * This is the reverse of how sequential structures are usually written,
794
 * such as vectors, but consistent with the bitset being a binary
795
 * representation of an integer and how they are usually written.
796
 *
797
 * </para><para>
798
 * No newline is printed at the end.
799
 *
800
 * \param bitset The bitset to be printed.
801
 * \param file The file to be written.
802
 * \return Error code.
803
 *
804
 * Time complexity: O(n).
805
 */
806
0
igraph_error_t igraph_bitset_fprint(const igraph_bitset_t *bitset, FILE *file) {
807
0
    for (igraph_int_t i = bitset->size - 1; i >= 0; i--) {
808
0
        fputc(IGRAPH_BIT_TEST(*bitset, i) ? '1' : '0', file);
809
0
    }
810
0
    return IGRAPH_SUCCESS;
811
0
}
812
813
#ifndef USING_R
814
0
igraph_error_t igraph_bitset_print(const igraph_bitset_t *bitset) {
815
    return igraph_bitset_fprint(bitset, stdout);
816
0
}
817
#endif