106 lines
4.9 KiB
C
106 lines
4.9 KiB
C
// bitset.h
|
|
// Řešení IJC-DU1, příklad a), 22.3.2024
|
|
// Autor: Roman Nečas, FIT
|
|
// Přeloženo: gcc 13.2.1
|
|
|
|
#ifndef BITSET_H
|
|
#define BITSET_H
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <limits.h>
|
|
#include "error.h"
|
|
#include <stdbool.h>
|
|
|
|
#define WORD_BITS (sizeof(unsigned long) * CHAR_BIT) // Number of bits in an unsigned long
|
|
#define WORD_BYTES sizeof(unsigned long) // Number of bytes in an unsigned long
|
|
#define HEADER_WORD 1 // First element is reserved for size
|
|
|
|
/* Index type for the bit set. */
|
|
typedef unsigned long bitset_index_t;
|
|
|
|
/* Bit set type (for passing as a parameter by reference). */
|
|
typedef unsigned long *bitset_t;
|
|
|
|
/* MACROS that are used always */
|
|
|
|
/* defines and initializes the variable name */
|
|
#define bitset_create(name, size) \
|
|
static_assert(size > 0 && size < ULONG_MAX, "ERROR: bitset_create: Invalid array size."); \
|
|
bitset_index_t name[(size)/WORD_BITS + HEADER_WORD + (((size) % WORD_BITS) ? 1 : 0)] = {size}
|
|
|
|
#define bitset_alloc(name, size) \
|
|
static_assert(size > 0 && size < ULONG_MAX, "ERROR: bitset_create: Invalid array size."); \
|
|
bitset_t name = calloc((size)/WORD_BITS + HEADER_WORD + (((size) % WORD_BITS) ? 1 : 0), sizeof(bitset_index_t)); \
|
|
if (name == NULL) error_exit("bitset_alloc: Memory allocation error"); \
|
|
name[0] = size
|
|
|
|
/* Frees the memory of a dynamically allocated array. */
|
|
#define bitset_free(name) free(name)
|
|
|
|
#ifdef USE_INLINE
|
|
/* INLINE FUNCTIONS */
|
|
/* Returns the declared size of the array stored at index 0 */
|
|
inline bitset_index_t bitset_size(bitset_t name)
|
|
{
|
|
return name[0];
|
|
}
|
|
|
|
/* Sets all bits in the array to 0 (false) or 1 (true) */
|
|
inline void bitset_fill(bitset_t name, bool bool_expr)
|
|
{
|
|
unsigned long i;
|
|
for (i = HEADER_WORD; i < ((bitset_size(name) / WORD_BITS) + HEADER_WORD + (((bitset_size(name)) % WORD_BITS) ? 1 : 0)); i++)
|
|
{
|
|
name[i] = (bool_expr) ? ~0UL : 0UL;
|
|
}
|
|
}
|
|
|
|
/* Sets the specified bit in the array to the value given by the expression */
|
|
inline void bitset_setbit(bitset_t name, bitset_index_t index, bool bool_expr)
|
|
{
|
|
if (index >= bitset_size(name))
|
|
error_exit("bitset_setbit: Index %lu out of range 0..%lu", (unsigned long)index, (unsigned long)bitset_size(name));
|
|
name[(index/WORD_BITS) + HEADER_WORD] = (bool_expr) ? (name[(index/WORD_BITS) + HEADER_WORD] | (1UL << (index & (WORD_BITS - 1))))
|
|
: (name[(index/WORD_BITS) + HEADER_WORD] & ~(1UL << (index & (WORD_BITS - 1))));
|
|
}
|
|
|
|
/* Gets the value of the specified bit, returns 0 or 1 */
|
|
inline char bitset_getbit(bitset_t name, bitset_index_t index)
|
|
{
|
|
if (index >= bitset_size(name))
|
|
error_exit("bitset_getbit: Index %lu out of range 0..%lu", (unsigned long)index, (unsigned long)bitset_size(name));
|
|
return name[(index/WORD_BITS + HEADER_WORD)] >> (index & (WORD_BITS - 1)) & 1UL;
|
|
}
|
|
#else
|
|
/* MACROS */
|
|
/* Sets all bits in the array to 0 (false) or 1 (true) */
|
|
#define bitset_fill(name, bool_expr) do \
|
|
{ \
|
|
unsigned long i; \
|
|
for (i = HEADER_WORD; i < ((bitset_size(name) / WORD_BITS) + HEADER_WORD + (((bitset_size(name)) % WORD_BITS) ? 1 : 0)); i++) \
|
|
{ \
|
|
name[i] = (bool_expr) ? ~0UL : 0UL; \
|
|
} \
|
|
} while (0)
|
|
|
|
/* Sets the specified bit in the array to the value given by the expression */
|
|
#define bitset_setbit(name, index, bool_expr) do \
|
|
{ \
|
|
if ((index) >= bitset_size(name)) error_exit("bitset_setbit: Index %lu out of range 0..%lu", \
|
|
(unsigned long)index, (unsigned long)bitset_size(name)); \
|
|
name[((index)/WORD_BITS) + HEADER_WORD] = (bool_expr) ? (name[((index)/WORD_BITS) + HEADER_WORD] | (1UL << ((index) & (WORD_BITS - 1)))) \
|
|
: (name[((index)/WORD_BITS) + HEADER_WORD] & ~(1UL << ((index) & (WORD_BITS - 1)))); \
|
|
} while (0)
|
|
|
|
/* Gets the value of the specified bit, returns 0 or 1 */
|
|
#define bitset_getbit(name, index) \
|
|
(((index) >= bitset_size(name)) ? (error_exit("bitset_getbit: Index %lu out of range 0..%lu", (unsigned long)index, (unsigned long)bitset_size(name)), 0) \
|
|
: ((name[((index)/WORD_BITS + HEADER_WORD)] >> ((index) & (WORD_BITS - 1))) & 1UL))
|
|
|
|
/* Returns the declared size of the array stored at index 0 */
|
|
#define bitset_size(name) name[0]
|
|
|
|
#endif
|
|
#endif
|