ENH: add failsafe accessors for ITstream

- failsafe examine elements: peek(), peekFirst(), peekLast()
- failsafe traversing: skip()

  For example,

      ITstream& is = dict.lookup(key);
      if (is.peek().isWord())
      {
          is.skip();
      }
This commit is contained in:
Mark Olesen
2021-04-16 16:49:45 +02:00
parent 9dc3d2bf40
commit b267f8b6da
3 changed files with 241 additions and 85 deletions

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017 OpenCFD Ltd.
Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -78,7 +78,7 @@ void printTokens(Istream& is)
if (t.good())
{
++count;
Info<<"token: " << t << endl;
Info<< "token: " << t << endl;
}
}
@ -86,14 +86,28 @@ void printTokens(Istream& is)
}
template<class BUF>
void doTest(const string& name, const BUF& input, bool verbose=false)
Ostream& reportPeek(const ITstream& is)
{
Info<<"test " << name.c_str() << ":" << nl
<<"====" << nl;
Info<< " index : " << is.tokenIndex() << nl
<< " peek : " << is.peek().info() << nl;
return Info;
}
template<class BUF>
void doTest
(
const string& name,
const BUF& input,
bool verbose = false,
bool testskip = false
)
{
Info<< "test " << name.c_str() << ":" << nl
<< "====" << nl;
toString(Info, input)
<< nl
<<"====" << nl << endl;
<< "====" << nl << endl;
ITstream its(name, input);
Info<< "got " << its.size() << " tokens - index at "
@ -107,6 +121,35 @@ void doTest(const string& name, const BUF& input, bool verbose=false)
}
Info<< nl;
}
if (testskip)
{
Info<< " first : " << its.peekFirst().info() << nl
<< " last : " << its.peekLast().info() << nl;
Info<< "rewind():" << nl;
reportPeek(its);
its.skip(3);
Info<< "skip(3):" << nl;
reportPeek(its);
its.skip(2);
Info<< "skip(2):" << nl;
reportPeek(its);
its.skip(-2);
Info<< "skip(-2):" << nl;
reportPeek(its);
its.skip(100);
Info<< "skip(100):" << nl;
reportPeek(its);
its.skip(-1000);
Info<< "skip(-1000):" << nl;
reportPeek(its);
}
}
@ -116,14 +159,16 @@ void doTest(const string& name, const BUF& input, bool verbose=false)
int main(int argc, char *argv[])
{
const char* charInput =
"( const char input \"string\" to tokenize )"
"( const char input \"string\" to tokenize )\n"
"List<label> 5(0 1 2 3 4);";
string stringInput("( string ; input \"string\" to tokenize )");
List<char> listInput(stringInput.cbegin(), stringInput.cend());
doTest("char*", charInput, true);
doTest("empty", "", true, true);
doTest("char*", charInput, true, true);
doTest("string", stringInput, true);
doTest("List<char>", listInput, true);

View File

@ -31,6 +31,31 @@ License
#include "StringStream.H"
#include "UIListStream.H"
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace
{
// Failsafe read-access.
// Return the token at location, or undefinedToken.
inline static const Foam::token& peekTokenAt
(
const Foam::UList<Foam::token>& list,
const Foam::label i
)
{
return
(
i >= 0 && i < list.size()
? list[i]
: Foam::token::undefinedToken
);
}
} // End anonymous namespace
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::label Foam::ITstream::parseStream(ISstream& is, tokenList& tokens)
@ -270,20 +295,21 @@ void Foam::ITstream::print(Ostream& os) const
{
os << "ITstream : " << name_.c_str() << ", line ";
if (size())
{
os << tokenList::first().lineNumber();
const tokenList& toks = *this;
if (tokenList::first().lineNumber() < tokenList::last().lineNumber())
{
os << '-' << tokenList::last().lineNumber();
}
}
else
if (toks.empty())
{
os << lineNumber();
}
else
{
os << toks.first().lineNumber();
if (toks.first().lineNumber() < toks.last().lineNumber())
{
os << '-' << toks.last().lineNumber();
}
}
os << ", ";
IOstream::print(os);
@ -292,44 +318,155 @@ void Foam::ITstream::print(Ostream& os) const
std::string Foam::ITstream::toString() const
{
OStringStream buf;
const tokenList& tokens = *this;
label len = tokens.size();
// NOTE: may wish to have special handling if there is a single token
// and it is already a string or word
for (const token& tok : tokens)
OStringStream buf;
unsigned i = 0;
for (const token& tok : *this)
{
buf << tok;
if (--len)
if (i++)
{
buf << ' ';
}
buf << tok;
}
return buf.str();
}
const Foam::token& Foam::ITstream::peekFirst() const
{
return peekTokenAt(*this, 0);
}
const Foam::token& Foam::ITstream::peekLast() const
{
return peekTokenAt(*this, tokenList::size()-1);
}
const Foam::token& Foam::ITstream::peek() const
{
// Use putback token if it exists
if (Istream::hasPutback())
{
return Istream::peekBack();
}
return peekTokenAt(*this, tokenIndex_);
}
void Foam::ITstream::seek(label pos)
{
lineNumber_ = 0;
const tokenList& toks = *this;
const label nToks = toks.size();
if (!pos)
{
// Seek begin (rewind)
tokenIndex_ = 0;
if (nToks)
{
lineNumber_ = toks.first().lineNumber();
}
setOpened();
setGood();
}
else if (pos < 0 || pos >= nToks)
{
// Seek end or seek is out of range
tokenIndex_ = nToks;
if (nToks)
{
lineNumber_ = toks.last().lineNumber();
}
setEof();
}
else
{
// Seek middle (from the beginning)
tokenIndex_ = pos;
if (nToks)
{
lineNumber_ = toks[tokenIndex_].lineNumber();
}
setOpened();
setGood();
}
}
void Foam::ITstream::skip(label n)
{
const tokenList& toks = *this;
const label nToks = toks.size();
if (n < 0)
{
// Move backwards
while (n++ && tokenIndex_)
{
--tokenIndex_;
}
if (tokenIndex_ < nToks)
{
lineNumber_ = toks[tokenIndex_].lineNumber();
setOpened();
setGood();
}
}
else if (n > 0)
{
// Move forward
while (n-- && tokenIndex_ < nToks)
{
++tokenIndex_;
}
if (tokenIndex_ < nToks)
{
lineNumber_ = toks[tokenIndex_].lineNumber();
setOpened();
setGood();
}
else
{
setEof();
}
}
}
Foam::Istream& Foam::ITstream::read(token& tok)
{
// Return the put back token if it exists
// Use putback token if it exists
if (Istream::getBack(tok))
{
lineNumber_ = tok.lineNumber();
return *this;
}
if (tokenIndex_ < size())
tokenList& toks = *this;
const label nToks = toks.size();
if (tokenIndex_ < nToks)
{
tok = operator[](tokenIndex_++);
tok = toks[tokenIndex_++];
lineNumber_ = tok.lineNumber();
if (tokenIndex_ == size())
if (tokenIndex_ == nToks)
{
setEof();
}
@ -350,9 +487,9 @@ Foam::Istream& Foam::ITstream::read(token& tok)
tok.reset();
if (size())
if (nToks)
{
tok.lineNumber(tokenList::last().lineNumber());
tok.lineNumber(toks.last().lineNumber());
}
else
{
@ -426,52 +563,6 @@ void Foam::ITstream::rewind()
}
void Foam::ITstream::seek(label pos)
{
lineNumber_ = 0;
tokenList& toks = *this;
if (!pos)
{
// Seek begin (rewind)
tokenIndex_ = 0;
if (!toks.empty())
{
lineNumber_ = toks.first().lineNumber();
}
setOpened();
setGood();
}
else if (pos < 0 || pos >= toks.size())
{
// Seek end or seek is out of range
tokenIndex_ = toks.size();
if (!toks.empty())
{
lineNumber_ = toks.last().lineNumber();
}
setEof();
}
else
{
// Seek middle (from the beginning)
tokenIndex_ = pos;
if (!toks.empty())
{
lineNumber_ = toks[tokenIndex_].lineNumber();
}
setOpened();
setGood();
}
}
void Foam::ITstream::append(const token& t, const bool lazy)
{
reserveCapacity(tokenIndex_ + 1, lazy);

View File

@ -187,29 +187,49 @@ public:
// Token Access
//- Failsafe peek at the \b first token in the list.
// \return \c undefinedToken if the list is empty.
const token& peekFirst() const;
//- Failsafe peek at the \b last token in the list.
// \return \c undefinedToken if the list is empty.
const token& peekLast() const;
//- Failsafe peek at what the next read would return,
// including handling of any putback
// \return \c undefinedToken if list is exhausted
const token& peek() const;
//- The current token index when reading, or the insertion point.
label tokenIndex() const
label tokenIndex() const noexcept
{
return tokenIndex_;
}
//- Non-const access to the current token index
label& tokenIndex()
label& tokenIndex() noexcept
{
return tokenIndex_;
}
//- The number of remaining tokens
label nRemainingTokens() const
//- Number of tokens remaining
label nRemainingTokens() const noexcept
{
return size() - tokenIndex_;
}
//- Move the tokenIndex to the specified position.
//- Move tokenIndex to the specified position
// Using seek(0) is identical to rewind.
// Using seek(-1) moves to the end.
void seek(label pos);
//- Move tokenIndex relative to the current position.
// Will not overrun the beginning or end positions.
//
// Use skip(2) to move forward two tokens.
// Use skip(-2) to move backward two tokens.
void skip(label n = 1);
// Inquiry