ENH: simpler internal handling of stderr in message streams

- delay construction of message buffer

- OStringStream count() method to test if anything has been streamed

STYLE: explicit use of std::ios_base in IOstreams

- document the return information of set flag methods
This commit is contained in:
Mark Olesen 2024-05-17 10:12:41 +02:00
parent 3b9176665f
commit bbde236be5
20 changed files with 238 additions and 150 deletions

View File

@ -1,3 +1,3 @@
Test-OCountStream.C
Test-OCountStream.cxx
EXE = $(FOAM_USER_APPBIN)/Test-OCountStream

View File

@ -65,11 +65,11 @@ int main(int argc, char *argv[])
OCountStream cnt;
OCharStream cstr;
OStringStream str;
OStringStream sstr;
ocountstream plain;
generateOutput(cstr);
generateOutput(str);
generateOutput(sstr);
generateOutput(cnt);
generateOutput(plain);
@ -77,7 +77,7 @@ int main(int argc, char *argv[])
Info<< "counter state: " << (cnt.stdStream().rdstate()) << nl
<< "via char-stream: " << label(cstr.view().size()) << " chars" << nl
<< "via string-stream: " << str.str().size() << " chars" << nl
<< "via string-stream: " << label(sstr.count()) << " chars" << nl
<< "via ocountstream: " << plain.count() << " chars" << endl;
fileName outputName;

View File

@ -166,9 +166,9 @@ inline Ostream& operator<<(Ostream& os, const Omanip<T>& m)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
inline Smanip<ios_base::fmtflags> setf(const ios_base::fmtflags flags)
inline Smanip<std::ios_base::fmtflags> setf(std::ios_base::fmtflags flags)
{
return Smanip<ios_base::fmtflags>(&IOstream::setf, flags);
return Smanip<std::ios_base::fmtflags>(&IOstream::setf, flags);
}

View File

@ -114,23 +114,19 @@ void Foam::IOstream::print(Ostream& os, const int streamState) const
{
if (streamState == std::ios_base::goodbit)
{
os << "ios_base::goodbit set : the last operation on stream succeeded"
<< endl;
os << "goodbit set : the last operation on stream succeeded" << endl;
}
else if (streamState & std::ios_base::badbit)
{
os << "ios_base::badbit set : characters possibly lost"
<< endl;
os << "badbit set : characters possibly lost" << endl;
}
else if (streamState & std::ios_base::failbit)
{
os << "ios_base::failbit set : some type of formatting error"
<< endl;
os << "failbit set : some type of formatting error" << endl;
}
else if (streamState & std::ios_base::eofbit)
{
os << "ios_base::eofbit set : at end of stream"
<< endl;
os << "eofbit set : at end of stream" << endl;
}
}

View File

@ -339,9 +339,6 @@ public:
return old;
}
//- Return flags of stream
virtual ios_base::fmtflags flags() const = 0;
//- Return the default precision
static unsigned int defaultPrecision() noexcept
{
@ -387,27 +384,30 @@ public:
ioState_ |= std::ios_base::badbit;
}
//- Set flags of stream
virtual ios_base::fmtflags flags(const ios_base::fmtflags f) = 0;
//- Return current stream flags
virtual std::ios_base::fmtflags flags() const = 0;
//- Set flags of stream
ios_base::fmtflags setf(const ios_base::fmtflags f)
//- Set stream flags, return old stream flags
virtual std::ios_base::fmtflags flags(std::ios_base::fmtflags) = 0;
//- Set stream flag(s), return old stream flags
std::ios_base::fmtflags setf(std::ios_base::fmtflags f)
{
return flags(flags() | f);
}
//- Set flags of given field of stream
ios_base::fmtflags setf
//- Set stream flag(s) with mask, return old stream flags
std::ios_base::fmtflags setf
(
const ios_base::fmtflags f,
const ios_base::fmtflags mask
const std::ios_base::fmtflags f,
const std::ios_base::fmtflags mask
)
{
return flags((flags() & ~mask) | (f & mask));
}
//- Unset flags of stream
void unsetf(const ios_base::fmtflags f)
void unsetf(std::ios_base::fmtflags f)
{
flags(flags() & ~f);
}

View File

@ -151,16 +151,18 @@ public:
// Stream State Functions
//- Return stream flags
virtual ios_base::fmtflags flags() const override
//- Return current stream flags.
//- Dummy for parallel stream, returns 0.
virtual std::ios_base::fmtflags flags() const override
{
return ios_base::fmtflags(0);
return std::ios_base::fmtflags(0);
}
//- Set flags of stream flags
virtual ios_base::fmtflags flags(const ios_base::fmtflags) override
//- Set stream flags, return old stream flags.
//- Dummy for parallel stream, returns 0.
virtual std::ios_base::fmtflags flags(std::ios_base::fmtflags) override
{
return ios_base::fmtflags(0);
return std::ios_base::fmtflags(0);
}

View File

@ -144,12 +144,20 @@ public:
// Member Functions
// Inquiry
// Stream State Functions
//- Return flags of output stream
virtual ios_base::fmtflags flags() const override
//- Return current stream flags.
//- Dummy for parallel stream, returns 0.
virtual std::ios_base::fmtflags flags() const override
{
return ios_base::fmtflags(0);
return std::ios_base::fmtflags(0);
}
//- Set stream flags, return old stream flags.
//- Dummy for parallel stream, returns 0.
virtual std::ios_base::fmtflags flags(std::ios_base::fmtflags) override
{
return std::ios_base::fmtflags(0);
}
@ -281,15 +289,6 @@ public:
virtual void rewind();
// Edit
//- Set flags of stream
virtual ios_base::fmtflags flags(const ios_base::fmtflags) override
{
return ios_base::fmtflags(0);
}
// Print
//- Print stream description to Ostream

View File

@ -147,14 +147,17 @@ public:
// Stream State
//- Return flags of output stream
virtual ios_base::fmtflags flags() const override
//- Return current stream flags
virtual std::ios_base::fmtflags flags() const override
{
return is_.flags();
}
//- Set stream flags
virtual ios_base::fmtflags flags(const ios_base::fmtflags f) override
//- Set stream flags, return old stream flags
virtual std::ios_base::fmtflags flags
(
std::ios_base::fmtflags f
) override
{
return is_.flags(f);
}

View File

@ -138,14 +138,17 @@ public:
// Stream State
//- Get stream flags
virtual ios_base::fmtflags flags() const override
//- Get current stream flags
virtual std::ios_base::fmtflags flags() const override
{
return os_.flags();
}
//- Set stream flags
virtual ios_base::fmtflags flags(const ios_base::fmtflags f) override
//- Set stream flags, return old stream flags
virtual std::ios_base::fmtflags flags
(
std::ios_base::fmtflags f
) override
{
return os_.flags(f);
}

View File

@ -215,6 +215,9 @@ public:
// Member Functions
//- The number of bytes outputted
std::streamsize count() { return stream_.tellp(); }
//- Get the string.
//- As Foam::string instead of std::string (may change in future)
Foam::string str() const { return Foam::string(stream_.str()); }

View File

@ -499,16 +499,18 @@ public:
// Stream State Functions
//- Get stream flags - always 0
virtual ios_base::fmtflags flags() const override
//- Return current stream flags.
//- Dummy for token stream, returns 0.
virtual std::ios_base::fmtflags flags() const override
{
return ios_base::fmtflags(0);
return std::ios_base::fmtflags(0);
}
//- Set flags of stream - ignored
ios_base::fmtflags flags(const ios_base::fmtflags) override
//- Set stream flags, return old stream flags.
//- Dummy for token stream, returns 0.
std::ios_base::fmtflags flags(std::ios_base::fmtflags) override
{
return ios_base::fmtflags(0);
return std::ios_base::fmtflags(0);
}

View File

@ -181,16 +181,18 @@ public:
// Stream State Functions
//- Get flags of output stream
virtual ios_base::fmtflags flags() const override
//- Return current stream flags.
//- Dummy for token stream, returns 0.
virtual std::ios_base::fmtflags flags() const override
{
return ios_base::fmtflags(0);
return std::ios_base::fmtflags(0);
}
//- Set flags of stream - ignored
std::ios_base::fmtflags flags(const ios_base::fmtflags) override
//- Set stream flags, return old stream flags.
//- Dummy for token stream, returns 0.
std::ios_base::fmtflags flags(std::ios_base::fmtflags) override
{
return ios_base::fmtflags(0);
return std::ios_base::fmtflags(0);
}
//- Flush stream

View File

@ -73,16 +73,18 @@ public:
// Stream-state
//- Return flags of stream
virtual ios_base::fmtflags flags() const override
//- Return current stream flags.
//- Dummy for dummy stream, returns 0.
virtual std::ios_base::fmtflags flags() const override
{
return ios_base::fmtflags(0);
return std::ios_base::fmtflags(0);
}
//- Set flags of stream
virtual ios_base::fmtflags flags(const ios_base::fmtflags) override
//- Set stream flags, return old stream flags.
//- Dummy for dummy stream, returns 0.
virtual std::ios_base::fmtflags flags(std::ios_base::fmtflags) override
{
return ios_base::fmtflags(0);
return std::ios_base::fmtflags(0);
}

View File

@ -30,15 +30,15 @@ Note
\*---------------------------------------------------------------------------*/
#include "error.H"
#include "StringStream.H"
#include "fileName.H"
#include "dictionary.H"
#include "JobInfo.H"
#include "Pstream.H"
#include "StringStream.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::IOerror::IOerror(const string& title)
Foam::IOerror::IOerror(const char* title)
:
error(title),
ioFileName_("unknown"),
@ -171,7 +171,7 @@ void Foam::IOerror::SafeFatalIOError
const char* sourceFileName,
const int sourceFileLineNumber,
const IOstream& ioStream,
const string& msg
const std::string& msg
)
{
if (JobInfo::constructed)
@ -182,10 +182,11 @@ void Foam::IOerror::SafeFatalIOError
sourceFileName,
sourceFileLineNumber,
ioStream
) << msg << Foam::exit(FatalIOError);
) << msg.c_str() << Foam::exit(FatalIOError);
}
else
{
// Without (openfoam=API patch=NN) since it is rarely used
std::cerr
<< nl
<< "--> FOAM FATAL IO ERROR:" << nl
@ -225,7 +226,7 @@ void Foam::IOerror::exiting(const int errNo, const bool isAbort)
IOerror errorException(*this);
// Reset the message buffer for the next error message
messageStreamPtr_->reset();
error::clear();
throw errorException;
return;
@ -297,7 +298,7 @@ void Foam::IOerror::write(Ostream& os, const bool withTitle) const
const label lineNo = sourceFileLineNumber();
if (IOerror::level >= 2 && lineNo && !functionName().empty())
if (messageStream::level >= 2 && lineNo && !functionName().empty())
{
os << nl << nl
<< " From " << functionName().c_str() << nl;

View File

@ -123,7 +123,7 @@ bool Foam::error::useAbort()
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::error::error(const string& title)
Foam::error::error(const char* title)
:
std::exception(),
messageStream(title, messageStream::FATAL),
@ -131,7 +131,7 @@ Foam::error::error(const string& title)
sourceFileName_("unknown"),
sourceFileLineNumber_(0),
throwing_(false),
messageStreamPtr_(new OStringStream())
messageStreamPtr_(nullptr)
{}
@ -143,7 +143,7 @@ Foam::error::error(const dictionary& errDict)
sourceFileName_(errDict.get<string>("sourceFileName")),
sourceFileLineNumber_(errDict.get<label>("sourceFileLineNumber")),
throwing_(false),
messageStreamPtr_(new OStringStream())
messageStreamPtr_(nullptr)
{}
@ -155,8 +155,13 @@ Foam::error::error(const error& err)
sourceFileName_(err.sourceFileName_),
sourceFileLineNumber_(err.sourceFileLineNumber_),
throwing_(err.throwing_),
messageStreamPtr_(new OStringStream(*err.messageStreamPtr_))
{}
messageStreamPtr_(nullptr)
{
if (err.messageStreamPtr_ && (err.messageStreamPtr_->count() > 0))
{
messageStreamPtr_.reset(new OStringStream(*err.messageStreamPtr_));
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
@ -176,7 +181,7 @@ Foam::OSstream& Foam::error::operator()
sourceFileName_.clear();
sourceFileLineNumber_ = -1;
return operator OSstream&();
return this->stream();
}
@ -251,7 +256,7 @@ void Foam::error::exiting(const int errNo, const bool isAbort)
error errorException(*this);
// Reset the message buffer for the next error message
messageStreamPtr_->reset();
error::clear();
throw errorException;
return;
@ -322,8 +327,11 @@ void Foam::error::simpleExit(const int errNo, const bool isAbort)
Foam::OSstream& Foam::error::stream()
{
// Don't need (messageStreamPtr_) check - always allocated
if (!messageStreamPtr_->good())
if (!messageStreamPtr_)
{
messageStreamPtr_ = std::make_unique<OStringStream>();
}
else if (!messageStreamPtr_->good())
{
Perr<< nl
<< "error::stream() : error stream has failed"
@ -337,13 +345,21 @@ Foam::OSstream& Foam::error::stream()
Foam::string Foam::error::message() const
{
return messageStreamPtr_->str();
if (messageStreamPtr_)
{
return messageStreamPtr_->str();
}
return string();
}
void Foam::error::clear() const
{
return messageStreamPtr_->reset();
if (messageStreamPtr_)
{
messageStreamPtr_->reset();
}
}
@ -384,7 +400,7 @@ void Foam::error::write(Ostream& os, const bool withTitle) const
const label lineNo = sourceFileLineNumber();
if (error::level >= 2 && lineNo && !functionName().empty())
if (messageStream::level >= 2 && lineNo && !functionName().empty())
{
os << nl << nl
<< " From " << functionName().c_str() << nl;

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2015-2023 OpenCFD Ltd.
Copyright (C) 2015-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -120,7 +120,10 @@ public:
// Constructors
//- Construct from title string
explicit error(const string& title);
explicit error(const char* title);
//- Construct from title string
explicit error(const std::string& title) : error(title.c_str()) {}
//- Construct from dictionary
explicit error(const dictionary& errDict);
@ -161,7 +164,7 @@ public:
//- The accumulated error message
string message() const;
//- Clear any messages
//- Clear any accumulated error messages
void clear() const;
//- The currently defined function name for output messages
@ -315,7 +318,10 @@ public:
// Constructors
//- Construct from title string
explicit IOerror(const string& title);
explicit IOerror(const char* title);
//- Construct from title string
explicit IOerror(const std::string& title) : IOerror(title.c_str()) {}
//- Construct from dictionary
explicit IOerror(const dictionary& errDict);
@ -412,7 +418,7 @@ public:
const char* sourceFileName,
const int sourceFileLineNumber,
const IOstream& ioStream,
const string& msg
const std::string& msg
);

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2023 OpenCFD Ltd.
Copyright (C) 2017-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -49,22 +49,32 @@ int Foam::infoDetailLevel(1);
Foam::messageStream::messageStream
(
const string& title,
const errorSeverity severity,
const int maxErrors
const char* title,
errorSeverity severity,
int maxErrors,
bool use_stderr
)
:
title_(title),
title_(),
severity_(severity),
maxErrors_(maxErrors),
errorCount_(0)
{}
{
if (title)
{
title_ = title;
}
if (use_stderr)
{
severity_ |= errorSeverity::USE_STDERR;
}
}
Foam::messageStream::messageStream(const dictionary& dict)
:
title_(dict.get<string>("title")),
severity_(FATAL),
severity_(errorSeverity::FATAL),
maxErrors_(0),
errorCount_(0)
{}
@ -72,54 +82,56 @@ Foam::messageStream::messageStream(const dictionary& dict)
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::OSstream& Foam::messageStream::stream(OSstream* alternative)
Foam::OSstream& Foam::messageStream::stream
(
OSstream* alternative
)
{
if (level)
{
// Serlal (master only) output?
const bool serialOnly
(
(
severity_ == INFO
|| severity_ == INFO_STDERR
|| severity_ == WARNING
)
|| !UPstream::parRun()
!UPstream::parRun()
|| ((severity_ & ~errorSeverity::USE_STDERR) == errorSeverity::INFO)
|| ((severity_ & ~errorSeverity::USE_STDERR) == errorSeverity::WARNING)
);
if (serialOnly && (UPstream::parRun() && !UPstream::master()))
{
return Snull; // Non-serial, non-master: exit early
return Snull; // Non-serial, non-master: exit early
}
// Use stderr instead of stdout:
// - requested via static <redirect> variable
// - explicit: INFO_STDERR
// - explicit: with USE_STDERR mask
// - inferred: WARNING -> stderr when infoDetailLevel == 0
const bool useStderr =
const bool use_stderr =
(
(redirect == 2)
|| (severity_ == INFO_STDERR)
|| (severity_ == WARNING && Foam::infoDetailLevel == 0)
|| (severity_ & errorSeverity::USE_STDERR)
|| (severity_ == errorSeverity::WARNING && Foam::infoDetailLevel == 0)
);
OSstream* osptr;
if (serialOnly)
{
// Use supplied alternative? Valid for serial only
osptr = alternative;
if (!osptr)
{
osptr = (useStderr ? &Serr : &Sout);
}
osptr =
(
alternative
? alternative
: (use_stderr ? &Serr : &Sout)
);
}
else
{
// Non-serial
osptr = (useStderr ? &Perr : &Pout);
osptr = (use_stderr ? &Perr : &Pout);
}
if (!title_.empty())
@ -220,13 +232,18 @@ Foam::OSstream& Foam::messageStream::deprecated
}
}
os << nl;
os << nl;
if (functionName) // nullptr check
{
os << " From " << functionName << nl
<< " in file " << sourceFileName
<< " at line " << sourceFileLineNumber << nl;
{
os << " From " << functionName << nl;
}
if (sourceFileName)
{
os << " in file " << sourceFileName
<< " at line " << sourceFileLineNumber << nl;
}
}
os << " ";
@ -279,13 +296,14 @@ Foam::OSstream& Foam::messageStream::operator()
const label ioEndLineNumber
)
{
OSstream& os = this->stream();
OSstream& os = operator()
(
functionName,
sourceFileName,
sourceFileLineNumber
);
os << nl
<< " From " << functionName << nl
<< " in file " << sourceFileName
<< " at line " << sourceFileLineNumber << nl
<< " Reading \"" << ioFileName.c_str() << '"';
os << "Reading \"" << ioFileName.c_str() << '"';
if (ioStartLineNumber >= 0)
{
@ -345,9 +363,19 @@ Foam::OSstream& Foam::messageStream::operator()
// * * * * * * * * * * * * * * * Global Variables * * * * * * * * * * * * * //
Foam::messageStream Foam::Info("", Foam::messageStream::INFO);
Foam::messageStream Foam::Info
(
"", // No title
Foam::messageStream::INFO
);
Foam::messageStream Foam::InfoErr("", Foam::messageStream::INFO_STDERR);
Foam::messageStream Foam::InfoErr
(
"", // No title
Foam::messageStream::INFO,
0,
true // use_stderr = true
);
Foam::messageStream Foam::Warning
(

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2023 OpenCFD Ltd.
Copyright (C) 2016-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -77,16 +77,18 @@ class messageStream
public:
//- Message type, error severity flags
enum errorSeverity
enum errorSeverity : int
{
// Serial-only output:
INFO = 1, //!< General information output (stdout)
INFO_STDERR, //!< General information output (stderr)
WARNING, //!< Warning of possible problem.
// Parallel-aware output:
SERIOUS, //!< A serious problem - eg, data corruption.
FATAL //!< A fatal error.
FATAL, //!< A fatal error.
//! Bitmask for stderr output (for the above enums)
USE_STDERR = 0x80
};
@ -94,9 +96,16 @@ protected:
// Protected Data
//- The title of this error type
string title_;
errorSeverity severity_;
//- The message type / error severity, possibly with USE_STDERR mask
int severity_;
//- The maximum number of errors before program termination
int maxErrors_;
//- The current number of errors counted
int errorCount_;
@ -124,12 +133,26 @@ public:
//- Construct from components
messageStream
(
const string& title,
const errorSeverity severity,
const int maxErrors = 0
const char* title,
errorSeverity severity,
int maxErrors = 0,
bool use_stderr = false
);
//- Construct as Fatal from dictionary, extracting the 'title'.
//- Construct from components
messageStream
(
const std::string& title,
errorSeverity severity,
int maxErrors = 0,
bool use_stderr = false
)
:
messageStream(title.c_str(), severity, maxErrors, use_stderr)
{}
//- Construct from dictionary as Fatal, extracting 'title'.
explicit messageStream(const dictionary& dict);
@ -160,9 +183,11 @@ public:
// Output
//- Return OSstream for output operations.
//- Use the \c alternative stream for serial-only output
//- if it is a valid pointer.
OSstream& stream(OSstream* alternative = nullptr);
OSstream& stream
(
//! An alternative output stream (serial-only)
OSstream* alternative = nullptr
);
//- Return OSstream for output operations on the master process only,
//- Snull on other processes.
@ -177,11 +202,12 @@ public:
OSstream& deprecated
(
const int afterVersion,
const char* functionName,
const char* sourceFileName,
const char* functionName = nullptr,
const char* sourceFileName = nullptr,
const int sourceFileLineNumber = 0
);
//- Implicit cast to OSstream for << operations
operator OSstream&()
{
@ -261,7 +287,7 @@ public:
//- Global for selective suppression of Info output.
// This is normally accessed implicitly via the DetailInfo macro and is often
// associated applications with suppressed banners. For example,
// associated with applications with suppressed banners. For example,
//
// \code
// DetailInfo << "Hello, I'm running from program xyz" << nl;

View File

@ -538,9 +538,8 @@ bool objective::write(const bool valid) const
{
setObjectiveFilePtr();
OFstream& file = objFunctionFilePtr_();
ios_base::fmtflags flags = file.flags();
flags |= std::cout.left;
file.flags(flags);
file.setf(std::ios_base::left);
if (target_)
{
file<< setw(width_) << "#target" << " "

View File

@ -105,7 +105,7 @@ void Foam::probes::createProbeFiles(const wordList& fieldNames)
DebugInfo<< "open probe stream: " << os.name() << endl;
const unsigned int width(IOstream::defaultPrecision() + 7);
os << setf(ios_base::left);
os.setf(std::ios_base::left);
forAll(*this, probei)
{