mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
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:
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user