/* igraph library. Copyright (C) 2024-2025 The igraph development team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef IGRAPH_BITSET_H #define IGRAPH_BITSET_H #include "igraph_decls.h" #include "igraph_error.h" #include "igraph_vector.h" #include "igraph_types.h" /* Required for MSVC intrinsics such as __popcnt and __popcnt64 */ #ifdef _MSC_VER #include "intrin.h" #endif IGRAPH_BEGIN_C_DECLS /** * \ingroup bitset * \section igraph_bitset_accessing_elements Accessing elements * * The simplest way to access an element of a bitset is * to use the \ref IGRAPH_BIT_TEST(), \ref IGRAPH_BIT_SET() and \ref IGRAPH_BIT_CLEAR() macros. * * * There are a few other macros which allow manual manipulation of bitsets. * Those are \ref VECTOR(), \ref IGRAPH_BIT_SLOT(), \ref IGRAPH_BIT_MASK() and * \ref IGRAPH_BIT_NSLOTS(). */ /** * \ingroup bitset * \define IGRAPH_BIT_MASK * \brief Computes mask used to access a specific bit of an integer. * * \experimental * * Used in combination with \ref IGRAPH_BIT_SLOT() to access an element of a bitset. * * Usage: * \verbatim IGRAPH_BIT_MASK(10) \endverbatim * to obtain an integer where only the 11th least significant bit is set. * * Note that passing negative values here results in undefined behaviour. * * \param b The only bit index that should have its bit set. * * Time complexity: O(1). */ #define IGRAPH_BIT_MASK(i) ((igraph_uint_t)(1) << ((i) % IGRAPH_INTEGER_SIZE)) /** * \ingroup bitset * \define IGRAPH_BIT_SLOT * \brief Computes index used to access a specific slot of a bitset. * * \experimental * * Used in combination with \ref IGRAPH_BIT_MASK to access an element of a bitset. * * Usage: * \verbatim IGRAPH_BIT_SLOT(70) \endverbatim * will return 1 if using 64-bit words or 2 if using 32-bit words. * * \param i The bit index whose slot should be determined. * * Time complexity: O(1). */ #define IGRAPH_BIT_SLOT(i) ((i) / IGRAPH_INTEGER_SIZE) /** * \ingroup bitset * \define IGRAPH_BIT_SET * \brief Sets a specific bit in a bitset to 1 without altering other bits. * * \experimental * * Usage: * \verbatim IGRAPH_BIT_SET(bitset, 3) \endverbatim * will set the fourth least significant bit in the bitset to 1. * * \param bitset The bitset * \param i The bit index that should have its bit set to 1 after the operation. * * Time complexity: O(1). */ #define IGRAPH_BIT_SET(bitset, i) (VECTOR((bitset))[IGRAPH_BIT_SLOT(i)] |= IGRAPH_BIT_MASK(i)) /** * \ingroup bitset * \define IGRAPH_BIT_CLEAR * \brief Sets a specific bit in a bitset to 0 without altering other bits. * * \experimental * * Usage: * \verbatim IGRAPH_BIT_CLEAR(bitset, 4) \endverbatim * will set the fifth least significant bit in the bitset to 0. * * \param bitset The bitset * \param i The bit index that should have its bit set to 0 after the operation. * * Time complexity: O(1). */ #define IGRAPH_BIT_CLEAR(bitset, i) (VECTOR((bitset))[IGRAPH_BIT_SLOT(i)] &= ~IGRAPH_BIT_MASK(i)) /** * \ingroup bitset * \define IGRAPH_BIT_TEST * \brief Tests whether a bit is set in a bitset. * * \experimental * * Returns 0 if the bit at the specified bit index is not set, * otherwise returns a non-zero value. * * Usage: * \verbatim IGRAPH_BIT_TEST(bitset, 7) \endverbatim * will test the eighth least significant bit in the bitset. * * \param bitset The bitset * \param i The bit index that should have its bit tested. * * Time complexity: O(1). */ #define IGRAPH_BIT_TEST(bitset, i) (VECTOR((bitset))[IGRAPH_BIT_SLOT(i)] & IGRAPH_BIT_MASK(i)) /** * \ingroup bitset * \define IGRAPH_BIT_NSLOTS * \brief Computes the number of slots required to store a specified number of bits. * * \experimental * * Usage: * \verbatim IGRAPH_BIT_NSLOTS(70) \endverbatim * will return 2 if using 64-bit words and 3 if using 32-bit words. * \verbatim IGRAPH_BIT_NSLOTS(128) \endverbatim * will return 2 if using 64-bit words and 4 if using 32-bit words. * * \param nbits The specified number of bits. * * Time complexity: O(1). */ #define IGRAPH_BIT_NSLOTS(nbits) ((nbits + IGRAPH_INTEGER_SIZE - (igraph_int_t)(1)) / IGRAPH_INTEGER_SIZE) #if defined(__GNUC__) /* GCC and Clang support these six builtins from very early versions. */ #define IGRAPH_I_POPCOUNT32(x) __builtin_popcount(x) #define IGRAPH_I_POPCOUNT64(x) __builtin_popcountll(x) /* The result of the following four builtins is undefined for zero input, * therefore we handle this specially. * See https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html */ #define IGRAPH_I_CTZ32(x) (x ? __builtin_ctz(x) : 32) #define IGRAPH_I_CTZ64(x) (x ? __builtin_ctzll(x) : 64) #define IGRAPH_I_CLZ32(x) (x ? __builtin_clz(x) : 32) #define IGRAPH_I_CLZ64(x) (x ? __builtin_clzll(x) : 64) #else /* Non-GNU compilers, i.e. MSVC and others. Attempt to use MSVC intrinsics * when available, otherwise use fallback implementation. */ #if IGRAPH_INTEGER_SIZE == 32 #ifdef HAVE__POPCNT #define IGRAPH_I_POPCOUNT32(x) __popcnt(x) #else igraph_int_t igraph_i_popcnt(igraph_uint_t x); #define IGRAPH_I_POPCOUNT32(x) igraph_i_popcnt(x) #endif #elif IGRAPH_INTEGER_SIZE == 64 #ifdef HAVE__POPCNT64 #define IGRAPH_I_POPCOUNT64(x) __popcnt64(x) #else igraph_int_t igraph_i_popcnt(igraph_uint_t x); #define IGRAPH_I_POPCOUNT64(x) igraph_i_popcnt(x) #endif #else #error "Unexpected IGRAPH_INTEGER_SIZE value." #endif igraph_int_t igraph_i_ctz32(igraph_uint_t x); igraph_int_t igraph_i_ctz64(igraph_uint_t x); igraph_int_t igraph_i_clz32(igraph_uint_t x); igraph_int_t igraph_i_clz64(igraph_uint_t x); #define IGRAPH_I_CTZ32(x) igraph_i_ctz32(x) #define IGRAPH_I_CTZ64(x) igraph_i_ctz64(x) #define IGRAPH_I_CLZ32(x) igraph_i_clz32(x) #define IGRAPH_I_CLZ64(x) igraph_i_clz64(x) #endif #if IGRAPH_INTEGER_SIZE == 32 #define IGRAPH_POPCOUNT IGRAPH_I_POPCOUNT32 #define IGRAPH_CLZ IGRAPH_I_CLZ32 #define IGRAPH_CTZ IGRAPH_I_CTZ32 #elif IGRAPH_INTEGER_SIZE == 64 #define IGRAPH_POPCOUNT IGRAPH_I_POPCOUNT64 #define IGRAPH_CLZ IGRAPH_I_CLZ64 #define IGRAPH_CTZ IGRAPH_I_CTZ64 #else #error "Unexpected IGRAPH_INTEGER_SIZE value." #endif #define IGRAPH_CLO(x) IGRAPH_CLZ(~(x)) #define IGRAPH_CTO(x) IGRAPH_CTZ(~(x)) typedef struct { igraph_int_t size; igraph_uint_t *stor_begin; igraph_uint_t *stor_end; } igraph_bitset_t; IGRAPH_EXPORT igraph_error_t igraph_bitset_init(igraph_bitset_t *bitset, igraph_int_t size); IGRAPH_EXPORT void igraph_bitset_destroy(igraph_bitset_t *bitset); IGRAPH_EXPORT igraph_error_t igraph_bitset_init_copy(igraph_bitset_t *dest, const igraph_bitset_t *src); IGRAPH_EXPORT igraph_error_t igraph_bitset_update(igraph_bitset_t *dest, const igraph_bitset_t *src); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_bitset_capacity(const igraph_bitset_t *bitset); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_bitset_size(const igraph_bitset_t *bitset); IGRAPH_EXPORT igraph_error_t igraph_bitset_reserve(igraph_bitset_t *bitset, igraph_int_t capacity); IGRAPH_EXPORT igraph_error_t igraph_bitset_resize(igraph_bitset_t *bitset, igraph_int_t new_size); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_bitset_popcount(const igraph_bitset_t *bitset); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_bitset_countl_zero(const igraph_bitset_t *bitset); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_bitset_countl_one(const igraph_bitset_t *bitset); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_bitset_countr_zero(const igraph_bitset_t *bitset); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_int_t igraph_bitset_countr_one(const igraph_bitset_t *bitset); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_bitset_is_all_zero(const igraph_bitset_t *bitset); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_bitset_is_all_one(const igraph_bitset_t *bitset); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_bitset_is_any_zero(const igraph_bitset_t *bitset); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_bitset_is_any_one(const igraph_bitset_t *bitset); IGRAPH_EXPORT void igraph_bitset_or(igraph_bitset_t *dest, const igraph_bitset_t *src1, const igraph_bitset_t *src2); IGRAPH_EXPORT void igraph_bitset_and(igraph_bitset_t *dest, const igraph_bitset_t *src1, const igraph_bitset_t *src2); IGRAPH_EXPORT void igraph_bitset_xor(igraph_bitset_t *dest, const igraph_bitset_t *src1, const igraph_bitset_t *src2); IGRAPH_EXPORT void igraph_bitset_not(igraph_bitset_t *dest, const igraph_bitset_t *src); IGRAPH_EXPORT void igraph_bitset_fill(igraph_bitset_t *bitset, igraph_bool_t value); IGRAPH_EXPORT void igraph_bitset_null(igraph_bitset_t *bitset); IGRAPH_EXPORT igraph_error_t igraph_bitset_fprint(const igraph_bitset_t *bitset, FILE *file); IGRAPH_EXPORT igraph_error_t igraph_bitset_print(const igraph_bitset_t *bitset); #define IGRAPH_BITSET_INIT_FINALLY(bitset, size) \ do { IGRAPH_CHECK(igraph_bitset_init(bitset, size)); \ IGRAPH_FINALLY(igraph_bitset_destroy, bitset); } while (0) IGRAPH_END_C_DECLS #endif /* IGRAPH_BITSET_H */