#1376 remove_deep_batched()

This commit is contained in:
Thomas Krijnen
2021-03-13 12:16:40 +01:00
parent 624e296d24
commit 5961253c29
4 changed files with 226 additions and 153 deletions
@@ -179,6 +179,14 @@ class file(object):
:rtype: None
"""
return self.wrapped_data.remove(inst.wrapped_data)
def batch(self):
"""Low-level mechanism to speed up deletion of large subgraphs"""
return self.wrapped_data.batch()
def unbatch(self):
"""Low-level mechanism to speed up deletion of large subgraphs"""
return self.wrapped_data.unbatch()
def __iter__(self):
return iter(self[id] for id in self.wrapped_data.entity_names())
@@ -126,6 +126,13 @@ def remove_deep(ifc_file, element):
ifc_file.remove(ref)
def remove_deep_batched(ifc_file, element):
# @todo maybe some sort of try-finally mechanism.
ifc_file.batch()
remove_deep(ifc_file, element)
ifc_file.unbatch()
def get_representation(element, context, subcontext=None, target_view=None):
if element.is_a("IfcProduct") and element.Representation:
for r in element.Representation.Representations:
+8
View File
@@ -131,6 +131,11 @@ private:
void initialize_(IfcParse::IfcSpfStream* f);
void build_inverses_(IfcUtil::IfcBaseClass*);
std::set<int> batch_deletion_ids_;
bool batch_mode_ = false;
void process_deletion_();
public:
IfcParse::IfcSpfLexer* tokens;
IfcParse::IfcSpfStream* stream;
@@ -226,6 +231,9 @@ public:
IfcUtil::IfcBaseClass* addEntity(IfcUtil::IfcBaseClass* entity);
void addEntities(IfcEntityList::ptr es);
void batch() { batch_mode_ = true; }
void unbatch() { process_deletion_(); batch_mode_ = false; }
/// Removes entity instance from file and unsets references.
///
/// Attention when running removeEntity inside a loop over a list of entities to be removed.
+203 -153
View File
@@ -1710,73 +1710,76 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) {
}
}
// The mapping by entity type is updated.
const IfcParse::declaration* ty = &new_entity->declaration();
// The mapping by entity type is updated.
const IfcParse::declaration* ty = &new_entity->declaration();
if (ty->as_entity()) {
IfcEntityList::ptr insts = instances_by_type_excl_subtypes(ty);
if (!insts) {
insts = IfcEntityList::ptr(new IfcEntityList());
bytype_excl[ty] = insts;
}
insts->push(new_entity);
if (ty->as_entity()) {
IfcEntityList::ptr insts = instances_by_type_excl_subtypes(ty);
if (!insts) {
insts = IfcEntityList::ptr(new IfcEntityList());
bytype_excl[ty] = insts;
}
insts->push(new_entity);
}
for (; ty->as_entity();) {
IfcEntityList::ptr insts = instances_by_type(ty);
if (!insts) {
insts = IfcEntityList::ptr(new IfcEntityList());
bytype[ty] = insts;
}
insts->push(new_entity);
const IfcParse::declaration* pt = ty->as_entity()->supertype();
if (pt) {
ty = pt;
}
else {
break;
}
}
if (ty->as_entity()) {
int new_id = -1;
if (!new_entity->data().file) {
// For newly created entities ensure a valid ENTITY_INSTANCE_NAME is set
new_entity->data().file = this;
new_id = new_entity->data().set_id();
}
else {
new_id = new_entity->data().id();
}
for (; ty->as_entity();) {
IfcEntityList::ptr insts = instances_by_type(ty);
if (!insts) {
insts = IfcEntityList::ptr(new IfcEntityList());
bytype[ty] = insts;
}
insts->push(new_entity);
const IfcParse::declaration* pt = ty->as_entity()->supertype();
if (pt) {
ty = pt;
} else {
break;
}
if (byid.find(new_id) != byid.end()) {
// This should not happen
std::stringstream ss;
ss << "Overwriting entity with id " << new_id;
Logger::Message(Logger::LOG_WARNING, ss.str());
}
if (ty->as_entity()) {
int new_id = -1;
if (!new_entity->data().file) {
// For newly created entities ensure a valid ENTITY_INSTANCE_NAME is set
new_entity->data().file = this;
new_id = new_entity->data().set_id();
} else {
new_id = new_entity->data().id();
}
// The mapping by entity instance name is updated.
byid[new_id] = new_entity;
}
if (byid.find(new_id) != byid.end()) {
// This should not happen
std::stringstream ss;
ss << "Overwriting entity with id " << new_id;
Logger::Message(Logger::LOG_WARNING, ss.str());
}
if (parsing_complete_ && ty->as_entity()) {
build_inverses_(new_entity);
}
// The mapping by entity instance name is updated.
byid[new_id] = new_entity;
}
if (parsing_complete_ && ty->as_entity()) {
build_inverses_(new_entity);
}
return new_entity;
return new_entity;
}
void IfcFile::removeEntity(IfcUtil::IfcBaseClass* entity) {
const unsigned id = entity->data().id();
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<IfcEntityList> entities = ...;
// for (auto it = entities->end() - 1; it >= entities->begin(); --it) {
// IfcUtil::IfcBaseClass *const inst = *it;
// model->removeEntity(inst);
// }
// 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
@@ -1789,133 +1792,180 @@ void IfcFile::removeEntity(IfcUtil::IfcBaseClass* entity) {
throw IfcParse::IfcException("Instance not part of this file");
}
IfcEntityList::ptr references = instances_by_reference(id);
batch_deletion_ids_.insert(id);
// 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 (IfcEntityList::it iit = references->begin(); iit != references->end(); ++iit) {
IfcUtil::IfcBaseEntity* related_instance = (IfcUtil::IfcBaseEntity*) *iit;
if (!batch_mode_) {
process_deletion_();
}
}
void IfcFile::process_deletion_() {
for (unsigned i = 0; i < related_instance->data().getArgumentCount(); ++i) {
Argument* attr = related_instance->data().getArgument(i);
if (attr->isNull()) continue;
for (auto& id : batch_deletion_ids_) {
auto entity = instance_by_id(id);
IfcUtil::ArgumentType attr_type = attr->type();
switch(attr_type) {
case IfcUtil::Argument_ENTITY_INSTANCE: {
IfcUtil::IfcBaseClass* instance_attribute = *attr;
if (instance_attribute == entity) {
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
copy->set(boost::blank());
related_instance->data().setArgument(i, copy);
} }
break;
case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: {
IfcEntityList::ptr instance_list = *attr;
if (instance_list->contains(entity)) {
instance_list->remove(entity);
IfcEntityList::ptr references = instances_by_reference(id);
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
copy->set(instance_list);
related_instance->data().setArgument(i, copy);
} }
break;
case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE: {
IfcEntityListList::ptr instance_list_list = *attr;
if (instance_list_list->contains(entity)) {
IfcEntityListList::ptr new_list(new IfcEntityListList);
for (IfcEntityListList::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);
// 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 (IfcEntityList::it iit = references->begin(); iit != references->end(); ++iit) {
IfcUtil::IfcBaseEntity* related_instance = (IfcUtil::IfcBaseEntity*) *iit;
if (std::find(batch_deletion_ids_.begin(), batch_deletion_ids_.end(), related_instance->data().id()) != batch_deletion_ids_.end()) {
continue;
}
for (unsigned i = 0; i < related_instance->data().getArgumentCount(); ++i) {
Argument* attr = related_instance->data().getArgument(i);
if (attr->isNull()) continue;
IfcUtil::ArgumentType attr_type = attr->type();
switch (attr_type) {
case IfcUtil::Argument_ENTITY_INSTANCE: {
IfcUtil::IfcBaseClass* instance_attribute = *attr;
if (instance_attribute == entity) {
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
copy->set(boost::blank());
related_instance->data().setArgument(i, copy);
} }
break;
case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: {
IfcEntityList::ptr instance_list = *attr;
if (instance_list->contains(entity)) {
instance_list->remove(entity);
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
copy->set(instance_list);
related_instance->data().setArgument(i, copy);
} }
break;
case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE: {
IfcEntityListList::ptr instance_list_list = *attr;
if (instance_list_list->contains(entity)) {
IfcEntityListList::ptr new_list(new IfcEntityListList);
for (IfcEntityListList::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);
}
new_list->push(instances);
}
new_list->push(instances);
}
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
copy->set(new_list);
related_instance->data().setArgument(i, copy);
} }
break;
default: break;
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
copy->set(new_list);
related_instance->data().setArgument(i, copy);
} }
break;
default: break;
}
}
}
}
byref.erase(byref.find(id));
}
IfcEntityList::ptr entity_attributes = traverse(entity, 1);
for (IfcEntityList::it it = entity_attributes->begin(); it != entity_attributes->end(); ++it) {
IfcUtil::IfcBaseClass* entity_attribute = *it;
if (entity_attribute == entity) continue;
const unsigned int name = entity_attribute->data().id();
// Do not update inverses for simple types (which have id()==0 in IfcOpenShell).
if (name != 0) {
entities_by_ref_t::iterator byref_it = byref.find(name);
if (byref_it != byref.end()) {
std::vector<unsigned>& ids = byref_it->second;
ids.erase(std::remove(ids.begin(), ids.end(), id), ids.end());
if (!batch_mode_) {
byref.erase(id);
// 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
IfcEntityList::ptr entity_attributes = traverse(entity, 1);
for (IfcEntityList::it it = entity_attributes->begin(); it != entity_attributes->end(); ++it) {
IfcUtil::IfcBaseClass* entity_attribute = *it;
if (entity_attribute == entity) continue;
const unsigned int name = entity_attribute->data().id();
// Do not update inverses for simple types (which have id()==0 in IfcOpenShell).
if (name != 0) {
entities_by_ref_t::iterator byref_it = byref.find(name);
if (byref_it != byref.end()) {
std::vector<unsigned>& ids = byref_it->second;
ids.erase(std::remove(ids.begin(), ids.end(), id), ids.end());
}
by_ref_cached_.erase(name);
}
}
by_ref_cached_.erase(name);
}
}
if (entity->declaration().is(*ifcroot_type_)) {
const std::string global_id = *entity->data().getArgument(0);
auto it = byguid.find(global_id);
if (it != byguid.end()) {
byguid.erase(it);
} else {
Logger::Warning("GlobalId on rooted instance not encountered in map");
if (entity->declaration().is(*ifcroot_type_)) {
const std::string global_id = *entity->data().getArgument(0);
auto it = byguid.find(global_id);
if (it != byguid.end()) {
byguid.erase(it);
}
else {
Logger::Warning("GlobalId on rooted instance not encountered in map");
}
}
}
byid.erase(byid.find(id));
const IfcParse::declaration* ty = &entity->declaration();
byid.erase(byid.find(id));
{
IfcEntityList::ptr instances_of_same_type = instances_by_type_excl_subtypes(ty);
instances_of_same_type->remove(entity);
if (instances_of_same_type->size() == 0) {
bytype_excl.erase(ty);
}
}
const IfcParse::declaration* ty = &entity->declaration();
for (;;) {
IfcEntityList::ptr instances_of_same_type = instances_by_type(ty);
if (instances_of_same_type) {
{
IfcEntityList::ptr instances_of_same_type = instances_by_type_excl_subtypes(ty);
instances_of_same_type->remove(entity);
}
if (instances_of_same_type->size() == 0) {
bytype.erase(ty);
if (instances_of_same_type->size() == 0) {
bytype_excl.erase(ty);
}
}
const IfcParse::declaration* pt = ty->as_entity()->supertype();
if (pt) {
ty = pt;
} else {
break;
}
}
for (;;) {
IfcEntityList::ptr instances_of_same_type = instances_by_type(ty);
if (instances_of_same_type) {
instances_of_same_type->remove(entity);
}
if (instances_of_same_type->size() == 0) {
bytype.erase(ty);
}
// This entity_file_map remains obviously flawed, but until we have proper lookup by value, or another mechanism,
// to prevent duplicate definitions with usage of add() we have to keep it. This might be a good moment to clear it.
for (auto it = entity_file_map.begin(); it != entity_file_map.end();) {
if (it->second == entity) {
it = entity_file_map.erase(it);
} else {
++it;
const IfcParse::declaration* pt = ty->as_entity()->supertype();
if (pt) {
ty = pt;
}
else {
break;
}
}
// This entity_file_map remains obviously flawed, but until we have proper lookup by value, or another mechanism,
// to prevent duplicate definitions with usage of add() we have to keep it. This might be a good moment to clear it.
for (auto it = entity_file_map.begin(); it != entity_file_map.end();) {
if (it->second == entity) {
it = entity_file_map.erase(it);
}
else {
++it;
}
}
delete entity;
}
delete entity;
if (batch_mode_) {
for (auto it = byref.begin(); it != byref.end();) {
bool do_delete = batch_deletion_ids_.find(it->first) != batch_deletion_ids_.end();
if (!do_delete) {
it->second.erase(std::remove_if(it->second.begin(), it->second.end(), [this](int x) {
return batch_deletion_ids_.find(x) != batch_deletion_ids_.end();
}), it->second.end());
do_delete = it->second.empty();
}
if (do_delete) {
it = byref.erase(it);
}
else {
++it;
}
}
}
by_ref_cached_.clear();
batch_deletion_ids_.clear();
}
IfcEntityList::ptr IfcFile::instances_by_type(const IfcParse::declaration* t) {