ENH: better handling of resizing for PackedList bit-wise operators

- previously using an '|=' or '^=' would increase the list size to
  match the RHS. Now it only increases to last bit set.

- limit bit-wise operations to addressable range for minor efficiency
  improvement

- trim results from '&' and '^' operations for more consistent
  behaviour
This commit is contained in:
Mark Olesen
2010-09-16 16:37:41 +02:00
parent bb32504c3b
commit ba896b6903
7 changed files with 277 additions and 171 deletions

View File

@ -40,10 +40,10 @@ using namespace Foam;
int main(int argc, char *argv[])
{
PackedBoolList list1(20);
// set every other one on
// set every third one on
forAll(list1, i)
{
list1[i] = i % 2;
list1[i] = !(i % 3);
}
Info<< "\nalternating bit pattern\n";
@ -52,70 +52,84 @@ int main(int argc, char *argv[])
PackedBoolList list2 = ~list1;
Info<< "\ncomplementary bit pattern\n";
list2.printInfo(Info, true);
list2.printBits(Info);
// set every other on
forAll(list2, i)
{
list2[i] = !(i % 2);
}
Info<< "\nalternating bit pattern\n";
list2.printBits(Info);
list2.resize(24, true);
list2.resize(28, false);
list2.resize(34, true);
list2.resize(40, false);
for (label i=0; i < 4; ++i)
{
list2[i] = true;
}
Info<< "\nresized with 4 true + 4 false, bottom 4 bits true\n";
Info<< "\nresized with false, 6 true + 6 false, bottom 4 bits true\n";
list2.printInfo(Info, true);
labelList list2Labels = list2.used();
Info<< "\noperator|\n";
(list1 | list2).printInfo(Info, true);
list1.printBits(Info);
list2.printBits(Info);
Info<< "==\n";
(list1 | list2).printBits(Info);
Info<< "\noperator& : does trim\n";
(list1 & list2).printInfo(Info, true);
(list1 & list2).printBits(Info);
Info<< "\noperator^\n";
(list1 ^ list2).printInfo(Info, true);
(list1 ^ list2).printBits(Info);
Info<< "\noperator|=\n";
{
PackedBoolList list3 = list1;
(list3 |= list2).printInfo(Info, true);
(list3 |= list2).printBits(Info);
}
Info<< "\noperator|= with UList<label>\n";
{
PackedBoolList list3 = list1;
(list3 |= list2Labels).printInfo(Info, true);
(list3 |= list2Labels).printBits(Info);
}
Info<< "\noperator&=\n";
{
PackedBoolList list3 = list1;
(list3 &= list2).printInfo(Info, true);
(list3 &= list2).printBits(Info);
}
Info<< "\noperator+=\n";
{
PackedBoolList list3 = list1;
(list3 += list2).printInfo(Info, true);
(list3 += list2).printBits(Info);
}
Info<< "\noperator+= with UList<label>\n";
{
PackedBoolList list3 = list1;
(list3 += list2Labels).printInfo(Info, true);
(list3 += list2Labels).printBits(Info);
}
Info<< "\noperator-=\n";
{
PackedBoolList list3 = list1;
(list3 -= list2).printInfo(Info, true);
(list3 -= list2).printBits(Info);
}
Info<< "\noperator-= with UList<label>\n";
{
PackedBoolList list3 = list1;
(list3 -= list2Labels).printInfo(Info, true);
(list3 -= list2Labels).printBits(Info);
}
PackedBoolList list4

View File

@ -26,6 +26,70 @@ License
#include "PackedBoolList.H"
#include "IOstreams.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
bool Foam::PackedBoolList::bitorPrepare
(
const PackedList<1>& lst,
label& maxPackLen
)
{
const StorageList& lhs = this->storage();
const StorageList& rhs = lst.storage();
const label packLen1 = this->packedLength();
const label packLen2 = lst.packedLength();
// check how the lists interact and if bit trimming is needed
bool needTrim = false;
maxPackLen = packLen1;
if (packLen1 == packLen2)
{
// identical packed lengths - only resize if absolutely necessary
if
(
this->size() != lst.size()
&& maxPackLen
&& rhs[maxPackLen-1] > lhs[maxPackLen-1]
)
{
// second list has a higher bit set
// extend addressable area and use trim
resize(lst.size());
needTrim = true;
}
}
else if (packLen2 < packLen1)
{
// second list is shorter, this limits the or
maxPackLen = packLen2;
}
else
{
// second list is longer, find the highest bit set
for (label storeI = packLen1; storeI < packLen2; ++storeI)
{
if (rhs[storeI])
{
maxPackLen = storeI+1;
}
}
// the upper limit moved - resize for full coverage and trim later
if (maxPackLen > packLen1)
{
resize(maxPackLen * packing());
needTrim = true;
}
}
return needTrim;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::PackedBoolList::PackedBoolList(Istream& is)
@ -62,7 +126,7 @@ Foam::Xfer<Foam::labelList> Foam::PackedBoolList::used() const
template<class LabelListType>
Foam::label Foam::PackedBoolList::setFromIndices(const LabelListType& indices)
Foam::label Foam::PackedBoolList::setIndices(const LabelListType& indices)
{
// no better information, just guess something about the size
reserve(indices.size());
@ -81,7 +145,7 @@ Foam::label Foam::PackedBoolList::setFromIndices(const LabelListType& indices)
template<class LabelListType>
Foam::label Foam::PackedBoolList::unsetFromIndices(const LabelListType& indices)
Foam::label Foam::PackedBoolList::unsetIndices(const LabelListType& indices)
{
label cnt = 0;
forAll(indices, elemI)
@ -98,46 +162,30 @@ Foam::label Foam::PackedBoolList::unsetFromIndices(const LabelListType& indices)
Foam::label Foam::PackedBoolList::set(const UList<label>& indices)
{
return setFromIndices(indices);
return setIndices(indices);
}
Foam::label Foam::PackedBoolList::set(const UIndirectList<label>& indices)
{
return setFromIndices(indices);
return setIndices(indices);
}
Foam::label Foam::PackedBoolList::unset(const UList<label>& indices)
{
return unsetFromIndices(indices);
return unsetIndices(indices);
}
Foam::label Foam::PackedBoolList::unset(const UIndirectList<label>& indices)
{
return unsetFromIndices(indices);
}
void Foam::PackedBoolList::modulo(const PackedList<1>& lst)
{
// operate directly with the underlying storage
StorageList& lhs = this->storage();
const StorageList& rhs = lst.storage();
const label len = min(lhs.size(), rhs.size());
for (label i=0; i < len; ++i)
{
lhs[i] &= ~rhs[i];
}
return unsetIndices(indices);
}
// * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * //
Foam::PackedBoolList&
Foam::PackedBoolList::operator=(const UList<bool>& lst)
{
@ -172,28 +220,6 @@ Foam::PackedBoolList::operator=(const UIndirectList<label>& indices)
}
Foam::PackedBoolList&
Foam::PackedBoolList::operator|=(const PackedList<1>& lst)
{
// extend addressable area if needed
if (this->size() < lst.size())
{
this->resize(lst.size());
}
// operate directly with the underlying storage
StorageList& lhs = this->storage();
const StorageList& rhs = lst.storage();
forAll(rhs, i)
{
lhs[i] |= rhs[i];
}
return *this;
}
Foam::PackedBoolList&
Foam::PackedBoolList::operator&=(const PackedList<1>& lst)
{
@ -207,14 +233,13 @@ Foam::PackedBoolList::operator&=(const PackedList<1>& lst)
StorageList& lhs = this->storage();
const StorageList& rhs = lst.storage();
forAll(lhs, i)
const label len = this->packedLength();
for (label i=0; i < len; ++i)
{
lhs[i] &= rhs[i];
}
// trim to bits actually used
this->trim();
return *this;
}
@ -222,27 +247,106 @@ Foam::PackedBoolList::operator&=(const PackedList<1>& lst)
Foam::PackedBoolList&
Foam::PackedBoolList::operator^=(const PackedList<1>& lst)
{
// extend addressable area if needed
if (this->size() < lst.size())
{
this->resize(lst.size());
}
// extend addressable area if needed, return maximum size possible
label len = 0;
const bool needTrim = bitorPrepare(lst, len);
// operate directly with the underlying storage
StorageList& lhs = this->storage();
const StorageList& rhs = lst.storage();
forAll(rhs, i)
for (label i=0; i < len; ++i)
{
lhs[i] ^= rhs[i];
}
if (needTrim)
{
trim();
}
return *this;
}
Foam::PackedBoolList&
Foam::PackedBoolList::operator|=(const PackedList<1>& lst)
{
// extend addressable area if needed, return maximum size possible
label len = 0;
const bool needTrim = bitorPrepare(lst, len);
// operate directly with the underlying storage
StorageList& lhs = this->storage();
const StorageList& rhs = lst.storage();
for (label i=0; i < len; ++i)
{
lhs[i] |= rhs[i];
}
if (needTrim)
{
trim();
}
return *this;
}
Foam::PackedBoolList&
Foam::PackedBoolList::operator-=(const PackedList<1>& lst)
{
// operate directly with the underlying storage
StorageList& lhs = this->storage();
const StorageList& rhs = lst.storage();
// overlapping storage size
const label len = min(this->packedLength(), lst.packedLength());
for (label i=0; i < len; ++i)
{
lhs[i] &= ~rhs[i];
}
return *this;
}
// * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * * //
Foam::PackedBoolList Foam::operator&
(
const PackedBoolList& lst1,
const PackedBoolList& lst2
)
{
PackedBoolList result(lst1);
result &= lst2;
// trim to bits actually used
result.trim();
return result;
}
Foam::PackedBoolList Foam::operator^
(
const PackedBoolList& lst1,
const PackedBoolList& lst2
)
{
PackedBoolList result(lst1);
result ^= lst2;
// trim to bits actually used
result.trim();
return result;
}
Foam::PackedBoolList Foam::operator|
(
const PackedBoolList& lst1,
@ -255,28 +359,4 @@ Foam::PackedBoolList Foam::operator|
}
Foam::PackedBoolList Foam::operator&
(
const PackedBoolList& lst1,
const PackedBoolList& lst2
)
{
PackedBoolList result(lst1);
result &= lst2;
return result;
}
Foam::PackedBoolList Foam::operator^
(
const PackedBoolList& lst1,
const PackedBoolList& lst2
)
{
PackedBoolList result(lst1);
result ^= lst2;
return result;
}
// ************************************************************************* //

View File

@ -61,19 +61,19 @@ class PackedBoolList
{
// Private Member Functions
//- Modulo is everything that is not in lst
// This is equivalent to unsetting the bits specified in lst
void modulo(const PackedList<1>&);
//- Preparation, resizing before a bitor operation
// returns true if the later result needs trimming
bool bitorPrepare(const PackedList<1>& lst, label& maxPackLen);
//- Set the listed indices. Return number of elements changed.
// Does auto-vivify for non-existent entries.
template<class LabelListType>
label setFromIndices(const LabelListType& indices);
label setIndices(const LabelListType& indices);
//- Unset the listed indices. Return number of elements changed.
// Never auto-vivify entries.
template<class LabelListType>
label unsetFromIndices(const LabelListType& indices);
label unsetIndices(const LabelListType& indices);
public:
@ -184,6 +184,13 @@ public:
//- Complement operator
inline PackedBoolList operator~() const;
//- And operator (lists may be dissimilar sizes)
PackedBoolList& operator&=(const PackedList<1>&);
//- Xor operator (lists may be dissimilar sizes)
// Retains unique entries
PackedBoolList& operator^=(const PackedList<1>&);
//- Or operator (lists may be dissimilar sizes)
PackedBoolList& operator|=(const PackedList<1>&);
@ -195,14 +202,6 @@ public:
// using the labels as indices to indicate which bits are set
inline PackedBoolList& operator|=(const UIndirectList<label>&);
//- And operator (lists may be dissimilar sizes)
// The result is trimmed to the smallest intersecting size
PackedBoolList& operator&=(const PackedList<1>&);
//- And operator (lists may be dissimilar sizes)
// Only retain unique entries
PackedBoolList& operator^=(const PackedList<1>&);
//- Add entries to this list, synonymous with the or operator
inline PackedBoolList& operator+=(const PackedList<1>&);
@ -213,13 +212,13 @@ public:
//- Add entries to this list, synonymous with the or operator
inline PackedBoolList& operator+=(const UIndirectList<label>&);
//- Remove entries from this list
inline PackedBoolList& operator-=(const PackedList<1>&);
//- Remove entries from this list - unset the specified bits
PackedBoolList& operator-=(const PackedList<1>&);
//- Remove entries from this list
//- Remove entries from this list - unset the specified bits
inline PackedBoolList& operator-=(const UList<label>& indices);
//- Remove entries from this list
//- Remove entries from this list - unset the specified bits
inline PackedBoolList& operator-=(const UIndirectList<label>&);
};
@ -227,14 +226,6 @@ public:
// Global Operators
//- Combine lists
PackedBoolList operator|
(
const PackedBoolList& lst1,
const PackedBoolList& lst2
);
//- Intersect lists - the result is trimmed to the smallest intersecting size
PackedBoolList operator&
(
@ -244,6 +235,7 @@ PackedBoolList operator&
//- Combine to form a unique list (xor)
// The result is trimmed to the smallest intersecting size
PackedBoolList operator^
(
const PackedBoolList& lst1,
@ -251,6 +243,14 @@ PackedBoolList operator^
);
//- Combine lists
PackedBoolList operator|
(
const PackedBoolList& lst1,
const PackedBoolList& lst2
);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam

View File

@ -127,16 +127,6 @@ inline Foam::Xfer<Foam::PackedBoolList> Foam::PackedBoolList::xfer()
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline Foam::PackedBoolList
Foam::PackedBoolList::operator~() const
{
PackedBoolList result(*this);
result.flip();
return result;
}
inline Foam::PackedBoolList&
Foam::PackedBoolList::operator=(const bool val)
{
@ -161,6 +151,16 @@ Foam::PackedBoolList::operator=(const PackedList<1>& lst)
}
inline Foam::PackedBoolList
Foam::PackedBoolList::operator~() const
{
PackedBoolList result(*this);
result.flip();
return result;
}
inline Foam::PackedBoolList&
Foam::PackedBoolList::operator|=(const UList<label>& indices)
{
@ -198,14 +198,6 @@ Foam::PackedBoolList::operator+=(const UIndirectList<label>& indices)
}
inline Foam::PackedBoolList&
Foam::PackedBoolList::operator-=(const PackedList<1>& lst)
{
this->modulo(lst);
return *this;
}
inline Foam::PackedBoolList&
Foam::PackedBoolList::operator-=(const UList<label>& indices)
{

View File

@ -29,13 +29,6 @@ License
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<unsigned nBits>
inline Foam::label Foam::PackedList<nBits>::byteSize() const
{
return packedLength(this->size()) * sizeof(StorageType);
}
#if (UINT_MAX == 0xFFFFFFFF)
// 32-bit counting, Hamming weight method
# define COUNT_PACKEDBITS(sum, x) \
@ -65,8 +58,7 @@ unsigned int Foam::PackedList<nBits>::count() const
if (size_)
{
const label packLen = packedLength(size_);
const label packLen = packedLength();
for (label i = 0; i < packLen; ++i)
{
register unsigned int bits = StorageList::operator[](i);
@ -87,8 +79,7 @@ bool Foam::PackedList<nBits>::trim()
}
const label oldSize = size_;
for (label storeI = packedLength(size_) - 1; storeI >= 0; --storeI)
for (label storeI = packedLength()-1; storeI >= 0; --storeI)
{
size_ = storeI * packing();
unsigned int bits = StorageList::operator[](storeI);
@ -120,7 +111,7 @@ void Foam::PackedList<nBits>::flip()
// mask value for complete segments
const unsigned int mask = maskLower(packing());
const label packLen = packedLength(size_);
const label packLen = packedLength();
for (label i=0; i < packLen; ++i)
{
StorageList::operator[](i) = mask & ~StorageList::operator[](i);
@ -171,26 +162,19 @@ Foam::Ostream& Foam::PackedList<nBits>::iteratorBase::printInfo
template<unsigned nBits>
Foam::Ostream& Foam::PackedList<nBits>::printInfo
Foam::Ostream& Foam::PackedList<nBits>::printBits
(
Ostream& os,
const bool fullOutput
) const
{
const label packLen = packedLength(size_);
os << "PackedList<" << nBits << ">"
<< " max_value:" << max_value()
<< " packing:" << packing() << nl
<< " count: " << count() << nl
<< " size/capacity: " << size_ << "/" << capacity() << nl
<< " storage/capacity: " << packLen << "/" << StorageList::size()
<< "\n(\n";
const label packLen = packedLength();
// mask value for complete segments
unsigned int mask = maskLower(packing());
const label outputLen = fullOutput ? StorageList::size() : packLen;
os << "(\n";
for (label i=0; i < outputLen; ++i)
{
const StorageType& rawBits = StorageList::operator[](i);
@ -240,12 +224,32 @@ Foam::Ostream& Foam::PackedList<nBits>::printInfo
}
os << '\n';
}
os << ")\n";
os << ")\n";
return os;
}
template<unsigned nBits>
Foam::Ostream& Foam::PackedList<nBits>::printInfo
(
Ostream& os,
const bool fullOutput
) const
{
os << "PackedList<" << nBits << ">"
<< " max_value:" << max_value()
<< " packing:" << packing() << nl
<< " count: " << count() << nl
<< " size/capacity: " << size_ << "/" << capacity() << nl
<< " storage/capacity: "
<< packedLength() << "/" << StorageList::size()
<< "\n";
return printBits(os, fullOutput);
}
template<unsigned nBits>
Foam::Istream& Foam::PackedList<nBits>::read(Istream& is)
{
@ -501,7 +505,7 @@ Foam::Ostream& Foam::PackedList<nBits>::write
template<unsigned nBits>
void Foam::PackedList<nBits>::writeEntry(Ostream& os) const
{
os << *this;
os << *this;
}
@ -514,7 +518,7 @@ void Foam::PackedList<nBits>::writeEntry
{
os.writeKeyword(keyword);
writeEntry(os);
os << token::END_STATEMENT << endl;
os << token::END_STATEMENT << endl;
}

View File

@ -269,9 +269,12 @@ public:
//- Return the underlying packed storage
inline const List<unsigned int>& storage() const;
//- The list length when packed
inline label packedLength() const;
//- Return the binary size in number of characters
// used in the underlying storage
label byteSize() const;
inline label byteSize() const;
//- Count number of bits set, O(log(n))
// Uses the Hamming weight (population count) method
@ -281,7 +284,7 @@ public:
//- Return the values as a list of labels
Xfer<labelList> values() const;
//- Print information and values, optionally output unused elements
//- Print bit patterns, optionally output unused elements
//
// addressable bits:
// on: '1', off: '-'
@ -289,6 +292,9 @@ public:
// non-addressable bits:
// on: '!', off: '.'
//
Ostream& printBits(Ostream&, const bool fullOutput=false) const;
//- Print information and bit patterns (with printBits)
Ostream& printInfo(Ostream&, const bool fullOutput=false) const;

View File

@ -869,10 +869,7 @@ inline void Foam::PackedList<nBits>::setCapacity(const label nElem)
template<unsigned nBits>
inline void Foam::PackedList<nBits>::reserve
(
const label nElem
)
inline void Foam::PackedList<nBits>::reserve(const label nElem)
{
const label len = packedLength(nElem);
@ -919,9 +916,8 @@ inline void Foam::PackedList<nBits>::clearStorage()
template<unsigned nBits>
inline void Foam::PackedList<nBits>::shrink()
{
const label len = packedLength(size_);
// we have unused space?
// any uneed space allocated?
const label len = packedLength();
if (len < StorageList::size())
{
StorageList::setSize(len);
@ -942,6 +938,20 @@ inline const Foam::List<unsigned int>& Foam::PackedList<nBits>::storage() const
}
template<unsigned nBits>
inline Foam::label Foam::PackedList<nBits>::packedLength() const
{
return packedLength(size_);
}
template<unsigned nBits>
inline Foam::label Foam::PackedList<nBits>::byteSize() const
{
return packedLength() * sizeof(StorageType);
}
template<unsigned nBits>
inline void Foam::PackedList<nBits>::transfer(PackedList<nBits>& lst)
{
@ -1070,7 +1080,7 @@ template<unsigned nBits>
inline Foam::PackedList<nBits>&
Foam::PackedList<nBits>::operator=(const unsigned int val)
{
const label packLen = packedLength(size_);
const label packLen = packedLength();
if (val && size_)
{