ENH: bitSet::find_first_not() method (issue #751)

- find the position of the first bit off - symmetrical with find_first()
This commit is contained in:
Mark Olesen
2018-05-02 08:33:49 +02:00
parent 4653beaa49
commit 0ea44eda59
3 changed files with 157 additions and 59 deletions

View File

@ -40,12 +40,19 @@ Description
using namespace Foam; using namespace Foam;
inline Ostream& report
( inline Ostream& extent(const bitSet& bitset)
const bitSet& bitset, {
bool showBits = false, Info<< "first: " << bitset.find_first()
bool debugOutput = false << " last: " << bitset.find_last()
) << " first_not: " << bitset.find_first_not()
<< endl;
return Info;
}
inline Ostream& info(const bitSet& bitset)
{ {
Info<< "size=" << bitset.size() << "/" << bitset.capacity() Info<< "size=" << bitset.size() << "/" << bitset.capacity()
<< " count=" << bitset.count() << " count=" << bitset.count()
@ -54,6 +61,32 @@ inline Ostream& report
<< " any:" << bitset.any() << " any:" << bitset.any()
<< " none:" << bitset.none() << nl; << " none:" << bitset.none() << nl;
return Info;
}
inline Ostream& info(const UList<bool>& bools)
{
Info<< "size=" << bools.size()
<< " count=" << BitOps::count(bools)
<< " !count=" << BitOps::count(bools, false)
<< " all:" << BitOps::all(bools)
<< " any:" << BitOps::any(bools)
<< " none:" << BitOps::none(bools) << nl;
return Info;
}
inline Ostream& report
(
const bitSet& bitset,
bool showBits = false,
bool debugOutput = false
)
{
info(bitset);
Info<< "values: " << flatOutput(bitset) << nl; Info<< "values: " << flatOutput(bitset) << nl;
if (showBits) if (showBits)
{ {
@ -66,14 +99,7 @@ inline Ostream& report
inline Ostream& report(const UList<bool>& bools) inline Ostream& report(const UList<bool>& bools)
{ {
Info<< "size=" << bools.size() return info(bools);
<< " count=" << BitOps::count(bools)
<< " !count=" << BitOps::count(bools, false)
<< " all:" << BitOps::all(bools)
<< " any:" << BitOps::any(bools)
<< " none:" << BitOps::none(bools) << nl;
return Info;
} }
@ -153,10 +179,7 @@ int main(int argc, char *argv[])
compare(list1, "...................1..1..1..1..1"); compare(list1, "...................1..1..1..1..1");
report(list1, true); report(list1, true);
extent(list1);
Info<< "first: " << list1.find_first()
<< " last: " << list1.find_last() << endl;
Info<< "iterate through:"; Info<< "iterate through:";
for (const label idx : list1) for (const label idx : list1)
@ -172,6 +195,21 @@ int main(int argc, char *argv[])
Info<< "\nflipped bit pattern\n"; Info<< "\nflipped bit pattern\n";
report(list2, true); report(list2, true);
extent(list2);
Info<< "\nsparse set\n";
{
bitSet sparse(1000);
sparse.set(300);
info(sparse);
extent(sparse);
sparse.set(0);
info(sparse);
extent(sparse);
}
// set every other on // set every other on
forAll(list2, i) forAll(list2, i)

View File

@ -65,6 +65,15 @@ class bitSet
: :
public PackedList<1> public PackedList<1>
{ {
private:
// Private Member Functions
//- Find the first block with a '0' bit
// \return block number or -1 if the set is empty or all bits are on.
inline label first_not_block() const;
protected: protected:
// Protected Member Functions // Protected Member Functions
@ -203,12 +212,18 @@ public:
// \note Method name compatibility with std::bitset // \note Method name compatibility with std::bitset
inline bool test(const label pos) const; inline bool test(const label pos) const;
//- Locate the first bit set. //- Locate the first bit that is set.
// \return the location or -1 if there are no bits set. // \return the location or -1 if there are no bits set.
// //
// \note Method name compatibility with boost::dynamic_bitset // \note Method name compatibility with boost::dynamic_bitset
inline label find_first() const; inline label find_first() const;
//- Locate the first bit that is unset.
// \return the location or -1 if the set is empty or all bits are on.
//
// \note Provided for symmetry with find_first()
inline label find_first_not() const;
//- Locate the last bit set. //- Locate the last bit set.
// \return the location or -1 if there are no bits set. // \return the location or -1 if there are no bits set.
// //

View File

@ -23,6 +23,53 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
inline Foam::label Foam::bitSet::first_not_block() const
{
if (empty())
{
return -1;
}
// Use complement to change 0 <-> 1 and check if any 1's now appear
const label nblocks = num_blocks(size());
// Extra bits in the final block?
const unsigned int off = size() % elem_per_block;
if (!off)
{
for (label blocki=0; blocki < nblocks; ++blocki)
{
if (~(blocks_[blocki]))
{
return blocki;
}
}
}
else
{
for (label blocki=0; blocki < nblocks-1; ++blocki)
{
if (~(blocks_[blocki]))
{
return blocki;
}
}
// The final block needs masking
if (~(blocks_[nblocks-1]) & mask_lower(off))
{
return nblocks-1;
}
}
return -1;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
inline constexpr Foam::bitSet::bitSet() noexcept inline constexpr Foam::bitSet::bitSet() noexcept
@ -257,6 +304,38 @@ inline Foam::label Foam::bitSet::find_first() const
} }
inline Foam::label Foam::bitSet::find_first_not() const
{
const label blocki = first_not_block();
if (blocki >= 0)
{
label pos = (blocki * elem_per_block);
// Detect first '0' bit by checking the complement.
// No special masking for the final block, that was already checked
// in the first_not_block() call.
for
(
unsigned int blockval = ~(blocks_[blocki]);
blockval;
blockval >>= 1u
)
{
if (blockval & 1u)
{
return pos;
}
++pos;
}
}
return -1;
}
inline Foam::label Foam::bitSet::find_last() const inline Foam::label Foam::bitSet::find_last() const
{ {
// Process block-wise, detecting any '1' bits // Process block-wise, detecting any '1' bits
@ -339,44 +418,7 @@ inline Foam::label Foam::bitSet::find_next(label pos) const
inline bool Foam::bitSet::all() const inline bool Foam::bitSet::all() const
{ {
if (empty()) return -1 == first_not_block();
{
return true;
}
// Use complement to change 0 <-> 1 and check if any 1's now appear
const label nblocks = num_blocks(size());
// Extra bits in the final block?
const unsigned int off = size() % elem_per_block;
if (!off)
{
for (label blocki=0; blocki < nblocks; ++blocki)
{
if (~(blocks_[blocki]))
{
return false;
}
}
}
else
{
for (label blocki=0; blocki < nblocks-1; ++blocki)
{
if (~(blocks_[blocki]))
{
return false;
}
}
// Verify the final block, with masking
return (!(~blocks_[nblocks-1] & mask_lower(off)));
}
return true;
} }
@ -388,7 +430,10 @@ inline bool Foam::bitSet::any() const
for (label blocki=0; blocki < nblocks; ++blocki) for (label blocki=0; blocki < nblocks; ++blocki)
{ {
if (blocks_[blocki]) return true; if (blocks_[blocki])
{
return true;
}
} }
} }
@ -421,7 +466,7 @@ inline unsigned int Foam::bitSet::count(const bool on) const
if (!on) if (!on)
{ {
// Return the number of bits that are off. // Return the number of bits that are OFF.
return (unsigned(size()) - total); return (unsigned(size()) - total);
} }