diff --git a/applications/test/PackedList1/PackedListTest1.C b/applications/test/PackedList1/PackedListTest1.C index 5e1902f382..461db54158 100644 --- a/applications/test/PackedList1/PackedListTest1.C +++ b/applications/test/PackedList1/PackedListTest1.C @@ -42,42 +42,42 @@ int main(int argc, char *argv[]) Info<< "\ntest allocation with value\n"; PackedList<3> list1(5,1); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest assign uniform value\n"; list1 = 3; - list1.print(Info); + list1.print(Info, true); Info<< "\ntest assign uniform value (with overflow)\n"; list1 = -1; - list1.print(Info); + list1.print(Info, true); Info<< "\ntest zero\n"; list1 = 0; - list1.print(Info); + list1.print(Info, true); Info<< "\ntest set() with default argument (max_value)\n"; list1.set(1); list1.set(3); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest unset() with in-range and out-of-range\n"; list1.unset(3); list1.unset(100000); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest assign between references\n"; list1[2] = 3; list1[4] = list1[2]; - list1.print(Info); + list1.print(Info, true); Info<< "\ntest assign between references, with chaining\n"; list1[0] = list1[4] = 1; - list1.print(Info); + list1.print(Info, true); Info<< "\ntest assign between references, with chaining and auto-vivify\n"; list1[1] = list1[8] = list1[10] = list1[14] = 2; - list1.print(Info); + list1.print(Info, true); Info<< "\ntest operator== between references\n"; @@ -126,7 +126,7 @@ int main(int argc, char *argv[]) { const PackedList<3>& constLst = list1; Info<< "\ntest operator[] const with out-of-range index\n"; - constLst.print(Info); + constLst.print(Info, true); if (constLst[20]) { Info<< "[20] is true (unexpected)\n"; @@ -136,7 +136,7 @@ int main(int argc, char *argv[]) Info<< "[20] is false (expected) list size should be unchanged " << "(const)\n"; } - constLst.print(Info); + constLst.print(Info, true); Info<< "\ntest operator[] non-const with out-of-range index\n"; if (list1[20]) @@ -148,7 +148,7 @@ int main(int argc, char *argv[]) Info<< "[20] is false (expected) but list was resized?? " << "(non-const)\n"; } - list1.print(Info); + list1.print(Info, true); } @@ -157,85 +157,85 @@ int main(int argc, char *argv[]) { Info<< "[20] is false, as expected\n"; } - list1.print(Info); + list1.print(Info, true); Info<< "\ntest resize with value (without reallocation)\n"; list1.resize(8, list1.max_value()); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest flip() function\n"; list1.flip(); - list1.print(Info); + list1.print(Info, true); Info<< "\nre-flip()\n"; list1.flip(); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest set() function\n"; list1.set(1, 5); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest assign bool\n"; list1 = false; - list1.print(Info); + list1.print(Info, true); Info<< "\ntest assign bool\n"; list1 = true; - list1.print(Info); + list1.print(Info, true); Info<< "\ntest resize without value (with reallocation)\n"; list1.resize(12); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest resize with value (with reallocation)\n"; list1.resize(25, list1.max_value()); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest resize smaller (should not touch allocation)\n"; list1.resize(8); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest append() operation\n"; list1.append(2); list1.append(3); list1.append(4); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest reserve() operation\n"; list1.reserve(32); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest shrink() operation\n"; list1.shrink(); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest setCapacity() operation\n"; list1.setCapacity(15); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest setCapacity() operation\n"; list1.setCapacity(100); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest operator[] assignment\n"; list1[16] = 5; - list1.print(Info); + list1.print(Info, true); Info<< "\ntest operator[] assignment with auto-vivify\n"; list1[36] = list1.max_value(); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest setCapacity smaller\n"; list1.setCapacity(24); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest resize much smaller\n"; list1.resize(150); - list1.print(Info); + list1.print(Info, true); Info<< "\ntest trim\n"; list1.trim(); - list1.print(Info); + list1.print(Info, true); // add in some misc values list1[31] = 1; @@ -250,7 +250,7 @@ int main(int argc, char *argv[]) Info<< "iterator:" << iter() << "\n"; iter() = 5; iter.print(Info); - list1.print(Info); + list1.print(Info, true); iter = list1[31]; Info<< "iterator:" << iter() << "\n"; @@ -259,7 +259,7 @@ int main(int argc, char *argv[]) Info<< "\ntest get() method\n"; Info<< "get(10):" << list1.get(10) << " and list[10]:" << list1[10] << "\n"; - list1.print(Info); + list1.print(Info, true); Info<< "\ntest iterator indexing\n"; Info<< "cend() "; @@ -267,7 +267,7 @@ int main(int argc, char *argv[]) { Info<< "\ntest assignment of iterator\n"; - list1.print(Info); + list1.print(Info, true); Info<< "cend()\n"; list1.end().print(Info); PackedList<3>::iterator cit = list1[100]; @@ -304,16 +304,16 @@ int main(int argc, char *argv[]) Info<< "size after write:" << list1.size() << "\n"; Info<< "list[45]:" << list1[45] << "\n"; list1[49] = list1[100]; - list1.print(Info); + list1.print(Info, true); Info<< "\ntest copy constructor + append\n"; PackedList<3> list2(list1); list2.append(4); Info<< "source list:\n"; - list1.print(Info); + list1.print(Info, true); Info<< "destination list:\n"; - list2.print(Info); + list2.print(Info, true); Info<< "\ntest pattern that fills all bits\n"; PackedList<4> list3(8, 8); @@ -323,10 +323,12 @@ int main(int argc, char *argv[]) list3[pos--] = list3.max_value(); list3[pos--] = 0; list3[pos--] = list3.max_value(); - list3.print(Info); + list3.print(Info, true); Info<< "removed final value: " << list3.remove() << endl; - list3.print(Info); + list3.print(Info, true); + + Info<<"list: " << list3 << endl; List list4(16, false); diff --git a/applications/test/PackedList3/PackedListTest3.C b/applications/test/PackedList3/PackedListTest3.C index 5ff6ee8644..7b27ffda09 100644 --- a/applications/test/PackedList3/PackedListTest3.C +++ b/applications/test/PackedList3/PackedListTest3.C @@ -33,7 +33,6 @@ Description #include "StaticHashTable.H" #include "cpuTime.H" #include -#include "PackedList.H" #include "PackedBoolList.H" using namespace Foam; @@ -57,7 +56,7 @@ int main(int argc, char *argv[]) { if ((i % nReport) == 0 && i) { - Info<< "i:" << i << " in " << timer.cpuTimeIncrement() << " s" + Info<< "i:" << i << " in " << timer.cpuTimeIncrement() << " s" <> list4; + + list4.print(Info, true); + Info<< list4 << " indices: " << list4.used()() <>(Istream& is, List& L) << exit(FatalIOError); } - // Putback the openning bracket + // Putback the opening bracket is.putBack(firstToken); // Now read as a singly-linked list diff --git a/src/OpenFOAM/containers/Lists/PackedList/PackedBoolList.C b/src/OpenFOAM/containers/Lists/PackedList/PackedBoolList.C index f393e144da..548d21414d 100644 --- a/src/OpenFOAM/containers/Lists/PackedList/PackedBoolList.C +++ b/src/OpenFOAM/containers/Lists/PackedList/PackedBoolList.C @@ -24,9 +24,51 @@ License \*---------------------------------------------------------------------------*/ #include "PackedBoolList.H" +#include "IOstreams.H" +#include + +// * * * * * * * * * * * * * * * Static Members * * * * * * * * * * * * * * * // + +// table-lookup instead of printf("%02x", char) +//! @cond localScope +static const char hexLookup[] = +{ + "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f" + "505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" +}; + + +// number of bytes required to pack nElem +static inline unsigned int packedBytes(const Foam::label nElem) +{ + return (nElem + CHAR_BIT - 1) / CHAR_BIT; +} +//! @endcond + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // +Foam::PackedBoolList::PackedBoolList(Istream &is) +: + PackedList<1>() +{ + is >> *this; +} + // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // @@ -232,6 +274,286 @@ Foam::PackedBoolList::operator^=(const PackedList<1>& lst) return *this; } +// * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * * // + +Foam::Istream& Foam::operator>> +( + Istream& istr, + PackedBoolList& lst +) +{ + // Takes into account that 'a' (or 'A') is 10 + static const label alphaOffset = toupper('A') - 10; + // Takes into account that '0' is 0 + static const label zeroOffset = int('0'); + + ISstream& is = dynamicCast(istr); + + lst.clear(); + is.fatalCheck("operator>>(Istream&, PackedBoolList&)"); + + token firstTok(is); + is.fatalCheck + ( + "operator>>(Istream&, PackedBoolList&) : reading first token" + ); + + if (firstTok.isLabel()) + { + const label sz = firstTok.labelToken(); + + // Set list length to that read + lst.resize(sz); + + // Read list contents as ASCII + + // Read beginning of contents + const char delimiter = is.readBeginList("PackedBoolList"); + + if (sz) + { + if (delimiter == token::BEGIN_LIST) + { + // number of bytes when packed: + unsigned int nBytes = packedBytes(lst.size()); + + for (label i=0, storeI=0; i < sz; ++storeI) + { + PackedList<1>::StorageType& stored = lst.storage()[storeI]; + + // byte-wise read + for + ( + unsigned byte=0; + byte < sizeof(PackedList<1>::StorageType); + ++byte + ) + { + PackedList<1>::StorageType result = 0; + char c = 0; + + // Get next non-whitespace character + while (is.get(c) && isspace(c)) + {} + + for (label nibble=0; nibble < 2; ++nibble) + { + if (!isxdigit(c)) + { + FatalIOErrorIn + ( + "operator>>(Istream&, PackedBoolList&) : " + "reading first token", + is + ) + << "Illegal hex digit: '" << c << "'" + << exit(FatalIOError); + } + + result <<= 4; + + if (isdigit(c)) + { + result += int(c) - zeroOffset; + } + else + { + result += toupper(c) - alphaOffset; + } + + // Get character for the lower part of the byte + if (!nibble) + { + is.get(c); + } + } + + stored |= result << (byte*CHAR_BIT); + + if (!--nBytes) + { + break; + } + } + i += PackedList<1>::packing(); + } + + // trim possible trailing junk + // mask off the final partial segment + { + const unsigned int off = sz % PackedList<1>::packing(); + if (off) + { + const unsigned int seg = sz / PackedList<1>::packing(); + + lst.storage()[seg] &= PackedList<1>::maskLower(off); + } + } + + + // skip over all trailing whitespace and zeroes + char c = 0; + while (is.get(c) && (isspace(c) || c == '0')) + {} + + // put back for later readEndList() to deal with + is.putback(c); + } + else + { + const label val = readLabel(is); + + is.fatalCheck + ( + "operator>>(Istream&, PackedBoolList&) : " + "reading the single entry" + ); + + lst = val; + } + } + + // Read end of contents + is.readEndList("PackedList"); + } + else if (firstTok.isPunctuation()) + { + if (firstTok.pToken() != token::BEGIN_LIST) + { + FatalIOErrorIn + ( + "operator>>(Istream&, PackedBoolList&)", + is + ) + << "incorrect first token, expected '(', found " + << firstTok.info() + << exit(FatalIOError); + } + + char c = '('; + + for (label storeI=0; c && c != ')'; ++storeI) + { + lst.resize((storeI+1)*PackedList<1>::packing()); + + PackedList<1>::StorageType& stored = lst.storage()[storeI]; + + // byte-wise read + for + ( + unsigned byte=0; + byte < sizeof(PackedList<1>::StorageType); + ++byte + ) + { + PackedList<1>::StorageType result = 0; + c = 0; + + // Get next non-whitespace character + while (is.get(c) && isspace(c)) + {} + + if (!c || c == ')') + { + break; + } + + for (label nibble=0; nibble < 2; ++nibble) + { + if (!isxdigit(c)) + { + FatalIOErrorIn + ( + "operator>>(Istream&, PackedBoolList&)", + is + ) + << "Illegal hex digit: '" << c << "'" + << exit(FatalIOError); + } + + result *= 16; + + if (isdigit(c)) + { + result += int(c) - zeroOffset; + } + else + { + result += toupper(c) - alphaOffset; + } + + // Get character for the lower part of the byte + if (!nibble) + { + is.get(c); + } + } + + stored |= result << (byte*CHAR_BIT); + } + } + + // put back for later readEndList() to deal with + is.putback(c); + + // Read end of contents + is.readEndList("PackedList"); + } + else + { + FatalIOErrorIn + ( + "operator>>(Istream&, PackedBoolList&)", + is + ) + << "incorrect first token, expected or '(', found " + << firstTok.info() + << exit(FatalIOError); + } + + return is; +} + + +Foam::Ostream& Foam::operator<< +( + Ostream& os, + const PackedBoolList& lst +) +{ + const label sz = lst.size(); + + unsigned int nBytes = packedBytes(sz); + + os << sz << token::BEGIN_LIST; + + for (label storeI=0; nBytes; ++storeI) + { + PackedList<1>::StorageType stored = lst.storage()[storeI]; + + for + ( + unsigned byte=0; + byte < sizeof(PackedList<1>::StorageType); + ++byte + ) + { + os << hexLookup[((stored & 0xFF) << 1)] + << hexLookup[((stored & 0xFF) << 1) + 1]; + + if (!--nBytes) + { + break; + } + stored >>= 8; + } + } + + os << token::END_LIST; + + return os; +} + // * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * * // diff --git a/src/OpenFOAM/containers/Lists/PackedList/PackedBoolList.H b/src/OpenFOAM/containers/Lists/PackedList/PackedBoolList.H index 1d2b19ac07..cf0ba7d6a5 100644 --- a/src/OpenFOAM/containers/Lists/PackedList/PackedBoolList.H +++ b/src/OpenFOAM/containers/Lists/PackedList/PackedBoolList.H @@ -27,6 +27,31 @@ Class Description A bit-packed bool list +Note + The input/output format differs from that of Foam::PackedBoolList in + that it is also packed. The input/output is always byte-wise, with + the lowest bytes first. + + Thus this label sequence + @code + 0 1 2 3 12 13 14 15 17 19 20 21 + @endcode + which has this bit representation: + @code + ..........111-1-1111--------1111 + @endcode + and this internal representation + @code + 0x003AF00F + @endcode + would be read/written in one of these formats: + @code + 22(0f f0 3a) + 22(0ff03a) + @endcode + Whitespace can be used to separate byte values, but must not appear + within a byte itself. + SourceFiles PackedBoolListI.H PackedBoolList.C @@ -47,6 +72,16 @@ SeeAlso namespace Foam { +// Forward declaration of classes +class Istream; +class Ostream; + +// Forward declaration of friend functions and operators +class PackedBoolList; +Istream& operator>>(Istream&, PackedBoolList&); +Ostream& operator<<(Ostream&, const PackedBoolList&); + + /*---------------------------------------------------------------------------*\ Class PackedBoolList Declaration \*---------------------------------------------------------------------------*/ @@ -55,7 +90,6 @@ class PackedBoolList : public PackedList<1> { - // Private Member Functions //- Modulo is everything that is not in lst @@ -72,7 +106,6 @@ class PackedBoolList template label unsetFromIndices(const LabelListType& indices); - public: // Constructors @@ -80,6 +113,9 @@ public: //- Construct null inline PackedBoolList(); + //- Construct from Istream + PackedBoolList(Istream&); + //- Construct with given size, initializes list to 0 explicit inline PackedBoolList(const label size); @@ -217,6 +253,10 @@ public: //- Remove entries from this list inline PackedBoolList& operator-=(const UIndirectList