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.
This commit is contained in:
Mark Olesen
2017-10-20 10:26:55 +02:00
parent 3cbf399470
commit 74f667a85b
12 changed files with 370 additions and 134 deletions

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -27,15 +27,18 @@ Description
#include "IndirectList.H" #include "IndirectList.H"
#include "IOstreams.H" #include "IOstreams.H"
#include "Fstream.H"
#include "ListOps.H" #include "ListOps.H"
#include "labelIndList.H" #include "labelIndList.H"
#include "argList.H"
using namespace Foam; using namespace Foam;
template<class ListType> template<class ListType>
void printInfo(const ListType& lst) 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 << "list: " << flatOutput(lst) << nl
<< endl; << endl;
} }
@ -61,6 +64,15 @@ void testFind(const T& val, const ListType& lst)
int main(int argc, char *argv[]) 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); List<label> completeList(20);
forAll(completeList, i) forAll(completeList, i)
@ -104,6 +116,55 @@ int main(int argc, char *argv[])
printInfo(idl2); printInfo(idl2);
printInfo(idl3); 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; Info<< "End\n" << endl;
return 0; return 0;

View File

@ -91,10 +91,10 @@ Foam::Ostream& Foam::FixedList<T, Size>::writeList
// Write size (so it is valid dictionary entry) and start delimiter // Write size (so it is valid dictionary entry) and start delimiter
os << Size << token::BEGIN_BLOCK; os << Size << token::BEGIN_BLOCK;
// Write contents // Contents
os << L[0]; os << L[0];
// Write end delimiter // End delimiter
os << token::END_BLOCK; os << token::END_BLOCK;
} }
else if else if
@ -103,31 +103,31 @@ Foam::Ostream& Foam::FixedList<T, Size>::writeList
|| (Size <= unsigned(shortListLen) && contiguous<T>()) || (Size <= unsigned(shortListLen) && contiguous<T>())
) )
{ {
// Write start delimiter // Start delimiter
os << token::BEGIN_LIST; os << token::BEGIN_LIST;
// Write contents // Contents
forAll(L, i) forAll(L, i)
{ {
if (i) os << token::SPACE; if (i) os << token::SPACE;
os << L[i]; os << L[i];
} }
// Write end delimiter // End delimiter
os << token::END_LIST; os << token::END_LIST;
} }
else else
{ {
// Write start delimiter // Start delimiter
os << nl << token::BEGIN_LIST << nl; os << nl << token::BEGIN_LIST << nl;
// Write contents // Contents
forAll(L, i) forAll(L, i)
{ {
os << L[i] << nl; os << L[i] << nl;
} }
// Write end delimiter // End delimiter
os << token::END_LIST << nl; os << token::END_LIST << nl;
} }
} }

View File

@ -64,10 +64,10 @@ Foam::Istream& Foam::operator>>(Istream& is, List<T>& L)
} }
else if (firstToken.isLabel()) else if (firstToken.isLabel())
{ {
const label s = firstToken.labelToken(); const label sz = firstToken.labelToken();
// Set list length to that read // Set list length to that read
L.setSize(s); L.setSize(sz);
// Read list contents depending on data format // Read list contents depending on data format
@ -76,11 +76,11 @@ Foam::Istream& Foam::operator>>(Istream& is, List<T>& L)
// Read beginning of contents // Read beginning of contents
const char delimiter = is.readBeginList("List"); const char delimiter = is.readBeginList("List");
if (s) if (sz)
{ {
if (delimiter == token::BEGIN_LIST) if (delimiter == token::BEGIN_LIST)
{ {
for (label i=0; i<s; ++i) for (label i=0; i<sz; ++i)
{ {
is >> L[i]; is >> L[i];
@ -103,7 +103,7 @@ Foam::Istream& Foam::operator>>(Istream& is, List<T>& L)
"reading the single entry" "reading the single entry"
); );
for (label i=0; i<s; ++i) for (label i=0; i<sz; ++i)
{ {
L[i] = element; L[i] = element;
} }
@ -115,11 +115,11 @@ Foam::Istream& Foam::operator>>(Istream& is, List<T>& L)
} }
else 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 is.fatalCheck
( (

View File

@ -48,19 +48,19 @@ void Foam::PtrList<T>::read(Istream& is, const INew& inewt)
if (firstToken.isLabel()) if (firstToken.isLabel())
{ {
// Read size of list // Read size of list
const label s = firstToken.labelToken(); const label sz = firstToken.labelToken();
// Set list length to that read // Set list length to that read
setSize(s); setSize(sz);
// Read beginning of contents // Read beginning of contents
const char delimiter = is.readBeginList("PtrList"); const char delimiter = is.readBeginList("PtrList");
if (s) if (sz)
{ {
if (delimiter == token::BEGIN_LIST) if (delimiter == token::BEGIN_LIST)
{ {
forAll(*this, i) for (label i=0; i<sz; ++i)
{ {
set(i, inewt(is)); set(i, inewt(is));
@ -82,7 +82,7 @@ void Foam::PtrList<T>::read(Istream& is, const INew& inewt)
"reading the single entry" "reading the single entry"
); );
for (label i=1; i<s; ++i) for (label i=1; i<sz; ++i)
{ {
set(i, tPtr->clone()); set(i, tPtr->clone());
} }

View File

@ -39,14 +39,16 @@ Foam::Ostream& Foam::UIndirectList<T>::writeList
{ {
const UIndirectList<T>& L = *this; const UIndirectList<T>& L = *this;
const label sz = L.size();
// Write list contents depending on data format // Write list contents depending on data format
if (os.format() == IOstream::ASCII || !contiguous<T>()) if (os.format() == IOstream::ASCII || !contiguous<T>())
{ {
// Can the contents be considered 'uniform' (ie, identical)? // Can the contents be considered 'uniform' (ie, identical)?
bool uniform = (L.size() > 1 && contiguous<T>()); bool uniform = (sz > 1 && contiguous<T>());
if (uniform) if (uniform)
{ {
forAll(L, i) for (label i=1; i < sz; ++i)
{ {
if (L[i] != L[0]) if (L[i] != L[0])
{ {
@ -58,65 +60,72 @@ Foam::Ostream& Foam::UIndirectList<T>::writeList
if (uniform) if (uniform)
{ {
// Write size and start delimiter // Size and start delimiter
os << L.size() << token::BEGIN_BLOCK; os << sz << token::BEGIN_BLOCK;
// Write contents // Contents
os << L[0]; os << L[0];
// Write end delimiter // End delimiter
os << token::END_BLOCK; os << token::END_BLOCK;
} }
else if else if
( (
L.size() <= 1 || !shortListLen sz <= 1 || !shortListLen
|| (L.size() <= shortListLen && contiguous<T>()) || (sz <= shortListLen && contiguous<T>())
) )
{ {
// Write size and start delimiter // Size and start delimiter
os << L.size() << token::BEGIN_LIST; os << sz << token::BEGIN_LIST;
// Write contents // Contents
forAll(L, i) for (label i=0; i < sz; ++i)
{ {
if (i) os << token::SPACE; if (i) os << token::SPACE;
os << L[i]; os << L[i];
} }
// Write end delimiter // End delimiter
os << token::END_LIST; os << token::END_LIST;
} }
else else
{ {
// Write size and start delimiter // Size and start delimiter
os << nl << L.size() << nl << token::BEGIN_LIST << nl; os << nl << sz << nl << token::BEGIN_LIST << nl;
// Write contents // Contents
forAll(L, i) for (label i=0; i < sz; ++i)
{ {
os << L[i] << nl; os << L[i] << nl;
} }
// Write end delimiter // End delimiter
os << token::END_LIST << nl; os << token::END_LIST << nl;
} }
} }
else else
{ {
// Contents are binary and contiguous // 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 // The TOTAL number of bytes to be written.
List<T> lst = L(); // - possibly add start delimiter
os.beginRaw(sz*sizeof(T));
// write(...) includes surrounding start/end delimiters // Contents
os.write for (label i=0; i < sz; ++i)
( {
reinterpret_cast<const char*>(lst.cdata()), os.writeRaw
lst.byteSize() (
); reinterpret_cast<const char*>(&(L[i])),
sizeof(T)
);
}
// End delimiter and/or cleanup.
os.endRaw();
} }
} }

View File

@ -76,14 +76,16 @@ Foam::Ostream& Foam::UList<T>::writeList
{ {
const UList<T>& L = *this; const UList<T>& L = *this;
const label sz = L.size();
// Write list contents depending on data format // Write list contents depending on data format
if (os.format() == IOstream::ASCII || !contiguous<T>()) if (os.format() == IOstream::ASCII || !contiguous<T>())
{ {
// Can the contents be considered 'uniform' (ie, identical)? // Can the contents be considered 'uniform' (ie, identical)?
bool uniform = (L.size() > 1 && contiguous<T>()); bool uniform = (sz > 1 && contiguous<T>());
if (uniform) if (uniform)
{ {
forAll(L, i) for (label i=1; i < sz; ++i)
{ {
if (L[i] != L[0]) if (L[i] != L[0])
{ {
@ -95,58 +97,62 @@ Foam::Ostream& Foam::UList<T>::writeList
if (uniform) if (uniform)
{ {
// Write size and start delimiter // Size and start delimiter
os << L.size() << token::BEGIN_BLOCK; os << sz << token::BEGIN_BLOCK;
// Write contents // Contents
os << L[0]; os << L[0];
// Write end delimiter // End delimiter
os << token::END_BLOCK; os << token::END_BLOCK;
} }
else if else if
( (
L.size() <= 1 || !shortListLen sz <= 1 || !shortListLen
|| (L.size() <= shortListLen && contiguous<T>()) || (sz <= shortListLen && contiguous<T>())
) )
{ {
// Write size and start delimiter // Size and start delimiter
os << L.size() << token::BEGIN_LIST; os << sz << token::BEGIN_LIST;
// Write contents // Contents
forAll(L, i) for (label i=0; i < sz; ++i)
{ {
if (i) os << token::SPACE; if (i) os << token::SPACE;
os << L[i]; os << L[i];
} }
// Write end delimiter // End delimiter
os << token::END_LIST; os << token::END_LIST;
} }
else else
{ {
// Write size and start delimiter // Size and start delimiter
os << nl << L.size() << nl << token::BEGIN_LIST << nl; os << nl << sz << nl << token::BEGIN_LIST << nl;
// Write contents // Contents
forAll(L, i) for (label i=0; i < sz; ++i)
{ {
os << L[i] << nl; os << L[i] << nl;
} }
// Write end delimiter // End delimiter
os << token::END_LIST << nl; os << token::END_LIST << nl;
} }
} }
else else
{ {
// Contents are binary and contiguous // 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 // 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 // Check list length
const label s = elems.size(); const label sz = elems.size();
if (s != L.size()) if (sz != L.size())
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect length for UList. Read " << s << "incorrect length for UList. Read " << sz
<< " expected " << L.size() << " expected " << L.size()
<< exit(FatalIOError); << exit(FatalIOError);
} }
for (label i=0; i<s; ++i) for (label i=0; i<sz; ++i)
{ {
L[i] = elems[i]; L[i] = elems[i];
} }
} }
else if (firstToken.isLabel()) else if (firstToken.isLabel())
{ {
const label s = firstToken.labelToken(); const label sz = firstToken.labelToken();
// Set list length to that read // Set list length to that read
if (s != L.size()) if (sz != L.size())
{ {
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "incorrect length for UList. Read " << s << "incorrect length for UList. Read " << sz
<< " expected " << L.size() << " expected " << L.size()
<< exit(FatalIOError); << exit(FatalIOError);
} }
@ -218,11 +224,11 @@ Foam::Istream& Foam::operator>>(Istream& is, UList<T>& L)
// Read beginning of contents // Read beginning of contents
const char delimiter = is.readBeginList("List"); const char delimiter = is.readBeginList("List");
if (s) if (sz)
{ {
if (delimiter == token::BEGIN_LIST) if (delimiter == token::BEGIN_LIST)
{ {
for (label i=0; i<s; ++i) for (label i=0; i<sz; ++i)
{ {
is >> L[i]; is >> L[i];
@ -245,7 +251,7 @@ Foam::Istream& Foam::operator>>(Istream& is, UList<T>& L)
"reading the single entry" "reading the single entry"
); );
for (label i=0; i<s; ++i) for (label i=0; i<sz; ++i)
{ {
L[i] = element; L[i] = element;
} }
@ -259,9 +265,9 @@ Foam::Istream& Foam::operator>>(Istream& is, UList<T>& L)
{ {
// 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 is.fatalCheck
( (

View File

@ -31,18 +31,20 @@ License
template<class T> template<class T>
Foam::Ostream& Foam::operator<<(Ostream& os, const UPtrList<T>& L) Foam::Ostream& Foam::operator<<(Ostream& os, const UPtrList<T>& L)
{ {
// Write size and start delimiter const label sz = L.size();
os << nl << indent << L.size() << nl
<< indent << token::BEGIN_LIST << incrIndent;
// Write contents // Size and start delimiter
forAll(L, i) 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 // End delimiter
os << nl << decrIndent << indent << token::END_LIST << nl; os << decrIndent << indent << token::END_LIST << nl;
os.check(FUNCTION_NAME); os.check(FUNCTION_NAME);
return os; return os;

View File

@ -97,47 +97,62 @@ public:
// Write functions // Write functions
//- Write next token to stream //- Write next token to stream
virtual Ostream& write(const token&) = 0; virtual Ostream& write(const token& t) = 0;
//- Write character //- Write character
virtual Ostream& write(const char) = 0; virtual Ostream& write(const char c) = 0;
//- Write character string //- Write character string
virtual Ostream& write(const char*) = 0; virtual Ostream& write(const char* str) = 0;
//- Write word //- Write word
virtual Ostream& write(const word&) = 0; virtual Ostream& write(const word& str) = 0;
//- Write keyType //- Write keyType
// A plain word is written unquoted. // A plain word is written unquoted.
// A regular expression is written as a quoted string. // A regular expression is written as a quoted string.
virtual Ostream& write(const keyType&); virtual Ostream& write(const keyType& kw);
//- Write string //- Write string
virtual Ostream& write(const string&) = 0; virtual Ostream& write(const string& str) = 0;
//- Write std::string surrounded by quotes. //- Write std::string surrounded by quotes.
// Optional write without quotes. // Optional write without quotes.
virtual Ostream& writeQuoted virtual Ostream& writeQuoted
( (
const std::string&, const std::string& str,
const bool quoted=true const bool quoted=true
) = 0; ) = 0;
//- Write int32_t //- Write int32_t
virtual Ostream& write(const int32_t) = 0; virtual Ostream& write(const int32_t val) = 0;
//- Write int64_t //- Write int64_t
virtual Ostream& write(const int64_t) = 0; virtual Ostream& write(const int64_t val) = 0;
//- Write floatScalar //- Write floatScalar
virtual Ostream& write(const floatScalar) = 0; virtual Ostream& write(const floatScalar val) = 0;
//- Write doubleScalar //- Write doubleScalar
virtual Ostream& write(const doubleScalar) = 0; virtual Ostream& write(const doubleScalar val) = 0;
//- Write binary block //- Write binary block.
virtual Ostream& write(const char*, std::streamsize) = 0; virtual Ostream& write(const char* data, std::streamsize count) = 0;
//- Emit begin marker for low-level raw binary output.
// The count should indicate the number of bytes for subsequent
// writeRaw calls.
virtual Ostream& beginRaw(std::streamsize count) = 0;
//- Low-level raw binary output.
virtual Ostream& writeRaw
(
const char* data,
std::streamsize count
) = 0;
//- Emit end marker for low-level raw binary output.
virtual Ostream& endRaw() = 0;
//- Add indentation characters //- Add indentation characters
virtual void indent() = 0; virtual void indent() = 0;
@ -164,11 +179,11 @@ public:
void decrIndent(); void decrIndent();
//- Write the keyword followed by an appropriate indentation //- Write the keyword followed by an appropriate indentation
virtual Ostream& writeKeyword(const keyType&); virtual Ostream& writeKeyword(const keyType& kw);
//- Write begin block group with the given name //- Write begin block group with the given name
// Increments indentation, adds newline. // Increments indentation, adds newline.
virtual Ostream& beginBlock(const keyType&); virtual Ostream& beginBlock(const keyType& keyword);
//- Write begin block group without a name //- Write begin block group without a name
// Increments indentation, adds newline. // Increments indentation, adds newline.

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd. \\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -26,15 +26,42 @@ License
#include "UOPstream.H" #include "UOPstream.H"
#include "int.H" #include "int.H"
#include "token.H" #include "token.H"
#include <cctype> #include <cctype>
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class T> inline void Foam::UOPstream::prepareBuffer
inline void Foam::UOPstream::writeToBuffer(const T& t) (
const size_t count,
const size_t align
)
{ {
writeToBuffer(&t, sizeof(T), sizeof(T)); if (!count)
{
return;
}
// The current output position
label pos = sendBuf_.size();
if (align > 1)
{
// Align output position. Pads sendBuf_.size() - oldPos characters.
pos = align + ((pos - 1) & ~(align - 1));
}
// Extend buffer (as required)
sendBuf_.reserve(max(1000, label(pos + count)));
// Move to the aligned output position
sendBuf_.setSize(pos);
}
template<class T>
inline void Foam::UOPstream::writeToBuffer(const T& val)
{
writeToBuffer(&val, sizeof(T), sizeof(T));
} }
@ -55,25 +82,26 @@ inline void Foam::UOPstream::writeToBuffer
const size_t align const size_t align
) )
{ {
if (!sendBuf_.capacity()) if (!count)
{ {
sendBuf_.setCapacity(1000); return;
} }
label alignedPos = sendBuf_.size(); prepareBuffer(count, align);
if (align > 1) // The aligned output position
const label pos = sendBuf_.size();
// Extend the addressable range for direct pointer access
sendBuf_.setSize(pos + count);
char* const __restrict__ buf = (sendBuf_.begin() + pos);
const char* const __restrict__ input = reinterpret_cast<const char*>(data);
for (size_t i = 0; i < count; ++i)
{ {
// Align bufPosition. Pads sendBuf_.size() - oldPos characters. buf[i] = input[i];
alignedPos = align + ((sendBuf_.size() - 1) & ~(align - 1));
} }
// Extend if necessary
sendBuf_.setSize(alignedPos + count);
const char* dataPtr = reinterpret_cast<const char*>(data);
size_t i = count;
while (i--) sendBuf_[alignedPos++] = *dataPtr++;
} }
@ -135,7 +163,7 @@ Foam::UOPstream::~UOPstream()
{ {
if if
( (
!UOPstream::write !UOPstream::write
( (
commsType_, commsType_,
toProcNo_, toProcNo_,
@ -298,6 +326,41 @@ Foam::Ostream& Foam::UOPstream::write
} }
Foam::Ostream& Foam::UOPstream::beginRaw
(
const std::streamsize count
)
{
if (format() != BINARY)
{
FatalErrorInFunction
<< "stream format not binary"
<< Foam::abort(FatalError);
}
// Alignment = 8, as per write(const char*, streamsize)
prepareBuffer(count, 8);
return *this;
}
Foam::Ostream& Foam::UOPstream::writeRaw
(
const char* data,
const std::streamsize count
)
{
// No check for format() == BINARY since this is either done in the
// beginRaw() method, or the caller knows what they are doing.
// Previously aligned and sizes reserved via beginRaw()
writeToBuffer(data, count, 1);
return *this;
}
void Foam::UOPstream::print(Ostream& os) const void Foam::UOPstream::print(Ostream& os) const
{ {
os << "Writing from processor " << toProcNo_ os << "Writing from processor " << toProcNo_

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2014 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2014 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -72,9 +72,12 @@ class UOPstream
// Private Member Functions // Private Member Functions
//- Write a T to the transfer buffer //- Prepare buffer for count bytes of output at specified alignment.
inline void prepareBuffer(const size_t count, const size_t align);
//- Write data to the transfer buffer
template<class T> template<class T>
inline void writeToBuffer(const T& t); inline void writeToBuffer(const T& val);
//- Write a char to the transfer buffer //- Write a char to the transfer buffer
inline void writeToBuffer(const char& c); inline void writeToBuffer(const char& c);
@ -182,6 +185,24 @@ public:
//- Write binary block with 8-byte alignment. //- Write binary block with 8-byte alignment.
Ostream& write(const char* data, const std::streamsize count); Ostream& write(const char* data, const std::streamsize count);
//- Begin marker for low-level raw binary output.
// The count should indicate the number of bytes for subsequent
// writeRaw calls.
Ostream& beginRaw(const std::streamsize count);
//- Low-level raw binary output.
Ostream& writeRaw
(
const char* data,
const std::streamsize count
);
//- End marker for low-level raw binary output.
Ostream& endRaw()
{
return *this;
}
//- Add indentation characters //- Add indentation characters
void indent() void indent()
{} {}

View File

@ -210,7 +210,24 @@ Foam::Ostream& Foam::OSstream::write(const doubleScalar val)
} }
Foam::Ostream& Foam::OSstream::write(const char* buf, std::streamsize count) Foam::Ostream& Foam::OSstream::write
(
const char* data,
const std::streamsize count
)
{
beginRaw(count);
writeRaw(data, count);
endRaw();
return *this;
}
Foam::Ostream& Foam::OSstream::beginRaw
(
const std::streamsize count
)
{ {
if (format() != BINARY) if (format() != BINARY)
{ {
@ -220,8 +237,6 @@ Foam::Ostream& Foam::OSstream::write(const char* buf, std::streamsize count)
} }
os_ << token::BEGIN_LIST; os_ << token::BEGIN_LIST;
os_.write(buf, count);
os_ << token::END_LIST;
setState(os_.rdstate()); setState(os_.rdstate());
@ -229,9 +244,34 @@ Foam::Ostream& Foam::OSstream::write(const char* buf, std::streamsize count)
} }
Foam::Ostream& Foam::OSstream::writeRaw
(
const char* data,
std::streamsize count
)
{
// No check for format() == BINARY since this is either done in the
// beginRaw() method, or the caller knows what they are doing.
os_.write(data, count);
setState(os_.rdstate());
return *this;
}
Foam::Ostream& Foam::OSstream::endRaw()
{
os_ << token::END_LIST;
setState(os_.rdstate());
return *this;
}
void Foam::OSstream::indent() void Foam::OSstream::indent()
{ {
for (unsigned short i = 0; i < indentLevel_*indentSize_; i++) for (unsigned short i = 0; i < indentLevel_*indentSize_; ++i)
{ {
os_ << ' '; os_ << ' ';
} }

View File

@ -143,7 +143,26 @@ public:
virtual Ostream& write(const doubleScalar val); virtual Ostream& write(const doubleScalar val);
//- Write binary block //- Write binary block
virtual Ostream& write(const char* buf, std::streamsize count); virtual Ostream& write
(
const char* data,
const std::streamsize count
);
//- Begin marker for low-level raw binary output.
// The count should indicate the number of bytes for subsequent
// writeRaw calls.
virtual Ostream& beginRaw(const std::streamsize count);
//- Low-level raw binary output.
virtual Ostream& writeRaw
(
const char* data,
const std::streamsize count
);
//- End marker for low-level raw binary output.
virtual Ostream& endRaw();
//- Add indentation characters //- Add indentation characters
virtual void indent(); virtual void indent();