ENH: adjustments to Switch

- align Switch more with Enum.
  Now have find(), found() static methods.
  Constructors with failsafe option.

  The find() method makes for clearer coding:

  OLD

     Switch sw(some_string, true); // NB: true = allowBad

     if (sw.valid()) ...

  NOW

     Switch sw = Switch::find(some_string);

     if (sw.good()) ...

  or

     if (Switch::found(some_string)) ...

- improve construct from dictionary to handle all valid token types.
  Previously just read in a word.

- Remove asText() method - replaced by c_str() and str() several
  versions ago.
This commit is contained in:
Mark Olesen 2020-02-14 17:21:44 +01:00
parent ed4bd54846
commit bb53e8adb3
10 changed files with 277 additions and 184 deletions

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2015-2017 OpenCFD Ltd.
Copyright (C) 2015-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -279,16 +279,9 @@ int main(int argc, char *argv[])
surfaceIntersection::NONE
);
const Switch writeObj = surfaceDict.lookupOrDefault<Switch>
(
"writeObj",
Switch::OFF
);
const Switch writeVTK = surfaceDict.lookupOrDefault<Switch>
(
"writeVTK",
Switch::OFF
);
const Switch writeObj("writeObj", surfaceDict, Switch::OFF);
const Switch writeVTK("writeVTK", surfaceDict, Switch::OFF);
// The "surfaces" entry is normally optional, but make it mandatory
// if the dictionary name doesn't have an extension

View File

@ -7,7 +7,7 @@
-------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2011 Symscape
Copyright (C) 2016-2018 OpenCFD Ltd.
Copyright (C) 2016-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -69,16 +69,11 @@ static void clearFpe()
// or by the specified flag
static bool isTrue(const char* envName, bool deflt)
{
const auto str(Foam::getEnv(envName));
Foam::Switch sw(Foam::Switch::find(Foam::getEnv(envName)));
if (str.size())
if (sw.good())
{
Foam::Switch sw(str, true); // Silently ignores bad input
if (sw.valid())
{
return sw;
}
return static_cast<bool>(sw);
}
// Env was not set or did not contain a valid bool value

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2016-2019 OpenCFD Ltd.
Copyright (C) 2016-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -67,16 +67,11 @@ bool Foam::sigFpe::nanActive_ = false;
// or by the specified flag
static bool isTrue(const char* envName, bool deflt)
{
const auto str(Foam::getEnv(envName));
Foam::Switch sw(Foam::Switch::find(Foam::getEnv(envName)));
if (str.size())
if (sw.good())
{
Foam::Switch sw(str, true); // Silently ignores bad input
if (sw.valid())
{
return sw;
}
return static_cast<bool>(sw);
}
// Env was not set or did not contain a valid bool value

View File

@ -71,8 +71,8 @@ Foam::IOstreamOption::compressionEnum(const word& compName)
{
// Handle bad input graciously
const Switch sw(compName, true);
if (sw.valid())
const Switch sw = Switch::find(compName);
if (sw.good())
{
return
(

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2019 OpenCFD Ltd.
Copyright (C) 2017-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -30,7 +30,6 @@ License
#include "scalar.H"
#include "error.H"
#include "dictionary.H"
#include "IOstreams.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -50,23 +49,45 @@ static const char* names[9] =
"no", "yes",
"off", "on",
"none", "any",
"invalid"
"invalid" //< Output representation only
};
} // End anonymous namespace
// * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * * //
const char* Foam::Switch::name(const bool b) noexcept
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
return names[(b ? 1 : 0)];
}
template<class OS>
static OS& printTokenError(OS& os, const token& tok)
{
if (!tok.good())
{
os << "Bad token - could not get bool/switch" << nl;
}
else if (tok.isWord())
{
os << "Expected true/false, on/off... found "
<< tok.wordToken() << nl;
}
else
{
os << "Wrong token - expected bool/switch, found "
<< tok.info() << nl;
}
return os;
}
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::Switch::switchType Foam::Switch::parse
(
const std::string& str,
bool allowBad
const bool failOnError
)
{
switch (str.size())
@ -108,10 +129,10 @@ Foam::Switch::switchType Foam::Switch::parse
}
}
if (!allowBad)
if (failOnError)
{
FatalErrorInFunction
<< "Unknown switch word " << str << nl
<< "Unknown switch " << str << nl
<< abort(FatalError);
}
@ -119,45 +140,116 @@ Foam::Switch::switchType Foam::Switch::parse
}
// * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * * //
const char* Foam::Switch::name(const bool b) noexcept
{
return names[(b ? 1 : 0)];
}
Foam::Switch Foam::Switch::find(const std::string& str)
{
return Switch(parse(str, false)); // failOnError=false
}
bool Foam::Switch::found(const std::string& str)
{
return (switchType::INVALID != parse(str, false)); // failOnError=false
}
Foam::Switch Foam::Switch::getOrAddToDict
(
const word& name,
const word& key,
dictionary& dict,
const Switch deflt
)
{
return dict.getOrAdd<Switch>(name, deflt);
return dict.getOrAdd<Switch>(key, deflt, keyType::LITERAL);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::Switch::Switch(const std::string& str)
:
value_(parse(str, true))
{}
Foam::Switch::Switch(const char* str)
:
value_(parse(str, true))
{}
Foam::Switch::Switch(const std::string& str, bool allowBad)
:
value_(parse(str, !allowBad))
{}
Foam::Switch::Switch(const char* str, bool allowBad)
:
value_(parse(str, !allowBad))
{}
Foam::Switch::Switch(const float val, const float tol)
:
switch_((mag(val) > tol) ? switchType::TRUE : switchType::FALSE)
value_((mag(val) > tol) ? switchType::TRUE : switchType::FALSE)
{}
Foam::Switch::Switch(const double val, const double tol)
:
switch_((mag(val) > tol) ? switchType::TRUE : switchType::FALSE)
value_((mag(val) > tol) ? switchType::TRUE : switchType::FALSE)
{}
Foam::Switch::Switch(const token& tok)
:
value_(switchType::INVALID)
{
if (tok.good())
{
if (tok.isBool())
{
(*this) = tok.boolToken();
}
else if (tok.isLabel())
{
(*this) = bool(tok.labelToken());
}
else if (tok.isWord())
{
value_ = parse(tok.wordToken(), false); // failOnError=false
}
}
}
Foam::Switch::Switch
(
const word& key,
const dictionary& dict
)
:
value_(switchType::INVALID)
{
const word str(dict.get<word>(key, keyType::LITERAL));
const token tok(dict.get<token>(key, keyType::LITERAL));
(*this) = parse(str, true);
Switch sw(tok);
if (!valid())
if (sw.good())
{
FatalIOErrorInFunction(dict)
<< "Expected 'true/false', 'on/off' ... found " << str << nl
(*this) = sw;
}
else
{
printTokenError(FatalIOErrorInFunction(dict), tok)
<< exit(FatalIOError);
}
}
@ -167,25 +259,30 @@ Foam::Switch::Switch
(
const word& key,
const dictionary& dict,
const Switch deflt
const Switch deflt,
const bool failsafe
)
:
Switch(deflt)
value_(deflt.value_)
{
const entry* eptr = dict.findEntry(key, keyType::LITERAL);
token tok;
if (eptr)
if (dict.readIfPresent<token>(key, tok, keyType::LITERAL))
{
const word str(eptr->get<word>());
Switch sw(tok);
(*this) = parse(str, true);
if (!valid())
if (sw.good())
{
// Found entry, but was bad input
FatalIOErrorInFunction(dict)
<< "Expected 'true/false', 'on/off' ... found " << str << nl
(*this) = sw;
}
else if (failsafe)
{
printTokenError(IOWarningInFunction(dict), tok)
<< "using failsafe " << deflt.c_str() << endl;
}
else
{
printTokenError(FatalIOErrorInFunction(dict), tok)
<< exit(FatalIOError);
}
}
@ -200,33 +297,37 @@ Foam::Switch::Switch(Istream& is)
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
bool Foam::Switch::valid() const noexcept
bool Foam::Switch::good() const noexcept
{
return switch_ != switchType::INVALID;
return (value_ < switchType::INVALID);
}
Foam::Switch::switchType Foam::Switch::type() const noexcept
{
return switchType(switch_);
return switchType(value_);
}
const char* Foam::Switch::c_str() const noexcept
{
return names[(switch_ & 0x0F)];
return names[(value_ & 0x0F)];
}
std::string Foam::Switch::str() const
{
return names[(switch_ & 0x0F)];
return names[(value_ & 0x0F)];
}
bool Foam::Switch::readIfPresent(const word& name, const dictionary& dict)
bool Foam::Switch::readIfPresent
(
const word& key,
const dictionary& dict
)
{
return dict.readIfPresent<Switch>(name, *this);
return dict.readIfPresent<Switch>(key, *this, keyType::LITERAL);
}
@ -234,47 +335,21 @@ bool Foam::Switch::readIfPresent(const word& name, const dictionary& dict)
Foam::Istream& Foam::operator>>(Istream& is, Switch& sw)
{
token t(is);
token tok(is);
if (!t.good())
{
FatalIOErrorInFunction(is)
<< "Bad token - could not get bool"
<< exit(FatalIOError);
is.setBad();
return is;
}
sw = Switch(tok);
if (t.isLabel())
if (sw.good())
{
sw = bool(t.labelToken());
}
else if (t.isWord())
{
// Permit invalid value, but catch immediately for better messages
sw = Switch(t.wordToken(), true);
if (!sw.valid())
{
FatalIOErrorInFunction(is)
<< "Expected 'true/false', 'on/off' ... found "
<< t.wordToken()
<< exit(FatalIOError);
is.setBad();
return is;
}
is.check(FUNCTION_NAME);
}
else
{
FatalIOErrorInFunction(is)
<< "Wrong token type - expected bool, found "
<< t.info()
printTokenError(FatalIOErrorInFunction(is), tok)
<< exit(FatalIOError);
is.setBad();
return is;
}
is.check(FUNCTION_NAME);
return is;
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2019 OpenCFD Ltd.
Copyright (C) 2017-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -40,7 +40,7 @@ SourceFiles
#define Switch_H
#include "bool.H"
#include "word.H"
#include "stdFoam.H"
// Avoid any pre-processor conflicts with enum names
#undef FALSE
@ -56,12 +56,18 @@ SourceFiles
namespace Foam
{
// Forward declarations
class Switch;
// Forward Declarations
class dictionary;
class token;
class word;
class Switch;
// IOstream Operators
//- Read Switch from stream using Foam::Switch(Istream&)
Istream& operator>>(Istream& is, Switch& sw);
//- Write Switch to stream as its text value (eg, "true", "false")
Ostream& operator<<(Ostream& is, const Switch& sw);
/*---------------------------------------------------------------------------*\
@ -72,19 +78,21 @@ class Switch
{
public:
//- Switch enumerations corresponding to common text representations.
// \note the values specified here are critical for its proper behaviour.
// The lower bit is tested for the true/false condition.
// The values correspond to an index into the predefined output names
// for the c_str() method.
enum switchType : unsigned char
{
FALSE = 0 /*!< "false" */, TRUE = 1 /*!< "true" */,
NO = 2 /*!< "no" */, YES = 3 /*!< "yes" */,
OFF = 4 /*!< "off" */, ON = 5 /*!< "on" */,
NONE = 6 /*!< "none" */, ANY = 7 /*!< "any" */,
INVALID = 8 /*!< "invalid" */
};
// Data Types
//- Switch enumerations corresponding to common text representations.
// \note The values here are critical for its proper behaviour.
// The values correspond to an index into the predefined output names
// for the c_str() method and the lower bit is tested for
// determining the true/false bool value.
enum switchType : unsigned char
{
FALSE = 0 /*!< "false" */, TRUE = 1 /*!< "true" */,
NO = 2 /*!< "no" */, YES = 3 /*!< "yes" */,
OFF = 4 /*!< "off" */, ON = 5 /*!< "on" */,
NONE = 6 /*!< "none" */, ANY = 7 /*!< "any" */,
INVALID = 8 /*!< "invalid" */,
};
private:
@ -92,43 +100,61 @@ private:
// Private Data
//- The logic and enumerated text representation stored in a byte
unsigned char switch_;
unsigned char value_;
// Static Member Functions
// Private Member Functions
//- Return enum value for input string
static switchType parse(const std::string& str, bool allowBad);
//- Find switchType for given string. Return 'INVALID' if not found.
// With failOnError, trigger FatalError if not found
static switchType parse(const std::string& str, const bool failOnError);
public:
// Generated Methods
//- Copy construct
Switch(const Switch&) noexcept = default;
//- Copy assignment
Switch& operator=(const Switch&) noexcept = default;
// Constructors
//- Null constructible as false
//- Default construct as false
constexpr Switch() noexcept
:
switch_(switchType::FALSE)
value_(switchType::FALSE)
{}
//- Construct from enumerated value
constexpr Switch(const switchType sw) noexcept
:
switch_(sw)
value_(sw)
{}
//- Construct from bool
constexpr Switch(const bool b) noexcept
:
switch_(b ? switchType::TRUE : switchType::FALSE)
value_(b ? switchType::TRUE : switchType::FALSE)
{}
//- Construct from int (treat integer as bool value)
constexpr Switch(const int i) noexcept
:
switch_(i ? switchType::TRUE : switchType::FALSE)
value_(i ? switchType::TRUE : switchType::FALSE)
{}
//- Construct from string - catches bad input.
// Use static find() method for a failsafe alternative
explicit Switch(const std::string& str);
//- Construct from character array - catches bad input.
// Use static find() method for a failsafe alternative
explicit Switch(const char* str);
//- Construct from float with rounding to zero given by
//- the tolerance (default: 0.5)
explicit Switch(const float val, const float tol=0.5);
@ -137,31 +163,8 @@ public:
//- the tolerance (default: 0.5)
explicit Switch(const double val, const double tol=0.5);
//- Construct from string - catches bad input.
explicit Switch(const std::string& str)
:
switch_(parse(str, false))
{}
//- Construct from character array - catches bad input.
explicit Switch(const char* str)
:
switch_(parse(str, false))
{}
//- Construct from string.
// Optionally allow bad words, and catch the error elsewhere
Switch(const std::string& str, bool allowBad)
:
switch_(parse(str, allowBad))
{}
//- Construct from character array.
// Optionally allow bad words, and catch the error elsewhere
Switch(const char* str, bool allowBad)
:
switch_(parse(str, allowBad))
{}
//- Construct from token. Handles bool/label/word types.
explicit Switch(const token& tok);
//- Construct from dictionary lookup.
// FatalError if anything is incorrect.
@ -171,17 +174,20 @@ public:
const dictionary& dict //!< dictionary
);
//- Find the key in the dictionary and return the corresponding
//- switch value, or the default value.
// FatalError if anything is incorrect.
//- Find the key in the dictionary and use the corresponding
//- switch value or the default if not found in dictionary.
//
// FatalIOError if the switch name is incorrect.
// Specifying failsafe downgrades the FatalIOError to an IOWarning.
Switch
(
const word& key, //!< Lookup key. Uses LITERAL (not REGEX)
const dictionary& dict, //!< dictionary
const Switch deflt //!< fallback if not found
const Switch deflt, //!< fallback if not found
const bool failsafe = false //!< Warn only on bad input
);
//- Construct from Istream
//- Construct from Istream by reading a token
explicit Switch(Istream& is);
@ -191,9 +197,9 @@ public:
//- value is not found, it is added into the dictionary.
static Switch getOrAddToDict
(
const word& name, //!< Lookup key. Uses REGEX!
dictionary& dict, //!< dictionary
const Switch deflt = switchType::FALSE //!< default to add
const word& key, //!< Lookup key. Uses LITERAL (not REGEX)
dictionary& dict, //!< dictionary
const Switch deflt = switchType::FALSE //!< default value to add
);
@ -202,16 +208,26 @@ public:
//- A string representation of bool as "false" / "true"
static const char* name(const bool b) noexcept;
//- Find switchType for the given string, returning as a Switch that
//- can be tested for good() or bad().
static Switch find(const std::string& str);
//- Test if there is a switch type corresponding to the given string.
static bool found(const std::string& str);
// Member Functions
//- True if the Switch represents a valid enumeration
bool valid() const noexcept;
bool good() const noexcept;
//- True if the Switch does not represent a valid enumeration
bool bad() const noexcept { return !good(); }
//- The underlying enumeration value
switchType type() const noexcept;
//- A string representation of the Switch value
//- A C-string representation of the Switch value
const char* c_str() const noexcept;
//- A string representation of the Switch value
@ -220,8 +236,8 @@ public:
//- Update the value of the Switch if it is found in the dictionary
bool readIfPresent
(
const word& name, //!< Lookup key. Uses REGEX!
const dictionary& dict //!< dictionary
const word& key, //!< Lookup key. Uses LITERAL (not REGEX)
const dictionary& dict //!< dictionary
);
@ -230,41 +246,54 @@ public:
//- Conversion to bool
operator bool() const noexcept
{
return (switch_ & 0x1);
return (value_ & 0x1);
}
//- Assignment from enumerated value
Switch& operator=(const switchType sw) noexcept
{
switch_ = sw;
value_ = sw;
return *this;
}
//- Assignment from bool
Switch& operator=(const bool b) noexcept
{
switch_ = (b ? Switch::TRUE : Switch::FALSE);
value_ = (b ? Switch::TRUE : Switch::FALSE);
return *this;
}
// Housekeeping
//- Construct from dictionary, supplying default value so that if the
//- value is not found, it is added into the dictionary.
//- Deprecated(2020-01) From string with/without bad input test
// \deprecated(2020-01) - confusing syntax, use static find() method
FOAM_DEPRECATED_FOR(2019-02, "static find() method")
Switch(const std::string& str, bool allowBad);
//- Deprecated(2020-01) From string with/without bad input test
// \deprecated(2020-01) - confusing syntax, use static find() method
FOAM_DEPRECATED_FOR(2019-02, "static find() method")
Switch(const char* str, bool allowBad);
//- Deprecated(2020-01) Use good() method, or static found() method
// \deprecated(2020-01) Use good() method, or static found() method
FOAM_DEPRECATED_FOR(2019-02, "good() or static found() method")
bool valid() const noexcept
{
return good();
}
//- Same as getOrAddToDict()
static Switch lookupOrAddToDict
(
const word& name, //!< Lookup key. Uses REGEX!
dictionary& dict, //!< dictionary
const Switch deflt = switchType::FALSE //!< default to add
const word& name,
dictionary& dict,
const Switch deflt = switchType::FALSE
)
{
return getOrAddToDict(name, dict, deflt);
}
//- Deprecated(2018-03) text representation of the Switch value
// \deprecated(2018-03) - use c_str() method
inline const char* asText() const { return c_str(); };
};

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2018 OpenCFD Ltd.
Copyright (C) 2018-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -61,7 +61,7 @@ Foam::Istream& Foam::operator>>(Istream& is, bool& b)
Foam::Ostream& Foam::operator<<(Ostream& os, const bool b)
{
// Emit as label (not byte etc) for proper send/receive in parallel
os.write(label(b));
os.write(static_cast<label>(b));
os.check(FUNCTION_NAME);
return os;
}

View File

@ -47,9 +47,15 @@ namespace Foam
class Istream;
class Ostream;
// IOstream Operators
//- Read bool from stream using Foam::Switch(Istream&)
Istream& operator>>(Istream& is, bool& b);
//- Write bool to a stream as an label (integer) value
Ostream& operator<<(Ostream& os, const bool b);
//- Read bool from stream using Foam::Switch(Istream&)
bool readBool(Istream& is);
} // End namespace Foam

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2019 OpenCFD Ltd.
Copyright (C) 2018-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -61,9 +61,9 @@ bool Foam::scalarRange::parse(const std::string& str, scalarRange& range)
if (str.size() >= 4)
{
Switch sw(str, true);
Switch sw = Switch::find(str);
if (sw.valid())
if (sw.good())
{
if (sw)
{

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -71,10 +71,10 @@ Foam::isoSurfaceBase::getFilterType
return deflt;
}
// Try as bool
Switch sw(filterName, true);
// Try as bool/switch
Switch sw = Switch::find(filterName);
if (sw.valid())
if (sw.good())
{
return
(