Commit 74b0582b authored by Andreas Seltenreich's avatar Andreas Seltenreich
Browse files

rbitset: Add a backward iterator rbitset_prev.

Also adds accompanying bitset_t functions and unittests.
parent f78cd2c2
......@@ -198,6 +198,38 @@ static inline size_t bitset_next_set(const bitset_t *bs, size_t pos)
#define bitset_foreach_clear(bitset, elm) \
for (size_t elm = 0; (elm = bitset_next_clear((bitset), elm)) != (size_t)-1; ++elm)
/**
* Find the previous unset bit from a given bit.
* @param bs The bitset.
* @param pos The bit from which to search for the previous unset bit.
* @return The previous unset bit from pos on, or (size_t)-1, if no unset bit was
* found before pos.
*/
static inline size_t bitset_prev_clear(const bitset_t *bs, size_t pos)
{
return rbitset_prev(bs->data, pos, false);
}
/**
* Find the previous set bit from a given bit.
* @param bs The bitset.
* @param pos The bit from which to search for the next set bit.
* @return The previous set bit from pos on, or (size_t)-1, if no set bit was
* found before pos.
*/
static inline size_t bitset_prev_set(const bitset_t *bs, size_t pos)
{
return rbitset_prev(bs->data, pos, true);
}
#define bitset_foreach_rev(bitset, elm) \
for (size_t elm = bitset->size; (elm = rbitset_prev(bitset->data, elm, true)) != (size_t)-1;)
#define bitset_foreach_clear_rev(bitset, elm) \
for (size_t elm = bitset->size; (elm = rbitset_prev(bitset->data, elm, false)) != (size_t)-1;)
/**
* Count the bits set.
* This can also be seen as the cardinality of the set.
......
......@@ -321,6 +321,55 @@ static inline size_t rbitset_next_max(const unsigned *bitset, size_t pos,
return res;
}
/**
* Returns the position of the previous bit starting from (but not including)
* a given position.
*
* @param bitset a bitset
* @param pos the position after the first bit to check
* @param set if 0 search for unset bit, else for set bit
*
* @return The first position where a matched bit was found or -1 if
* none found.
*
*/
static inline size_t rbitset_prev(const unsigned *bitset, size_t pos,
bool set)
{
size_t elem_pos = pos / BITS_PER_ELEM;
size_t bit_pos = pos % BITS_PER_ELEM;
unsigned elem = bitset[elem_pos];
unsigned mask = set ? 0 : ~0u;
/*
* Mask out the bits larger than pos in the current unit.
* We are only interested in bits set lower than pos.
*/
unsigned in_elem_mask = ~((1u << bit_pos) - 1u);
elem ^= mask;
unsigned p = nlz(elem & ~in_elem_mask);
/* If there is a bit set in the current elem, exit. */
if (p < BITS_PER_ELEM) {
return (1+elem_pos) * BITS_PER_ELEM - p - 1;
}
/* Else search for set bits in the previous units. */
while (elem_pos > 0) {
elem_pos--;
elem = bitset[elem_pos] ^ mask;
p = nlz(elem);
if (p < BITS_PER_ELEM) {
return (1+elem_pos) * BITS_PER_ELEM - p - 1;
}
}
return -1;
}
/**
* Inplace Intersection of two sets.
*
......
......@@ -44,6 +44,15 @@ int main(void)
assert(rbitset_next_max(field1, 3, 66, false) == 4);
assert(rbitset_next_max(field1, 60, 66, true) == (size_t)-1);
assert(rbitset_next_max(field1, 3, 4, false) == (size_t)-1);
assert(rbitset_prev(field1, 0, true) == (size_t)-1);
assert(rbitset_prev(field1, 3, true) == (size_t)-1);
assert(rbitset_prev(field1, 4, true) == 3);
assert(rbitset_prev(field1, 59, true) == 3);
assert(rbitset_prev(field1, 60, true) == 59);
assert(rbitset_prev(field1, 34, true) == 3);
assert(rbitset_prev(field1, 0, false) == (size_t)-1);
assert(rbitset_prev(field1, 3, false) == 2);
assert(rbitset_prev(field1, 1, false) == 0);
unsigned *null = (unsigned*)0;
rbitset_flip_all(null, 0);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment