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

PackedList: encapsulate calculations in an iterator

- eliminated previous PackedBitRef class, the iterator does all of that and
  can also be used to (forward) traverse the list
- no const_iterator yet

- Note that PackedList is also a bit like DynamicList in terms of storage
  management and the append() method. Since the underlying storage in
  integer, any auto-vivified elements will also flood-fill the gaps with
  zero.
parent 173607fd
......@@ -28,112 +28,144 @@ Description
\*---------------------------------------------------------------------------*/
#include "OSspecific.H"
#include "IOstreams.H"
#include "IStringStream.H"
#include "scalar.H"
#include "vector.H"
#include "ListOps.H"
#include "List.H"
#include "PackedBoolList.H"
#include <bitset>
using namespace Foam;
template <int nBits>
void printPackedList(const PackedList<nBits>& L)
{
const List<unsigned int>& stor = L.storage();
cout<< "PackedList<" << nBits << ">"
<< " max_bits:" << L.max_bits()
<< " max_value:" << L.max_value()
<< " packing:" << L.packing() << nl;
cout<< "values: " << L.size() << "/" << L.capacity() << " ( ";
forAll(L, i)
{
cout<< L[i] << ' ';
}
cout<< ")\n";
// using std:bitset for output works, but annoys valgrind
cout<< "storage: " << stor.size() << "( ";
forAll(stor, i)
{
cout<< std::bitset<32>(stor[i]) << ' ';
}
cout<< ")\n" << nl;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
cout<< "PackedList::max_bits() = " << PackedList<0>::max_bits() << nl;
{
bool changed;
Info<< "PackedList max_bits() = " << PackedList<0>::max_bits() << nl;
Info<< "\ntest allocation with value\n";
PackedList<3> list1(5,1);
list1.print(Info);
printPackedList(list1);
Info<< "\ntest assign uniform value\n";
list1 = 2;
printPackedList(list1);
list1.print(Info);
Info<< "\ntest resize with value (without reallocation)\n";
list1.resize(6, 3);
printPackedList(list1);
list1.print(Info);
Info<< "\ntest set() function\n";
list1.set(1, 5);
list1.print(Info);
Info<< "\ntest assign bool\n";
list1 = false;
printPackedList(list1);
list1.print(Info);
Info<< "\ntest assign bool\n";
list1 = true;
printPackedList(list1);
list1.print(Info);
Info<< "\ntest resize without value (with reallocation)\n";
list1.resize(12);
printPackedList(list1);
list1.print(Info);
Info<< "\ntest resize with value (with reallocation)\n";
list1.resize(25, list1.max_value());
printPackedList(list1);
list1.print(Info);
Info<< "\ntest resize smaller (should not touch allocation)\n";
list1.resize(8);
printPackedList(list1);
list1.print(Info);
Info<< "\ntest append() operation\n";
list1.append(2);
list1.append(3);
list1.append(4);
printPackedList(list1);
list1.print(Info);
Info<< "\ntest reserve() operation\n";
list1.reserve(32);
printPackedList(list1);
list1.print(Info);
Info<< "\ntest shrink() operation\n";
list1.shrink();
printPackedList(list1);
list1.print(Info);
list1.setSize(15);
printPackedList(list1);
Info<< "\ntest setCapacity() operation\n";
list1.setCapacity(15);
list1.print(Info);
list1.setSize(32);
printPackedList(list1);
Info<< "\ntest setCapacity() operation\n";
list1.setCapacity(30);
list1.print(Info);
// test assignment
Info<< "\ntest operator[] assignment\n";
list1[16] = 5;
printPackedList(list1);
list1.print(Info);
// auto-vivify
Info<< "\ntest operator[] assignment with auto-vivify\n";
list1[36] = list1.max_value();
printPackedList(list1);
list1.print(Info);
Info<< "\ntest setCapacity smaller\n";
list1.setCapacity(32);
list1.print(Info);
// add in some misc values
list1[31] = 1;
list1[32] = 2;
list1[33] = 3;
Info<< "\ntest iterator\n";
PackedList<3>::iterator iter = list1.begin();
Info<< "iterator:" << iter() << "\n";
iter.print(Info) << "\n";
Info<< "\ntest iterator operator=\n";
changed = (iter = 5);
Info<< "iterator:" << iter() << "\n";
Info<< "changed:" << changed << "\n";
changed = (iter = 5);
Info<< "changed:" << changed << "\n";
list1.print(Info);
Info<< "\ntest get() method\n";
Info<< "get(10):" << list1.get(10)
<< " and list[10]:" << unsigned(list1[10]) << "\n";
list1.print(Info);
list1.setSize(4);
printPackedList(list1);
Info<< "\ntest iterator indexing\n";
Info<< "end() ";
list1.end().print(Info) << "\n";
for (iter = list1[31]; iter != list1.end(); ++iter)
{
iter.print(Info);
}
Info<< "\ntest operator[] auto-vivify\n";
const unsigned int val = list1[45];
Info<< "list[45]:" << val << "\n";
list1.print(Info);
Info<< "\ntest copy constructor + append\n";
PackedList<3> list2(list1);
list2.append(4);
cout << "after copy + append\n";
printPackedList(list1);
printPackedList(list2);
Info<< "source list:\n";
list1.print(Info);
Info<< "destination list:\n";
list2.print(Info);
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();
list3.print(Info);
Info<< "\n\nDone.\n";
return 0;
}
......
......@@ -31,7 +31,7 @@ License
template<int nBits>
Foam::PackedList<nBits>::PackedList(const label size, const unsigned int val)
:
List<unsigned int>(storageSize(size)),
List<PackedStorage>(packedLength(size), 0u),
size_(size)
{
operator=(val);
......@@ -41,7 +41,7 @@ Foam::PackedList<nBits>::PackedList(const label size, const unsigned int val)
template<int nBits>
Foam::PackedList<nBits>::PackedList(const UList<label>& lst)
:
List<unsigned int>(storageSize(lst.size()), 0),
List<PackedStorage>(packedLength(lst.size()), 0u),
size_(lst.size())
{
forAll(lst, i)
......@@ -51,7 +51,6 @@ Foam::PackedList<nBits>::PackedList(const UList<label>& lst)
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<int nBits>
......@@ -67,13 +66,81 @@ Foam::labelList Foam::PackedList<nBits>::values() const
}
template<int nBits>
Foam::Ostream& Foam::PackedList<nBits>::iterator::print(Ostream& os) const
{
os << "iterator<" << nBits << "> [" << position() << "]"
<< " elem:" << elem_ << " offset:" << offset_
<< " value:" << unsigned(*this)
<< nl;
return os;
}
template<int nBits>
Foam::Ostream& Foam::PackedList<nBits>::print(Ostream& os) const
{
os << "PackedList<" << nBits << ">"
<< " max_value:" << max_value()
<< " packing:" << packing() << nl
<< "values: " << size() << "/" << capacity() << "( ";
forAll(*this, i)
{
os << get(i) << ' ';
}
os << ")\n"
<< "storage: " << storage().size() << "( ";
label count = size();
forAll(storage(), i)
{
const PackedStorage& rawBits = storage()[i];
// create mask for unaddressed bits
unsigned int addressed = 0;
for (unsigned packI = 0; count && packI < packing(); packI++, count--)
{
addressed <<= nBits;
addressed |= max_value();
}
for (unsigned int testBit = 0x1 << max_bits(); testBit; testBit >>= 1)
{
if (testBit & addressed)
{
if (rawBits & testBit)
{
os << '1';
}
else
{
os << '0';
}
}
else
{
os << '_';
}
}
cout << ' ';
}
os << ")\n";
return os;
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<int nBits>
void Foam::PackedList<nBits>::operator=(const PackedList<nBits>& lst)
{
setCapacity(lst.size());
List<unsigned int>::operator=(lst);
List<PackedStorage>::operator=(lst);
}
......
......@@ -40,7 +40,7 @@ SeeAlso
ToDo
Add checks for bad template parameters (ie, nBits=0, nBits too large).
Could make PackedBitRef an iterator and use for traversing as well.
The missing const_iterator might eventually still be needed.
SourceFiles
PackedListI.H
......@@ -52,7 +52,6 @@ SourceFiles
#define PackedList_H
#include "labelList.H"
#include "List.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -72,84 +71,6 @@ template<int nBits> class PackedList;
TemplateName(PackedList);
/*---------------------------------------------------------------------------*\
Class PackedBitRef Declaration
\*---------------------------------------------------------------------------*/
//- The PackedBitRef is used for PackedList
template <int nBits>
class PackedBitRef
{
private:
// private data
// const mutable List<unsigned int>& list_;
unsigned int& elem_;
const label startBit_;
public:
// Static Public Members
//- The max. number of bits that can be templated.
// Might someday be useful for a template assert.
inline static unsigned int max_bits();
//- The max. value for an entry, can also be used as the mask
// eg, ((1 << 2) - 1) yields 0b0011
inline static unsigned int max_value();
//- The number of entries per storage entry
inline static unsigned int packing();
// Constructors
inline PackedBitRef
(
// const List<unsigned int>& lst
const unsigned int& elem, label startBit)
:
// list_(lst),
elem_(const_cast<unsigned int&>(elem)),
startBit_(startBit)
{}
// Members
// Assign value
inline void operator=(const unsigned int val)
{
unsigned int shiftedMask = max_value() << startBit_;
unsigned int shiftedVal = (val & max_value()) << startBit_;
elem_ = (elem_ & ~shiftedMask) | shiftedVal;
}
// return value
inline unsigned int operator()() const
{
return ((elem_ >> startBit_) & max_value());
}
//- Conversion operator
inline operator unsigned int () const
{
return ((elem_ >> startBit_) & max_value());
}
//- Conversion operator
inline operator bool() const
{
return !!((elem_ >> startBit_) & max_value());
}
};
/*---------------------------------------------------------------------------*\
Class PackedList Declaration
\*---------------------------------------------------------------------------*/
......@@ -159,6 +80,8 @@ class PackedList
:
private List<unsigned int>
{
typedef unsigned int PackedStorage;
// Private data
//- Number of nBits entries
......@@ -166,16 +89,10 @@ class PackedList
// Private Member Functions
//- Calculate underlying list size
inline static label storageSize(const label);
//- Calculate element index and offset (start) bit within storage
inline static label location(const label, label& offset);
//- Check if value is representable in nBits
inline static void checkValue(const unsigned int);
//- Calculate the list length when packed
inline static label packedLength(const label);
//- Check index i is within valid range (0 ... size-1).
//- Check index I is within valid range [ 0 .. max_value() ]
inline void checkIndex(const label) const;
public:
......@@ -184,23 +101,18 @@ public:
//- The max. number of bits that can be templated.
// Might someday be useful for a template assert.
inline static unsigned int max_bits()
{
return PackedBitRef<nBits>::max_bits();
}
inline static unsigned int max_bits();
//- The max. value for an entry, can also be used as the mask
//- The max. value for an entry, which simultaneously the bit-mask
// eg, ((1 << 2) - 1) yields 0b0011
inline static unsigned int max_value()
{
return PackedBitRef<nBits>::max_value();
}
inline static unsigned int max_value();
//- The number of entries per packed storage element
inline static unsigned int packing();
//- The number of entries per storage entry
inline static unsigned int packing()
{
return PackedBitRef<nBits>::packing();
}
// Forward declaration of iterator
class iterator;
friend class iterator;
// Constructors
......@@ -208,7 +120,7 @@ public:
//- Null constructor
inline PackedList();
//- Construct with given size. Note: initializes list to 0.
//- Construct with given size, initializes list to 0.
inline PackedList(const label size);
//- Construct with given size and value for all elements.
......@@ -233,38 +145,41 @@ public:
//- The number of elements that can be stored before resizing
inline label capacity() const;
//- Number of packed elements.
//- Number of entries.
inline label size() const;
//- Return true if the list is empty (i.e., if size() == 0).
inline bool empty() const;
//- Get value at index I.
// Does not auto-vivifies elements.
inline unsigned int get(const label i) const;
// Does not auto-vivifies entries.
inline unsigned int get(const label) const;
//- Set value at index I. Return true if value changed.
// Does not auto-vivifies elements.
inline bool set(const label i, const unsigned int val);
// Does not auto-vivifies entries.
inline bool set(const label, const unsigned int val);
//- Underlying storage
//- Return the underlying packed storage
inline const List<unsigned int>& storage() const;
//- Return as labelList
//- Return the values as a labelList
labelList values() const;
//- Print values and information
Ostream& print(Ostream&) const;
// Edit
//- Alter the size of the underlying storage.
// The addressed size will be truncated if needed to fit, but will
// remain otherwise untouched.
// Use this or reserve() in combination with append().
inline void setCapacity(const label);
//- Reset size of List, optionally specify a value for new elements.
//- Reset addressable list size, does not shrink the allocated size.
// Optionally specify a value for new elements.
inline void resize(const label, const unsigned int& val = 0);
//- Reset size of List, optionally specify a value for new elements.
//- Alias for resize()
inline void setSize(const label, const unsigned int& val = 0);
//- Reserve allocation space for at least this size.
......@@ -272,8 +187,8 @@ public:
// Optionally provide an initialization value for new elements.
inline void reserve(const label, const unsigned int& val = 0);
//- Clear the list, i.e. set size to zero.
//- Does not adjust the underlying storage
//- Clear the list, i.e. set addressable size to zero.
// Does not adjust the underlying storage
inline void clear();
//- Clear the list and delete storage.
......@@ -282,7 +197,7 @@ public:
//- Shrink the allocated space to what is used.
inline void shrink();
//- Transfer the contents of the argument List into this List
//- Transfer the contents of the argument list into this list
// and annull the argument list.
inline void transfer(PackedList<nBits>&);
......@@ -291,17 +206,17 @@ public:
// Member operators
//- Append a value at the end of the list. Return true if value changed.
inline bool append(const unsigned int val);
//- Append a value at the end of the list
inline void append(const unsigned int val);
//- Get value at index I
// Does not auto-vivifies elements.
inline unsigned int operator[](const label i) const;
// Auto-vivifies any new values to zero.
inline unsigned int operator[](const label) const;
//- Set value at index I.
// Returns proxy to perform the actual operation.
// Auto-vivifies any new values to zero.
inline ::Foam::PackedBitRef<nBits> operator[](const label i);
inline iterator operator[](const label);
//- Assignment of all entries to the given value.
// Does set on all elements.
......@@ -318,6 +233,71 @@ public:
// // Write PackedList to Ostream.
// friend Ostream& operator<< <nBits> (Ostream&, const PackedList<nBits>&);
//- The iterator-like class used for PackedList
class iterator
{
friend class PackedList;
// Private Data
//- Reference to original list
PackedList& list_;
//- Element index within storage
unsigned elem_;
//- Offset within storage element
unsigned offset_;
//- Return the raw storage element
inline PackedStorage& chunk() const;
//- Return the position in the PackedList
inline label position() const;
public: