/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 |