From 35facb8208fde43986efe271ab4be903a42674de Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Wed, 1 Aug 2018 12:48:35 +0200
Subject: [PATCH] ENH: add PackedList::unpack() method

- allows for simpler unpacking of a full list, or list range into any
  sufficiently large integral type.

  For example,
    processorPolyPatch pp = ...;

    UOPstream toNbr(pp.neighbProcNo(), pBufs);
    toNbr << faceValues.unpack<char>(pp.range());
---
 .../test/PackedList/Test-PackedList.C         | 22 ++---
 .../test/PackedList1/Test-PackedList1.C       | 12 +++
 .../containers/Bits/PackedList/PackedList.C   | 93 ++++++++++++++++++-
 .../containers/Bits/PackedList/PackedList.H   | 16 ++++
 src/OpenFOAM/containers/Bits/bitSet/bitSet.H  |  6 +-
 .../meshes/polyMesh/syncTools/syncTools.H     | 16 ++--
 .../polyMesh/syncTools/syncToolsTemplates.C   | 16 ++--
 7 files changed, 148 insertions(+), 33 deletions(-)

diff --git a/applications/test/PackedList/Test-PackedList.C b/applications/test/PackedList/Test-PackedList.C
index f2ae2e923a2..35ad7f2dd8c 100644
--- a/applications/test/PackedList/Test-PackedList.C
+++ b/applications/test/PackedList/Test-PackedList.C
@@ -38,30 +38,30 @@ Description
 
 using namespace Foam;
 
-template<unsigned nBits>
+template<unsigned Width>
 inline void reportInfo()
 {
-    const unsigned offset = PackedList<nBits>::elem_per_block;
+    const unsigned offset = PackedList<Width>::elem_per_block;
 
-    unsigned useSHL = ((1u << (nBits * offset)) - 1);
-    unsigned useSHR = (~0u >> (sizeof(unsigned)*CHAR_BIT - nBits * offset));
+    unsigned useSHL = ((1u << (Width * offset)) - 1);
+    unsigned useSHR = (~0u >> (sizeof(unsigned)*CHAR_BIT - Width * offset));
 
     Info<< nl
-        << "PackedList<" << nBits << ">" << nl
-        << " max_value: " << PackedList<nBits>::max_value << nl
-        << " packing: " << PackedList<nBits>::elem_per_block << nl
-        << " utilization: " << (nBits * offset) << nl;
+        << "PackedList<" << Width << ">" << nl
+        << " max_value: " << PackedList<Width>::max_value << nl
+        << " packing: " << PackedList<Width>::elem_per_block << nl
+        << " utilization: " << (Width * offset) << nl;
 
     Info<< " Masking:" << nl
         << "  shift << "
-        << unsigned(nBits * offset) << nl
+        << unsigned(Width * offset) << nl
         << "  shift >> "
-        << unsigned((sizeof(unsigned)*CHAR_BIT) - nBits * offset)
+        << unsigned((sizeof(unsigned)*CHAR_BIT) - Width * offset)
         << nl;
 
     hex(Info);
     Info<< "   maskLower: "
-        << PackedList<nBits>::mask_lower(PackedList<nBits>::elem_per_block)
+        << PackedList<Width>::mask_lower(PackedList<Width>::elem_per_block)
         << nl
         << "      useSHL: " << useSHL << nl
         << "      useSHR: " << useSHR << nl;
diff --git a/applications/test/PackedList1/Test-PackedList1.C b/applications/test/PackedList1/Test-PackedList1.C
index b9e023baff3..81a212ddaa1 100644
--- a/applications/test/PackedList1/Test-PackedList1.C
+++ b/applications/test/PackedList1/Test-PackedList1.C
@@ -118,6 +118,18 @@ int main(int argc, char *argv[])
     list1.set(14, 2);
     report(list1);
 
+    Info<< "values()    : " << flatOutput(list1.unpack<char>()) << nl
+        << "values(5,8) : " << flatOutput(list1.unpack<char>(labelRange(5,8)))
+        << nl;
+
+    {
+        labelList locations({-5, -2, 2, 1, 8});
+
+        Info<< "values at " << flatOutput(locations) << " = "
+            << flatOutput(list1.unpack<char>(locations))
+            << nl;
+    }
+
     Info<< "\ntest operator== between references\n";
     if (list1[1] == list1[8])
     {
diff --git a/src/OpenFOAM/containers/Bits/PackedList/PackedList.C b/src/OpenFOAM/containers/Bits/PackedList/PackedList.C
index 9f636b2c413..79a7911ed7c 100644
--- a/src/OpenFOAM/containers/Bits/PackedList/PackedList.C
+++ b/src/OpenFOAM/containers/Bits/PackedList/PackedList.C
@@ -83,14 +83,34 @@ bool Foam::PackedList<Width>::uniform() const
 template<unsigned Width>
 Foam::labelList Foam::PackedList<Width>::values() const
 {
+    return this->unpack<label>();
+}
+
+
+template<unsigned Width>
+template<class IntType>
+Foam::List<IntType>
+Foam::PackedList<Width>::unpack() const
+{
+    static_assert
+    (
+        std::is_integral<IntType>::value,
+        "Integral required for output."
+    );
+    static_assert
+    (
+        std::numeric_limits<IntType>::digits >= Width,
+        "Width of IntType is too small to hold result"
+    );
+
     if (size() < 2 || uniform())
     {
-        const label val = (size() ? get(0) : 0);
+        const IntType val = (size() ? get(0) : 0);
 
-        return labelList(size(), val);
+        return List<IntType>(size(), val);
     }
 
-    labelList output(size());
+    List<IntType> output(size());
     label outi = 0;
 
     // Process n-1 complete blocks
@@ -102,7 +122,7 @@ Foam::labelList Foam::PackedList<Width>::values() const
 
         for (unsigned nget = elem_per_block; nget; --nget, ++outi)
         {
-            output[outi] = label(blockval & max_value);
+            output[outi] = IntType(blockval & max_value);
             blockval >>= Width;
         }
     }
@@ -117,4 +137,69 @@ Foam::labelList Foam::PackedList<Width>::values() const
 }
 
 
+template<unsigned Width>
+template<class IntType>
+Foam::List<IntType>
+Foam::PackedList<Width>::unpack(const labelRange& range) const
+{
+    static_assert
+    (
+        std::is_integral<IntType>::value,
+        "Integral required for unpack output."
+    );
+    static_assert
+    (
+        std::numeric_limits<IntType>::digits >= Width,
+        "Width of IntType is too small to hold unpack output."
+    );
+
+
+    // Could be more efficient but messier with block-wise access.
+    // - automatically handles any invalid positions
+
+    auto pos = range.start();
+
+    List<IntType> output(range.size());
+
+    for (IntType& out : output)
+    {
+        out = IntType(get(pos));
+        ++pos;
+    }
+
+    return output;
+}
+
+
+template<unsigned Width>
+template<class IntType>
+Foam::List<IntType>
+Foam::PackedList<Width>::unpack(const labelUList& locations) const
+{
+    static_assert
+    (
+        std::is_integral<IntType>::value,
+        "Integral required for unpack output."
+    );
+    static_assert
+    (
+        std::numeric_limits<IntType>::digits >= Width,
+        "Width of IntType is too small to hold unpack output."
+    );
+
+
+    label pos = 0;
+
+    List<IntType> output(locations.size());
+
+    for (IntType& out : output)
+    {
+        out = IntType(get(locations[pos]));
+        ++pos;
+    }
+
+    return output;
+}
+
+
 // ************************************************************************* //
diff --git a/src/OpenFOAM/containers/Bits/PackedList/PackedList.H b/src/OpenFOAM/containers/Bits/PackedList/PackedList.H
index 700ffb6db52..8a133069d6b 100644
--- a/src/OpenFOAM/containers/Bits/PackedList/PackedList.H
+++ b/src/OpenFOAM/containers/Bits/PackedList/PackedList.H
@@ -294,6 +294,22 @@ public:
         //- Return the values as a list of labels
         labelList values() const;
 
+        //- Return the values as a list of integral type.
+        //  The default integral type is unsigned int.
+        template<class IntType = unsigned int>
+        List<IntType> unpack() const;
+
+        //- Return the range of values as a list of integral type.
+        //  The default integral type is unsigned int.
+        template<class IntType = unsigned int>
+        List<IntType> unpack(const labelRange& range) const;
+
+        //- Extract the values for the specified locations as
+        //- a list of integral type.
+        //  The default integral type is unsigned int.
+        template<class IntType = unsigned int>
+        List<IntType> unpack(const labelUList& locations) const;
+
 
     // Edit
 
diff --git a/src/OpenFOAM/containers/Bits/bitSet/bitSet.H b/src/OpenFOAM/containers/Bits/bitSet/bitSet.H
index 9f033ca2976..2acade14166 100644
--- a/src/OpenFOAM/containers/Bits/bitSet/bitSet.H
+++ b/src/OpenFOAM/containers/Bits/bitSet/bitSet.H
@@ -248,6 +248,7 @@ public:
         inline labelList sortedToc() const;
 
         //- Return the bitset values as a boolList.
+        //  When the output is a bool, this is more efficient than unpack()
         List<bool> values() const;
 
 
@@ -522,17 +523,18 @@ public:
             return *this;
         }
 
+
     // Housekeeping
 
         //- Identical to toc()
-        //  \deprecated compatibility method for PackedBoolList (APR-2018)
+        //  \deprecated compatibility name for PackedBoolList (APR-2018)
         inline labelList used() const { return toc(); }
 
 };
 
 
 // Global Operators
-//
+
 Ostream& operator<<(Ostream& os, const InfoProxy<bitSet>& info);
 Ostream& operator<<(Ostream& os, const bitSet& bitset);
 
diff --git a/src/OpenFOAM/meshes/polyMesh/syncTools/syncTools.H b/src/OpenFOAM/meshes/polyMesh/syncTools/syncTools.H
index 6c19c323fbf..e81db709295 100644
--- a/src/OpenFOAM/meshes/polyMesh/syncTools/syncTools.H
+++ b/src/OpenFOAM/meshes/polyMesh/syncTools/syncTools.H
@@ -552,36 +552,36 @@ public:
 
         // PackedList versions
 
-            template<unsigned nBits, class CombineOp>
+            template<unsigned Width, class CombineOp>
             static void syncFaceList
             (
                 const polyMesh& mesh,
-                PackedList<nBits>& faceValues,
+                PackedList<Width>& faceValues,
                 const CombineOp& cop,
                 const bool parRun = Pstream::parRun()
             );
 
-            template<unsigned nBits>
+            template<unsigned Width>
             static void swapFaceList
             (
                 const polyMesh& mesh,
-                PackedList<nBits>& faceValues
+                PackedList<Width>& faceValues
             );
 
-            template<unsigned nBits, class CombineOp>
+            template<unsigned Width, class CombineOp>
             static void syncPointList
             (
                 const polyMesh& mesh,
-                PackedList<nBits>& pointValues,
+                PackedList<Width>& pointValues,
                 const CombineOp& cop,
                 const unsigned int nullValue
             );
 
-            template<unsigned nBits, class CombineOp>
+            template<unsigned Width, class CombineOp>
             static void syncEdgeList
             (
                 const polyMesh& mesh,
-                PackedList<nBits>& edgeValues,
+                PackedList<Width>& edgeValues,
                 const CombineOp& cop,
                 const unsigned int nullValue
             );
diff --git a/src/OpenFOAM/meshes/polyMesh/syncTools/syncToolsTemplates.C b/src/OpenFOAM/meshes/polyMesh/syncTools/syncToolsTemplates.C
index 4f5ad0b5c6d..66ffd62cb39 100644
--- a/src/OpenFOAM/meshes/polyMesh/syncTools/syncToolsTemplates.C
+++ b/src/OpenFOAM/meshes/polyMesh/syncTools/syncToolsTemplates.C
@@ -1413,11 +1413,11 @@ void Foam::syncTools::syncBoundaryFaceList
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-template<unsigned nBits, class CombineOp>
+template<unsigned Width, class CombineOp>
 void Foam::syncTools::syncFaceList
 (
     const polyMesh& mesh,
-    PackedList<nBits>& faceValues,
+    PackedList<Width>& faceValues,
     const CombineOp& cop,
     const bool parRun
 )
@@ -1564,22 +1564,22 @@ void Foam::syncTools::swapBoundaryCellList
 }
 
 
-template<unsigned nBits>
+template<unsigned Width>
 void Foam::syncTools::swapFaceList
 (
     const polyMesh& mesh,
-    PackedList<nBits>& faceValues
+    PackedList<Width>& faceValues
 )
 {
     syncFaceList(mesh, faceValues, eqOp<unsigned int>());
 }
 
 
-template<unsigned nBits, class CombineOp>
+template<unsigned Width, class CombineOp>
 void Foam::syncTools::syncPointList
 (
     const polyMesh& mesh,
-    PackedList<nBits>& pointValues,
+    PackedList<Width>& pointValues,
     const CombineOp& cop,
     const unsigned int nullValue
 )
@@ -1618,11 +1618,11 @@ void Foam::syncTools::syncPointList
 }
 
 
-template<unsigned nBits, class CombineOp>
+template<unsigned Width, class CombineOp>
 void Foam::syncTools::syncEdgeList
 (
     const polyMesh& mesh,
-    PackedList<nBits>& edgeValues,
+    PackedList<Width>& edgeValues,
     const CombineOp& cop,
     const unsigned int nullValue
 )
-- 
GitLab