From 252914599ad73e01ca8d0a89ef8d8d391d072858 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Wed, 2 May 2018 08:33:49 +0200 Subject: [PATCH] ENH: bitSet::find_first_not() method (issue #751) - find the position of the first bit off - symmetrical with find_first() --- applications/test/bitSet2/Test-bitSet2.C | 72 +++++++--- src/OpenFOAM/containers/Bits/bitSet/bitSet.H | 17 ++- src/OpenFOAM/containers/Bits/bitSet/bitSetI.H | 125 ++++++++++++------ 3 files changed, 156 insertions(+), 58 deletions(-) diff --git a/applications/test/bitSet2/Test-bitSet2.C b/applications/test/bitSet2/Test-bitSet2.C index 9c62bd7e7a..b76048b01d 100644 --- a/applications/test/bitSet2/Test-bitSet2.C +++ b/applications/test/bitSet2/Test-bitSet2.C @@ -40,12 +40,19 @@ Description using namespace Foam; -inline Ostream& report -( - const bitSet& bitset, - bool showBits = false, - bool debugOutput = false -) + +inline Ostream& extent(const bitSet& bitset) +{ + Info<< "first: " << bitset.find_first() + << " 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() << " count=" << bitset.count() @@ -54,17 +61,11 @@ inline Ostream& report << " any:" << bitset.any() << " none:" << bitset.none() << nl; - Info<< "values: " << flatOutput(bitset) << nl; - if (showBits) - { - bitset.printBits(Info, debugOutput) << nl; - } - return Info; } -inline Ostream& report(const UList<bool>& bools) +inline Ostream& info(const UList<bool>& bools) { Info<< "size=" << bools.size() << " count=" << BitOps::count(bools) @@ -77,6 +78,31 @@ inline Ostream& report(const UList<bool>& bools) } +inline Ostream& report +( + const bitSet& bitset, + bool showBits = false, + bool debugOutput = false +) +{ + info(bitset); + + Info<< "values: " << flatOutput(bitset) << nl; + if (showBits) + { + bitset.printBits(Info, debugOutput) << nl; + } + + return Info; +} + + +inline Ostream& report(const UList<bool>& bools) +{ + return info(bools); +} + + template<class UIntType> std::string toString(UIntType value, char off='.', char on='1') { @@ -153,10 +179,7 @@ int main(int argc, char *argv[]) compare(list1, "...................1..1..1..1..1"); report(list1, true); - - - Info<< "first: " << list1.find_first() - << " last: " << list1.find_last() << endl; + extent(list1); Info<< "iterate through:"; for (const label idx : list1) @@ -172,6 +195,21 @@ int main(int argc, char *argv[]) Info<< "\nflipped bit pattern\n"; 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 forAll(list2, i) diff --git a/src/OpenFOAM/containers/Bits/bitSet/bitSet.H b/src/OpenFOAM/containers/Bits/bitSet/bitSet.H index 32b104df2c..8f2cfae003 100644 --- a/src/OpenFOAM/containers/Bits/bitSet/bitSet.H +++ b/src/OpenFOAM/containers/Bits/bitSet/bitSet.H @@ -65,6 +65,15 @@ class bitSet : 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 Member Functions @@ -203,12 +212,18 @@ public: // \note Method name compatibility with std::bitset 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. // // \note Method name compatibility with boost::dynamic_bitset 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. // \return the location or -1 if there are no bits set. // diff --git a/src/OpenFOAM/containers/Bits/bitSet/bitSetI.H b/src/OpenFOAM/containers/Bits/bitSet/bitSetI.H index 0ab1bb59ab..413aa87c33 100644 --- a/src/OpenFOAM/containers/Bits/bitSet/bitSetI.H +++ b/src/OpenFOAM/containers/Bits/bitSet/bitSetI.H @@ -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 * * * * * * * * * * * * * * // 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 { // 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 { - if (empty()) - { - 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; + return -1 == first_not_block(); } @@ -388,7 +430,10 @@ inline bool Foam::bitSet::any() const 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) { - // Return the number of bits that are off. + // Return the number of bits that are OFF. return (unsigned(size()) - total); } -- GitLab