Commit 41f59b07 authored by Mark Olesen's avatar Mark Olesen
Browse files

ENH: improve consistency in parsing primitives from strings (issue #590)

- Any trailing whitespace when parsing from strings or character buffers
  is ignored rather than being treated as an error. This is consistent
  with behaviour when reading from an Istream and with leading whitespace
  being ignored in the underlying atof/atod, strtof/strtod... functions.

- Allow parsing directly from a std::string instead of just from a 'char*'.
  This reflects the C++11 addition of std::stod to complement the C
  functions strtod. This also makes it easier to parse string directly
  without using an IStringStream.

- Two-parameter parsing methods return success/failure.
  Eg,

      if (readInt32(str, &int32Val)) ...

- One-parameter parsing methods return the value on success or
  emit a FatalIOError.
  Eg,

      const char* buf;
      int32Val = readInt32(buf, &);

- Improved consistency when parsing unsigned ints.
  Use strtoimax and strtoumax throughout.

- Rename readDoubleScalar -> readDouble, readFloatScalar -> readFloat.
  Using the primitive name directly instead of the Foam typedef for
  better consistency with readInt32 etc.

- Clean/improve parseNasScalar.
  Handle normal numbers directly, reduce some operations.
parent 3cb9c66c
Test-primitives.C
EXE = $(FOAM_USER_APPBIN)/Test-primitives
EXE_INC = \
-I$(LIB_SRC)/fileFormats/lnInclude
EXE_LIBS = \
-lfileFormats
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
Application
Test-primitives
Description
Parsing etc for primitives.
\*---------------------------------------------------------------------------*/
#include "scalar.H"
#include "label.H"
#include "StringStream.H"
#include "NASCore.H"
#include "parsing.H"
#include "Tuple2.H"
using namespace Foam;
// Shadow fileFormats::NASCore::readNasScalar
inline scalar readNasScalar(const std::string& str)
{
return fileFormats::NASCore::readNasScalar(str);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class TYPE>
unsigned testParsing
(
TYPE (*function)(const std::string&),
const List<Tuple2<std::string, bool>>& tests
)
{
unsigned nFail = 0;
// Expect some failures
const bool prev = FatalIOError.throwExceptions();
for (const Tuple2<std::string, bool>& test : tests)
{
const std::string& str = test.first();
const bool expected = test.second();
bool parsed = true;
TYPE val;
try
{
val = function (str);
}
catch (Foam::error& err)
{
parsed = false;
}
if (parsed)
{
if (expected)
{
Info<< "(pass) parsed " << str << " = " << val << nl;
}
else
{
++nFail;
Info<< "(fail) unexpected success for " << str << nl;
}
}
else
{
if (expected)
{
++nFail;
Info<< "(fail) unexpected failure " << str << nl;
}
else
{
Info<< "(pass) expected failure " << str << nl;
}
}
}
FatalIOError.throwExceptions(prev);
return nFail;
}
int main(int argc, char *argv[])
{
unsigned nFail = 0;
{
Info<< nl << "Test readDouble:" << nl;
nFail += testParsing
(
&readDouble,
{
{ "", false },
{ " ", false },
{ " xxx ", false },
{ " 1234E-", false },
{ " 1234E junk", false },
{ " 3.14159 ", true },
{ " 31.4159E-1 " , true },
}
);
}
{
Info<< nl << "Test readFloat:" << nl;
nFail += testParsing
(
&readFloat,
{
{ " 3.14159 ", true },
{ " 31.4159E-1 " , true },
{ " 31.4159E200 " , false },
{ " 31.4159E20 " , true },
}
);
}
{
Info<< nl << "Test readNasScalar:" << nl;
nFail += testParsing
(
&readNasScalar,
{
{ " 3.14159 ", true },
{ " 31.4159E-1 " , true },
{ " 314.159-2 " , true },
{ " 31.4159E200 " , true },
{ " 31.4159E20 " , true },
}
);
}
{
Info<< nl << "Test readInt32 (max= " << INT32_MAX << "):" << nl;
nFail += testParsing
(
&readInt32,
{
{ " 3.14159 ", false },
{ " 31.4159E-1 " , false },
{ "100" , true },
{ " 2147483644" , true },
{ " 2147483700 " , false },
}
);
}
{
Info<< nl << "Test readUint32 (max= " << INT32_MAX << "):" << nl;
nFail += testParsing
(
&readUint32,
{
{ " 2147483644" , true },
{ " 2147483700 " , true },
}
);
}
if (nFail)
{
Info<< nl << "failed " << nFail << " tests" << nl;
return 1;
}
Info<< nl << "passed all tests" << nl;
return 0;
}
// ************************************************************************* //
......@@ -28,7 +28,7 @@ License
#include "IFstream.H"
#include "StringStream.H"
#include <inttypes.h>
#include <cinttypes>
#include <cxxabi.h>
#include <execinfo.h>
#include <dlfcn.h>
......
......@@ -114,6 +114,7 @@ $(strings)/wordRe/wordRe.C
$(strings)/wordRes/wordRes.C
$(strings)/lists/hashedWordList.C
$(strings)/stringOps/stringOps.C
$(strings)/parsing/parsing.C
ops = primitives/ops
$(ops)/flipOp.C
......
......@@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
\\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -42,9 +42,9 @@ const Scalar pTraits<Scalar>::rootMax = ScalarROOTVGREAT;
const char* const pTraits<Scalar>::componentNames[] = { "" };
pTraits<Scalar>::pTraits(const Scalar& p)
pTraits<Scalar>::pTraits(const Scalar& val)
:
p_(p)
p_(val)
{}
......@@ -54,7 +54,7 @@ pTraits<Scalar>::pTraits(Istream& is)
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * * IO/Conversion * * * * * * * * * * * * * * * //
word name(const Scalar val)
{
......@@ -76,18 +76,59 @@ word name(const std::string& fmt, const Scalar val)
}
Scalar ScalarRead(const char* buf)
{
char* endptr = nullptr;
errno = 0;
const Scalar val = ScalarConvert(buf, &endptr);
const parsing::errorType err = parsing::checkConversion(buf, endptr);
if (err != parsing::errorType::NONE)
{
FatalIOErrorInFunction("unknown")
<< parsing::errorNames[err] << " '" << buf << "'"
<< exit(FatalIOError);
}
return val;
}
bool readScalar(const char* buf, Scalar& val)
{
char* endptr = nullptr;
errno = 0;
val = ScalarConvert(buf, &endptr);
const parsing::errorType err = parsing::checkConversion(buf, endptr);
if (err != parsing::errorType::NONE)
{
#ifdef FULLDEBUG
IOWarningInFunction("unknown")
<< parsing::errorNames[err] << " '" << buf << "'"
<< endl;
#endif
return false;
}
return true;
}
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
Scalar readScalar(Istream& is)
Scalar ScalarRead(Istream& is)
{
Scalar rs;
is >> rs;
Scalar val;
is >> val;
return rs;
return val;
}
Istream& operator>>(Istream& is, Scalar& s)
Istream& operator>>(Istream& is, Scalar& val)
{
token t(is);
......@@ -99,7 +140,7 @@ Istream& operator>>(Istream& is, Scalar& s)
if (t.isNumber())
{
s = t.number();
val = t.number();
}
else
{
......@@ -116,9 +157,9 @@ Istream& operator>>(Istream& is, Scalar& s)
}
Ostream& operator<<(Ostream& os, const Scalar s)
Ostream& operator<<(Ostream& os, const Scalar val)
{
os.write(s);
os.write(val);
os.check(FUNCTION_NAME);
return os;
}
......
......@@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
\\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -25,7 +25,7 @@ Typedef
Foam::Scalar
Description
Single floating point number (float or double)
Floating-point number (float or double)
SourceFiles
Scalar.C
......@@ -81,10 +81,10 @@ public:
// Constructors
//- Construct from primitive
explicit pTraits(const Scalar&);
explicit pTraits(const Scalar& val);
//- Construct from Istream
pTraits(Istream&);
pTraits(Istream& is);
// Member Functions
......@@ -103,22 +103,48 @@ public:
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * * IO/Conversion * * * * * * * * * * * * * * * //
//- Return a string representation of a Scalar
word name(const Scalar);
word name(const Scalar val);
//- Return a word representation of a Scalar, using printf-style formatter.
// The representation is not checked for valid word characters.
word name(const char* fmt, const Scalar);
word name(const char* fmt, const Scalar val);
//- Return a word representation of a Scalar, using printf-style formatter.
// The representation is not checked for valid word characters.
word name(const std::string& fmt, const Scalar);
word name(const std::string& fmt, const Scalar val);
//- Parse entire buffer as a float/double, skipping leading/trailing whitespace.
// \return Parsed value or FatalIOError on any problem
Scalar ScalarRead(const char* buf);
//- Parse entire string as a float/double, skipping leading/trailing whitespace.
// \return Parsed value or FatalIOError on any problem
inline Scalar ScalarRead(const std::string& str)
{
return ScalarRead(str.c_str());
}
//- Parse entire buffer as a float/double, skipping leading/trailing whitespace.
// \return True if successful.
bool readScalar(const char* buf, Scalar& val);
//- Parse entire string as a float/double, skipping leading/trailing whitespace.
// \return True if successful.
inline bool readScalar(const std::string& str, Scalar& val)
{
return readScalar(str.c_str(), val);
}
Scalar ScalarRead(Istream& is);
Istream& operator>>(Istream& is, Scalar& val);
Ostream& operator<<(Ostream& os, const Scalar val);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Standard C++ transcendental functions
transFunc(sqrt)
......@@ -344,8 +370,8 @@ inline Scalar cmptMag(const Scalar s)
inline Scalar sqrtSumSqr(const Scalar a, const Scalar b)
{
Scalar maga = mag(a);
Scalar magb = mag(b);
const Scalar maga = mag(a);
const Scalar magb = mag(b);
if (maga > magb)
{
......@@ -372,12 +398,6 @@ inline Scalar stabilise(const Scalar s, const Scalar small)
}
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
Scalar readScalar(Istream&);
Istream& operator>>(Istream&, Scalar&);
Ostream& operator<<(Ostream&, const Scalar);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
......
......@@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -24,24 +24,32 @@ License
\*---------------------------------------------------------------------------*/
#include "doubleScalar.H"
#include "error.H"
#include "parsing.H"
#include "IOstreams.H"
#include <sstream>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Scalar.C is used for template-like substitution
#define Scalar doubleScalar
#define ScalarVGREAT doubleScalarVGREAT
#define ScalarVSMALL doubleScalarVSMALL
#define ScalarROOTVGREAT doubleScalarROOTVGREAT
#define ScalarROOTVSMALL doubleScalarROOTVSMALL
#define readScalar readDoubleScalar
#define ScalarRead readDouble
#define ScalarConvert ::strtod
#include "Scalar.C"
#undef Scalar
#undef ScalarVGREAT
#undef ScalarVSMALL
#undef ScalarROOTVGREAT
#undef ScalarROOTVSMALL
#undef readScalar
#undef ScalarRead
#undef ScalarConvert
// ************************************************************************* //
......@@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -25,7 +25,7 @@ Typedef
Foam::doubleScalar
Description
Double precision floating point scalar type.
Floating-point double precision scalar type.
SourceFiles
doubleScalar.C
......@@ -59,48 +59,20 @@ static const doubleScalar doubleScalarROOTSMALL = 3.0e-8;
static const doubleScalar doubleScalarVSMALL = 1.0e-300;
static const doubleScalar doubleScalarROOTVSMALL = 1.0e-150;
//- Read whole of buf as a scalar. Return true if succesful.
inline bool readScalar(const char* buf, doubleScalar& s)
{
char* endPtr;
s = strtod(buf, &endPtr);
return (*endPtr == '\0');
}
#define Scalar doubleScalar
#define ScalarVGREAT doubleScalarVGREAT
#define ScalarVSMALL doubleScalarVSMALL
#define ScalarROOTVGREAT doubleScalarROOTVGREAT
#define ScalarROOTVSMALL doubleScalarROOTVSMALL
#define readScalar readDoubleScalar
#define ScalarRead readDouble
inline Scalar mag(const Scalar s)
{
return ::fabs(s);
}
#define transFunc(func) \
inline Scalar func(const Scalar s) \
{ \
return ::func(s); \
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "Scalar.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
inline Scalar hypot(const Scalar x, const Scalar y)
{
return ::hypot(x, y);
......@@ -121,19 +93,30 @@ inline Scalar yn(const int n, const Scalar s)
return ::yn(n, s);
}
// Normal (double-precision) transcendental functions
#define transFunc(func) \
inline Scalar func(const Scalar s) \
{ \
return ::func(s); \
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "Scalar.H"
#undef Scalar
#undef ScalarVGREAT
#undef ScalarVSMALL
#undef ScalarROOTVGREAT
#undef ScalarROOTVSMALL
#undef readScalar
#undef ScalarRead
#undef transFunc
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
......
......@@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -24,24 +24,32 @@ License
\*---------------------------------------------------------------------------*/
#include "floatScalar.H"
#include "error.H"
#include "parsing.H"
#include "IOstreams.H"
#include <sstream>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Scalar.C is used for template-like substitution