diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 910d17ad18..8847d803e2 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -122,6 +122,7 @@ bool rename_file(const std::string& old_filename, const std::string& new_filenam static std::stringstream log_stream; void write_log(bool); void fix_quantities(IfcParse::IfcFile&, bool, bool, bool); +std::string format_duration(time_t start, time_t end); /// @todo make the filters non-global IfcGeom::entity_filter entity_filter; // Entity filter is used always by default. @@ -475,10 +476,14 @@ int main(int argc, char** argv) int exit_code = EXIT_FAILURE; try { if (init_input_file(input_filename, ifc_file, no_progress || quiet, mmap)) { + time_t start, end; + time(&start); XmlSerializer s(ifc_file, output_temp_filename); Logger::Status("Writing XML output..."); s.finalize(); - Logger::Status("Done!"); + time(&end); + Logger::Status("Done! Conversion took " + format_duration(start, end)); + rename_file(output_temp_filename, output_filename); exit_code = EXIT_SUCCESS; } @@ -786,28 +791,33 @@ int main(int argc, char** argv) time(&end); - if (!quiet) { - int seconds = (int)difftime(end, start); - std::stringstream msg; - int minutes = seconds / 60; - seconds = seconds % 60; - msg << "\nConversion took"; - if (minutes > 0) { - msg << " " << minutes << " minute"; - if (minutes > 1) { - msg << "s"; - } - } - msg << " " << seconds << " second"; - if (seconds > 1) { - msg << "s"; - } - Logger::Status(msg.str()); - } + if (!quiet) { + Logger::Status("\nConversion took " + format_duration(start, end)); + } return successful ? EXIT_SUCCESS : EXIT_FAILURE; } +std::string format_duration(time_t start, time_t end) +{ + int seconds = (int)difftime(end, start); + std::stringstream ss; + int minutes = seconds / 60; + seconds = seconds % 60; + if (minutes > 0) { + ss << minutes << " minute"; + if (minutes == 0 || minutes > 1) { + ss << "s"; + } + ss << " "; + } + ss << seconds << " second"; + if (seconds == 0 || seconds > 1) { + ss << "s"; + } + return ss.str(); +} + void write_log(bool header) { std::string log = log_stream.str(); if (!log.empty()) { @@ -821,10 +831,12 @@ void write_log(bool header) { #include bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, bool no_progress, bool mmap) { + time_t start, end; // Prevent IfcFile::Init() prints by setting output to null temporarily if (no_progress) { Logger::SetOutput(NULL, &log_stream); } + time(&start); #ifdef USE_MMAP ifc_file = new IfcParse::IfcFile(filename, mmap); #else @@ -841,8 +853,10 @@ bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, Logger::Error("Unable to parse input file '" + filename + "'"); return false; } + time(&end); if (no_progress) { Logger::SetOutput(&std::cout, &log_stream); } + else { Logger::Status("Parsing input file took " + format_duration(start, end)); } return true; diff --git a/src/ifcgeom_schema_agnostic/Kernel.cpp b/src/ifcgeom_schema_agnostic/Kernel.cpp index ecd738a048..e6def6a42a 100644 --- a/src/ifcgeom_schema_agnostic/Kernel.cpp +++ b/src/ifcgeom_schema_agnostic/Kernel.cpp @@ -151,15 +151,6 @@ IfcUtil::IfcBaseEntity* IfcGeom::Kernel::get_decomposing_entity(IfcUtil::IfcBase } namespace { - - // LayerAssignments renamed from plural to singular, LayerAssignment, so work around that - IfcEntityList::ptr getLayerAssignments(Ifc2x3::IfcRepresentationItem* item) { - return item->LayerAssignments()->generalize(); - } - IfcEntityList::ptr getLayerAssignments(Ifc4::IfcRepresentationItem* item) { - return item->LayerAssignment()->generalize(); - } - template static std::map get_layers_impl(typename Schema::IfcProduct* prod) { std::map layers; @@ -172,14 +163,6 @@ namespace { layers[(*jt)->Name()] = *jt; } } - - typename Schema::IfcRepresentationItem::list::ptr items = r->as(); - for (typename Schema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++it) { - typename Schema::IfcPresentationLayerAssignment::list::ptr a = getLayerAssignments(*it)->template as(); - for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) { - layers[(*jt)->Name()] = *jt; - } - } } return layers; } diff --git a/src/ifcparse/IfcEntityList.h b/src/ifcparse/IfcEntityList.h index 263ab2cf6b..784f90a63f 100644 --- a/src/ifcparse/IfcEntityList.h +++ b/src/ifcparse/IfcEntityList.h @@ -40,6 +40,7 @@ public: it end(); IfcUtil::IfcBaseClass* operator[] (int i); unsigned int size() const; + void reserve(unsigned capacity); bool contains(IfcUtil::IfcBaseClass*) const; template typename U::list::ptr as() { diff --git a/src/ifcparse/IfcFile.h b/src/ifcparse/IfcFile.h index a3120ec620..f613c938c9 100644 --- a/src/ifcparse/IfcFile.h +++ b/src/ifcparse/IfcFile.h @@ -41,6 +41,7 @@ public: typedef boost::unordered_map entity_by_id_t; typedef std::map entity_by_guid_t; typedef std::map > entities_by_ref_t; + typedef std::map ref_map_t; typedef entity_by_id_t::const_iterator const_iterator; class type_iterator : private entities_by_type_t::const_iterator { @@ -86,6 +87,7 @@ private: entities_by_type_t bytype; entities_by_type_t bytype_excl; entities_by_ref_t byref; + ref_map_t by_ref_cached_; entity_by_guid_t byguid; entity_entity_map_t entity_file_map; @@ -181,6 +183,10 @@ public: IfcEntityList::ptr getInverse(int instance_id, const IfcParse::declaration* type, int attribute_index); + /// Marks entity as modified so that potential cache for it is invalidated. + /// @todo Currently the whole cache is invalidated. Implement more fine-grained invalidation. + void mark_entity_as_modified(int id); + unsigned int FreshId() { return ++MaxId; } IfcUtil::IfcBaseClass* addEntity(IfcUtil::IfcBaseClass* entity); diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index 78fa39f312..99ebefe959 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -1257,7 +1257,9 @@ void IfcEntityInstanceData::setArgument(unsigned int i, Argument* a, IfcUtil::Ar if (this->file) { register_inverse_visitor visitor(*this->file, *this); apply_individual_instance_visitor(copy).apply(visitor); - } + + this->file->mark_entity_as_modified(id_); + } attributes_[i] = copy; } @@ -1504,6 +1506,11 @@ IfcEntityList::ptr IfcFile::traverse(IfcUtil::IfcBaseClass* instance, int max_le return IfcParse::traverse(instance, max_level); } +void IfcFile::mark_entity_as_modified(int /*id*/) +{ + by_ref_cached_.clear(); +} + void IfcFile::addEntities(IfcEntityList::ptr es) { for( IfcEntityList::it i = es->begin(); i != es->end(); ++ i ) { addEntity(*i); @@ -1868,17 +1875,25 @@ IfcEntityList::ptr IfcFile::instances_by_type(const std::string& t) { IfcEntityList::ptr IfcFile::instances_by_reference(int t) { entities_by_ref_t::const_iterator it = byref.find(t); - IfcEntityList::ptr return_value; + IfcEntityList::ptr ret; if (it != byref.end()) { - const std::vector& ids = it->second; - for (std::vector::const_iterator jt = ids.begin(); jt != ids.end(); ++jt) { - if (!return_value) { - return_value.reset(new IfcEntityList); - } - return_value->push(instance_by_id(*jt)); - } + ref_map_t::const_iterator cached_it = by_ref_cached_.find(t); + if (cached_it != by_ref_cached_.end()) { + ret = cached_it->second; + } + else { + if (it->second.size()) { + ret.reset(new IfcEntityList); + ret->reserve((unsigned)it->second.size()); + const std::vector& ids = it->second; + for (std::vector::const_iterator jt = ids.begin(); jt != ids.end(); ++jt) { + ret->push(instance_by_id(*jt)); + } + } + by_ref_cached_[t] = ret; + } } - return return_value; + return ret; } IfcUtil::IfcBaseClass* IfcFile::instance_by_id(int id) { diff --git a/src/ifcparse/IfcUtil.cpp b/src/ifcparse/IfcUtil.cpp index 48ea296329..0aecf0757f 100644 --- a/src/ifcparse/IfcUtil.cpp +++ b/src/ifcparse/IfcUtil.cpp @@ -42,6 +42,7 @@ void IfcEntityList::push(const IfcEntityList::ptr& l) { } } unsigned int IfcEntityList::size() const { return (unsigned int) ls.size(); } +void IfcEntityList::reserve(unsigned capacity) { ls.reserve((size_t)capacity); } IfcEntityList::it IfcEntityList::begin() { return ls.begin(); } IfcEntityList::it IfcEntityList::end() { return ls.end(); } IfcUtil::IfcBaseClass* IfcEntityList::operator[] (int i) {