Commit bb53e8ad authored by Mark Olesen's avatar Mark Olesen
Browse files

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.
parent ed4bd548
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
(
......
......@@ -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())
{
(*this) = sw;
}
else
{
FatalIOErrorInFunction(dict)
<< "Expected 'true/false', 'on/off' ... found " << str << nl
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>());
(*this) = parse(str, true);
Switch sw(tok);
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())
{
sw = bool(t.labelToken());
}
else if (t.isWord())
if (sw.good())
{
// 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;
}
......
......@@ -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)
: