ENH: improve flexiblity for flat output of items (#1929)

- change to a templated implementation instead of relying on
  the container's writeList() method.

  This inlines the generation while also adding the flexibility to
  define different delimiters (at compile time) without the
  performance penalty of passing run-time parameters.
This commit is contained in:
Mark Olesen 2020-11-20 15:58:36 +01:00
parent d2f1690536
commit 0de32a6e6f
6 changed files with 379 additions and 115 deletions

View File

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

View File

@ -0,0 +1,2 @@
/* EXE_INC = */
/* EXE_LIBS = */

View File

@ -0,0 +1,103 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Description
Simple test of FlatOutput
\*---------------------------------------------------------------------------*/
#include "wordList.H"
#include "ListOps.H"
#include "FlatOutput.H"
#include "IOstreams.H"
#include "macros.H"
using namespace Foam;
// For testing various pre-defined formatting
#define printFlatOutput(Content, Format) \
STRINGIFY(Format) << ": " << flatOutput(Content, FlatOutput::Format{})
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
wordList words1
{
"ab", "cd", "ef", "gh",
"ij", "kl", "mn", "op",
"qr", "st", "uv", "wx", "yz"
};
{
Info<< nl
<< "regular" << nl
<< "#----------------" << nl;
Info<< nl << "operator<< " << words1 << nl;
Info<< nl << "writeList: ";
words1.writeList(Info) << nl;
}
Info<< nl
<< "Using c++ " << int(__cplusplus) << nl;
{
Info<< nl
<< "flatOutput" << nl
<< "#----------------" << nl;
Info<< nl << "operator<< " << flatOutput(words1) << nl;
Info<< nl << "write: ";
flatOutput(words1).write(Info) << nl;
Info<< nl << printFlatOutput(words1, BareComma) << nl;
Info<< nl << printFlatOutput(words1, BareSpace) << nl;
Info<< nl << printFlatOutput(words1, BraceComma) << nl;
Info<< nl << printFlatOutput(words1, BraceSpace) << nl;
Info<< nl << printFlatOutput(words1, ParenComma) << nl;
Info<< nl << printFlatOutput(words1, ParenSpace) << nl;
Info<< nl << printFlatOutput(words1, PointyComma) << nl;
Info<< nl << printFlatOutput(words1, PointySpace) << nl;
Info<< nl << printFlatOutput(words1, SquareComma) << nl;
Info<< nl << printFlatOutput(words1, SquareSpace) << nl;
}
Info<< "\nEnd\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -1,98 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::FlatOutput
Description
Simple output adapter for list output on a single line.
The backend type must support a two-argument \c writeList() method.
\*---------------------------------------------------------------------------*/
#ifndef FlatOutput_H
#define FlatOutput_H
#include "Ostream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of friend functions and operators
template<class Container> class FlatOutput;
template<class Container>
Ostream& operator<<(Ostream& os, const FlatOutput<Container>& obj);
/*---------------------------------------------------------------------------*\
Class FlatOutput Declaration
\*---------------------------------------------------------------------------*/
template<class Container>
class FlatOutput
{
const Container& ref_;
const label len_;
public:
//- Construct from components
inline FlatOutput(const Container& obj, label len)
:
ref_(obj),
len_(len)
{}
//- Ostream operator
inline friend Ostream& operator<<
(
Ostream& os,
const FlatOutput<Container>& wrapped
)
{
return wrapped.ref_.writeList(os, wrapped.len_);
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Global flatOutput function
template<class Container>
FlatOutput<Container> flatOutput(const Container& obj, label len=0)
{
return FlatOutput<Container>(obj, len);
}
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,247 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Namespace
Foam::FlatOutput
Description
Various output adaptors, principally to output a list of items
on a single line.
\*---------------------------------------------------------------------------*/
#ifndef FlatOutput_H
#define FlatOutput_H
#include "Ostream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace FlatOutput
{
// Forward Declarations
template<class Container, class Delimiters> class OutputAdaptor;
} // End namespace FlatOutput
// Forward Declarations
template<class Container, class Delimiters>
inline Ostream& operator<<
(
Ostream&,
const FlatOutput::OutputAdaptor<Container, Delimiters>&
);
namespace FlatOutput
{
/*---------------------------------------------------------------------------*\
Class Decorators Declaration
\*---------------------------------------------------------------------------*/
//- List decorators with \c open, \c close and \c separator characters
template<char OpenChar, char CloseChar, char SepChar>
struct Decorators
{
static constexpr char open = OpenChar;
static constexpr char close = CloseChar;
static constexpr char separator = SepChar;
};
#undef makeDecorator
#define makeDecorator(Name, Open, Close, Sep) \
/*! \brief Surround with \c Open and \c Close separate with \c Sep */ \
struct Name : public Decorators<Open, Close, Sep> {};
makeDecorator(BareComma, '\0','\0', ',');
makeDecorator(BareSpace, '\0','\0', ' ');
makeDecorator(BraceComma, '{','}', ',');
makeDecorator(BraceSpace, '{','}', ' ');
makeDecorator(ParenComma, '(',')', ',');
makeDecorator(ParenSpace, '(',')', ' '); // Normal default
makeDecorator(PointyComma, '<','>', ',');
makeDecorator(PointySpace, '<','>', ' ');
makeDecorator(SquareComma,'[',']', ',');
makeDecorator(SquareSpace,'[',']', ' ');
#undef makeDecorator
/*---------------------------------------------------------------------------*\
Class OutputAdaptor Declaration
\*---------------------------------------------------------------------------*/
//- An output adaptor with a write method and an Ostream operator.
//
// Generate single line (flat) output using the characters specified by
// the templated Delimiters.
// Normally called with the global flatOutput() function.
// For example,
// \code
//
// /* With default parenthesis/space delimiters */
// Info<< "Names: " << flatOutput(names) << nl;
//
// /* Other delimiters */
// Info<< flatOutput(names, FlatOutput::SquareComma{}) << nl;
//
// /* User-specified delimiters */
// Info<< flatOutput(names, FlatOutput::Decorators<'[',')',':'>{}) << nl;
//
// \endcode
//
// \noop
template<class Container, class Delimiters>
class OutputAdaptor
{
// Private Data
//- The container of values for output
const Container& values;
public:
// Constructors
//- Construct from component
explicit OutputAdaptor(const Container& obj)
:
values(obj)
{}
// Member Functions
//- Write list using \c open, \c close and \c separator characters
//- specified by Delimiters template, which generally results in
//- a single line without line breaks.
//
// \note Suppresses nul char output.
// No special handling for newline separators.
inline Ostream& write(Ostream& os) const
{
bool started = false;
// In c++17, can use constexpr if
if (Delimiters::open)
{
os << Delimiters::open;
}
for (const auto& item : values)
{
if (started)
{
if (Delimiters::separator)
{
os << Delimiters::separator;
}
}
else
{
started = true;
}
os << item;
}
if (Delimiters::close)
{
os << Delimiters::close;
}
return os;
}
// Operators
//- Ostream Operator
inline friend Ostream&
operator<<
(
Ostream& os,
const OutputAdaptor<Container, Delimiters>& adaptor
)
{
return adaptor.write(os);
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace FlatOutput
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
//- Global flatOutput() function with specified output delimiters
template<class Container, class Delimiters>
inline FlatOutput::OutputAdaptor<Container, Delimiters>
flatOutput
(
const Container& obj,
Delimiters delim
)
{
return FlatOutput::OutputAdaptor<Container, Delimiters>(obj);
}
//- Global flatOutput() function with default (parenthesis/space) delimiters
template<class Container>
inline FlatOutput::OutputAdaptor<Container, FlatOutput::ParenSpace>
flatOutput
(
const Container& obj
)
{
return FlatOutput::OutputAdaptor<Container, FlatOutput::ParenSpace>(obj);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -348,10 +348,26 @@ Foam::simpleObjectRegistry& Foam::debug::dimensionedConstantObjects()
namespace Foam
{
// Print the switch status
static inline void printStatus
(
const char * const message,
const wordList& list
)
{
// Use writeList with length = -1 to ensure we always have newlines,
// even for short lists
Info<< message << nl;
list.writeList(Info, -1) << nl;
}
// Write the switch names.
//
// Use flatOutput with -1 for the length to ensure we always have newlines,
// Use writeList with -1 for the length to ensure we always have newlines,
// even if the lists are short
static void listSwitches
(
const wordList& debugSwitches,
@ -373,7 +389,7 @@ static void listSwitches
controlDict.merge(dictionary(is));
}
// Use a HashSet to track switches that have not been set
// HashSet to track switches that have not been set
wordHashSet hashed;
// DebugSwitches
@ -381,9 +397,7 @@ static void listSwitches
{
hashed = debugSwitches;
hashed.unset(controlDict.subDict("DebugSwitches").toc());
Info<< "Unset DebugSwitches"
<< flatOutput(hashed.sortedToc(), -1) << nl;
printStatus("Unset DebugSwitches", hashed.sortedToc());
}
// InfoSwitches
@ -391,9 +405,7 @@ static void listSwitches
{
hashed = infoSwitches;
hashed.unset(controlDict.subDict("InfoSwitches").toc());
Info<< "Unset InfoSwitches"
<< flatOutput(hashed.sortedToc(), -1) << nl;
printStatus("Unset InfoSwitches", hashed.sortedToc());
}
// OptimisationSwitches
@ -401,9 +413,7 @@ static void listSwitches
{
hashed = optSwitches;
hashed.unset(controlDict.subDict("OptimisationSwitches").toc());
Info<< "Unset OptimisationSwitches"
<< flatOutput(hashed.sortedToc(), -1) << nl;
printStatus("Unset OptimisationSwitches", hashed.sortedToc());
}
}
else
@ -411,22 +421,19 @@ static void listSwitches
// DebugSwitches
if (notNull(debugSwitches))
{
Info<< "DebugSwitches"
<< flatOutput(debugSwitches, -1) << nl;
printStatus("DebugSwitches", debugSwitches);
}
// InfoSwitches
if (notNull(infoSwitches))
{
Info<< "InfoSwitches"
<< flatOutput(infoSwitches, -1) << nl;
printStatus("InfoSwitches", infoSwitches);
}
// OptimisationSwitches
if (notNull(optSwitches))
{
Info<< "OptimisationSwitches"
<< flatOutput(optSwitches, -1) << nl;
printStatus("OptimisationSwitches", optSwitches);
}
}
}