[Libclc-developers] New clc_bitset proposal
Status: Planning
Brought to you by:
augestad
|
From: <bo...@me...> - 2003-03-25 20:10:08
|
Regis has been working hard and has come up with a new clc_bitset.
Regis' version is much more complete than the current, so this may be a
winner. :-)
The excellent documentation Regis provided has been moved to a separate
file, libclc/src/bitset/clc_bitset.dox. That file is available in CVS
for review.
Here is the implementation, please comment.
----------------------------------------------------------
#include "clc_assert.h"
#include "clc_bitset.h"
/** \brief The chosen word size for the buffer of bits.
*
* I would choose unsigned integer instead of unsigned char
* if I knew how to get the number of value bits in an unsigned
* at compile time.
*/
typedef unsigned char clc_bitset_word;
static const size_t nbytes_per_word = sizeof(clc_bitset_word);
static const size_t nbits_per_word = CHAR_BIT;
static const clc_bitset_word mask_all = ~0;
static const clc_bitset_word comask_all = 0;
/** \brief The internal struct that implements the ADT clc_bitset.
*
* The bitset holds 'nbits' bits (nbits > 0).
* The bits are packed in unsigned values of type clc_bitset_word.
* There are 'nwords' such words that hold the 'nbits' bits.
* The 'nwords' words are stored in an array pointed by 'words'.
* Since only some of the bits of the last are generally used,
* 'nlast_bits' is the number of used bits in words[nword-1].
* The unused bits should remain zero.
*/
struct clc_bitset_tag {
/** number of words in the array 'words[]'. */
size_t nwords;
/** number of bits in the bitset. */
size_t nbits;
/** number of used bits in the last word. */
size_t nlast_bits;
/** pointer to the array of words. */
clc_bitset_word *words;
};
static size_t bit_index(size_t i)
{
return i / nbits_per_word;
}
static size_t bit_offset(size_t i)
{
return i % nbits_per_word;
}
static void bit_pos(size_t * idx, size_t * off, size_t i)
{
clc_assert_not_null(bit_pos, idx);
clc_assert_not_null(bit_pos, off);
*idx = i / nbits_per_word;
*off = i % nbits_per_word;
}
static clc_bitset_word mask_one(size_t i)
{
clc_assert_arg(mask_one, i < nbits_per_word);
return (1 << i);
}
static clc_bitset_word comask_one(size_t i)
{
clc_assert_arg(comask_one, i < nbits_per_word);
return ~(1 << i);
}
static clc_bitset_word mask_first(size_t n)
{
clc_assert_arg(mask_first, n <= nbits_per_word);
return ((1 << n) - 1);
}
static clc_bitset_word comask_first(size_t n)
{
clc_assert_arg(comask_first, n <= nbits_per_word);
return ~((1 << n) - 1);
}
static clc_bitset_word mask_range(size_t i, size_t j)
{
clc_assert_arg(mask_range, i <= j);
clc_assert_arg(mask_range, i < nbits_per_word);
clc_assert_arg(mask_range, i <= nbits_per_word);
return (((1 << j) - 1) ^ ((1 << i) - 1));
}
static clc_bitset_word comask_range(size_t i, size_t j)
{
clc_assert_arg(comask_range, i <= j);
clc_assert_arg(comask_range, i < nbits_per_word);
clc_assert_arg(comask_range, i <= nbits_per_word);
return ~(((1 << j) - 1) ^ ((1 << i) - 1));
}
static size_t first_one(clc_bitset_word w)
{
size_t off = 0;
clc_assert_arg(first_one, w != 0);
for (off = 0; (w & 1) != 1; off++)
w >>= 1;
return off;
}
static size_t first_zero(clc_bitset_word w)
{
size_t off = 0;
clc_assert_arg(first_zero, w != mask_all);
for (off = 0; (w & 1) != 0; off++)
w >>= 1;
return off;
}
static size_t last_one(clc_bitset_word w)
{
size_t off = 0;
clc_assert_arg(last_one, w != 0);
for (off = 0; w != 0; off++)
w >>= 1;
return off - 1;
}
static size_t last_zero(clc_bitset_word w)
{
size_t off = 0;
clc_assert_arg(last_zero, w != mask_all);
w = ~w;
for (off = 0; w != 0; off++)
w >>= 1;
return off - 1;
}
static clc_bitset unary_result(clc_bitset r, clc_bitset b1,
int init_zero)
{
clc_assert_not_null(unary_result, b1);
clc_assert_arg(unary_result, r == NULL || r->nbits == b1->nbits);
if(r == NULL)
return clc_bitset_new(b1->nbits, init_zero);
return r;
}
static clc_bitset binary_result(clc_bitset r, clc_bitset b1,
clc_bitset b2, int init_zero)
{
clc_assert_not_null(binary_result, b1 != NULL);
clc_assert_not_null(binary_result, b2 != NULL);
clc_assert_arg(binary_result, b1->nbits == b2->nbits);
clc_assert_arg(binary_result, r == NULL || r->nbits == b1->nbits);
if(r == NULL)
return clc_bitset_new(b1->nbits, init_zero);
return r;
}
clc_bitset clc_bitset_new(size_t nbits, int init_to_zero)
{
clc_bitset b = malloc(sizeof *b);
if(!b)
return NULL;
b->nbits = nbits;
bit_pos(&b->nwords, &b->nlast_bits, nbits);
if(b->nlast_bits != 0)
b->nwords++;
else
b->nlast_bits = nbits_per_word;
b->words = malloc(b->nwords * nbytes_per_word);
if(!b->words) {
clc_bitset_delete(b);
return NULL;
}
if(init_to_zero)
clc_bitset_clear_all(b);
return b;
}
void clc_bitset_delete(clc_bitset b)
{
if(b) {
free(b->words);
free(b);
}
}
clc_bitset clc_bitset_copy(clc_bitset copy, clc_bitset b)
{
size_t idx;
if(!(copy = unary_result(copy, b, 0)))
return NULL;
for (idx = 0; idx < b->nwords; idx++)
copy->words[idx] = b->words[idx];
return copy;
}
size_t clc_bitset_size(clc_bitset b)
{
clc_assert_not_null(clc_bitet_size, b);
return b->nbits;
}
size_t clc_bitset_count_ones(clc_bitset b)
{
size_t idx, nbits = 0;
clc_bitset_word word;
clc_assert_not_null(clc_bitset_count_ones, b);
/* the last word does not need any special treatment
*/
for (idx = 0; idx < b->nwords; idx++) {
word = b->words[idx];
while (word) {
nbits += word & 1;
word >>= 1;
}
}
return nbits;
}
size_t clc_bitset_first_one(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_first_one, b);
/* the last word does not need any special treatment
*/
for (idx = 0; idx < b->nwords; idx++)
if(b->words[idx])
return idx * nbits_per_word + first_one(b->words[idx]);
return b->nbits;
}
size_t clc_bitset_last_one(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_last_one, b);
/* the last word does not need any special treatment
* the first word is a specil case since the loop is
* downward to zero and size_t is of unsigned type
*/
for (idx = b->nwords - 1; idx != 0; idx--)
if(b->words[idx])
return idx * nbits_per_word + last_one(b->words[idx]);
return b->words[0] == 0 ? b->nbits : last_one(b->words[0]);
}
size_t clc_bitset_first_zero(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_first_zero, b);
/* though the last word does not need any special treatment
* with the convention to return nbits, we treat it separately
* to emphazise that a special treatment would be required if this
* convention changed.
*/
for (idx = 0; idx < b->nwords - 1; idx++)
if(b->words[idx] != mask_all)
return idx * nbits_per_word + first_zero(b->words[idx]);
return b->words[idx] == mask_first(b->nlast_bits) ?
b->nbits : first_zero(b->words[idx]);
}
size_t clc_bitset_last_zero(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_last_zero, b);
/* the unused zeroes of the last word should be ignored
*/
if(b->words[b->nwords - 1] != mask_first(b->nlast_bits))
return (b->nwords - 1) * nbits_per_word
+ last_zero(b->words[b->nwords - 1] |
comask_first(b->nlast_bits));
if(b->nwords == 1)
return b->nbits;
for (idx = b->nwords - 2; idx != 0; idx--)
if(b->words[idx] != mask_all)
return idx * nbits_per_word + last_zero(b->words[idx]);
return b->words[0] == mask_all ? b->nbits : last_zero(b->words[0]);
}
void clc_bitset_set(clc_bitset b, size_t i)
{
clc_assert_not_null(clc_bitset_set, b);
clc_assert_arg(clc_bitset_set, i < b->nbits);
b->words[bit_index(i)] |= mask_one(bit_offset(i));
}
void clc_bitset_clear(clc_bitset b, size_t i)
{
clc_assert_not_null(clc_bitset_set, b);
clc_assert_arg(clc_bitset_set, i < b->nbits);
b->words[bit_index(i)] &= comask_one(bit_offset(i));
}
void clc_bitset_toggle(clc_bitset b, size_t i)
{
clc_assert_not_null(clc_bitset_toggle, b);
clc_assert_arg(clc_bitset_toggle, i < b->nbits);
b->words[bit_index(i)] ^= mask_one(bit_offset(i));
}
void clc_bitset_assign(clc_bitset b, size_t i, int value)
{
clc_assert_not_null(clc_bitset_assign, b);
clc_assert_arg(clc_bitset_assign, i < b->nbits);
if(value)
clc_bitset_set(b, i);
else
clc_bitset_clear(b, i);
}
int clc_bitset_is_set(clc_bitset b, size_t i)
{
clc_assert_not_null(clc_bitset_is_set, b);
clc_assert_arg(clc_bitset_is_set, i < b->nbits);
return b->words[bit_index(i)] & mask_one(bit_offset(i));
}
int clc_bitset_and(clc_bitset b1, clc_bitset b2, size_t i)
{
size_t off_i, idx_i;
clc_assert_not_null(clc_bitset_and, b1 != NULL);
clc_assert_not_null(clc_bitset_and, b2 != NULL);
clc_assert_arg(clc_bitset_and, b1->nbits == b2->nbits);
clc_assert_arg(clc_bitset_and, i < b1->nbits);
bit_pos(&off_i, &idx_i, i);
return ((b1->words[idx_i] & b2->words[idx_i]) >> off_i) & 1;
}
int clc_bitset_or(clc_bitset b1, clc_bitset b2, size_t i)
{
size_t off_i, idx_i;
clc_assert_not_null(clc_bitset_or, b1 != NULL);
clc_assert_not_null(clc_bitset_or, b2 != NULL);
clc_assert_arg(clc_bitset_or, b1->nbits == b2->nbits);
clc_assert_arg(clc_bitset_or, i < b1->nbits);
bit_pos(&off_i, &idx_i, i);
return ((b1->words[idx_i] | b2->words[idx_i]) >> off_i) & 1;
}
int clc_bitset_xor(clc_bitset b1, clc_bitset b2, size_t i)
{
size_t off_i, idx_i;
clc_assert_not_null(clc_bitset_xor, b1 != NULL);
clc_assert_not_null(clc_bitset_xor, b2 != NULL);
clc_assert_arg(clc_bitset_xor, b1->nbits == b2->nbits);
clc_assert_arg(clc_bitset_xor, i < b1->nbits);
bit_pos(&off_i, &idx_i, i);
return ((b1->words[idx_i] ^ b2->words[idx_i]) >> off_i) & 1;
}
void clc_bitset_clear_all(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_clear_all, b);
/* the last word does not require any special treatment
*/
for (idx = 0; idx < b->nwords; idx++)
b->words[idx] = comask_all;
}
void clc_bitset_set_all(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_set_all, b);
/* the unused bits of the last word should be left zero
*/
for (idx = 0; idx < b->nwords - 1; idx++)
b->words[idx] = mask_all;
b->words[idx] = mask_first(b->nlast_bits);
}
void clc_bitset_toggle_all(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_toggle_all, b);
/* the unused bits of the last word should be left zero
*/
for (idx = 0; idx < b->nwords - 1; idx++)
b->words[idx] = ~b->words[idx];
b->words[idx] ^= mask_first(b->nlast_bits);
}
void clc_bitset_assign_all(clc_bitset b, int value)
{
clc_assert_not_null(clc_bitset_assign_all, b);
if(value)
clc_bitset_set_all(b);
else
clc_bitset_clear_all(b);
}
int clc_bitset_is_all_set(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_is_all_set, b);
/* the unused bits of the last word should be ignored
*/
for (idx = 0; idx < b->nwords - 1; idx++)
if(b->words[idx] != mask_all)
return 0;
return (mask_first(b->nlast_bits) & b->words[idx])
== mask_first(b->nlast_bits);
}
int clc_bitset_is_all_clear(clc_bitset b)
{
size_t idx;
clc_assert_not_null(clc_bitset_is_all_clear, b);
/* the last word does not require any special treatment
*/
for (idx = 0; idx < b->nwords; idx++)
if(b->words[idx] != comask_all)
return 0;
return 1;
}
clc_bitset clc_bitset_or_all(clc_bitset r, clc_bitset b1, clc_bitset b2)
{
size_t idx;
if(!(r = binary_result(r, b1, b2, 0)))
return NULL;
/* the last word does not require any special treatment
*/
for (idx = 0; idx < r->nwords; idx++)
r->words[idx] = b1->words[idx] | b2->words[idx];
return r;
}
clc_bitset clc_bitset_and_all(clc_bitset r,
clc_bitset b1, clc_bitset b2)
{
size_t idx;
if(!(r = binary_result(r, b1, b2, 0)))
return NULL;
/* the last word does not require any special treatment
*/
for (idx = 0; idx < r->nwords; idx++)
r->words[idx] = b1->words[idx] & b2->words[idx];
return r;
}
clc_bitset clc_bitset_xor_all(clc_bitset r,
clc_bitset b1, clc_bitset b2)
{
size_t idx;
if(!(r = binary_result(r, b1, b2, 0)))
return NULL;
/* the last word does not require any special treatment
*/
for (idx = 0; idx < r->nwords; idx++)
r->words[idx] = b1->words[idx] ^ b2->words[idx];
return r;
}
clc_bitset clc_bitset_range(clc_bitset r,
clc_bitset b, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
clc_assert_not_null(clc_bitset_range, b);
clc_assert_arg(clc_bitset_range, i <= j);
clc_assert_arg(clc_bitset_range, i < b->nbits);
clc_assert_arg(clc_bitset_range, j <= b->nbits);
if(!(r = unary_result(r, b, 1)))
return NULL;
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j) {
r->words[idx_i] =
(r->words[idx_i] & comask_range(off_i, off_j)) |
(b->words[idx_i] & mask_range(off_i, off_j));
return r;
}
r->words[idx_i] =
(r->words[idx_i] & mask_first(off_i)) |
(b->words[idx_i] & comask_first(off_i));
for (idx = idx_i + 1; idx < idx_j; idx++)
r->words[idx] = b->words[idx];
if(idx_j < b->nwords)
r->words[idx_j] =
(r->words[idx_j] & comask_first(off_j)) |
(b->words[idx_j] & mask_first(off_j));
return r;
}
void clc_bitset_set_range(clc_bitset b, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
clc_assert_not_null(clc_bitset_set_range, b);
clc_assert_arg(clc_bitset_set_range, i <= j);
clc_assert_arg(clc_bitset_set_range, i < b->nbits);
clc_assert_arg(clc_bitset_set_range, j <= b->nbits);
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j) {
b->words[idx_i] |= mask_range(off_i, off_j);
return;
}
b->words[idx_i] |= comask_first(off_i);
for (idx = idx_i + 1; idx < idx_j; idx++)
b->words[idx] = mask_all;
if(idx_j < b->nwords)
b->words[idx_j] |= mask_first(off_j);
}
void clc_bitset_clear_range(clc_bitset b, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
clc_assert_not_null(clc_bitset_clear_range, b);
clc_assert_arg(clc_bitset_clear_range, i <= j);
clc_assert_arg(clc_bitset_clear_range, i < b->nbits);
clc_assert_arg(clc_bitset_clear_range, j <= b->nbits);
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j) {
b->words[idx_i] &= comask_range(off_i, off_j);
return;
}
b->words[idx_i] &= mask_first(off_i);
for (idx = idx_i + 1; idx < idx_j; idx++)
b->words[idx] = comask_all;
if(idx_j < b->nwords)
b->words[idx_j] &= comask_first(off_j);
}
void clc_bitset_toggle_range(clc_bitset b, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
clc_assert_not_null(clc_bitset_toggle_range, b);
clc_assert_arg(clc_bitset_toggle_range, i <= j);
clc_assert_arg(clc_bitset_toggle_range, i < b->nbits);
clc_assert_arg(clc_bitset_toggle_range, j <= b->nbits);
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j) {
b->words[idx_i] ^= mask_range(off_i, off_j);
return;
}
b->words[idx_i] ^= comask_first(off_i);
for (idx = idx_i + 1; idx < idx_j; idx++)
b->words[idx] ^= mask_all;
if(idx_j < b->nwords)
b->words[idx_j] ^= mask_first(off_j);
}
void clc_bitset_assign_range(clc_bitset b, size_t i, size_t j,
int value)
{
if(value)
clc_bitset_set_range(b, i, j);
else
clc_bitset_clear_range(b, i, j);
}
int clc_bitset_range_is_set(clc_bitset b, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
clc_assert_not_null(clc_bitset_range_is_set, b);
clc_assert_arg(clc_bitset_range_is_set, i <= j);
clc_assert_arg(clc_bitset_range_is_set, i < b->nbits);
clc_assert_arg(clc_bitset_range_is_set, j <= b->nbits);
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j)
return (mask_range(off_i, off_j) & b->words[idx_i])
== mask_range(off_i, off_j);
if((comask_first(off_i) & b->words[idx_i])
!= comask_first(off_i))
return 0;
for (idx = idx_i + 1; idx < idx_j; idx++)
if(b->words[idx] != mask_all)
return 0;
return idx_j == b->nwords ||
(mask_first(idx_j) & b->words[idx_j]) == mask_first(idx_j);
}
int clc_bitset_range_is_clear(clc_bitset b, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
clc_assert_not_null(clc_bitset_range_is_clear, b);
clc_assert_arg(clc_bitset_range_is_clear, i <= j);
clc_assert_arg(clc_bitset_range_is_clear, i < b->nbits);
clc_assert_arg(clc_bitset_range_is_clear, j <= b->nbits);
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j)
return (b->words[idx_i] & mask_range(off_i, off_j))
== comask_all;
if((b->words[idx_i] & comask_first(off_i)) != comask_all)
return 0;
for (idx = idx_i + 1; idx < idx_j; idx++)
if(b->words[idx] != comask_all)
return 0;
return idx_j == b->nwords ||
(b->words[idx_j] & mask_first(idx_j)) == comask_all;
}
clc_bitset clc_bitset_or_range(clc_bitset r,
clc_bitset b1,
clc_bitset b2, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
if(!(r = binary_result(r, b1, b2, 1)))
return NULL;
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j) {
r->words[idx_i] = (r->words[idx_i] &
comask_range(off_i, off_j)) |
((b1->words[idx_i] | b2->words[idx_i]) &
mask_range(off_i, off_j));
return r;
}
r->words[idx_i] = (r->words[idx_i] & mask_first(off_i)) |
((b1->words[idx_i] | b2->words[idx_i]) & comask_first(off_i));
for (idx = idx_i + 1; idx < idx_j; idx++)
r->words[idx] = b1->words[idx_i] | b2->words[idx_i];
if(idx_j < r->nwords)
r->words[idx_j] = (r->words[idx_j] & comask_first(off_j)) |
((b1->words[idx_j] | b2->words[idx_j]) & mask_first(off_j));
return r;
}
clc_bitset clc_bitset_and_range(clc_bitset r,
clc_bitset b1,
clc_bitset b2, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
if(!(r = binary_result(r, b1, b2, 1)))
return NULL;
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j) {
r->words[idx_i] = (r->words[idx_i] &
comask_range(off_i, off_j)) |
((b1->words[idx_i] & b2->words[idx_i]) &
mask_range(off_i, off_j));
return r;
}
r->words[idx_i] = (r->words[idx_i] & mask_first(off_i)) |
((b1->words[idx_i] & b2->words[idx_i]) & comask_first(off_i));
for (idx = idx_i + 1; idx < idx_j; idx++)
r->words[idx] = b1->words[idx_i] & b2->words[idx_i];
if(idx_j < r->nwords)
r->words[idx_j] = (r->words[idx_j] & comask_first(off_j)) |
((b1->words[idx_j] & b2->words[idx_j]) & mask_first(off_j));
return r;
}
clc_bitset clc_bitset_xor_range(clc_bitset r,
clc_bitset b1,
clc_bitset b2, size_t i, size_t j)
{
size_t idx, idx_i, idx_j, off_i, off_j;
if(!(r = binary_result(r, b1, b2, 1)))
return NULL;
bit_pos(&idx_i, &off_i, i);
bit_pos(&idx_j, &off_j, j);
if(idx_i == idx_j) {
r->words[idx_i] = (r->words[idx_i] &
comask_range(off_i, off_j)) |
((b1->words[idx_i] ^ b2->words[idx_i]) &
mask_range(off_i, off_j));
return r;
}
r->words[idx_i] = (r->words[idx_i] & mask_first(off_i)) |
((b1->words[idx_i] ^ b2->words[idx_i]) & comask_first(off_i));
for (idx = idx_i + 1; idx < idx_j; idx++)
r->words[idx] = b1->words[idx_i] ^ b2->words[idx_i];
if(idx_j < r->nwords)
r->words[idx_j] = (r->words[idx_j] & comask_first(off_j)) |
((b1->words[idx_j] ^ b2->words[idx_j]) & mask_first(off_j));
return r;
}
void clc_bitset_print(clc_bitset b, size_t block_length, char sep,
FILE * file)
{
size_t idx, off, n, count = 0;
clc_bitset_word word;
for (idx = n = 0; idx < b->nwords; idx++) {
size_t nused_bits = (idx != b->nwords - 1) ?
nbits_per_word : b->nlast_bits;
word = b->words[idx];
for (off = 0; off < nused_bits; off++, n++) {
fprintf(file, "%c", (word & 1) ? '1' : '0');
if(++count == block_length && n != b->nbits) {
fprintf(file, "%c", sep);
count = 0;
}
word >>= 1;
}
}
printf("\n");
}
--
boa
libclc home: http://libclc.sourceforge.net
|