// 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 #include #include #include #include "error.h" #include #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