Option to bypass storing types when opening model

This commit is contained in:
Thomas Krijnen
2025-10-24 12:06:59 +02:00
parent a6d20c0cc4
commit 0494bd9677
8 changed files with 174 additions and 33 deletions
+20
View File
@@ -651,6 +651,17 @@ IfcParse::filetype IfcParse::guess_file_type(const std::string& fn) {
}
}
void IfcParse::InstanceStreamer::bypassTypes(const std::set<std::string>& type_names) {
for (auto& name : type_names) {
try {
types_to_bypass_.push_back(schema_->declaration_by_name(name));
} catch (const IfcException&) {
continue;
}
}
}
std::optional<std::tuple<size_t, const IfcParse::declaration*, IfcEntityInstanceData>> IfcParse::InstanceStreamer::readInstance() {
std::optional<std::tuple<size_t, const IfcParse::declaration*, IfcEntityInstanceData>> return_value;
@@ -698,6 +709,15 @@ std::optional<std::tuple<size_t, const IfcParse::declaration*, IfcEntityInstance
goto advance;
}
for (auto& ty : types_to_bypass_) {
if (entity_type->is(*ty)) {
bypassed_instances_.push_back(current_id);
// Why is this a conditional clause in the loop?
current_id = 0;
goto advance;
}
}
parse_context ps;
lexer_->Next();
try {
+31 -2
View File
@@ -98,8 +98,10 @@ private:
int progress_;
IfcParse::unresolved_references references_to_resolve_;
int yielded_header_instances_ = 0;
std::vector<const declaration*> types_to_bypass_;
std::vector<unsigned> bypassed_instances_;
public:
public:
bool coerce_attribute_count = true;
operator bool() const {
@@ -118,6 +120,11 @@ public:
return references_to_resolve_;
}
const std::vector<unsigned>& bypassed_instances() {
std::sort(bypassed_instances_.begin(), bypassed_instances_.end());
return bypassed_instances_;
}
const IfcParse::impl::in_memory_file_storage::entities_by_ref_t& inverses() const {
return storage_.byref_excl_;
}
@@ -142,6 +149,8 @@ public:
InstanceStreamer(const IfcParse::schema_definition* schema, IfcParse::IfcSpfLexer* lexer);
void bypassTypes(const std::set<std::string>& type_names);
~InstanceStreamer() {
delete stream_;
if (stream_) {
@@ -153,6 +162,9 @@ public:
std::optional<std::tuple<size_t, const IfcParse::declaration*, IfcEntityInstanceData>> readInstance();
};
class uninitialized_tag {};
/// This class provides access to the entity instances in an IFC file
/// The file takes ownership of instances added to this file and deletes them when the file is deleted.
class IFC_PARSE_API IfcFile {
@@ -179,7 +191,10 @@ public:
// @todo temporarily public for header
storage_t storage_;
private:
std::set<std::string> types_to_bypass_loading_;
private:
file_open_status good_ = file_open_status::SUCCESS;
const IfcParse::schema_definition* schema_;
@@ -246,6 +261,20 @@ private:
/// <param name="path">The file system path to the IFC file. Defaults to an empty string.</param>
IfcFile(const IfcParse::schema_definition* schema = IfcParse::schema_by_name("IFC4"), filetype ty = FT_AUTODETECT, const std::string& path = "");
/// <summary>
/// Constructs an unitialized IfcFile object. Call initialize() later on. Allows to specify which types to bypass during load.
/// </summary>
IfcFile(const uninitialized_tag&);
bool initialize(const std::string& path, filetype ty = FT_AUTODETECT, bool readonly = false);
#ifdef USE_MMAP
bool initialize(const std::string& path, bool mmap);
#endif
/// @brief Bypass loading of all instances of the specified type name. Only applies to parsed IFC-SPF files.
/// @param type_name case insensitive name of the type to bypass
void bypass_type(const std::string& type_name);
~IfcFile();
IfcParse::file_open_status good() const { return good_; }
+44 -17
View File
@@ -1178,15 +1178,19 @@ IfcUtil::IfcBaseClass::set_attribute_value(const std::string& s, const T& t) {
//
#ifdef USE_MMAP
IfcFile::IfcFile(const std::string& fn, bool mmap) {
std::unique_ptr<FileReader> s;
initialize(fn, mmap);
}
bool IfcParse::IfcFile::initialize(const std::string& fn, bool mmap) {
std::unique_ptr<FileReader> s;
if (mmap) {
s = std::make_unique<FileReader>(fn, FileReader::mmap_tag{});
} else {
s = std::make_unique<FileReader>(fn);
}
}
storage_.emplace<1>(this);
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&*s, schema_, max_id_);
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&*s, schema_, max_id_, types_to_bypass_loading_);
if ((good_ = std::get<impl::in_memory_file_storage>(storage_).good_)) {
// @todo unify these names, it's already confusing enough as it stands
@@ -1199,25 +1203,23 @@ IfcFile::IfcFile(const std::string& fn, bool mmap) {
}
#endif
IfcFile::IfcFile(const std::string& path, filetype ty, bool readonly)
: schema_(nullptr)
, max_id_(0)
, _header(this)
{
// @todo allow for rocksdb from path
IfcFile::IfcFile(const uninitialized_tag&)
: schema_(nullptr), max_id_(0), _header(this), good_(file_open_status::UNKNOWN), ifcroot_type_(nullptr) {}
bool IfcParse::IfcFile::initialize(const std::string& path, filetype ty, bool readonly) {
if (ty == FT_AUTODETECT) {
ty = guess_file_type(path);
}
if (ty == FT_IFCSPF) {
FileReader s(path);
storage_.emplace<1>(this);
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_);
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_, types_to_bypass_loading_);
if ((good_ = std::get<impl::in_memory_file_storage>(storage_).good_)) {
// @todo unify these names, it's already confusing enough as it stands
byid_ = decltype(byid_)(&std::get<impl::in_memory_file_storage>(storage_).byid_);
byref_excl_ = decltype(byref_excl_)(&std::get<impl::in_memory_file_storage>(storage_).byref_excl_);
byguid_ = decltype(byguid_)(&std::get<impl::in_memory_file_storage>(storage_).byguid_);
byguid_ = decltype(byguid_)(&std::get<impl::in_memory_file_storage>(storage_).byguid_);
}
// byidentity_ = decltype(byidentity_)(&std::get<impl::in_memory_file_storage>(storage_).byidentity_);
} else if (ty == FT_ROCKSDB) {
@@ -1246,6 +1248,19 @@ IfcFile::IfcFile(const std::string& path, filetype ty, bool readonly)
// throw std::runtime_error("Unsupported file format");
}
ifcroot_type_ = schema_ ? schema_->declaration_by_name("IfcRoot") : nullptr;
return good_ == file_open_status::SUCCESS;
}
void IfcParse::IfcFile::bypass_type(const std::string& type_name) {
types_to_bypass_loading_.insert(type_name);
}
IfcFile::IfcFile(const std::string& path, filetype ty, bool readonly)
: schema_(nullptr)
, max_id_(0)
, _header(this)
{
initialize(path, ty, readonly);
}
IfcFile::IfcFile(std::istream& stream, int length)
@@ -1260,7 +1275,7 @@ IfcFile::IfcFile(std::istream& stream, int length)
s.pushNextPage(string_data);
storage_.emplace<1>(this);
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_);
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_, types_to_bypass_loading_);
good_ = std::get<impl::in_memory_file_storage>(storage_).good_;
ifcroot_type_ = schema_ ? schema_->declaration_by_name("IfcRoot") : nullptr;
@@ -1276,7 +1291,7 @@ IfcFile::IfcFile(void* data, int length)
FileReader s(std::string((char*)data, length), FileReader::caller_fed_tag{});
storage_.emplace<1>(this);
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_);
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_, types_to_bypass_loading_);
good_ = std::get<impl::in_memory_file_storage>(storage_).good_;
ifcroot_type_ = schema_ ? schema_->declaration_by_name("IfcRoot") : nullptr;
@@ -1290,7 +1305,7 @@ IfcFile::IfcFile(IfcParse::FileReader* s)
, max_id_(0)
{
storage_.emplace<1>(this);
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(s, schema_, max_id_);
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(s, schema_, max_id_, types_to_bypass_loading_);
good_ = std::get<impl::in_memory_file_storage>(storage_).good_;
ifcroot_type_ = schema_ ? schema_->declaration_by_name("IfcRoot") : nullptr;
@@ -1330,8 +1345,7 @@ IfcFile::IfcFile(const IfcParse::schema_definition* schema, filetype ty, const s
setDefaultHeaderValues();
}
bool IfcParse::InstanceStreamer::hasSemicolon() const
{
bool IfcParse::InstanceStreamer::hasSemicolon() const {
auto local_stream = stream_->clone();
auto local_lexer = IfcSpfLexer(&local_stream);
Token t;
@@ -1452,7 +1466,7 @@ IfcParse::InstanceStreamer::InstanceStreamer(const IfcParse::schema_definition*
storage_.references_to_resolve = &references_to_resolve_;
}
void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::FileReader* s, const IfcParse::schema_definition*& schema, unsigned int& max_id) {
void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::FileReader* s, const IfcParse::schema_definition*& schema, unsigned int& max_id, const std::set<std::string>& typed_to_bypass) {
// Initialize a "C" locale for locale-independent
// number parsing. See comment above on line 41.
init_locale();
@@ -1499,6 +1513,7 @@ void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::FileRead
auto ifcroot_type_ = schema->declaration_by_name("IfcRoot");
InstanceStreamer streamer(schema, tokens);
streamer.bypassTypes(typed_to_bypass);
Logger::Status("Scanning file...");
@@ -1510,6 +1525,7 @@ void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::FileRead
// No more instances to read
break;
}
auto current_id = std::get<0>(*inst);
auto instance = schema->instantiate(std::get<1>(*inst), std::move(std::get<2>(*inst)));
@@ -1569,11 +1585,16 @@ void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::FileRead
return;
}
const auto& bypassed = streamer.bypassed_instances();
for (const auto& p : streamer.references()) {
const auto& ref = p.first.name_;
const auto& refattr = p.first.index_;
if (auto* v = std::get_if<reference_or_simple_type>(&p.second)) {
if (auto* name = std::get_if<InstanceReference>(v)) {
if (std::binary_search(bypassed.begin(), bypassed.end(), *name)) {
continue;
}
auto it = byid_.find(*name);
if (it == byid_.end()) {
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));
@@ -1604,6 +1625,9 @@ void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::FileRead
instances->reserve(vv->size());
for (const auto& vi : *vv) {
if (auto* name = std::get_if<InstanceReference>(&vi)) {
if (std::binary_search(bypassed.begin(), bypassed.end(), *name)) {
continue;
}
auto it = byid_.find(*name);
if (it == byid_.end()) {
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));
@@ -1638,6 +1662,9 @@ void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::FileRead
std::vector<IfcUtil::IfcBaseClass*> inner;
for (const auto& vii : vi) {
if (auto* name = std::get_if<InstanceReference>(&vii)) {
if (std::binary_search(bypassed.begin(), bypassed.end(), *name)) {
continue;
}
auto it = byid_.find(*name);
if (it == byid_.end()) {
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));
+1 -1
View File
@@ -268,7 +268,7 @@ namespace IfcParse {
// @todo is this still used
IfcEntityInstanceData read(unsigned int index);
void read_from_stream(IfcParse::FileReader* stream, const IfcParse::schema_definition*& schema, unsigned int& max_id);
void read_from_stream(IfcParse::FileReader* stream, const IfcParse::schema_definition*& schema, unsigned int& max_id, const std::set<std::string>& typed_to_bypass);
file_open_status good_ = file_open_status::SUCCESS;