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

ENH: new bitSet class and improved PackedList class (closes #751)

- The bitSet class replaces the old PackedBoolList class.
  The redesign provides better block-wise access and reduced method
  calls. This helps both in cases where the bitSet may be relatively
  sparse, and in cases where advantage of contiguous operations can be
  made. This makes it easier to work with a bitSet as top-level object.

  In addition to the previously available count() method to determine
  if a bitSet is being used, now have simpler queries:

    - all()  - true if all bits in the addressable range are empty
    - any()  - true if any bits are set at all.
    - none() - true if no bits are set.

  These are faster than count() and allow early termination.

  The new test() method tests the value of a single bit position and
  returns a bool without any ambiguity caused by the return type
  (like the get() method), nor the const/non-const access (like
  operator[] has). The name corresponds to what std::bitset uses.

  The new find_first(), find_last(), find_next() methods provide a faster
  means of searching for bits that are set.

  This can be especially useful when using a bitSet to control an
  conditional:

  OLD (with macro):

      forAll(selected, celli)
      {
          if (selected[celli])
          {
              sumVol += mesh_.cellVolumes()[celli];
          }
      }

  NEW (with const_iterator):

      for (const label celli : selected)
      {
          sumVol += mesh_.cellVolumes()[celli];
      }

      or manually

      for
      (
          label celli = selected.find_first();
          celli != -1;
          celli = selected.find_next()
      )
      {
          sumVol += mesh_.cellVolumes()[celli];
      }

- When marking up contiguous parts of a bitset, an interval can be
  represented more efficiently as a labelRange of start/size.
  For example,

  OLD:

      if (isA<processorPolyPatch>(pp))
      {
          forAll(pp, i)
          {
              ignoreFaces.set(i);
          }
      }

  NEW:

      if (isA<processorPolyPatch>(pp))
      {
          ignoreFaces.set(pp.range());
      }
parent 2768500d
......@@ -122,7 +122,7 @@ int main(int argc, char *argv[])
fvc::makeAbsolute(phi, rho, U);
// Test : disable refinement for some cells
PackedBoolList& protectedCell =
bitSet& protectedCell =
refCast<dynamicRefineFvMesh>(mesh).protectedCell();
if (protectedCell.empty())
......
......@@ -2,8 +2,8 @@
interpolationCellPoint<vector> UInterpolator(HbyA);
// Determine faces on outside of interpolated cells
PackedBoolList isOwnerInterpolatedFace(mesh.nInternalFaces());
PackedBoolList isNeiInterpolatedFace(mesh.nInternalFaces());
bitSet isOwnerInterpolatedFace(mesh.nInternalFaces());
bitSet isNeiInterpolatedFace(mesh.nInternalFaces());
// Determine donor cells
labelListList donorCell(mesh.nInternalFaces());
......@@ -175,11 +175,11 @@ surfaceVectorField faceNormals(mesh.Sf()/mesh.magSf());
forAll(isNeiInterpolatedFace, faceI)
{
label cellId = -1;
if (isNeiInterpolatedFace[faceI])
if (isNeiInterpolatedFace.test(faceI))
{
cellId = mesh.faceNeighbour()[faceI];
}
else if (isOwnerInterpolatedFace[faceI])
else if (isOwnerInterpolatedFace.test(faceI))
{
cellId = mesh.faceOwner()[faceI];
}
......
......@@ -474,7 +474,7 @@ int main(int argc, char *argv[])
}
{
PackedBoolList select = HashSetOps::bitset(locations);
bitSet select = HashSetOps::bitset(locations);
auto output = ListOps::createWithValue<label>
(
30,
......@@ -482,8 +482,8 @@ int main(int argc, char *argv[])
100,
-1 // default value
);
Info<< "with PackedBoolList: " << flatOutput(output)
<< " selector: " << flatOutput(select.used()) << nl;
Info<< "with bitSet: " << flatOutput(output)
<< " selector: " << flatOutput(select.toc()) << nl;
}
{
......@@ -516,7 +516,7 @@ int main(int argc, char *argv[])
}
{
PackedBoolList select = HashSetOps::bitset(locations);
bitSet select = HashSetOps::bitset(locations);
auto output = ListOps::createWithValue<label>
(
30,
......@@ -524,7 +524,7 @@ int main(int argc, char *argv[])
100,
-1 // default value
);
Info<< "with PackedBoolList: " << flatOutput(output)
Info<< "with bitSet: " << flatOutput(output)
<< " selector: " << flatOutput(HashSetOps::used(select))
<< nl;
}
......
......@@ -145,7 +145,7 @@ int main(int argc, char *argv[])
Info<<"Test reorder - oldToNew:" << nl
<< flatOutput(oldToNew) << nl << nl;
PackedBoolList bitset
bitSet bitset
(
ListOps::createWithValue<bool>
(
......
......@@ -32,7 +32,7 @@ Description
#include "IOobject.H"
#include "IOstreams.H"
#include "IFstream.H"
#include "PackedBoolList.H"
#include "bitSet.H"
#include <climits>
......@@ -131,7 +131,7 @@ int main(int argc, char *argv[])
IFstream ifs(srcFile);
List<label> rawLst(ifs);
PackedBoolList packLst(rawLst);
bitSet packLst(rawLst);
Info<< "size: " << packLst.size() << nl;
......
......@@ -28,61 +28,100 @@ Description
\*---------------------------------------------------------------------------*/
#include "uLabel.H"
#include "labelRange.H"
#include "bitSet.H"
#include "FlatOutput.H"
#include "IOstreams.H"
#include "PackedBoolList.H"
using namespace Foam;
template<unsigned Width>
inline Ostream& report
(
const PackedList<Width>& list,
bool showBits = false,
bool debugOutput = false
)
{
Info<< list.info();
if (showBits)
{
list.printBits(Info, debugOutput) << nl;
}
return Info;
}
inline Ostream& report
(
const bitSet& bitset,
bool showBits = false,
bool debugOutput = false
)
{
Info<< bitset.info();
Info<< "all:" << bitset.all()
<< " any:" << bitset.any()
<< " none:" << bitset.none() << nl;
if (showBits)
{
bitset.printBits(Info, debugOutput) << nl;
}
return Info;
}
// BitOps::printBits((Info<< list1.info()), true) << nl;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
Info<< "PackedList max_bits() = " << PackedList<>::max_bits() << nl;
Info<< "\ntest allocation with value\n";
PackedList<3> list1(5,1);
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest assign uniform value\n";
list1 = 3;
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest assign uniform value (with overflow)\n";
list1 = -1;
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest zero\n";
list1 = 0;
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest set() with default argument (max_value)\n";
list1.set(1);
list1.set(3);
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest unset() with in-range and out-of-range\n";
list1.unset(3);
list1.unset(100000);
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest assign between references\n";
list1[2] = 3;
list1[4] = list1[2];
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest assign between references, with chaining\n";
list1[0] = 1;
list1[4] = 1;
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest assign between references, with chaining and auto-vivify\n";
list1[1] = 2;
list1[8] = 2;
list1[10] = 2;
list1[14] = 2;
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest operator== between references\n";
if (list1[1] == list1[8])
......@@ -106,7 +145,9 @@ int main(int argc, char *argv[])
{
const PackedList<3>& constLst = list1;
Info<< "\ntest operator[] const with out-of-range index\n";
constLst.printInfo(Info, true);
report(constLst);
if (constLst[20])
{
Info<< "[20] is true (unexpected)\n";
......@@ -116,7 +157,7 @@ int main(int argc, char *argv[])
Info<< "[20] is false (expected) list size should be unchanged "
<< "(const)\n";
}
constLst.printInfo(Info, true);
report(constLst);
Info<< "\ntest operator[] non-const with out-of-range index\n";
if (list1[20])
......@@ -128,7 +169,8 @@ int main(int argc, char *argv[])
Info<< "[20] is false (expected) but list was resized?? "
<< "(non-const)\n";
}
list1.printInfo(Info, true);
report(list1);
}
......@@ -137,94 +179,94 @@ int main(int argc, char *argv[])
{
Info<< "[20] is false, as expected\n";
}
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest resize with value (without reallocation)\n";
list1.resize(8, list1.max_value());
list1.printInfo(Info, true);
list1.resize(8, list1.max_value);
report(list1);
Info<< "\ntest flip() function\n";
list1.flip();
list1.printInfo(Info, true);
report(list1);
Info<< "\nre-flip()\n";
list1.flip();
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest set() function\n";
list1.set(1, 5);
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest assign bool\n";
list1 = false;
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest assign bool\n";
list1 = true;
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest resize without value (with reallocation)\n";
list1.resize(12);
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest resize with value (with reallocation)\n";
list1.resize(25, list1.max_value());
list1.printInfo(Info, true);
list1.resize(25, list1.max_value);
report(list1);
Info<< "\ntest resize smaller (should not touch allocation)\n";
list1.resize(8);
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest append() operation\n";
list1.append(2);
list1.append(3);
list1.append(4);
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest reserve() operation\n";
list1.reserve(32);
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest shrink() operation\n";
list1.shrink();
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest setCapacity() operation\n";
list1.setCapacity(15);
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest setCapacity() operation\n";
list1.setCapacity(100);
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest operator[] assignment\n";
list1[16] = 5;
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest operator[] assignment with auto-vivify\n";
list1[36] = list1.max_value();
list1.printInfo(Info, true);
list1[36] = list1.max_value;
report(list1);
Info<< "\ntest setCapacity smaller\n";
list1.setCapacity(24);
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest resize much smaller\n";
list1.resize(150);
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest trim\n";
list1.trim();
list1.printInfo(Info, true);
report(list1);
// add in some misc values
// Add in some misc values
list1[31] = 1;
list1[32] = 2;
list1[33] = 3;
Info<< "\ntest get() method\n";
Info<< "get(10):" << list1.get(10) << " and list[10]:" << list1[10] << "\n";
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest operator[] auto-vivify\n";
Info<< "size:" << list1.size() << "\n";
......@@ -234,33 +276,34 @@ int main(int argc, char *argv[])
Info<< "list[45]:" << val << "\n";
Info<< "size after read:" << list1.size() << "\n";
list1[45] = list1.max_value();
list1[45] = list1.max_value;
Info<< "size after write:" << list1.size() << "\n";
Info<< "list[45]:" << list1[45] << "\n";
list1[49] = list1[100];
list1.printInfo(Info, true);
report(list1);
Info<< "\ntest copy constructor + append\n";
PackedList<3> list2(list1);
list2.append(4);
Info<< "source list:\n";
list1.printInfo(Info, true);
report(list1);
Info<< "destination list:\n";
list2.printInfo(Info, true);
report(list2);
Info<< "\ntest pattern that fills all bits\n";
PackedList<4> list3(8, 8);
label pos = list3.size() - 1;
list3[pos--] = list3.max_value();
list3[pos--] = list3.max_value;
list3[pos--] = 0;
list3[pos--] = list3.max_value();
list3.printInfo(Info, true);
list3[pos--] = list3.max_value;
report(list3);
Info<< "removed final value: " << list3.remove() << endl;
list3.printInfo(Info, true);
report(list3);
Info<<"list: " << list3 << endl;
......@@ -289,18 +332,117 @@ int main(int argc, char *argv[])
}
PackedBoolList listb(list4);
bitSet listb(list4);
Info<< "copied from bool list " << endl;
listb.printInfo(Info, true);
// report(listb);
{
labelList indices = listb.used();
labelList indices = listb.toc();
Info<< "indices: " << indices << endl;
}
Info<< nl
<< "resizing: " << nl;
{
PackedList<1> list1(81, 1);
PackedList<3> list3(27, 5); // ie, 101
Info<< "initial" << nl; report(list1, true);
Info<< "initial" << nl; report(list3, true);
list1.resize(118, 1);
list3.resize(37, 3);
Info<< "extend with val" << nl; report(list1, true);
Info<< "extend with val" << nl; report(list3, true);
list1.resize(90, 0);
list3.resize(30, 4);
Info<< "contract with val" << nl; report(list1, true);
Info<< "contract with val" << nl; report(list3, true);
}
{
bitSet bits(45);
Info<< "bits" << nl; report(bits, true);
bits = true;
Info<< "bits" << nl; report(bits, true);
bits.unset(35);
Info<< "bits" << nl; report(bits, true);
bits.resize(39);
Info<< "bits" << nl; report(bits, true);
Info<< "values:" << flatOutput(bits.values()) << nl;
Info<< "used:" << flatOutput(bits.toc()) << nl;
bits.unset(labelRange(-15, 8));
Info<< "bits" << nl; report(bits, true);
bits.set(labelRange(-15, 100));
Info<< "bits" << nl; report(bits, true);
bits.set(labelRange(-15, 100));
Info<< "bits" << nl; report(bits, true);
bits.set(labelRange(150, 15));
Info<< "bits" << nl; report(bits, true);
bits.set(labelRange(0, 5));
Info<< "bits" << nl; report(bits, true);
bits.reset();
bits.resize(50);
Info<< "bits" << nl; report(bits, true);
bits.set(labelRange(4, 8));
Info<< "bits" << nl; report(bits, true);
bits.set(labelRange(30, 35));
Info<< "bits" << nl; report(bits, true);
bits.set(labelRange(80, 12));
Info<< "bits" << nl; report(bits, true);
bits.unset(labelRange(35, 16));
Info<< "bits" << nl; report(bits, true);
bits.unset(labelRange(0, 50));
bits.resize(100000);
bits.set(labelRange(30, 6));
bits[33] = false;
Info<<"used: " << flatOutput(bits.toc()) << endl;
Info<<"first: " << bits.find_first() << endl;
Info<<"next: " << bits.find_next(29) << endl;
Info<<"next: " << bits.find_next(30) << endl;
Info<<"next: " << bits.find_next(31) << endl;
Info<<"next: " << bits.find_next(31) << endl;
bits.set(labelRange(80, 10));
bits.resize(100);
Info<< "bits" << nl; report(bits, true);
bits.set(labelRange(125, 10));
Info<<"next: " << bits.find_next(64) << endl;
Info<<"used: " << flatOutput(bits.toc()) << endl;
for (const auto pos : bits)
{
Info<<"have: " << pos << nl;
}
}
Info<< "\n\nDone.\n";
return 0;
......
......@@ -29,7 +29,7 @@ Description
#include "argList.H"
#include "boolList.H"
#include "PackedBoolList.H"
#include "bitSet.H"
#include "HashSet.H"
#include "cpuTime.H"
#include <vector>
......@@ -63,7 +63,7 @@ int main(int argc, char *argv[])
unsigned long sum = 0;
PackedBoolList packed(n, 1);
bitSet packed(n, true);
boolList unpacked(n, true);
#ifdef TEST_STD_BOOLLIST
......
Test-PackedList3.C
EXE = $(FOAM_USER_APPBIN)/Test-PackedList3
Test-PackedList4.C
EXE = $(FOAM_USER_APPBIN)/Test-PackedList4
......@@ -218,7 +218,7 @@ int main(int argc, char *argv[])
labelList patchEdges;
labelList coupledEdges;
PackedBoolList sameEdgeOrientation;
bitSet sameEdgeOrientation;
PatchTools::matchEdges
(
pp,
......
Test-bitSet1.C
EXE = $(FOAM_USER_APPBIN)/Test-bitSet1
......@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2018 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
......@@ -22,50 +22,60 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Application
Test-bitSet1
Description
Test bitSet functionality
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "boolList.H"