mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
Performance improvement of IfcParse tokenizer (#82)
* Applied MSVC tabify to IfcParse.cpp/h. * Now Argument base class has throwing implementation for each conversion operator (removed those from derived classes). * Added NullArgument class for the case when null arguments appear after setting elements. * Now operator tokens are handled just like any other token. * Refactoring: Token is now a struct with good fields, not a nameless pair. * Now end position of token is set at its construction. * Now type of token is determined on construction, as* function simply check stored type. * Now int-s, float-s and some etc are parsed when token is created. * Implemented simple way to remove spaces in parsing. * Tokens are now created without allocations. * Call RemoveTokenSeparators once for every token. * Added temporary std::string object in lexer (for optimization purposes). * Reimplemented asString without allocations. * Parsing keywords without allocations. * Added checks for type to tokenFunc::as*** functions.
This commit is contained in:
committed by
Thomas Krijnen
parent
cbbdb61a0c
commit
8725c66306
+159
-129
@@ -100,8 +100,8 @@ void init_locale() {
|
||||
// Opens the file, gets the filesize and reads a chunk in memory
|
||||
//
|
||||
IfcSpfStream::IfcSpfStream(const std::string& fn)
|
||||
: stream(0)
|
||||
, buffer(0)
|
||||
: stream(0)
|
||||
, buffer(0)
|
||||
{
|
||||
eof = false;
|
||||
#ifdef _MSC_VER
|
||||
@@ -134,8 +134,8 @@ IfcSpfStream::IfcSpfStream(const std::string& fn)
|
||||
}
|
||||
|
||||
IfcSpfStream::IfcSpfStream(std::istream& f, int l)
|
||||
: stream(0)
|
||||
, buffer(0)
|
||||
: stream(0)
|
||||
, buffer(0)
|
||||
{
|
||||
eof = false;
|
||||
size = l;
|
||||
@@ -151,8 +151,8 @@ IfcSpfStream::IfcSpfStream(std::istream& f, int l)
|
||||
}
|
||||
|
||||
IfcSpfStream::IfcSpfStream(void* data, int l)
|
||||
: stream(0)
|
||||
, buffer(0)
|
||||
: stream(0)
|
||||
, buffer(0)
|
||||
{
|
||||
eof = false;
|
||||
size = l;
|
||||
@@ -333,11 +333,11 @@ unsigned int IfcSpfLexer::skipComment() {
|
||||
//
|
||||
Token IfcSpfLexer::Next() {
|
||||
|
||||
if ( stream->eof ) return TokenPtr();
|
||||
if ( stream->eof ) return NoneTokenPtr();
|
||||
|
||||
while (skipWhitespace() || skipComment()) {}
|
||||
|
||||
if ( stream->eof ) return TokenPtr();
|
||||
if ( stream->eof ) return NoneTokenPtr();
|
||||
unsigned int pos = stream->Tell();
|
||||
|
||||
char c = stream->Peek();
|
||||
@@ -345,7 +345,7 @@ Token IfcSpfLexer::Next() {
|
||||
// If the cursor is at [()=,;$*] we know token consists of single char
|
||||
if (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' || c == '$' || c == '*') {
|
||||
stream->Inc();
|
||||
return TokenPtr(c);
|
||||
return OperatorTokenPtr(this, pos, pos+1);
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
@@ -361,142 +361,200 @@ Token IfcSpfLexer::Next() {
|
||||
// If a string is encountered defer processing to the IfcCharacterDecoder
|
||||
if ( c == '\'' ) decoder->dryRun();
|
||||
}
|
||||
if ( len ) return TokenPtr(this,pos);
|
||||
else return TokenPtr();
|
||||
if ( len ) return GeneralTokenPtr(this, pos, stream->Tell());
|
||||
else return NoneTokenPtr();
|
||||
}
|
||||
|
||||
//
|
||||
// Reads a std::string from the file at specified offset
|
||||
// Omits whitespace and comments
|
||||
//
|
||||
std::string IfcSpfLexer::TokenString(unsigned int offset) {
|
||||
void IfcSpfLexer::TokenString(unsigned int offset, std::string &buffer) {
|
||||
const bool was_eof = stream->eof;
|
||||
unsigned int old_offset = stream->Tell();
|
||||
stream->Seek(offset);
|
||||
std::string buffer;
|
||||
buffer.reserve(128);
|
||||
buffer.clear();
|
||||
while ( ! stream->eof ) {
|
||||
char c = stream->Peek();
|
||||
if ( buffer.size() && (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' || c == '/') ) break;
|
||||
stream->Inc();
|
||||
if ( c == ' ' || c == '\r' || c == '\n' || c == '\t' ) continue;
|
||||
else if ( c == '\'' ) return *decoder;
|
||||
else if ( c == '\'' ) {
|
||||
buffer = *decoder;
|
||||
return;
|
||||
}
|
||||
else buffer.push_back(c);
|
||||
}
|
||||
if ( was_eof ) stream->eof = true;
|
||||
else stream->Seek(old_offset);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//
|
||||
// Functions for creating Tokens from an arbitary file offset.
|
||||
// The first 4 bits are reserved for Tokens of type ()=,;$*
|
||||
//
|
||||
Token IfcParse::TokenPtr(IfcSpfLexer* tokens, unsigned int offset) { return Token(tokens,offset); }
|
||||
Token IfcParse::TokenPtr(char c) { return Token((IfcSpfLexer*)0,(unsigned) c); }
|
||||
Token IfcParse::TokenPtr() { return Token((IfcSpfLexer*)0,0); }
|
||||
//Note: according to STEP standard, there may be newlines in tokens
|
||||
inline void RemoveTokenSeparators(IfcSpfStream* stream, unsigned start, unsigned end, std::string &oDestination) {
|
||||
oDestination.clear();
|
||||
for (unsigned i = start; i < end; i++) {
|
||||
char c = stream->Read(i);
|
||||
if (c == ' ' || c == '\r' || c == '\n' || c == '\t')
|
||||
continue;
|
||||
oDestination += c;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Functions to convert Tokens to binary data
|
||||
//
|
||||
bool TokenFunc::startsWith(const Token& t, char c) {
|
||||
return t.first->stream->Read(t.second) == c;
|
||||
bool ParseInt(const char *pStart, int &val) {
|
||||
char* pEnd;
|
||||
long result = strtol(pStart, &pEnd, 10);
|
||||
if (*pEnd != 0)
|
||||
return false;
|
||||
val = (int)result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseFloat(const char *pStart, double &val) {
|
||||
char* pEnd;
|
||||
#ifdef _MSC_VER
|
||||
double result = _strtod_l(pStart, &pEnd, locale);
|
||||
#else
|
||||
double result = strtod_l(pStart, &pEnd, locale);
|
||||
#endif
|
||||
if (*pEnd != 0)
|
||||
return false;
|
||||
val = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseBool(const char *pStart, bool &val) {
|
||||
if (strlen(pStart) != 3 || pStart[0] != '.' || pStart[2] != '.')
|
||||
return false;
|
||||
char mid = pStart[1];
|
||||
if (!(mid == 'T' || mid == 'F'))
|
||||
return false;
|
||||
val = (mid == 'T');
|
||||
return true;
|
||||
}
|
||||
|
||||
Token IfcParse::OperatorTokenPtr(IfcSpfLexer* lexer, unsigned start, unsigned end) {
|
||||
char first = lexer->stream->Read(start);
|
||||
Token token(lexer, start, end, Token_OPERATOR);
|
||||
token.value_char = first;
|
||||
return token;
|
||||
}
|
||||
|
||||
Token IfcParse::GeneralTokenPtr(IfcSpfLexer* lexer, unsigned start, unsigned end) {
|
||||
Token token(lexer, start, end, Token_NONE);
|
||||
|
||||
//extract token into temp buffer (remove eol-s, no encoding changes)
|
||||
std::string &tokenStr = lexer->GetTempString();
|
||||
RemoveTokenSeparators(lexer->stream, start, end, tokenStr);
|
||||
|
||||
//determine type of the token
|
||||
char first = lexer->stream->Read(start);
|
||||
if (first == '#') {
|
||||
token.type = Token_IDENTIFIER;
|
||||
if (!ParseInt(tokenStr.c_str() + 1, token.value_int))
|
||||
throw IfcException("Identifier token as not integer");
|
||||
}
|
||||
else if (first == '\'')
|
||||
token.type = Token_STRING;
|
||||
else if (first == '.') {
|
||||
token.type = Token_ENUMERATION;
|
||||
if (ParseBool(tokenStr.c_str(), token.value_bool)) //bool is also enumeration
|
||||
token.type = Token_BOOL;
|
||||
}
|
||||
else if (first == '"')
|
||||
token.type = Token_BINARY;
|
||||
else if (ParseInt(tokenStr.c_str(), token.value_int))
|
||||
token.type = Token_INT;
|
||||
else if (ParseFloat(tokenStr.c_str(), token.value_double))
|
||||
token.type = Token_FLOAT;
|
||||
else
|
||||
token.type = Token_KEYWORD;
|
||||
|
||||
return token;
|
||||
}
|
||||
Token IfcParse::NoneTokenPtr() { return Token(); }
|
||||
|
||||
|
||||
bool TokenFunc::isOperator(const Token& t) {
|
||||
return t.type == Token_OPERATOR;
|
||||
}
|
||||
|
||||
bool TokenFunc::isOperator(const Token& t, char op) {
|
||||
return (!t.first) && (!op || (unsigned)op == t.second);
|
||||
return t.type == Token_OPERATOR && t.value_char == op;
|
||||
}
|
||||
|
||||
bool TokenFunc::isIdentifier(const Token& t) {
|
||||
return ! isOperator(t) && startsWith(t, '#');
|
||||
return t.type == Token_IDENTIFIER;
|
||||
}
|
||||
|
||||
bool TokenFunc::isString(const Token& t) {
|
||||
return ! isOperator(t) && startsWith(t, '\'');
|
||||
return t.type == Token_STRING;
|
||||
}
|
||||
|
||||
bool TokenFunc::isEnumeration(const Token& t) {
|
||||
return ! isOperator(t) && startsWith(t, '.');
|
||||
return t.type == Token_ENUMERATION || t.type == Token_BOOL;
|
||||
}
|
||||
|
||||
bool TokenFunc::isBinary(const Token& t) {
|
||||
return ! isOperator(t) && startsWith(t, '"');
|
||||
return t.type == Token_BINARY;
|
||||
}
|
||||
|
||||
bool TokenFunc::isKeyword(const Token& t) {
|
||||
// bool is a subtype of enumeration, no need to test for that
|
||||
return !isOperator(t) && !isIdentifier(t) && !isString(t) && !isEnumeration(t) && !isInt(t) && !isFloat(t) && !isBinary(t);
|
||||
return t.type == Token_KEYWORD;
|
||||
}
|
||||
|
||||
bool TokenFunc::isInt(const Token& t) {
|
||||
if (isOperator(t) || isString(t) || isEnumeration(t)) {
|
||||
return false;
|
||||
}
|
||||
const std::string str = asString(t);
|
||||
const char* start = str.c_str();
|
||||
char* end;
|
||||
/*long result =*/ strtol(start,&end,10);
|
||||
return ((end - start) == (ptrdiff_t)str.length());
|
||||
return t.type == Token_INT;
|
||||
}
|
||||
|
||||
bool TokenFunc::isBool(const Token& t) {
|
||||
if (!isEnumeration(t)) return false;
|
||||
const std::string str = asString(t);
|
||||
return str == "T" || str == "F";
|
||||
return t.type == Token_BOOL;
|
||||
}
|
||||
|
||||
bool TokenFunc::isFloat(const Token& t) {
|
||||
if (isOperator(t) || isString(t) || isEnumeration(t)) {
|
||||
return false;
|
||||
}
|
||||
const std::string str = asString(t);
|
||||
const char* start = str.c_str();
|
||||
char* end;
|
||||
#ifdef _MSC_VER
|
||||
/*double result =*/ _strtod_l(start,&end,locale);
|
||||
#else
|
||||
double result = strtod_l(start,&end,locale);
|
||||
#endif
|
||||
return ((end - start) == (ptrdiff_t)str.length());
|
||||
return t.type == Token_FLOAT || t.type == Token_INT;
|
||||
}
|
||||
|
||||
int TokenFunc::asInt(const Token& t) {
|
||||
const std::string str = asString(t);
|
||||
// In case of an ENTITY_INSTANCE_NAME skip the leading #
|
||||
const char* start = str.c_str() + (isIdentifier(t) ? 1 : 0);
|
||||
char* end;
|
||||
long result = strtol(start,&end,10);
|
||||
if ( start == end ) throw IfcException("Token is not an integer or identifier");
|
||||
return (int) result;
|
||||
if (t.type != Token_INT)
|
||||
throw IfcException("Token is not an integer");
|
||||
return t.value_int;
|
||||
}
|
||||
|
||||
int TokenFunc::asIdentifier(const Token& t) {
|
||||
if (t.type != Token_IDENTIFIER)
|
||||
throw IfcException("Token is not an identifier");
|
||||
return t.value_int;
|
||||
}
|
||||
|
||||
bool TokenFunc::asBool(const Token& t) {
|
||||
const std::string str = asString(t);
|
||||
return str == "T";
|
||||
if (t.type != Token_BOOL)
|
||||
throw IfcException("Token is not a boolean");
|
||||
return t.value_bool;
|
||||
}
|
||||
|
||||
double TokenFunc::asFloat(const Token& t) {
|
||||
const std::string str = asString(t);
|
||||
const char* start = str.c_str();
|
||||
char* end;
|
||||
#ifdef _MSC_VER
|
||||
double result = _strtod_l(start,&end,locale);
|
||||
#else
|
||||
double result = strtod_l(start,&end,locale);
|
||||
#endif
|
||||
if ( start == end ) throw IfcException("Token is not a real");
|
||||
return result;
|
||||
if (t.type != Token_FLOAT)
|
||||
throw IfcException("Token is not a float");
|
||||
return t.value_double;
|
||||
}
|
||||
|
||||
const std::string &TokenFunc::asStringRef(const Token& t) {
|
||||
std::string &str = t.lexer->GetTempString();
|
||||
t.lexer->TokenString(t.startPos, str);
|
||||
if (isString(t) || isEnumeration(t) || isBinary(t)) {
|
||||
//remove start+end characters in-place
|
||||
str.pop_back();
|
||||
str.erase(str.begin());
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string TokenFunc::asString(const Token& t) {
|
||||
if ( isOperator(t,'$') ) return "";
|
||||
else if ( isOperator(t) ) throw IfcException("Token is not a string");
|
||||
std::string str = t.first->TokenString(t.second);
|
||||
return isString(t) || isEnumeration(t) || isBinary(t) ? str.substr(1,str.size()-2) : str;
|
||||
return asStringRef(t);
|
||||
}
|
||||
|
||||
boost::dynamic_bitset<> TokenFunc::asBinary(const Token& t) {
|
||||
const std::string str = asString(t);
|
||||
const std::string &str = asStringRef(t);
|
||||
if (str.size() < 1) {
|
||||
throw IfcException("Token is not a valid binary sequence");
|
||||
}
|
||||
@@ -526,8 +584,9 @@ boost::dynamic_bitset<> TokenFunc::asBinary(const Token& t) {
|
||||
}
|
||||
|
||||
std::string TokenFunc::toString(const Token& t) {
|
||||
if ( isOperator(t) ) return std::string ( (char*) &t.second , 1 );
|
||||
else return t.first->TokenString(t.second);
|
||||
std::string result;
|
||||
t.lexer->TokenString(t.startPos, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -536,11 +595,11 @@ TokenArgument::TokenArgument(const Token& t) {
|
||||
}
|
||||
|
||||
EntityArgument::EntityArgument(const Token& t) {
|
||||
IfcParse::IfcFile* file = t.first->file;
|
||||
IfcParse::IfcFile* file = t.lexer->file;
|
||||
if (file->create_latebound_entities()) {
|
||||
entity = new IfcLateBoundEntity(new Entity(0, file, t.second));
|
||||
entity = new IfcLateBoundEntity(new Entity(0, file, t.startPos));
|
||||
} else {
|
||||
entity = IfcSchema::SchemaEntity(new Entity(0, file, t.second));
|
||||
entity = IfcSchema::SchemaEntity(new Entity(0, file, t.startPos));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,7 +610,7 @@ EntityArgument::EntityArgument(const Token& t) {
|
||||
void ArgumentList::read(IfcSpfLexer* t, std::vector<unsigned int>& ids) {
|
||||
//IfcParse::IfcFile* file = t->file;
|
||||
Token next = t->Next();
|
||||
while( next.second || next.first ) {
|
||||
while( next.startPos || next.lexer ) {
|
||||
if ( TokenFunc::isOperator(next,',') ) {
|
||||
// do nothing
|
||||
} else if ( TokenFunc::isOperator(next,')') ) {
|
||||
@@ -562,7 +621,7 @@ void ArgumentList::read(IfcSpfLexer* t, std::vector<unsigned int>& ids) {
|
||||
push(alist);
|
||||
} else {
|
||||
if ( TokenFunc::isIdentifier(next) ) {
|
||||
ids.push_back(TokenFunc::asInt(next));
|
||||
ids.push_back(TokenFunc::asIdentifier(next));
|
||||
} if ( TokenFunc::isKeyword(next) ) {
|
||||
t->Next();
|
||||
try {
|
||||
@@ -631,12 +690,6 @@ std::vector< std::vector<T> > read_aggregate_of_aggregate_as_vector2(const std::
|
||||
//
|
||||
// Functions for casting the ArgumentList to other types
|
||||
//
|
||||
ArgumentList::operator int() const { throw IfcException("Argument is not an integer"); }
|
||||
ArgumentList::operator bool() const { throw IfcException("Argument is not a boolean"); }
|
||||
ArgumentList::operator double() const { throw IfcException("Argument is not a number"); }
|
||||
ArgumentList::operator std::string() const { throw IfcException("Argument is not a string"); }
|
||||
ArgumentList::operator boost::dynamic_bitset<>() const { throw IfcException("Argument is not a binary"); }
|
||||
|
||||
ArgumentList::operator std::vector<double>() const {
|
||||
return read_aggregate_as_vector<double>(list);
|
||||
}
|
||||
@@ -653,8 +706,6 @@ ArgumentList::operator std::vector<boost::dynamic_bitset<> >() const {
|
||||
return read_aggregate_as_vector<boost::dynamic_bitset<> >(list);
|
||||
}
|
||||
|
||||
ArgumentList::operator IfcUtil::IfcBaseClass*() const { throw IfcException("Argument is not an entity instance"); }
|
||||
|
||||
ArgumentList::operator IfcEntityList::ptr() const {
|
||||
IfcEntityList::ptr l ( new IfcEntityList() );
|
||||
std::vector<Argument*>::const_iterator it;
|
||||
@@ -699,7 +750,7 @@ Argument* ArgumentList::operator [] (unsigned int i) const {
|
||||
|
||||
void ArgumentList::set(unsigned int i, Argument* argument) {
|
||||
while (size() < i) {
|
||||
push(new TokenArgument(Token(static_cast<IfcSpfLexer*>(0), '$')));
|
||||
push(new NullArgument());
|
||||
}
|
||||
if (i < size()) {
|
||||
delete list[i];
|
||||
@@ -762,15 +813,7 @@ TokenArgument::operator bool() const { return TokenFunc::asBool(token); }
|
||||
TokenArgument::operator double() const { return TokenFunc::asFloat(token); }
|
||||
TokenArgument::operator std::string() const { return TokenFunc::asString(token); }
|
||||
TokenArgument::operator boost::dynamic_bitset<>() const { return TokenFunc::asBinary(token); }
|
||||
TokenArgument::operator std::vector<double>() const { throw IfcException("Argument is not a list of floats"); }
|
||||
TokenArgument::operator std::vector<int>() const { throw IfcException("Argument is not a list of ints"); }
|
||||
TokenArgument::operator std::vector<std::string>() const { throw IfcException("Argument is not a list of strings"); }
|
||||
TokenArgument::operator std::vector<boost::dynamic_bitset<> >() const { throw IfcException("Argument is not a list of binaries"); }
|
||||
TokenArgument::operator IfcUtil::IfcBaseClass*() const { return token.first->file->entityById(TokenFunc::asInt(token)); }
|
||||
TokenArgument::operator IfcEntityList::ptr() const { throw IfcException("Argument is not a list of entity instances"); }
|
||||
TokenArgument::operator std::vector< std::vector<int> >() const { throw IfcException("Argument is not a list of list of ints"); }
|
||||
TokenArgument::operator std::vector< std::vector<double> >() const { throw IfcException("Argument is not a list of list of floats"); }
|
||||
TokenArgument::operator IfcEntityListList::ptr() const { throw IfcException("Argument is not a list of list of entity instances"); }
|
||||
TokenArgument::operator IfcUtil::IfcBaseClass*() const { return token.lexer->file->entityById(TokenFunc::asIdentifier(token)); }
|
||||
unsigned int TokenArgument::size() const { return 1; }
|
||||
Argument* TokenArgument::operator [] (unsigned int /*i*/) const { throw IfcException("Argument is not a list of attributes"); }
|
||||
std::string TokenArgument::toString(bool upper) const {
|
||||
@@ -789,20 +832,7 @@ IfcUtil::ArgumentType EntityArgument::type() const {
|
||||
//
|
||||
// Functions for casting the EntityArgument to other types
|
||||
//
|
||||
EntityArgument::operator int() const { throw IfcException("Argument is not an integer"); }
|
||||
EntityArgument::operator bool() const { throw IfcException("Argument is not a boolean"); }
|
||||
EntityArgument::operator double() const { throw IfcException("Argument is not a number"); }
|
||||
EntityArgument::operator boost::dynamic_bitset<>() const { throw IfcException("Argument is not a binary"); }
|
||||
EntityArgument::operator std::string() const { throw IfcException("Argument is not a string"); }
|
||||
EntityArgument::operator std::vector<double>() const { throw IfcException("Argument is not a list of floats"); }
|
||||
EntityArgument::operator std::vector<int>() const { throw IfcException("Argument is not a list of ints"); }
|
||||
EntityArgument::operator std::vector<std::string>() const { throw IfcException("Argument is not a list of strings"); }
|
||||
EntityArgument::operator std::vector<boost::dynamic_bitset<> >() const { throw IfcException("Argument is not a list of binaries"); }
|
||||
EntityArgument::operator IfcUtil::IfcBaseClass*() const { return entity; }
|
||||
EntityArgument::operator IfcEntityList::ptr() const { throw IfcException("Argument is not a list of entity instances"); }
|
||||
EntityArgument::operator std::vector< std::vector<int> >() const { throw IfcException("Argument is not a list of list of ints"); }
|
||||
EntityArgument::operator std::vector< std::vector<double> >() const { throw IfcException("Argument is not a list of list of floats"); }
|
||||
EntityArgument::operator IfcEntityListList::ptr() const { throw IfcException("Argument is not a list of list of entity instances"); }
|
||||
unsigned int EntityArgument::size() const { return 1; }
|
||||
Argument* EntityArgument::operator [] (unsigned int /*i*/) const { throw IfcException("Argument is not a list of arguments"); }
|
||||
std::string EntityArgument::toString(bool upper) const {
|
||||
@@ -819,8 +849,8 @@ Entity::Entity(unsigned int i, IfcFile* f) : args(0), _id(i) {
|
||||
file = f;
|
||||
Token datatype = f->tokens->Next();
|
||||
if ( ! TokenFunc::isKeyword(datatype)) throw IfcException("Unexpected token while parsing entity");
|
||||
_type = IfcSchema::Type::FromString(TokenFunc::asString(datatype));
|
||||
offset = datatype.second;
|
||||
_type = IfcSchema::Type::FromString(TokenFunc::asStringRef(datatype));
|
||||
offset = datatype.startPos;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -861,7 +891,7 @@ void Entity::Load(std::vector<unsigned int>& ids, bool seek) const {
|
||||
file->tokens->stream->Seek(offset);
|
||||
Token datatype = file->tokens->Next();
|
||||
if ( ! TokenFunc::isKeyword(datatype)) throw IfcException("Unexpected token while parsing entity");
|
||||
_type = IfcSchema::Type::FromString(TokenFunc::asString(datatype));
|
||||
_type = IfcSchema::Type::FromString(TokenFunc::asStringRef(datatype));
|
||||
}
|
||||
Token open = file->tokens->Next();
|
||||
args = new ArgumentList();
|
||||
@@ -975,8 +1005,8 @@ bool IfcFile::Init(IfcParse::IfcSpfStream* s) {
|
||||
Logger::Message(Logger::LOG_ERROR, std::string("File schema encountered different from expected '") + IfcSchema::Identifier + "'");
|
||||
}
|
||||
|
||||
Token token = TokenPtr();
|
||||
Token previous = TokenPtr();
|
||||
Token token = NoneTokenPtr();
|
||||
Token previous = NoneTokenPtr();
|
||||
|
||||
unsigned int currentId = 0;
|
||||
lastId = 0;
|
||||
@@ -1045,13 +1075,13 @@ bool IfcFile::Init(IfcParse::IfcSpfStream* s) {
|
||||
currentId = 0;
|
||||
} else {
|
||||
try { token = tokens->Next(); }
|
||||
catch (... ) { token = TokenPtr(); }
|
||||
catch (... ) { token = NoneTokenPtr(); }
|
||||
}
|
||||
|
||||
if ( ! (token.second || token.first) ) break;
|
||||
if ( ! (token.startPos || token.lexer) ) break;
|
||||
|
||||
if ( (previous.second || previous.first) && TokenFunc::isIdentifier(previous) ) {
|
||||
int id = TokenFunc::asInt(previous);
|
||||
if ( (previous.startPos || previous.lexer) && TokenFunc::isIdentifier(previous) ) {
|
||||
int id = TokenFunc::asIdentifier(previous);
|
||||
if ( TokenFunc::isOperator(token,'=') ) {
|
||||
currentId = id;
|
||||
} else if (entity) {
|
||||
|
||||
+55
-38
@@ -60,7 +60,34 @@ namespace IfcParse {
|
||||
class IfcFile;
|
||||
class IfcSpfLexer;
|
||||
|
||||
typedef std::pair<IfcSpfLexer*, unsigned> Token;
|
||||
enum TokenType {
|
||||
Token_NONE,
|
||||
Token_STRING,
|
||||
Token_IDENTIFIER,
|
||||
Token_OPERATOR,
|
||||
Token_ENUMERATION,
|
||||
Token_KEYWORD,
|
||||
Token_INT,
|
||||
Token_BOOL,
|
||||
Token_FLOAT,
|
||||
Token_BINARY
|
||||
};
|
||||
|
||||
struct Token {
|
||||
IfcSpfLexer* lexer; //TODO: remove it from here
|
||||
unsigned startPos, endPos;
|
||||
TokenType type;
|
||||
union {
|
||||
bool value_bool; //types: BOOL
|
||||
char value_char; //types: OPERATOR
|
||||
int value_int; //types: INT, IDENTIFIER
|
||||
double value_double; //types: FLOAT
|
||||
};
|
||||
|
||||
Token() : lexer(0), startPos(0), endPos(0), type(Token_NONE) {}
|
||||
Token(IfcSpfLexer* _lexer, unsigned _startPos, unsigned _endPos, TokenType _type)
|
||||
: lexer(_lexer), startPos(_startPos), endPos(_endPos), type(_type) {}
|
||||
};
|
||||
|
||||
/// Provides functions to convert Tokens to binary data
|
||||
/// Tokens are merely offsets to where they can be read in the file
|
||||
@@ -75,7 +102,9 @@ namespace IfcParse {
|
||||
/// Returns whether the token can be interpreted as an identifier
|
||||
static bool isIdentifier(const Token& t);
|
||||
/// Returns whether the token can be interpreted as a syntactical operator
|
||||
static bool isOperator(const Token& t, char op = 0);
|
||||
static bool isOperator(const Token& t);
|
||||
/// Returns whether the token is a given operator
|
||||
static bool isOperator(const Token& t, char op);
|
||||
/// Returns whether the token can be interpreted as an enumerated value
|
||||
static bool isEnumeration(const Token& t);
|
||||
/// Returns whether the token can be interpreted as a datatype name
|
||||
@@ -90,12 +119,16 @@ namespace IfcParse {
|
||||
static bool isBinary(const Token& t);
|
||||
/// Returns the token interpreted as an integer
|
||||
static int asInt(const Token& t);
|
||||
/// Returns the token interpreted as an identifier
|
||||
static int asIdentifier(const Token& t);
|
||||
/// Returns the token interpreted as an boolean (.T. or .F.)
|
||||
static bool asBool(const Token& t);
|
||||
/// Returns the token as a floating point number
|
||||
static double asFloat(const Token& t);
|
||||
/// Returns the token as a string (without the dot or apostrophe)
|
||||
static std::string asString(const Token& t);
|
||||
/// Returns the token as a string in internal buffer (for optimization purposes)
|
||||
static const std::string &asStringRef(const Token& t);
|
||||
/// Returns the token as a string (without the dot or apostrophe)
|
||||
static boost::dynamic_bitset<> asBinary(const Token& t);
|
||||
/// Returns a string representation of the token (including the dot or apostrophe)
|
||||
@@ -106,23 +139,26 @@ namespace IfcParse {
|
||||
// Functions for creating Tokens from an arbitary file offset
|
||||
// The first 4 bits are reserved for Tokens of type ()=,;$*
|
||||
//
|
||||
Token TokenPtr(IfcSpfLexer* tokens, unsigned int offset);
|
||||
Token TokenPtr(char c);
|
||||
Token TokenPtr();
|
||||
Token OperatorTokenPtr(IfcSpfLexer* tokens, unsigned start, unsigned end);
|
||||
Token GeneralTokenPtr(IfcSpfLexer* tokens, unsigned start, unsigned end);
|
||||
Token NoneTokenPtr();
|
||||
|
||||
/// A stream of tokens to be read from a IfcSpfStream.
|
||||
class IfcParse_EXPORT IfcSpfLexer {
|
||||
private:
|
||||
IfcCharacterDecoder* decoder;
|
||||
//storage for temporary string without allocation
|
||||
mutable std::string _tempString;
|
||||
unsigned int skipWhitespace();
|
||||
unsigned int skipComment();
|
||||
public:
|
||||
std::string &GetTempString() const { return _tempString; }
|
||||
IfcSpfStream* stream;
|
||||
IfcFile* file;
|
||||
IfcSpfLexer(IfcSpfStream* s, IfcFile* f);
|
||||
Token Next();
|
||||
~IfcSpfLexer();
|
||||
std::string TokenString(unsigned int offset);
|
||||
void TokenString(unsigned int offset, std::string &result);
|
||||
};
|
||||
|
||||
/// Argument of type list, e.g.
|
||||
@@ -139,13 +175,6 @@ namespace IfcParse {
|
||||
|
||||
IfcUtil::ArgumentType type() const;
|
||||
|
||||
operator int() const;
|
||||
operator bool() const;
|
||||
operator double() const;
|
||||
operator std::string() const;
|
||||
operator boost::dynamic_bitset<>() const;
|
||||
operator IfcUtil::IfcBaseClass*() const;
|
||||
|
||||
operator std::vector<int>() const;
|
||||
operator std::vector<double>() const;
|
||||
operator std::vector<std::string>() const;
|
||||
@@ -165,6 +194,19 @@ namespace IfcParse {
|
||||
std::string toString(bool upper=false) const;
|
||||
};
|
||||
|
||||
|
||||
/// Argument being null, e.g. '$'
|
||||
/// == ===
|
||||
class IfcParse_EXPORT NullArgument : public Argument {
|
||||
public:
|
||||
NullArgument() {}
|
||||
IfcUtil::ArgumentType type() const { return IfcUtil::Argument_NULL; }
|
||||
bool isNull() const { return true; }
|
||||
unsigned int size() const { return 1; }
|
||||
Argument* operator [] (unsigned int /*i*/) const { throw IfcException("Argument is not a list of attributes"); }
|
||||
std::string toString(bool /*upper=false*/) const { return "$"; }
|
||||
};
|
||||
|
||||
/// Argument of type scalar or string, e.g.
|
||||
/// #1=IfcVector(#2,1.0);
|
||||
/// == ===
|
||||
@@ -184,16 +226,6 @@ namespace IfcParse {
|
||||
operator boost::dynamic_bitset<>() const;
|
||||
operator IfcUtil::IfcBaseClass*() const;
|
||||
|
||||
operator std::vector<int>() const;
|
||||
operator std::vector<double>() const;
|
||||
operator std::vector<std::string>() const;
|
||||
operator std::vector<boost::dynamic_bitset<> >() const;
|
||||
operator IfcEntityList::ptr() const;
|
||||
|
||||
operator std::vector< std::vector<int> >() const;
|
||||
operator std::vector< std::vector<double> >() const;
|
||||
operator IfcEntityListList::ptr() const;
|
||||
|
||||
bool isNull() const;
|
||||
unsigned int size() const;
|
||||
|
||||
@@ -213,23 +245,8 @@ namespace IfcParse {
|
||||
|
||||
IfcUtil::ArgumentType type() const;
|
||||
|
||||
operator int() const;
|
||||
operator bool() const;
|
||||
operator double() const;
|
||||
operator std::string() const;
|
||||
operator boost::dynamic_bitset<>() const;
|
||||
operator IfcUtil::IfcBaseClass*() const;
|
||||
|
||||
operator std::vector<int>() const;
|
||||
operator std::vector<double>() const;
|
||||
operator std::vector<std::string>() const;
|
||||
operator std::vector<boost::dynamic_bitset<> >() const;
|
||||
operator IfcEntityList::ptr() const;
|
||||
|
||||
operator std::vector< std::vector<int> >() const;
|
||||
operator std::vector< std::vector<double> >() const;
|
||||
operator IfcEntityListList::ptr() const;
|
||||
|
||||
bool isNull() const;
|
||||
unsigned int size() const;
|
||||
|
||||
|
||||
@@ -76,6 +76,24 @@ unsigned int IfcUtil::IfcBaseType::getArgumentCount() const { return 1; }
|
||||
Argument* IfcUtil::IfcBaseType::getArgument(unsigned int i) const { return entity->getArgument(i); }
|
||||
const char* IfcUtil::IfcBaseType::getArgumentName(unsigned int i) const { if (i == 0) { return "wrappedValue"; } else { throw IfcParse::IfcAttributeOutOfRangeException("Argument index out of range"); } }
|
||||
|
||||
|
||||
//Note: some of these methods are overloaded in derived classes
|
||||
Argument::operator int() const { throw IfcParse::IfcException("Argument is not an integer"); }
|
||||
Argument::operator bool() const { throw IfcParse::IfcException("Argument is not a boolean"); }
|
||||
Argument::operator double() const { throw IfcParse::IfcException("Argument is not a number"); }
|
||||
Argument::operator std::string() const { throw IfcParse::IfcException("Argument is not a string"); }
|
||||
Argument::operator boost::dynamic_bitset<>() const { throw IfcParse::IfcException("Argument is not a binary"); }
|
||||
Argument::operator IfcUtil::IfcBaseClass*() const { throw IfcParse::IfcException("Argument is not an entity instance"); }
|
||||
Argument::operator std::vector<double>() const { throw IfcParse::IfcException("Argument is not a list of floats"); }
|
||||
Argument::operator std::vector<int>() const { throw IfcParse::IfcException("Argument is not a list of ints"); }
|
||||
Argument::operator std::vector<std::string>() const { throw IfcParse::IfcException("Argument is not a list of strings"); }
|
||||
Argument::operator std::vector<boost::dynamic_bitset<> >() const { throw IfcParse::IfcException("Argument is not a list of binaries"); }
|
||||
Argument::operator IfcEntityList::ptr() const { throw IfcParse::IfcException("Argument is not a list of entity instances"); }
|
||||
Argument::operator std::vector< std::vector<int> >() const { throw IfcParse::IfcException("Argument is not a list of list of ints"); }
|
||||
Argument::operator std::vector< std::vector<double> >() const { throw IfcParse::IfcException("Argument is not a list of list of floats"); }
|
||||
Argument::operator IfcEntityListList::ptr() const { throw IfcParse::IfcException("Argument is not a list of list of entity instances"); }
|
||||
|
||||
|
||||
static const char* const argument_type_string[] = {
|
||||
"NULL",
|
||||
"DERIVED",
|
||||
|
||||
+14
-14
@@ -283,22 +283,22 @@ namespace IfcParse {
|
||||
|
||||
class IfcParse_EXPORT Argument {
|
||||
public:
|
||||
virtual operator int() const = 0;
|
||||
virtual operator bool() const = 0;
|
||||
virtual operator double() const = 0;
|
||||
virtual operator std::string() const = 0;
|
||||
virtual operator boost::dynamic_bitset<>() const = 0;
|
||||
virtual operator IfcUtil::IfcBaseClass*() const = 0;
|
||||
virtual operator int() const;
|
||||
virtual operator bool() const;
|
||||
virtual operator double() const;
|
||||
virtual operator std::string() const;
|
||||
virtual operator boost::dynamic_bitset<>() const;
|
||||
virtual operator IfcUtil::IfcBaseClass*() const;
|
||||
|
||||
virtual operator std::vector<int>() const = 0;
|
||||
virtual operator std::vector<double>() const = 0;
|
||||
virtual operator std::vector<std::string>() const = 0;
|
||||
virtual operator std::vector<boost::dynamic_bitset<> >() const = 0;
|
||||
virtual operator IfcEntityList::ptr() const = 0;
|
||||
virtual operator std::vector<int>() const;
|
||||
virtual operator std::vector<double>() const;
|
||||
virtual operator std::vector<std::string>() const;
|
||||
virtual operator std::vector<boost::dynamic_bitset<> >() const;
|
||||
virtual operator IfcEntityList::ptr() const;
|
||||
|
||||
virtual operator std::vector< std::vector<int> >() const = 0;
|
||||
virtual operator std::vector< std::vector<double> >() const = 0;
|
||||
virtual operator IfcEntityListList::ptr() const = 0;
|
||||
virtual operator std::vector< std::vector<int> >() const;
|
||||
virtual operator std::vector< std::vector<double> >() const;
|
||||
virtual operator IfcEntityListList::ptr() const;
|
||||
|
||||
virtual bool isNull() const = 0;
|
||||
virtual unsigned int size() const = 0;
|
||||
|
||||
Reference in New Issue
Block a user