Commit 74f667a8 authored by Mark Olesen's avatar Mark Olesen
Browse files

ENH: additional low-level raw binary output for Ostream.

- low-level beginRaw(), writeRaw(), endRaw() methods.
  These can be used to directly add '()' decorators for serial output
  or prepare/cleanup parallel buffers.
  Used, for example, when outputting indirect lists in binary to avoid.
parent 3cbf3994
......@@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -27,15 +27,18 @@ Description
#include "IndirectList.H"
#include "IOstreams.H"
#include "Fstream.H"
#include "ListOps.H"
#include "labelIndList.H"
#include "argList.H"
using namespace Foam;
template<class ListType>
void printInfo(const ListType& lst)
{
Info<< "addr: " << flatOutput(lst.addressing()) << nl
Info<< "full: " << flatOutput(lst.completeList()) << nl
<< "addr: " << flatOutput(lst.addressing()) << nl
<< "list: " << flatOutput(lst) << nl
<< endl;
}
......@@ -61,6 +64,15 @@ void testFind(const T& val, const ListType& lst)
int main(int argc, char *argv[])
{
argList::addOption
(
"binary",
"file",
"write lists in binary to specified file"
);
argList args(argc, argv);
List<label> completeList(20);
forAll(completeList, i)
......@@ -104,6 +116,55 @@ int main(int argc, char *argv[])
printInfo(idl2);
printInfo(idl3);
fileName binaryOutput;
if (args.optionReadIfPresent("binary", binaryOutput))
{
Info<<"Writing output to " << binaryOutput << endl;
OFstream os(binaryOutput, IOstream::BINARY);
os.writeEntry("idl1", idl1);
os.writeEntry("idl2", idl2);
os.writeEntry("idl3", idl3);
}
if (Pstream::parRun())
{
if (Pstream::master())
{
Pout<< "full: " << flatOutput(idl3.completeList()) << nl
<< "send: " << flatOutput(idl3) << endl;
for
(
int slave = Pstream::firstSlave();
slave <= Pstream::lastSlave();
++slave
)
{
OPstream toSlave(Pstream::commsTypes::scheduled, slave);
toSlave << idl3;
}
}
else
{
// From master
IPstream fromMaster
(
Pstream::commsTypes::scheduled,
Pstream::masterNo()
);
List<label> recv(fromMaster);
Pout<<"recv: " << flatOutput(recv) << endl;
}
// MPI barrier
bool barrier = true;
Pstream::scatter(barrier);
}
Info<< "End\n" << endl;
return 0;
......
......@@ -91,10 +91,10 @@ Foam::Ostream& Foam::FixedList<T, Size>::writeList
// Write size (so it is valid dictionary entry) and start delimiter
os << Size << token::BEGIN_BLOCK;
// Write contents
// Contents
os << L[0];
// Write end delimiter
// End delimiter
os << token::END_BLOCK;
}
else if
......@@ -103,31 +103,31 @@ Foam::Ostream& Foam::FixedList<T, Size>::writeList
|| (Size <= unsigned(shortListLen) && contiguous<T>())
)
{
// Write start delimiter
// Start delimiter
os << token::BEGIN_LIST;
// Write contents
// Contents
forAll(L, i)
{
if (i) os << token::SPACE;
os << L[i];
}
// Write end delimiter
// End delimiter
os << token::END_LIST;
}
else
{
// Write start delimiter
// Start delimiter
os << nl << token::BEGIN_LIST << nl;
// Write contents
// Contents
forAll(L, i)
{
os << L[i] << nl;
}
// Write end delimiter
// End delimiter
os << token::END_LIST << nl;
}
}
......
......@@ -64,10 +64,10 @@ Foam::Istream& Foam::operator>>(Istream& is, List<T>& L)
}
else if (firstToken.isLabel())
{
const label s = firstToken.labelToken();
const label sz = firstToken.labelToken();
// Set list length to that read
L.setSize(s);
L.setSize(sz);
// Read list contents depending on data format
......@@ -76,11 +76,11 @@ Foam::Istream& Foam::operator>>(Istream& is, List<T>& L)
// Read beginning of contents
const char delimiter = is.readBeginList("List");
if (s)
if (sz)
{
if (delimiter == token::BEGIN_LIST)
{
for (label i=0; i<s; ++i)
for (label i=0; i<sz; ++i)
{
is >> L[i];
......@@ -103,7 +103,7 @@ Foam::Istream& Foam::operator>>(Istream& is, List<T>& L)
"reading the single entry"
);
for (label i=0; i<s; ++i)
for (label i=0; i<sz; ++i)
{
L[i] = element;
}
......@@ -115,11 +115,11 @@ Foam::Istream& Foam::operator>>(Istream& is, List<T>& L)
}
else
{
// contents are binary and contiguous
// Contents are binary and contiguous
if (s)
if (sz)
{
is.read(reinterpret_cast<char*>(L.data()), s*sizeof(T));
is.read(reinterpret_cast<char*>(L.data()), sz*sizeof(T));
is.fatalCheck
(
......
......@@ -48,19 +48,19 @@ void Foam::PtrList<T>::read(Istream& is, const INew& inewt)
if (firstToken.isLabel())
{
// Read size of list
const label s = firstToken.labelToken();
const label sz = firstToken.labelToken();
// Set list length to that read
setSize(s);
setSize(sz);
// Read beginning of contents
const char delimiter = is.readBeginList("PtrList");
if (s)
if (sz)
{
if (delimiter == token::BEGIN_LIST)
{
forAll(*this, i)
for (label i=0; i<sz; ++i)
{
set(i, inewt(is));
......@@ -82,7 +82,7 @@ void Foam::PtrList<T>::read(Istream& is, const INew& inewt)
"reading the single entry"
);
for (label i=1; i<s; ++i)
for (label i=1; i<sz; ++i)
{
set(i, tPtr->clone());
}
......
......@@ -39,14 +39,16 @@ Foam::Ostream& Foam::UIndirectList<T>::writeList
{
const UIndirectList<T>& L = *this;
const label sz = L.size();
// Write list contents depending on data format
if (os.format() == IOstream::ASCII || !contiguous<T>())
{
// Can the contents be considered 'uniform' (ie, identical)?
bool uniform = (L.size() > 1 && contiguous<T>());
bool uniform = (sz > 1 && contiguous<T>());
if (uniform)
{
forAll(L, i)
for (label i=1; i < sz; ++i)
{
if (L[i] != L[0])
{
......@@ -58,65 +60,72 @@ Foam::Ostream& Foam::UIndirectList<T>::writeList
if (uniform)
{
// Write size and start delimiter
os << L.size() << token::BEGIN_BLOCK;
// Size and start delimiter
os << sz << token::BEGIN_BLOCK;
// Write contents
// Contents
os << L[0];
// Write end delimiter
// End delimiter
os << token::END_BLOCK;
}
else if
(
L.size() <= 1 || !shortListLen
|| (L.size() <= shortListLen && contiguous<T>())
sz <= 1 || !shortListLen
|| (sz <= shortListLen && contiguous<T>())
)
{
// Write size and start delimiter
os << L.size() << token::BEGIN_LIST;
// Size and start delimiter
os << sz << token::BEGIN_LIST;
// Write contents
forAll(L, i)
// Contents
for (label i=0; i < sz; ++i)
{
if (i) os << token::SPACE;
os << L[i];
}
// Write end delimiter
// End delimiter
os << token::END_LIST;
}
else
{
// Write size and start delimiter
os << nl << L.size() << nl << token::BEGIN_LIST << nl;
// Size and start delimiter
os << nl << sz << nl << token::BEGIN_LIST << nl;
// Write contents
forAll(L, i)
// Contents
for (label i=0; i < sz; ++i)
{
os << L[i] << nl;
}
// Write end delimiter
// End delimiter
os << token::END_LIST << nl;
}
}
else
{
// Contents are binary and contiguous
os << nl << L.size() << nl;
os << nl << sz << nl;
if (L.size())
if (sz)
{
// This is annoying, and wasteful, but currently no alternative
List<T> lst = L();
// write(...) includes surrounding start/end delimiters
os.write
(
reinterpret_cast<const char*>(lst.cdata()),
lst.byteSize()
);
// The TOTAL number of bytes to be written.
// - possibly add start delimiter
os.beginRaw(sz*sizeof(T));
// Contents
for (label i=0; i < sz; ++i)
{
os.writeRaw
(
reinterpret_cast<const char*>(&(L[i])),
sizeof(T)
);
}
// End delimiter and/or cleanup.
os.endRaw();
}
}
......
......@@ -76,14 +76,16 @@ Foam::Ostream& Foam::UList<T>::writeList
{
const UList<T>& L = *this;
const label sz = L.size();
// Write list contents depending on data format
if (os.format() == IOstream::ASCII || !contiguous<T>())
{
// Can the contents be considered 'uniform' (ie, identical)?
bool uniform = (L.size() > 1 && contiguous<T>());
bool uniform = (sz > 1 && contiguous<T>());
if (uniform)
{
forAll(L, i)
for (label i=1; i < sz; ++i)
{
if (L[i] != L[0])
{
......@@ -95,58 +97,62 @@ Foam::Ostream& Foam::UList<T>::writeList
if (uniform)
{
// Write size and start delimiter
os << L.size() << token::BEGIN_BLOCK;
// Size and start delimiter
os << sz << token::BEGIN_BLOCK;
// Write contents
// Contents
os << L[0];
// Write end delimiter
// End delimiter
os << token::END_BLOCK;
}
else if
(
L.size() <= 1 || !shortListLen
|| (L.size() <= shortListLen && contiguous<T>())
sz <= 1 || !shortListLen
|| (sz <= shortListLen && contiguous<T>())
)
{
// Write size and start delimiter
os << L.size() << token::BEGIN_LIST;
// Size and start delimiter
os << sz << token::BEGIN_LIST;
// Write contents
forAll(L, i)
// Contents
for (label i=0; i < sz; ++i)
{
if (i) os << token::SPACE;
os << L[i];
}
// Write end delimiter
// End delimiter
os << token::END_LIST;
}
else
{
// Write size and start delimiter
os << nl << L.size() << nl << token::BEGIN_LIST << nl;
// Size and start delimiter
os << nl << sz << nl << token::BEGIN_LIST << nl;
// Write contents
forAll(L, i)
// Contents
for (label i=0; i < sz; ++i)
{
os << L[i] << nl;
}
// Write end delimiter
// End delimiter
os << token::END_LIST << nl;
}
}
else
{
// Contents are binary and contiguous
os << nl << L.size() << nl;
os << nl << sz << nl;
if (L.size())
if (sz)
{
// write(...) includes surrounding start/end delimiters
os.write(reinterpret_cast<const char*>(L.cdata()), L.byteSize());
os.write
(
reinterpret_cast<const char*>(L.cdata()),
L.byteSize()
);
}
}
......@@ -184,29 +190,29 @@ Foam::Istream& Foam::operator>>(Istream& is, UList<T>& L)
)
);
// Check list length
const label s = elems.size();
const label sz = elems.size();
if (s != L.size())
if (sz != L.size())
{
FatalIOErrorInFunction(is)
<< "incorrect length for UList. Read " << s
<< "incorrect length for UList. Read " << sz
<< " expected " << L.size()
<< exit(FatalIOError);
}
for (label i=0; i<s; ++i)
for (label i=0; i<sz; ++i)
{
L[i] = elems[i];
}
}
else if (firstToken.isLabel())
{
const label s = firstToken.labelToken();
const label sz = firstToken.labelToken();
// Set list length to that read
if (s != L.size())
if (sz != L.size())
{
FatalIOErrorInFunction(is)
<< "incorrect length for UList. Read " << s
<< "incorrect length for UList. Read " << sz
<< " expected " << L.size()
<< exit(FatalIOError);
}
......@@ -218,11 +224,11 @@ Foam::Istream& Foam::operator>>(Istream& is, UList<T>& L)
// Read beginning of contents
const char delimiter = is.readBeginList("List");
if (s)
if (sz)
{
if (delimiter == token::BEGIN_LIST)
{
for (label i=0; i<s; ++i)
for (label i=0; i<sz; ++i)
{
is >> L[i];
......@@ -245,7 +251,7 @@ Foam::Istream& Foam::operator>>(Istream& is, UList<T>& L)
"reading the single entry"
);
for (label i=0; i<s; ++i)
for (label i=0; i<sz; ++i)
{
L[i] = element;
}
......@@ -259,9 +265,9 @@ Foam::Istream& Foam::operator>>(Istream& is, UList<T>& L)
{
// contents are binary and contiguous
if (s)
if (sz)
{
is.read(reinterpret_cast<char*>(L.data()), s*sizeof(T));
is.read(reinterpret_cast<char*>(L.data()), sz*sizeof(T));
is.fatalCheck
(
......
......@@ -31,18 +31,20 @@ License
template<class T>
Foam::Ostream& Foam::operator<<(Ostream& os, const UPtrList<T>& L)
{
// Write size and start delimiter
os << nl << indent << L.size() << nl
<< indent << token::BEGIN_LIST << incrIndent;
const label sz = L.size();
// Write contents
forAll(L, i)
// Size and start delimiter
os << nl << indent << sz << nl
<< indent << token::BEGIN_LIST << incrIndent << nl;
// Contents
for (label i=0; i < sz; ++i)
{
os << nl << L[i];
os << L[i] << nl;
}
// Write end delimiter
os << nl << decrIndent << indent << token::END_LIST << nl;
// End delimiter
os << decrIndent << indent << token::END_LIST << nl;
os.check(FUNCTION_NAME);
return os;
......
......@@ -97,47 +97,62 @@ public:
// Write functions
//- Write next token to stream
virtual Ostream& write(const token&) = 0;
virtual Ostream& write(const token& t) = 0;
//- Write character
virtual Ostream& write(const char) = 0;
virtual Ostream& write(const char c) = 0;
//- Write character string
virtual Ostream& write(const char*) = 0;
virtual Ostream& write(const char* str) = 0;
//- Write word
virtual Ostream& write(const word&) = 0;
virtual Ostream& write(const word& str) = 0;
//- Write keyType
// A plain word is written unquoted.
// A regular expression is written as a quoted string.
virtual Ostream& write(const keyType&);
virtual Ostream& write(const keyType& kw);
//- Write string
virtual Ostream& write(const string&) = 0;
virtual Ostream& write(const string& str) = 0;
//- Write std::string surrounded by quotes.
// Optional write without quotes.
virtual Ostream& writeQuoted
(
const std::string&,
const std::string& str,
const bool quoted=true
) = 0;
//- Write int32_t
virtual Ostream& write(const int32_t) = 0;
virtual Ostream& write(const int32_t val) = 0;
//- Write int64_t
virtual Ostream& write(const int64_t) = 0;
virtual Ostream& write(const int64_t val) = 0;