# PhasicFlow: src/phasicFlow/streams/Stream/Istream.cpp Source File
PhasicFlow is an open-source parallel DEM (discrete element method) package for simulating granular flow. It is developed in C++ and can be exectued on both GPU (like CUDA) and CPU.

Istream.cpp
Go to the documentation of this file.
/*------------------------------- phasicFlow ---------------------------------
O C enter of
O O E ngineering and
O O M ultiscale modeling of
OOOOOOO F luid flow
------------------------------------------------------------------------------
Copyright (C): www.cemf.ir
email: hamid.r.norouzi AT gmail.com
------------------------------------------------------------------------------
Licence:
This file is part of phasicFlow code. It is a free software for simulating
granular and multiphase flows. You can redistribute it and/or modify it under
the terms of GNU General Public License v3 or any other later versions.
phasicFlow is distributed to help others in their research in the field of
granular and multiphase flows, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-----------------------------------------------------------------------------*/
#include "Istream.hpp"
#include "token.hpp"
#include "error.hpp"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
// Truncate error message for readability
static constexpr const unsigned errLen = 80;
namespace
{
// Convert a single character to a word with length 1
inline static pFlow::word charToWord(char c)
{
return pFlow::word(std::string(1, c), false);
}
// Permit slash-scoping of entries
static inline bool validVariableChar(char c)
{
return (pFlow::validWord(c) || c == '/');
}
} // End anonymous namespace
char pFlow::Istream::nextValid()
{
char c = 0;
while (true)
{
// Get next non-whitespace character
while (get(c) && isspace(c))
{}
// Return if stream is bad - ie, previous get() failed
if (bad() || isspace(c))
{
return 0;
}
// Is this the start of a C/C++ comment?
if (c == '/')
{
if (!get(c))
{
// Cannot get another character - return this one
return '/';
}
if (c == '/')
{
// C++ style single-line comment - skip through past end-of-line
while (get(c) && c != '\n')
{}
}
else if (c == '*')
{
// Within a C-style comment
while (true)
{
// Search for end of C-style comment - '*/'
if (get(c) && c == '*')
{
if (get(c))
{
if (c == '/')
{
// matched '*/'
break;
}
else if (c == '*')
{
// check again
putback(c);
}
}
}
if (!good())
{
return 0;
}
}
}
else
{
// The '/' did not start a C/C++ comment - return it
putback(c);
return '/';
}
}
else
{
// A valid character - return it
return c;
}
}
return 0;
}
void pFlow::Istream::readWordToken(token& t)
{
word val;
if (read(val).bad())
{
t.setBad();
}
else
{
t = std::move(val); // Move contents to token
}
}
pFlow::Istream& pFlow::Istream::readVariable(word& str)
{
constexpr const unsigned maxLen = 1024;
static char buf[maxLen];
unsigned nChar = 0;
unsigned depth = 0; // Track depth of (..) or {..} nesting
char c;
// First character must be '$'
if (!get(c) || c != token::DOLLAR)
{
ioErrorInFile( name(), lineNumber())
<< "Invalid first character found : " << c << nl;
fatalExit;
}
buf[nChar++] = c;
// Next character should also exist.
// This should never fail, since it was checked before calling.
if (!get(c))
{
str.assign(buf, nChar);
warningInFunction
<< "Truncated variable name : " << str << nl;
return *this;
}
buf[nChar++] = c;
str.clear();
if (c == token::BEGIN_BLOCK)
{
// Processing ${...} style.
++depth;
// Could check that the next char is good and not one of '{}'
// since this would indicate "${}", "${{..." or truncated "${"
while (get(c))
{
buf[nChar++] = c;
if (nChar == maxLen)
{
str.append(buf, nChar);
nChar = 0;
}
if (c == token::BEGIN_BLOCK)
{
++depth;
}
else if (c == token::END_BLOCK)
{
--depth;
if (!depth)
{
// Found closing '}' character
str.append(buf, nChar);
return *this;
}
}
}
// Should never reach here on normal input
str.append(buf, nChar); // Finalize pending buffer input
nChar = str.length();
if (str.length() > errLen)
{
str.erase(errLen);
}
ioErrorInFile(name(), lineNumber())
<< "stream terminated while reading variable '"
<< str.c_str() << "...' [" << static_cast< int32 >(nChar) << "]\n";
fatalExit;
return *this;
}
else if (validVariableChar(c))
{
// Processing $var style
while
(
(nChar < maxLen) && get(c)
&& (validVariableChar(c))
)
{
if (c == token::BEGIN_LIST)
{
++depth;
}
else if (c == token::END_LIST)
{
if (!depth)
{
break; // Closed ')' without an opening '(' ? ... stop
}
--depth;
}
buf[nChar++] = c;
}
}
else
{
// Invalid character. Terminate string (for message) without
// including the invalid character in the count.
buf[nChar--] = '\0';
warningInFunction
<< "Bad variable name: " << buf << nl << endl;
}
if (nChar >= maxLen)
{
buf[errLen] = '\0';
ioErrorInFile(name(), lineNumber())
<< "variable '" << buf << "...'\n"
<< " is too long (max. " << static_cast< int32 >(maxLen) << " characters)";
fatalExit;
return *this;
}
buf[nChar] = '\0'; // Terminate string
if (bad())
{
// Could probably skip this check
buf[errLen] = '\0';
ioErrorInFile(name(), lineNumber())
<< "Problem while reading variable '" << buf << "...' after "
<< static_cast< int32 >(nChar) << " characters\n";
fatalExit;
ioErrorInFile(name(), lineNumber());
return *this;
}
if (depth)
{
warningInFunction
<< "Missing " << static_cast< int32 >(depth)
<< " closing ')' while parsing" << nl << nl
<< buf << nl << endl;
}
// Finalize
str.assign(buf, nChar);
putback(c);
return *this;
}
pFlow::Istream::Istream
(
std::istream& is,
const word& streamName,
writeFormat wf
)
:
iIstream(wf),
name_(streamName),
is_(is)
{
if (is_.good())
{
setOpened();
setGood();
}
else
{
setState(is_.rdstate());
}
}
pFlow::Istream& pFlow::Istream::get(char& c)
{
is_.get(c);
setState(is_.rdstate());
if (good() && c == '\n')
{
++lineNumber_;
}
return *this;
}
int pFlow::Istream::peek()
{
return is_.peek();
}
pFlow::Istream& pFlow::Istream::getLine(std::string& str, char delim)
{
std::getline(is_, str, delim);
setState(is_.rdstate());
if (delim == '\n')
{
++lineNumber_;
}
return *this;
}
std::streamsize pFlow::Istream::getLine(std::nullptr_t, char delim)
{
is_.ignore(std::numeric_limits<std::streamsize>::max(), delim);
setState(is_.rdstate());
std::streamsize count = is_.gcount();
if (count && delim == '\n')
{
++lineNumber_;
}
return count;
}
pFlow::Istream& pFlow::Istream::putback(const char c)
{
if (c == '\n')
{
--lineNumber_;
}
if (!is_.putback(c))
{
setBad();
}
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(token& t)
{
constexpr const unsigned maxLen = 128; // Max length for units/scalars
static char buf[maxLen];
// Return the put back token if it exists
if (Istream::getBack(t))
{
return *this;
}
// Assume that the streams supplied are in working order.
// Lines are counted by '\n'
// Get next 'valid character': i.e. proceed through any whitespace
// and/or comments until a semantically valid character is found
char c = nextValid();
// Set the line number of this token to the current stream line number
t.lineNumber() = lineNumber();
// Return on error
if (!c)
{
t.setBad();
return *this;
}
// Analyse input starting with this character.
switch (c)
{
// Check for punctuation first - same as token::isseparator()
case token::END_STATEMENT :
case token::BEGIN_LIST :
case token::END_LIST :
case token::BEGIN_SQR :
case token::END_SQR :
case token::BEGIN_BLOCK :
case token::END_BLOCK :
case token::COLON :
case token::COMMA :
case token::DIVIDE :
{
t = token::punctuationToken(c);
return *this;
}
// String: enclosed by double quotes.
case token::BEGIN_STRING :
{
putback(c);
word val;
if (readString(val).bad())
{
t.setBad();
}
else
{
t = std::move(val); // Move contents to token
}
return *this;
}
// Dictionary variable (as rvalue)
case token::DOLLAR :
{
char nextC;
if (read(nextC).bad())
{
// Return lone '$' as word
t = charToWord(c);
}
else
{
// Put back both so that '$...' is included in the variable
putback(nextC);
putback(c);
word val;
if (readVariable(val).bad())
{
t.setBad();
}
else
{
t = std::move(val); // Move contents to token
t.setType(token::tokenType::VARIABLE);
}
}
return *this;
}
// Number: integer or floating point
//
// ideally match the equivalent of this regular expression
//
// /[-+]?([0-9]+\.?[0-9]*|\.[0-9]+)([Ee][-+]?[0-9]+)?/
//
case '-' :
case '.' :
case '0' : case '1' : case '2' : case '3' : case '4' :
case '5' : case '6' : case '7' : case '8' : case '9' :
{
int64 int64Val = (c != '.'); // used as bool here
unsigned nChar = 0;
buf[nChar++] = c;
// get everything that could resemble a number and let
// readScalar determine the validity
while
(
is_.get(c)
&& (
isdigit(c)
|| c == '+'
|| c == '-'
|| c == '.'
|| c == 'E'
|| c == 'e'
)
)
{
if (int64Val)
{
int64Val = isdigit(c);
}
buf[nChar++] = c;
if (nChar == maxLen)
{
// Runaway argument - avoid buffer overflow
buf[maxLen-1] = '\0';
ioErrorInFile( name(), lineNumber())
<< "number '" << buf << "...'\n"
<< " is too long (max. " <<
static_cast< int32 >(maxLen) << " characters)";
fatalExit;
t.setBad();
return *this;
}
}
buf[nChar] = '\0'; // Terminate string
setState(is_.rdstate());
if (is_.bad())
{
t.setBad();
}
else
{
is_.putback(c);
if (nChar == 1 && buf[0] == '-')
{
// A single '-' is punctuation
t = token::punctuationToken(token::SUBTRACT);
}
else if (int64Val && readInt64(buf, int64Val))
{
t = int64Val;
}
else
{
real realVal;
if (readReal(buf, realVal))
{
// A scalar or too big to fit as a unit
t = realVal;
}
else
{
t.setBad();
}
}
}
return *this;
}
// Should be a word (which can also be a single character)
default:
{
putback(c);
readWordToken(t);
return *this;
}
}
}
pFlow::iIstream& pFlow::Istream::read(char& c)
{
c = nextValid();
return *this;
}
pFlow::iIstream& pFlow::Istream::read(word& str)
{
constexpr const unsigned maxLen = 1024;
static char buf[maxLen];
unsigned nChar = 0;
unsigned depth = 0; // Track depth of (..) nesting
char c;
while
(
(nChar < maxLen)
&& get(c)
&& validWord(c)
)
{
if (c == token::BEGIN_LIST)
{
++depth;
}
else if (c == token::END_LIST)
{
if (!depth)
{
break; // Closed ')' without an opening '(' ? ... stop
}
--depth;
}
buf[nChar++] = c;
}
if (nChar >= maxLen)
{
buf[errLen] = '\0';
ioErrorInFile(name(), lineNumber())
<< "word '" << buf << "...'\n"
<< " is too long (max. " <<
static_cast< int32 >(maxLen) << " characters)";
fatalExit;
return *this;
}
buf[nChar] = '\0'; // Terminate string
if (bad())
{
// Could probably skip this check
buf[errLen] = '\0';
ioErrorInFile(name(), lineNumber())
<< "Problem while reading word '" << buf << "...' after "
<< static_cast< int32 >(nChar) << " characters\n";
fatalExit;
return *this;
}
if (nChar == 0)
{
ioErrorInFile(name(), lineNumber())
<< "Invalid first character found : " << c;
fatalExit;
}
else if (depth)
{
warningInFunction
<< "Missing " << static_cast< int32 >(depth)
<< " closing ')' while parsing" << nl << nl
<< buf << nl << endl;
}
// Finalize: content already validated, assign without additional checks.
str.assign(buf, nChar);
putback(c);
return *this;
}
pFlow::iIstream& pFlow::Istream::readString(word& str)
{
constexpr const unsigned maxLen = 1024;
static char buf[maxLen];
char c;
if (!get(c))
{
ioErrorInFile(name(), lineNumber())
<< "cannot read start of string";
fatalExit;
return *this;
}
// Note, we could also handle single-quoted strings here (if desired)
if (c != token::BEGIN_STRING)
{
ioErrorInFile(name(), lineNumber())
<< "Incorrect start of string character found : " << c;
fatalExit;
return *this;
}
unsigned nChar = 0;
bool escaped = false;
while
(
(nChar < maxLen)
&& get(c)
)
{
if (c == token::END_STRING)
{
if (escaped)
{
escaped = false;
--nChar; // Overwrite backslash
}
else
{
// Done reading
str.assign(buf, nChar);
return *this;
}
}
else if (c == token::NL)
{
if (escaped)
{
escaped = false;
--nChar; // Overwrite backslash
}
else
{
buf[errLen] = buf[nChar] = '\0';
ioErrorInFile(name(), lineNumber())
<< "found '\\n' while reading string \""
<< buf << "...\"";
fatalExit;
return *this;
}
}
else if (c == '\\')
{
escaped = !escaped; // toggle state (retains backslashes)
}
else
{
escaped = false;
}
buf[nChar++] = c;
}
if (nChar >= maxLen)
{
buf[errLen] = '\0';
ioErrorInFile(name(), lineNumber())
<< "string \"" << buf << "...\"\n"
<< " is too long (max. " << static_cast< int32 >(maxLen) << " characters)";
fatalExit;
return *this;
}
// Don't worry about a dangling backslash if string terminated prematurely
buf[errLen] = buf[nChar] = '\0';
ioErrorInFile(name(), lineNumber())
<< "Problem while reading string \"" << buf << "...\"";
fatalExit;
return *this;
}
pFlow::iIstream& pFlow::Istream::read(int64& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(int32& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(int8& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(uint64& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(uint32& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(uint8& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(float& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(double& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read
(
char* buffer,
std::streamsize count
)
{
if ( !isBinary() )
{
fatalErrorInFunction<<"stream format is not binray. Stream name is "<<
name()<<'\n';
fatalExit;
}
readBegin("binaryBlock");
is_.read(buffer, count);
readEnd("binaryBlock");
setState(is_.rdstate());
return *this;
}
size_t pFlow::Istream::findBinaryBlockStart()
{
size_t pos = 0;
char getChar = 'a';
unsigned char bFlag = 255;
int numFound = 0;
while( is_.good() && !is_.eof() )
{
getChar = is_.get();
pos++;
if( numFound <3 &&
static_cast<unsigned char>(getChar) == bFlag )
{
numFound++;
}
else if(numFound == 3 && static_cast<unsigned char>(getChar) == 0 )
{
return pos;
}
else
{
numFound = 0;
}
}
return static_cast<size_t>(-1);
}
void pFlow::Istream::rewind()
{
lineNumber_ = 1; // Reset line number
stdStream().clear(); // Clear the iostate error state flags
setGood(); // Sync local copy of iostate
// pubseekpos() rather than seekg() so that it works with gzstream
stdStream().rdbuf()->pubseekpos(0, std::ios_base::in);
}
void pFlow::Istream::seek(size_t pos)
{
stdStream().clear(); // Clear the iostate error state flags
setGood(); // Sync local copy of iostate
resetPutBack();
// pubseekpos() rather than seekg() so that it works with gzstream
stdStream().rdbuf()->pubseekpos(pos, std::ios_base::in);
}
size_t pFlow::Istream::tell()
{
auto pos = static_cast<size_t>(stdStream().tellg());
if(stdStream().fail())
{
fatalErrorInFunction<<
"Error in getting current position from stream "<<
this->name()<<endl;
fatalExit;
}
return pos;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
std::ios_base::fmtflags pFlow::Istream::flags() const
{
return is_.flags();
}
std::ios_base::fmtflags pFlow::Istream::flags(const ios_base::fmtflags f)
{
return is_.flags(f);
}
// ************************************************************************* //
pFlow::token::setType
bool setType(const tokenType tokType)
Change the token type, for similar types.
Definition: tokenI.hpp:308
pFlow::real
float real
Definition: builtinTypes.hpp:45
fatalExit
#define fatalExit
Fatal exit.
Definition: error.hpp:98
pFlow::token
Token class based on OpenFOAM stream, with some modifications/simplifications to be tailored to our n...
Definition: token.hpp:44
pFlow::Istream::nextValid
char nextValid()
Get the next valid character.
Definition: Istream.cpp:49
pFlow::Istream::readWordToken
void readWordToken(token &t)
Read a word token.
Definition: Istream.cpp:127
errLen
static constexpr const unsigned errLen
Definition: Istream.cpp:28
pFlow::Istream::findBinaryBlockStart
size_t findBinaryBlockStart() override
It seek for a character sequence that indicates the start of a binary block char sequence is 255 255 ...
Definition: Istream.cpp:861
pFlow::Istream::tell
size_t tell() override
Return current position indicator.
Definition: Istream.cpp:911
warningInFunction
#define warningInFunction
Report a warning.
Definition: error.hpp:95
pFlow::token::punctuationToken
punctuationToken
Standard punctuation tokens (a character)
Definition: token.hpp:83
pFlow::algorithms::KOKKOS::max
INLINE_FUNCTION_H Type max(const Type *first, uint32 numElems)
Definition: kokkosAlgorithms.hpp:104
pFlow::Istream::Istream
Istream(std::istream &is, const word &streamName, writeFormat wf=ASCII)
Construct wrapper around std::istream, set stream status.
Definition: Istream.cpp:304
pFlow::token::END_BLOCK
@ END_BLOCK
Begin block [isseparator].
Definition: token.hpp:96
pFlow::uint32
unsigned int uint32
Definition: builtinTypes.hpp:56
pFlow::readReal
bool readReal(const word &w, real &val)
Convert word to real.
Definition: bTypesFunctions.cpp:343
token.hpp
pFlow::word
std::string word
Definition: builtinTypes.hpp:64
pFlow::token::NL
@ NL
Tab [isspace].
Definition: token.hpp:88
pFlow::int64
long long int int64
Definition: builtinTypes.hpp:52
pFlow::validWord
bool validWord(char c)
Is the character valid for a word name?
Definition: bTypesFunctions.cpp:211
Istream.hpp
pFlow::endl
iOstream & endl(iOstream &os)
Add newline and flush stream.
Definition: iOstream.hpp:341
pFlow::token::BEGIN_BLOCK
@ BEGIN_BLOCK
End dimensions [isseparator].
Definition: token.hpp:95
pFlow::readInt64
bool readInt64(const word &w, int64 &val)
Convert word to int64.
Definition: bTypesFunctions.cpp:279
pFlow::Istream::seek
void seek(size_t pos) override
Definition: Istream.cpp:902
pFlow::Istream::readString
virtual iIstream & readString(word &str) override
Read a string.
Definition: Istream.cpp:680
pFlow::Istream
Standard input stream for binary and ascii data.
Definition: Istream.hpp:39
pFlow::iIstream
Interface class for any input stream
Definition: iIstream.hpp:37
pFlow::IOstream::bad
bool bad() const
Return true if stream is corrupted.
Definition: IOstream.hpp:204
pFlow::iIstream::getBack
bool getBack(token &tok)
Get the put back token if there is one and return true.
Definition: iIstream.cpp:45
pFlow::Istream::readVariable
Istream & readVariable(word &str)
Read a variable name starting with '$'.
Definition: Istream.cpp:141
fatalErrorInFunction
#define fatalErrorInFunction
Report a fatal error and function name and exit the application.
Definition: error.hpp:77
pFlow::int32
int int32
Definition: builtinTypes.hpp:50
pFlow::Istream::read
virtual iIstream & read(token &t) override
Return next token from stream.
Definition: Istream.cpp:392
pFlow::token::BEGIN_STRING
@ BEGIN_STRING
Divide [isseparator].
Definition: token.hpp:106
pFlow::token::END_LIST
@ END_LIST
Begin list [isseparator].
Definition: token.hpp:92
pFlow::token::DOLLAR
@ DOLLAR
Comma [isseparator].
Definition: token.hpp:99
pFlow::count
auto count(const Vector< T, Allocator > &vec, const T &val)
Definition: VectorAlgorithm.hpp:26
pFlow::Istream::get
Istream & get(char &c)
Raw, low-level get character function.
Definition: Istream.cpp:325
pFlow::token::COLON
@ COLON
End block [isseparator].
Definition: token.hpp:97
pFlow::token::END_STATEMENT
@ END_STATEMENT
Newline [isspace].
Definition: token.hpp:90
pFlow::IOstream::good
bool good() const
Return true if next operation might succeed.
Definition: IOstream.hpp:186
pFlow::Istream::rewind
void rewind() override
Rewind the stream so that it may be read again.
Definition: Istream.cpp:891
pFlow::token::SUBTRACT
@ SUBTRACT
Double quote.
Definition: token.hpp:103
pFlow::token::BEGIN_LIST
@ BEGIN_LIST
End entry [isseparator].
Definition: token.hpp:91
pFlow::token::BEGIN_SQR
@ BEGIN_SQR
End list [isseparator].
Definition: token.hpp:93
pFlow::token::DIVIDE
@ DIVIDE
Subtract or start of negative number.
Definition: token.hpp:104
ioErrorInFile
#define ioErrorInFile(fileName, lineNumber)
Report an error in file operation with supplied fileName and lineNumber.
Definition: error.hpp:87
pFlow::uint64
unsigned long long int uint64
Definition: builtinTypes.hpp:58
pFlow::token::COMMA
@ COMMA
Colon [isseparator].
Definition: token.hpp:98
pFlow::int8
signed char int8
Definition: builtinTypes.hpp:48
pFlow::Istream::peek
int peek()
Raw, low-level peek function.
Definition: Istream.cpp:339
pFlow::IOstream::writeFormat
writeFormat
Definition: IOstream.hpp:59
pFlow::Istream::flags
virtual ios_base::fmtflags flags() const
Return flags of output stream.
Definition: Istream.cpp:927
pFlow::token::END_STRING
@ END_STRING
Begin string with double quote.
Definition: token.hpp:107
pFlow::Istream::putback
Istream & putback(const char c)
Raw, low-level putback character function.
Definition: Istream.cpp:375
pFlow::Istream::getLine
Istream & getLine(word &str, char delim='\n')
Raw, low-level getline (until delimiter) into a string.
Definition: Istream.cpp:345
pFlow::uint8
unsigned char uint8
Definition: builtinTypes.hpp:54
pFlow::nl
constexpr char nl
Definition: iOstream.hpp:440
pFlow::token::END_SQR
@ END_SQR
Begin dimensions [isseparator].
Definition: token.hpp:94
pFlow::token::setBad
void setBad()
Clear token and set to be ERROR.
Definition: tokenI.hpp:676
pFlow::token::lineNumber
int32 lineNumber() const
The line number for the token.
Definition: tokenI.hpp:378
error.hpp