From e3d9084c62ae46790d85b992254c4853cf0aeadd Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@Germany>
Date: Fri, 10 Feb 2017 09:55:37 +0100
Subject: [PATCH] ENH: support ASCII List output on a single-line

- Introduce writeList(Ostream&, label) method in various List classes to
  provide more flexibility and avoid hard-coded limits when deciding if a
  list is too long and should be broken up into multiple lines (ASCII only).

- The old hard-code limit (10) is retained in the operator<< versions

- This functionality is wrapped in the FlatOutput output adapter class
  and directly accessible via the 'flatOutput()' function.

Eg,
    #include "ListOps.H"
    Info<< "methods: " << flatOutput(myLongList) << endl;

    // OR

    Info<< "methods: ";
    myLongList.writeList(os) << endl;
---
 applications/test/List/Test-List.C            |  34 +++-
 .../test/PackedList4/Test-PackedList4.C       |  13 +-
 .../containers/Lists/FixedList/FixedList.H    |   5 +-
 .../containers/Lists/FixedList/FixedListIO.C  | 159 ++++++++++--------
 .../containers/Lists/ListOps/FlatOutput.H     |  96 +++++++++++
 .../containers/Lists/ListOps/ListOps.H        |   3 +-
 .../containers/Lists/PackedList/PackedList.C  |  28 ++-
 .../containers/Lists/PackedList/PackedList.H  |  42 +++--
 .../Lists/UIndirectList/UIndirectList.H       |  12 +-
 .../Lists/UIndirectList/UIndirectListIO.C     |  41 +++--
 src/OpenFOAM/containers/Lists/UList/UList.H   |   5 +-
 src/OpenFOAM/containers/Lists/UList/UListIO.C |  33 +++-
 12 files changed, 325 insertions(+), 146 deletions(-)
 create mode 100644 src/OpenFOAM/containers/Lists/ListOps/FlatOutput.H

diff --git a/applications/test/List/Test-List.C b/applications/test/List/Test-List.C
index fc8fab51780..bbba8219b32 100644
--- a/applications/test/List/Test-List.C
+++ b/applications/test/List/Test-List.C
@@ -40,7 +40,6 @@ See also
 #include "IStringStream.H"
 #include "scalar.H"
 #include "vector.H"
-#include "ListOps.H"
 
 #include "labelRange.H"
 #include "ListOps.H"
@@ -140,11 +139,36 @@ int main(int argc, char *argv[])
     Info<< "Elements " << map << " out of " << list3
         << " => " << subList3 << endl;
 
+    // test flattened output
+    {
+        Info<< nl;
+
+        labelList longLabelList = identity(15);
+
+        Info<< "labels (contiguous=" << contiguous<label>() << ")" << nl;
+
+        Info<< "normal: " << longLabelList << nl;
+        Info<< "flatOutput: " << flatOutput(longLabelList) << nl;
+        // Info<< "flatOutput(14): " << flatOutput(longLabelList, 14) << nl;
+        // Info<< "flatOutput(15): " << flatOutput(longLabelList, 15) << nl;
+
+        stringList longStringList(12);
+        forAll(longStringList, i)
+        {
+            longStringList[i].resize(3, 'a' + i);
+        }
+
+        Info<< "string (contiguous=" << contiguous<string>() << ")" << nl;
+
+        Info<< "normal: " << longStringList << nl;
+        Info<< "flatOutput: " << flatOutput(longStringList) << nl;
+        // contiguous longStringList[i].resize(3, 'a' + i);
+    }
+
     wordReList reLst;
     wordList wLst;
     stringList sLst;
 
-
     scalar xxx(-1);
 
     if (args.optionFound("flag"))
@@ -173,9 +197,9 @@ int main(int argc, char *argv[])
     }
 
     Info<< nl
-        << "-reList: " << reLst << nl
-        << "-wordList: " << wLst << nl
-        << "-stringList: " << sLst << endl;
+        << "-reList:     " << flatOutput(reLst) << nl
+        << "-wordList:   " << flatOutput(wLst)  << nl
+        << "-stringList: " << flatOutput(sLst)  << endl;
 
     return 0;
 }
diff --git a/applications/test/PackedList4/Test-PackedList4.C b/applications/test/PackedList4/Test-PackedList4.C
index 071d5b812e4..6d284a339bf 100644
--- a/applications/test/PackedList4/Test-PackedList4.C
+++ b/applications/test/PackedList4/Test-PackedList4.C
@@ -143,7 +143,7 @@ int main(int argc, char *argv[])
     Info<< "\ntest Istream constructor\n";
 
     list4.printInfo(Info, true);
-    Info<< list4 << " indices: " << list4.used()() <<endl;
+    Info<< list4 << " indices: " << list4.used()() << nl;
 
     Info<< "\nassign from labelList\n";
     list4 = labelList
@@ -155,7 +155,7 @@ int main(int argc, char *argv[])
     );
 
     list4.printInfo(Info, true);
-    Info<< list4 << " indices: " << list4.used()() <<endl;
+    Info<< list4 << " indices: " << list4.used()() << nl;
 
     Info<< "\nassign from indices\n";
     list4.read
@@ -168,7 +168,7 @@ int main(int argc, char *argv[])
 
 
     list4.printInfo(Info, true);
-    Info<< list4 << " indices: " << list4.used()() <<endl;
+    Info<< list4 << " indices: " << list4.used()() << nl;
 
     List<bool> boolLst(list4.size());
     forAll(list4, i)
@@ -176,8 +176,7 @@ int main(int argc, char *argv[])
         boolLst[i] = list4[i];
     }
 
-    Info<< "List<bool>: " << boolLst <<endl;
-
+    Info<< "List<bool>: " << boolLst << nl;
 
     // check roundabout assignments
     PackedList<2> pl2
@@ -188,7 +187,7 @@ int main(int argc, char *argv[])
         )()
     );
 
-    Info<< "roundabout assignment: " << pl2 << endl;
+    Info<< "roundabout assignment: " << pl2 << nl;
 
     list4.clear();
     forAll(pl2, i)
@@ -196,7 +195,7 @@ int main(int argc, char *argv[])
         list4[i] = pl2[i];
     }
 
-    list4.write(Info, true) << endl;
+    list4.writeList(Info, -1) << nl; // indexed output
 
     list4.writeEntry("PackedBoolList", Info);
 
diff --git a/src/OpenFOAM/containers/Lists/FixedList/FixedList.H b/src/OpenFOAM/containers/Lists/FixedList/FixedList.H
index 6e23dc70409..c969f4f4ad8 100644
--- a/src/OpenFOAM/containers/Lists/FixedList/FixedList.H
+++ b/src/OpenFOAM/containers/Lists/FixedList/FixedList.H
@@ -364,6 +364,9 @@ public:
         //- Write the List as a dictionary entry with keyword
         void writeEntry(const word& keyword, Ostream& os) const;
 
+        //- Write the List, with line-breaks in ASCII if the list length
+        //  exceeds shortListLen. Using '0' suppresses line-breaks entirely.
+        Ostream& writeList(Ostream& os, const label shortListLen=0) const;
 
 
     // IOstream operators
@@ -375,7 +378,7 @@ public:
             FixedList<T, Size>& L
         );
 
-        //- Write FixedList to Ostream
+        //- Write List to Ostream, as per writeList() with shortListLen=10
         friend Ostream& operator<< <T, Size>
         (
             Ostream& os,
diff --git a/src/OpenFOAM/containers/Lists/FixedList/FixedListIO.C b/src/OpenFOAM/containers/Lists/FixedList/FixedListIO.C
index 03a610af9f7..cac31770144 100644
--- a/src/OpenFOAM/containers/Lists/FixedList/FixedListIO.C
+++ b/src/OpenFOAM/containers/Lists/FixedList/FixedListIO.C
@@ -60,6 +60,92 @@ void Foam::FixedList<T, Size>::writeEntry
 }
 
 
+template<class T, unsigned Size>
+Foam::Ostream& Foam::FixedList<T, Size>::writeList
+(
+    Ostream& os,
+    const label shortListLen
+) const
+{
+    const FixedList<T, Size>& L = *this;
+
+    // Write list contents depending on data format
+    if (os.format() == IOstream::ASCII || !contiguous<T>())
+    {
+        // Can the contents be considered 'uniform' (ie, identical)?
+        bool uniform = (Size > 1 && contiguous<T>());
+        if (uniform)
+        {
+            forAll(L, i)
+            {
+                if (L[i] != L[0])
+                {
+                    uniform = false;
+                    break;
+                }
+            }
+        }
+
+        if (uniform)
+        {
+            // Write size (so it is valid dictionary entry) and start delimiter
+            os << Size << token::BEGIN_BLOCK;
+
+            // Write contents
+            os << L[0];
+
+            // Write end delimiter
+            os << token::END_BLOCK;
+        }
+        else if
+        (
+            Size <= 1 || !shortListLen
+         || (Size <= shortListLen && contiguous<T>())
+        )
+        {
+            // Write start delimiter
+            os << token::BEGIN_LIST;
+
+            // Write contents
+            forAll(L, i)
+            {
+                if (i) os << token::SPACE;
+                os << L[i];
+            }
+
+            // Write end delimiter
+            os << token::END_LIST;
+        }
+        else
+        {
+            // Write start delimiter
+            os << nl << token::BEGIN_LIST << nl;
+
+            // Write contents
+            forAll(L, i)
+            {
+                os << L[i] << nl;
+            }
+
+            // Write end delimiter
+            os << token::END_LIST << nl;
+        }
+    }
+    else
+    {
+        // Contents are binary and contiguous
+
+        // write(...) includes surrounding start/end delimiters
+        os.write(reinterpret_cast<const char*>(L.cdata()), Size*sizeof(T));
+    }
+
+    // Check state of IOstream
+    os.check("const FixedList::writeList(Ostream&)");
+
+    return os;
+}
+
+
 // * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
 
 template<class T, unsigned Size>
@@ -164,81 +250,10 @@ Foam::Istream& Foam::operator>>(Foam::Istream& is, FixedList<T, Size>& L)
 }
 
 
-// * * * * * * * * * * * * * * * Ostream Operator *  * * * * * * * * * * * * //
-
 template<class T, unsigned Size>
 Foam::Ostream& Foam::operator<<(Ostream& os, const FixedList<T, Size>& L)
 {
-    // Write list contents depending on data format
-    if (os.format() == IOstream::ASCII || !contiguous<T>())
-    {
-        // Can the contents be considered 'uniform' (ie, identical)?
-        bool uniform = (Size > 1 && contiguous<T>());
-        if (uniform)
-        {
-            forAll(L, i)
-            {
-                if (L[i] != L[0])
-                {
-                    uniform = false;
-                    break;
-                }
-            }
-        }
-
-        if (uniform)
-        {
-            // Write size (so it is valid dictionary entry) and start delimiter
-            os << L.size() << token::BEGIN_BLOCK;
-
-            // Write contents
-            os << L[0];
-
-            // Write end delimiter
-            os << token::END_BLOCK;
-        }
-        else if (Size <= 1 || (Size < 11 && contiguous<T>()))
-        {
-            // Write start delimiter
-            os << token::BEGIN_LIST;
-
-            // Write contents
-            forAll(L, i)
-            {
-                if (i) os << token::SPACE;
-                os << L[i];
-            }
-
-            // Write end delimiter
-            os << token::END_LIST;
-        }
-        else
-        {
-            // Write start delimiter
-            os << nl << token::BEGIN_LIST;
-
-            // Write contents
-            forAll(L, i)
-            {
-                os << nl << L[i];
-            }
-
-            // Write end delimiter
-            os << nl << token::END_LIST << nl;
-        }
-    }
-    else
-    {
-        // Contents are binary and contiguous
-
-        // write(...) includes surrounding start/end delimiters
-        os.write(reinterpret_cast<const char*>(L.cdata()), Size*sizeof(T));
-    }
-
-    // Check state of IOstream
-    os.check("Ostream& operator<<(Ostream&, const FixedList&)");
-
-    return os;
+    return L.writeList(os, 10);
 }
 
 
diff --git a/src/OpenFOAM/containers/Lists/ListOps/FlatOutput.H b/src/OpenFOAM/containers/Lists/ListOps/FlatOutput.H
new file mode 100644
index 00000000000..18e4b9c7f9b
--- /dev/null
+++ b/src/OpenFOAM/containers/Lists/ListOps/FlatOutput.H
@@ -0,0 +1,96 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 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 3 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, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::FlatOutput
+
+Description
+    Simple output adapter for list output on a single line.
+    The backend type must support a two-argument \c writeList() method.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef FlatOutput_H
+#define FlatOutput_H
+
+#include "Ostream.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of friend functions and operators
+template<class Container> class FlatOutput;
+template<class Container>
+Ostream& operator<<(Ostream& os, const FlatOutput<Container>& obj);
+
+
+/*---------------------------------------------------------------------------*\
+                         Class FlatOutput Declaration
+\*---------------------------------------------------------------------------*/
+
+template<class Container>
+class FlatOutput
+{
+    const Container& ref_;
+    const label len_;
+
+public:
+
+    //- Construct from components
+    inline FlatOutput(const Container& obj, label len)
+    :
+        ref_(obj),
+        len_(len)
+    {}
+
+    //- Ostream operator
+    inline friend Ostream& operator<<
+    (
+        Ostream& os,
+        const FlatOutput<Container>& wrapped
+    )
+    {
+        return wrapped.ref_.writeList(os, wrapped.len_);
+    }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+//- Global flatOutput function
+template<class Container>
+FlatOutput<Container> flatOutput(const Container& obj, label len=0)
+{
+    return FlatOutput<Container>(obj, len);
+}
+
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/containers/Lists/ListOps/ListOps.H b/src/OpenFOAM/containers/Lists/ListOps/ListOps.H
index 68a43ff8760..faacc501b40 100644
--- a/src/OpenFOAM/containers/Lists/ListOps/ListOps.H
+++ b/src/OpenFOAM/containers/Lists/ListOps/ListOps.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -36,6 +36,7 @@ SourceFiles
 #ifndef ListOps_H
 #define ListOps_H
 
+#include "FlatOutput.H"
 #include "labelList.H"
 #include "ops.H"
 
diff --git a/src/OpenFOAM/containers/Lists/PackedList/PackedList.C b/src/OpenFOAM/containers/Lists/PackedList/PackedList.C
index 095453d9c93..53889b02ad4 100644
--- a/src/OpenFOAM/containers/Lists/PackedList/PackedList.C
+++ b/src/OpenFOAM/containers/Lists/PackedList/PackedList.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -405,12 +405,13 @@ Foam::Istream& Foam::PackedList<nBits>::read(Istream& is)
 
 
 template<unsigned nBits>
-Foam::Ostream& Foam::PackedList<nBits>::write
+Foam::Ostream& Foam::PackedList<nBits>::writeList
 (
     Ostream& os,
-    const bool indexedOutput
+    const label shortListLen
 ) const
 {
+    const bool indexedOutput = (shortListLen < 0);
     const PackedList<nBits>& lst = *this;
     const label sz = lst.size();
 
@@ -456,36 +457,33 @@ Foam::Ostream& Foam::PackedList<nBits>::write
 
             os  << token::END_BLOCK << nl;
         }
-        else if (sz < 11)
+        else if (!shortListLen || sz <= shortListLen)
         {
-            // short list:
+            // Shorter list, or line-breaks suppressed
             os  << sz << token::BEGIN_LIST;
             forAll(lst, i)
             {
-                if (i)
-                {
-                    os  << token::SPACE;
-                }
+                if (i) os << token::SPACE;
                 os  << lst[i];
             }
             os  << token::END_LIST;
         }
         else
         {
-            // longer list:
-            os  << nl << sz << nl << token::BEGIN_LIST;
+            // Longer list
+            os << nl << sz << nl << token::BEGIN_LIST << nl;
             forAll(lst, i)
             {
-                os  << nl << lst[i];
+                os << lst[i] << nl;
             }
-            os  << nl << token::END_LIST << nl;
+            os << token::END_LIST << nl;
         }
     }
     else
     {
         // Contents are binary and contiguous
-
         os  << nl << sz << nl;
+
         if (sz)
         {
             // write(...) includes surrounding start/end delimiters
@@ -562,7 +560,7 @@ Foam::Istream& Foam::operator>>(Istream& is, PackedList<nBits>& lst)
 template<unsigned nBits>
 Foam::Ostream& Foam::operator<<(Ostream& os, const PackedList<nBits>& lst)
 {
-    return lst.write(os, false);
+    return lst.writeList(os, 10);
 }
 
 
diff --git a/src/OpenFOAM/containers/Lists/PackedList/PackedList.H b/src/OpenFOAM/containers/Lists/PackedList/PackedList.H
index 1d04851e4c7..c07bb1eab11 100644
--- a/src/OpenFOAM/containers/Lists/PackedList/PackedList.H
+++ b/src/OpenFOAM/containers/Lists/PackedList/PackedList.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -232,19 +232,19 @@ public:
         inline PackedList(const label size, const unsigned val);
 
         //- Construct from Istream
-        inline PackedList(Istream&);
+        inline PackedList(Istream& is);
 
         //- Copy constructor
-        inline PackedList(const PackedList<nBits>&);
+        inline PackedList(const PackedList<nBits>& lst);
 
         //- Construct by transferring the parameter contents
-        inline PackedList(const Xfer<PackedList<nBits>>&);
+        inline PackedList(const Xfer<PackedList<nBits>>& lst);
 
         //- Construct from a list of labels
-        explicit inline PackedList(const labelUList&);
+        explicit inline PackedList(const labelUList& lst);
 
         //- Construct from an indirect list of labels
-        explicit inline PackedList(const UIndirectList<label>&);
+        explicit inline PackedList(const UIndirectList<label>& lst);
 
         //- Clone
         inline autoPtr<PackedList<nBits>> clone() const;
@@ -265,16 +265,16 @@ public:
 
             //- Get value at index I.
             //  Never auto-vivify entries.
-            inline unsigned int get(const label) const;
+            inline unsigned int get(const label i) const;
 
             //- Set value at index I. Return true if value changed.
             //  Does auto-vivify for non-existent entries.
             //  Default value set is the max_value.
-            inline bool set(const label, const unsigned int val = ~0u);
+            inline bool set(const label i, const unsigned int val = ~0u);
 
             //- Unset the entry at index I. Return true if value changed.
             //  Never auto-vivify entries.
-            inline bool unset(const label);
+            inline bool unset(const label i);
 
             //- Return the underlying packed storage
             //  Manipulate with utmost caution
@@ -364,7 +364,10 @@ public:
             //- Clear list and read from stream
             Istream& read(Istream& is);
 
-            //- Write, optionally with indexedOutput
+            //- Write the List, with line-breaks in ASCII if the list length
+            //  exceeds shortListLen. Using '0' suppresses line-breaks entirely.
+            //  A special indexed output (ASCII only) is triggered by specifying
+            //  a negative value for shortListLen.
             //
             // The indexed output may be convenient in some situations.
             // The general format is a group of index/value pairs:
@@ -376,14 +379,7 @@ public:
             // \verbatim
             //     { index1 index2 index3 }
             // \endverbatim
-            //
-            // Note the indexed output is only supported for ASCII streams.
-            Ostream& write
-            (
-                Ostream& os,
-                const bool indexedOutput=false
-            ) const;
-
+            Ostream& writeList(Ostream& os, const label shortListLen=0) const;
 
             //- Write as a dictionary entry with keyword
             void writeEntry(const word& keyword, Ostream& os) const;
@@ -399,24 +395,24 @@ public:
 
             //- Get value at index I
             //  Never auto-vivify entries.
-            inline unsigned int operator[](const label) const;
+            inline unsigned int operator[](const label i) const;
 
             //- Set value at index I.
             //  Returns iterator to perform the actual operation.
             //  Does not auto-vivify entries, but will when assigned to.
-            inline iteratorBase operator[](const label);
+            inline iteratorBase operator[](const label i);
 
             //- Assignment of all entries to the given value. Takes linear time.
             inline void operator=(const unsigned int val);
 
             //- Assignment operator.
-            void operator=(const PackedList<nBits>&);
+            void operator=(const PackedList<nBits>& lst);
 
             //- Assignment operator.
-            void operator=(const labelUList&);
+            void operator=(const labelUList& lst);
 
             //- Assignment operator.
-            void operator=(const UIndirectList<label>&);
+            void operator=(const UIndirectList<label>& lst);
 
 
     // Iterators and helpers
diff --git a/src/OpenFOAM/containers/Lists/UIndirectList/UIndirectList.H b/src/OpenFOAM/containers/Lists/UIndirectList/UIndirectList.H
index 377e6725024..e39d899f899 100644
--- a/src/OpenFOAM/containers/Lists/UIndirectList/UIndirectList.H
+++ b/src/OpenFOAM/containers/Lists/UIndirectList/UIndirectList.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -148,9 +148,17 @@ public:
         typedef label size_type;
 
 
+    // Writing
+
+        //- Write the List, with line-breaks in ASCII if the list length
+        //  exceeds shortListLen. Using '0' suppresses line-breaks entirely.
+        //  Binary output is currently still a bit of an annoyance.
+        Ostream& writeList(Ostream& os, const label shortListLen=0) const;
+
+
     // Ostream operator
 
-        //- Write List to Ostream, as per write() method with shortListLen=10
+        //- Write List to Ostream, as per writeList() with shortListLen=10
         friend Ostream& operator<< <T>
         (
             Ostream& os,
diff --git a/src/OpenFOAM/containers/Lists/UIndirectList/UIndirectListIO.C b/src/OpenFOAM/containers/Lists/UIndirectList/UIndirectListIO.C
index 3b52f8484cb..f6a82069c20 100644
--- a/src/OpenFOAM/containers/Lists/UIndirectList/UIndirectListIO.C
+++ b/src/OpenFOAM/containers/Lists/UIndirectList/UIndirectListIO.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2014 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,15 +28,17 @@ License
 #include "token.H"
 #include "contiguous.H"
 
-// * * * * * * * * * * * * * * * Ostream Operator *  * * * * * * * * * * * * //
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
 
 template<class T>
-Foam::Ostream& Foam::operator<<
+Foam::Ostream& Foam::UIndirectList<T>::writeList
 (
-    Foam::Ostream& os,
-    const Foam::UIndirectList<T>& L
-)
+    Ostream& os,
+    const label shortListLen
+) const
 {
+    const UIndirectList<T>& L = *this;
+
     // Write list contents depending on data format
     if (os.format() == IOstream::ASCII || !contiguous<T>())
     {
@@ -65,7 +67,11 @@ Foam::Ostream& Foam::operator<<
             // Write end delimiter
             os << token::END_BLOCK;
         }
-        else if (L.size() <= 1 || (L.size() < 11 && contiguous<T>()))
+        else if
+        (
+            L.size() <= 1 || !shortListLen
+         || (L.size() <= shortListLen && contiguous<T>())
+        )
         {
             // Write size and start delimiter
             os << L.size() << token::BEGIN_LIST;
@@ -83,16 +89,16 @@ Foam::Ostream& Foam::operator<<
         else
         {
             // Write size and start delimiter
-            os << nl << L.size() << nl << token::BEGIN_LIST;
+            os << nl << L.size() << nl << token::BEGIN_LIST << nl;
 
             // Write contents
             forAll(L, i)
             {
-                os << nl << L[i];
+                os << L[i] << nl;
             }
 
             // Write end delimiter
-            os << nl << token::END_LIST << nl;
+            os << token::END_LIST << nl;
         }
     }
     else
@@ -115,10 +121,23 @@ Foam::Ostream& Foam::operator<<
     }
 
     // Check state of IOstream
-    os.check("Ostream& operator<<(Ostream&, const UIndirectList&)");
+    os.check("UIndirectList::writeList(Ostream&)");
 
     return os;
 }
 
 
+// * * * * * * * * * * * * * * * Ostream Operator *  * * * * * * * * * * * * //
+
+template<class T>
+Foam::Ostream& Foam::operator<<
+(
+    Foam::Ostream& os,
+    const Foam::UIndirectList<T>& L
+)
+{
+    return L.writeList(os, 10);
+}
+
+
 // ************************************************************************* //
diff --git a/src/OpenFOAM/containers/Lists/UList/UList.H b/src/OpenFOAM/containers/Lists/UList/UList.H
index 74c57a7deac..362a15ccbc2 100644
--- a/src/OpenFOAM/containers/Lists/UList/UList.H
+++ b/src/OpenFOAM/containers/Lists/UList/UList.H
@@ -372,11 +372,14 @@ public:
         //- Write the List as a dictionary entry with keyword
         void writeEntry(const word& keyword, Ostream& os) const;
 
+        //- Write the List, with line-breaks in ASCII if the list length
+        //  exceeds shortListLen. Using '0' suppresses line-breaks entirely.
+        Ostream& writeList(Ostream& os, const label shortListLen=0) const;
 
 
     // IOstream operators
 
-        //- Write List to Ostream, as per write() method with shortListLen=10
+        //- Write List to Ostream, as per writeList() with shortListLen=10
         friend Ostream& operator<< <T>
         (
             Ostream& os,
diff --git a/src/OpenFOAM/containers/Lists/UList/UListIO.C b/src/OpenFOAM/containers/Lists/UList/UListIO.C
index 0cdf2f2dd5c..cd6d8cd6bf4 100644
--- a/src/OpenFOAM/containers/Lists/UList/UListIO.C
+++ b/src/OpenFOAM/containers/Lists/UList/UListIO.C
@@ -67,11 +67,15 @@ void Foam::UList<T>::writeEntry(const word& keyword, Ostream& os) const
 }
 
 
-// * * * * * * * * * * * * * * * Ostream Operator *  * * * * * * * * * * * * //
-
 template<class T>
-Foam::Ostream& Foam::operator<<(Foam::Ostream& os, const Foam::UList<T>& L)
+Foam::Ostream& Foam::UList<T>::writeList
+(
+    Ostream& os,
+    const label shortListLen
+) const
 {
+    const UList<T>& L = *this;
+
     // Write list contents depending on data format
     if (os.format() == IOstream::ASCII || !contiguous<T>())
     {
@@ -100,7 +104,11 @@ Foam::Ostream& Foam::operator<<(Foam::Ostream& os, const Foam::UList<T>& L)
             // Write end delimiter
             os << token::END_BLOCK;
         }
-        else if (L.size() <= 1 || (L.size() < 11 && contiguous<T>()))
+        else if
+        (
+            L.size() <= 1 || !shortListLen
+         || (L.size() <= shortListLen && contiguous<T>())
+        )
         {
             // Write size and start delimiter
             os << L.size() << token::BEGIN_LIST;
@@ -118,16 +126,16 @@ Foam::Ostream& Foam::operator<<(Foam::Ostream& os, const Foam::UList<T>& L)
         else
         {
             // Write size and start delimiter
-            os << nl << L.size() << nl << token::BEGIN_LIST;
+            os << nl << L.size() << nl << token::BEGIN_LIST << nl;
 
             // Write contents
             forAll(L, i)
             {
-                os << nl << L[i];
+                os << L[i] << nl;
             }
 
             // Write end delimiter
-            os << nl << token::END_LIST << nl;
+            os << token::END_LIST << nl;
         }
     }
     else
@@ -143,12 +151,21 @@ Foam::Ostream& Foam::operator<<(Foam::Ostream& os, const Foam::UList<T>& L)
     }
 
     // Check state of IOstream
-    os.check("Ostream& operator<<(Ostream&, const UList&)");
+    os.check("UList<T>::writeList(Ostream&)");
 
     return os;
 }
 
 
+// * * * * * * * * * * * * * * * Ostream Operator *  * * * * * * * * * * * * //
+
+template<class T>
+Foam::Ostream& Foam::operator<<(Foam::Ostream& os, const Foam::UList<T>& L)
+{
+    return L.writeList(os, 10);
+}
+
+
 template<class T>
 Foam::Istream& Foam::operator>>(Istream& is, UList<T>& L)
 {
-- 
GitLab