Files
Abdelrahman Said a11edf0c53 Add graph references
2026-06-28 13:49:01 +01:00

266 lines
9.7 KiB
C

/*
igraph library.
Copyright (C) 2024-2025 The igraph development team <igraph@igraph.org>
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 <https://www.gnu.org/licenses/>.
*/
#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
*
* <para>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.
* </para>
*
* <para>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().</para>
*/
/**
* \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 */