From 15a25c7283887c2b7cfe37a666edfd1a17b209d1 Mon Sep 17 00:00:00 2001 From: Xu Shaohua Date: Thu, 7 Dec 2023 11:50:54 +0800 Subject: [PATCH] cii: Add bit vector interface --- cii/CMakeLists.txt | 2 + cii/include/cii/bit.h | 166 ++++++++++++++++++++++++++++++++++++++++++ cii/src/bit.c | 111 ++++++++++++++++++++++++++++ 3 files changed, 279 insertions(+) create mode 100644 cii/include/cii/bit.h create mode 100644 cii/src/bit.c diff --git a/cii/CMakeLists.txt b/cii/CMakeLists.txt index fefe36d5..209d8c9f 100644 --- a/cii/CMakeLists.txt +++ b/cii/CMakeLists.txt @@ -10,6 +10,7 @@ set(SOURCE_FILES src/arith.c src/assert.c src/atom.c + src/bit.c src/except.c src/hash.c src/list.c @@ -25,6 +26,7 @@ set(HEADER_FILES include/cii/arith.h include/cii/assert.h include/cii/atom.h + include/cii/bit.h include/cii/except.h include/cii/hash.h include/cii/list.h diff --git a/cii/include/cii/bit.h b/cii/include/cii/bit.h new file mode 100644 index 00000000..93820864 --- /dev/null +++ b/cii/include/cii/bit.h @@ -0,0 +1,166 @@ +// Copyright (c) 2023 Xu Shaohua . All rights reserved. +// Use of this source is governed by GNU General Public License +// that can be found in the LICENSE file. + +#ifndef CII_BIT_H +#define CII_BIT_H + +#include +#include + +typedef struct bit_s bit_t; + +/** + * Create a bit vector with fixed |length| and sets all the bits to zero. + * + * @param length + * @return + */ +extern bit_t* bit_new(size_t length); + +/** + * Get fixed length of a bit vector. + * + * @param set + * @return + */ +extern size_t bit_length(bit_t* set); + +/** + * Returns number of bits with one values in a bit vector. + * + * @param set + * @return + */ +extern size_t bit_count_ones(bit_t* set); + +/** + * Returns number of bits with zero values in a bit vector. + * @param set + * @return + */ +extern size_t bit_count_zeros(bit_t* set); + +/** + * Deallocate and clear a bit vector. + * + * @param set + */ +extern void bit_free(bit_t** set); + +/** + * Check bit at |index| is set or not. + * + * @param set + * @param index + * @return + */ +extern bool bit_get(bit_t* set, size_t index); + +/** + * update bit value at |index| and returns old value. + * + * @param set + * @param index + * @param value + * @return + */ +extern bool bit_put(bit_t* set, size_t index, bool value); + +/** + * Clear bits in range [start, end) in a bit vector. + * + * @param set + * @param start + * @param end + */ +extern void bit_clear(bit_t* set, size_t start, size_t end); + +/** + * Set bits in range [start, end) in a bit vector. + * + * @param set + * @param start + * @param end + */ +extern void bit_set(bit_t* set, size_t start, size_t end); + +/** + * Toggle bits in range [start, end) in a bit vector. + * + * @param set + * @param start + * @param end + */ +extern void bit_not(bit_t* set, size_t start, size_t end); + +/** + * Check whether bit vector s is less than t. + * + * @param s + * @param t + * @return + */ +extern bool bit_less(bit_t* s, bit_t* t); + +/** + * Check whether bit vector s equals to t. + * + * @param s + * @param t + * @return + */ +extern bool bit_equal(bit_t* s, bit_t* t); + +/** + * Check whether bit vector s is less than or equal to t. + * + * @param s + * @param t + * @return + */ +extern bool bit_less_equal(bit_t* s, bit_t* t); + +/** + * Calls |apply| for each bit in set. + * @param s + * @param apply + * @param user_data + */ +extern void bit_map(bit_t* s, + void(*apply)(size_t index, bool is_set, void* user_data), + void* user_data); + +/** + * Returns the union of s and t, denoted s + t. + * @param s + * @param t + * @return + */ +extern bit_t* bit_union(bit_t* s, bit_t* t); + +/** + * Returns the intersection of s and t, denoted s * t. + * @param s + * @param t + * @return + */ +extern bit_t* bit_inter(bit_t* s, bit_t* t); + +/** + * Returns the difference of s and t, denoted s - t. + * @param s + * @param t + * @return + */ +extern bit_t* bit_minus(bit_t* s, bit_t* t); + +/** + * Returns the symmetric difference of s and t, denoted s / t. + * @param s + * @param t + * @return + */ +extern bit_t* bit_diff(bit_t* s, bit_t* t); + +#endif // CII_BIT_H diff --git a/cii/src/bit.c b/cii/src/bit.c new file mode 100644 index 00000000..f82e71ed --- /dev/null +++ b/cii/src/bit.c @@ -0,0 +1,111 @@ +// Copyright (c) 2023 Xu Shaohua . All rights reserved. +// Use of this source is governed by GNU General Public License +// that can be found in the LICENSE file. + +#include "cii/bit.h" + +#include +#include +#include + +#include "cii/assert.h" +#include "cii/mem.h" + +struct bit_s { + // The |length| field gives the number of bits in the vector. + size_t length; + + // |bytes| points to at least [length / 8] bytes. + // The bits are accessed by indexing bytes. + uint8_t* bytes; + size_t* words; +}; + +// Bytes per word. +static size_t bpw() { + return 8 * sizeof(size_t); +} + +// Computes the number of words needed for a bit vector of length bits. +static size_t num_words(size_t length) { + return ((length + bpw() - 1) & (~(bpw() - 1))) / bpw(); +} + +bit_t* bit_new(size_t length) { + bit_t* set; + NEW(set); + if (length > 0) { + set->words = CALLOC(num_words(length), sizeof(size_t)); + } else { + set->words = NULL; + } + set->length = length; + set->bytes = (uint8_t*) set->words; + + return set; +} + +void bit_free(bit_t** set) { + assert(set != NULL && *set != NULL); + FREE((*set)->words); + FREE(*set); +} + +size_t bit_length(bit_t* set) { + assert(set != NULL); + return set->length; +} + +size_t bit_count_ones(bit_t* set) { + assert(set != NULL); + size_t length = 0; + const uint8_t kCount[] = { + 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 + }; + const size_t n_words = num_words(set->length); + for (size_t i = 0; i < n_words; ++i) { + uint8_t c = set->bytes[i]; + length += kCount[c & 0x0F] + kCount[c >> 4]; + } + + return length; +} + +size_t bit_count_zeros(bit_t* set) { + assert(set != NULL); + return bit_length(set) - bit_count_ones(set); +} + +static bool bit_get_bit(bit_t* set, size_t index) { + return (set->bytes[ index / 8] >> (index % 8)) & 1; +} + +bool bit_get(bit_t* set, size_t index) { + assert(set != NULL); + assert(index < set->length); + return bit_get_bit(set, index); +} + +bool bit_put(bit_t* set, size_t index, bool value) { + assert(set != NULL); + assert(index < set->length); + const bool prev = bit_get_bit(set, index); + if (value) { + set->bytes[index / 8] |= 1 << (index % 8); + } else { + set->bytes[index / 8] &= ~(1 << (index % 8)); + } + return prev; +} + +void bit_clear(bit_t* set, size_t start, size_t end) { + +} + +void bit_set(bit_t* set, size_t start, size_t end) { + +} + +void bit_not(bit_t* set, size_t start, size_t end) { + +} \ No newline at end of file