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

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;
parent 28544277
......@@ -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;
}
......
......@@ -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);
......
......@@ -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,
......
......@@ -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);
}
......
/*---------------------------------------------------------------------------*\
========= |
\\ / 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
// ************************************************************************* //
......@@ -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"
......
......@@ -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);
}
......
......@@ -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
...