Commit 84ec272d authored by Mark Olesen's avatar Mark Olesen
Browse files

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.
parent 42c04b85
......@@ -46,11 +46,11 @@ int main(int argc, char *argv[])
list1.print(Info);
Info<< "\ntest assign uniform value\n";
list1 = 2;
list1 = 4;
list1.print(Info);
Info<< "\ntest resize with value (without reallocation)\n";
list1.resize(6, 3);
list1.resize(8, list1.max_value());
list1.print(Info);
Info<< "\ntest set() function\n";
......@@ -96,7 +96,7 @@ int main(int argc, char *argv[])
list1.print(Info);
Info<< "\ntest setCapacity() operation\n";
list1.setCapacity(30);
list1.setCapacity(100);
list1.print(Info);
Info<< "\ntest operator[] assignment\n";
......@@ -108,7 +108,7 @@ int main(int argc, char *argv[])
list1.print(Info);
Info<< "\ntest setCapacity smaller\n";
list1.setCapacity(32);
list1.setCapacity(24);
list1.print(Info);
// add in some misc values
......@@ -118,7 +118,7 @@ int main(int argc, char *argv[])
Info<< "\ntest iterator\n";
PackedList<3>::iterator iter = list1.begin();
Info<< "iterator:" << iter() << "\n";
Info<< "begin():";
iter.print(Info) << "\n";
Info<< "\ntest iterator operator=\n";
......@@ -131,23 +131,29 @@ int main(int argc, char *argv[])
list1.print(Info);
Info<< "\ntest get() method\n";
Info<< "get(10):" << list1.get(10)
<< " and list[10]:" << unsigned(list1[10]) << "\n";
Info<< "get(10):" << list1.get(10) << " and list[10]:" << list1[10] << "\n";
list1.print(Info);
Info<< "\ntest iterator indexing\n";
Info<< "end() ";
list1.end().print(Info) << "\n";
for (iter = list1[31]; iter != list1.end(); ++iter)
Info<< "cend() ";
list1.cend().print(Info) << "\n";
for
(
PackedList<3>::const_iterator cit = list1[30];
cit != list1.cend();
++cit)
{
iter.print(Info);
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);
......@@ -161,8 +167,15 @@ int main(int argc, char *argv[])
Info<< "\ntest pattern that fills all bits\n";
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);
Info<< "\n\nDone.\n";
......
PackedListTest2.C
EXE = $(FOAM_USER_APPBIN)/PackedListTest2
/*---------------------------------------------------------------------------*\
========= |
\\ / 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;
}
// ************************************************************************* //
......@@ -67,10 +67,11 @@ Foam::labelList Foam::PackedList<nBits>::values() const
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() << "]"
<< " elem:" << elem_ << " offset:" << offset_
os << "iterator<" << nBits << "> ["
<< (index_ * packing() + offset_) << "]"
<< " index:" << index_ << " offset:" << offset_
<< " value:" << unsigned(*this)
<< nl;
......@@ -90,27 +91,41 @@ Foam::Ostream& Foam::PackedList<nBits>::print(Ostream& os) const
os << get(i) << ' ';
}
label packLen = packedLength(size());
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];
// create mask for unaddressed bits
unsigned int addressed = 0;
for (unsigned packI = 0; count && packI < packing(); packI++, count--)
// the final storage may not be full, modify validBits accordingly
if (i+1 == packLen)
{
addressed <<= nBits;
addressed |= max_value();
label junk = size() % packing();
if (junk)
{
junk = packing() - junk;
}
for (label j=0; j < junk; j++)
{
validBits >>= nBits;
}
}
for (unsigned int testBit = 0x1 << max_bits(); testBit; testBit >>= 1)
{
if (testBit & addressed)
if (testBit & validBits)
{
if (rawBits & testBit)
{
......@@ -123,7 +138,7 @@ Foam::Ostream& Foam::PackedList<nBits>::print(Ostream& os) const
}
else
{
os << '_';
os << '.';
}
}
cout << ' ';
......@@ -156,7 +171,6 @@ void Foam::PackedList<nBits>::operator=(const UList<label>& lst)
}
// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
//template<int nBits>
......
......@@ -28,19 +28,31 @@ Class
Description
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()
and setSize() behave like their DynamicList counterparts and the methods
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
Foam::DynamicList
ToDo
Add checks for bad template parameters (ie, nBits=0, nBits too large).
The missing const_iterator might eventually still be needed.
Checks for bad template parameters (ie, nBits=0, nBits too large)?
SourceFiles
PackedListI.H
......@@ -110,10 +122,9 @@ public:
//- The number of entries per packed storage element
inline static unsigned int packing();
// Forward declaration of iterator
// Forward declaration of iterator and const_iterator
class iterator;
friend class iterator;
class const_iterator;
// Constructors
......@@ -152,11 +163,11 @@ public:
inline bool empty() const;
//- Get value at index I.
// Does not auto-vivifies entries.
// Does not auto-vivify entries.
inline unsigned int get(const label) const;
//- 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);
//- Return the underlying packed storage
......@@ -185,7 +196,7 @@ public:
//- Reserve allocation space for at least this size.
// Never shrinks the allocated size.
// 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.
// Does not adjust the underlying storage
......@@ -209,17 +220,19 @@ public:
//- Append a value at the end of the list
inline void append(const unsigned int val);
//- Remove and return the last element
inline unsigned int remove();
//- Get value at index I
// Auto-vivifies any new values to zero.
// Does not auto-vivify elements.
inline unsigned int operator[](const label) const;
//- 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.
inline iterator operator[](const label);