Commit ba896b69 authored by Mark Olesen's avatar Mark Olesen
Browse files

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
parent bb32504c
......@@ -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
......
......@@ -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)
{
......@@ -173,10 +221,10 @@ Foam::PackedBoolList::operator=(const UIndirectList<label>& indices)
Foam::PackedBoolList&
Foam::PackedBoolList::operator|=(const PackedList<1>& lst)
Foam::PackedBoolList::operator&=(const PackedList<1>& lst)
{
// extend addressable area if needed
if (this->size() < lst.size())
// shrink addressable area if needed
if (this->size() > lst.size())
{
this->resize(lst.size());
}
......@@ -185,9 +233,11 @@ Foam::PackedBoolList::operator|=(const PackedList<1>& lst)
StorageList& lhs = this->storage();
const StorageList& rhs = lst.storage();
forAll(rhs, i)
const label len = this->packedLength();
for (label i=0; i < len; ++i)
{
lhs[i] |= rhs[i];
lhs[i] &= rhs[i];
}
return *this;
......@@ -195,46 +245,68 @@ Foam::PackedBoolList::operator|=(const PackedList<1>& lst)
Foam::PackedBoolList&
Foam::PackedBoolList::operator&=(const PackedList<1>& lst)
Foam::PackedBoolList::operator^=(const PackedList<1>& lst)
{
// shrink 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(lhs, i)
for (label i=0; i < len; ++i)
{
lhs[i] &= rhs[i];
lhs[i] ^= rhs[i];
}
// trim to bits actually used
this->trim();
if (needTrim)
{
trim();
}
return *this;
}
Foam::PackedBoolList&
Foam::PackedBoolList::operator^=(const PackedList<1>& lst)
Foam::PackedBoolList::operator|=(const PackedList<1>& lst)
{
// extend addressable area if needed
if (this->size() < 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();
for (label i=0; i < len; ++i)
{
this->resize(lst.size());
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();
forAll(rhs, i)
// overlapping storage size
const label len = min(this->packedLength(), lst.packedLength());
for (label i=0; i < len; ++i)
{
lhs[i] ^= rhs[i];
lhs[i] &= ~rhs[i];
}
return *this;
......@@ -243,38 +315,46 @@ Foam::PackedBoolList::operator^=(const PackedList<1>& lst)
// * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * * //
Foam::PackedBoolList Foam::operator|
Foam::PackedBoolList Foam::operator&
(
const PackedBoolList& lst1,
const PackedBoolList& lst2
)
{
PackedBoolList result(lst1);
result |= lst2;
result &= lst2;
// trim to bits actually used
result.trim();
return result;
}
Foam::PackedBoolList Foam::operator&
Foam::PackedBoolList Foam::operator^
(
const PackedBoolList& lst1,
const PackedBoolList& lst2
)
{
PackedBoolList result(lst1);
result &= lst2;
result ^= lst2;
// trim to bits actually used
result.trim();
return result;
}
Foam::PackedBoolList Foam::operator^
Foam::PackedBoolList Foam::operator|
(
const PackedBoolList& lst1,
const PackedBoolList& lst2
)
{
PackedBoolList result(lst1);
result ^= lst2;
result |= lst2;
return result;
}
......
......@@ -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,24 +226,25 @@ public:
// Global Operators
//- Combine lists
PackedBoolList operator|
//- Intersect lists - the result is trimmed to the smallest intersecting size
PackedBoolList operator&
(
const PackedBoolList& lst1,
const PackedBoolList& lst2
);
//- Intersect lists - the result is trimmed to the smallest intersecting size
PackedBoolList operator&
//- Combine to form a unique list (xor)
// The result is trimmed to the smallest intersecting size
PackedBoolList operator^
(
const PackedBoolList& lst1,
const PackedBoolList& lst2
);
//- Combine to form a unique list (xor)
PackedBoolList operator^
//- Combine lists
PackedBoolList operator|
(
const PackedBoolList& lst1,
const PackedBoolList& lst2
......
......@@ -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)
{
......
......@@ -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