ENH: unify read/write for containers

- handle binary/contiguous first as being the most obvious, followed
  by increasing complexity of ascii.
  Structure reading and writing routines similarly by introducing a
  readList method to compliment the writeList method.
This commit is contained in:
Mark Olesen
2021-02-26 18:10:42 +01:00
committed by Andrew Heather
parent a76a3d760c
commit 498de8a74a
29 changed files with 728 additions and 642 deletions

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2018-2019 OpenCFD Ltd. Copyright (C) 2018-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -37,6 +37,8 @@ Description
#include "HashSet.H" #include "HashSet.H"
#include "ListOps.H" #include "ListOps.H"
#include "cpuTime.H" #include "cpuTime.H"
#include "StringStream.H"
#include "FlatOutput.H"
#include <vector> #include <vector>
#include <unordered_set> #include <unordered_set>
@ -65,6 +67,28 @@ inline Ostream& report
} }
// Create equivalent to flat output
inline void undecorated
(
Ostream& os,
const bitSet& list
)
{
const label len = list.size();
os << token::BEGIN_LIST;
// Contents
for (label i=0; i < len; ++i)
{
if (i) os << token::SPACE;
os << label(list.get(i));
}
os << token::END_LIST;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -97,6 +121,28 @@ int main(int argc, char *argv[])
Info<<"bits used: " << flatOutput(set3b.toc()) << nl; Info<<"bits used: " << flatOutput(set3b.toc()) << nl;
Info<<"inverted: " << flatOutput(invert(set3b)) << nl; Info<<"inverted: " << flatOutput(invert(set3b)) << nl;
Info<< "Test read/write (ASCII)" << nl;
OStringStream ostr;
undecorated(ostr, set3a); // like flatOutput
ostr << bitSet();
set3a.flip();
undecorated(ostr, set3a); // like flatOutput
{
IStringStream istr(ostr.str());
Info<< "parse: " << istr.str() << nl;
bitSet bset1(istr);
bitSet bset2(istr);
bitSet bset3(istr);
Info<< "got: " << bset1 << nl
<< "and: " << bset2 << nl
<< "and: " << bset3 << nl;
}
} }
Info<< "End\n" << endl; Info<< "End\n" << endl;

View File

@ -416,7 +416,7 @@ public:
Ostream& printBits(Ostream& os, bool debugOutput=false) const; Ostream& printBits(Ostream& os, bool debugOutput=false) const;
//- Clear list and read from stream //- Clear list and read from stream
Istream& read(Istream& is); Istream& readList(Istream& is);
//- Write List, with line-breaks in ASCII when length exceeds shortLen. //- Write List, with line-breaks in ASCII when length exceeds shortLen.
// Using '0' suppresses line-breaks entirely. // Using '0' suppresses line-breaks entirely.

View File

@ -212,7 +212,7 @@ inline Foam::PackedList<Width>::PackedList(Istream& is)
blocks_(), blocks_(),
size_(0) size_(0)
{ {
read(is); readList(is);
} }

View File

@ -61,70 +61,33 @@ Foam::Ostream& Foam::PackedList<Width>::printBits
template<unsigned Width> template<unsigned Width>
Foam::Istream& Foam::PackedList<Width>::read(Istream& is) Foam::Istream& Foam::PackedList<Width>::readList(Istream& is)
{ {
PackedList<Width>& list = *this; PackedList<Width>& list = *this;
// Anull list
list.clear(); list.clear();
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
token firstTok(is); token tok(is);
is.fatalCheck
(
"PackedList::read(Istream&) : "
"reading first token"
);
if (firstTok.isLabel()) is.fatalCheck("PackedList::readList(Istream&) : reading first token");
if (tok.isLabel())
{ {
const label len = firstTok.labelToken(); const label len = tok.labelToken();
// Set list length to that read // Set list length to that read
list.resize(len); list.resize(len);
// Read list contents depending on data format if (is.format() == IOstream::BINARY)
if (is.format() == IOstream::ASCII)
{ {
// Read beginning of contents // Binary (always contiguous)
const char delimiter = is.readBeginList("PackedList");
if (len)
{
if (delimiter == token::BEGIN_LIST)
{
for (label i=0; i<len; ++i)
{
list[i] = list.readValue(is);
is.fatalCheck
(
"PackedList::read(Istream&) : "
"reading entry"
);
}
}
else
{
// Assign for all entries
list = list.readValue(is);
is.fatalCheck
(
"PackedList::read(Istream&) : "
"reading the single entry"
);
}
}
// Read end of contents
is.readEndList("PackedList");
}
else
{
// NOTE: binary content should be independent of WM_LABEL_SIZE
if (len) if (len)
{ {
// NOTE: independent of WM_LABEL_SIZE
is.read is.read
( (
reinterpret_cast<char*>(list.data()), reinterpret_cast<char*>(list.data()),
@ -133,37 +96,73 @@ Foam::Istream& Foam::PackedList<Width>::read(Istream& is)
is.fatalCheck is.fatalCheck
( (
"PackedList::read(Istream&) : " "PackedList::readList(Istream&) : "
"reading the binary block" "reading the binary block"
); );
} }
} }
} else
else if (firstTok.isPunctuation(token::BEGIN_LIST))
{ {
token nextTok(is); // Begin of contents marker
const char delimiter = is.readBeginList("PackedList");
if (len)
{
if (delimiter == token::BEGIN_LIST)
{
for (label i=0; i<len; ++i)
{
list.set(i, list.readValue(is));
is.fatalCheck
(
"PackedList::readList(Istream&) : "
"reading entry"
);
}
}
else // token::BEGIN_BLOCK
{
// Assign for all entries
list = list.readValue(is);
is.fatalCheck
(
"PackedList::readList(Istream&) : "
"reading the single entry"
);
}
}
// End of contents marker
is.readEndList("PackedList");
}
}
else if (tok.isPunctuation(token::BEGIN_LIST))
{
is >> tok;
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
while (!nextTok.isPunctuation(token::END_LIST)) while (!tok.isPunctuation(token::END_LIST))
{ {
is.putBack(nextTok); is.putBack(tok);
list.append(list.readValue(is)); list.append(list.readValue(is));
is >> nextTok; is >> tok;
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
} }
} }
else if (firstTok.isPunctuation(token::BEGIN_BLOCK)) else if (tok.isPunctuation(token::BEGIN_BLOCK))
{ {
token nextTok(is); is >> tok;
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
while (!nextTok.isPunctuation(token::END_BLOCK)) while (!tok.isPunctuation(token::END_BLOCK))
{ {
is.putBack(nextTok); is.putBack(tok);
list.setPair(is); list.setPair(is);
is >> nextTok; is >> tok;
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
} }
} }
@ -171,7 +170,7 @@ Foam::Istream& Foam::PackedList<Width>::read(Istream& is)
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect first token, expected <int>, '(' or '{', found " << "incorrect first token, expected <int>, '(' or '{', found "
<< firstTok.info() << nl << tok.info() << nl
<< exit(FatalIOError); << exit(FatalIOError);
} }
@ -189,39 +188,10 @@ Foam::Ostream& Foam::PackedList<Width>::writeList
const PackedList<Width>& list = *this; const PackedList<Width>& list = *this;
const label len = list.size(); const label len = list.size();
// Write list contents depending on data format if (os.format() == IOstream::BINARY)
if (os.format() == IOstream::ASCII)
{ {
if (len > 1 && list.uniform()) // Binary (always contiguous)
{
// Two or more entries, and all have identical values.
os << len << token::BEGIN_BLOCK << list[0] << token::END_BLOCK;
}
else if (!shortLen || len <= shortLen)
{
// Shorter list, or line-breaks suppressed
os << len << token::BEGIN_LIST;
for (label i=0; i < len; ++i)
{
if (i) os << token::SPACE;
os << list[i];
}
os << token::END_LIST;
}
else
{
// Longer list
os << nl << len << nl << token::BEGIN_LIST << nl;
for (label i=0; i < len; ++i)
{
os << list[i] << nl;
}
os << token::END_LIST << nl;
}
}
else
{
// Contents are binary and contiguous
os << nl << len << nl; os << nl << len << nl;
if (len) if (len)
@ -234,6 +204,44 @@ Foam::Ostream& Foam::PackedList<Width>::writeList
); );
} }
} }
else if (len > 1 && list.uniform())
{
// Two or more entries, and all entries have identical values.
os << len << token::BEGIN_BLOCK << list[0] << token::END_BLOCK;
}
else if (!shortLen || len <= shortLen)
{
// Single-line output
// Size and start delimiter
os << len << token::BEGIN_LIST;
// Contents
for (label i=0; i < len; ++i)
{
if (i) os << token::SPACE;
os << label(list.get(i));
}
// End delimiter
os << token::END_LIST;
}
else
{
// Multi-line output
// Size and start delimiter
os << nl << len << nl << token::BEGIN_LIST << nl;
// Contents
for (label i=0; i < len; ++i)
{
os << label(list.get(i)) << nl;
}
// End delimiter
os << token::END_LIST << nl;
}
return os; return os;
} }
@ -260,7 +268,7 @@ void Foam::PackedList<Width>::writeEntry
template<unsigned Width> template<unsigned Width>
Foam::Istream& Foam::operator>>(Istream& is, PackedList<Width>& list) Foam::Istream& Foam::operator>>(Istream& is, PackedList<Width>& list)
{ {
return list.read(is); return list.readList(is);
} }

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2018-2020 OpenCFD Ltd. Copyright (C) 2018-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -74,11 +74,6 @@ class bitSet
protected: protected:
// Protected Member Functions
//- Write as a dictionary entry
void writeEntry(Ostream& os) const;
// Logic/Set Operations // Logic/Set Operations
//- The set difference //- The set difference
@ -582,16 +577,6 @@ public:
inline bitSet& operator-=(const bitSet& other); inline bitSet& operator-=(const bitSet& other);
// IO
//- Write bitSet, with line-breaks (ASCII) when length exceeds shortLen.
// Using '0' suppresses line-breaks entirely.
Ostream& writeList(Ostream& os, const label shortLen=0) const;
//- Write as a dictionary entry with keyword
void writeEntry(const word& keyword, Ostream& os) const;
// IOstream Operators // IOstream Operators
//- Return info proxy //- Return info proxy
@ -611,8 +596,7 @@ public:
// * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * //
//- Write bitset to Ostream, as per bitSet::writeList() with default length //- Write bitset to Ostream with 40 items per line.
//- of 40 items.
Ostream& operator<<(Ostream& os, const bitSet& bitset); Ostream& operator<<(Ostream& os, const bitSet& bitset);
//- Output bitset information //- Output bitset information

View File

@ -28,90 +28,6 @@ License
#include "bitSet.H" #include "bitSet.H"
#include "IOstreams.H" #include "IOstreams.H"
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::bitSet::writeEntry(Ostream& os) const
{
os << *this;
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::Ostream& Foam::bitSet::writeList
(
Ostream& os,
const label shortLen
) const
{
const bitSet& list = *this;
const label len = list.size();
// Write list contents depending on data format
if (os.format() == IOstream::ASCII)
{
if (len > 1 && list.uniform())
{
// Two or more entries, and all entries have identical values.
os << len << token::BEGIN_BLOCK << list[0] << token::END_BLOCK;
}
else if (!shortLen || len <= shortLen)
{
// Shorter list, or line-breaks suppressed
os << len << token::BEGIN_LIST;
for (label i=0; i < len; ++i)
{
if (i) os << token::SPACE;
os << list[i];
}
os << token::END_LIST;
}
else
{
// Longer list
os << nl << len << nl << token::BEGIN_LIST << nl;
for (label i=0; i < len; ++i)
{
os << list[i] << nl;
}
os << token::END_LIST << nl;
}
}
else
{
// Contents are binary and contiguous
os << nl << len << nl;
if (len)
{
// write(...) includes surrounding start/end delimiters
os.write
(
reinterpret_cast<const char*>(list.cdata()),
list.size_bytes()
);
}
}
return os;
}
void Foam::bitSet::writeEntry
(
const word& keyword,
Ostream& os
) const
{
if (keyword.size())
{
os.writeKeyword(keyword);
}
writeEntry(os);
os << token::END_STATEMENT << endl;
}
// * * * * * * * * * * * * * * Ostream Operators * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Ostream Operators * * * * * * * * * * * * * * //
Foam::Ostream& Foam::operator<<(Ostream& os, const bitSet& bitset) Foam::Ostream& Foam::operator<<(Ostream& os, const bitSet& bitset)

View File

@ -168,7 +168,10 @@ public:
//- Clear all entries from table and delete any allocated pointers //- Clear all entries from table and delete any allocated pointers
void clear(); void clear();
//- Write
// Reading/writing
//- Invoke write() on each non-null entry
void write(Ostream& os) const; void write(Ostream& os) const;
@ -183,6 +186,7 @@ public:
// IOstream Operators // IOstream Operators
//- Clear table and read from Istream
friend Istream& operator>> <T, Key, Hash> friend Istream& operator>> <T, Key, Hash>
( (
Istream& is, Istream& is,

View File

@ -44,7 +44,7 @@ void Foam::HashPtrTable<T, Key, Hash>::readIstream
{ {
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
token firstToken(is); token tok(is);
is.fatalCheck is.fatalCheck
( (
@ -52,9 +52,9 @@ void Foam::HashPtrTable<T, Key, Hash>::readIstream
"reading first token" "reading first token"
); );
if (firstToken.isLabel()) if (tok.isLabel())
{ {
const label len = firstToken.labelToken(); const label len = tok.labelToken();
// Read beginning of contents // Read beginning of contents
const char delimiter = is.readBeginList("HashPtrTable"); const char delimiter = is.readBeginList("HashPtrTable");
@ -84,7 +84,8 @@ void Foam::HashPtrTable<T, Key, Hash>::readIstream
else else
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect first token, '(', found " << firstToken.info() << "incorrect first token, '(', found "
<< tok.info() << nl
<< exit(FatalIOError); << exit(FatalIOError);
} }
} }
@ -92,12 +93,13 @@ void Foam::HashPtrTable<T, Key, Hash>::readIstream
// Read end of contents // Read end of contents
is.readEndList("HashPtrTable"); is.readEndList("HashPtrTable");
} }
else if (firstToken.isPunctuation(token::BEGIN_LIST)) else if (tok.isPunctuation(token::BEGIN_LIST))
{ {
token lastToken(is); is >> tok;
while (!lastToken.isPunctuation(token::END_LIST))
while (!tok.isPunctuation(token::END_LIST))
{ {
is.putBack(lastToken); is.putBack(tok);
Key key; Key key;
is >> key; is >> key;
this->set(key, inew(key, is).ptr()); this->set(key, inew(key, is).ptr());
@ -108,14 +110,14 @@ void Foam::HashPtrTable<T, Key, Hash>::readIstream
"reading entry" "reading entry"
); );
is >> lastToken; is >> tok;
} }
} }
else else
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect first token, expected <int> or '(', found " << "incorrect first token, expected <int> or '(', found "
<< firstToken.info() << tok.info() << nl
<< exit(FatalIOError); << exit(FatalIOError);
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2020 OpenCFD Ltd. Copyright (C) 2017-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -105,6 +105,12 @@ template<class T> class UList;
template<class T, unsigned N> class FixedList; template<class T, unsigned N> class FixedList;
template<class T, class Key, class Hash> class HashTable; template<class T, class Key, class Hash> class HashTable;
template<class T, class Key, class Hash>
Istream& operator>>(Istream&, HashTable<T, Key, Hash>&);
template<class T, class Key, class Hash>
Ostream& operator<<(Ostream&, const HashTable<T, Key, Hash>&);
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class HashTable Declaration Class HashTable Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -148,6 +154,12 @@ class HashTable
template<class... Args> template<class... Args>
bool setEntry(const bool overwrite, const Key& key, Args&&... args); bool setEntry(const bool overwrite, const Key& key, Args&&... args);
//- Read hash table
Istream& readTable(Istream& is);
//- Write hash table
Ostream& writeTable(Ostream& os) const;
public: public:
@ -893,7 +905,7 @@ public:
inline constexpr const_iterator cend() const noexcept; inline constexpr const_iterator cend() const noexcept;
// Writing // Reading/writing
//- Print information //- Print information
Ostream& printInfo(Ostream& os) const; Ostream& printInfo(Ostream& os) const;
@ -902,16 +914,22 @@ public:
//- when length exceeds shortLen. //- when length exceeds shortLen.
// Using '0' suppresses line-breaks entirely. // Using '0' suppresses line-breaks entirely.
Ostream& writeKeys(Ostream& os, const label shortLen=0) const; Ostream& writeKeys(Ostream& os, const label shortLen=0) const;
};
// IOstream Operators // IOstream Operators
template<class T, class Key, class Hash> friend Istream& operator>> <T, Key, Hash>
Istream& operator>>(Istream& is, HashTable<T, Key, Hash>& tbl); (
Istream&,
HashTable<T, Key, Hash>& tbl
);
template<class T, class Key, class Hash> friend Ostream& operator<< <T, Key, Hash>
Ostream& operator<<(Ostream& os, const HashTable<T, Key, Hash>& tbl); (
Ostream&,
const HashTable<T, Key, Hash>& tbl
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -141,21 +141,20 @@ Foam::Ostream& Foam::HashTable<T, Key, Hash>::writeKeys
} }
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
Foam::Istream& Foam::operator>> Foam::Istream& Foam::HashTable<T, Key, Hash>::readTable
( (
Istream& is, Istream& is
HashTable<T, Key, Hash>& tbl
) )
{ {
HashTable<T, Key, Hash>& tbl = *this;
// Anull existing table // Anull existing table
tbl.clear(); tbl.clear();
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
token firstToken(is); token tok(is);
is.fatalCheck is.fatalCheck
( (
@ -163,9 +162,9 @@ Foam::Istream& Foam::operator>>
"reading first token" "reading first token"
); );
if (firstToken.isLabel()) if (tok.isLabel())
{ {
const label len = firstToken.labelToken(); const label len = tok.labelToken();
// Read beginning of contents // Read beginning of contents
const char delimiter = is.readBeginList("HashTable"); const char delimiter = is.readBeginList("HashTable");
@ -175,7 +174,8 @@ Foam::Istream& Foam::operator>>
if (delimiter != token::BEGIN_LIST) if (delimiter != token::BEGIN_LIST)
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect first token, '(', found " << firstToken.info() << "incorrect first token, '(', found "
<< tok.info() << nl
<< exit(FatalIOError); << exit(FatalIOError);
} }
@ -203,12 +203,12 @@ Foam::Istream& Foam::operator>>
// Read end of contents // Read end of contents
is.readEndList("HashTable"); is.readEndList("HashTable");
} }
else if (firstToken.isPunctuation(token::BEGIN_LIST)) else if (tok.isPunctuation(token::BEGIN_LIST))
{ {
token lastToken(is); is >> tok;
while (!lastToken.isPunctuation(token::END_LIST)) while (!tok.isPunctuation(token::END_LIST))
{ {
is.putBack(lastToken); is.putBack(tok);
Key key; Key key;
@ -222,14 +222,14 @@ Foam::Istream& Foam::operator>>
"reading entry" "reading entry"
); );
is >> lastToken; is >> tok;
} }
} }
else else
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect first token, expected <int> or '(', found " << "incorrect first token, expected <int> or '(', found "
<< firstToken.info() << tok.info() << nl
<< exit(FatalIOError); << exit(FatalIOError);
} }
@ -239,12 +239,13 @@ Foam::Istream& Foam::operator>>
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
Foam::Ostream& Foam::operator<< Foam::Ostream& Foam::HashTable<T, Key, Hash>::writeTable
( (
Ostream& os, Ostream& os
const HashTable<T, Key, Hash>& tbl ) const
)
{ {
const HashTable<T, Key, Hash>& tbl = *this;
const label len = tbl.size(); const label len = tbl.size();
if (len) if (len)
@ -271,4 +272,28 @@ Foam::Ostream& Foam::operator<<
} }
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
template<class T, class Key, class Hash>
Foam::Istream& Foam::operator>>
(
Istream& is,
HashTable<T, Key, Hash>& tbl
)
{
return tbl.readTable(is);
}
template<class T, class Key, class Hash>
Foam::Ostream& Foam::operator<<
(
Ostream& os,
const HashTable<T, Key, Hash>& tbl
)
{
return tbl.writeTable(os);
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2020 OpenCFD Ltd. Copyright (C) 2017-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2014 OpenFOAM Foundation Copyright (C) 2011-2014 OpenFOAM Foundation
Copyright (C) 2016-2019 OpenCFD Ltd. Copyright (C) 2016-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -44,59 +44,9 @@ Foam::Ostream& Foam::IndirectListBase<T, Addr>::writeList
const label len = list.size(); const label len = list.size();
// Write list contents depending on data format if (os.format() == IOstream::BINARY && is_contiguous<T>::value)
if (os.format() == IOstream::ASCII || !is_contiguous<T>::value)
{ {
if (len > 1 && is_contiguous<T>::value && list.uniform()) // Binary and contiguous
{
// Two or more entries, and all entries have identical values.
os << len << token::BEGIN_BLOCK << list[0] << token::END_BLOCK;
}
else if
(
(len <= 1 || !shortLen)
||
(
(len <= shortLen)
&&
(
Detail::ListPolicy::no_linebreak<T>::value
|| is_contiguous<T>::value
)
)
)
{
// Size and start delimiter
os << len << token::BEGIN_LIST;
// Contents
for (label i=0; i < len; ++i)
{
if (i) os << token::SPACE;
os << list[i];
}
// End delimiter
os << token::END_LIST;
}
else
{
// Size and start delimiter
os << nl << len << nl << token::BEGIN_LIST << nl;
// Contents
for (label i=0; i < len; ++i)
{
os << list[i] << nl;
}
// End delimiter
os << token::END_LIST << nl;
}
}
else
{
// Contents are binary and contiguous
os << nl << len << nl; os << nl << len << nl;
if (len) if (len)
@ -119,6 +69,56 @@ Foam::Ostream& Foam::IndirectListBase<T, Addr>::writeList
os.endRawWrite(); os.endRawWrite();
} }
} }
else if (len > 1 && is_contiguous<T>::value && list.uniform())
{
// Two or more entries, and all entries have identical values.
os << len << token::BEGIN_BLOCK << list[0] << token::END_BLOCK;
}
else if
(
(len <= 1 || !shortLen)
||
(
(len <= shortLen)
&&
(
is_contiguous<T>::value
|| Detail::ListPolicy::no_linebreak<T>::value
)
)
)
{
// Single-line output
// Size and start delimiter
os << len << token::BEGIN_LIST;
// Contents
for (label i=0; i < len; ++i)
{
if (i) os << token::SPACE;
os << list[i];
}
// End delimiter
os << token::END_LIST;
}
else
{
// Multi-line output
// Size and start delimiter
os << nl << len << nl << token::BEGIN_LIST << nl;
// Contents
for (label i=0; i < len; ++i)
{
os << list[i] << nl;
}
// End delimiter
os << token::END_LIST << nl;
}
os.check(FUNCTION_NAME); os.check(FUNCTION_NAME);
return os; return os;

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2018 OpenCFD Ltd. Copyright (C) 2017-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -46,7 +46,7 @@ SourceFiles
namespace Foam namespace Foam
{ {
// Forward declarations // Forward Declarations
class Istream; class Istream;
class Ostream; class Ostream;
@ -79,7 +79,7 @@ public:
// Constructors // Constructors
//- Null construct //- Default construct
ILList() = default; ILList() = default;
//- Construct and insert the initial T item pointer //- Construct and insert the initial T item pointer
@ -126,7 +126,7 @@ public:
void transfer(ILList<LListBase, T>& lst); void transfer(ILList<LListBase, T>& lst);
// Member operators // Member Operators
//- Copy assignment using the 'clone()' method for each element //- Copy assignment using the 'clone()' method for each element
void operator=(const ILList<LListBase, T>& lst); void operator=(const ILList<LListBase, T>& lst);
@ -135,7 +135,7 @@ public:
void operator=(ILList<LListBase, T>&& lst); void operator=(ILList<LListBase, T>&& lst);
// Istream operator // Istream Operator
//- Read from Istream, discarding existing contents. //- Read from Istream, discarding existing contents.
friend Istream& operator>> <LListBase, T> friend Istream& operator>> <LListBase, T>

View File

@ -38,7 +38,7 @@ void Foam::ILList<LListBase, T>::readIstream(Istream& is, const INew& inew)
{ {
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
token firstToken(is); token tok(is);
is.fatalCheck is.fatalCheck
( (
@ -46,9 +46,9 @@ void Foam::ILList<LListBase, T>::readIstream(Istream& is, const INew& inew)
"reading first token" "reading first token"
); );
if (firstToken.isLabel()) if (tok.isLabel())
{ {
const label len = firstToken.labelToken(); const label len = tok.labelToken();
// Read beginning of contents // Read beginning of contents
const char delimiter = is.readBeginList("ILList"); const char delimiter = is.readBeginList("ILList");
@ -69,7 +69,7 @@ void Foam::ILList<LListBase, T>::readIstream(Istream& is, const INew& inew)
); );
} }
} }
else else // BEGIN_BLOCK
{ {
T* p = inew(is).ptr(); T* p = inew(is).ptr();
this->append(p); this->append(p);
@ -90,19 +90,19 @@ void Foam::ILList<LListBase, T>::readIstream(Istream& is, const INew& inew)
// Read end of contents // Read end of contents
is.readEndList("ILList"); is.readEndList("ILList");
} }
else if (firstToken.isPunctuation(token::BEGIN_LIST)) else if (tok.isPunctuation(token::BEGIN_LIST))
{ {
token lastToken(is); is >> tok;
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
while (!lastToken.isPunctuation(token::END_LIST)) while (!tok.isPunctuation(token::END_LIST))
{ {
is.putBack(lastToken); is.putBack(tok);
T* p = inew(is).ptr(); T* p = inew(is).ptr();
this->append(p); this->append(p);
is >> lastToken; is >> tok;
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
} }
} }
@ -110,7 +110,7 @@ void Foam::ILList<LListBase, T>::readIstream(Istream& is, const INew& inew)
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect first token, expected <int> or '(', found " << "incorrect first token, expected <int> or '(', found "
<< firstToken.info() << tok.info() << nl
<< exit(FatalIOError); << exit(FatalIOError);
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017 OpenCFD Ltd. Copyright (C) 2017-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -47,7 +47,7 @@ SourceFiles
namespace Foam namespace Foam
{ {
// Forward declarations // Forward Declarations
class Istream; class Istream;
class Ostream; class Ostream;
@ -162,7 +162,7 @@ public:
// Constructors // Constructors
//- Null construct //- Default construct
LList() = default; LList() = default;
//- Construct and copy insert the initial T item //- Construct and copy insert the initial T item
@ -283,7 +283,7 @@ public:
void transfer(LList<LListBase, T>& lst); void transfer(LList<LListBase, T>& lst);
// Member operators // Member Operators
//- Copy assignment //- Copy assignment
void operator=(const LList<LListBase, T>& lst); void operator=(const LList<LListBase, T>& lst);
@ -295,7 +295,10 @@ public:
void operator=(std::initializer_list<T> lst); void operator=(std::initializer_list<T> lst);
// IOstream operators // IOstream Operators
//- Read list from Istream
Istream& readList(Istream& is);
//- Write LList with line-breaks when length exceeds shortLen. //- Write LList with line-breaks when length exceeds shortLen.
// Using '0' suppresses line-breaks entirely. // Using '0' suppresses line-breaks entirely.

View File

@ -42,22 +42,24 @@ Foam::LList<LListBase, T>::LList(Istream& is)
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * // // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
template<class LListBase, class T> template<class LListBase, class T>
Foam::Istream& Foam::operator>>(Istream& is, LList<LListBase, T>& lst) Foam::Istream& Foam::LList<LListBase, T>::readList(Istream& is)
{ {
LList<LListBase, T>& list = *this;
// Anull list // Anull list
lst.clear(); list.clear();
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
token firstToken(is); token tok(is);
is.fatalCheck("LList::readList : reading first token"); is.fatalCheck("LList::readList : reading first token");
if (firstToken.isLabel()) if (tok.isLabel())
{ {
const label len = firstToken.labelToken(); const label len = tok.labelToken();
// Read beginning of contents // Begin of contents marker
const char delimiter = is.readBeginList("LList"); const char delimiter = is.readBeginList("LList");
if (len) if (len)
@ -68,7 +70,7 @@ Foam::Istream& Foam::operator>>(Istream& is, LList<LListBase, T>& lst)
{ {
T element; T element;
is >> element; is >> element;
lst.append(element); list.append(element);
} }
} }
else else
@ -78,28 +80,28 @@ Foam::Istream& Foam::operator>>(Istream& is, LList<LListBase, T>& lst)
for (label i=0; i<len; ++i) for (label i=0; i<len; ++i)
{ {
lst.append(element); list.append(element);
} }
} }
} }
// Read end of contents // End of contents marker
is.readEndList("LList"); is.readEndList("LList");
} }
else if (firstToken.isPunctuation(token::BEGIN_LIST)) else if (tok.isPunctuation(token::BEGIN_LIST))
{ {
token lastToken(is); is >> tok;
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
while (!lastToken.isPunctuation(token::END_LIST)) while (!tok.isPunctuation(token::END_LIST))
{ {
is.putBack(lastToken); is.putBack(tok);
T element; T element;
is >> element; is >> element;
lst.append(element); list.append(element);
is >> lastToken; is >> tok;
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
} }
} }
@ -107,7 +109,7 @@ Foam::Istream& Foam::operator>>(Istream& is, LList<LListBase, T>& lst)
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect first token, expected <int> or '(', found " << "incorrect first token, expected <int> or '(', found "
<< firstToken.info() << tok.info()
<< exit(FatalIOError); << exit(FatalIOError);
} }
@ -123,6 +125,8 @@ Foam::Ostream& Foam::LList<LListBase, T>::writeList
const label shortLen const label shortLen
) const ) const
{ {
// NB: no binary, contiguous output
const label len = this->size(); const label len = this->size();
if if
@ -167,9 +171,16 @@ Foam::Ostream& Foam::LList<LListBase, T>::writeList
template<class LListBase, class T> template<class LListBase, class T>
Foam::Ostream& Foam::operator<<(Ostream& os, const LList<LListBase, T>& lst) Foam::Istream& Foam::operator>>(Istream& is, LList<LListBase, T>& list)
{ {
return lst.writeList(os, -1); // Always with line breaks return list.readList(is);
}
template<class LListBase, class T>
Foam::Ostream& Foam::operator<<(Ostream& os, const LList<LListBase, T>& list)
{
return list.writeList(os, -1); // Always with line breaks
} }

View File

@ -39,7 +39,7 @@ void Foam::LPtrList<LListBase, T>::readIstream(Istream& is, const INew& inew)
{ {
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
token firstToken(is); token tok(is);
is.fatalCheck is.fatalCheck
( (
@ -47,9 +47,9 @@ void Foam::LPtrList<LListBase, T>::readIstream(Istream& is, const INew& inew)
"reading first token" "reading first token"
); );
if (firstToken.isLabel()) if (tok.isLabel())
{ {
const label len = firstToken.labelToken(); const label len = tok.labelToken();
// Read beginning of contents // Read beginning of contents
const char delimiter = is.readBeginList("LPtrList"); const char delimiter = is.readBeginList("LPtrList");
@ -70,7 +70,7 @@ void Foam::LPtrList<LListBase, T>::readIstream(Istream& is, const INew& inew)
); );
} }
} }
else else // Assumed to be token::BEGIN_BLOCK
{ {
T* p = inew(is).ptr(); T* p = inew(is).ptr();
this->append(p); this->append(p);
@ -91,17 +91,17 @@ void Foam::LPtrList<LListBase, T>::readIstream(Istream& is, const INew& inew)
// Read end of contents // Read end of contents
is.readEndList("LPtrList"); is.readEndList("LPtrList");
} }
else if (firstToken.isPunctuation(token::BEGIN_LIST)) else if (tok.isPunctuation(token::BEGIN_LIST))
{ {
token lastToken(is); is >> tok;
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
while (!lastToken.isPunctuation(token::END_LIST)) while (!tok.isPunctuation(token::END_LIST))
{ {
is.putBack(lastToken); is.putBack(tok);
this->append(inew(is).ptr()); this->append(inew(is).ptr());
is >> lastToken; is >> tok;
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
} }
} }
@ -109,7 +109,7 @@ void Foam::LPtrList<LListBase, T>::readIstream(Istream& is, const INew& inew)
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect first token, expected <int> or '(', found " << "incorrect first token, expected <int> or '(', found "
<< firstToken.info() << tok.info() << nl
<< exit(FatalIOError); << exit(FatalIOError);
} }

View File

@ -47,8 +47,7 @@ SourceFiles
namespace Foam namespace Foam
{ {
// Forward declarations // Forward Declarations
class Ostream; class Ostream;
template<class LListBase, class T> class UILList; template<class LListBase, class T> class UILList;
@ -107,7 +106,7 @@ public:
// Constructors // Constructors
//- Null construct //- Default construct
UILList() = default; UILList() = default;
//- Construct and insert the initial T item //- Construct and insert the initial T item
@ -179,7 +178,7 @@ public:
bool operator!=(const UILList<LListBase, T>& lst) const; bool operator!=(const UILList<LListBase, T>& lst) const;
// IOstream operators // IOstream Operators
//- Write UILList with line-breaks when length exceeds shortLen. //- Write UILList with line-breaks when length exceeds shortLen.
// Using '0' suppresses line-breaks entirely. // Using '0' suppresses line-breaks entirely.

View File

@ -39,6 +39,8 @@ Foam::Ostream& Foam::UILList<LListBase, T>::writeList
const label shortLen const label shortLen
) const ) const
{ {
// NB: no binary, contiguous output
const label len = this->size(); const label len = this->size();
if if

View File

@ -334,20 +334,26 @@ public:
inline void operator=(SortableList<T>&& lst); inline void operator=(SortableList<T>&& lst);
// Reading/writing
//- Read from Istream, discarding existing contents
inline Istream& readList(Istream& is);
// IOstream Operators // IOstream Operators
//- Read from Istream, discarding existing contents //- Read from Istream, discarding existing contents
friend Istream& operator>> <T, SizeMin> friend Istream& operator>> <T, SizeMin>
( (
Istream& is, Istream& is,
DynamicList<T, SizeMin>& rhs DynamicList<T, SizeMin>& list
); );
//- Write to Ostream //- Write to Ostream
friend Ostream& operator<< <T, SizeMin> friend Ostream& operator<< <T, SizeMin>
( (
Ostream& os, Ostream& os,
const DynamicList<T, SizeMin>& rhs const DynamicList<T, SizeMin>& list
); );
}; };

View File

@ -223,9 +223,11 @@ inline Foam::DynamicList<T, SizeMin>::DynamicList
template<class T, int SizeMin> template<class T, int SizeMin>
inline Foam::DynamicList<T, SizeMin>::DynamicList(Istream& is) inline Foam::DynamicList<T, SizeMin>::DynamicList(Istream& is)
: :
List<T>(is), List<T>(),
capacity_(List<T>::size()) capacity_(0)
{} {
this->readList(is);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
@ -865,20 +867,32 @@ inline void Foam::DynamicList<T, SizeMin>::operator=
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * // // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
template<class T, int SizeMin>
inline Foam::Istream& Foam::DynamicList<T, SizeMin>::readList
(
Istream& is
)
{
DynamicList<T, SizeMin>& list = *this;
// Use entire storage - ie, resize(capacity())
(void) list.expandStorage();
static_cast<List<T>&>(list).readList(is);
list.capacity_ = list.size();
return is;
}
template<class T, int SizeMin> template<class T, int SizeMin>
inline Foam::Istream& Foam::operator>> inline Foam::Istream& Foam::operator>>
( (
Istream& is, Istream& is,
DynamicList<T, SizeMin>& rhs DynamicList<T, SizeMin>& list
) )
{ {
// Use entire storage - ie, resize(capacity()) return list.readList(is);
(void) rhs.expandStorage();
is >> static_cast<List<T>&>(rhs);
rhs.capacity_ = rhs.List<T>::size();
return is;
} }
@ -886,10 +900,10 @@ template<class T, int SizeMin>
inline Foam::Ostream& Foam::operator<< inline Foam::Ostream& Foam::operator<<
( (
Ostream& os, Ostream& os,
const DynamicList<T, SizeMin>& rhs const DynamicList<T, SizeMin>& list
) )
{ {
os << static_cast<const List<T>&>(rhs); os << static_cast<const List<T>&>(list);
return os; return os;
} }

View File

@ -430,7 +430,10 @@ public:
bool operator>=(const FixedList<T, N>& list) const; bool operator>=(const FixedList<T, N>& list) const;
// Writing // Reading/writing
//- Read from Istream, discarding contents of existing List
Istream& readList(Istream& is);
//- Write the list as a dictionary entry with keyword //- Write the list as a dictionary entry with keyword
void writeEntry(const word& keyword, Ostream& os) const; void writeEntry(const word& keyword, Ostream& os) const;

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2020 OpenCFD Ltd. Copyright (C) 2017-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -72,15 +72,22 @@ Foam::Ostream& Foam::FixedList<T, N>::writeList
{ {
const FixedList<T, N>& list = *this; const FixedList<T, N>& list = *this;
// Write list contents depending on data format // Unlike UList, no compact ascii output since a FixedList is generally
// small and we prefer a consistent appearance.
// Eg, FixedList<T,2> or Pair<T> as "(-1 -1)", never as "2{-1}"
// Unlike UList, no compact output form since a FixedList is generally if (os.format() == IOstream::BINARY && is_contiguous<T>::value)
// small and we desire a consistent appearance.
// Eg, FixedList<T,2> or Pair<T> as "(-1 -1)", not as "2{-1}"
if (os.format() == IOstream::ASCII || !is_contiguous<T>::value)
{ {
if // Binary and contiguous. Size is always non-zero
// write(...) includes surrounding start/end delimiters
os.write
(
reinterpret_cast<const char*>(list.cdata()),
list.size_bytes()
);
}
else if
( (
(N <= 1 || !shortLen) (N <= 1 || !shortLen)
|| ||
@ -88,12 +95,14 @@ Foam::Ostream& Foam::FixedList<T, N>::writeList
(N <= unsigned(shortLen)) (N <= unsigned(shortLen))
&& &&
( (
Detail::ListPolicy::no_linebreak<T>::value is_contiguous<T>::value
|| is_contiguous<T>::value || Detail::ListPolicy::no_linebreak<T>::value
) )
) )
) )
{ {
// Single-line output
// Start delimiter // Start delimiter
os << token::BEGIN_LIST; os << token::BEGIN_LIST;
@ -109,6 +118,8 @@ Foam::Ostream& Foam::FixedList<T, N>::writeList
} }
else else
{ {
// Multi-line output
// Start delimiter // Start delimiter
os << nl << token::BEGIN_LIST << nl; os << nl << token::BEGIN_LIST << nl;
@ -121,73 +132,79 @@ Foam::Ostream& Foam::FixedList<T, N>::writeList
// End delimiter // End delimiter
os << token::END_LIST << nl; os << token::END_LIST << nl;
} }
}
else
{
// Binary, contiguous
// write(...) includes surrounding start/end delimiters
os.write(reinterpret_cast<const char*>(list.cdata()), N*sizeof(T));
}
os.check(FUNCTION_NAME); os.check(FUNCTION_NAME);
return os; return os;
} }
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
template<class T, unsigned N> template<class T, unsigned N>
Foam::FixedList<T, N>::FixedList(Istream& is) Foam::Istream& Foam::FixedList<T, N>::readList
(
Istream& is
)
{ {
operator>>(is, *this); FixedList<T, N>& list = *this;
}
template<class T, unsigned N>
Foam::Istream& Foam::operator>>(Foam::Istream& is, FixedList<T, N>& list)
{
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
if (is.format() == IOstream::ASCII || !is_contiguous<T>::value) if (is.format() == IOstream::BINARY && is_contiguous<T>::value)
{ {
token firstToken(is); // Binary and contiguous
Detail::readContiguous<T>
(
is,
reinterpret_cast<char*>(list.data()),
list.size_bytes()
);
is.fatalCheck is.fatalCheck
( (
"operator>>(Istream&, FixedList<T, N>&) : " "FixedList<T, N>::readList(Istream&) : "
"reading the binary block"
);
}
else
{
token tok(is);
is.fatalCheck
(
"FixedList<T, N>::readList(Istream&) : "
"reading first token" "reading first token"
); );
if (firstToken.isCompound()) if (tok.isCompound())
{ {
// Compound: transfer contents
list = dynamicCast<token::Compound<List<T>>> list = dynamicCast<token::Compound<List<T>>>
( (
firstToken.transferCompoundToken(is) tok.transferCompoundToken(is)
); );
} }
else if (firstToken.isLabel()) else if (tok.isLabel())
{ {
const label len = firstToken.labelToken(); const label len = tok.labelToken();
// List lengths must match // List lengths must match
list.checkSize(len); list.checkSize(len);
} }
else if (!firstToken.isPunctuation()) else if (!tok.isPunctuation())
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect first token, expected <label> " << "incorrect first token, expected <label> "
"or '(' or '{', found " "or '(' or '{', found "
<< firstToken.info() << tok.info() << nl
<< exit(FatalIOError); << exit(FatalIOError);
} }
else else
{ {
// Putback the opening bracket // Putback the opening bracket
is.putBack(firstToken); is.putBack(tok);
} }
// Read beginning of contents // Begin of contents marker
const char delimiter = is.readBeginList("FixedList"); const char delimiter = is.readBeginList("FixedList");
if (delimiter == token::BEGIN_LIST) if (delimiter == token::BEGIN_LIST)
@ -198,19 +215,21 @@ Foam::Istream& Foam::operator>>(Foam::Istream& is, FixedList<T, N>& list)
is.fatalCheck is.fatalCheck
( (
"operator>>(Istream&, FixedList<T, N>&) : " "FixedList<T, N>::readList(Istream&) : "
"reading entry" "reading entry"
); );
} }
} }
else else
{ {
// Uniform content (delimiter == token::BEGIN_BLOCK)
T val; T val;
is >> val; is >> val;
is.fatalCheck is.fatalCheck
( (
"operator>>(Istream&, FixedList<T, N>&) : " "FixedList<T, N>::readList(Istream&) : "
"reading the single entry" "reading the single entry"
); );
@ -220,29 +239,28 @@ Foam::Istream& Foam::operator>>(Foam::Istream& is, FixedList<T, N>& list)
} }
} }
// Read end of contents // End of contents marker
is.readEndList("FixedList"); is.readEndList("FixedList");
} }
else
{
// Binary and contiguous
Detail::readContiguous<T>
(
is,
reinterpret_cast<char*>(list.data()),
N*sizeof(T)
);
is.fatalCheck
(
"operator>>(Istream&, FixedList<T, N>&) : "
"reading the binary block"
);
}
return is; return is;
} }
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
template<class T, unsigned N>
Foam::FixedList<T, N>::FixedList(Istream& is)
{
this->readList(is);
}
template<class T, unsigned N>
Foam::Istream& Foam::operator>>(Foam::Istream& is, FixedList<T, N>& list)
{
return list.readList(is);
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2020 OpenCFD Ltd. Copyright (C) 2017-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -302,7 +302,13 @@ public:
void operator=(SLList<T>&& list); void operator=(SLList<T>&& list);
// Istream Operator // Reading/writing
//- Read List from Istream, discarding contents of existing List
Istream& readList(Istream& is);
// IOstream Operators
//- Read List from Istream, discarding contents of existing List //- Read List from Istream, discarding contents of existing List
friend Istream& operator>> <T> friend Istream& operator>> <T>

View File

@ -39,23 +39,25 @@ Foam::List<T>::List(Istream& is)
: :
UList<T>(nullptr, 0) UList<T>(nullptr, 0)
{ {
operator>>(is, *this); this->readList(is);
} }
template<class T> template<class T>
Foam::Istream& Foam::operator>>(Istream& is, List<T>& list) Foam::Istream& Foam::List<T>::readList(Istream& is)
{ {
List<T>& list = *this;
// Anull list // Anull list
list.resize(0); list.clear();
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
token firstToken(is); token tok(is);
is.fatalCheck(FUNCTION_NAME); is.fatalCheck("List<T>::readList(Istream&) : reading first token");
if (firstToken.isCompound()) if (tok.isCompound())
{ {
// Compound: simply transfer contents // Compound: simply transfer contents
@ -63,24 +65,42 @@ Foam::Istream& Foam::operator>>(Istream& is, List<T>& list)
( (
dynamicCast<token::Compound<List<T>>> dynamicCast<token::Compound<List<T>>>
( (
firstToken.transferCompoundToken(is) tok.transferCompoundToken(is)
) )
); );
} }
else if (firstToken.isLabel()) else if (tok.isLabel())
{ {
// Label: could be int(..), int{...} or just a plain '0' // Label: could be int(..), int{...} or just a plain '0'
const label len = firstToken.labelToken(); const label len = tok.labelToken();
// Resize to length read // Resize to actual length read
list.resize(len); list.resize(len);
// Read list contents depending on data format if (is.format() == IOstream::BINARY && is_contiguous<T>::value)
if (is.format() == IOstream::ASCII || !is_contiguous<T>::value)
{ {
// Read beginning of contents // Binary and contiguous
if (len)
{
Detail::readContiguous<T>
(
is,
reinterpret_cast<char*>(list.data()),
list.size_bytes()
);
is.fatalCheck
(
"List<T>::readList(Istream&) : "
"reading the binary block"
);
}
}
else
{
// Begin of contents marker
const char delimiter = is.readBeginList("List"); const char delimiter = is.readBeginList("List");
if (len) if (len)
@ -93,7 +113,7 @@ Foam::Istream& Foam::operator>>(Istream& is, List<T>& list)
is.fatalCheck is.fatalCheck
( (
"operator>>(Istream&, List<T>&) : " "List<T>::readList(Istream&) : "
"reading entry" "reading entry"
); );
} }
@ -102,48 +122,31 @@ Foam::Istream& Foam::operator>>(Istream& is, List<T>& list)
{ {
// Uniform content (delimiter == token::BEGIN_BLOCK) // Uniform content (delimiter == token::BEGIN_BLOCK)
T element; T elem;
is >> element; is >> elem;
is.fatalCheck is.fatalCheck
( (
"operator>>(Istream&, List<T>&) : " "List<T>::readList(Istream&) : "
"reading the single entry" "reading the single entry"
); );
for (label i=0; i<len; ++i) for (label i=0; i<len; ++i)
{ {
list[i] = element; // Copy the value list[i] = elem; // Copy the value
} }
} }
} }
// Read end of contents // End of contents marker
is.readEndList("List"); is.readEndList("List");
} }
else if (len)
{
// Non-empty, binary, contiguous
Detail::readContiguous<T>
(
is,
reinterpret_cast<char*>(list.data()),
len*sizeof(T)
);
is.fatalCheck
(
"operator>>(Istream&, List<T>&) : "
"reading the binary block"
);
} }
} else if (tok.isPunctuation(token::BEGIN_LIST))
else if (firstToken.isPunctuation(token::BEGIN_LIST))
{ {
// "(...)" : read as SLList and transfer contents // "(...)" : read as SLList and transfer contents
is.putBack(firstToken); // Putback the opening bracket is.putBack(tok); // Putback the opening bracket
SLList<T> sll(is); // Read as singly-linked list SLList<T> sll(is); // Read as singly-linked list
// Reallocate and move assign list elements // Reallocate and move assign list elements
@ -153,7 +156,7 @@ Foam::Istream& Foam::operator>>(Istream& is, List<T>& list)
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect first token, expected <int> or '(', found " << "incorrect first token, expected <int> or '(', found "
<< firstToken.info() << nl << tok.info() << nl
<< exit(FatalIOError); << exit(FatalIOError);
} }
@ -161,4 +164,11 @@ Foam::Istream& Foam::operator>>(Istream& is, List<T>& list)
} }
template<class T>
Foam::Istream& Foam::operator>>(Istream& is, List<T>& list)
{
return list.readList(is);
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -459,7 +459,11 @@ public:
bool operator>=(const UList<T>& a) const; bool operator>=(const UList<T>& a) const;
// Writing // Reading/writing
//- Read List contents from Istream.
// The List must have the proper size before calling
Istream& readList(Istream& is);
//- Write the List as a dictionary entry with keyword //- Write the List as a dictionary entry with keyword
void writeEntry(const word& keyword, Ostream& os) const; void writeEntry(const word& keyword, Ostream& os) const;
@ -472,7 +476,7 @@ public:
// IOstream Operators // IOstream Operators
//- Read List contents from Istream. //- Read List contents from Istream.
// Requires size to have been set before // The List must have the proper size before calling
friend Istream& operator>> <T> friend Istream& operator>> <T>
( (
Istream& os, Istream& os,

View File

@ -85,10 +85,23 @@ Foam::Ostream& Foam::UList<T>::writeList
const label len = list.size(); const label len = list.size();
// Write list contents depending on data format if (os.format() == IOstream::BINARY && is_contiguous<T>::value)
if (os.format() == IOstream::ASCII || !is_contiguous<T>::value)
{ {
if (len > 1 && is_contiguous<T>::value && list.uniform()) // Binary and contiguous
os << nl << len << nl;
if (len)
{
// write(...) includes surrounding start/end delimiters
os.write
(
reinterpret_cast<const char*>(list.cdata()),
list.size_bytes()
);
}
}
else if (len > 1 && is_contiguous<T>::value && list.uniform())
{ {
// Two or more entries, and all entries have identical values. // Two or more entries, and all entries have identical values.
os << len << token::BEGIN_BLOCK << list[0] << token::END_BLOCK; os << len << token::BEGIN_BLOCK << list[0] << token::END_BLOCK;
@ -101,12 +114,14 @@ Foam::Ostream& Foam::UList<T>::writeList
(len <= shortLen) (len <= shortLen)
&& &&
( (
Detail::ListPolicy::no_linebreak<T>::value is_contiguous<T>::value
|| is_contiguous<T>::value || Detail::ListPolicy::no_linebreak<T>::value
) )
) )
) )
{ {
// Single-line output
// Size and start delimiter // Size and start delimiter
os << len << token::BEGIN_LIST; os << len << token::BEGIN_LIST;
@ -122,6 +137,8 @@ Foam::Ostream& Foam::UList<T>::writeList
} }
else else
{ {
// Multi-line output
// Size and start delimiter // Size and start delimiter
os << nl << len << nl << token::BEGIN_LIST << nl; os << nl << len << nl << token::BEGIN_LIST << nl;
@ -134,43 +151,27 @@ Foam::Ostream& Foam::UList<T>::writeList
// End delimiter // End delimiter
os << token::END_LIST << nl; os << token::END_LIST << nl;
} }
}
else
{
// Contents are binary and contiguous
os << nl << len << nl;
if (len)
{
// write(...) includes surrounding start/end delimiters
os.write
(
reinterpret_cast<const char*>(list.cdata()),
list.size_bytes()
);
}
}
os.check(FUNCTION_NAME); os.check(FUNCTION_NAME);
return os; return os;
} }
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
template<class T> template<class T>
Foam::Istream& Foam::operator>>(Istream& is, UList<T>& list) Foam::Istream& Foam::UList<T>::readList(Istream& is)
{ {
UList<T>& list = *this;
// The target list length - must match with sizes read // The target list length - must match with sizes read
const label len = list.size(); const label len = list.size();
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
token firstToken(is); token tok(is);
is.fatalCheck("operator>>(Istream&, UList<T>&) : reading first token"); is.fatalCheck("UList<T>::readList(Istream&) : reading first token");
if (firstToken.isCompound()) if (tok.isCompound())
{ {
// Compound: simply transfer contents // Compound: simply transfer contents
@ -179,7 +180,7 @@ Foam::Istream& Foam::operator>>(Istream& is, UList<T>& list)
( (
dynamicCast<token::Compound<List<T>>> dynamicCast<token::Compound<List<T>>>
( (
firstToken.transferCompoundToken(is) tok.transferCompoundToken(is)
) )
); );
@ -199,11 +200,11 @@ Foam::Istream& Foam::operator>>(Istream& is, UList<T>& list)
list[i] = std::move(elems[i]); list[i] = std::move(elems[i]);
} }
} }
else if (firstToken.isLabel()) else if (tok.isLabel())
{ {
// Label: could be int(..), int{...} or just a plain '0' // Label: could be int(..), int{...} or just a plain '0'
const label inputLen = firstToken.labelToken(); const label inputLen = tok.labelToken();
// List lengths must match // List lengths must match
if (inputLen != len) if (inputLen != len)
@ -214,11 +215,29 @@ Foam::Istream& Foam::operator>>(Istream& is, UList<T>& list)
<< exit(FatalIOError); << exit(FatalIOError);
} }
// Read list contents depending on data format if (is.format() == IOstream::BINARY && is_contiguous<T>::value)
if (is.format() == IOstream::ASCII || !is_contiguous<T>::value)
{ {
// Read beginning of contents // Binary and contiguous
if (len)
{
Detail::readContiguous<T>
(
is,
reinterpret_cast<char*>(list.data()),
list.size_bytes()
);
is.fatalCheck
(
"UList<T>::readList(Istream&) : "
"reading binary block"
);
}
}
else
{
// Begin of contents marker
const char delimiter = is.readBeginList("List"); const char delimiter = is.readBeginList("List");
if (len) if (len)
@ -231,7 +250,8 @@ Foam::Istream& Foam::operator>>(Istream& is, UList<T>& list)
is.fatalCheck is.fatalCheck
( (
"operator>>(Istream&, UList<T>&) : reading entry" "UList<T>::readList(Istream&) : "
"reading entry"
); );
} }
} }
@ -239,47 +259,31 @@ Foam::Istream& Foam::operator>>(Istream& is, UList<T>& list)
{ {
// Uniform content (delimiter == token::BEGIN_BLOCK) // Uniform content (delimiter == token::BEGIN_BLOCK)
T element; T elem;
is >> element; is >> elem;
is.fatalCheck is.fatalCheck
( (
"operator>>(Istream&, UList<T>&) : " "UList<T>::readList(Istream&) : "
"reading the single entry" "reading the single entry"
); );
for (label i=0; i<len; ++i) for (label i=0; i<len; ++i)
{ {
list[i] = element; // Copy the value list[i] = elem; // Copy the value
} }
} }
} }
// Read end of contents // End of contents marker
is.readEndList("List"); is.readEndList("List");
} }
else if (len)
{
// Non-empty, binary, contiguous
Detail::readContiguous<T>
(
is,
reinterpret_cast<char*>(list.data()),
len*sizeof(T)
);
is.fatalCheck
(
"operator>>(Istream&, UList<T>&) : reading the binary block"
);
} }
} else if (tok.isPunctuation(token::BEGIN_LIST))
else if (firstToken.isPunctuation(token::BEGIN_LIST))
{ {
// "(...)" : read as SLList and transfer contents // "(...)" : read as SLList and transfer contents
is.putBack(firstToken); // Putback the opening bracket is.putBack(tok); // Putback the opening bracket
SLList<T> sll(is); // Read as singly-linked list SLList<T> sll(is); // Read as singly-linked list
// List lengths must match // List lengths must match
@ -301,7 +305,7 @@ Foam::Istream& Foam::operator>>(Istream& is, UList<T>& list)
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect first token, expected <int> or '(', found " << "incorrect first token, expected <int> or '(', found "
<< firstToken.info() << nl << tok.info() << nl
<< exit(FatalIOError); << exit(FatalIOError);
} }
@ -309,4 +313,11 @@ Foam::Istream& Foam::operator>>(Istream& is, UList<T>& list)
} }
template<class T>
Foam::Istream& Foam::operator>>(Istream& is, UList<T>& list)
{
return list.readList(is);
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -41,20 +41,16 @@ void Foam::PtrList<T>::readIstream(Istream& is, const INew& inew)
is.fatalCheck(FUNCTION_NAME); is.fatalCheck(FUNCTION_NAME);
token firstToken(is); token tok(is);
is.fatalCheck is.fatalCheck("PtrList::readIstream : reading first token");
(
"PtrList::readIstream : "
"reading first token"
);
if (firstToken.isLabel()) if (tok.isLabel())
{ {
// Label: could be int(..), int{...} or just a plain '0' // Label: could be int(..), int{...} or just a plain '0'
// Read size of list // Read size of list
const label len = firstToken.labelToken(); const label len = tok.labelToken();
// Set list length to that read // Set list length to that read
resize(len); resize(len);
@ -78,7 +74,7 @@ void Foam::PtrList<T>::readIstream(Istream& is, const INew& inew)
); );
} }
} }
else else // Assumed to be BEGIN_BLOCK
{ {
T* p = inew(is).ptr(); T* p = inew(is).ptr();
set(0, p); set(0, p);
@ -99,7 +95,7 @@ void Foam::PtrList<T>::readIstream(Istream& is, const INew& inew)
// Read end of contents // Read end of contents
is.readEndList("PtrList"); is.readEndList("PtrList");
} }
else if (firstToken.isPunctuation(token::BEGIN_LIST)) else if (tok.isPunctuation(token::BEGIN_LIST))
{ {
// "(...)" : read as SLList and transfer contents // "(...)" : read as SLList and transfer contents
// This would be more efficient (fewer allocations, lower overhead) // This would be more efficient (fewer allocations, lower overhead)
@ -107,20 +103,20 @@ void Foam::PtrList<T>::readIstream(Istream& is, const INew& inew)
SLList<T*> slList; SLList<T*> slList;
token lastToken(is); is >> tok;
while (!lastToken.isPunctuation(token::END_LIST)) while (!tok.isPunctuation(token::END_LIST))
{ {
is.putBack(lastToken); is.putBack(tok);
if (is.eof()) if (is.eof())
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "Premature EOF after reading " << lastToken.info() << "Premature EOF after reading " << tok.info() << nl
<< exit(FatalIOError); << exit(FatalIOError);
} }
slList.append(inew(is).ptr()); slList.append(inew(is).ptr());
is >> lastToken; is >> tok;
} }
resize(slList.size()); resize(slList.size());
@ -136,7 +132,7 @@ void Foam::PtrList<T>::readIstream(Istream& is, const INew& inew)
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect first token, expected <int> or '(', found " << "incorrect first token, expected <int> or '(', found "
<< firstToken.info() << nl << tok.info() << nl
<< exit(FatalIOError); << exit(FatalIOError);
} }
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -68,10 +68,26 @@ bool Foam::Matrix<Form, Type>::readMatrix(Istream& is)
// The total size // The total size
const label len = size(); const label len = size();
// Read list contents depending on data format if (is.format() == IOstream::BINARY && is_contiguous<Type>::value)
if (is.format() == IOstream::ASCII || !is_contiguous<Type>::value)
{ {
// Read beginning of contents // Binary and contiguous
if (len)
{
Detail::readContiguous<Type>
(
is,
reinterpret_cast<char*>(v_),
this->size_bytes()
);
is.fatalCheck("readMatrix : reading the binary block");
}
}
else
{
// Begin of contents marker
char listDelimiter = is.readBeginList("Matrix"); char listDelimiter = is.readBeginList("Matrix");
if (len) if (len)
@ -88,14 +104,13 @@ bool Foam::Matrix<Form, Type>::readMatrix(Istream& is)
for (label j = 0; j < nCols_; ++j) for (label j = 0; j < nCols_; ++j)
{ {
is >> v_[idx++]; is >> v_[idx++];
is.fatalCheck("readMatrix : reading entry");
is.fatalCheck("readMatrix : reading reading entry");
} }
is.readEndList("MatrixRow"); is.readEndList("MatrixRow");
} }
} }
else else // BEGIN_BLOCK
{ {
Type element; Type element;
is >> element; is >> element;
@ -106,31 +121,16 @@ bool Foam::Matrix<Form, Type>::readMatrix(Istream& is)
} }
} }
// Read end of contents // End of contents marker
is.readEndList("Matrix"); is.readEndList("Matrix");
} }
else
{
if (len)
{
Detail::readContiguous<Type>
(
is,
reinterpret_cast<char*>(v_),
len*sizeof(Type)
);
is.fatalCheck("readMatrix : reading the binary block");
}
}
return len; return len;
} }
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect first token, expected <int>, found " << "incorrect first token, expected <int>, found "
<< firstToken.info() << firstToken.info() << nl
<< exit(FatalIOError); << exit(FatalIOError);
return 0; return 0;
@ -150,10 +150,23 @@ Foam::Ostream& Foam::Matrix<Form, Type>::writeMatrix
const label len = mat.size(); const label len = mat.size();
// Rows, columns size // Rows, columns size
os << mat.m() << token::SPACE << mat.n(); os << mat.nRows() << token::SPACE << mat.nCols();
// Write list contents depending on data format if (os.format() == IOstream::BINARY && is_contiguous<Type>::value)
if (os.format() == IOstream::ASCII || !is_contiguous<Type>::value) {
// Binary and contiguous
if (len)
{
// write(...) includes surrounding start/end delimiters
os.write
(
reinterpret_cast<const char*>(mat.cdata()),
mat.size_bytes()
);
}
}
else
{ {
if (len) if (len)
{ {
@ -173,12 +186,12 @@ Foam::Ostream& Foam::Matrix<Form, Type>::writeMatrix
label idx = 0; label idx = 0;
// Loop over rows // Loop over rows
for (label i = 0; i < mat.m(); ++i) for (label i = 0; i < mat.nRows(); ++i)
{ {
os << token::BEGIN_LIST; os << token::BEGIN_LIST;
// Write row // Write row
for (label j = 0; j < mat.n(); ++j) for (label j = 0; j < mat.nCols(); ++j)
{ {
if (j) os << token::SPACE; if (j) os << token::SPACE;
os << v[idx++]; os << v[idx++];
@ -198,12 +211,12 @@ Foam::Ostream& Foam::Matrix<Form, Type>::writeMatrix
label idx = 0; label idx = 0;
// Loop over rows // Loop over rows
for (label i=0; i < mat.m(); ++i) for (label i=0; i < mat.nRows(); ++i)
{ {
os << nl << token::BEGIN_LIST; os << nl << token::BEGIN_LIST;
// Write row // Write row
for (label j=0; j < mat.n(); ++j) for (label j = 0; j < mat.nCols(); ++j)
{ {
os << nl << v[idx++]; os << nl << v[idx++];
} }
@ -217,23 +230,10 @@ Foam::Ostream& Foam::Matrix<Form, Type>::writeMatrix
} }
else else
{ {
// Empty matrix
os << token::BEGIN_LIST << token::END_LIST << nl; os << token::BEGIN_LIST << token::END_LIST << nl;
} }
} }
else
{
// Contents are binary and contiguous
if (len)
{
// write(...) includes surrounding start/end delimiters
os.write
(
reinterpret_cast<const char*>(mat.cdata()),
len*sizeof(Type)
);
}
}
os.check(FUNCTION_NAME); os.check(FUNCTION_NAME);
return os; return os;