Commit 4e56643e authored by Mark Olesen's avatar Mark Olesen
Browse files

PackedList improvements

- dropped auto-vivification for now (performance issue), but reworked to
  allow easy reinstatement
- derived both iterator and const_iterator from iteratorBase and use
  iteratorBase as our proxy for non-const access to the list elements.
  This allows properly chaining assignments:
     list[1] = list[2];
     list[1] = list[2] = 10;
- assigning iterators from iteratorBase or other iterators works:
     iterator iter = list[20];
- made template parameter nBits=1 the default
parent 69f8c3b3
......@@ -52,25 +52,29 @@ int main(int argc, char *argv[])
list1 = -1;
list1.print(Info);
Info<< "\ntest assign between references - does not work as expected\n";
Info<< "\ntest assign between references\n";
list1[2] = 3;
list1[4] = list1[2];
list1.print(Info);
Info<< "\ntest assign between references, with chaining\n";
list1[4] = list1[2] = 1;
list1.print(Info);
{
const PackedList<3>& constLst = list1;
Info<< "\ntest operator[] const with out-of-range index\n";
constLst.print(Info);
if (!constLst[20])
{
Info<< "[20] is false, as expected\n";
Info<< "[20] is false (expected) list size should be unchanged (const)\n";
}
constLst.print(Info);
Info<< "\ntest operator[] non-const with out-of-range index\n";
if (!list1[20])
{
Info<< "[20] is false, as expected but list was resized!! (non-const)\n";
Info<< "[20] is false (expected) but list was resized?? (non-const)\n";
}
list1.print(Info);
}
......@@ -145,6 +149,10 @@ int main(int argc, char *argv[])
list1.setCapacity(24);
list1.print(Info);
Info<< "\ntest resize much smaller\n";
list1.resize(150);
list1.print(Info);
Info<< "\ntest trim\n";
list1.trim();
list1.print(Info);
......@@ -159,13 +167,16 @@ int main(int argc, char *argv[])
Info<< "begin():";
iter.print(Info) << "\n";
Info<< "\ntest iterator operator=\n";
iter = 2;
Info<< "iterator:" << iter() << "\n";
iter = 5;
iter() = 5;
iter.print(Info);
list1.print(Info);
iter = list1[31];
Info<< "iterator:" << iter() << "\n";
iter.print(Info);
Info<< "\ntest get() method\n";
Info<< "get(10):" << list1.get(10) << " and list[10]:" << list1[10] << "\n";
list1.print(Info);
......@@ -173,25 +184,34 @@ int main(int argc, char *argv[])
Info<< "\ntest iterator indexing\n";
Info<< "cend() ";
list1.cend().print(Info) << "\n";
{
Info<< "\ntest assignment of iterator\n";
list1.print(Info);
PackedList<3>::iterator cit = list1[25];
cit.print(Info);
list1.end().print(Info);
}
for
(
PackedList<3>::const_iterator cit = list1[30];
cit != list1.cend();
PackedList<3>::iterator cit = list1[5];
cit != list1.end();
++cit
)
{
cit.print(Info);
}
Info<< "\ntest operator[] auto-vivify\n";
const unsigned int val = list1[45];
Info<< "list[45]:" << val << "\n";
list1[45] = list1.max_value();
Info<< "list[45]:" << list1[45] << "\n";
list1[49] = list1.max_value();
list1.print(Info);
// Info<< "\ntest operator[] auto-vivify\n";
// const unsigned int val = list1[45];
//
// Info<< "list[45]:" << val << "\n";
// list1[45] = list1.max_value();
// Info<< "list[45]:" << list1[45] << "\n";
// list1[49] = list1.max_value();
// list1.print(Info);
Info<< "\ntest copy constructor + append\n";
......
......@@ -61,8 +61,8 @@ int main(int argc, char *argv[])
}
cpuTime timer;
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
packed.resize(40);
packed.shrink();
......@@ -76,7 +76,7 @@ int main(int argc, char *argv[])
// Count packed
sum = 0;
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
forAll(packed, i)
{
......@@ -90,7 +90,7 @@ int main(int argc, char *argv[])
// Count packed
sum = 0;
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
sum += packed.count();
}
......@@ -101,7 +101,7 @@ int main(int argc, char *argv[])
// Dummy addition
sum = 0;
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
forAll(unpacked, i)
{
......@@ -117,7 +117,7 @@ int main(int argc, char *argv[])
// Read stl
sum = 0;
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
for(unsigned int i = 0; i < stlVector.size(); i++)
{
......@@ -130,7 +130,7 @@ int main(int argc, char *argv[])
// Read unpacked
sum = 0;
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
forAll(unpacked, i)
{
......@@ -143,7 +143,7 @@ int main(int argc, char *argv[])
// Read packed
sum = 0;
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
forAll(packed, i)
{
......@@ -157,7 +157,7 @@ int main(int argc, char *argv[])
// Read packed
sum = 0;
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
forAll(packed, i)
{
......@@ -171,7 +171,7 @@ int main(int argc, char *argv[])
// Read via iterator
sum = 0;
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
for
(
......@@ -190,7 +190,7 @@ int main(int argc, char *argv[])
// Read via iterator
sum = 0;
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
for
(
......@@ -209,7 +209,7 @@ int main(int argc, char *argv[])
// Read empty hash
sum = 0;
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
forAll(unpacked, i)
{
......@@ -223,7 +223,7 @@ int main(int argc, char *argv[])
// Read full hash
sum = 0;
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
forAll(unpacked, i)
{
......@@ -240,7 +240,7 @@ int main(int argc, char *argv[])
//
// Write stl
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
for (unsigned int i = 0; i < stlVector.size(); i++)
{
......@@ -250,7 +250,7 @@ int main(int argc, char *argv[])
Info<< "Writing stl:" << timer.cpuTimeIncrement() << " s" << endl;
// Write unpacked
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
forAll(unpacked, i)
{
......@@ -261,7 +261,7 @@ int main(int argc, char *argv[])
// Write packed
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
forAll(packed, i)
{
......@@ -273,7 +273,7 @@ int main(int argc, char *argv[])
// Write packed
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
forAll(packed, i)
{
......@@ -283,25 +283,9 @@ int main(int argc, char *argv[])
Info<< "Writing packed using set:" << timer.cpuTimeIncrement()
<< " s" << endl;
// Write packed
for (label iter = 0; iter < nIters; iter++)
{
for
(
PackedBoolList::iterator it = packed.begin();
it != packed.end();
++it
)
{
it = 1;
}
}
Info<< "Writing packed using iterator:" << timer.cpuTimeIncrement()
<< " s" << endl;
// Write packed
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
for
(
......@@ -313,12 +297,12 @@ int main(int argc, char *argv[])
it() = 1;
}
}
Info<< "Writing packed using iteratorRef:" << timer.cpuTimeIncrement()
Info<< "Writing packed using iterator:" << timer.cpuTimeIncrement()
<< " s" << endl;
// Write packed
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
packed = 0;
}
......@@ -327,7 +311,7 @@ int main(int argc, char *argv[])
// Write packed
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
packed = 1;
}
......@@ -338,7 +322,7 @@ int main(int argc, char *argv[])
PackedList<3> oddPacked(n, 3);
// Write packed
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
packed = 0;
}
......@@ -347,14 +331,14 @@ int main(int argc, char *argv[])
// Write packed
for (label iter = 0; iter < nIters; iter++)
for (label iter = 0; iter < nIters; ++iter)
{
packed = 1;
}
Info<< "Writing packed<3> uniform 1:" << timer.cpuTimeIncrement()
<< " s" << endl;
Info << "End\n" << endl;
return 0;
......
......@@ -84,7 +84,7 @@ unsigned int Foam::PackedList<nBits>::count() const
if (size_)
{
// mask value for complete chunks
unsigned int mask = (0x1 << (nBits * packing())) - 1;
unsigned int mask = maskLower(packing());
unsigned int endIdx = size_ / packing();
unsigned int endOff = size_ % packing();
......@@ -99,7 +99,7 @@ unsigned int Foam::PackedList<nBits>::count() const
// count bits in partial chunk
if (endOff)
{
mask = (0x1 << (nBits * endOff)) - 1;
mask = maskLower(endOff);
register unsigned int bits = StorageList::operator[](endIdx) & mask;
COUNT_PACKEDBITS(c, bits);
......@@ -119,7 +119,7 @@ bool Foam::PackedList<nBits>::trim()
}
// mask value for complete chunks
unsigned int mask = (0x1 << (nBits * packing())) - 1;
unsigned int mask = maskLower(packing());
label currElem = packedLength(size_) - 1;
unsigned int endOff = size_ % packing();
......@@ -127,7 +127,7 @@ bool Foam::PackedList<nBits>::trim()
// clear trailing bits on final segment
if (endOff)
{
StorageList::operator[](currElem) &= ((0x1 << (nBits * endOff)) - 1);
StorageList::operator[](currElem) &= maskLower(endOff);
}
// test entire chunk
......@@ -176,7 +176,7 @@ Foam::labelList Foam::PackedList<nBits>::values() const
template<int nBits>
Foam::Ostream& Foam::PackedList<nBits>::const_iterator::print(Ostream& os) const
Foam::Ostream& Foam::PackedList<nBits>::iteratorBase::print(Ostream& os) const
{
os << "iterator<" << nBits << "> ["
<< (index_ * packing() + offset_) << "]"
......@@ -206,7 +206,7 @@ Foam::Ostream& Foam::PackedList<nBits>::print(Ostream& os) const
<< "storage: " << packLen << "/" << StorageList::size() << "( ";
// mask value for complete chunks
unsigned int mask = (0x1 << (nBits * packing())) - 1;
unsigned int mask = maskLower(packing());
for (label i=0; i < packLen; i++)
{
......@@ -219,7 +219,7 @@ Foam::Ostream& Foam::PackedList<nBits>::print(Ostream& os) const
if (endOff)
{
mask = (0x1 << (nBits * endOff)) - 1;
mask = maskLower(endOff);
}
else
{
......@@ -227,7 +227,7 @@ Foam::Ostream& Foam::PackedList<nBits>::print(Ostream& os) const
}
}
for (unsigned int testBit = 0x1 << max_bits(); testBit; testBit >>= 1)
for (unsigned int testBit = (1 << max_bits()); testBit; testBit >>= 1)
{
if (testBit & mask)
{
......
......@@ -35,21 +35,32 @@ Description
The number of bits per item is specified by the template parameter nBits.
Note
The iterator '()' dereferencing operator returns a proxy class that handles
assignment. However, the iterator itself can also handle assignment
directly, but does not return anything.
Thus the following bit of code works as expected:
In a const context, the '[]' operator simply returns the stored value,
with out-of-range elements returned as zero.
In a non-const context, the '[]' operator returns an iteratorBase, which
may not have a valid reference for out-of-range elements.
The iteratorBase class handles the assignment of new values.
Using the iteratorBase as a proxy allows assignment of values
between list elements. Thus the following bit of code works as expected:
@code
blist[5] = 4;
changed = blist.set(5, 8);
changed = (blist[5] = 1); // ERROR - operator= is 'void'
blist[1] = blist[5]; // value assignment, not iterator position
blist[2] = blist[5] = 4; // propagates value
blist[1] = blist[5] = blist[6]; // propagates value
@endcode
Making the assignment operator void prevents people from trying this type
of thing:
Using get() or the '[]' operator are similarly fast. Looping and reading
with an iterator is approx. 15% slower, but can be more flexible.
Using the set() operator (and the '[]' operator) are marginally slower
(approx. 5%) than using an iterator, but the set() method has an
advantage that it also returns a bool if the value changed. This can be
useful for branching on changed values.
@code
blist[2] = blist[5] = 4; // bad idea, thus ERROR - operator= is 'void'
blist[1] = blist[5]; // iterator not value assignment!
blist[5] = 4;
changed = blist.set(5, 8);
if (changed) ...
@endcode
SeeAlso
......@@ -91,7 +102,7 @@ TemplateName(PackedList);
Class PackedList Declaration
\*---------------------------------------------------------------------------*/
template <int nBits>
template <int nBits=1>
class PackedList
:
private List<unsigned int>
......@@ -127,9 +138,12 @@ public:
//- The number of entries per packed storage element
inline static unsigned int packing();
// Forward declaration of iterator and const_iterator
class iterator;
class const_iterator;
//- Masking for all bits below the offset
inline static unsigned int maskLower(unsigned offset);
// Forward declaration of iteratorBase
class iteratorBase;
// Constructors
......@@ -241,13 +255,13 @@ public:
inline unsigned int remove();
//- Get value at index I
// Does not auto-vivify elements.
// Does not auto-vivify entries.
inline unsigned int operator[](const label) const;
//- Set value at index I.
// Returns iterator to perform the actual operation.
// Auto-vivifies any new values to zero.
inline iterator operator[](const label);
// Does not auto-vivify entries.
inline iteratorBase operator[](const label);
//- Assignment of all entries to the given value. Takes linear time.
inline void operator=(const unsigned int val);
......@@ -263,11 +277,12 @@ public:
// // Write PackedList to Ostream.
// friend Ostream& operator<< <nBits> (Ostream&, const PackedList<nBits>&);
//- The const_iterator for PackedList
// Note: data and functions are protected, to allow reuse by iterator.
// Try not to be disturbed by non-const methods such as set(), they are
// just inherited and used by iterator.
class const_iterator
// Iterators and helpers
//- The iterator base for PackedList
// Note: data and functions are protected, to allow reuse by iterator
// and prevent most external usage.
class iteratorBase
{
friend class PackedList;
......@@ -275,125 +290,121 @@ public:
// Protected Data
//- Pointer to original list
// This also lets us use the default bitwise copy/assignment
PackedList* list_;
//- Pointer to original list
// This also lets us use the default bitwise copy/assignment
PackedList* list_;
//- Element index within storage
unsigned index_;
//- Element index within storage
unsigned index_;
//- Offset within storage element
unsigned offset_;
//- Offset within storage element
unsigned offset_;
// Protected Member Functions
//- Get value as unsigned
inline unsigned int get() const;
//- Get value as unsigned
inline unsigned int get() const;
//- Set value, returning true if changed
// This is obviously used by iterator and not by const_iterator
inline bool set(unsigned int);
//- Set value, returning true if changed
inline bool set(unsigned int);
public:
//- Increment to new position
inline void incr();
// Constructors
//- Decrement to new position
inline void decr();
//- Construct from base list and position index
inline const_iterator(const PackedList*, const label);
//- Move to new position, but not beyond end()
inline void seek(const iteratorBase&);
//- Construct from non-const iterator
explicit inline const_iterator(const iterator&);
// Member operators
// Constructors
inline bool operator==(const const_iterator&) const;
inline bool operator!=(const const_iterator&) const;
//- Construct null
inline iteratorBase();
//- Return referenced value directly
inline unsigned int operator*() const;
//- Copy construct
inline iteratorBase(const iteratorBase&);
//- Return referenced value directly
inline unsigned int operator()() const;
//- Construct from base list and position index
inline iteratorBase(const PackedList*, const label);
inline const_iterator& operator++();
inline const_iterator operator++(int);
public:
inline const_iterator& operator--();
inline const_iterator operator--(int);
// Member Functions
//- Conversion operator
inline operator unsigned int () const;
//- Return true if the element is within addressable range
inline bool valid() const;
//- Print value and information
Ostream& print(Ostream&) const;
};
//- Move iterator to end() if it would otherwise be out-of-range
// Returns true if the element was already ok
inline bool validate();
// Member Operators
//- const_iterator set to the beginning of the PackedList
inline const_iterator cbegin() const;
//- Compare positions
inline bool operator==(const iteratorBase&) const;
inline bool operator!=(const iteratorBase&) const;
//- const_iterator set to beyond the end of the PackedList
inline const_iterator cend() const;
//- Assign value, not position.
// This allows packed[0] = packed[3] for assigning values
inline unsigned int operator=(const iteratorBase&);
//- const_iterator set to the beginning of the PackedList
inline const_iterator begin() const;
//- Assign value
inline unsigned int operator=(const unsigned int val);
//- const_iterator set to beyond the end of the PackedList
inline const_iterator end() const;
//- Conversion operator
inline operator unsigned int () const;
//- Print value and information
Ostream& print(Ostream&) const;