PackedList changes

- added Mattijs' speed tests
- optimized resize() and assignment operators to avoid set() method
- add const_iterator and re-did the proxy handling.

Reading/writing by looping across iterators is still somewhat slow, but
might be acceptable.
This commit is contained in:
Mark Olesen
2009-01-26 00:33:28 +01:00
parent 42c04b8505
commit 84ec272d23
7 changed files with 774 additions and 160 deletions

View File

@ -46,11 +46,11 @@ int main(int argc, char *argv[])
list1.print(Info); list1.print(Info);
Info<< "\ntest assign uniform value\n"; Info<< "\ntest assign uniform value\n";
list1 = 2; list1 = 4;
list1.print(Info); list1.print(Info);
Info<< "\ntest resize with value (without reallocation)\n"; Info<< "\ntest resize with value (without reallocation)\n";
list1.resize(6, 3); list1.resize(8, list1.max_value());
list1.print(Info); list1.print(Info);
Info<< "\ntest set() function\n"; Info<< "\ntest set() function\n";
@ -96,7 +96,7 @@ int main(int argc, char *argv[])
list1.print(Info); list1.print(Info);
Info<< "\ntest setCapacity() operation\n"; Info<< "\ntest setCapacity() operation\n";
list1.setCapacity(30); list1.setCapacity(100);
list1.print(Info); list1.print(Info);
Info<< "\ntest operator[] assignment\n"; Info<< "\ntest operator[] assignment\n";
@ -108,7 +108,7 @@ int main(int argc, char *argv[])
list1.print(Info); list1.print(Info);
Info<< "\ntest setCapacity smaller\n"; Info<< "\ntest setCapacity smaller\n";
list1.setCapacity(32); list1.setCapacity(24);
list1.print(Info); list1.print(Info);
// add in some misc values // add in some misc values
@ -118,7 +118,7 @@ int main(int argc, char *argv[])
Info<< "\ntest iterator\n"; Info<< "\ntest iterator\n";
PackedList<3>::iterator iter = list1.begin(); PackedList<3>::iterator iter = list1.begin();
Info<< "iterator:" << iter() << "\n"; Info<< "begin():";
iter.print(Info) << "\n"; iter.print(Info) << "\n";
Info<< "\ntest iterator operator=\n"; Info<< "\ntest iterator operator=\n";
@ -131,23 +131,29 @@ int main(int argc, char *argv[])
list1.print(Info); list1.print(Info);
Info<< "\ntest get() method\n"; Info<< "\ntest get() method\n";
Info<< "get(10):" << list1.get(10) Info<< "get(10):" << list1.get(10) << " and list[10]:" << list1[10] << "\n";
<< " and list[10]:" << unsigned(list1[10]) << "\n";
list1.print(Info); list1.print(Info);
Info<< "\ntest iterator indexing\n"; Info<< "\ntest iterator indexing\n";
Info<< "end() "; Info<< "cend() ";
list1.end().print(Info) << "\n"; list1.cend().print(Info) << "\n";
for (iter = list1[31]; iter != list1.end(); ++iter) for
(
PackedList<3>::const_iterator cit = list1[30];
cit != list1.cend();
++cit)
{ {
iter.print(Info); cit.print(Info);
} }
Info<< "\ntest operator[] auto-vivify\n"; Info<< "\ntest operator[] auto-vivify\n";
const unsigned int val = list1[45]; const unsigned int val = list1[45];
Info<< "list[45]:" << val << "\n"; Info<< "list[45]:" << val << "\n";
list1[45] = list1.max_value();
Info<< "list[45]:" << list1[45] << "\n";
list1[49] = list1.max_value();
list1.print(Info); list1.print(Info);
@ -161,8 +167,15 @@ int main(int argc, char *argv[])
Info<< "\ntest pattern that fills all bits\n"; Info<< "\ntest pattern that fills all bits\n";
PackedList<4> list3(8, 8); PackedList<4> list3(8, 8);
list3[list3.size()-2] = 0;
list3[list3.size()-1] = list3.max_value(); label pos = list3.size() - 1;
list3[pos--] = list3.max_value();
list3[pos--] = 0;
list3[pos--] = list3.max_value();
list3.print(Info);
Info<< "removed final value: " << list3.remove() << endl;
list3.print(Info); list3.print(Info);
Info<< "\n\nDone.\n"; Info<< "\n\nDone.\n";

View File

@ -0,0 +1,3 @@
PackedListTest2.C
EXE = $(FOAM_USER_APPBIN)/PackedListTest2

View File

@ -0,0 +1,337 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Application
Description
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "boolList.H"
#include "PackedBoolList.H"
#include "HashSet.H"
#include "cpuTime.H"
#include <vector>
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
const label n = 1000000;
const label nIters = 1000;
unsigned int sum = 0;
PackedBoolList packed(n, 1);
boolList unpacked(n, true);
std::vector<bool> stlVector(n, true);
labelHashSet emptyHash;
labelHashSet fullHash;
for(label i = 0; i < n; i++)
{
fullHash.insert(i);
}
cpuTime timer;
for (label iter = 0; iter < nIters; iter++)
{
packed.resize(40);
packed.shrink();
packed.resize(n, 1);
}
Info<< "resize/shrink/resize:" << timer.cpuTimeIncrement() << " s\n\n";
// Dummy addition
sum = 0;
for (label iter = 0; iter < nIters; iter++)
{
forAll(unpacked, i)
{
sum += i + 1;
}
}
Info<< "Dummy loop:" << timer.cpuTimeIncrement() << " s" << endl;
Info<< " sum " << sum << endl;
//
// Read
//
// Read stl
sum = 0;
for (label iter = 0; iter < nIters; iter++)
{
for(unsigned int i = 0; i < stlVector.size(); i++)
{
sum += stlVector[i];
}
}
Info<< "Reading stl:" << timer.cpuTimeIncrement() << " s" << endl;
Info<< " sum " << sum << endl;
// Read unpacked
sum = 0;
for (label iter = 0; iter < nIters; iter++)
{
forAll(unpacked, i)
{
sum += unpacked[i];
}
}
Info<< "Reading unpacked:" << timer.cpuTimeIncrement() << " s" << endl;
Info<< " sum " << sum << endl;
// Read packed
sum = 0;
for (label iter = 0; iter < nIters; iter++)
{
forAll(packed, i)
{
sum += packed.get(i);
}
}
Info<< "Reading packed using get:" << timer.cpuTimeIncrement()
<< " s" << endl;
Info<< " sum " << sum << endl;
// Read packed
sum = 0;
for (label iter = 0; iter < nIters; iter++)
{
forAll(packed, i)
{
sum += packed[i];
}
}
Info<< "Reading packed using reference:" << timer.cpuTimeIncrement()
<< " s" << endl;
Info<< " sum " << sum << endl;
// Read via iterator
sum = 0;
for (label iter = 0; iter < nIters; iter++)
{
for
(
PackedBoolList::iterator it = packed.begin();
it != packed.end();
++it
)
{
sum += it;
}
}
Info<< "Reading packed using iterator:" << timer.cpuTimeIncrement()
<< " s" << endl;
Info<< " sum " << sum << endl;
// Read via iterator
sum = 0;
for (label iter = 0; iter < nIters; iter++)
{
for
(
PackedBoolList::const_iterator cit = packed.cbegin();
cit != packed.cend();
++cit
)
{
sum += cit();
}
}
Info<< "Reading packed using const_iterator():" << timer.cpuTimeIncrement()
<< " s" << endl;
Info<< " sum " << sum << endl;
// Read empty hash
sum = 0;
for (label iter = 0; iter < nIters; iter++)
{
forAll(packed, i)
{
sum += emptyHash.found(i);
}
}
Info<< "Reading empty labelHashSet:" << timer.cpuTimeIncrement()
<< " s" << endl;
Info<< " sum " << sum << endl;
// Read full hash
sum = 0;
for (label iter = 0; iter < nIters; iter++)
{
forAll(packed, i)
{
sum += fullHash.found(i);
}
}
Info<< "Reading full labelHashSet:" << timer.cpuTimeIncrement()
<< " s" << endl;
Info<< " sum " << sum << endl;
//
// Write
//
// Write stl
for (label iter = 0; iter < nIters; iter++)
{
for (unsigned int i = 0; i < stlVector.size(); i++)
{
stlVector[i] = true;
}
}
Info<< "Writing stl:" << timer.cpuTimeIncrement() << " s" << endl;
// Write unpacked
for (label iter = 0; iter < nIters; iter++)
{
forAll(unpacked, i)
{
unpacked[i] = true;
}
}
Info<< "Writing unpacked:" << timer.cpuTimeIncrement() << " s" << endl;
// Write packed
for (label iter = 0; iter < nIters; iter++)
{
forAll(packed, i)
{
packed[i] = 1;
}
}
Info<< "Writing packed using reference:" << timer.cpuTimeIncrement()
<< " s" << endl;
// Write packed
for (label iter = 0; iter < nIters; iter++)
{
forAll(packed, i)
{
packed.set(i, 1);
}
}
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
(
PackedBoolList::iterator it = packed.begin();
it != packed.end();
++it
)
{
it() = 1;
}
}
Info<< "Writing packed using iteratorRef:" << timer.cpuTimeIncrement()
<< " s" << endl;
// Write packed
for (label iter = 0; iter < nIters; iter++)
{
packed = 0;
}
Info<< "Writing packed uniform 0:" << timer.cpuTimeIncrement()
<< " s" << endl;
// Write packed
for (label iter = 0; iter < nIters; iter++)
{
packed = 1;
}
Info<< "Writing packed uniform 1:" << timer.cpuTimeIncrement()
<< " s" << endl;
PackedList<3> oddPacked(n, 3);
// Write packed
for (label iter = 0; iter < nIters; iter++)
{
packed = 0;
}
Info<< "Writing packed<3> uniform 0:" << timer.cpuTimeIncrement()
<< " s" << endl;
// Write packed
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;
}
// ************************************************************************* //

View File

@ -67,10 +67,11 @@ Foam::labelList Foam::PackedList<nBits>::values() const
template<int nBits> template<int nBits>
Foam::Ostream& Foam::PackedList<nBits>::iterator::print(Ostream& os) const Foam::Ostream& Foam::PackedList<nBits>::const_iterator::print(Ostream& os) const
{ {
os << "iterator<" << nBits << "> [" << position() << "]" os << "iterator<" << nBits << "> ["
<< " elem:" << elem_ << " offset:" << offset_ << (index_ * packing() + offset_) << "]"
<< " index:" << index_ << " offset:" << offset_
<< " value:" << unsigned(*this) << " value:" << unsigned(*this)
<< nl; << nl;
@ -90,27 +91,41 @@ Foam::Ostream& Foam::PackedList<nBits>::print(Ostream& os) const
os << get(i) << ' '; os << get(i) << ' ';
} }
label packLen = packedLength(size());
os << ")\n" os << ")\n"
<< "storage: " << storage().size() << "( "; << "storage: " << packLen << "/" << storage().size() << "( ";
label count = size(); // mask for the valid bits
unsigned int validBits = max_value();
for (unsigned int i = 1; i < packing(); ++i)
{
validBits |= (validBits << nBits);
}
forAll(storage(), i) for (label i=0; i < packLen; i++)
{ {
const PackedStorage& rawBits = storage()[i]; const PackedStorage& rawBits = storage()[i];
// create mask for unaddressed bits // the final storage may not be full, modify validBits accordingly
unsigned int addressed = 0; if (i+1 == packLen)
for (unsigned packI = 0; count && packI < packing(); packI++, count--)
{ {
addressed <<= nBits; label junk = size() % packing();
addressed |= max_value();
if (junk)
{
junk = packing() - junk;
}
for (label j=0; j < junk; j++)
{
validBits >>= nBits;
}
} }
for (unsigned int testBit = 0x1 << max_bits(); testBit; testBit >>= 1) for (unsigned int testBit = 0x1 << max_bits(); testBit; testBit >>= 1)
{ {
if (testBit & addressed) if (testBit & validBits)
{ {
if (rawBits & testBit) if (rawBits & testBit)
{ {
@ -123,7 +138,7 @@ Foam::Ostream& Foam::PackedList<nBits>::print(Ostream& os) const
} }
else else
{ {
os << '_'; os << '.';
} }
} }
cout << ' '; cout << ' ';
@ -156,7 +171,6 @@ void Foam::PackedList<nBits>::operator=(const UList<label>& lst)
} }
// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
//template<int nBits> //template<int nBits>

View File

@ -28,19 +28,31 @@ Class
Description Description
A Dynamically allocatable list of packed unsigned ints. A Dynamically allocatable list of packed unsigned ints.
Gets given the number of bits per item.
Note
The list resizing is similar to DynamicList, thus the methods clear() The list resizing is similar to DynamicList, thus the methods clear()
and setSize() behave like their DynamicList counterparts and the methods and setSize() behave like their DynamicList counterparts and the methods
reserve() and setCapacity() can be used to influence the allocation. reserve() and setCapacity() can be used to influence the allocation.
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 and also returns a bool as per the set() methods.
Thus the following bit of code works as expected:
@code
blist[5] = 4;
changed = (blist[5] = 10);
changed = blist.set(5, 8);
@endcode
Using set() might be more readable (as expected) though.
SeeAlso SeeAlso
Foam::DynamicList Foam::DynamicList
ToDo ToDo
Add checks for bad template parameters (ie, nBits=0, nBits too large). Checks for bad template parameters (ie, nBits=0, nBits too large)?
The missing const_iterator might eventually still be needed.
SourceFiles SourceFiles
PackedListI.H PackedListI.H
@ -110,10 +122,9 @@ public:
//- The number of entries per packed storage element //- The number of entries per packed storage element
inline static unsigned int packing(); inline static unsigned int packing();
// Forward declaration of iterator // Forward declaration of iterator and const_iterator
class iterator; class iterator;
friend class iterator; class const_iterator;
// Constructors // Constructors
@ -152,11 +163,11 @@ public:
inline bool empty() const; inline bool empty() const;
//- Get value at index I. //- Get value at index I.
// Does not auto-vivifies entries. // Does not auto-vivify entries.
inline unsigned int get(const label) const; inline unsigned int get(const label) const;
//- Set value at index I. Return true if value changed. //- Set value at index I. Return true if value changed.
// Does not auto-vivifies entries. // Does not auto-vivify entries.
inline bool set(const label, const unsigned int val); inline bool set(const label, const unsigned int val);
//- Return the underlying packed storage //- Return the underlying packed storage
@ -185,7 +196,7 @@ public:
//- Reserve allocation space for at least this size. //- Reserve allocation space for at least this size.
// Never shrinks the allocated size. // Never shrinks the allocated size.
// Optionally provide an initialization value for new elements. // Optionally provide an initialization value for new elements.
inline void reserve(const label, const unsigned int& val = 0); inline void reserve(const label);
//- Clear the list, i.e. set addressable size to zero. //- Clear the list, i.e. set addressable size to zero.
// Does not adjust the underlying storage // Does not adjust the underlying storage
@ -209,17 +220,19 @@ public:
//- Append a value at the end of the list //- Append a value at the end of the list
inline void append(const unsigned int val); inline void append(const unsigned int val);
//- Remove and return the last element
inline unsigned int remove();
//- Get value at index I //- Get value at index I
// Auto-vivifies any new values to zero. // Does not auto-vivify elements.
inline unsigned int operator[](const label) const; inline unsigned int operator[](const label) const;
//- Set value at index I. //- Set value at index I.
// Returns proxy to perform the actual operation. // Returns iterator to perform the actual operation.
// Auto-vivifies any new values to zero. // Auto-vivifies any new values to zero.
inline iterator operator[](const label); inline iterator operator[](const label);
//- Assignment of all entries to the given value. //- Assignment of all entries to the given value. Takes linear time.
// Does set on all elements.
inline void operator=(const unsigned int val); inline void operator=(const unsigned int val);
//- Assignment operator. Takes linear time. //- Assignment operator. Takes linear time.
@ -233,66 +246,136 @@ public:
// // Write PackedList to Ostream. // // Write PackedList to Ostream.
// friend Ostream& operator<< <nBits> (Ostream&, const PackedList<nBits>&); // friend Ostream& operator<< <nBits> (Ostream&, const PackedList<nBits>&);
//- The const_iterator for PackedList
//- The iterator-like class used for PackedList // Note: make data and functions protected, to allow reuse by iterator.
class iterator // Try not to be disturbed by non-const methods such as set(), they are
// just inherited by iterator.
class const_iterator
{ {
friend class PackedList; friend class PackedList;
// Private Data protected:
// Protected Data
//- Reference to original list //- Reference to original list
PackedList& list_; PackedList& list_;
//- Element index within storage //- Element index within storage
unsigned elem_; unsigned index_;
//- Offset within storage element //- Offset within storage element
unsigned offset_; unsigned offset_;
//- Return the raw storage element // Protected Member Functions
inline PackedStorage& chunk() const;
//- Return the position in the PackedList //- Get value as unsigned
inline label position() const; 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);
public: public:
// Constructors // Constructors
//- Construct from base list and position index //- Construct from base list and position index
inline iterator(const PackedList&, const label i); inline const_iterator(const PackedList&, const label);
// Members //- Construct from non-const iterator
explicit inline const_iterator(const iterator&);
//- Assign value, returns true if the value changed // Member operators
inline bool operator=(const unsigned int val);
inline bool operator==(const const_iterator&) const;
inline bool operator!=(const const_iterator&) const;
//- Return referenced value directly
inline unsigned int operator*() const;
//- Return referenced value directly
inline unsigned int operator()() const;
inline const_iterator& operator++();
inline const_iterator operator++(int);
//- Conversion operator //- Conversion operator
inline operator unsigned int () const; inline operator unsigned int () const;
//- Conversion operator
inline operator bool() const;
// Member operators
inline void operator=(const iterator&);
inline bool operator==(const iterator&) const;
inline bool operator!=(const iterator&) const;
//- Return referenced value
inline unsigned int operator()() const;
inline iterator& operator++();
inline iterator operator++(int);
//- Print value and information //- Print value and information
Ostream& print(Ostream&) const; Ostream& print(Ostream&) const;
}; };
//- iterator set to the begining of the PackedList //- const_iterator set to the beginning of the PackedList
inline const_iterator cbegin() const;
//- const_iterator set to beyond the end of the PackedList
inline const_iterator cend() const;
//- const_iterator set to the beginning of the PackedList
inline const_iterator begin() const;
//- const_iterator set to beyond the end of the PackedList
inline const_iterator end() const;
//- The iterator class used for PackedList
class iterator
:
public const_iterator
{
friend class PackedList;
//- A private proxy reference to the iterator, used for setting values
// Also provides a uniform target for the iterator 'operator*'
// and 'operator()' methods
class iteratorProxy
{
iterator* iter_;
public:
//- Construct from pointer to iterator
inline iteratorProxy(iterator*);
//- Assign value, returns true if the value changed
inline bool operator=(const unsigned int val);
//- Conversion operator
inline operator unsigned int () const;
};
public:
// Constructors
//- Construct from base list and position index
inline iterator(const PackedList&, const label);
// Member Operators
inline void operator=(const iterator&);
//- Assign value directly, returns true if the value changed
inline bool operator=(unsigned int);
//- Return value
inline unsigned int operator*() const;
//- Return value
inline unsigned int operator()() const;
//- Return proxy for assigning the referenced value
inline iteratorProxy operator*();
//- Return proxy for assigning the referenced value
inline iteratorProxy operator()();
inline iterator& operator++();
inline iterator operator++(int);
};
//- iterator set to the beginning of the PackedList
inline iterator begin(); inline iterator begin();
//- iterator set to beyond the end of the HashTable //- iterator set to beyond the end of the HashTable
@ -300,6 +383,7 @@ public:
}; };
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam } // End namespace Foam

View File

@ -26,27 +26,28 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "error.H" #include "error.H"
#include <climits>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<int nBits> template<int nBits>
inline unsigned int Foam::PackedList<nBits>::max_bits() inline unsigned int Foam::PackedList<nBits>::max_bits()
{ {
return sizeof(PackedStorage)*8 - 1; return sizeof(PackedStorage)*CHAR_BIT - 1;
} }
template<int nBits> template<int nBits>
inline unsigned int Foam::PackedList<nBits>::max_value() inline unsigned int Foam::PackedList<nBits>::max_value()
{ {
return ((1u << nBits) - 1); return (1u << nBits) - 1;
} }
template<int nBits> template<int nBits>
inline unsigned int Foam::PackedList<nBits>::packing() inline unsigned int Foam::PackedList<nBits>::packing()
{ {
return sizeof(PackedStorage)*8 / nBits; return sizeof(PackedStorage)*CHAR_BIT / nBits;
} }
@ -119,43 +120,66 @@ Foam::PackedList<nBits>::clone() const
// * * * * * * * * * * * * * * * * Iterators * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Iterators * * * * * * * * * * * * * * * * //
template<int nBits> template<int nBits>
inline Foam::PackedList<nBits>::iterator::iterator inline Foam::PackedList<nBits>::const_iterator::const_iterator
( (
const PackedList<nBits>& lst, const PackedList<nBits>& lst,
const label i const label i
) )
: :
list_(const_cast<PackedList<nBits>&>(lst)), list_(const_cast<PackedList<nBits>&>(lst)),
elem_(i / packing()), index_(i / packing()),
offset_(i % packing()) offset_(i % packing())
{} {}
template<int nBits>
inline Foam::PackedList<nBits>::iterator::iterator
(
const PackedList<nBits>& lst,
const label i
)
:
const_iterator(lst, i)
{}
template<int nBits>
inline Foam::PackedList<nBits>::const_iterator::const_iterator
(
const iterator& it
)
:
list_(it.list_),
index_(it.index_),
offset_(it.offset_)
{}
template<int nBits> template<int nBits>
inline void Foam::PackedList<nBits>::iterator::operator= inline void Foam::PackedList<nBits>::iterator::operator=
( (
const iterator& iter const iterator& it
) )
{ {
elem_ = iter.elem_; this->index_ = it.index_;
offset_ = iter.offset_; this->offset_ = it.offset_;
} }
template<int nBits> template<int nBits>
inline bool Foam::PackedList<nBits>::iterator::operator== inline bool Foam::PackedList<nBits>::const_iterator::operator==
( (
const iterator& iter const const_iterator& iter
) const ) const
{ {
return elem_ == iter.elem_ && offset_ == iter.offset_; return index_ == iter.index_ && offset_ == iter.offset_;
} }
template<int nBits> template<int nBits>
inline bool Foam::PackedList<nBits>::iterator::operator!= inline bool Foam::PackedList<nBits>::const_iterator::operator!=
( (
const iterator& iter const const_iterator& iter
) const ) const
{ {
return !(operator==(iter)); return !(operator==(iter));
@ -163,35 +187,40 @@ inline bool Foam::PackedList<nBits>::iterator::operator!=
template<int nBits> template<int nBits>
inline bool Foam::PackedList<nBits>::iterator::operator= inline unsigned int Foam::PackedList<nBits>::const_iterator::get() const
(
const unsigned int val
)
{ {
const unsigned int& stored = list_.List<PackedStorage>::operator[](index_);
return (stored >> (nBits * offset_)) & max_value();
}
template<int nBits>
inline bool Foam::PackedList<nBits>::const_iterator::set(const unsigned int val)
{
unsigned int& stored = list_.List<PackedStorage>::operator[](index_);
const unsigned int prev = stored;
const unsigned int startBit = nBits * offset_; const unsigned int startBit = nBits * offset_;
const unsigned int mask = max_value() << startBit; const unsigned int maskNew = max_value() << startBit;
unsigned int& stored = chunk(); stored = (stored & ~maskNew) | (maskNew & (val << startBit));
const unsigned int old = stored; return prev != stored;
stored &= ~mask;
stored |= (val << startBit) & mask;
return (old != stored);
} }
template<int nBits>
inline Foam::label Foam::PackedList<nBits>::iterator::position() const
{
return (elem_ * packing() + offset_);
}
template<int nBits> template<int nBits>
inline unsigned int& Foam::PackedList<nBits>::iterator::chunk() const inline typename Foam::PackedList<nBits>::const_iterator&
Foam::PackedList<nBits>::const_iterator::operator++()
{ {
return list_.List<PackedStorage>::operator[](elem_); offset_++;
if (offset_ >= packing())
{
offset_ = 0;
index_++;
}
return *this;
} }
@ -199,20 +228,27 @@ template<int nBits>
inline typename Foam::PackedList<nBits>::iterator& inline typename Foam::PackedList<nBits>::iterator&
Foam::PackedList<nBits>::iterator::operator++() Foam::PackedList<nBits>::iterator::operator++()
{ {
if (position() < list_.size()) this->offset_++;
if (this->offset_ >= packing())
{ {
offset_++; this->offset_ = 0;
if (offset_ >= packing()) this->index_++;
{
elem_++;
offset_ = 0;
}
} }
return *this; return *this;
} }
template<int nBits>
inline typename Foam::PackedList<nBits>::const_iterator
Foam::PackedList<nBits>::const_iterator::operator++(int)
{
const_iterator old = *this;
++*this;
return old;
}
template<int nBits> template<int nBits>
inline typename Foam::PackedList<nBits>::iterator inline typename Foam::PackedList<nBits>::iterator
Foam::PackedList<nBits>::iterator::operator++(int) Foam::PackedList<nBits>::iterator::operator++(int)
@ -225,25 +261,76 @@ Foam::PackedList<nBits>::iterator::operator++(int)
template<int nBits> template<int nBits>
inline unsigned int inline unsigned int
Foam::PackedList<nBits>::iterator::operator()() const Foam::PackedList<nBits>::const_iterator::operator*() const
{ {
return (chunk() >> (nBits * offset_)) & max_value(); return get();
} }
template<int nBits> template<int nBits>
inline Foam::PackedList<nBits>::iterator::operator inline unsigned int
Foam::PackedList<nBits>::const_iterator::operator()() const
{
return get();
}
template<int nBits>
inline typename Foam::PackedList<nBits>::iterator::iteratorProxy
Foam::PackedList<nBits>::iterator::operator*()
{
return iteratorProxy(this);
}
template<int nBits>
inline typename Foam::PackedList<nBits>::iterator::iteratorProxy
Foam::PackedList<nBits>::iterator::operator()()
{
return iteratorProxy(this);
}
template<int nBits>
inline bool Foam::PackedList<nBits>::iterator::operator=(const unsigned int val)
{
return set(val);
}
template<int nBits>
inline Foam::PackedList<nBits>::const_iterator::operator
unsigned int () const unsigned int () const
{ {
return (chunk() >> (nBits * offset_)) & max_value(); return get();
} }
template<int nBits> template<int nBits>
inline Foam::PackedList<nBits>::iterator::operator inline Foam::PackedList<nBits>::iterator::iteratorProxy::iteratorProxy
bool() const (
PackedList<nBits>::iterator* it
)
:
iter_(it)
{}
template<int nBits>
inline Foam::PackedList<nBits>::iterator::iteratorProxy::operator
unsigned int () const
{ {
return !!(chunk() >> (nBits * offset_)) & max_value(); return iter_->get();
}
template<int nBits>
inline bool Foam::PackedList<nBits>::iterator::iteratorProxy::operator=
(
const unsigned int val
)
{
return iter_->set(val);
} }
@ -255,6 +342,22 @@ Foam::PackedList<nBits>::begin()
} }
template<int nBits>
inline typename Foam::PackedList<nBits>::const_iterator
Foam::PackedList<nBits>::begin() const
{
return const_iterator(*this, 0);
}
template<int nBits>
inline typename Foam::PackedList<nBits>::const_iterator
Foam::PackedList<nBits>::cbegin() const
{
return const_iterator(*this, 0);
}
template<int nBits> template<int nBits>
inline typename Foam::PackedList<nBits>::iterator inline typename Foam::PackedList<nBits>::iterator
Foam::PackedList<nBits>::end() Foam::PackedList<nBits>::end()
@ -263,6 +366,22 @@ Foam::PackedList<nBits>::end()
} }
template<int nBits>
inline typename Foam::PackedList<nBits>::const_iterator
Foam::PackedList<nBits>::end() const
{
return iterator(*this, size());
}
template<int nBits>
inline typename Foam::PackedList<nBits>::const_iterator
Foam::PackedList<nBits>::cend() const
{
return iterator(*this, size());
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<int nBits> template<int nBits>
@ -286,7 +405,53 @@ inline void Foam::PackedList<nBits>::resize
const unsigned int& val const unsigned int& val
) )
{ {
reserve(nElem, val); reserve(nElem);
if (nElem > size_)
{
// fill new elements or newly exposed elements
if (size_)
{
// fill value for complete chunks
unsigned int fill = val & max_value();
for (unsigned int i = 1; i < packing(); ++i)
{
fill |= (fill << nBits);
}
unsigned begIdx = size_ / packing();
unsigned begOff = size_ % packing();
unsigned endIdx = nElem / packing();
// partial chunk, preserve existing value
if (begOff)
{
unsigned int maskOld = max_value();
for (unsigned int i = 1; i < begOff; ++i)
{
maskOld |= (maskOld << nBits);
}
List<PackedStorage>::operator[](begIdx) &= maskOld;
List<PackedStorage>::operator[](begIdx) |= ~maskOld & fill;
// continue with the next chunk
begIdx++;
}
// fill in complete elements
while (begIdx < endIdx)
{
List<PackedStorage>::operator[](begIdx++) = fill;
}
}
else
{
// no original size - simply flood-fill
operator=(val);
}
}
size_ = nElem; size_ = nElem;
} }
@ -315,34 +480,18 @@ inline void Foam::PackedList<nBits>::setCapacity(const label nElem)
{ {
List<PackedStorage>::setSize(packedLength(nElem), 0u); List<PackedStorage>::setSize(packedLength(nElem), 0u);
// truncates addressable section too // truncate addressed size too?
if (size_ > nElem) if (size_ > nElem)
{ {
# ifdef DEBUGList
// clear old values (purely cosmetics for string output)
for (label i = nElem; i < size_; i++)
{
set(i, 0);
}
# endif
size_ = nElem; size_ = nElem;
} }
else
{
// fill new elements
for (label i = size_; i < nElem; i++)
{
set(i, 0);
}
}
} }
template<int nBits> template<int nBits>
inline void Foam::PackedList<nBits>::reserve inline void Foam::PackedList<nBits>::reserve
( (
const label nElem, const label nElem
const unsigned int& val
) )
{ {
label len = packedLength(nElem); label len = packedLength(nElem);
@ -352,12 +501,6 @@ inline void Foam::PackedList<nBits>::reserve
{ {
List<PackedStorage>::setSize(len, 0); List<PackedStorage>::setSize(len, 0);
} }
// fill new elements
for (label i = size_; i < nElem; i++)
{
set(i, val);
}
} }
@ -421,22 +564,14 @@ inline unsigned int Foam::PackedList<nBits>::get(const label i) const
checkIndex(i); checkIndex(i);
# endif # endif
return iterator(*this, i)(); return const_iterator(*this, i).get();
} }
template<int nBits> template<int nBits>
inline unsigned int Foam::PackedList<nBits>::operator[](const label i) const inline unsigned int Foam::PackedList<nBits>::operator[](const label i) const
{ {
if (i >= size_) return const_iterator(*this, i).get();
{
setSize(i + 1);
return 0;
}
else
{
return iterator(*this, i)();
}
} }
@ -460,7 +595,7 @@ inline bool Foam::PackedList<nBits>::set
} }
# endif # endif
return (iterator(*this, i) = val); return iterator(*this, i).set(val);
} }
@ -475,32 +610,60 @@ inline void Foam::PackedList<nBits>::append(const unsigned int val)
} }
template<int nBits>
inline unsigned int Foam::PackedList<nBits>::remove()
{
label elemI = size_ - 1;
if (elemI < 0)
{
FatalErrorIn
(
"Foam::PackedList<nBits>::remove()"
) << "List is empty" << abort(FatalError);
}
const unsigned int val = const_iterator(*this, elemI).get();
resize(elemI);
return val;
}
template<int nBits> template<int nBits>
inline typename Foam::PackedList<nBits>::iterator inline typename Foam::PackedList<nBits>::iterator
Foam::PackedList<nBits>::operator[](const label i) Foam::PackedList<nBits>::operator[](const label i)
{ {
if (i >= size_) if (i >= size_)
{ {
setSize(i + 1); resize(i + 1);
} }
return iterator(*this, i); return iterator(*this, i);
} }
template<int nBits> template<int nBits>
inline void Foam::PackedList<nBits>::operator=(const unsigned int val) inline void Foam::PackedList<nBits>::operator=(const unsigned int val)
{ {
if (val) if (val)
{ {
forAll(*this, elemI) // specialization for nBits=1 isn't worth the bother
unsigned int fill = val & max_value();
for (unsigned int i = 1; i < packing(); ++i)
{ {
set(elemI, val); fill |= (fill << nBits);
} }
List<PackedStorage>::operator=(fill);
} }
else else
{ {
List<PackedStorage>::operator=(val); List<PackedStorage>::operator=(0u);
} }
} }