2012-08-11 13:24:08 +00:00
/********************************************************************************
2023-09-18 16:13:44 +02:00
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell 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 *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
2011-05-08 11:04:32 +00:00
2023-09-17 12:30:17 +02:00
# include "IfcParse.h"
# include "IfcBaseClass.h"
# include "IfcCharacterDecoder.h"
# include "IfcException.h"
# include "IfcFile.h"
2023-10-24 11:47:44 +02:00
# include "IfcLogger.h"
2023-09-17 12:30:17 +02:00
# include "IfcSchema.h"
# include "IfcSIPrefix.h"
# include "IfcSpfStream.h"
# include "utils.h"
2011-05-08 11:04:32 +00:00
2023-09-17 12:30:17 +02:00
# include <algorithm>
# include <boost/algorithm/string.hpp>
2024-08-23 20:29:07 +02:00
# include <boost/variant.hpp>
2023-09-17 12:30:17 +02:00
# include <boost/math/special_functions/fpclassify.hpp>
2019-07-03 12:10:27 +02:00
# include <ctime>
2023-09-17 12:30:17 +02:00
# include <set>
2019-07-03 12:10:27 +02:00
# include <stdio.h>
# include <stdlib.h>
2023-09-17 12:30:17 +02:00
# include <string>
2024-08-23 20:29:07 +02:00
# include <iomanip>
2019-07-03 12:10:27 +02:00
2023-09-18 16:13:44 +02:00
# ifdef USE_MMAP
# include <boost/filesystem/path.hpp>
# endif
2016-06-12 11:22:08 +02:00
# define PERMISSIVE_FLOAT
2011-05-08 11:04:32 +00:00
using namespace IfcParse ;
2023-09-17 12:30:17 +02:00
// A static locale for the real number parser. strtod() is locale-dependent, causing issues
// in locales that have ',' as a decimal separator. Therefore the non standard _strtod_l() /
// strtod_l() is used and a reference to the "C" locale is obtained here. The alternative is
// to use std::istringstream::imbue(std::locale::classic()), but there are subtleties in
// parsing in MSVC2010 and it appears to be much slower.
2016-06-05 14:03:03 +02:00
# if defined(_MSC_VER)
2023-09-17 12:30:17 +02:00
static _locale_t locale = ( _locale_t ) 0 ;
2015-02-03 13:53:36 +00:00
void init_locale ( ) {
2023-09-17 12:30:17 +02:00
if ( locale = = ( _locale_t ) 0 ) {
locale = _create_locale ( LC_NUMERIC , " C " ) ;
}
2015-02-03 13:53:36 +00:00
}
2016-05-29 17:58:03 +01:00
2016-06-05 14:03:03 +02:00
# else
2015-02-03 13:53:36 +00:00
2016-06-05 14:03:03 +02:00
# if defined(__MINGW64__) || defined(__MINGW32__)
2016-05-29 17:58:03 +01:00
# include <locale>
# include <sstream>
typedef void * locale_t ;
2016-06-05 14:03:03 +02:00
static locale_t locale = ( locale_t ) 0 ;
2016-05-29 17:58:03 +01:00
void init_locale ( ) { }
double strtod_l ( const char * start , char * * end , locale_t loc ) {
2023-09-17 12:30:17 +02:00
double d ;
std : : stringstream ss ;
ss . imbue ( std : : locale : : classic ( ) ) ;
ss < < start ;
ss > > d ;
size_t nread = ss . tellg ( ) ;
* end = const_cast < char * > ( start ) + nread ;
return d ;
2016-06-05 14:03:03 +02:00
}
# else
# ifdef __APPLE__
# include <xlocale.h>
# endif
# include <locale.h>
static locale_t locale = ( locale_t ) 0 ;
void init_locale ( ) {
2023-09-17 12:30:17 +02:00
if ( locale = = ( locale_t ) 0 ) {
locale = newlocale ( LC_NUMERIC_MASK , " C " , ( locale_t ) 0 ) ;
}
2016-05-29 17:58:03 +01:00
}
2016-06-05 14:03:03 +02:00
2016-05-29 17:58:03 +01:00
# endif
2016-06-05 14:03:03 +02:00
# endif
2016-05-29 17:58:03 +01:00
2023-09-17 12:30:17 +02:00
//
2017-07-23 14:52:04 +02:00
// Opens the file and gets the filesize
2011-07-11 09:33:18 +00:00
//
2017-07-23 14:52:04 +02:00
# ifdef USE_MMAP
2023-11-06 20:29:00 +01:00
IfcSpfStream : : IfcSpfStream ( const std : : string & path , bool mmap )
2017-07-23 14:52:04 +02:00
# else
2023-11-06 20:29:00 +01:00
IfcSpfStream : : IfcSpfStream ( const std : : string & path )
2017-07-23 14:52:04 +02:00
# endif
2023-11-06 20:38:19 +01:00
: stream_ ( 0 ) ,
buffer_ ( 0 ) ,
2023-09-17 12:30:17 +02:00
valid ( false ) ,
eof ( false ) {
2012-12-31 11:47:46 +00:00
# ifdef _MSC_VER
2023-11-06 20:29:00 +01:00
std : : wstring fn_ws = IfcUtil : : path : : from_utf8 ( path ) ;
2023-09-17 12:30:17 +02:00
const wchar_t * fn_wide = fn_ws . c_str ( ) ;
2017-07-23 14:52:04 +02:00
# ifdef USE_MMAP
2023-09-17 12:30:17 +02:00
if ( mmap ) {
mfs = boost : : iostreams : : mapped_file_source ( boost : : filesystem : : wpath ( fn_wide ) ) ;
} else {
2017-07-23 14:52:04 +02:00
# endif
2023-11-06 20:38:19 +01:00
stream_ = _wfopen ( fn_wide , L " rb " ) ;
2023-09-17 12:30:17 +02:00
# ifdef USE_MMAP
}
2017-07-23 14:52:04 +02:00
# endif
2012-12-31 11:47:46 +00:00
# else
2017-07-23 14:52:04 +02:00
# ifdef USE_MMAP
2023-09-17 12:30:17 +02:00
if ( mmap ) {
2023-11-06 20:29:00 +01:00
mfs = boost : : iostreams : : mapped_file_source ( path ) ;
2023-09-17 12:30:17 +02:00
} else {
2012-12-31 11:47:46 +00:00
# endif
2023-11-06 20:29:00 +01:00
stream_ = fopen ( path . c_str ( ) , " rb " ) ;
2023-09-17 12:30:17 +02:00
# ifdef USE_MMAP
}
2017-07-23 14:52:04 +02:00
# endif
# endif
# ifdef USE_MMAP
2023-09-17 12:30:17 +02:00
if ( mmap ) {
if ( ! mfs . is_open ( ) ) {
return ;
}
valid = true ;
2023-11-06 20:38:19 +01:00
buffer_ = mfs . data ( ) ;
ptr_ = 0 ;
len_ = mfs . size ( ) ;
2023-09-17 12:30:17 +02:00
} else {
2017-07-23 14:52:04 +02:00
# endif
2023-11-06 20:38:19 +01:00
if ( stream_ = = NULL ) {
2023-09-17 12:30:17 +02:00
return ;
}
valid = true ;
2023-11-06 20:38:19 +01:00
fseek ( stream_ , 0 , SEEK_END ) ;
size = ( unsigned int ) ftell ( stream_ ) ;
rewind ( stream_ ) ;
2023-09-17 12:30:17 +02:00
char * buffer_rw = new char [ size ] ;
2023-11-06 20:38:19 +01:00
len_ = ( unsigned int ) fread ( buffer_rw , 1 , size , stream_ ) ;
buffer_ = buffer_rw ;
eof = len_ = = 0 ;
ptr_ = 0 ;
fclose ( stream_ ) ;
stream_ = nullptr ;
2023-09-17 12:30:17 +02:00
# ifdef USE_MMAP
}
2012-05-26 09:00:30 +00:00
# endif
2011-07-11 09:33:18 +00:00
}
2023-11-06 20:29:00 +01:00
IfcSpfStream : : IfcSpfStream ( std : : istream & stream , int length )
2023-11-06 20:38:19 +01:00
: stream_ ( 0 ) ,
buffer_ ( 0 ) {
2023-09-17 12:30:17 +02:00
eof = false ;
2023-11-06 20:29:00 +01:00
size = length ;
2023-09-17 12:30:17 +02:00
char * buffer_rw = new char [ size ] ;
2023-11-06 20:29:00 +01:00
stream . read ( buffer_rw , size ) ;
2023-11-06 20:38:19 +01:00
buffer_ = buffer_rw ;
2023-11-06 20:29:00 +01:00
valid = stream . gcount ( ) = = size ;
2023-11-06 20:38:19 +01:00
ptr_ = 0 ;
2023-11-06 20:29:00 +01:00
len_ = length ;
2011-08-20 09:08:56 +00:00
}
2023-11-06 20:29:00 +01:00
IfcSpfStream : : IfcSpfStream ( void * data , int length )
2023-11-06 20:38:19 +01:00
: stream_ ( 0 ) ,
buffer_ ( 0 ) {
2023-09-17 12:30:17 +02:00
eof = false ;
2023-11-06 20:29:00 +01:00
size = length ;
2023-11-06 20:38:19 +01:00
buffer_ = ( char * ) data ;
2023-09-17 12:30:17 +02:00
valid = true ;
2023-11-06 20:38:19 +01:00
ptr_ = 0 ;
2023-11-06 20:29:00 +01:00
len_ = length ;
2011-10-27 16:13:29 +00:00
}
2023-09-17 12:30:17 +02:00
IfcSpfStream : : ~ IfcSpfStream ( ) {
Close ( ) ;
2016-02-07 22:45:42 +02:00
}
2012-08-11 13:24:08 +00:00
void IfcSpfStream : : Close ( ) {
2017-07-23 14:52:04 +02:00
# ifdef USE_MMAP
2023-09-17 12:30:17 +02:00
if ( mfs . is_open ( ) ) {
mfs . close ( ) ;
return ;
}
2012-08-11 13:24:08 +00:00
# endif
2023-11-06 20:38:19 +01:00
delete [ ] buffer_ ;
if ( stream_ ! = nullptr ) {
fclose ( stream_ ) ;
2023-09-17 12:30:17 +02:00
}
2011-07-11 09:33:18 +00:00
}
//
// Seeks an arbitrary position in the file
//
2023-11-06 20:29:00 +01:00
void IfcSpfStream : : Seek ( unsigned int offset ) {
ptr_ = offset ;
2023-11-06 20:38:19 +01:00
if ( ptr_ > = len_ ) {
2023-09-17 12:30:17 +02:00
throw IfcException ( " Reading outside of file limits " ) ;
}
eof = false ;
2011-07-11 09:33:18 +00:00
}
//
// Returns the character at the cursor
//
2012-08-11 13:24:08 +00:00
char IfcSpfStream : : Peek ( ) {
2023-11-06 20:38:19 +01:00
return buffer_ [ ptr_ ] ;
2011-07-11 09:33:18 +00:00
}
//
// Returns the character at specified offset
//
2023-11-06 20:29:00 +01:00
char IfcSpfStream : : Read ( unsigned int offset ) {
return buffer_ [ offset ] ;
2011-07-11 09:33:18 +00:00
}
//
// Returns the cursor position
//
2024-08-23 20:29:07 +02:00
unsigned int IfcSpfStream : : Tell ( ) const {
2023-11-06 20:38:19 +01:00
return ptr_ ;
2011-07-11 09:33:18 +00:00
}
//
// Increments cursor and reads new chunk if necessary
//
2012-08-11 13:24:08 +00:00
void IfcSpfStream : : Inc ( ) {
2023-11-06 20:38:19 +01:00
if ( + + ptr_ = = len_ ) {
2023-09-17 12:30:17 +02:00
eof = true ;
return ;
}
const char current = IfcSpfStream : : Peek ( ) ;
if ( current = = ' \n ' | | current = = ' \r ' ) {
// NB this is recursive. It might as well be a loop.
IfcSpfStream : : Inc ( ) ;
}
2011-07-11 09:33:18 +00:00
}
2025-08-25 12:45:10 +02:00
IfcSpfLexer : : IfcSpfLexer ( IfcParse : : IfcSpfStream * stream_ ) {
2023-11-06 20:29:00 +01:00
stream = stream_ ;
decoder_ = new IfcCharacterDecoder ( stream_ ) ;
2011-09-25 09:53:22 +00:00
}
2015-01-05 17:46:23 +00:00
IfcSpfLexer : : ~ IfcSpfLexer ( ) {
2023-11-06 20:38:19 +01:00
delete decoder_ ;
2011-07-11 09:33:18 +00:00
}
2024-08-23 20:29:07 +02:00
unsigned int IfcSpfLexer : : skipWhitespace ( ) const {
2023-11-06 20:29:00 +01:00
unsigned int index = 0 ;
2023-09-17 12:30:17 +02:00
while ( ! stream - > eof ) {
2023-11-06 20:29:00 +01:00
char character = stream - > Peek ( ) ;
if ( ( character = = ' ' | | character = = ' \r ' | | character = = ' \n ' | | character = = ' \t ' ) ) {
2023-09-17 12:30:17 +02:00
stream - > Inc ( ) ;
2023-11-06 20:29:00 +01:00
+ + index ;
2023-09-17 12:30:17 +02:00
} else {
break ;
}
}
2023-11-06 20:29:00 +01:00
return index ;
2014-04-02 15:04:09 +00:00
}
2024-08-23 20:29:07 +02:00
unsigned int IfcSpfLexer : : skipComment ( ) const {
2023-11-06 20:29:00 +01:00
char character = stream - > Peek ( ) ;
if ( character ! = ' / ' ) {
2023-09-17 12:30:17 +02:00
return 0 ;
}
stream - > Inc ( ) ;
2023-11-06 20:29:00 +01:00
character = stream - > Peek ( ) ;
if ( character ! = ' * ' ) {
2023-09-17 12:30:17 +02:00
stream - > Seek ( stream - > Tell ( ) - 1 ) ;
return 0 ;
}
2023-11-06 20:29:00 +01:00
unsigned int index = 2 ;
char intermediate = 0 ;
2023-09-17 12:30:17 +02:00
while ( ! stream - > eof ) {
2023-11-06 20:29:00 +01:00
character = stream - > Peek ( ) ;
2023-09-17 12:30:17 +02:00
stream - > Inc ( ) ;
2023-11-06 20:29:00 +01:00
+ + index ;
if ( character = = ' / ' & & intermediate = = ' * ' ) {
2023-09-17 12:30:17 +02:00
break ;
}
2023-11-06 20:29:00 +01:00
intermediate = character ;
2023-09-17 12:30:17 +02:00
}
2023-11-06 20:29:00 +01:00
return index ;
2014-04-02 15:04:09 +00:00
}
2011-07-11 09:33:18 +00:00
//
// Returns the offset of the current Token and moves cursor to next
//
2015-01-05 17:46:23 +00:00
Token IfcSpfLexer : : Next ( ) {
2011-07-11 09:33:18 +00:00
2023-09-17 12:30:17 +02:00
if ( stream - > eof ) {
2025-08-25 12:45:10 +02:00
return Token { } ;
2023-09-17 12:30:17 +02:00
}
2011-07-11 09:33:18 +00:00
2023-10-24 14:16:26 +02:00
while ( ( skipWhitespace ( ) ! = 0U ) | | ( skipComment ( ) ! = 0U ) ) {
2023-09-17 12:30:17 +02:00
}
2011-07-11 09:33:18 +00:00
2023-09-17 12:30:17 +02:00
if ( stream - > eof ) {
2025-08-25 12:45:10 +02:00
return Token { } ;
2023-09-17 12:30:17 +02:00
}
unsigned int pos = stream - > Tell ( ) ;
2023-11-06 20:29:00 +01:00
char character = stream - > Peek ( ) ;
2011-07-11 09:33:18 +00:00
2023-09-17 12:30:17 +02:00
// If the cursor is at [()=,;$*] we know token consists of single char
2023-11-06 20:29:00 +01:00
if ( character = = ' ( ' | |
character = = ' ) ' | |
character = = ' = ' | |
character = = ' , ' | |
character = = ' ; ' | |
character = = ' $ ' | |
character = = ' * ' ) {
2023-09-17 12:30:17 +02:00
stream - > Inc ( ) ;
return OperatorTokenPtr ( this , pos , pos + 1 ) ;
}
2011-07-11 09:33:18 +00:00
2023-09-17 12:30:17 +02:00
int len = 0 ;
2011-07-11 09:33:18 +00:00
2023-09-17 12:30:17 +02:00
while ( ! stream - > eof ) {
2011-07-11 09:33:18 +00:00
2023-09-17 12:30:17 +02:00
// Read character and increment pointer if not starting a new token
2023-11-06 20:29:00 +01:00
character = stream - > Peek ( ) ;
if ( ( len ! = 0 ) & & ( character = = ' ( ' | |
character = = ' ) ' | |
character = = ' = ' | |
character = = ' , ' | |
character = = ' ; ' | |
character = = ' / ' ) ) {
2023-09-17 12:30:17 +02:00
break ;
}
stream - > Inc ( ) ;
len + + ;
// If a string is encountered defer processing to the IfcCharacterDecoder
2023-11-06 20:29:00 +01:00
if ( character = = ' \' ' ) {
2023-11-06 20:38:19 +01:00
decoder_ - > skip ( ) ;
2023-09-17 12:30:17 +02:00
}
}
2024-08-23 20:29:07 +02:00
Token t ;
2023-10-24 14:16:26 +02:00
if ( len ! = 0 ) {
2024-08-23 20:29:07 +02:00
t = GeneralTokenPtr ( this , pos , stream - > Tell ( ) ) ;
} else {
2025-08-25 12:45:10 +02:00
t = Token { } ;
2023-09-17 12:30:17 +02:00
}
2024-08-23 20:29:07 +02:00
// std::wcout << "token: " << pos << " " << TokenFunc::asStringRef(t).c_str() << std::endl;
return t ;
2011-07-11 09:33:18 +00:00
}
2024-08-23 20:29:07 +02:00
bool IfcSpfStream : : is_eof_at ( unsigned int local_ptr ) const {
2023-11-06 20:38:19 +01:00
return local_ptr > = len_ ;
2019-07-03 12:10:27 +02:00
}
void IfcSpfStream : : increment_at ( unsigned int & local_ptr ) {
2023-11-06 20:38:19 +01:00
if ( + + local_ptr = = len_ ) {
2023-09-17 12:30:17 +02:00
return ;
}
const char current = IfcSpfStream : : peek_at ( local_ptr ) ;
if ( current = = ' \n ' | | current = = ' \r ' ) {
IfcSpfStream : : increment_at ( local_ptr ) ;
}
2019-07-03 12:10:27 +02:00
}
char IfcSpfStream : : peek_at ( unsigned int local_ptr ) {
2023-11-06 20:38:19 +01:00
return buffer_ [ local_ptr ] ;
2019-07-03 12:10:27 +02:00
}
2011-07-11 09:33:18 +00:00
//
// Reads a std::string from the file at specified offset
// Omits whitespace and comments
//
2023-09-17 12:30:17 +02:00
void IfcSpfLexer : : TokenString ( unsigned int offset , std : : string & buffer ) {
buffer . clear ( ) ;
while ( ! stream - > is_eof_at ( offset ) ) {
2023-11-06 20:29:00 +01:00
char character = stream - > peek_at ( offset ) ;
if ( ! buffer . empty ( ) & & ( character = = ' ( ' | |
character = = ' ) ' | |
character = = ' = ' | |
character = = ' , ' | |
character = = ' ; ' | |
character = = ' / ' ) ) {
2023-09-17 12:30:17 +02:00
break ;
}
stream - > increment_at ( offset ) ;
2023-11-06 20:29:00 +01:00
if ( character = = ' ' | |
character = = ' \r ' | |
character = = ' \n ' | |
character = = ' \t ' ) {
2023-09-17 12:30:17 +02:00
continue ;
2023-10-24 12:21:32 +02:00
}
2023-11-06 20:29:00 +01:00
if ( character = = ' \' ' ) {
2023-09-17 12:30:17 +02:00
// todo, make decoder use local offset ptr
2023-11-06 20:38:19 +01:00
buffer = decoder_ - > get ( offset ) ;
2023-09-17 12:30:17 +02:00
break ;
}
2023-11-06 20:29:00 +01:00
buffer . push_back ( character ) ;
2023-09-17 12:30:17 +02:00
}
2011-07-11 09:33:18 +00:00
}
2016-06-09 22:25:50 +06:00
//Note: according to STEP standard, there may be newlines in tokens
2023-09-17 12:30:17 +02:00
inline void RemoveTokenSeparators ( IfcSpfStream * stream , unsigned start , unsigned end , std : : string & oDestination ) {
oDestination . clear ( ) ;
for ( unsigned i = start ; i < end ; i + + ) {
2023-11-06 20:29:00 +01:00
char character = stream - > Read ( i ) ;
if ( character = = ' ' | |
character = = ' \r ' | |
character = = ' \n ' | |
character = = ' \t ' ) {
2023-09-17 12:30:17 +02:00
continue ;
}
2023-11-06 20:29:00 +01:00
oDestination + = character ;
2023-09-17 12:30:17 +02:00
}
2016-06-09 22:25:50 +06:00
}
2011-07-11 09:33:18 +00:00
2023-09-17 12:30:17 +02:00
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 ;
2016-06-09 22:25:50 +06:00
}
2023-09-17 12:30:17 +02:00
bool ParseFloat ( const char * pStart , double & val ) {
char * pEnd ;
2016-06-09 22:25:50 +06:00
# ifdef _MSC_VER
2023-09-17 12:30:17 +02:00
double result = _strtod_l ( pStart , & pEnd , locale ) ;
2016-06-09 22:25:50 +06:00
# else
2023-09-17 12:30:17 +02:00
double result = strtod_l ( pStart , & pEnd , locale ) ;
2016-06-09 22:25:50 +06:00
# endif
2023-09-17 12:30:17 +02:00
if ( * pEnd ! = 0 ) {
return false ;
}
val = result ;
return true ;
}
2021-07-29 14:54:51 +02:00
2023-09-17 12:30:17 +02:00
bool ParseBool ( const char * pStart , int & val ) {
if ( strlen ( pStart ) ! = 3 | | pStart [ 0 ] ! = ' . ' | | pStart [ 2 ] ! = ' . ' ) {
return false ;
}
char mid = pStart [ 1 ] ;
if ( mid = = ' T ' ) {
val = 1 ;
} else if ( mid = = ' F ' ) {
val = 0 ;
} else if ( mid = = ' U ' ) {
val = 2 ;
} else {
return false ;
}
return true ;
2016-06-09 22:25:50 +06:00
}
Token IfcParse : : OperatorTokenPtr ( IfcSpfLexer * lexer , unsigned start , unsigned end ) {
2023-09-17 12:30:17 +02:00
char first = lexer - > stream - > Read ( start ) ;
Token token ( lexer , start , end , Token_OPERATOR ) ;
token . value_char = first ;
return token ;
2016-06-09 22:25:50 +06:00
}
Token IfcParse : : GeneralTokenPtr ( IfcSpfLexer * lexer , unsigned start , unsigned end ) {
2023-09-17 12:30:17 +02:00
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 ) ) {
2025-01-14 12:07:21 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Token ' " + tokenStr + " ' at offset " + std : : to_string ( token . startPos ) + " is not valid " ) ;
token . type = Token_OPERATOR ;
token . value_char = ' $ ' ;
2023-09-17 12:30:17 +02:00
}
} else if ( first = = ' \' ' ) {
token . type = Token_STRING ;
} else if ( first = = ' . ' ) {
token . type = Token_ENUMERATION ;
if ( ParseBool ( tokenStr . c_str ( ) , token . value_int ) ) { //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 ;
}
2016-06-09 22:25:50 +06:00
2023-09-17 12:30:17 +02:00
return token ;
2016-06-09 22:25:50 +06:00
}
2023-11-06 20:29:00 +01:00
bool TokenFunc : : isOperator ( const Token & token ) {
return token . type = = Token_OPERATOR ;
2011-05-08 11:04:32 +00:00
}
2015-02-03 13:53:36 +00:00
2023-11-06 20:29:00 +01:00
bool TokenFunc : : isOperator ( const Token & token , char character ) {
return token . type = = Token_OPERATOR & & token . value_char = = character ;
2011-06-13 07:23:09 +00:00
}
2015-02-03 13:53:36 +00:00
2023-11-06 20:29:00 +01:00
bool TokenFunc : : isIdentifier ( const Token & token ) {
return token . type = = Token_IDENTIFIER ;
2011-05-08 11:04:32 +00:00
}
2015-02-03 13:53:36 +00:00
2023-11-06 20:29:00 +01:00
bool TokenFunc : : isString ( const Token & token ) {
return token . type = = Token_STRING ;
2011-05-08 11:04:32 +00:00
}
2015-02-03 13:53:36 +00:00
2023-11-06 20:29:00 +01:00
bool TokenFunc : : isEnumeration ( const Token & token ) {
return token . type = = Token_ENUMERATION | | token . type = = Token_BOOL ;
2011-05-08 11:04:32 +00:00
}
2015-02-03 13:53:36 +00:00
2023-11-06 20:29:00 +01:00
bool TokenFunc : : isBinary ( const Token & token ) {
return token . type = = Token_BINARY ;
2015-04-07 15:06:56 +00:00
}
2023-11-06 20:29:00 +01:00
bool TokenFunc : : isKeyword ( const Token & token ) {
return token . type = = Token_KEYWORD ;
2011-05-08 11:04:32 +00:00
}
2015-02-03 13:53:36 +00:00
2023-11-06 20:29:00 +01:00
bool TokenFunc : : isInt ( const Token & token ) {
return token . type = = Token_INT ;
2014-11-02 18:36:51 +00:00
}
2015-02-03 13:53:36 +00:00
2023-11-06 20:29:00 +01:00
bool TokenFunc : : isBool ( const Token & token ) {
2023-09-17 12:30:17 +02:00
// Bool and logical share the same storage type, just logical unknown is stored as 2.
2023-11-06 20:29:00 +01:00
return token . type = = Token_BOOL & & token . value_int ! = 2 ;
2021-07-29 14:54:51 +02:00
}
2023-11-06 20:29:00 +01:00
bool TokenFunc : : isLogical ( const Token & token ) {
return token . type = = Token_BOOL ;
2014-11-02 18:36:51 +00:00
}
2015-02-03 13:53:36 +00:00
2023-11-06 20:29:00 +01:00
bool TokenFunc : : isFloat ( const Token & token ) {
2016-06-12 11:22:08 +02:00
# ifdef PERMISSIVE_FLOAT
2023-09-17 12:30:17 +02:00
/// NB: We are being more permissive here then allowed by the standard
2023-11-06 20:29:00 +01:00
return token . type = = Token_FLOAT | | token . type = = Token_INT ;
2016-06-12 11:22:08 +02:00
# else
2023-11-06 20:29:00 +01:00
return token . type = = Token_FLOAT ;
2016-06-12 11:22:08 +02:00
# endif
2014-11-02 18:36:51 +00:00
}
2015-02-03 13:53:36 +00:00
2023-11-06 20:29:00 +01:00
int TokenFunc : : asInt ( const Token & token ) {
if ( token . type ! = Token_INT ) {
throw IfcInvalidTokenException ( token . startPos , toString ( token ) , " integer " ) ;
2023-09-17 12:30:17 +02:00
}
2023-11-06 20:29:00 +01:00
return token . value_int ;
2016-06-09 22:25:50 +06:00
}
2023-11-06 20:29:00 +01:00
int TokenFunc : : asIdentifier ( const Token & token ) {
if ( token . type ! = Token_IDENTIFIER ) {
throw IfcInvalidTokenException ( token . startPos , toString ( token ) , " instance name " ) ;
2023-09-17 12:30:17 +02:00
}
2023-11-06 20:29:00 +01:00
return token . value_int ;
2011-06-13 07:23:09 +00:00
}
2015-02-03 13:53:36 +00:00
2023-11-06 20:29:00 +01:00
bool TokenFunc : : asBool ( const Token & token ) {
if ( token . type ! = Token_BOOL ) {
throw IfcInvalidTokenException ( token . startPos , toString ( token ) , " boolean " ) ;
2023-09-17 12:30:17 +02:00
}
2023-11-06 20:29:00 +01:00
return token . value_int = = 1 ;
2021-07-29 14:54:51 +02:00
}
2023-11-06 20:29:00 +01:00
boost : : logic : : tribool TokenFunc : : asLogical ( const Token & token ) {
if ( token . type ! = Token_BOOL ) {
throw IfcInvalidTokenException ( token . startPos , toString ( token ) , " boolean " ) ;
2023-09-17 12:30:17 +02:00
}
2023-11-06 20:29:00 +01:00
if ( token . value_int = = 0 ) {
2023-09-17 12:30:17 +02:00
return false ;
2023-10-24 12:21:32 +02:00
}
2023-11-06 20:29:00 +01:00
if ( token . value_int = = 1 ) {
2023-09-17 12:30:17 +02:00
return true ;
}
2023-10-24 12:21:32 +02:00
return boost : : logic : : indeterminate ;
2011-05-08 11:04:32 +00:00
}
2015-02-03 13:53:36 +00:00
2023-11-06 20:29:00 +01:00
double TokenFunc : : asFloat ( const Token & token ) {
2016-06-12 11:22:08 +02:00
# ifdef PERMISSIVE_FLOAT
2023-11-06 20:29:00 +01:00
if ( token . type = = Token_INT ) {
2023-09-17 12:30:17 +02:00
/// NB: We are being more permissive here then allowed by the standard
2023-11-06 20:29:00 +01:00
return token . value_int ;
2023-10-24 12:21:32 +02:00
} // ----> continues beyond preprocessor directive
2016-06-12 11:22:08 +02:00
# endif
2023-11-06 20:29:00 +01:00
if ( token . type = = Token_FLOAT ) {
return token . value_double ;
2023-09-17 12:30:17 +02:00
}
2023-11-06 20:29:00 +01:00
throw IfcInvalidTokenException ( token . startPos , toString ( token ) , " real " ) ;
2016-06-09 22:25:50 +06:00
}
2023-11-06 20:29:00 +01:00
const std : : string & TokenFunc : : asStringRef ( const Token & token ) {
if ( token . type = = Token_NONE ) {
2017-03-02 16:12:20 +02:00
throw IfcParse : : IfcException ( " Null token encountered, premature end of file? " ) ;
}
2023-11-06 20:29:00 +01:00
std : : string & str = token . lexer - > GetTempString ( ) ;
token . lexer - > TokenString ( token . startPos , str ) ;
if ( ( isString ( token ) | | isEnumeration ( token ) | | isBinary ( token ) ) & & ! str . empty ( ) ) {
2023-09-17 12:30:17 +02:00
//remove start+end characters in-place
str . erase ( str . end ( ) - 1 ) ;
str . erase ( str . begin ( ) ) ;
}
return str ;
2011-07-11 09:33:18 +00:00
}
2015-02-03 13:53:36 +00:00
2023-11-06 20:29:00 +01:00
std : : string TokenFunc : : asString ( const Token & token ) {
if ( isString ( token ) | | isEnumeration ( token ) | | isBinary ( token ) ) {
return asStringRef ( token ) ;
2023-09-17 12:30:17 +02:00
}
2023-11-06 20:29:00 +01:00
throw IfcInvalidTokenException ( token . startPos , toString ( token ) , " string " ) ;
2015-04-07 15:06:56 +00:00
}
2023-11-06 20:29:00 +01:00
boost : : dynamic_bitset < > TokenFunc : : asBinary ( const Token & token ) {
const std : : string & str = asStringRef ( token ) ;
2024-08-23 20:29:07 +02:00
if ( str . empty ( ) ) {
2023-09-17 12:30:17 +02:00
throw IfcException ( " Token is not a valid binary sequence " ) ;
}
2015-04-07 15:06:56 +00:00
2023-09-17 12:30:17 +02:00
std : : string : : const_iterator it = str . begin ( ) ;
int n = * it - ' 0 ' ;
if ( ( n < 0 | | n > 3 ) | | ( str . size ( ) = = 1 & & n ! = 0 ) ) {
throw IfcException ( " Token is not a valid binary sequence " ) ;
}
+ + it ;
unsigned i = ( ( unsigned ) str . size ( ) - 1 ) * 4 - n ;
boost : : dynamic_bitset < > bitset ( i ) ;
for ( ; it ! = str . end ( ) ; + + it ) {
const std : : string : : value_type & c = * it ;
int value = ( c < ' A ' ) ? ( c - ' 0 ' ) : ( c - ' A ' + 10 ) ;
for ( unsigned j = 0 ; j < 4 ; + + j ) {
if ( i - - = = 0 ) {
break ;
}
2023-10-24 14:16:26 +02:00
if ( ( value & ( 1 < < ( 3 - j ) ) ) ! = 0 ) {
2023-09-17 12:30:17 +02:00
bitset . set ( i ) ;
}
}
}
2015-04-07 15:06:56 +00:00
2023-09-17 12:30:17 +02:00
return bitset ;
2011-05-08 11:04:32 +00:00
}
2015-02-03 13:53:36 +00:00
2023-11-06 20:29:00 +01:00
std : : string TokenFunc : : toString ( const Token & token ) {
2023-09-17 12:30:17 +02:00
std : : string result ;
2023-11-06 20:29:00 +01:00
token . lexer - > TokenString ( token . startPos , result ) ;
2023-09-17 12:30:17 +02:00
return result ;
2011-07-11 09:33:18 +00:00
}
2023-09-17 12:30:17 +02:00
//
2011-07-11 09:33:18 +00:00
// Reads the arguments from a list of token
2017-06-05 17:26:58 +02:00
// Aditionally, registers the ids (i.e. #[\d]+) in the inverse map
2011-07-11 09:33:18 +00:00
//
2025-02-21 16:12:16 +01:00
void IfcParse : : impl : : in_memory_file_storage : : load ( unsigned entity_instance_name , const IfcParse : : entity * entity , parse_context & context , int attribute_index ) {
2023-09-17 12:30:17 +02:00
Token next = tokens - > Next ( ) ;
2024-08-23 20:29:07 +02:00
/*
if (TokenFunc::isOperator(next, '(')) {
next = tokens->Next();
2023-09-17 12:30:17 +02:00
}
2024-08-23 20:29:07 +02:00
*/
2018-01-29 12:11:50 +01:00
2024-08-23 20:29:07 +02:00
size_t attribute_index_within_data = 0 ;
2023-09-17 12:30:17 +02:00
size_t return_value = 0 ;
2023-10-24 14:16:26 +02:00
while ( ( next . startPos ! = 0U ) | | ( next . lexer ! = nullptr ) ) {
2023-09-17 12:30:17 +02:00
if ( TokenFunc : : isOperator ( next , ' , ' ) ) {
2024-08-23 20:29:07 +02:00
if ( attribute_index = = - 1 ) {
attribute_index_within_data + = 1 ;
}
2023-09-17 12:30:17 +02:00
} else if ( TokenFunc : : isOperator ( next , ' ) ' ) ) {
break ;
} else if ( TokenFunc : : isOperator ( next , ' ( ' ) ) {
return_value + + ;
2024-08-23 20:29:07 +02:00
load ( entity_instance_name , entity , context . push ( ) , attribute_index = = - 1 ? ( int ) attribute_index_within_data : attribute_index ) ;
2023-09-17 12:30:17 +02:00
} else {
return_value + + ;
2024-09-11 20:13:50 +02:00
if ( TokenFunc : : isIdentifier ( next ) & & entity ) {
2025-02-21 16:12:16 +01:00
register_inverse ( entity_instance_name , entity , next . value_int , attribute_index = = - 1 ? attribute_index_within_data : attribute_index ) ;
2023-09-17 12:30:17 +02:00
}
if ( TokenFunc : : isKeyword ( next ) ) {
try {
2025-08-25 12:45:10 +02:00
const auto * decl = ( schema ? schema : file - > schema ( ) ) - > declaration_by_name ( TokenFunc : : asStringRef ( next ) ) ;
2024-08-23 20:29:07 +02:00
parse_context ps ;
tokens - > Next ( ) ;
2025-04-11 15:52:40 +02:00
// The only case we know where a defined type contains entity
// instance references is IfcPropertySetDefinitionSet. For
// that purpose we propagate the entity_instance_name to
// register inverses to the host entity (and not the defined
// type) and to be able to actually register the references in
// the 2nd pass.
load ( entity_instance_name , entity , ps , attribute_index = = - 1 ? ( int ) attribute_index_within_data : attribute_index ) ;
2025-08-26 10:20:08 +02:00
auto * simple_type_instance = ( schema ? schema : file - > schema ( ) ) - > instantiate ( decl , ps . construct ( entity_instance_name , * references_to_resolve , decl , boost : : none , attribute_index = = - 1 ? ( int ) attribute_index_within_data : attribute_index ) ) ;
2024-08-23 20:29:07 +02:00
//@todo decide addEntity(((IfcUtil::IfcBaseClass*)*entity));
context . push ( simple_type_instance ) ;
2025-02-21 16:12:16 +01:00
simple_type_instance - > file_ = file ;
2023-09-17 12:30:17 +02:00
} catch ( IfcException & e ) {
Logger : : Message ( Logger : : LOG_ERROR , e . what ( ) ) ;
2024-03-27 09:36:05 +01:00
// #4070 We didn't actually capture an aggregate entry, undo length increment.
return_value - - ;
2023-09-17 12:30:17 +02:00
}
} else {
2024-08-23 20:29:07 +02:00
context . push ( next ) ;
2023-09-17 12:30:17 +02:00
}
}
next = tokens - > Next ( ) ;
}
2022-10-20 20:30:48 +02:00
}
2011-07-11 09:33:18 +00:00
//
// Reads an Entity from the list of Tokens at the specified offset in the file
//
2025-02-21 16:12:16 +01:00
IfcEntityInstanceData IfcParse : : impl : : in_memory_file_storage : : read ( unsigned int i ) {
Token datatype = tokens - > Next ( ) ;
2023-09-17 12:30:17 +02:00
if ( ! TokenFunc : : isKeyword ( datatype ) ) {
throw IfcException ( " Unexpected token while parsing entity " ) ;
}
2025-02-21 16:12:16 +01:00
const IfcParse : : declaration * ty = file - > schema ( ) - > declaration_by_name ( TokenFunc : : asStringRef ( datatype ) ) ;
2024-08-23 20:29:07 +02:00
parse_context pc ;
2025-02-21 16:12:16 +01:00
tokens - > Next ( ) ;
load ( i , ty - > as_entity ( ) , pc , - 1 ) ;
2025-08-26 10:20:08 +02:00
return IfcEntityInstanceData ( pc . construct ( i , * references_to_resolve , ty , boost : : none , - 1 ) ) ;
2011-05-08 11:04:32 +00:00
}
2011-07-11 09:33:18 +00:00
2025-02-21 16:12:16 +01:00
void IfcParse : : impl : : in_memory_file_storage : : try_read_semicolon ( ) const {
2023-09-17 12:30:17 +02:00
unsigned int old_offset = tokens - > stream - > Tell ( ) ;
Token semilocon = tokens - > Next ( ) ;
if ( ! TokenFunc : : isOperator ( semilocon , ' ; ' ) ) {
tokens - > stream - > Seek ( old_offset ) ;
}
2011-05-08 11:04:32 +00:00
}
2011-07-11 09:33:18 +00:00
2025-02-21 16:12:16 +01:00
void IfcParse : : impl : : in_memory_file_storage : : register_inverse ( unsigned id_from , const IfcParse : : entity * from_entity , int inst_id , int attribute_index ) {
2023-09-17 12:30:17 +02:00
// Assume a check on token type has already been performed
2025-02-21 16:12:16 +01:00
byref_excl_ [ { inst_id , from_entity - > index_in_schema ( ) , attribute_index } ] . push_back ( id_from ) ;
2011-05-08 11:04:32 +00:00
}
2011-07-11 09:33:18 +00:00
2025-02-21 16:12:16 +01:00
void IfcParse : : impl : : in_memory_file_storage : : unregister_inverse ( unsigned id_from , const IfcParse : : entity * from_entity , IfcUtil : : IfcBaseClass * inst , int attribute_index ) {
2025-03-09 21:20:16 +01:00
auto & ids = byref_excl_ [ { inst - > id ( ) , from_entity - > index_in_schema ( ) , attribute_index } ] ;
auto iter = std : : find ( ids . begin ( ) , ids . end ( ) , id_from ) ;
2023-11-06 20:29:00 +01:00
if ( iter = = ids . end ( ) ) {
2023-09-17 12:30:17 +02:00
// @todo inverses also need to be populated when multiple instances are added to a new file.
// throw IfcParse::IfcException("Instance not found among inverses");
} else {
2023-11-06 20:29:00 +01:00
ids . erase ( iter ) ;
2023-09-17 12:30:17 +02:00
}
2017-07-03 14:18:56 +02:00
}
2025-02-21 16:12:16 +01:00
namespace {
template < typename T >
std : : string to_string_fixed_width ( const T & t , size_t w ) {
2025-03-09 21:20:16 +01:00
// @todo currently inactive
2025-02-21 16:12:16 +01:00
std : : ostringstream oss ;
2025-03-09 21:20:16 +01:00
oss < < /*std::setfill('0') << std::setw(w) <<*/ t ;
2025-02-21 16:12:16 +01:00
return oss . str ( ) ;
}
}
void IfcParse : : impl : : rocks_db_file_storage : : register_inverse ( unsigned id_from , const IfcParse : : entity * from_entity , int inst_id , int attribute_index ) {
2025-08-26 13:56:03 +02:00
# ifdef WITH_ROCKSDB
2025-02-21 16:12:16 +01:00
static std : : string s ;
2025-03-14 16:16:25 +01:00
uint32_t v = id_from ;
s . resize ( sizeof ( uint32_t ) ) ;
memcpy ( s . data ( ) , & v , sizeof ( uint32_t ) ) ;
2025-02-27 22:07:31 +01:00
2025-03-14 16:16:25 +01:00
auto key = " v| " + to_string_fixed_width ( inst_id , 10 ) + " | " + to_string_fixed_width ( from_entity - > index_in_schema ( ) , 4 ) + " | " + to_string_fixed_width ( attribute_index , 2 ) ;
db - > Merge ( wopts , key , s ) ;
2025-02-27 22:07:31 +01:00
/*
2025-03-14 16:16:25 +01:00
// Python client does not support merges
// @todo turn this into a setting
2025-02-27 22:07:31 +01:00
{
std::string current;
db->Get(rocksdb::ReadOptions{}, key, ¤t);
auto new_val = current + s;
2025-03-14 16:16:25 +01:00
db->Put(wopts, key, new_val);
}*/
2025-08-26 13:56:03 +02:00
# endif
2025-02-21 16:12:16 +01:00
}
void IfcParse : : impl : : rocks_db_file_storage : : unregister_inverse ( unsigned id_from , const IfcParse : : entity * from_entity , IfcUtil : : IfcBaseClass * inst , int attribute_index ) {
2025-08-26 13:56:03 +02:00
# ifdef WITH_ROCKSDB
2025-02-21 16:12:16 +01:00
static std : : string s ;
auto inst_id = inst - > id ( ) ;
auto key = " v| " + to_string_fixed_width ( inst_id , 10 ) + " | " + to_string_fixed_width ( from_entity - > index_in_schema ( ) , 4 ) + " | " + to_string_fixed_width ( attribute_index , 2 ) ;
if ( db - > Get ( rocksdb : : ReadOptions { } , key , & s ) . ok ( ) ) {
2025-03-14 16:16:25 +01:00
std : : vector < uint32_t > vals ( s . size ( ) / sizeof ( uint32_t ) ) ;
2025-02-21 16:12:16 +01:00
memcpy ( vals . data ( ) , s . data ( ) , s . size ( ) ) ;
2025-08-25 12:45:10 +02:00
auto it = std : : find ( vals . begin ( ) , vals . end ( ) , ( uint32_t ) id_from ) ;
if ( it ! = vals . end ( ) ) {
vals . erase ( it ) ;
} else {
Logger : : Error ( " Unregistering non-existant inverse # " + std : : to_string ( id_from ) + " on instance # " + std : : to_string ( inst_id ) + " at attribute " + std : : to_string ( attribute_index ) ) ;
}
2025-03-14 16:16:25 +01:00
s . resize ( vals . size ( ) * sizeof ( uint32_t ) ) ;
2025-02-21 16:12:16 +01:00
memcpy ( s . data ( ) , vals . data ( ) , s . size ( ) ) ;
2025-03-14 16:16:25 +01:00
db - > Put ( wopts , key , s ) ;
2025-02-21 16:12:16 +01:00
}
2025-08-26 13:56:03 +02:00
# endif
2025-02-21 16:12:16 +01:00
}
2025-02-24 20:46:29 +01:00
void IfcParse : : impl : : rocks_db_file_storage : : add_type_ref ( IfcUtil : : IfcBaseClass * new_entity )
{
2025-08-26 13:56:03 +02:00
# ifdef WITH_ROCKSDB
2025-03-09 21:20:16 +01:00
size_t v ;
2025-02-24 20:46:29 +01:00
std : : string s ( sizeof ( size_t ) , ' ' ) ;
2025-02-27 22:07:31 +01:00
2025-03-09 21:20:16 +01:00
if ( new_entity - > declaration ( ) . as_entity ( ) ) {
v = new_entity - > id ( ) ;
memcpy ( s . data ( ) , & v , sizeof ( size_t ) ) ;
// no merges yet, because the python client doesn't support them
2025-03-14 16:16:25 +01:00
db - > Merge ( rocksdb : : WriteOptions { } , " t| " + std : : to_string ( new_entity - > declaration ( ) . index_in_schema ( ) ) , s ) ;
/*{
2025-03-09 21:20:16 +01:00
std::string current;
// @todo this uses the same key-namespace as typedecl instances, not a direct conflict, but also not very clear
auto key = "t|" + std::to_string(new_entity->declaration().index_in_schema());
db->Get(rocksdb::ReadOptions{}, key, ¤t);
auto new_val = current + s;
2025-03-14 16:16:25 +01:00
db->Put(wopts, key, new_val);
}*/
2025-02-27 22:07:31 +01:00
}
// not only mapping also register type
v = new_entity - > declaration ( ) . index_in_schema ( ) ;
memcpy ( s . data ( ) , & v , sizeof ( size_t ) ) ;
2025-03-14 16:16:25 +01:00
db - > Put ( wopts , ( new_entity - > declaration ( ) . as_entity ( ) ? " i| " : " t| " ) + std : : to_string ( new_entity - > id ( ) ? new_entity - > id ( ) : new_entity - > identity ( ) ) + " |_ " , s ) ;
2025-08-26 13:56:03 +02:00
# endif
2025-02-24 20:46:29 +01:00
}
void IfcParse : : impl : : rocks_db_file_storage : : remove_type_ref ( IfcUtil : : IfcBaseClass * new_entity )
{
2025-08-26 13:56:03 +02:00
# ifdef WITH_ROCKSDB
2025-03-09 21:20:16 +01:00
if ( new_entity - > declaration ( ) . as_entity ( ) ) {
std : : string s ;
auto key = " t| " + std : : to_string ( new_entity - > declaration ( ) . index_in_schema ( ) ) ;
if ( db - > Get ( rocksdb : : ReadOptions { } , key , & s ) . ok ( ) ) {
std : : vector < size_t > vals ( s . size ( ) / sizeof ( size_t ) ) ;
memcpy ( vals . data ( ) , s . data ( ) , s . size ( ) ) ;
vals . erase ( std : : find ( vals . begin ( ) , vals . end ( ) , ( size_t ) new_entity - > id ( ) ) ) ;
s . resize ( vals . size ( ) * sizeof ( size_t ) ) ;
memcpy ( s . data ( ) , vals . data ( ) , s . size ( ) ) ;
2025-03-14 16:16:25 +01:00
db - > Put ( wopts , key , s ) ;
2025-03-09 21:20:16 +01:00
}
2025-02-24 20:46:29 +01:00
}
2025-02-27 22:07:31 +01:00
2025-03-14 16:16:25 +01:00
db - > Delete ( wopts , ( new_entity - > declaration ( ) . as_entity ( ) ? " i| " : " t| " ) + std : : to_string ( new_entity - > id ( ) ? new_entity - > id ( ) : new_entity - > identity ( ) ) + " |_ " ) ;
2025-08-26 13:56:03 +02:00
# endif
2025-02-24 20:46:29 +01:00
}
2024-08-23 20:29:07 +02:00
namespace {
class StringBuilderVisitor : public boost : : static_visitor < void > {
private :
StringBuilderVisitor ( const StringBuilderVisitor & ) ; //N/A
StringBuilderVisitor & operator = ( const StringBuilderVisitor & ) ; //N/A
std : : ostream & data_ ;
template < typename T >
void serialize ( const std : : vector < T > & i ) {
data_ < < " ( " ;
for ( typename std : : vector < T > : : const_iterator it = i . begin ( ) ; it ! = i . end ( ) ; + + it ) {
if ( it ! = i . begin ( ) ) {
data_ < < " , " ;
}
data_ < < * it ;
}
data_ < < " ) " ;
}
// The REAL token definition from the IFC SPF standard does not necessarily match
// the output of the C++ ostream formatting operation.
// REAL = [ SIGN ] DIGIT { DIGIT } "." { DIGIT } [ "E" [ SIGN ] DIGIT { DIGIT } ] .
static std : : string format_double ( const double & d ) {
std : : ostringstream oss ;
oss . imbue ( std : : locale : : classic ( ) ) ;
oss < < std : : setprecision ( std : : numeric_limits < double > : : digits10 ) < < d ;
const std : : string str = oss . str ( ) ;
oss . str ( " " ) ;
std : : string : : size_type e = str . find ( ' e ' ) ;
if ( e = = std : : string : : npos ) {
e = str . find ( ' E ' ) ;
}
const std : : string mantissa = str . substr ( 0 , e ) ;
oss < < mantissa ;
if ( mantissa . find ( ' . ' ) = = std : : string : : npos ) {
oss < < " . " ;
}
if ( e ! = std : : string : : npos ) {
oss < < " E " ;
oss < < str . substr ( e + 1 ) ;
}
return oss . str ( ) ;
}
static std : : string format_binary ( const boost : : dynamic_bitset < > & b ) {
std : : ostringstream oss ;
oss . imbue ( std : : locale : : classic ( ) ) ;
oss . put ( ' " ' ) ;
oss < < std : : uppercase < < std : : hex < < std : : setw ( 1 ) ;
unsigned c = ( unsigned ) b . size ( ) ;
unsigned n = ( 4 - ( c % 4 ) ) & 3 ;
oss < < n ;
for ( unsigned i = 0 ; i < c + n ; ) {
unsigned accum = 0 ;
for ( int j = 0 ; j < 4 ; + + j , + + i ) {
unsigned bit = i < n ? 0 : b . test ( c - i + n - 1 ) ? 1
: 0 ;
accum | = bit < < ( 3 - j ) ;
}
oss < < accum ;
}
oss . put ( ' " ' ) ;
return oss . str ( ) ;
}
bool upper_ ;
public :
StringBuilderVisitor ( std : : ostream & stream , bool upper = false )
: data_ ( stream ) ,
upper_ ( upper ) { }
void operator ( ) ( const Blank & /*i*/ ) { data_ < < " $ " ; }
void operator ( ) ( const Derived & /*i*/ ) { data_ < < " * " ; }
void operator ( ) ( const int & i ) { data_ < < i ; }
void operator ( ) ( const bool & i ) { data_ < < ( i ? " .T. " : " .F. " ) ; }
void operator ( ) ( const boost : : logic : : tribool & i ) { data_ < < ( i ? " .T. " : ( boost : : logic : : indeterminate ( i ) ? " .U. " : " .F. " ) ) ; }
void operator ( ) ( const double & i ) { data_ < < format_double ( i ) ; }
void operator ( ) ( const boost : : dynamic_bitset < > & i ) { data_ < < format_binary ( i ) ; }
void operator ( ) ( const std : : string & i ) {
std : : string s = i ;
if ( upper_ ) {
data_ < < static_cast < std : : string > ( IfcCharacterEncoder ( s ) ) ;
} else {
data_ < < ' \' ' < < s < < ' \' ' ;
}
}
void operator ( ) ( const std : : vector < int > & i ) ;
void operator ( ) ( const std : : vector < double > & i ) ;
void operator ( ) ( const std : : vector < std : : string > & i ) ;
void operator ( ) ( const std : : vector < boost : : dynamic_bitset < > > & i ) ;
void operator ( ) ( const EnumerationReference & i ) {
data_ < < " . " < < i . value ( ) < < " . " ;
}
void operator ( ) ( const IfcUtil : : IfcBaseClass * const & i ) {
if ( i - > declaration ( ) . as_entity ( ) = = nullptr ) {
i - > toString ( data_ , upper_ ) ;
} else {
data_ < < " # " < < i - > id ( ) ;
}
}
void operator ( ) ( const aggregate_of_instance : : ptr & i ) {
data_ < < " ( " ;
for ( aggregate_of_instance : : it it = i - > begin ( ) ; it ! = i - > end ( ) ; + + it ) {
if ( it ! = i - > begin ( ) ) {
data_ < < " , " ;
}
( * this ) ( * it ) ;
}
data_ < < " ) " ;
}
void operator ( ) ( const std : : vector < std : : vector < int > > & i ) ;
void operator ( ) ( const std : : vector < std : : vector < double > > & i ) ;
void operator ( ) ( const aggregate_of_aggregate_of_instance : : ptr & i ) {
data_ < < " ( " ;
for ( aggregate_of_aggregate_of_instance : : outer_it outer_it = i - > begin ( ) ; outer_it ! = i - > end ( ) ; + + outer_it ) {
if ( outer_it ! = i - > begin ( ) ) {
data_ < < " , " ;
}
data_ < < " ( " ;
for ( aggregate_of_aggregate_of_instance : : inner_it inner_it = outer_it - > begin ( ) ; inner_it ! = outer_it - > end ( ) ; + + inner_it ) {
if ( inner_it ! = outer_it - > begin ( ) ) {
data_ < < " , " ;
}
( * this ) ( * inner_it ) ;
}
data_ < < " ) " ;
}
data_ < < " ) " ;
}
void operator ( ) ( const empty_aggregate_t & /*unused*/ ) const { data_ < < " () " ; }
void operator ( ) ( const empty_aggregate_of_aggregate_t & /*unused*/ ) const { data_ < < " () " ; }
} ;
template < >
void StringBuilderVisitor : : serialize ( const std : : vector < std : : string > & i ) {
data_ < < " ( " ;
for ( std : : vector < std : : string > : : const_iterator it = i . begin ( ) ; it ! = i . end ( ) ; + + it ) {
if ( it ! = i . begin ( ) ) {
data_ < < " , " ;
}
std : : string encoder = IfcCharacterEncoder ( * it ) ;
data_ < < encoder ;
}
data_ < < " ) " ;
2023-09-17 12:30:17 +02:00
}
2015-01-25 10:50:12 +00:00
2024-08-23 20:29:07 +02:00
template < >
void StringBuilderVisitor : : serialize ( const std : : vector < double > & i ) {
data_ < < " ( " ;
for ( std : : vector < double > : : const_iterator it = i . begin ( ) ; it ! = i . end ( ) ; + + it ) {
if ( it ! = i . begin ( ) ) {
data_ < < " , " ;
}
data_ < < format_double ( * it ) ;
}
data_ < < " ) " ;
}
2015-01-25 10:50:12 +00:00
2024-08-23 20:29:07 +02:00
template < >
void StringBuilderVisitor : : serialize ( const std : : vector < boost : : dynamic_bitset < > > & i ) {
data_ < < " ( " ;
for ( std : : vector < boost : : dynamic_bitset < > > : : const_iterator it = i . begin ( ) ; it ! = i . end ( ) ; + + it ) {
if ( it ! = i . begin ( ) ) {
data_ < < " , " ;
}
data_ < < format_binary ( * it ) ;
2023-09-17 12:30:17 +02:00
}
2024-08-23 20:29:07 +02:00
data_ < < " ) " ;
}
2023-09-17 12:30:17 +02:00
2024-08-23 20:29:07 +02:00
void StringBuilderVisitor : : operator ( ) ( const std : : vector < int > & i ) { serialize ( i ) ; }
void StringBuilderVisitor : : operator ( ) ( const std : : vector < double > & i ) { serialize ( i ) ; }
void StringBuilderVisitor : : operator ( ) ( const std : : vector < std : : string > & i ) { serialize ( i ) ; }
void StringBuilderVisitor : : operator ( ) ( const std : : vector < boost : : dynamic_bitset < > > & i ) { serialize ( i ) ; }
void StringBuilderVisitor : : operator ( ) ( const std : : vector < std : : vector < int > > & i ) {
data_ < < " ( " ;
for ( std : : vector < std : : vector < int > > : : const_iterator it = i . begin ( ) ; it ! = i . end ( ) ; + + it ) {
if ( it ! = i . begin ( ) ) {
data_ < < " , " ;
}
serialize ( * it ) ;
}
data_ < < " ) " ;
}
void StringBuilderVisitor : : operator ( ) ( const std : : vector < std : : vector < double > > & i ) {
data_ < < " ( " ;
for ( std : : vector < std : : vector < double > > : : const_iterator it = i . begin ( ) ; it ! = i . end ( ) ; + + it ) {
if ( it ! = i . begin ( ) ) {
data_ < < " , " ;
}
serialize ( * it ) ;
2023-09-17 12:30:17 +02:00
}
2024-08-23 20:29:07 +02:00
data_ < < " ) " ;
2023-09-17 12:30:17 +02:00
}
2024-08-23 20:29:07 +02:00
}
2023-09-17 12:30:17 +02:00
2024-08-23 20:29:07 +02:00
//
// Returns a string representation of the entity
// Note that this initializes the entity if it is not initialized
//
2025-02-27 22:07:31 +01:00
void IfcEntityInstanceData : : toString ( void * storage , const IfcParse : : declaration * decl , std : : size_t identity , std : : ostream & ss , bool upper ) const {
2024-08-23 20:29:07 +02:00
ss . imbue ( std : : locale : : classic ( ) ) ;
2023-09-17 12:30:17 +02:00
2024-08-23 20:29:07 +02:00
ss < < " ( " ;
StringBuilderVisitor vis ( ss , upper ) ;
2025-02-27 22:07:31 +01:00
// @todo perhaps IfcEntityInstanceData::size() can be removed now?
for ( size_t i = 0 ; i < ( decl & & decl - > as_entity ( ) ? decl - > as_entity ( ) - > attribute_count ( ) : 1 ) ; + + i ) {
2023-09-17 12:30:17 +02:00
if ( i ! = 0 ) {
ss < < " , " ;
}
2025-02-27 22:07:31 +01:00
if ( has_attribute_value < Blank > ( storage , decl , identity , i ) ) {
if ( decl ! = nullptr & & decl - > as_entity ( ) & & decl - > as_entity ( ) - > derived ( ) [ i ] ) {
2024-07-10 12:43:01 -07:00
ss < < " * " ;
2024-07-17 09:45:34 +02:00
} else {
2024-07-10 12:43:01 -07:00
ss < < " $ " ;
2024-08-23 20:29:07 +02:00
}
2023-09-17 12:30:17 +02:00
} else {
2025-02-27 22:07:31 +01:00
apply_visitor ( storage , decl , identity , vis , i ) ;
2023-09-17 12:30:17 +02:00
}
}
ss < < " ) " ;
2011-05-08 11:04:32 +00:00
}
2011-07-11 09:33:18 +00:00
2024-08-23 20:29:07 +02:00
unsigned IfcUtil : : IfcBaseEntity : : set_id ( const boost : : optional < unsigned > & i ) {
2023-09-17 12:30:17 +02:00
if ( i ) {
return id_ = * i ;
}
2024-08-23 20:29:07 +02:00
return id_ = file_ - > FreshId ( ) ;
2017-06-05 17:26:58 +02:00
}
2021-11-19 09:38:28 +01:00
namespace {
2023-09-17 12:30:17 +02:00
// @todo remove redundancy with python wrapper code (which is not identical due to
// different handling of enumerations)
IfcUtil : : ArgumentType get_argument_type ( const IfcParse : : declaration * decl , size_t i ) {
const IfcParse : : parameter_type * pt = 0 ;
2023-10-24 14:16:26 +02:00
if ( decl - > as_entity ( ) ! = nullptr ) {
2023-09-17 12:30:17 +02:00
pt = decl - > as_entity ( ) - > attribute_by_index ( i ) - > type_of_attribute ( ) ;
if ( decl - > as_entity ( ) - > derived ( ) [ i ] ) {
return IfcUtil : : Argument_DERIVED ;
}
2023-10-24 14:16:26 +02:00
} else if ( ( decl - > as_type_declaration ( ) ! = nullptr ) & & i = = 0 ) {
2023-09-17 12:30:17 +02:00
pt = decl - > as_type_declaration ( ) - > declared_type ( ) ;
2023-10-24 14:16:26 +02:00
} else if ( ( decl - > as_enumeration_type ( ) ! = nullptr ) & & i = = 0 ) {
2023-09-17 12:30:17 +02:00
return IfcUtil : : Argument_ENUMERATION ;
}
if ( pt = = 0 ) {
return IfcUtil : : Argument_UNKNOWN ;
}
2023-10-24 12:21:32 +02:00
return IfcUtil : : from_parameter_type ( pt ) ;
2021-11-19 09:38:28 +01:00
}
2023-09-17 12:30:17 +02:00
} // namespace
2021-11-19 09:38:28 +01:00
2017-07-03 14:18:56 +02:00
class unregister_inverse_visitor {
2023-09-17 12:30:17 +02:00
private :
IfcFile & file_ ;
2024-08-23 20:29:07 +02:00
const IfcUtil : : IfcBaseClass * data_ ;
2017-07-03 14:18:56 +02:00
2023-09-17 12:30:17 +02:00
public :
2024-08-23 20:29:07 +02:00
unregister_inverse_visitor ( IfcFile & file , const IfcUtil : : IfcBaseClass * data )
2023-09-17 12:30:17 +02:00
: file_ ( file ) ,
data_ ( data ) { }
2017-07-03 14:18:56 +02:00
2023-09-17 12:30:17 +02:00
void operator ( ) ( IfcUtil : : IfcBaseClass * inst , int index ) {
2024-08-23 20:29:07 +02:00
file_ . unregister_inverse ( data_ - > id ( ) , data_ - > declaration ( ) . as_entity ( ) , inst , index ) ;
2023-09-17 12:30:17 +02:00
}
2017-07-03 14:18:56 +02:00
} ;
class register_inverse_visitor {
2023-09-17 12:30:17 +02:00
private :
IfcFile & file_ ;
2024-08-23 20:29:07 +02:00
const IfcUtil : : IfcBaseClass * data_ ;
2017-07-03 14:18:56 +02:00
2023-09-17 12:30:17 +02:00
public :
2024-08-23 20:29:07 +02:00
register_inverse_visitor ( IfcFile & file , const IfcUtil : : IfcBaseClass * data )
2023-09-17 12:30:17 +02:00
: file_ ( file ) ,
data_ ( data ) { }
2017-07-03 14:18:56 +02:00
2023-09-17 12:30:17 +02:00
void operator ( ) ( IfcUtil : : IfcBaseClass * inst , int index ) {
2025-02-21 16:12:16 +01:00
file_ . register_inverse ( data_ - > id ( ) , data_ - > declaration ( ) . as_entity ( ) , inst - > id ( ) , index ) ;
2023-09-17 12:30:17 +02:00
}
2017-07-03 14:18:56 +02:00
} ;
class add_to_instance_list_visitor {
2023-09-17 12:30:17 +02:00
private :
aggregate_of_instance : : ptr & list_ ;
2017-07-03 14:18:56 +02:00
2023-09-17 12:30:17 +02:00
public :
add_to_instance_list_visitor ( aggregate_of_instance : : ptr & list )
: list_ ( list ) { }
2017-07-03 14:18:56 +02:00
2023-09-17 12:30:17 +02:00
void operator ( ) ( IfcUtil : : IfcBaseClass * inst ) {
list_ - > push ( inst ) ;
}
2017-07-03 14:18:56 +02:00
} ;
class apply_individual_instance_visitor {
2023-09-17 12:30:17 +02:00
private :
2024-08-23 20:29:07 +02:00
boost : : optional < AttributeValue > attribute_ ;
2023-09-17 12:30:17 +02:00
int attribute_index_ ;
2025-02-27 22:07:31 +01:00
const IfcUtil : : IfcBaseClass * inst_ ;
2023-09-17 12:30:17 +02:00
template < typename T >
2024-08-23 20:29:07 +02:00
void apply_attribute_ ( T & t , const AttributeValue & attr , int index ) const {
2025-03-14 16:16:25 +01:00
switch ( attr . type ( ) ) {
case IfcUtil : : Argument_ENTITY_INSTANCE : {
2024-08-23 20:29:07 +02:00
IfcUtil : : IfcBaseClass * inst = attr ;
2023-09-17 12:30:17 +02:00
t ( inst , index ) ;
2025-03-14 16:16:25 +01:00
break ;
}
case IfcUtil : : Argument_AGGREGATE_OF_ENTITY_INSTANCE : {
2024-08-23 20:29:07 +02:00
aggregate_of_instance : : ptr entity_list_attribute = attr ;
2023-09-17 12:30:17 +02:00
for ( aggregate_of_instance : : it it = entity_list_attribute - > begin ( ) ; it ! = entity_list_attribute - > end ( ) ; + + it ) {
t ( * it , index ) ;
}
2025-03-14 16:16:25 +01:00
break ;
}
case IfcUtil : : Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE : {
2024-08-23 20:29:07 +02:00
aggregate_of_aggregate_of_instance : : ptr entity_list_attribute = attr ;
2023-09-17 12:30:17 +02:00
for ( aggregate_of_aggregate_of_instance : : outer_it it = entity_list_attribute - > begin ( ) ; it ! = entity_list_attribute - > end ( ) ; + + it ) {
for ( aggregate_of_aggregate_of_instance : : inner_it jt = it - > begin ( ) ; jt ! = it - > end ( ) ; + + jt ) {
t ( * jt , index ) ;
}
}
2025-03-14 16:16:25 +01:00
break ;
2023-09-17 12:30:17 +02:00
}
2025-03-14 16:16:25 +01:00
default :
break ;
}
}
2023-09-17 12:30:17 +02:00
public :
2024-08-23 20:29:07 +02:00
apply_individual_instance_visitor ( const AttributeValue & attribute , int idx )
: attribute_ ( attribute )
, attribute_index_ ( idx )
{ }
2023-09-17 12:30:17 +02:00
2025-02-27 22:07:31 +01:00
apply_individual_instance_visitor ( const IfcUtil : : IfcBaseClass * data )
: inst_ ( data )
2024-08-23 20:29:07 +02:00
{ }
2023-09-17 12:30:17 +02:00
template < typename T >
void apply ( T & t ) const {
if ( attribute_ ) {
2024-08-23 20:29:07 +02:00
apply_attribute_ ( t , * attribute_ , attribute_index_ ) ;
2023-09-17 12:30:17 +02:00
} else {
2025-02-27 22:07:31 +01:00
const auto & decl = inst_ - > declaration ( ) ;
for ( size_t i = 0 ; i < ( decl . as_entity ( ) ? decl . as_entity ( ) - > attribute_count ( ) : 1 ) ; + + i ) {
auto attr = inst_ - > get_attribute_value ( i ) ;
2024-08-23 20:29:07 +02:00
apply_attribute_ ( t , attr , ( int ) i ) ;
2023-09-17 12:30:17 +02:00
}
}
} ;
2017-07-03 14:18:56 +02:00
} ;
2024-08-23 20:29:07 +02:00
template < typename T >
2025-08-26 10:19:47 +02:00
typename std : : enable_if <
( ! ( std : : is_pointer < T > : : value & & std : : is_base_of < IfcUtil : : IfcBaseClass , typename std : : remove_pointer < T > : : type > : : value ) | | std : : is_same_v < IfcUtil : : IfcBaseClass , std : : remove_pointer_t < T > > ) ,
void > : : type
IfcUtil : : IfcBaseClass : : set_attribute_value ( size_t i , const T & t ) {
2025-03-25 10:15:24 +01:00
if constexpr ( std : : is_same_v < std : : decay_t < T > , double > ) {
if ( ! std : : isfinite ( t ) ) {
throw IfcParse : : IfcException ( " Only finite values are allowed " ) ;
}
}
if constexpr ( std : : is_same_v < std : : decay_t < T > , std : : vector < double > > ) {
if ( std : : any_of ( t . begin ( ) , t . end ( ) , [ ] ( double d ) { return ! std : : isfinite ( d ) ; } ) ) {
throw IfcParse : : IfcException ( " Only finite values are allowed " ) ;
}
}
if constexpr ( std : : is_same_v < std : : decay_t < T > , std : : vector < std : : vector < double > > > ) {
for ( auto & tt : t ) {
if ( std : : any_of ( tt . begin ( ) , tt . end ( ) , [ ] ( double d ) { return ! std : : isfinite ( d ) ; } ) ) {
throw IfcParse : : IfcException ( " Only finite values are allowed " ) ;
}
}
}
2025-02-27 22:07:31 +01:00
auto current_attribute = get_attribute_value ( i ) ;
2024-08-23 20:29:07 +02:00
if ( file_ ! = nullptr ) {
2023-09-17 12:30:17 +02:00
2024-08-23 20:29:07 +02:00
// Deregister old attribute guid in file guid map.
if ( i = = 0 & & ( file_ - > ifcroot_type ( ) ! = nullptr ) & & this - > declaration ( ) . is ( * file_ - > ifcroot_type ( ) ) ) {
try {
auto guid = ( std : : string ) current_attribute ;
auto it = file_ - > internal_guid_map ( ) . find ( guid ) ;
2025-02-27 22:07:31 +01:00
if ( it ! = file_ - > internal_guid_map ( ) . end ( ) ) {
const std : : pair < const std : : string , IfcUtil : : IfcBaseClass * > & p = * it ;
if ( p . second = = this ) {
file_ - > internal_guid_map ( ) . erase ( it ) ;
}
2023-09-17 12:30:17 +02:00
}
2024-08-23 20:29:07 +02:00
} catch ( IfcParse : : IfcException & e ) {
Logger : : Error ( e ) ;
2023-09-17 12:30:17 +02:00
}
}
2017-07-03 14:18:56 +02:00
2025-03-14 16:16:25 +01:00
if constexpr ( std : : is_same_v < T , IfcUtil : : IfcBaseClass * > | | std : : is_same_v < T , aggregate_of_instance : : ptr > | | std : : is_same_v < T , aggregate_of_aggregate_of_instance : : ptr > | | std : : is_same_v < T , Blank > ) {
// Deregister inverse indices in file
unregister_inverse_visitor visitor ( * file_ , this ) ;
apply_individual_instance_visitor ( current_attribute , ( int ) i ) . apply ( visitor ) ;
}
2023-09-17 12:30:17 +02:00
}
2025-02-27 22:07:31 +01:00
{
void * const storage = file_ ? std : : visit ( [ ] ( const auto & m ) { return ( void * ) & m ; } , file_ - > storage_ ) : nullptr ;
if constexpr ( std : : is_pointer_v < T > ) {
if ( t ) {
2025-03-09 21:20:16 +01:00
data_ . set_attribute_value ( storage , & declaration ( ) , id ( ) ? id ( ) : identity ( ) , i , t ) ;
2025-02-27 22:07:31 +01:00
} else {
2025-03-09 21:20:16 +01:00
data_ . set_attribute_value ( storage , & declaration ( ) , id ( ) ? id ( ) : identity ( ) , i , Blank { } ) ;
2025-02-27 22:07:31 +01:00
}
2024-09-05 14:38:21 +02:00
} else {
2025-03-09 21:20:16 +01:00
data_ . set_attribute_value ( storage , & declaration ( ) , id ( ) ? id ( ) : identity ( ) , i , t ) ;
2024-09-05 14:38:21 +02:00
}
}
2025-02-27 22:07:31 +01:00
auto new_attribute = get_attribute_value ( i ) ;
2023-09-17 12:30:17 +02:00
2024-08-23 20:29:07 +02:00
if ( file_ ! = nullptr ) {
2023-09-17 12:30:17 +02:00
// Register inverse indices in file
2025-03-14 16:16:25 +01:00
if constexpr ( std : : is_same_v < T , IfcUtil : : IfcBaseClass * > | | std : : is_same_v < T , aggregate_of_instance : : ptr > | | std : : is_same_v < T , aggregate_of_aggregate_of_instance : : ptr > ) {
register_inverse_visitor visitor ( * file_ , this ) ;
apply_individual_instance_visitor ( new_attribute , ( int ) i ) . apply ( visitor ) ;
}
2024-08-23 20:29:07 +02:00
// Register new attribute guid in guid map
if ( i = = 0 & & ( file_ - > ifcroot_type ( ) ! = nullptr ) & & this - > declaration ( ) . is ( * file_ - > ifcroot_type ( ) ) ) {
2023-09-17 12:30:17 +02:00
try {
2024-08-23 20:29:07 +02:00
auto guid = ( std : : string ) new_attribute ;
auto it = file_ - > internal_guid_map ( ) . find ( guid ) ;
if ( it ! = file_ - > internal_guid_map ( ) . end ( ) ) {
2023-09-17 12:30:17 +02:00
Logger : : Warning ( " Duplicate guid " + guid ) ;
}
2025-02-27 22:07:31 +01:00
file_ - > internal_guid_map ( ) . insert ( { guid , this } ) ;
2023-09-17 12:30:17 +02:00
} catch ( IfcParse : : IfcException & e ) {
Logger : : Error ( e ) ;
}
}
}
2017-06-05 17:26:58 +02:00
}
2024-08-23 20:29:07 +02:00
template < typename T >
2025-08-26 10:19:47 +02:00
typename std : : enable_if <
( ! ( std : : is_pointer < T > : : value & & std : : is_base_of < IfcUtil : : IfcBaseClass , typename std : : remove_pointer < T > : : type > : : value ) | | std : : is_same_v < IfcUtil : : IfcBaseClass , std : : remove_pointer_t < T > > ) ,
void > : : type
IfcUtil : : IfcBaseClass : : set_attribute_value ( const std : : string & s , const T & t ) {
2024-08-23 20:29:07 +02:00
set_attribute_value ( declaration ( ) . as_entity ( ) - > attribute_index ( s ) , t ) ;
}
2011-07-11 09:33:18 +00:00
//
// Parses the IFC file in fn
// Creates the maps
//
2017-07-23 14:52:04 +02:00
# ifdef USE_MMAP
2017-12-12 10:33:24 +01:00
IfcFile : : IfcFile ( const std : : string & fn , bool mmap ) {
2025-02-21 16:12:16 +01:00
IfcSpfStream s ( fn , mmap ) ;
storage_ = impl : : in_memory_file_storage { } ;
std : : get < impl : : in_memory_file_storage > ( storage_ ) . read_from_stream ( & s ) ;
2017-07-23 14:52:04 +02:00
}
# else
2025-02-21 16:12:16 +01:00
IfcFile : : IfcFile ( const std : : string & path , filetype ty ) {
// @todo allow for rocksdb from path
2025-03-13 13:09:39 +01:00
if ( ty = = FT_AUTODETECT ) {
ty = guess_file_type ( path ) ;
}
if ( ty = = FT_IFCSPF ) {
2025-02-21 16:12:16 +01:00
IfcSpfStream s ( path ) ;
2025-02-24 20:46:29 +01:00
storage_ . emplace < 1 > ( ) ; // impl::in_memory_file_storage{};
// @todo assign in constructor
std : : get < impl : : in_memory_file_storage > ( storage_ ) . file = this ;
2025-02-21 16:12:16 +01:00
std : : get < impl : : in_memory_file_storage > ( storage_ ) . read_from_stream ( & s , schema_ , max_id_ ) ;
2025-02-27 22:07:31 +01:00
// @todo unify these names, it's already confusing enough as it stands
byid_ = decltype ( byid_ ) ( & std : : get < impl : : in_memory_file_storage > ( storage_ ) . byid_ ) ;
2025-03-09 21:20:16 +01:00
byref_excl_ = decltype ( byref_excl_ ) ( & std : : get < impl : : in_memory_file_storage > ( storage_ ) . byref_excl_ ) ;
// byidentity_ = decltype(byidentity_)(&std::get<impl::in_memory_file_storage>(storage_).byidentity_);
2025-03-13 13:09:39 +01:00
} else if ( ty = = FT_ROCKSDB ) {
2025-02-25 21:29:54 +01:00
// @todo this can only be used for databases that already exist, because otherwise there is no way to specify the schema
2025-02-27 22:07:31 +01:00
storage_ . emplace < 2 > ( path , this ) ;
2025-02-21 16:12:16 +01:00
std : : get < impl : : rocks_db_file_storage > ( storage_ ) . read_schema ( schema_ ) ;
2025-02-27 22:07:31 +01:00
2025-03-09 21:20:16 +01:00
byid_ = decltype ( byid_ ) ( & std : : get < impl : : rocks_db_file_storage > ( storage_ ) . instance_by_name_ ) ;
byref_excl_ = decltype ( byref_excl_ ) ( & std : : get < impl : : rocks_db_file_storage > ( storage_ ) . byref_excl_ ) ;
// byidentity_ = decltype(byidentity_)(&std::get<impl::rocks_db_file_storage>(storage_).instance_cache_);
2025-03-13 13:09:39 +01:00
} else {
throw std : : runtime_error ( " Unsupported file format " ) ;
2025-02-21 16:12:16 +01:00
}
2025-08-25 12:45:10 +02:00
if ( schema_ ) {
ifcroot_type_ = schema_ - > declaration_by_name ( " IfcRoot " ) ;
}
2011-08-20 09:08:56 +00:00
}
2017-07-23 14:52:04 +02:00
# endif
2017-08-22 10:16:07 +02:00
2023-11-06 20:29:00 +01:00
IfcFile : : IfcFile ( std : : istream & stream , int length ) {
2024-08-23 20:29:07 +02:00
IfcSpfStream s ( stream , length ) ;
2025-02-24 20:46:29 +01:00
storage_ . emplace < 1 > ( ) ;
2025-02-21 16:12:16 +01:00
std : : get < impl : : in_memory_file_storage > ( storage_ ) . read_from_stream ( & s , schema_ , max_id_ ) ;
ifcroot_type_ = schema_ - > declaration_by_name ( " IfcRoot " ) ;
2011-08-20 09:08:56 +00:00
}
2015-02-17 19:48:41 +00:00
2023-11-06 20:29:00 +01:00
IfcFile : : IfcFile ( void * data , int length ) {
2024-08-23 20:29:07 +02:00
IfcSpfStream s ( data , length ) ;
2025-02-24 20:46:29 +01:00
storage_ . emplace < 1 > ( ) ;
2025-02-21 16:12:16 +01:00
std : : get < impl : : in_memory_file_storage > ( storage_ ) . read_from_stream ( & s , schema_ , max_id_ ) ;
ifcroot_type_ = schema_ - > declaration_by_name ( " IfcRoot " ) ;
2017-12-12 10:33:24 +01:00
}
IfcFile : : IfcFile ( IfcParse : : IfcSpfStream * s ) {
2025-02-24 20:46:29 +01:00
storage_ . emplace < 1 > ( ) ;
2025-02-21 16:12:16 +01:00
std : : get < impl : : in_memory_file_storage > ( storage_ ) . read_from_stream ( s , schema_ , max_id_ ) ;
ifcroot_type_ = schema_ - > declaration_by_name ( " IfcRoot " ) ;
2017-12-12 10:33:24 +01:00
}
2025-02-25 21:29:54 +01:00
IfcFile : : IfcFile ( const IfcParse : : schema_definition * schema , filetype ty , const std : : string & path )
2025-02-21 16:12:16 +01:00
: schema_ ( schema )
, ifcroot_type_ ( schema_ - > declaration_by_name ( " IfcRoot " ) )
, max_id_ ( 0 )
2025-03-13 13:09:39 +01:00
, _header ( ty = = FT_ROCKSDB ? this : nullptr )
2025-02-21 16:12:16 +01:00
{
2025-03-13 13:09:39 +01:00
if ( ty = = FT_AUTODETECT ) {
ty = guess_file_type ( path ) ;
}
if ( ty = = FT_IFCSPF ) {
2025-02-25 21:29:54 +01:00
storage_ . emplace < 1 > ( ) ;
2025-02-27 22:07:31 +01:00
std : : get < impl : : in_memory_file_storage > ( storage_ ) . file = this ;
byid_ = decltype ( byid_ ) ( & std : : get < impl : : in_memory_file_storage > ( storage_ ) . byid_ ) ;
2025-03-09 21:20:16 +01:00
byref_excl_ = decltype ( byref_excl_ ) ( & std : : get < impl : : in_memory_file_storage > ( storage_ ) . byref_excl_ ) ;
// byidentity_ = decltype(byidentity_)(&std::get<impl::in_memory_file_storage>(storage_).byidentity_);
2025-03-13 13:09:39 +01:00
} else if ( ty = = FT_ROCKSDB ) {
2025-02-25 21:29:54 +01:00
storage_ . emplace < 2 > ( path , this ) ;
2025-02-27 22:07:31 +01:00
2025-03-09 21:20:16 +01:00
byid_ = decltype ( byid_ ) ( & std : : get < impl : : rocks_db_file_storage > ( storage_ ) . instance_by_name_ ) ;
byref_excl_ = decltype ( byref_excl_ ) ( & std : : get < impl : : rocks_db_file_storage > ( storage_ ) . byref_excl_ ) ;
// byidentity_ = decltype(byidentity_)(&std::get<impl::rocks_db_file_storage>(storage_).instance_cache_);
2025-03-13 13:09:39 +01:00
} else {
throw std : : runtime_error ( " Unsupported file format " ) ;
2025-02-25 21:29:54 +01:00
}
2023-09-17 12:30:17 +02:00
setDefaultHeaderValues ( ) ;
2011-10-27 16:13:29 +00:00
}
2015-02-17 19:48:41 +00:00
2025-02-21 16:12:16 +01:00
void IfcParse : : impl : : in_memory_file_storage : : read_from_stream ( IfcParse : : IfcSpfStream * s , const IfcParse : : schema_definition * & schema , unsigned int & max_id ) {
2023-09-17 12:30:17 +02:00
// Initialize a "C" locale for locale-independent
// number parsing. See comment above on line 41.
init_locale ( ) ;
2025-08-25 12:45:10 +02:00
tokens = nullptr ;
if ( ! s - > valid ) {
2025-02-21 16:12:16 +01:00
// @todo set good on parent file
2023-09-17 12:30:17 +02:00
good_ = file_open_status : : READ_ERROR ;
return ;
}
2015-01-05 17:46:23 +00:00
2025-08-25 12:45:10 +02:00
tokens = new IfcSpfLexer ( s ) ;
2017-08-01 16:45:11 +02:00
2023-09-17 12:30:17 +02:00
std : : vector < std : : string > schemas ;
2017-12-12 10:33:24 +01:00
2025-02-21 16:12:16 +01:00
// @todo this line makes no sense
file - > header ( ) . file ( file ) ;
if ( file - > header ( ) . tryRead ( ) ) {
2023-09-17 12:30:17 +02:00
try {
2025-02-27 22:07:31 +01:00
schemas = file - > header ( ) . file_schema ( ) - > schema_identifiers ( ) ;
2023-09-17 12:30:17 +02:00
} catch ( . . . ) {
// Purposely empty catch block
}
} else {
good_ = file_open_status : : NO_HEADER ;
}
if ( schemas . size ( ) = = 1 ) {
try {
2025-02-21 16:12:16 +01:00
schema = IfcParse : : schema_by_name ( schemas . front ( ) ) ;
2023-09-17 12:30:17 +02:00
} catch ( const IfcParse : : IfcException & e ) {
good_ = file_open_status : : UNSUPPORTED_SCHEMA ;
Logger : : Error ( e ) ;
}
}
2025-02-21 16:12:16 +01:00
if ( schema = = 0 ) {
2023-09-17 12:30:17 +02:00
Logger : : Message ( Logger : : LOG_ERROR , " No support for file schema encountered ( " + boost : : algorithm : : join ( schemas , " , " ) + " ) " ) ;
return ;
}
2025-02-21 16:12:16 +01:00
auto ifcroot_type_ = schema - > declaration_by_name ( " IfcRoot " ) ;
2023-09-17 12:30:17 +02:00
2025-08-25 12:45:10 +02:00
InstanceStreamer streamer ( schema , tokens ) ;
2023-09-17 12:30:17 +02:00
Logger : : Status ( " Scanning file... " ) ;
2015-01-05 17:46:23 +00:00
2025-08-25 12:45:10 +02:00
while ( streamer ) {
2023-09-17 12:30:17 +02:00
2025-08-25 12:45:10 +02:00
auto inst = streamer . read_instance ( ) ;
2023-09-17 12:30:17 +02:00
2025-08-25 12:45:10 +02:00
if ( ! inst ) {
// No more instances to read
break ;
}
auto current_id = std : : get < 0 > ( * inst ) ;
2023-09-17 12:30:17 +02:00
2025-08-25 12:45:10 +02:00
auto instance = schema - > instantiate ( std : : get < 1 > ( * inst ) , std : : move ( std : : get < 2 > ( * inst ) ) ) ;
instance - > file_ = file ;
instance - > id_ = current_id ;
2023-09-17 12:30:17 +02:00
2025-08-25 12:45:10 +02:00
if ( instance - > declaration ( ) . is ( * ifcroot_type_ ) ) {
try {
// @nb here we know we're using in-memory so 'nullptr, nullptr, 0' is safe
const std : : string guid = instance - > data ( ) . get_attribute_value ( nullptr , nullptr , 0 , 0 ) ;
if ( byguid_ . find ( guid ) ! = byguid_ . end ( ) ) {
std : : stringstream ss ;
ss < < " Instance encountered with non-unique GlobalId " < < guid ;
Logger : : Message ( Logger : : LOG_WARNING , ss . str ( ) ) ;
2023-09-17 12:30:17 +02:00
}
2025-08-25 12:45:10 +02:00
byguid_ [ guid ] = instance ;
} catch ( const IfcException & ex ) {
Logger : : Message ( Logger : : LOG_ERROR , ex . what ( ) ) ;
2023-09-17 12:30:17 +02:00
}
2025-08-25 12:45:10 +02:00
}
2023-09-17 12:30:17 +02:00
2025-08-25 12:45:10 +02:00
const IfcParse : : declaration * ty = & instance - > declaration ( ) ;
2023-09-17 12:30:17 +02:00
2025-08-25 12:45:10 +02:00
{
if ( bytype_excl_ . find ( ty ) = = bytype_excl_ . end ( ) ) {
bytype_excl_ [ ty ] . reset ( new aggregate_of_instance ( ) ) ;
2023-09-17 12:30:17 +02:00
}
2025-08-25 12:45:10 +02:00
bytype_excl_ [ ty ] - > push ( instance ) ;
2023-09-17 12:30:17 +02:00
}
2025-08-25 12:45:10 +02:00
if ( byid_ . find ( current_id ) ! = byid_ . end ( ) ) {
std : : stringstream ss ;
ss < < " Overwriting instance with name # " < < current_id ;
Logger : : Message ( Logger : : LOG_WARNING , ss . str ( ) ) ;
2023-09-17 12:30:17 +02:00
}
2025-08-25 12:45:10 +02:00
// byidentity_[instance->identity()] = instance;
byid_ . insert ( { current_id , instance } ) ;
// @nb cannot assign to byid_;
// byid_[current_id] = instance;
2017-06-05 17:26:58 +02:00
2025-08-25 12:45:10 +02:00
max_id = ( std : : max ) ( max_id , ( unsigned int ) current_id ) ;
2023-09-17 12:30:17 +02:00
}
2017-06-05 17:26:58 +02:00
2025-08-25 12:45:10 +02:00
good_ = streamer . status ( ) ;
byref_excl_ = streamer . inverses ( ) ;
2023-09-17 12:30:17 +02:00
Logger : : Status ( " \r Done scanning file " ) ;
2017-06-05 17:26:58 +02:00
2024-08-23 20:29:07 +02:00
delete tokens ;
2025-01-23 16:20:06 +01:00
if ( good_ ! = file_open_status : : SUCCESS ) {
return ;
}
2025-08-25 12:45:10 +02:00
for ( const auto & p : streamer . references ( ) ) {
2024-09-23 15:10:37 +02:00
const auto & ref = p . first . name_ ;
const auto & refattr = p . first . index_ ;
2025-08-25 12:45:10 +02:00
if ( auto * v = std : : get_if < reference_or_simple_type > ( & p . second ) ) {
if ( auto * name = std : : get_if < InstanceReference > ( v ) ) {
2025-02-21 16:12:16 +01:00
auto it = byid_ . find ( * name ) ;
2024-09-23 15:10:37 +02:00
if ( it = = byid_ . end ( ) ) {
2025-03-25 11:44:46 +01:00
Logger : : Error ( " Instance reference # " + std : : to_string ( * name ) + " used by instance # " + std : : to_string ( ref ) + " at attribute index " + std : : to_string ( refattr ) + " not found at offset " + std : : to_string ( name - > file_offset ) ) ;
2024-09-23 15:10:37 +02:00
} else {
2025-08-26 10:17:57 +02:00
auto * storage = & byid_ [ p . first . name_ ] - > data ( ) ;
2025-04-11 15:52:40 +02:00
auto attr_index = p . first . index_ ;
2025-08-26 10:17:57 +02:00
if ( storage - > has_attribute_value < IfcUtil : : IfcBaseClass * > ( nullptr , nullptr , 0 , attr_index ) ) {
2025-08-26 10:20:08 +02:00
IfcUtil : : IfcBaseClass * inst = storage - > get_attribute_value ( nullptr , nullptr , 0 , attr_index ) ;
2025-04-11 15:52:40 +02:00
if ( ! inst - > declaration ( ) . as_entity ( ) ) {
2025-08-26 10:17:57 +02:00
// Probably a case of IfcPropertySetDefinitionSet, divert storage of reference to the simply type instance
storage = & inst - > data ( ) ;
2025-04-11 15:52:40 +02:00
attr_index = 0 ;
}
}
2025-08-26 10:17:57 +02:00
if ( storage - > has_attribute_value < Blank > ( nullptr , nullptr , 0 , attr_index ) ) {
2025-08-26 10:20:08 +02:00
storage - > set_attribute_value ( nullptr , nullptr , 0 , attr_index , it - > second ) ;
2025-04-11 15:52:40 +02:00
} else {
Logger : : Error ( " Duplicate definition for instance reference " ) ;
}
2024-08-23 20:29:07 +02:00
}
2025-08-25 12:45:10 +02:00
} else if ( auto * inst = std : : get_if < IfcUtil : : IfcBaseClass * > ( v ) ) {
2025-03-09 21:20:16 +01:00
byid_ [ p . first . name_ ] - > data ( ) . set_attribute_value ( nullptr , nullptr , 0 , p . first . index_ , * inst ) ;
2024-09-23 15:10:37 +02:00
}
2025-08-25 12:45:10 +02:00
} else if ( auto * v = std : : get_if < std : : vector < reference_or_simple_type > > ( & p . second ) ) {
2024-09-23 15:10:37 +02:00
aggregate_of_instance : : ptr instances ( new aggregate_of_instance ) ;
instances - > reserve ( v - > size ( ) ) ;
for ( const auto & vi : * v ) {
2025-08-25 12:45:10 +02:00
if ( auto * name = std : : get_if < InstanceReference > ( & vi ) ) {
2025-02-21 16:12:16 +01:00
auto it = byid_ . find ( * name ) ;
2024-09-23 15:10:37 +02:00
if ( it = = byid_ . end ( ) ) {
2025-03-25 11:44:46 +01:00
Logger : : Error ( " Instance reference # " + std : : to_string ( * name ) + " used by instance # " + std : : to_string ( ref ) + " at attribute index " + std : : to_string ( refattr ) + " not found at offset " + std : : to_string ( name - > file_offset ) ) ;
2024-09-23 15:10:37 +02:00
} else {
instances - > push ( it - > second ) ;
2024-08-23 20:29:07 +02:00
}
2025-08-25 12:45:10 +02:00
} else if ( auto * inst = std : : get_if < IfcUtil : : IfcBaseClass * > ( & vi ) ) {
2024-09-23 15:10:37 +02:00
instances - > push ( * inst ) ;
2024-08-23 20:29:07 +02:00
}
2024-09-23 15:10:37 +02:00
}
2025-04-11 15:52:40 +02:00
2025-08-26 10:17:57 +02:00
auto * storage = & byid_ [ p . first . name_ ] - > data ( ) ;
2025-04-11 15:52:40 +02:00
auto attr_index = p . first . index_ ;
2025-08-26 10:17:57 +02:00
if ( storage - > has_attribute_value < IfcUtil : : IfcBaseClass * > ( nullptr , nullptr , 0 , attr_index ) ) {
2025-08-26 10:20:08 +02:00
IfcUtil : : IfcBaseClass * inst = storage - > get_attribute_value ( nullptr , nullptr , 0 , attr_index ) ;
2025-04-11 15:52:40 +02:00
if ( ! inst - > declaration ( ) . as_entity ( ) ) {
2025-08-26 10:17:57 +02:00
// Probably a case of IfcPropertySetDefinitionSet, divert storage of reference to the simply type instance
storage = & inst - > data ( ) ;
2025-04-11 15:52:40 +02:00
attr_index = 0 ;
}
}
2025-08-26 10:17:57 +02:00
if ( storage - > has_attribute_value < Blank > ( nullptr , nullptr , 0 , attr_index ) ) {
2025-08-26 10:20:08 +02:00
storage - > set_attribute_value ( nullptr , nullptr , 0 , attr_index , instances ) ;
2025-04-11 15:52:40 +02:00
} else {
Logger : : Error ( " Duplicate definition for instance reference " ) ;
}
2025-08-25 12:45:10 +02:00
} else if ( auto * v = std : : get_if < std : : vector < std : : vector < reference_or_simple_type > > > ( & p . second ) ) {
2024-09-23 15:10:37 +02:00
aggregate_of_aggregate_of_instance : : ptr instances ( new aggregate_of_aggregate_of_instance ) ;
for ( const auto & vi : * v ) {
std : : vector < IfcUtil : : IfcBaseClass * > inner ;
for ( const auto & vii : vi ) {
2025-08-25 12:45:10 +02:00
if ( auto * name = std : : get_if < InstanceReference > ( & vii ) ) {
2025-02-21 16:12:16 +01:00
auto it = byid_ . find ( * name ) ;
2024-09-23 15:10:37 +02:00
if ( it = = byid_ . end ( ) ) {
2025-03-25 11:44:46 +01:00
Logger : : Error ( " Instance reference # " + std : : to_string ( * name ) + " used by instance # " + std : : to_string ( ref ) + " at attribute index " + std : : to_string ( refattr ) + " not found at offset " + std : : to_string ( name - > file_offset ) ) ;
2024-09-23 15:10:37 +02:00
} else {
inner . push_back ( it - > second ) ;
2024-08-23 20:29:07 +02:00
}
2025-08-25 12:45:10 +02:00
} else if ( auto * inst = std : : get_if < IfcUtil : : IfcBaseClass * > ( & vii ) ) {
2024-09-23 15:10:37 +02:00
inner . push_back ( * inst ) ;
2024-08-23 20:29:07 +02:00
}
}
2024-09-23 15:10:37 +02:00
instances - > push ( inner ) ;
2024-08-23 20:29:07 +02:00
}
2025-04-11 15:52:40 +02:00
2025-08-26 10:17:57 +02:00
auto * storage = & byid_ [ p . first . name_ ] - > data ( ) ;
2025-04-11 15:52:40 +02:00
auto attr_index = p . first . index_ ;
2025-08-26 10:17:57 +02:00
if ( storage - > has_attribute_value < IfcUtil : : IfcBaseClass * > ( nullptr , nullptr , 0 , attr_index ) ) {
2025-08-26 10:20:08 +02:00
IfcUtil : : IfcBaseClass * inst = storage - > get_attribute_value ( nullptr , nullptr , 0 , attr_index ) ;
2025-04-11 15:52:40 +02:00
if ( ! inst - > declaration ( ) . as_entity ( ) ) {
2025-08-26 10:17:57 +02:00
// Probably a case of IfcPropertySetDefinitionSet, divert storage of reference to the simply type instance
storage = & inst - > data ( ) ;
2025-04-11 15:52:40 +02:00
attr_index = 0 ;
}
}
2025-08-26 10:17:57 +02:00
if ( storage - > has_attribute_value < Blank > ( nullptr , nullptr , 0 , attr_index ) ) {
2025-08-26 10:20:08 +02:00
storage - > set_attribute_value ( nullptr , nullptr , 0 , attr_index , instances ) ;
2025-04-11 15:52:40 +02:00
} else {
Logger : : Error ( " Duplicate definition for instance reference " ) ;
}
2024-09-23 15:10:37 +02:00
}
2024-08-23 20:29:07 +02:00
}
2023-09-17 12:30:17 +02:00
2024-09-23 15:10:37 +02:00
Logger : : Status ( " Done resolving references " ) ;
2011-07-11 09:33:18 +00:00
}
2015-02-17 19:48:41 +00:00
2021-06-26 13:23:55 +02:00
void IfcFile : : recalculate_id_counter ( ) {
2025-02-21 16:12:16 +01:00
/*
// @todo
2023-09-17 12:30:17 +02:00
entity_by_id_t::key_type k = 0;
2023-11-06 20:38:19 +01:00
for (auto& p : byid_) {
2023-09-17 12:30:17 +02:00
if (p.first > k) {
k = p.first;
}
}
2025-02-21 16:12:16 +01:00
max_id_ = (unsigned int)k;
*/
2021-06-26 13:23:55 +02:00
}
2021-08-12 13:35:45 +02:00
class traversal_recorder {
2023-09-17 12:30:17 +02:00
aggregate_of_instance : : ptr list_ ;
std : : map < int , aggregate_of_instance : : ptr > instances_by_level_ ;
int mode_ ;
public :
traversal_recorder ( int mode ) : mode_ ( mode ) {
if ( mode = = 0 ) {
list_ . reset ( new aggregate_of_instance ) ;
}
} ;
void push_back ( int level , IfcUtil : : IfcBaseClass * instance ) {
if ( mode_ = = 0 ) {
list_ - > push ( instance ) ;
} else {
auto & l = instances_by_level_ [ level ] ;
if ( ! l ) {
l . reset ( new aggregate_of_instance ) ;
}
l - > push ( instance ) ;
}
}
2021-08-12 13:35:45 +02:00
2023-09-17 12:30:17 +02:00
aggregate_of_instance : : ptr get_list ( ) const {
if ( mode_ = = 0 ) {
return list_ ;
}
2023-10-24 12:21:32 +02:00
aggregate_of_instance : : ptr l ( new aggregate_of_instance ) ;
2023-10-24 16:11:26 +02:00
for ( const auto & p : instances_by_level_ ) {
2023-10-24 12:21:32 +02:00
l - > push ( p . second ) ;
}
return l ;
2023-09-17 12:30:17 +02:00
}
2021-08-12 13:35:45 +02:00
} ;
2017-08-01 19:07:46 +02:00
class traversal_visitor {
2023-09-17 12:30:17 +02:00
private :
std : : set < IfcUtil : : IfcBaseClass * > & visited_ ;
traversal_recorder & list_ ;
int level_ ;
int max_level_ ;
public :
traversal_visitor ( std : : set < IfcUtil : : IfcBaseClass * > & visited , traversal_recorder & list , int level , int max_level )
: visited_ ( visited ) ,
list_ ( list ) ,
level_ ( level ) ,
max_level_ ( max_level ) { }
void operator ( ) ( IfcUtil : : IfcBaseClass * inst , int index ) ;
2017-08-01 19:07:46 +02:00
} ;
2021-08-12 13:35:45 +02:00
void traverse_ ( IfcUtil : : IfcBaseClass * instance , std : : set < IfcUtil : : IfcBaseClass * > & visited , traversal_recorder & list , int level , int max_level ) {
2023-09-17 12:30:17 +02:00
if ( visited . find ( instance ) ! = visited . end ( ) ) {
return ;
}
visited . insert ( instance ) ;
list . push_back ( level , instance ) ;
2015-02-17 19:48:41 +00:00
2023-09-17 12:30:17 +02:00
if ( level > = max_level & & max_level > 0 ) {
return ;
}
2015-02-17 19:48:41 +00:00
2023-09-17 12:30:17 +02:00
traversal_visitor visit ( visited , list , level + 1 , max_level ) ;
2025-02-27 22:07:31 +01:00
apply_individual_instance_visitor ( instance ) . apply ( visit ) ;
2015-02-17 19:48:41 +00:00
}
2021-08-22 12:22:44 +02:00
void traversal_visitor : : operator ( ) ( IfcUtil : : IfcBaseClass * inst , int /* index */ ) {
2023-09-17 12:30:17 +02:00
traverse_ ( inst , visited_ , list_ , level_ , max_level_ ) ;
2017-08-01 19:07:46 +02:00
}
2021-07-29 14:54:51 +02:00
aggregate_of_instance : : ptr IfcParse : : traverse ( IfcUtil : : IfcBaseClass * instance , int max_level ) {
2023-09-17 12:30:17 +02:00
std : : set < IfcUtil : : IfcBaseClass * > visited ;
2023-11-06 20:29:00 +01:00
traversal_recorder recorder ( 0 ) ;
traverse_ ( instance , visited , recorder , 0 , max_level ) ;
return recorder . get_list ( ) ;
2021-08-12 13:35:45 +02:00
}
// I'm cheating this isn't breadth-first, but rather we record visited instances
// keeping track of their rank and return a list ordered by rank. Is this equivalent?
2021-08-15 20:40:55 +02:00
aggregate_of_instance : : ptr IfcParse : : traverse_breadth_first ( IfcUtil : : IfcBaseClass * instance , int max_level ) {
2023-09-17 12:30:17 +02:00
std : : set < IfcUtil : : IfcBaseClass * > visited ;
2023-11-06 20:29:00 +01:00
traversal_recorder recorder ( 1 ) ;
traverse_ ( instance , visited , recorder , 0 , max_level ) ;
return recorder . get_list ( ) ;
2015-02-17 19:48:41 +00:00
}
2017-06-20 18:54:30 +02:00
/// @note: for backwards compatibility
2021-07-29 14:54:51 +02:00
aggregate_of_instance : : ptr IfcFile : : traverse ( IfcUtil : : IfcBaseClass * instance , int max_level ) {
2023-09-17 12:30:17 +02:00
return IfcParse : : traverse ( instance , max_level ) ;
2017-06-20 18:54:30 +02:00
}
2021-08-12 13:35:45 +02:00
/// @note: for backwards compatibility
2021-08-15 20:40:55 +02:00
aggregate_of_instance : : ptr IfcFile : : traverse_breadth_first ( IfcUtil : : IfcBaseClass * instance , int max_level ) {
2023-09-17 12:30:17 +02:00
return IfcParse : : traverse_breadth_first ( instance , max_level ) ;
2021-08-12 13:35:45 +02:00
}
2023-11-06 20:29:00 +01:00
void IfcFile : : addEntities ( aggregate_of_instance : : ptr entities ) {
for ( aggregate_of_instance : : it i = entities - > begin ( ) ; i ! = entities - > end ( ) ; + + i ) {
2023-09-17 12:30:17 +02:00
addEntity ( * i ) ;
}
2012-08-11 13:24:08 +00:00
}
2015-02-17 19:48:41 +00:00
2021-06-27 11:14:26 +02:00
IfcUtil : : IfcBaseClass * IfcFile : : addEntity ( IfcUtil : : IfcBaseClass * entity , int id ) {
2025-02-21 16:12:16 +01:00
if ( id ! = - 1 ) {
bool id_already_exists = false ;
try {
2025-03-14 18:56:27 +01:00
if ( check_existance_before_adding ) {
instance_by_id ( id ) ;
id_already_exists = true ;
}
2025-02-21 16:12:16 +01:00
} catch ( . . . ) { }
if ( id_already_exists ) {
throw IfcParse : : IfcException ( " An instance with id " + boost : : lexical_cast < std : : string > ( id ) + " is already part of this file " ) ;
}
2023-09-17 12:30:17 +02:00
}
2021-06-27 11:14:26 +02:00
2023-09-17 12:30:17 +02:00
if ( entity - > declaration ( ) . schema ( ) ! = schema ( ) ) {
throw IfcParse : : IfcException ( " Unabled to add instance from " + entity - > declaration ( ) . schema ( ) - > name ( ) + " schema to file with " + schema ( ) - > name ( ) + " schema " ) ;
}
2018-11-04 15:16:08 +01:00
2023-09-17 12:30:17 +02:00
// If this instance has been inserted before, return
// a reference to the copy that was created from it.
2023-11-06 20:38:19 +01:00
entity_entity_map_t : : iterator mit = entity_file_map_ . find ( entity - > identity ( ) ) ;
if ( mit ! = entity_file_map_ . end ( ) ) {
2023-09-17 12:30:17 +02:00
return mit - > second ;
}
2015-02-17 19:48:41 +00:00
2023-09-17 12:30:17 +02:00
IfcUtil : : IfcBaseClass * new_entity = entity ;
// Obtain all forward references by a depth-first
// traversal and add them to the file.
2024-08-23 20:29:07 +02:00
try {
aggregate_of_instance : : ptr entity_attributes = traverse ( entity , 1 ) ;
for ( aggregate_of_instance : : it it = entity_attributes - > begin ( ) ; it ! = entity_attributes - > end ( ) ; + + it ) {
if ( * it ! = entity ) {
entity_entity_map_t : : iterator mit2 = entity_file_map_ . find ( ( * it ) - > identity ( ) ) ;
if ( mit2 = = entity_file_map_ . end ( ) ) {
entity_file_map_ . insert ( entity_entity_map_t : : value_type ( ( * it ) - > identity ( ) , addEntity ( * it ) ) ) ;
2023-09-17 12:30:17 +02:00
}
}
}
2024-08-23 20:29:07 +02:00
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_ERROR , " Failed to visit forward references of " , entity ) ;
2023-09-17 12:30:17 +02:00
}
2015-02-17 19:48:41 +00:00
2023-09-17 12:30:17 +02:00
// See whether the instance is already part of a file
2024-08-23 20:29:07 +02:00
if ( entity - > file_ ! = nullptr ) {
if ( entity - > file_ = = this ) {
2023-10-24 14:16:26 +02:00
if ( entity - > declaration ( ) . as_entity ( ) = = nullptr ) {
2023-09-17 12:30:17 +02:00
// While not a mapping that can be queried, we do need to free the instance later on
2025-02-21 16:12:16 +01:00
// @todo. why (over?)write this when adding from the same file?
2025-03-09 21:20:16 +01:00
std : : visit ( [ new_entity ] ( auto & m ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( m ) > , impl : : in_memory_file_storage > ) {
// @todo not freed yet
m . tbyid_ . insert ( { new_entity - > identity ( ) , new_entity } ) ;
}
} , storage_ ) ;
2023-09-17 12:30:17 +02:00
}
// If it is part of this file
// nothing else needs to be done.
return entity ;
}
// An instance is being added from another file. A copy of the
// container and entity is created. The attribute references
// need to be updated to point to instances in this file.
2024-08-23 20:29:07 +02:00
IfcFile * other_file = entity - > file_ ;
2025-02-27 22:07:31 +01:00
auto * decl = & entity - > declaration ( ) ;
if ( storage_ . index ( ) = = 1 ) {
if ( auto * ent = decl - > as_entity ( ) ) {
new_entity = schema_ - > instantiate ( decl , in_memory_attribute_storage ( ent - > attribute_count ( ) ) ) ;
} else if ( auto * typedecl = decl - > as_type_declaration ( ) ) {
new_entity = schema_ - > instantiate ( decl , in_memory_attribute_storage ( 1 ) ) ;
}
}
if ( storage_ . index ( ) = = 2 ) {
new_entity = schema_ - > instantiate ( decl , rocks_db_attribute_storage { } ) ;
}
new_entity - > file_ = this ;
2024-08-23 20:29:07 +02:00
2025-03-09 21:20:16 +01:00
// A new entity instance name is generated and
// the instance is pointed to this file.
if ( new_entity - > declaration ( ) . as_entity ( ) ! = nullptr ) {
if ( id = = - 1 ) {
new_entity - > as < IfcUtil : : IfcBaseEntity > ( ) - > set_id ( FreshId ( ) ) ;
} else {
new_entity - > as < IfcUtil : : IfcBaseEntity > ( ) - > set_id ( ( unsigned int ) id ) ;
if ( ( unsigned ) id > max_id_ ) {
max_id_ = ( unsigned ) id ;
}
}
}
2025-02-27 22:07:31 +01:00
void * own_storage = std : : visit ( [ ] ( const auto & m ) { return ( void * ) & m ; } , storage_ ) ;
void * other_storage = std : : visit ( [ ] ( const auto & m ) { return ( void * ) & m ; } , other_file - > storage_ ) ;
2025-03-14 16:16:25 +01:00
auto num_attributes = ( entity - > declaration ( ) . as_entity ( ) ? entity - > declaration ( ) . as_entity ( ) - > attribute_count ( ) : 1 ) ;
for ( size_t i = 0 ; i < num_attributes ; + + i ) {
2025-03-09 21:20:16 +01:00
entity - > data ( ) . apply_visitor ( other_storage , decl , entity - > id ( ) ? entity - > id ( ) : entity - > identity ( ) , [ this , i , decl , new_entity , own_storage ] ( const auto & v ) {
2025-02-27 22:07:31 +01:00
using U = std : : decay_t < decltype ( v ) > ;
// only need to copy non-instance attribute values, others are assigned below after mapping
if constexpr ( std : : is_same_v < U , IfcUtil : : IfcBaseClass * > ) {
} else if constexpr ( std : : is_same_v < U , aggregate_of_instance : : ptr > ) {
} else if constexpr ( std : : is_same_v < U , aggregate_of_aggregate_of_instance : : ptr > ) {
} else {
new_entity - > set_attribute_value ( i , v ) ;
}
} , i ) ;
}
2023-09-17 12:30:17 +02:00
// In case an entity is added that contains geometry, the unit
// information needs to be accounted for for IfcLengthMeasures.
2025-03-14 18:56:27 +01:00
double conversion_factor = calculate_unit_factors ? std : : numeric_limits < double > : : quiet_NaN ( ) : 1.0 ;
2015-02-17 19:48:41 +00:00
2025-02-27 22:07:31 +01:00
for ( size_t i = 0 ; i < ( new_entity - > declaration ( ) . as_entity ( ) ? new_entity - > declaration ( ) . as_entity ( ) - > attribute_count ( ) : 1 ) ; + + i ) {
// old attribute value
auto attr = entity - > get_attribute_value ( i ) ;
2024-08-23 20:29:07 +02:00
IfcUtil : : ArgumentType attr_type = attr . type ( ) ;
2023-09-17 12:30:17 +02:00
IfcParse : : declaration * decl = 0 ;
2023-10-24 14:16:26 +02:00
if ( entity - > declaration ( ) . as_entity ( ) ! = nullptr ) {
2023-09-17 12:30:17 +02:00
decl = 0 ;
const parameter_type * pt = entity - > declaration ( ) . as_entity ( ) - > attribute_by_index ( i ) - > type_of_attribute ( ) ;
2023-10-24 14:16:26 +02:00
while ( pt - > as_aggregation_type ( ) ! = nullptr ) {
2023-09-17 12:30:17 +02:00
pt = pt - > as_aggregation_type ( ) - > type_of_element ( ) ;
}
2023-10-24 14:16:26 +02:00
if ( pt - > as_named_type ( ) ! = nullptr ) {
2023-09-17 12:30:17 +02:00
decl = pt - > as_named_type ( ) - > declared_type ( ) ;
}
}
if ( attr_type = = IfcUtil : : Argument_ENTITY_INSTANCE ) {
2024-08-23 20:29:07 +02:00
entity_entity_map_t : : const_iterator eit = entity_file_map_ . find ( ( ( IfcUtil : : IfcBaseClass * ) ( attr ) ) - > identity ( ) ) ;
2023-11-06 20:38:19 +01:00
if ( eit = = entity_file_map_ . end ( ) ) {
2023-09-17 12:30:17 +02:00
throw IfcParse : : IfcException ( " Unable to map instance to file " ) ;
}
2025-02-27 22:07:31 +01:00
// @todo previously, we directly use storage::set() not to trigger inverse recalculation which happens at the end
new_entity - > set_attribute_value ( i , eit - > second ) ;
2023-09-17 12:30:17 +02:00
} else if ( attr_type = = IfcUtil : : Argument_AGGREGATE_OF_ENTITY_INSTANCE ) {
2024-08-23 20:29:07 +02:00
aggregate_of_instance : : ptr instances = attr ;
2023-09-17 12:30:17 +02:00
aggregate_of_instance : : ptr new_instances ( new aggregate_of_instance ) ;
for ( aggregate_of_instance : : it it = instances - > begin ( ) ; it ! = instances - > end ( ) ; + + it ) {
2023-11-06 20:38:19 +01:00
entity_entity_map_t : : const_iterator eit = entity_file_map_ . find ( ( * it ) - > identity ( ) ) ;
if ( eit = = entity_file_map_ . end ( ) ) {
2023-09-17 12:30:17 +02:00
throw IfcParse : : IfcException ( " Unable to map instance to file " ) ;
}
new_instances - > push ( eit - > second ) ;
}
2025-02-27 22:07:31 +01:00
new_entity - > set_attribute_value ( i , new_instances ) ;
2023-09-17 12:30:17 +02:00
} else if ( attr_type = = IfcUtil : : Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE ) {
2024-08-23 20:29:07 +02:00
aggregate_of_aggregate_of_instance : : ptr instances = attr ;
2023-09-17 12:30:17 +02:00
aggregate_of_aggregate_of_instance : : ptr new_instances ( new aggregate_of_aggregate_of_instance ) ;
for ( aggregate_of_aggregate_of_instance : : outer_it it = instances - > begin ( ) ; it ! = instances - > end ( ) ; + + it ) {
std : : vector < IfcUtil : : IfcBaseClass * > list ;
for ( aggregate_of_aggregate_of_instance : : inner_it jt = it - > begin ( ) ; jt ! = it - > end ( ) ; + + jt ) {
2023-11-06 20:38:19 +01:00
entity_entity_map_t : : const_iterator eit = entity_file_map_ . find ( ( * jt ) - > identity ( ) ) ;
if ( eit = = entity_file_map_ . end ( ) ) {
2023-09-17 12:30:17 +02:00
throw IfcParse : : IfcException ( " Unable to map instance to file " ) ;
}
list . push_back ( eit - > second ) ;
}
new_instances - > push ( list ) ;
}
2024-08-23 20:29:07 +02:00
2025-02-27 22:07:31 +01:00
new_entity - > set_attribute_value ( i , new_instances ) ;
2023-10-24 14:16:26 +02:00
} else if ( ( decl ! = nullptr ) & & decl - > is ( * schema ( ) - > declaration_by_name ( " IfcLengthMeasure " ) ) ) {
2023-09-17 12:30:17 +02:00
if ( boost : : math : : isnan ( conversion_factor ) ) {
std : : pair < IfcUtil : : IfcBaseClass * , double > this_file_unit = { nullptr , 1.0 } ;
std : : pair < IfcUtil : : IfcBaseClass * , double > other_file_unit = { nullptr , 1.0 } ;
try {
this_file_unit = getUnit ( " LENGTHUNIT " ) ;
other_file_unit = other_file - > getUnit ( " LENGTHUNIT " ) ;
} catch ( IfcParse : : IfcException & ) {
}
2023-10-24 14:16:26 +02:00
if ( ( this_file_unit . first ! = nullptr ) & & ( other_file_unit . first ! = nullptr ) ) {
2023-09-17 12:30:17 +02:00
conversion_factor = other_file_unit . second / this_file_unit . second ;
} else {
conversion_factor = 1. ;
}
}
if ( attr_type = = IfcUtil : : Argument_DOUBLE ) {
2024-08-23 20:29:07 +02:00
double v = attr ;
2023-09-17 12:30:17 +02:00
v * = conversion_factor ;
2025-02-27 22:07:31 +01:00
new_entity - > set_attribute_value ( i , v ) ;
2023-09-17 12:30:17 +02:00
} else if ( attr_type = = IfcUtil : : Argument_AGGREGATE_OF_DOUBLE ) {
2024-08-23 20:29:07 +02:00
std : : vector < double > v = attr ;
2023-09-17 12:30:17 +02:00
for ( std : : vector < double > : : iterator it = v . begin ( ) ; it ! = v . end ( ) ; + + it ) {
( * it ) * = conversion_factor ;
}
2025-02-27 22:07:31 +01:00
new_entity - > set_attribute_value ( i , v ) ;
2023-09-17 12:30:17 +02:00
} else if ( attr_type = = IfcUtil : : Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE ) {
2024-08-23 20:29:07 +02:00
std : : vector < std : : vector < double > > v = attr ;
2023-09-17 12:30:17 +02:00
for ( std : : vector < std : : vector < double > > : : iterator it = v . begin ( ) ; it ! = v . end ( ) ; + + it ) {
std : : vector < double > & v2 = ( * it ) ;
for ( std : : vector < double > : : iterator jt = v2 . begin ( ) ; jt ! = v2 . end ( ) ; + + jt ) {
( * jt ) * = conversion_factor ;
}
}
2025-02-27 22:07:31 +01:00
new_entity - > set_attribute_value ( i , v ) ;
2023-09-17 12:30:17 +02:00
}
}
}
2015-02-17 19:48:41 +00:00
2023-11-06 20:38:19 +01:00
entity_file_map_ . insert ( entity_entity_map_t : : value_type ( entity - > identity ( ) , new_entity ) ) ;
2023-09-17 12:30:17 +02:00
}
2017-08-16 21:46:39 +02:00
2023-09-17 12:30:17 +02:00
// For subtypes of IfcRoot, the GUID mapping needs to be updated.
if ( new_entity - > declaration ( ) . is ( * ifcroot_type_ ) ) {
try {
2025-02-27 22:07:31 +01:00
const std : : string guid = new_entity - > get_attribute_value ( 0 ) ;
2023-11-06 20:38:19 +01:00
if ( byguid_ . find ( guid ) ! = byguid_ . end ( ) ) {
2023-09-17 12:30:17 +02:00
std : : stringstream ss ;
ss < < " Overwriting entity with guid " < < guid ;
Logger : : Message ( Logger : : LOG_WARNING , ss . str ( ) ) ;
}
2025-02-21 16:12:16 +01:00
byguid_ . insert ( { guid , new_entity } ) ;
2024-08-23 20:29:07 +02:00
} catch ( const std : : exception & ex ) {
2023-09-17 12:30:17 +02:00
Logger : : Message ( Logger : : LOG_ERROR , ex . what ( ) ) ;
}
}
2017-08-16 21:46:39 +02:00
2023-09-17 12:30:17 +02:00
// The mapping by entity type is updated.
const IfcParse : : declaration * ty = & new_entity - > declaration ( ) ;
2012-07-18 19:32:58 +00:00
2025-03-09 21:20:16 +01:00
// @nb happens always because this also registers the type of the instance in rocksdb
// if (ty->as_entity() != nullptr) {
2025-02-21 16:12:16 +01:00
add_type_ref ( new_entity ) ;
2025-03-09 21:20:16 +01:00
// }
2023-09-17 12:30:17 +02:00
2023-10-24 14:16:26 +02:00
if ( ty - > as_entity ( ) ! = nullptr ) {
2023-09-17 12:30:17 +02:00
int new_id = - 1 ;
2024-08-23 20:29:07 +02:00
if ( new_entity - > file_ = = nullptr ) {
2023-09-17 12:30:17 +02:00
// For newly created entities ensure a valid ENTITY_INSTANCE_NAME is set
2024-08-23 20:29:07 +02:00
new_entity - > file_ = this ;
2023-09-17 12:30:17 +02:00
boost : : optional < unsigned > id_value ;
if ( id ! = - 1 ) {
id_value = ( unsigned ) id ;
2025-02-21 16:12:16 +01:00
if ( ( unsigned ) id > max_id_ ) {
max_id_ = ( unsigned ) id ;
2023-09-17 12:30:17 +02:00
}
}
2024-08-23 20:29:07 +02:00
new_id = new_entity - > as < IfcUtil : : IfcBaseEntity > ( ) - > set_id ( id_value ) ;
2023-09-17 12:30:17 +02:00
} else {
2024-08-23 20:29:07 +02:00
new_id = new_entity - > id ( ) ;
2023-09-17 12:30:17 +02:00
}
2025-03-14 16:16:25 +01:00
/*
2023-11-06 20:38:19 +01:00
if (byid_.find(new_id) != byid_.end()) {
2023-09-17 12:30:17 +02:00
// This should not happen
std::stringstream ss;
ss << "Overwriting entity with id " << new_id;
Logger::Message(Logger::LOG_WARNING, ss.str());
}
2025-03-14 16:16:25 +01:00
*/
2025-03-09 21:20:16 +01:00
// rocksdb instances are assumed to be create with file.create();
std : : visit ( [ new_entity ] ( auto & m ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( m ) > , impl : : in_memory_file_storage > ) {
// @todo not freed yet
2025-03-14 16:16:25 +01:00
m . byid_ . insert ( { new_entity - > id ( ) , new_entity } ) ;
2025-03-09 21:20:16 +01:00
}
} , storage_ ) ;
2024-08-23 20:29:07 +02:00
} else if ( new_entity - > file_ = = nullptr ) {
2023-09-17 12:30:17 +02:00
// For non-entity instances, no mappings are updated, but the file
// pointer has to be set, so that actual copies are created in subsequent
// times.
2024-08-23 20:29:07 +02:00
new_entity - > file_ = this ;
2023-09-17 12:30:17 +02:00
2025-03-09 21:20:16 +01:00
// rocksdb instances are assumed to be create with file.create();
std : : visit ( [ new_entity ] ( auto & m ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( m ) > , impl : : in_memory_file_storage > ) {
// @todo not freed yet
m . tbyid_ . insert ( { new_entity - > identity ( ) , new_entity } ) ;
}
} , storage_ ) ;
2023-09-17 12:30:17 +02:00
}
2021-03-13 12:16:40 +01:00
2025-02-27 22:07:31 +01:00
/*
// @todo not needed anymore, because these are now calculated by using baseclass::set() ?
2024-08-23 20:29:07 +02:00
if ((ty->as_entity() != nullptr)) {
2023-09-17 12:30:17 +02:00
build_inverses_(new_entity);
}
2025-02-27 22:07:31 +01:00
*/
2023-09-17 12:30:17 +02:00
return new_entity ;
2015-02-17 19:48:41 +00:00
}
void IfcFile : : removeEntity ( IfcUtil : : IfcBaseClass * entity ) {
2024-08-23 20:29:07 +02:00
const unsigned id = entity - > id ( ) ;
2023-09-17 12:30:17 +02:00
IfcUtil : : IfcBaseClass * file_entity = instance_by_id ( id ) ;
// Attention when running removeEntity inside a loop over a list of entities to be removed.
// This invalidates the iterator. A workaround is to reverse the loop:
// boost::shared_ptr<aggregate_of_instance> entities = ...;
// for (auto it = entities->end() - 1; it >= entities->begin(); --it) {
// IfcUtil::IfcBaseClass *const inst = *it;
// model->removeEntity(inst);
// }
// TODO: Create a set of weak relations. Inverse relations that do not dictate an
// instance to be retained. For example: when deleting an IfcRepresentation, the
// individual IfcRepresentationItems can not be deleted if an IfcStyledItem is
// related. Hence, the IfcRepresentationItem::StyledByItem relation could be
// characterized as weak.
// std::set<IfcSchema::Type::Enum> weak_roots;
if ( entity ! = file_entity ) {
throw IfcParse : : IfcException ( " Instance not part of this file " ) ;
}
2015-02-17 19:48:41 +00:00
2025-02-21 16:12:16 +01:00
aggregate_of_instance : : ptr references = instances_by_reference ( id ) ;
2015-02-17 19:48:41 +00:00
2025-02-21 16:12:16 +01:00
// Alter entity instances with INVERSE relations to the entity being
// deleted. This is necessary to maintain a valid IFC file, because
// dangling references to it's entities name should be removed. At this
// moment, inversely related instances affected by the removal of the
// entity being deleted are not deleted themselves.
if ( references ) {
for ( aggregate_of_instance : : it iit = references - > begin ( ) ; iit ! = references - > end ( ) ; + + iit ) {
IfcUtil : : IfcBaseEntity * related_instance = ( IfcUtil : : IfcBaseEntity * ) * iit ;
2017-12-11 14:47:30 +01:00
2025-02-21 16:12:16 +01:00
if ( std : : find ( batch_deletion_ids_ . begin ( ) , batch_deletion_ids_ . end ( ) , related_instance - > id ( ) ) ! = batch_deletion_ids_ . end ( ) ) {
continue ;
}
2023-09-17 12:30:17 +02:00
2025-02-27 22:07:31 +01:00
const auto & decl = related_instance - > declaration ( ) ;
for ( size_t i = 0 ; i < ( decl . as_entity ( ) ? decl . as_entity ( ) - > attribute_count ( ) : 1 ) ; + + i ) {
auto attr = related_instance - > get_attribute_value ( i ) ;
2025-02-21 16:12:16 +01:00
if ( attr . isNull ( ) ) {
2023-09-17 12:30:17 +02:00
continue ;
}
2025-02-21 16:12:16 +01:00
IfcUtil : : ArgumentType attr_type = attr . type ( ) ;
switch ( attr_type ) {
case IfcUtil : : Argument_ENTITY_INSTANCE : {
IfcUtil : : IfcBaseClass * instance_attribute = attr ;
if ( instance_attribute = = entity ) {
related_instance - > set_attribute_value ( i , Blank { } ) ;
2023-09-17 12:30:17 +02:00
}
2025-02-21 16:12:16 +01:00
} break ;
case IfcUtil : : Argument_AGGREGATE_OF_ENTITY_INSTANCE : {
aggregate_of_instance : : ptr instance_list = attr ;
if ( instance_list - > contains ( entity ) ) {
instance_list - > remove ( entity ) ;
if ( ( instance_list - > size ( ) = = 0U ) & & related_instance - > declaration ( ) . as_entity ( ) - > attribute_by_index ( i ) - > optional ( ) ) {
// @todo we can also check the lower bound of the attribute type before setting to null.
2024-08-23 20:29:07 +02:00
related_instance - > set_attribute_value ( i , Blank { } ) ;
2025-02-21 16:12:16 +01:00
} else {
related_instance - > set_attribute_value ( i , instance_list ) ;
2023-09-17 12:30:17 +02:00
}
2025-02-21 16:12:16 +01:00
}
} break ;
case IfcUtil : : Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE : {
aggregate_of_aggregate_of_instance : : ptr instance_list_list = attr ;
if ( instance_list_list - > contains ( entity ) ) {
aggregate_of_aggregate_of_instance : : ptr new_list ( new aggregate_of_aggregate_of_instance ) ;
for ( aggregate_of_aggregate_of_instance : : outer_it it = instance_list_list - > begin ( ) ; it ! = instance_list_list - > end ( ) ; + + it ) {
std : : vector < IfcUtil : : IfcBaseClass * > instances = * it ;
std : : vector < IfcUtil : : IfcBaseClass * > : : iterator jt ;
while ( ( jt = std : : find ( instances . begin ( ) , instances . end ( ) , entity ) ) ! = instances . end ( ) ) {
instances . erase ( jt ) ;
2023-09-17 12:30:17 +02:00
}
2025-02-21 16:12:16 +01:00
new_list - > push ( instances ) ;
2023-09-17 12:30:17 +02:00
}
2025-02-21 16:12:16 +01:00
related_instance - > set_attribute_value ( i , new_list ) ;
2023-09-17 12:30:17 +02:00
}
2025-02-21 16:12:16 +01:00
} break ;
default :
break ;
2023-09-17 12:30:17 +02:00
}
}
}
2025-02-21 16:12:16 +01:00
}
2021-03-13 12:16:40 +01:00
2025-02-27 22:07:31 +01:00
if ( entity - > declaration ( ) . is ( * ifcroot_type_ ) & & ! entity - > get_attribute_value ( 0 ) . isNull ( ) ) {
const std : : string global_id = entity - > get_attribute_value ( 0 ) ;
2025-02-21 16:12:16 +01:00
auto it = byguid_ . find ( global_id ) ;
if ( it ! = byguid_ . end ( ) ) {
byguid_ . erase ( it ) ;
} else {
Logger : : Warning ( " GlobalId on rooted instance not encountered in map " ) ;
}
}
2023-09-17 12:30:17 +02:00
2025-03-09 21:20:16 +01:00
//byid_.erase(byid_.find(id));
byid_ . erase ( id ) ;
2023-09-17 12:30:17 +02:00
2025-02-21 16:12:16 +01:00
const IfcParse : : declaration * ty = & entity - > declaration ( ) ;
2023-09-17 12:30:17 +02:00
2025-02-21 16:12:16 +01:00
{
remove_type_ref ( entity ) ;
/*auto it = bytype_excl_.find(ty);
if (it != bytype_excl_.end()) {
it->second->remove(entity);
if (it->second->size() == 0) {
bytype_excl_.erase(ty);
2023-09-17 12:30:17 +02:00
}
2025-02-21 16:12:16 +01:00
}*/
}
// entity_file_map is in place to prevent duplicate definitions with usage of add().
// Upon deletion the pairs need to be erased.
for ( auto it = entity_file_map_ . begin ( ) ; it ! = entity_file_map_ . end ( ) ; ) {
if ( it - > second = = entity ) {
it = entity_file_map_ . erase ( it ) ;
} else {
+ + it ;
2023-09-17 12:30:17 +02:00
}
2025-02-21 16:12:16 +01:00
}
2023-09-17 12:30:17 +02:00
2025-02-21 16:12:16 +01:00
delete entity ;
}
2023-09-17 12:30:17 +02:00
2025-02-21 16:12:16 +01:00
void IfcParse : : impl : : in_memory_file_storage : : process_deletion_inverse ( IfcUtil : : IfcBaseClass * entity ) {
auto id = entity - > id ( ) ;
2023-09-17 12:30:17 +02:00
2025-02-21 16:12:16 +01:00
// Delete inverses into entity
byref_excl_ . erase (
byref_excl_ . lower_bound ( { id , - 1 , - 1 } ) ,
byref_excl_ . upper_bound ( { id , std : : numeric_limits < short > : : max ( ) , std : : numeric_limits < short > : : max ( ) } ) ) ;
2023-09-17 12:30:17 +02:00
2025-02-21 16:12:16 +01:00
// This is based on traversal which needs instances to still be contained in the map.
// another option would be to keep byid intact for the remainder of this loop
aggregate_of_instance : : ptr entity_attributes = traverse ( entity , 1 ) ;
for ( aggregate_of_instance : : it it = entity_attributes - > begin ( ) ; it ! = entity_attributes - > end ( ) ; + + it ) {
IfcUtil : : IfcBaseClass * entity_attribute = * it ;
if ( entity_attribute = = entity ) {
continue ;
2023-09-17 12:30:17 +02:00
}
2025-02-21 16:12:16 +01:00
const unsigned int name = entity_attribute - > id ( ) ;
// Do not update inverses for simple types (which have id()==0 in IfcOpenShell).
if ( name ! = 0 ) {
// Find instances entity -> other
// and update inverses from entity into other
auto lower = byref_excl_ . lower_bound ( { name , - 1 , - 1 } ) ;
auto upper = byref_excl_ . upper_bound ( { name , std : : numeric_limits < short > : : max ( ) , std : : numeric_limits < short > : : max ( ) } ) ;
for ( auto byref_it = lower ; byref_it ! = upper ; + + byref_it ) {
auto & ids = byref_it - > second ;
ids . erase ( std : : remove ( ids . begin ( ) , ids . end ( ) , id ) , ids . end ( ) ) ;
2023-09-17 12:30:17 +02:00
}
}
2025-02-24 20:46:29 +01:00
}
2012-07-18 19:32:58 +00:00
}
2015-02-17 19:48:41 +00:00
2024-08-23 20:29:07 +02:00
namespace {
template < typename Fn >
void visit_subtypes ( const IfcParse : : entity * ent , Fn fn ) {
fn ( ent ) ;
for ( const auto & st : ent - > subtypes ( ) ) {
visit_subtypes ( st , fn ) ;
}
}
template < typename Fn >
void visit_supertypes ( const IfcParse : : entity * ent , Fn fn ) {
fn ( ent ) ;
if ( ent - > supertype ( ) ) {
visit_supertypes ( ent - > supertype ( ) , fn ) ;
}
}
}
2021-07-29 14:54:51 +02:00
aggregate_of_instance : : ptr IfcFile : : instances_by_type ( const IfcParse : : declaration * t ) {
2024-08-23 20:29:07 +02:00
aggregate_of_instance : : ptr insts ( new aggregate_of_instance ) ;
if ( t - > as_entity ( ) ! = nullptr ) {
visit_subtypes ( t - > as_entity ( ) , [ this , & insts ] ( const IfcParse : : entity * ent ) {
2025-02-21 16:12:16 +01:00
auto subtype_insts = instances_by_type_excl_subtypes ( ent ) ;
// @todo stop returning empty shared_ptrs
if ( subtype_insts ) {
insts - > push ( subtype_insts ) ;
2024-08-23 20:29:07 +02:00
}
} ) ;
}
return insts ;
2011-05-08 11:04:32 +00:00
}
2015-02-17 19:48:41 +00:00
2021-07-29 14:54:51 +02:00
aggregate_of_instance : : ptr IfcFile : : instances_by_type_excl_subtypes ( const IfcParse : : declaration * t ) {
2025-02-21 16:12:16 +01:00
return std : : visit ( [ t ] ( auto & x ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : in_memory_file_storage > ) {
auto it = x . bytype_excl_ . find ( t ) ;
return ( it = = x . bytype_excl_ . end ( ) ) ? aggregate_of_instance : : ptr ( new aggregate_of_instance ) : it - > second ;
} else if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : rocks_db_file_storage > ) {
aggregate_of_instance : : ptr ret ( new aggregate_of_instance ) ;
auto it = x . bytype_ . find ( t - > index_in_schema ( ) ) ;
2025-02-27 22:07:31 +01:00
if ( it ! = x . bytype_ . end ( ) ) {
const auto & s = it - > second ;
// @todo generalize this, bytype_ should be a map_adapter
std : : vector < size_t > vals ( s . size ( ) / sizeof ( size_t ) ) ;
memcpy ( vals . data ( ) , s . data ( ) , s . size ( ) ) ;
for ( auto & v : vals ) {
2025-03-09 21:20:16 +01:00
ret - > push ( x . assert_existance ( v , IfcParse : : impl : : rocks_db_file_storage : : entityinstance_ref ) ) ;
2025-02-27 22:07:31 +01:00
}
2025-02-21 16:12:16 +01:00
}
return ret ;
} else {
throw std : : runtime_error ( " Storage not initialized " ) ;
aggregate_of_instance : : ptr ret ( new aggregate_of_instance ) ;
return ret ;
}
} , storage_ ) ;
2017-08-16 21:46:39 +02:00
}
2021-07-29 14:54:51 +02:00
aggregate_of_instance : : ptr IfcFile : : instances_by_type ( const std : : string & t ) {
2023-09-17 12:30:17 +02:00
return instances_by_type ( schema ( ) - > declaration_by_name ( t ) ) ;
2012-07-19 00:14:01 +00:00
}
2015-02-17 19:48:41 +00:00
2021-07-29 14:54:51 +02:00
aggregate_of_instance : : ptr IfcFile : : instances_by_type_excl_subtypes ( const std : : string & t ) {
2023-09-17 12:30:17 +02:00
return instances_by_type_excl_subtypes ( schema ( ) - > declaration_by_name ( t ) ) ;
2020-07-11 11:55:00 +02:00
}
2021-07-29 14:54:51 +02:00
aggregate_of_instance : : ptr IfcFile : : instances_by_reference ( int t ) {
2023-09-17 12:30:17 +02:00
aggregate_of_instance : : ptr ret ( new aggregate_of_instance ) ;
2025-02-21 16:12:16 +01:00
std : : visit ( [ this , t , & ret ] ( auto & x ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : in_memory_file_storage > ) {
auto lower = x . byref_excl_ . lower_bound ( { t , - 1 , - 1 } ) ;
auto upper = x . byref_excl_ . upper_bound ( { t , std : : numeric_limits < short > : : max ( ) , std : : numeric_limits < short > : : max ( ) } ) ;
for ( auto it = lower ; it ! = upper ; + + it ) {
for ( auto & i : it - > second ) {
ret - > push ( instance_by_id ( i ) ) ;
}
}
2025-08-26 13:56:03 +02:00
}
# ifdef WITH_ROCKSDB
else if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : rocks_db_file_storage > ) {
2025-03-14 16:16:25 +01:00
// @todo no lower/upper_bounds() implemented yet
auto prefix = " v| " + std : : to_string ( t ) + " | " ;
auto it = x . db - > NewIterator ( rocksdb : : ReadOptions ( ) ) ;
it - > Seek ( prefix ) ;
while ( it - > Valid ( ) & & it - > key ( ) . starts_with ( prefix ) ) {
std : : vector < uint32_t > vals ( it - > value ( ) . size ( ) / sizeof ( uint32_t ) ) ;
memcpy ( vals . data ( ) , it - > value ( ) . data ( ) , it - > value ( ) . size ( ) ) ;
for ( auto & v : vals ) {
ret - > push ( instance_by_id ( v ) ) ;
}
it - > Next ( ) ;
}
2025-08-26 13:56:03 +02:00
}
# endif
else {
2025-02-21 16:12:16 +01:00
throw std : : runtime_error ( " Storage not initialized " ) ;
2024-08-23 20:29:07 +02:00
}
2025-02-21 16:12:16 +01:00
} , storage_ ) ;
2023-09-17 12:30:17 +02:00
return ret ;
2011-05-08 11:04:32 +00:00
}
2015-02-17 19:48:41 +00:00
2017-12-13 13:16:49 +01:00
IfcUtil : : IfcBaseClass * IfcFile : : instance_by_id ( int id ) {
2025-02-24 20:46:29 +01:00
return std : : visit ( [ id ] ( auto & x ) {
2025-02-21 16:12:16 +01:00
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , std : : monostate > ) {
throw std : : runtime_error ( " Storage not initialized " ) ;
return ( IfcUtil : : IfcBaseClass * ) nullptr ;
} else {
return x . instance_by_id ( id ) ;
}
} , storage_ ) ;
2011-05-08 11:04:32 +00:00
}
2015-02-17 19:48:41 +00:00
2025-02-21 16:12:16 +01:00
void IfcParse : : IfcFile : : add_type_ref ( IfcUtil : : IfcBaseClass * new_entity )
{
std : : visit ( [ new_entity ] ( auto & x ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , std : : monostate > ) {
throw std : : runtime_error ( " Storage not initialized " ) ;
} else {
return x . add_type_ref ( new_entity ) ;
}
} , storage_ ) ;
2012-03-13 11:56:52 +00:00
}
2011-07-25 14:56:40 +00:00
2025-02-21 16:12:16 +01:00
void IfcParse : : IfcFile : : remove_type_ref ( IfcUtil : : IfcBaseClass * new_entity )
{
std : : visit ( [ new_entity ] ( auto & x ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , std : : monostate > ) {
throw std : : runtime_error ( " Storage not initialized " ) ;
} else {
return x . remove_type_ref ( new_entity ) ;
}
} , storage_ ) ;
2012-08-11 13:24:08 +00:00
}
2025-02-21 16:12:16 +01:00
void IfcParse : : IfcFile : : process_deletion_inverse ( IfcUtil : : IfcBaseClass * inst )
{
std : : visit ( [ inst ] ( auto & x ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , std : : monostate > ) {
throw std : : runtime_error ( " Storage not initialized " ) ;
} else {
return x . process_deletion_inverse ( inst ) ;
}
} , storage_ ) ;
2012-03-16 15:21:52 +00:00
}
2015-02-17 19:48:41 +00:00
2025-02-21 16:12:16 +01:00
IfcUtil : : IfcBaseClass * IfcFile : : instance_by_guid ( const std : : string & guid ) {
auto it = byguid_ . find ( guid ) ;
if ( it = = byguid_ . end ( ) ) {
throw IfcException ( " Instance with GlobalId ' " + guid + " ' not found " ) ;
}
return it - > second ;
2012-03-16 15:21:52 +00:00
}
2012-08-11 13:24:08 +00:00
2017-08-16 21:46:39 +02:00
IfcFile : : type_iterator IfcFile : : types_begin ( ) const {
2025-02-21 16:12:16 +01:00
return std : : visit ( [ ] ( const auto & x ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , std : : monostate > ) {
2025-03-14 10:20:22 +01:00
return IfcFile : : type_iterator { impl : : rocks_db_file_storage : : rocksdb_types_iterator { } } ;
2025-02-21 16:12:16 +01:00
} else if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : in_memory_file_storage > ) {
2025-03-14 10:20:22 +01:00
return IfcFile : : type_iterator { x . bytype_excl_ . begin ( ) } ;
2025-02-21 16:12:16 +01:00
} else if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : rocks_db_file_storage > ) {
2025-03-14 10:20:22 +01:00
return IfcFile : : type_iterator { impl : : rocks_db_file_storage : : rocksdb_types_iterator ( & x ) } ;
2025-02-21 16:12:16 +01:00
}
} , storage_ ) ;
2017-08-16 21:46:39 +02:00
}
IfcFile : : type_iterator IfcFile : : types_end ( ) const {
2025-02-21 16:12:16 +01:00
return std : : visit ( [ ] ( const auto & x ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , std : : monostate > ) {
2025-03-14 10:20:22 +01:00
return IfcFile : : type_iterator { impl : : rocks_db_file_storage : : rocksdb_types_iterator { } } ;
2025-02-21 16:12:16 +01:00
} else if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : in_memory_file_storage > ) {
2025-03-14 10:20:22 +01:00
return IfcFile : : type_iterator { x . bytype_excl_ . end ( ) } ;
2025-02-21 16:12:16 +01:00
} else if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : rocks_db_file_storage > ) {
2025-03-14 10:20:22 +01:00
return IfcFile : : type_iterator { impl : : rocks_db_file_storage : : rocksdb_types_iterator { } } ;
2025-02-21 16:12:16 +01:00
}
} , storage_ ) ;
2017-08-16 21:46:39 +02:00
}
2023-11-06 20:29:00 +01:00
std : : ostream & operator < < ( std : : ostream & out , const IfcParse : : IfcFile & file ) {
file . header ( ) . write ( out ) ;
2012-07-18 19:32:58 +00:00
2025-02-21 16:12:16 +01:00
typedef std : : vector < IfcUtil : : IfcBaseClass * > vector_t ;
vector_t sorted ;
2025-02-25 21:29:54 +01:00
std : : transform ( file . begin ( ) , file . end ( ) , std : : back_inserter ( sorted ) , [ & file ] ( const auto & x ) { return x . second ; } ) ;
2025-02-21 16:12:16 +01:00
std : : sort ( sorted . begin ( ) , sorted . end ( ) , [ ] ( const auto & a , const auto & b ) { return a - > id ( ) < b - > id ( ) ; } ) ;
2018-11-13 14:46:15 +01:00
2025-02-21 16:12:16 +01:00
for ( auto & e : sorted ) {
// @todo this check should no longer be necessary?
2023-10-24 14:16:26 +02:00
if ( e - > declaration ( ) . as_entity ( ) ! = nullptr ) {
2024-08-23 20:29:07 +02:00
e - > toString ( out , true ) ;
out < < " ; " < < std : : endl ;
2023-09-17 12:30:17 +02:00
}
}
2012-07-18 19:32:58 +00:00
2023-11-06 20:29:00 +01:00
out < < " ENDSEC; " < < std : : endl ;
out < < " END-ISO-10303-21; " < < std : : endl ;
2012-08-11 13:24:08 +00:00
2023-11-06 20:29:00 +01:00
return out ;
2012-08-11 13:24:08 +00:00
}
2012-11-17 15:19:38 +00:00
2024-08-23 20:29:07 +02:00
std : : string IfcFile : : createTimestamp ( ) {
2023-09-17 12:30:17 +02:00
char buf [ 255 ] ;
time_t t ;
time ( & t ) ;
struct tm * ti = localtime ( & t ) ;
2015-01-16 16:26:40 +00:00
2024-08-23 20:29:07 +02:00
std : : string result ;
2023-10-24 14:16:26 +02:00
if ( strftime ( buf , 255 , " %Y-%m-%dT%H:%M:%S " , ti ) ! = 0U ) {
2023-09-17 12:30:17 +02:00
result = std : : string ( buf ) ;
}
return result ;
2015-01-10 22:13:52 +00:00
}
2022-10-20 13:35:02 +02:00
std : : vector < int > IfcFile : : get_inverse_indices ( int instance_id ) {
2023-09-17 12:30:17 +02:00
std : : vector < int > return_value ;
2022-10-20 13:35:02 +02:00
2023-09-17 12:30:17 +02:00
// Mapping of instance id to attribute offset.
std : : map < int , std : : vector < int > > mapping ;
2025-02-21 16:12:16 +01:00
std : : visit ( [ & mapping , instance_id ] ( const auto & x ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , std : : monostate > ) {
} else if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : in_memory_file_storage > ) {
auto lower = x . byref_excl_ . lower_bound ( { instance_id , - 1 , - 1 } ) ;
auto upper = x . byref_excl_ . upper_bound ( { instance_id , std : : numeric_limits < short > : : max ( ) , std : : numeric_limits < short > : : max ( ) } ) ;
for ( auto it = lower ; it ! = upper ; + + it ) {
for ( auto & i : it - > second ) {
mapping [ i ] . push_back ( std : : get < 2 > ( it - > first ) ) ;
}
2023-09-17 12:30:17 +02:00
}
2025-02-21 16:12:16 +01:00
} else if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : rocks_db_file_storage > ) {
// @todo
2023-09-17 12:30:17 +02:00
}
2025-02-21 16:12:16 +01:00
} , storage_ ) ;
2023-09-17 12:30:17 +02:00
auto refs = instances_by_reference ( instance_id ) ;
2023-11-06 20:29:00 +01:00
for ( const auto & ref : * refs ) {
2024-08-23 20:29:07 +02:00
auto it = mapping . find ( ref - > id ( ) ) ;
2023-09-17 12:30:17 +02:00
if ( it = = mapping . end ( ) | | it - > second . empty ( ) ) {
throw IfcException ( " Internal error " ) ;
}
return_value . push_back ( it - > second . front ( ) ) ;
it - > second . erase ( it - > second . begin ( ) ) ;
if ( it - > second . empty ( ) ) {
mapping . erase ( it ) ;
}
}
2022-10-20 13:35:02 +02:00
2023-09-17 12:30:17 +02:00
// Test whether all mappings where indeed used.
if ( ! mapping . empty ( ) ) {
throw IfcException ( " Internal error " ) ;
}
return return_value ;
2022-10-20 13:35:02 +02:00
}
2021-07-29 14:54:51 +02:00
aggregate_of_instance : : ptr IfcFile : : getInverse ( int instance_id , const IfcParse : : declaration * type , int attribute_index ) {
2023-09-17 12:30:17 +02:00
if ( type = = nullptr & & attribute_index = = - 1 ) {
return instances_by_reference ( instance_id ) ;
}
2015-01-10 22:13:52 +00:00
2023-09-17 12:30:17 +02:00
aggregate_of_instance : : ptr return_value ( new aggregate_of_instance ) ;
2021-08-22 12:22:44 +02:00
2024-08-23 20:29:07 +02:00
visit_subtypes ( type - > as_entity ( ) , [ this , attribute_index , instance_id , & return_value ] ( const IfcParse : : declaration * ent ) {
2015-01-16 16:26:40 +00:00
2025-02-21 16:12:16 +01:00
std : : visit ( [ & return_value , this , attribute_index , instance_id , ent ] ( const auto & x ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , std : : monostate > ) {
} else if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : in_memory_file_storage > ) {
if ( attribute_index = = - 1 ) {
auto lower = x . byref_excl_ . lower_bound ( { instance_id , ent - > index_in_schema ( ) , - 1 } ) ;
auto upper = x . byref_excl_ . upper_bound ( { instance_id , ent - > index_in_schema ( ) , std : : numeric_limits < short > : : max ( ) } ) ;
for ( auto it = lower ; it ! = upper ; + + it ) {
for ( auto & i : it - > second ) {
return_value - > push ( instance_by_id ( i ) ) ;
}
}
} else {
auto it = x . byref_excl_ . find ( { instance_id , ent - > index_in_schema ( ) , attribute_index } ) ;
if ( it ! = x . byref_excl_ . end ( ) ) {
for ( auto & i : it - > second ) {
return_value - > push ( instance_by_id ( i ) ) ;
}
}
2024-08-23 20:29:07 +02:00
}
2025-08-26 13:56:03 +02:00
}
# ifdef WITH_ROCKSDB
else if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : rocks_db_file_storage > ) {
2025-03-09 21:20:16 +01:00
if ( attribute_index = = - 1 ) {
// @todo no lower/upper_bounds() implemented yet
2025-03-13 12:34:54 +01:00
auto prefix = " v| " + std : : to_string ( instance_id ) + " | " + std : : to_string ( ent - > index_in_schema ( ) ) + " | " ;
2025-03-09 21:20:16 +01:00
auto it = x . db - > NewIterator ( rocksdb : : ReadOptions ( ) ) ;
it - > Seek ( prefix ) ;
while ( it - > Valid ( ) & & it - > key ( ) . starts_with ( prefix ) ) {
2025-03-13 12:34:54 +01:00
std : : vector < uint32_t > vals ( it - > value ( ) . size ( ) / sizeof ( uint32_t ) ) ;
2025-03-09 21:20:16 +01:00
memcpy ( vals . data ( ) , it - > value ( ) . data ( ) , it - > value ( ) . size ( ) ) ;
for ( auto & v : vals ) {
return_value - > push ( instance_by_id ( v ) ) ;
}
2025-03-13 12:34:54 +01:00
it - > Next ( ) ;
2025-03-09 21:20:16 +01:00
}
} else {
auto it = x . byref_excl_ . find ( { instance_id , ent - > index_in_schema ( ) , attribute_index } ) ;
if ( it ! = x . byref_excl_ . end ( ) ) {
for ( auto & i : it - > second ) {
return_value - > push ( instance_by_id ( i ) ) ;
}
}
}
2023-09-17 12:30:17 +02:00
}
2025-08-26 13:56:03 +02:00
# endif
2025-02-21 16:12:16 +01:00
} , storage_ ) ;
2024-08-23 20:29:07 +02:00
} ) ;
2021-11-30 13:25:02 +11:00
2023-09-17 12:30:17 +02:00
return return_value ;
2021-11-30 13:25:02 +11:00
}
2024-08-23 20:29:07 +02:00
size_t IfcFile : : getTotalInverses ( int instance_id ) {
size_t n = 0 ;
2025-02-21 16:12:16 +01:00
std : : visit ( [ & n , instance_id ] ( const auto & x ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , std : : monostate > ) {
} else if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : in_memory_file_storage > ) {
auto lower = x . byref_excl_ . lower_bound ( { instance_id , - 1 , - 1 } ) ;
auto upper = x . byref_excl_ . upper_bound ( { instance_id , std : : numeric_limits < short > : : max ( ) , std : : numeric_limits < short > : : max ( ) } ) ;
for ( auto it = lower ; it ! = upper ; + + it ) {
n + = it - > second . size ( ) ;
}
} else if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : rocks_db_file_storage > ) {
// @todo
}
} , storage_ ) ;
2024-08-23 20:29:07 +02:00
return n ;
2023-09-17 12:30:17 +02:00
}
2021-11-30 13:25:02 +11:00
2015-01-16 16:26:40 +00:00
void IfcFile : : setDefaultHeaderValues ( ) {
2024-08-23 20:29:07 +02:00
const std : : string empty_string ;
std : : vector < std : : string > file_description ;
std : : vector < std : : string > schema_identifiers ;
2024-09-02 14:38:23 +05:00
std : : vector < std : : string > string_vector = { " " } ;
2015-01-16 16:26:40 +00:00
2023-09-17 12:30:17 +02:00
file_description . push_back ( " ViewDefinition [CoordinationView] " ) ;
2023-10-24 14:16:26 +02:00
if ( schema ( ) ! = nullptr ) {
2023-09-17 12:30:17 +02:00
schema_identifiers . push_back ( schema ( ) - > name ( ) ) ;
}
2015-01-16 16:26:40 +00:00
2025-02-27 22:07:31 +01:00
header ( ) . file_description ( ) - > setdescription ( file_description ) ;
header ( ) . file_description ( ) - > setimplementation_level ( " 2;1 " ) ;
2015-01-16 16:26:40 +00:00
2025-02-27 22:07:31 +01:00
header ( ) . file_name ( ) - > setname ( empty_string ) ;
header ( ) . file_name ( ) - > settime_stamp ( createTimestamp ( ) ) ;
header ( ) . file_name ( ) - > setauthor ( string_vector ) ;
header ( ) . file_name ( ) - > setorganization ( string_vector ) ;
header ( ) . file_name ( ) - > setpreprocessor_version ( " IfcOpenShell " IFCOPENSHELL_VERSION ) ;
header ( ) . file_name ( ) - > setoriginating_system ( " IfcOpenShell " IFCOPENSHELL_VERSION ) ;
header ( ) . file_name ( ) - > setauthorisation ( empty_string ) ;
2015-01-16 16:26:40 +00:00
2025-02-27 22:07:31 +01:00
header ( ) . file_schema ( ) - > setschema_identifiers ( schema_identifiers ) ;
2015-01-16 16:26:40 +00:00
}
2017-12-13 18:05:10 +01:00
std : : pair < IfcUtil : : IfcBaseClass * , double > IfcFile : : getUnit ( const std : : string & unit_type ) {
2023-09-17 12:30:17 +02:00
std : : pair < IfcUtil : : IfcBaseClass * , double > return_value ( 0 , 1. ) ;
2021-09-24 09:03:58 +02:00
2023-09-17 12:30:17 +02:00
aggregate_of_instance : : ptr projects = instances_by_type ( schema ( ) - > declaration_by_name ( " IfcProject " ) ) ;
if ( ! projects | | projects - > size ( ) = = 0 ) {
try {
projects = instances_by_type ( schema ( ) - > declaration_by_name ( " IfcContext " ) ) ;
2024-08-23 20:29:07 +02:00
} catch ( IfcException & ) {
2023-09-17 12:30:17 +02:00
}
}
2017-12-13 18:05:10 +01:00
2023-09-17 12:30:17 +02:00
if ( projects & & projects - > size ( ) = = 1 ) {
IfcUtil : : IfcBaseClass * project = * projects - > begin ( ) ;
2025-02-27 22:07:31 +01:00
IfcUtil : : IfcBaseClass * unit_assignment = project - > get_attribute_value (
2023-09-17 12:30:17 +02:00
project - > declaration ( ) . as_entity ( ) - > attribute_index ( " UnitsInContext " ) ) ;
2025-02-27 22:07:31 +01:00
aggregate_of_instance : : ptr units = unit_assignment - > get_attribute_value (
2023-09-17 12:30:17 +02:00
unit_assignment - > declaration ( ) . as_entity ( ) - > attribute_index ( " Units " ) ) ;
for ( aggregate_of_instance : : it it = units - > begin ( ) ; it ! = units - > end ( ) ; + + it ) {
IfcUtil : : IfcBaseClass * unit = * it ;
if ( unit - > declaration ( ) . is ( " IfcNamedUnit " ) ) {
2025-02-27 22:07:31 +01:00
const std : : string file_unit_type = unit - > get_attribute_value (
2023-09-17 12:30:17 +02:00
unit - > declaration ( ) . as_entity ( ) - > attribute_index ( " UnitType " ) ) ;
if ( file_unit_type ! = unit_type ) {
continue ;
}
IfcUtil : : IfcBaseClass * siunit = 0 ;
if ( unit - > declaration ( ) . is ( " IfcConversionBasedUnit " ) ) {
2025-02-27 22:07:31 +01:00
IfcUtil : : IfcBaseClass * mu = unit - > get_attribute_value (
2023-09-17 12:30:17 +02:00
unit - > declaration ( ) . as_entity ( ) - > attribute_index ( " ConversionFactor " ) ) ;
2017-12-13 18:05:10 +01:00
2025-02-27 22:07:31 +01:00
IfcUtil : : IfcBaseClass * vlc = mu - > get_attribute_value (
2023-09-17 12:30:17 +02:00
mu - > declaration ( ) . as_entity ( ) - > attribute_index ( " ValueComponent " ) ) ;
2025-02-27 22:07:31 +01:00
IfcUtil : : IfcBaseClass * unc = mu - > get_attribute_value (
2023-09-17 12:30:17 +02:00
mu - > declaration ( ) . as_entity ( ) - > attribute_index ( " UnitComponent " ) ) ;
2025-02-27 22:07:31 +01:00
return_value . second * = static_cast < double > ( vlc - > get_attribute_value ( 0 ) ) ;
2023-09-17 12:30:17 +02:00
return_value . first = unit ;
if ( unc - > declaration ( ) . is ( " IfcSIUnit " ) ) {
siunit = unc ;
}
} else if ( unit - > declaration ( ) . is ( " IfcSIUnit " ) ) {
return_value . first = siunit = unit ;
}
2023-10-24 14:16:26 +02:00
if ( siunit ! = nullptr ) {
2025-02-27 22:07:31 +01:00
AttributeValue prefix = siunit - > get_attribute_value (
2023-09-17 12:30:17 +02:00
siunit - > declaration ( ) . as_entity ( ) - > attribute_index ( " Prefix " ) ) ;
2024-08-23 20:29:07 +02:00
if ( ! prefix . isNull ( ) ) {
return_value . second * = IfcSIPrefixToValue ( prefix ) ;
2023-09-17 12:30:17 +02:00
}
}
}
}
}
return return_value ;
2016-05-15 15:47:21 +02:00
}
2018-08-29 12:54:25 +02:00
void IfcParse : : IfcFile : : build_inverses_ ( IfcUtil : : IfcBaseClass * inst ) {
2023-09-17 12:30:17 +02:00
std : : function < void ( IfcUtil : : IfcBaseClass * , int ) > fn = [ this , inst ] ( IfcUtil : : IfcBaseClass * attr , int idx ) {
2023-10-24 14:16:26 +02:00
if ( attr - > declaration ( ) . as_entity ( ) ! = nullptr ) {
2024-08-23 20:29:07 +02:00
unsigned entity_attribute_id = attr - > id ( ) ;
2023-10-24 16:11:26 +02:00
const auto * decl = inst - > declaration ( ) . as_entity ( ) ;
2025-02-21 16:12:16 +01:00
std : : visit ( [ entity_attribute_id , decl , idx , inst ] ( auto & x ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , std : : monostate > ) {
} else if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : in_memory_file_storage > ) {
x . byref_excl_ [ { entity_attribute_id , decl - > index_in_schema ( ) , idx } ] . push_back ( inst - > id ( ) ) ;
} else if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , impl : : rocks_db_file_storage > ) {
// @todo
}
} , storage_ ) ;
2023-09-17 12:30:17 +02:00
}
} ;
2025-02-27 22:07:31 +01:00
apply_individual_instance_visitor ( inst ) . apply ( fn ) ;
2018-08-29 12:54:25 +02:00
}
void IfcParse : : IfcFile : : build_inverses ( ) {
2023-10-24 16:11:26 +02:00
for ( const auto & pair : * this ) {
2025-02-25 21:29:54 +01:00
build_inverses_ ( pair . second ) ;
2023-09-17 12:30:17 +02:00
}
2020-09-30 09:38:01 +02:00
}
2021-09-11 12:59:48 +02:00
2025-02-24 20:46:29 +01:00
void IfcParse : : IfcFile : : register_inverse ( unsigned id_from , const IfcParse : : entity * from_entity , int inst_id , int attribute_index )
{
std : : visit ( [ id_from , from_entity , inst_id , attribute_index ] ( auto & x ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , std : : monostate > ) {
throw std : : runtime_error ( " Storage not initialized " ) ;
} else {
return x . register_inverse ( id_from , from_entity , inst_id , attribute_index ) ;
}
} , storage_ ) ;
}
void IfcParse : : IfcFile : : unregister_inverse ( unsigned id_from , const IfcParse : : entity * from_entity , IfcUtil : : IfcBaseClass * inst , int attribute_index )
{
std : : visit ( [ id_from , from_entity , inst , attribute_index ] ( auto & x ) {
if constexpr ( std : : is_same_v < std : : decay_t < decltype ( x ) > , std : : monostate > ) {
throw std : : runtime_error ( " Storage not initialized " ) ;
} else {
return x . unregister_inverse ( id_from , from_entity , inst , attribute_index ) ;
}
} , storage_ ) ;
}
2021-09-13 13:17:08 +02:00
std : : atomic_uint32_t IfcUtil : : IfcBaseClass : : counter_ ( 0 ) ;
2025-02-21 16:12:16 +01:00
// bool IfcParse::IfcFile::guid_map_ = true;
2024-05-12 16:57:34 +02:00
2024-08-23 20:29:07 +02:00
void IfcUtil : : IfcBaseClass : : unset_attribute_value ( size_t index ) {
2025-02-27 22:07:31 +01:00
void * storage = file_ ? std : : visit ( [ ] ( const auto & m ) { return ( void * ) & m ; } , file_ - > storage_ ) : nullptr ;
2025-03-09 21:20:16 +01:00
data_ . set_attribute_value ( storage , & declaration ( ) , id ( ) ? id ( ) : identity ( ) , index , Blank { } ) ;
2025-02-21 16:12:16 +01:00
}
AttributeValue IfcUtil : : IfcBaseClass : : get_attribute_value ( size_t index ) const {
2025-02-27 22:07:31 +01:00
void * storage = file_ ? std : : visit ( [ ] ( const auto & m ) { return ( void * ) & m ; } , file_ - > storage_ ) : nullptr ;
2025-03-09 21:20:16 +01:00
return data_ . get_attribute_value ( storage , & declaration ( ) , id ( ) ? id ( ) : identity ( ) , index ) ;
2024-08-23 20:29:07 +02:00
}
void IfcUtil : : IfcBaseClass : : toString ( std : : ostream & out , bool upper ) const
{
const auto * ent = declaration ( ) . as_entity ( ) ;
if ( ent ! = nullptr ) {
out < < " # " < < as < IfcUtil : : IfcBaseEntity > ( ) - > id ( ) < < " = " ;
}
if ( upper ) {
out < < declaration ( ) . name_uc ( ) ;
} else {
out < < declaration ( ) . name ( ) ;
}
2025-02-27 22:07:31 +01:00
void * storage = file_ ? std : : visit ( [ ] ( const auto & m ) { return ( void * ) & m ; } , file_ - > storage_ ) : nullptr ;
2025-03-09 21:20:16 +01:00
data ( ) . toString ( storage , & declaration ( ) , id ( ) ? id ( ) : identity ( ) , out , upper ) ;
2024-08-23 20:29:07 +02:00
}
2025-02-27 22:07:31 +01:00
/*
2024-08-23 20:29:07 +02:00
IfcEntityInstanceData::IfcEntityInstanceData(const IfcEntityInstanceData& data)
2025-02-21 16:12:16 +01:00
: storage_(data.size())
2024-08-23 20:29:07 +02:00
{
2025-02-27 22:07:31 +01:00
2024-08-23 20:29:07 +02:00
}
2025-02-27 22:07:31 +01:00
*/
2024-08-23 20:29:07 +02:00
2025-02-27 22:07:31 +01:00
AttributeValue IfcEntityInstanceData : : get_attribute_value ( void * storage , const IfcParse : : declaration * decl , std : : size_t identity , size_t index ) const
2024-08-23 20:29:07 +02:00
{
2025-03-18 10:41:03 +01:00
if ( storage_ ) {
return AttributeValue ( storage_ , ( uint8_t ) index ) ;
} else {
return AttributeValue ( ( IfcParse : : impl : : rocks_db_file_storage * ) storage , identity , decl - > as_entity ( ) ? 1 : 0 , index ) ;
}
2024-08-23 20:29:07 +02:00
}
2025-02-27 22:07:31 +01:00
bool IfcParse : : impl : : rocks_db_file_storage : : read_schema ( const IfcParse : : schema_definition * & schema ) {
2025-08-26 13:56:03 +02:00
# ifdef WITH_ROCKSDB
2025-02-27 22:07:31 +01:00
std : : string value ;
auto key = " h|file_schema|0 " ;
db - > Get ( rocksdb : : ReadOptions { } , key , & value ) ;
std : : vector < std : : string > strings ;
if ( : : impl : : deserialize ( this , value , strings ) & & strings . size ( ) = = 1 ) {
schema = schema_by_name ( strings [ 0 ] ) ;
return true ;
}
2025-08-26 13:56:03 +02:00
# endif
2025-02-27 22:07:31 +01:00
return false ;
}
2025-03-09 21:20:16 +01:00
IfcUtil : : IfcBaseClass : : IfcBaseClass ( IfcEntityInstanceData & & data )
: identity_ ( counter_ + + )
, id_ ( 0 )
, file_ ( nullptr )
, data_ ( std : : move ( data ) )
{
/*
* @todo this is not allowed cannot call virtual func in constructor
if (!declaration().as_entity()) {
// @nb from v0.9 type decl instances have their own id, which may collide with instance names in the file
// but is otherwise unique
id_ = identity_;
}
*/
}
2025-02-27 22:07:31 +01:00
2025-08-26 10:19:47 +02:00
void IfcUtil : : IfcBaseClass : : set_attribute_value ( size_t i , IfcUtil : : IfcBaseClass * p ) {
set_attribute_value < IfcUtil : : IfcBaseClass * > ( i , p ) ;
}
void IfcUtil : : IfcBaseClass : : set_attribute_value ( const std : : string & name , IfcUtil : : IfcBaseClass * p ) {
set_attribute_value < IfcUtil : : IfcBaseClass * > ( name , p ) ;
}
2024-08-23 20:29:07 +02:00
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < Blank > ( size_t index , const Blank & value ) ;
2025-02-27 22:07:31 +01:00
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < Derived > ( size_t index , const Derived & value ) ;
2024-08-23 20:29:07 +02:00
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < int > ( size_t index , const int & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < bool > ( size_t index , const bool & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < boost : : logic : : tribool > ( size_t index , const boost : : logic : : tribool & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < double > ( size_t index , const double & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < std : : string > ( size_t index , const std : : string & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < boost : : dynamic_bitset < > > ( size_t index , const boost : : dynamic_bitset < > & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < EnumerationReference > ( size_t index , const EnumerationReference & value ) ;
2025-08-26 10:19:47 +02:00
// template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value<IfcUtil::IfcBaseClass*>(size_t index, IfcUtil::IfcBaseClass* const& value);
2024-08-23 20:29:07 +02:00
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < std : : vector < int > > ( size_t index , const std : : vector < int > & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < std : : vector < double > > ( size_t index , const std : : vector < double > & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < std : : vector < std : : string > > ( size_t index , const std : : vector < std : : string > & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < std : : vector < boost : : dynamic_bitset < > > > ( size_t index , const std : : vector < boost : : dynamic_bitset < > > & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < aggregate_of_instance : : ptr > ( size_t index , const aggregate_of_instance : : ptr & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < std : : vector < std : : vector < int > > > ( size_t index , const std : : vector < std : : vector < int > > & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < std : : vector < std : : vector < double > > > ( size_t index , const std : : vector < std : : vector < double > > & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < aggregate_of_aggregate_of_instance : : ptr > ( size_t index , const aggregate_of_aggregate_of_instance : : ptr & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < Blank > ( const std : : string & name , const Blank & value ) ;
2025-02-27 22:07:31 +01:00
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < Derived > ( const std : : string & name , const Derived & value ) ;
2024-08-23 20:29:07 +02:00
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < int > ( const std : : string & name , const int & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < bool > ( const std : : string & name , const bool & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < boost : : logic : : tribool > ( const std : : string & name , const boost : : logic : : tribool & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < double > ( const std : : string & name , const double & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < std : : string > ( const std : : string & name , const std : : string & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < boost : : dynamic_bitset < > > ( const std : : string & name , const boost : : dynamic_bitset < > & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < EnumerationReference > ( const std : : string & name , const EnumerationReference & value ) ;
2025-08-26 10:19:47 +02:00
// template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value<IfcUtil::IfcBaseClass*>(const std::string& name, IfcUtil::IfcBaseClass* const& value);
2024-08-23 20:29:07 +02:00
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < std : : vector < int > > ( const std : : string & name , const std : : vector < int > & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < std : : vector < double > > ( const std : : string & name , const std : : vector < double > & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < std : : vector < std : : string > > ( const std : : string & name , const std : : vector < std : : string > & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < std : : vector < boost : : dynamic_bitset < > > > ( const std : : string & name , const std : : vector < boost : : dynamic_bitset < > > & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < aggregate_of_instance : : ptr > ( const std : : string & name , const aggregate_of_instance : : ptr & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < std : : vector < std : : vector < int > > > ( const std : : string & name , const std : : vector < std : : vector < int > > & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < std : : vector < std : : vector < double > > > ( const std : : string & name , const std : : vector < std : : vector < double > > & value ) ;
template void IFC_PARSE_API IfcUtil : : IfcBaseClass : : set_attribute_value < aggregate_of_aggregate_of_instance : : ptr > ( const std : : string & name , const aggregate_of_aggregate_of_instance : : ptr & value ) ;