Commit b886000e authored by Andrew Heather's avatar Andrew Heather Committed by Andrew Heather
Browse files

Merge branch 'feature-dictionary-checking' into 'develop'

Feature dictionary checking

See merge request OpenFOAM-plus!259
parents 515027b7 32916fa8
......@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017-2018 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2017-2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
......@@ -34,6 +34,8 @@ Description
#include "IOobject.H"
#include "IFstream.H"
#include "dictionary.H"
#include "ops.H"
#include "scalarRange.H"
#include "stringOps.H"
using namespace Foam;
......@@ -108,6 +110,42 @@ scalar try_getScalar(const dictionary& dict, const word& k)
}
// Try with getCheck<scalar>
template<class Predicate>
scalar try_getCheckScalar
(
const dictionary& dict,
const word& k,
const Predicate& pred
)
{
scalar val(-GREAT);
const bool throwingIOError = FatalIOError.throwExceptions();
const bool throwingError = FatalError.throwExceptions();
try
{
val = dict.getCheck<scalar>(k, pred);
Info<< "getCheck<scalar>(" << k << ") = " << val << nl;
}
catch (const Foam::IOerror& err)
{
Info<< "getCheck<scalar>(" << k << ") Caught FatalIOError "
<< err << nl << endl;
}
catch (const Foam::error& err)
{
Info<< "getCheck<scalar>(" << k << ") Caught FatalError "
<< err << nl << endl;
}
FatalError.throwExceptions(throwingError);
FatalIOError.throwExceptions(throwingIOError);
return val;
}
// Try with *entry (from findEntry) and get<scalar>
scalar try_getScalar(const entry* eptr, const word& k)
{
......@@ -311,6 +349,7 @@ int main(int argc, char *argv[])
IStringStream
(
"good 3.14159;\n"
"negative -3.14159;\n"
"empty;\n"
// "bad text;\n" // always fails
// "bad 3.14159 1234;\n" // fails for readScalar
......@@ -338,6 +377,26 @@ int main(int argc, char *argv[])
try_getScalar(dict2, "empty");
}
// With getCheck<scalar>
{
Info<< nl << "Test some input with getCheck<scalar>()" << nl;
try_getCheckScalar(dict2, "good", scalarRange::gt0());
try_getCheckScalar(dict2, "negative", scalarRange::gt0());
try_getCheckScalar(dict2, "good", greaterOp1<scalar>(0));
try_getCheckScalar(dict2, "negative", greaterOp1<scalar>(0));
Info<< nl << "with lambda" << nl;
try_getCheckScalar
(
dict2,
"good",
[](const scalar x) { return x > 0; }
);
}
// With findEntry and get<scalar>
{
Info<< nl
......
......@@ -27,12 +27,16 @@ Description
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "IOobject.H"
#include "IOstreams.H"
#include "IFstream.H"
#include "Switch.H"
#include "SubStrings.H"
#include "regExpCxx.H"
#ifndef _WIN32
#include "regExpPosix.H"
#endif
using namespace Foam;
......@@ -83,6 +87,7 @@ static Ostream& operator<<(Ostream& os, const regExpCxx::results_type& sm)
// Simple output of match groups
#ifndef _WIN32
static Ostream& operator<<(Ostream& os, const regExpPosix::results_type& sm)
{
for (std::smatch::size_type i = 1; i < sm.size(); ++i)
......@@ -92,6 +97,7 @@ static Ostream& operator<<(Ostream& os, const regExpPosix::results_type& sm)
return os;
}
#endif
template<class RegexType>
......@@ -209,7 +215,6 @@ void generalTests()
}
template<class RegexType>
void testExpressions(const UList<regexTest>& tests)
{
......@@ -293,11 +298,13 @@ int main(int argc, char *argv[])
"Test C++11 regular expressions"
);
#ifndef _WIN32
argList::addBoolOption
(
"posix",
"Test POSIX regular expressions"
);
#endif
argList::addArgument("file");
argList::addArgument("...");
......@@ -306,6 +313,17 @@ int main(int argc, char *argv[])
#include "setRootCase.H"
if (std::is_same<regExp, regExpCxx>::value)
{
Info<<"Foam::regExp uses C++11 regex" << nl << nl;
}
#ifndef _WIN32
if (std::is_same<regExp, regExpPosix>::value)
{
Info<<"Foam::regExp uses POSIX regex" << nl << nl;
}
#endif
if (!args.count({"cxx", "posix"}))
{
Info<< "Specified one or more of -cxx, -posix" << nl;
......@@ -321,10 +339,12 @@ int main(int argc, char *argv[])
generalTests<regExpCxx>();
}
#ifndef _WIN32
if (args.found("posix"))
{
generalTests<regExpPosix>();
}
#endif
}
for (label argi = 1; argi < args.size(); ++argi)
......@@ -339,10 +359,12 @@ int main(int argc, char *argv[])
testExpressions<regExpCxx>(tests);
}
#ifndef _WIN32
if (args.found("posix"))
{
testExpressions<regExpPosix>(tests);
}
#endif
}
Info<< "\nDone" << nl << endl;
......
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1812 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Pattern, String
(
( true "(U|k|epsilon)" "U" )
( false "(U|k|epsilon)" "alpha" )
( true "ab.*" "abc" )
( true ".*" "abc" )
)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -36,6 +36,8 @@ Description
#include "FlatOutput.H"
#include "Tuple2.H"
#include "StringStream.H"
#include "ops.H"
#include "bitSet.H"
using namespace Foam;
......@@ -44,7 +46,7 @@ void doTest(const scalarList& values, const predicates::scalars& accept)
{
// Also tests that output is suppressed
Info<<"Have: " << accept.size() << " predicates" << accept << endl;
Info<<"values: " << flatOutput(values) << endl;
Info<<"values: " << flatOutput(values) << endl;
for (const scalar& value : values)
{
......@@ -60,6 +62,30 @@ void doTest(const scalarList& values, const predicates::scalars& accept)
}
template<class Predicate>
void testPredicate(const scalarList& values, const Predicate& pred)
{
bitSet matches;
label i=0;
for (const scalar& value : values)
{
if (pred(value))
{
matches.set(i);
}
++i;
}
IndirectList<scalar> matched(values, matches.toc());
Info<< "matched: " << flatOutput(matched.addressing())
<< " = " << flatOutput(matched) << nl;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
......@@ -149,6 +175,16 @@ int main(int argc, char *argv[])
}
Info<< nl << "Test with ops" << nl;
Info<<"values: " << flatOutput(values) << endl;
{
testPredicate(values, lessOp1<scalar>(10));
testPredicate(values, greaterOp1<scalar>(100));
// Also with dissimilar type
testPredicate(values, lessEqOp1<label>(0));
}
Info<< "\nEnd\n" << endl;
return 0;
......
......@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
| Copyright (C) 2011-2016 OpenFOAM Foundation
......@@ -313,7 +313,7 @@ void rewriteField
if
(
boundaryField.found(patchName)
&& !boundaryField.found(newName, false, false)
&& !boundaryField.found(newName, keyType::LITERAL)
)
{
Info<< " Changing entry " << patchName << " to " << newName
......
......@@ -37,6 +37,8 @@ InfoSwitches
writePrecision 6;
writeDictionaries 0;
// Report optional dictionary entries. For value > 1, treat as fatal.
writeOptionalEntries 0;
// Write lagrangian "positions" file in v1706 format (and earlier)
......
......@@ -32,6 +32,7 @@ Description
#ifndef regExp_H
#define regExp_H
#include "regExpCxx.H"
#include "regExpPosix.H"
#include "regExpFwd.H"
......
......@@ -39,7 +39,12 @@ namespace Foam
class regExpCxx;
class regExpPosix;
// Newer compilers support regex directly
#if (_GLIBCXX_RELEASE >= 7) || (__clang_major__ >= 7)
typedef regExpCxx regExp;
#else
typedef regExpPosix regExp;
#endif
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......
......@@ -120,7 +120,7 @@ public:
inline ~regExpPosix();
// Member functions
// Member Functions
// Access
......
......@@ -243,8 +243,7 @@ public:
//- Deprecated(2019-01) Pointing at a valid storage node
// \deprecated(2019-01) - use good() method
inline bool found() const
FOAM_DEPRECATED_FOR(2019-01, "good() method")
bool FOAM_DEPRECATED_FOR(2019-01, "good() method") found() const
{
return this->good();
}
......@@ -297,8 +296,7 @@ public:
//- Deprecated(2019-01) Pointing at a valid storage node
// \deprecated(2019-01) - use good() method
inline bool found() const
FOAM_DEPRECATED_FOR(2019-01, "good() method")
bool FOAM_DEPRECATED_FOR(2019-01, "good() method") found() const
{
return this->good();
}
......
......@@ -219,8 +219,7 @@ public:
//- Deprecated(2019-01) Pointing at a valid storage node
// \deprecated(2019-01) - use good() method
inline bool found() const
FOAM_DEPRECATED_FOR(2019-01, "good() method")
bool FOAM_DEPRECATED_FOR(2019-01, "good() method") found() const
{
return this->good();
}
......@@ -271,8 +270,7 @@ public:
//- Deprecated(2019-01) Pointing at a valid storage node
// \deprecated(2019-01) - use good() method
inline bool found() const
FOAM_DEPRECATED_FOR(2019-01, "good() method")
bool FOAM_DEPRECATED_FOR(2019-01, "good() method") found() const
{
return this->good();
}
......
......@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015-2018 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
| Copyright (C) 2011-2017 OpenFOAM Foundation
......@@ -42,13 +42,12 @@ namespace Foam
const Foam::dictionary Foam::dictionary::null;
bool Foam::dictionary::writeOptionalEntries
int Foam::dictionary::writeOptionalEntries
(
Foam::debug::infoSwitch("writeOptionalEntries", 0)
);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::dictionary::dictionary()
......@@ -311,13 +310,30 @@ void Foam::dictionary::checkITstream
}
void Foam::dictionary::raiseBadInput(const word& keyword) const
{
// Can use FatalIOError instead of SafeFatalIOError
// since predicate checks are not used at the earliest stages
FatalIOError
(
"", // functionName
"", // sourceFileName
0, // sourceFileLineNumber
*this // ios
)
<< "Entry '" << keyword << "' with invalid input in dictionary "
<< name() << nl << nl
<< exit(FatalIOError);
}
bool Foam::dictionary::found
(
const word& keyword,
enum keyType::option matchOpt
) const
{
return csearch(keyword, matchOpt).found();
return csearch(keyword, matchOpt).good();
}
......@@ -359,11 +375,11 @@ const Foam::entry& Foam::dictionary::lookupEntry
{
const const_searcher finder(csearch(keyword, matchOpt));
if (!finder.found())
if (!finder.good())
{
FatalIOErrorInFunction(*this)
<< "Entry '" << keyword << "' not found in dictionary "
<< name()
<< name() << nl
<< exit(FatalIOError);
}
......@@ -395,7 +411,7 @@ bool Foam::dictionary::substituteKeyword(const word& keyword, bool mergeEntry)
const const_searcher finder(csearch(varName, keyType::REGEX_RECURSIVE));
// If defined insert its entries into this dictionary
if (finder.found())
if (finder.good())
{
for (const entry& e : finder.dict())
{
......@@ -427,7 +443,7 @@ bool Foam::dictionary::substituteScopedKeyword
const auto finder(csearchScoped(varName, keyType::REGEX_RECURSIVE));
// If defined insert its entries into this dictionary
if (finder.found())
if (finder.good())
{
for (const entry& e : finder.dict())
{
......@@ -473,11 +489,11 @@ const Foam::dictionary& Foam::dictionary::subDict(const word& keyword) const
// Allow patterns, non-recursive
const const_searcher finder(csearch(keyword, keyType::REGEX));
if (!finder.found())
if (!finder.good())
{
FatalIOErrorInFunction(*this)
<< "Entry '" << keyword << "' not found in dictionary "
<< name()
<< name() << nl
<< exit(FatalIOError);
}
......@@ -490,11 +506,11 @@ Foam::dictionary& Foam::dictionary::subDict(const word& keyword)
// Allow patterns, non-recursive
searcher finder(search(keyword, keyType::REGEX));
if (!finder.found())
if (!finder.good())
{
FatalIOErrorInFunction(*this)
<< "Entry '" << keyword << "' not found in dictionary "
<< name()
<< name() << nl
<< exit(FatalIOError);
}
......@@ -526,7 +542,7 @@ Foam::dictionary Foam::dictionary::subOrEmptyDict
<< exit(FatalIOError);
}
if (finder.found())
if (finder.good())
{
IOWarningInFunction(*this)
<< "Entry '" << keyword
......@@ -552,7 +568,7 @@ const Foam::dictionary& Foam::dictionary::optionalSubDict
return finder.dict();
}
if (finder.found())
if (finder.good())
{
IOWarningInFunction(*this)
<< "Entry '" << keyword
......@@ -611,7 +627,7 @@ Foam::entry* Foam::dictionary::add(entry* entryPtr, bool mergeEntry)
auto iter = hashedEntries_.find(entryPtr->keyword());
if (mergeEntry && iter.found())
if (mergeEntry && iter.good())
{
// Merge dictionary with dictionary
if (iter()->isDict() && entryPtr->isDict())
......@@ -786,7 +802,7 @@ bool Foam::dictionary::merge(const dictionary& dict)
{
auto fnd = hashedEntries_.find(e.keyword());
if (fnd.found())
if (fnd.good())
{
// Recursively merge sub-dictionaries
// TODO: merge without copying
......
......@@ -62,8 +62,8 @@ Note
key2 $..key1; // use key1 value from parent
subdict2
{
key2 val2;
key3 $...key1; // use key1 value from grandparent
key2 val2;
key3 $...key1; // use key1 value from grandparent
}
}
......@@ -285,8 +285,9 @@ private:
// Private Data
//- Report optional keywords and values if not present in dictionary
// For value greater than 1: fatal.
// Set/unset via an InfoSwitch
static bool writeOptionalEntries;
static int writeOptionalEntries;
//- The dictionary name
fileName name_;
......@@ -359,6 +360,10 @@ private:
) const;
//- Emit IOError about bad input for the entry
void raiseBadInput(const word& keyword) const;
public:
// Declare name of the class and its debug switch
......@@ -532,7 +537,6 @@ public:
enum keyType::option matchOpt = keyType::REGEX
);
//- Search for an entry (const access) with the given keyword.
//- Find and return a sub-dictionary pointer if present
// (and a sub-dictionary) otherwise return nullptr.
//
......@@ -543,6 +547,7 @@ public:
enum keyType::option matchOpt = keyType::REGEX
) const;
//- Search for an entry (const access) with the given keyword.
//
// \param matchOpt the default search is non-recursive with patterns
//
......@@ -553,22 +558,22 @@ public:
enum keyType::option matchOpt
) const;
//- Find and return a T.
//- Find and return an entry data stream.
//- FatalIOError if not found, or if the number of tokens is incorrect.
//
// \param matchOpt the default search is non-recursive with patterns
template<class T>
T get
ITstream& lookup
(
const word& keyword,
enum keyType::option matchOpt = keyType::REGEX
) const;
//- Find and return an entry data stream.
//- Find and return a T.
//- FatalIOError if not found, or if the number of tokens is incorrect.
//
// \param matchOpt the default search is non-recursive with patterns
ITstream& lookup
template<class T>
T get
(
const word& keyword,
enum keyType::option matchOpt = keyType::REGEX
......@@ -579,7 +584,7 @@ public:
//
// \param matchOpt the default search is non-recursive with patterns
template<class T>
T lookupOrDefault
T getOrDefault
(
const word& keyword,
const T& deflt,
......@@ -592,7 +597,7 @@ public:
//
// \param matchOpt the default search is non-recursive with patterns
template<class T>
T lookupOrAddDefault
T getOrAdd
(
const word& keyword,
const T& deflt,
......@@ -633,6 +638,86 @@ public:
enum keyType::option matchOpt = keyType::REGEX
) const;
//- Find and return a T with additional checking
//- FatalIOError if not found, or if the number of tokens is incorrect.
//
// \param pred the value check predicate