From ce4407ff3c038da059acc182921ceb5a2a144ef6 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 27 Feb 2025 22:07:31 +0100 Subject: [PATCH] Some successes writing and reading --- src/ifcconvert/IfcConvert.cpp | 24 +- src/ifcgeom/IfcGeomElement.h | 4 +- .../ifcopenshell/express/schema_class.py | 28 +- src/ifcparse/Header_section_schema-schema.cpp | 32 +- src/ifcparse/IfcEntityInstanceData.cpp | 126 ++++--- src/ifcparse/IfcEntityInstanceData.h | 162 +++++---- src/ifcparse/IfcFile.cpp | 82 ++++- src/ifcparse/IfcFile.h | 58 ++-- src/ifcparse/IfcHierarchyHelper.h | 13 +- src/ifcparse/IfcParse.cpp | 309 +++++++++++------- src/ifcparse/IfcSIPrefix.cpp | 3 +- src/ifcparse/IfcSpfHeader.cpp | 172 ++++++---- src/ifcparse/IfcSpfHeader.h | 112 +------ src/ifcparse/IfcUtil.cpp | 4 +- src/ifcparse/parse_ifcxml.cpp | 28 +- src/ifcparse/rocksdb_map_adapter.h | 12 +- src/serializers/SvgSerializer.cpp | 2 +- .../schema_dependent/XmlSerializer.cpp | 29 +- win/build-deps.cmd | 5 +- 19 files changed, 678 insertions(+), 527 deletions(-) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 5103d34299..c2802df073 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -206,7 +206,7 @@ size_t read_filters_from_file(const std::string&, inclusion_filter&, inclusion_t void parse_filter(geom_filter &, const std::vector&); std::vector setup_filters(const std::vector&, const std::string&); -bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, bool no_progress, bool mmap); +bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, bool no_progress, bool mmap, bool rocksdb); // from https://stackoverflow.com/questions/31696328/boost-program-options-using-zero-parameter-options-multiple-times struct verbosity_counter { @@ -239,6 +239,7 @@ int main(int argc, char** argv) { path_t cache_file; std::string log_format; std::string geometry_kernel; + std::string input_format; po::options_description generic_options("Command line options"); verbosity_counter vcounter; @@ -254,6 +255,7 @@ int main(int argc, char** argv) { ("yes,y", "answer 'yes' automatically to possible confirmation queries (e.g. overwriting an existing output file)") ("no-progress", "suppress possible progress bar type of prints that use carriage return") ("log-format", po::value(&log_format), "log format: plain or json") + ("input-format", po::value(&input_format), "input format: ifcspf, ifcxml, rocksdb") ("log-file", new po::typed_value(&log_file), "redirect log output to file"); po::options_description fileio_options; @@ -564,10 +566,12 @@ int main(int argc, char** argv) { } const path_t input_filename = vmap["input-file"].as(); - if (!file_exists(IfcUtil::path::to_utf8(input_filename))) { + /* + // todo also allow rocksdb dir + if (!file_exists(IfcUtil::path::to_utf8(input_filename))) { cerr_ << "[Error] Input file '" << input_filename << "' does not exist" << std::endl; return EXIT_FAILURE; - } + }*/ // If no output filename is specified a Wavefront OBJ file will be output // to maintain backwards compatibility with the obsolete IfcObj executable. @@ -658,7 +662,7 @@ int main(int argc, char** argv) { if (output_extension == XML) { int exit_code = EXIT_FAILURE; try { - if (init_input_file(IfcUtil::path::to_utf8(input_filename), ifc_file, no_progress || quiet, mmap)) { + if (init_input_file(IfcUtil::path::to_utf8(input_filename), ifc_file, no_progress || quiet, mmap, input_format=="rocksdb")) { time_t start, end; time(&start); XmlSerializer s(ifc_file, IfcUtil::path::to_utf8(output_temp_filename)); @@ -678,7 +682,7 @@ int main(int argc, char** argv) { } else if (output_extension == IFC) { int exit_code = EXIT_FAILURE; try { - if (init_input_file(IfcUtil::path::to_utf8(input_filename), ifc_file, no_progress || quiet, mmap)) { + if (init_input_file(IfcUtil::path::to_utf8(input_filename), ifc_file, no_progress || quiet, mmap, input_format == "rocksdb")) { time_t start, end; time(&start); std::ofstream fs(output_filename.c_str()); @@ -704,11 +708,11 @@ int main(int argc, char** argv) { else if (output_extension == RDB) { int exit_code = EXIT_FAILURE; try { - if (init_input_file(IfcUtil::path::to_utf8(input_filename), ifc_file, no_progress || quiet, mmap)) { + if (init_input_file(IfcUtil::path::to_utf8(input_filename), ifc_file, no_progress || quiet, mmap, input_format == "rocksdb")) { time_t start, end; time(&start); RocksDbSerializer s(ifc_file, IfcUtil::path::to_utf8(output_filename)); - Logger::Status("Populating RockDB Key-Value store..."); + Logger::Status("Populating RocksDB Key-Value store..."); s.finalize(); time(&end); Logger::Status("Done! Conversion took " + format_duration(start, end)); @@ -937,7 +941,7 @@ int main(int argc, char** argv) { time_t start,end; time(&start); - if (!init_input_file(IfcUtil::path::to_utf8(input_filename), ifc_file, no_progress || quiet, mmap)) { + if (!init_input_file(IfcUtil::path::to_utf8(input_filename), ifc_file, no_progress || quiet, mmap, input_format == "rocksdb")) { write_log(!quiet); serializer.reset(); IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename)); /**< @todo Windows Unicode support */ @@ -1270,7 +1274,7 @@ void write_log(bool header) { #include -bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, bool no_progress, bool mmap) { +bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, bool no_progress, bool mmap, bool rocksdb) { time_t start, end; // Prevent IfcFile::Init() prints by setting output to null temporarily @@ -1289,7 +1293,7 @@ bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, ifc_file = new IfcParse::IfcFile(filename, mmap); #else (void)mmap; - ifc_file = new IfcParse::IfcFile(filename); + ifc_file = new IfcParse::IfcFile(filename, rocksdb ? IfcParse::rocksdb : IfcParse::ifcspf); #endif } diff --git a/src/ifcgeom/IfcGeomElement.h b/src/ifcgeom/IfcGeomElement.h index 5b1473037c..cb4ba87f06 100644 --- a/src/ifcgeom/IfcGeomElement.h +++ b/src/ifcgeom/IfcGeomElement.h @@ -72,8 +72,8 @@ namespace IfcGeom { friend bool operator < (const Element& element1, const Element& element2) { if (element1.type() == "IfcBuildingStorey" && element2.type() == "IfcBuildingStorey") { size_t attr_index = element1.product()->declaration().as_entity()->attribute_index("Elevation"); - auto elev_attr1 = element1.product()->data().get_attribute_value(attr_index); - auto elev_attr2 = element2.product()->data().get_attribute_value(attr_index); + auto elev_attr1 = element1.product()->get_attribute_value(attr_index); + auto elev_attr2 = element2.product()->get_attribute_value(attr_index); if (!elev_attr1.isNull() && !elev_attr2.isNull()) { double elev1 = elev_attr1; diff --git a/src/ifcopenshell-python/ifcopenshell/express/schema_class.py b/src/ifcopenshell-python/ifcopenshell/express/schema_class.py index 89db02b4a9..50a4e50c5d 100644 --- a/src/ifcopenshell-python/ifcopenshell/express/schema_class.py +++ b/src/ifcopenshell-python/ifcopenshell/express/schema_class.py @@ -174,12 +174,10 @@ class EarlyBoundCodeWriter: def begin_schema(self): self.names.sort(key=str.lower) - schema_name = self.schema_name + schema_name = self.schema_name.upper() num_names = len(self.names) self.statements.append("declaration* %(schema_name)s_types[%(num_names)d] = {nullptr};" % locals()) - self.statements.append("{string_pool_placeholder}") - self.statements.append("{factory_placeholder}") # self.statements.append( @@ -194,10 +192,11 @@ class EarlyBoundCodeWriter: # #endif # """ # ) - self.statements.append("IfcParse::schema_definition* %s_populate_schema() {" % self.schema_name) + self.statements.append("IfcParse::schema_definition* %s_populate_schema() {" % self.schema_name.upper()) + self.statements.append("{string_pool_placeholder}") def typedef(self, name, declared_type): - schema_name = self.schema_name + schema_name = self.schema_name.upper() index_in_schema = self.names.index(name) ref = self.strings.append(name) self.statements.append( @@ -206,7 +205,7 @@ class EarlyBoundCodeWriter: ) def enumeration(self, name, enum): - schema_name = self.schema_name + schema_name = self.schema_name.upper() index_in_schema = self.names.index(name) ref = self.strings.append(name) items = ",".join(self.strings.append(v) for v in enum.values) @@ -216,7 +215,7 @@ class EarlyBoundCodeWriter: ) def entity(self, name, type): - schema_name = self.schema_name + schema_name = self.schema_name.upper() index_in_schema = self.names.index(name) ref = self.strings.append(name) supertype = "0" if len(type.supertypes) == 0 else "%s_types[%d]" % (self.schema_name, self.names.index(type.supertypes[0])) @@ -227,7 +226,7 @@ class EarlyBoundCodeWriter: ) def select(self, name, type): - schema_name = self.schema_name + schema_name = self.schema_name.upper() index_in_schema = self.names.index(name) ref = self.strings.append(name) items = ",".join( @@ -239,7 +238,7 @@ class EarlyBoundCodeWriter: ) def entity_attributes(self, name, attribute_definitions, is_derived): - schema_name = self.schema_name + schema_name = self.schema_name.upper() index_in_schema = self.names.index(name) def _(): index_in_schema = self.names.index(name) @@ -253,7 +252,7 @@ class EarlyBoundCodeWriter: self.statements.append(" ((entity*)%(schema_name)s_types[%(index_in_schema)d])->set_attributes({%(attributes)s}, {%(derived)s});" % locals()) def inverse_attributes(self, name, inv_attrs): - schema_name = self.schema_name + schema_name = self.schema_name.upper() index_in_schema = self.names.index(name) def _(): schema_name = self.schema_name @@ -269,16 +268,16 @@ class EarlyBoundCodeWriter: self.statements.append(" ((entity*) %(schema_name)s_types[%(index_in_schema)d])->set_inverse_attributes({%(attributes)s});" % locals()) def entity_subtypes(self, name, tys): - schema_name = self.schema_name + schema_name = self.schema_name.upper() index_in_schema = self.names.index(name) subtypes = ",".join(map(lambda t: ("((entity*) %%(schema_name)s_types[%d])" % self.names.index(t)), tys)) % locals() self.statements.append(" ((entity*) %(schema_name)s_types[%(index_in_schema)d])->set_subtypes({%(subtypes)s});" % locals()) def finalize(self, can_be_instantiated_set): - schema_name = self.schema_name + schema_name = self.schema_name.upper() schema_name_title = self.schema_name.capitalize() def _(): - schema_name = self.schema_name + schema_name = self.schema_name.upper() schema_name_title = self.schema_name.capitalize() for type_name in self.names: index_in_schema = self.names.index(type_name) @@ -378,6 +377,7 @@ class SchemaClass(codegen.Base): def transform_to_indexed(fn): def wrapper(*args, **kwargs): + schema_name_upper = mapping.schema.name.upper() declared_type = fn(*args, **kwargs) if 'simple_type' in declared_type: pass @@ -387,7 +387,7 @@ class SchemaClass(codegen.Base): old_decl = match.group(1) name = old_decl.lower().replace(schema_name.lower() + '_', '').replace('_type', '') idx = [n.lower() for n in x.names].index(name) - declared_type = declared_type.replace(old_decl, '%(schema_name)s_types[%(idx)d]' % locals()) + declared_type = declared_type.replace(old_decl, '%(schema_name_upper)s_types[%(idx)d]' % locals()) return declared_type return wrapper if code == EarlyBoundCodeWriter else fn diff --git a/src/ifcparse/Header_section_schema-schema.cpp b/src/ifcparse/Header_section_schema-schema.cpp index 09af82ddd4..4116491c06 100644 --- a/src/ifcparse/Header_section_schema-schema.cpp +++ b/src/ifcparse/Header_section_schema-schema.cpp @@ -6,12 +6,9 @@ using namespace std::string_literals; using namespace IfcParse; -declaration* header_section_schema_types[5] = {nullptr}; +declaration* HEADER_SECTION_SCHEMA_types[5] = {nullptr}; -const std::string strings[] = {"schema_name"s,"time_stamp_text"s,"file_description"s,"file_name"s,"file_schema"s,"description"s,"implementation_level"s,"name"s,"time_stamp"s,"author"s,"organization"s,"preprocessor_version"s,"originating_system"s,"authorisation"s,"schema_identifiers"s,"header_section_schema"s}; - - -class header_section_schema_instance_factory : public IfcParse::instance_factory { +class HEADER_SECTION_SCHEMA_instance_factory : public IfcParse::instance_factory { virtual IfcUtil::IfcBaseClass* operator()(const IfcParse::declaration* decl, IfcEntityInstanceData&& data) const { switch(decl->index_in_schema()) { case 0: return new ::Header_section_schema::file_description(std::move(data)); @@ -25,16 +22,19 @@ class header_section_schema_instance_factory : public IfcParse::instance_factory } }; -IfcParse::schema_definition* header_section_schema_populate_schema() { - header_section_schema_types[3] = new type_declaration(strings[0], 3, new simple_type(simple_type::string_type)); - header_section_schema_types[4] = new type_declaration(strings[1], 4, new simple_type(simple_type::string_type)); - header_section_schema_types[0] = new entity(strings[2], false, 0, (entity*) 0); - header_section_schema_types[1] = new entity(strings[3], false, 1, (entity*) 0); - header_section_schema_types[2] = new entity(strings[4], false, 2, (entity*) 0); - ((entity*)header_section_schema_types[0])->set_attributes({new attribute(strings[5], new aggregation_type(aggregation_type::list_type, 1, -1, new simple_type(simple_type::string_type)), false),new attribute(strings[6], new simple_type(simple_type::string_type), false)}, {false,false}); - ((entity*)header_section_schema_types[1])->set_attributes({new attribute(strings[7], new simple_type(simple_type::string_type), false),new attribute(strings[8], new named_type(header_section_schema_types[4]), false),new attribute(strings[9], new aggregation_type(aggregation_type::list_type, 1, -1, new simple_type(simple_type::string_type)), false),new attribute(strings[10], new aggregation_type(aggregation_type::list_type, 1, -1, new simple_type(simple_type::string_type)), false),new attribute(strings[11], new simple_type(simple_type::string_type), false),new attribute(strings[12], new simple_type(simple_type::string_type), false),new attribute(strings[13], new simple_type(simple_type::string_type), false)}, {false,false,false,false,false,false,false}); - ((entity*)header_section_schema_types[2])->set_attributes({new attribute(strings[14], new aggregation_type(aggregation_type::list_type, 1, -1, new named_type(header_section_schema_types[3])), false)}, {false}); - return new schema_definition(strings[15], {header_section_schema_types[0],header_section_schema_types[1],header_section_schema_types[2],header_section_schema_types[3],header_section_schema_types[4]}, new header_section_schema_instance_factory()); +IfcParse::schema_definition* HEADER_SECTION_SCHEMA_populate_schema() { + +const std::string strings[] = {"schema_name"s,"time_stamp_text"s,"file_description"s,"file_name"s,"file_schema"s,"description"s,"implementation_level"s,"name"s,"time_stamp"s,"author"s,"organization"s,"preprocessor_version"s,"originating_system"s,"authorisation"s,"schema_identifiers"s,"HEADER_SECTION_SCHEMA"s}; + + HEADER_SECTION_SCHEMA_types[3] = new type_declaration(strings[0], 3, new simple_type(simple_type::string_type)); + HEADER_SECTION_SCHEMA_types[4] = new type_declaration(strings[1], 4, new simple_type(simple_type::string_type)); + HEADER_SECTION_SCHEMA_types[0] = new entity(strings[2], false, 0, (entity*) 0); + HEADER_SECTION_SCHEMA_types[1] = new entity(strings[3], false, 1, (entity*) 0); + HEADER_SECTION_SCHEMA_types[2] = new entity(strings[4], false, 2, (entity*) 0); + ((entity*)HEADER_SECTION_SCHEMA_types[0])->set_attributes({new attribute(strings[5], new aggregation_type(aggregation_type::list_type, 1, -1, new simple_type(simple_type::string_type)), false),new attribute(strings[6], new simple_type(simple_type::string_type), false)}, {false,false}); + ((entity*)HEADER_SECTION_SCHEMA_types[1])->set_attributes({new attribute(strings[7], new simple_type(simple_type::string_type), false),new attribute(strings[8], new named_type(HEADER_SECTION_SCHEMA_types[4]), false),new attribute(strings[9], new aggregation_type(aggregation_type::list_type, 1, -1, new simple_type(simple_type::string_type)), false),new attribute(strings[10], new aggregation_type(aggregation_type::list_type, 1, -1, new simple_type(simple_type::string_type)), false),new attribute(strings[11], new simple_type(simple_type::string_type), false),new attribute(strings[12], new simple_type(simple_type::string_type), false),new attribute(strings[13], new simple_type(simple_type::string_type), false)}, {false,false,false,false,false,false,false}); + ((entity*)HEADER_SECTION_SCHEMA_types[2])->set_attributes({new attribute(strings[14], new aggregation_type(aggregation_type::list_type, 1, -1, new named_type(HEADER_SECTION_SCHEMA_types[3])), false)}, {false}); + return new schema_definition(strings[15], {HEADER_SECTION_SCHEMA_types[0],HEADER_SECTION_SCHEMA_types[1],HEADER_SECTION_SCHEMA_types[2],HEADER_SECTION_SCHEMA_types[3],HEADER_SECTION_SCHEMA_types[4]}, new HEADER_SECTION_SCHEMA_instance_factory()); } static std::unique_ptr schema; @@ -44,7 +44,7 @@ void Header_section_schema::clear_schema() { const schema_definition& Header_section_schema::get_schema() { if (!schema) { - schema.reset(header_section_schema_populate_schema()); + schema.reset(HEADER_SECTION_SCHEMA_populate_schema()); } return *schema; } diff --git a/src/ifcparse/IfcEntityInstanceData.cpp b/src/ifcparse/IfcEntityInstanceData.cpp index 1753a284f4..793e8fda07 100644 --- a/src/ifcparse/IfcEntityInstanceData.cpp +++ b/src/ifcparse/IfcEntityInstanceData.cpp @@ -43,8 +43,8 @@ namespace { !std::is_same_v>, IfcUtil::IfcBaseClass>) { std::string str; - array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "a|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str); - impl::deserialize(str, val); + array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str); + impl::deserialize(array_.db_ptr, str, val); } return val; } @@ -57,7 +57,7 @@ namespace { return array_.storage_ptr->has(index_); } else { std::string str; - array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "a|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str); + array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str); return str[0] == TypeEncoder::encode_type(); } } @@ -68,7 +68,7 @@ namespace { return array_.storage_ptr->index(index_); } else { std::string str; - array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "a|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str); + array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str); return (size_t) str[0] - 'A'; } } @@ -107,11 +107,11 @@ AttributeValue::operator std::string() const return dispatch_get_(array_, storage_model_, instance_name_, index_).value(); } else { std::string str; - array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "a|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str); + array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str); size_t v; memcpy(&v, str.data() + 1, sizeof(size_t)); auto decl = schema_->declarations()[v]->as_enumeration_type(); - memcpy(&v, str.data() + 5, sizeof(size_t)); + memcpy(&v, str.data() + 1 + sizeof(size_t), sizeof(size_t)); return decl->lookup_enum_value(v); } } @@ -124,7 +124,7 @@ AttributeValue::operator EnumerationReference() const return dispatch_get_(array_, storage_model_, instance_name_, index_); } else { std::string str; - array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "a|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str); + array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str); size_t v; memcpy(&v, str.data() + 1, sizeof(size_t)); auto decl = schema_->declarations()[v]->as_enumeration_type(); @@ -144,12 +144,17 @@ AttributeValue::operator IfcUtil::IfcBaseClass* () const return dispatch_get_(array_, storage_model_, instance_name_, index_); } else { std::string str; - array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "a|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str); + array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str); size_t v; - memcpy(&v, str.data() + 1, sizeof(size_t)); - auto decl = schema_->declarations()[v]->as_enumeration_type(); - memcpy(&v, str.data() + 5, sizeof(size_t)); - return array_.db_ptr->assert_existance(v); + memcpy(&v, str.data() + 2, sizeof(size_t)); + if (str[1] == 'e') { + // entity reference, by #Name + return array_.db_ptr->assert_existance(v, IfcParse::impl::rocks_db_file_storage::by_name); + } else if (str[1] == 't') { + // type reference by Identity + return array_.db_ptr->assert_existance(v, IfcParse::impl::rocks_db_file_storage::by_identity); + } + } } @@ -216,7 +221,7 @@ bool impl::serialize(std::string& val, const IfcUtil::IfcBaseClass* t) val[0] = TypeEncoder::encode_type(); // 1 = entity - stored by id (entity name) // 2 = type - stored by identity (internal counter in class) - val[1] = t->declaration().as_entity() ? 1 : 2; + val[1] = t->declaration().as_entity() ? 'e' : 't'; size_t iden = t->declaration().as_entity() ? t->id() : t->identity(); memcpy(val.data() + 2, &iden, s); return true; @@ -230,16 +235,24 @@ bool impl::serialize(std::string& val, const EnumerationReference& v) size_t vv = v.enumeration()->index_in_schema(); memcpy(val.data() + 1, &vv, sizeof(size_t)); vv = v.index(); - memcpy(val.data() + 1, &vv, sizeof(size_t)); + memcpy(val.data() + 1 + sizeof(size_t), &vv, sizeof(size_t)); return true; } bool impl::serialize(std::string& val, const aggregate_of_instance::ptr& t) { - std::vector ids; - // @nb this has to be identity, because needs to work for typedecls as well - std::transform(t->begin(), t->end(), std::back_inserter(ids), [](auto& x) { return x->identity(); }); - return false; + // no attempt at alignment + val.resize(t->size() * (sizeof(size_t) + 1) + 1); + val[0] = TypeEncoder::encode_type(); + char* ptr = val.data() + 1; + for (auto it = t->begin(); it != t->end(); ++it) { + *ptr = (*it)->declaration().as_entity() ? 'e' : 't'; + ptr++; + size_t iden = (*it)->declaration().as_entity() ? (*it)->id() : (*it)->identity(); + memcpy(ptr, &iden, sizeof(size_t)); + ptr += sizeof(size_t); + } + return true; } bool impl::serialize(std::string& val, const aggregate_of_aggregate_of_instance::ptr& t) @@ -282,7 +295,7 @@ bool impl::serialize(std::string& val, const boost::dynamic_bitset<>& t) return false; } -bool impl::deserialize(std::string& val, boost::logic::tribool& t) { +bool impl::deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, boost::logic::tribool& t) { if (val[0] != TypeEncoder::encode_type()) { return false; } @@ -297,7 +310,7 @@ bool impl::deserialize(std::string& val, boost::logic::tribool& t) { } } -bool impl::deserialize(std::string& val, boost::dynamic_bitset<>& t) { +bool impl::deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, boost::dynamic_bitset<>& t) { if (val[0] != TypeEncoder::encode_type>()) { return false; } @@ -305,41 +318,64 @@ bool impl::deserialize(std::string& val, boost::dynamic_bitset<>& t) { return true; } -bool impl::deserialize(std::string& val, aggregate_of_instance::ptr& t) { - return false; +bool impl::deserialize(IfcParse::impl::rocks_db_file_storage* storage, const std::string& val, aggregate_of_instance::ptr& t) { + t.reset(new aggregate_of_instance); + // val[0] = TypeEncoder::encode_type(); + auto n = (val.size() - 1) / (sizeof(size_t) + 1); + for (int i = 0; i < n; ++i) { + auto ptr = val.data() + 1 + (sizeof(size_t) + 1) * i; + auto tt = *ptr; + ptr++; + size_t v; + memcpy(&v, ptr, sizeof(size_t)); + if (tt == 'e') { + t->push(storage->assert_existance(v, IfcParse::impl::rocks_db_file_storage::by_name)); + } else if (tt == 't') { + t->push(storage->assert_existance(v, IfcParse::impl::rocks_db_file_storage::by_identity)); + } else { + throw std::runtime_error(""); + } + } + return true; } -bool impl::deserialize(std::string& val, aggregate_of_aggregate_of_instance::ptr& t) { +bool impl::deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, aggregate_of_aggregate_of_instance::ptr& t) { return false; } template -void rocks_db_attribute_storage::set(std::size_t index, const T& value) +void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, std::size_t index, const T& value) { + const bool is_header = decl->schema() == &Header_section_schema::get_schema(); + IfcParse::impl::rocks_db_file_storage* rdb_storage = (IfcParse::impl::rocks_db_file_storage*)storage; std::string v; impl::serialize(v, value); - fs_->db->Put(rocksdb::WriteOptions{}, prefix_ + ("|" + std::to_string(index)), v); + rdb_storage->db->Put( + rocksdb::WriteOptions{}, + (is_header ? "h|" : "i|") + + (is_header ? decl->name() : std::to_string(identity)) + "|" + + std::to_string(index), v); } -template void rocks_db_attribute_storage::set(size_t index, const Blank& value); -template void rocks_db_attribute_storage::set(size_t index, const int& value); -template void rocks_db_attribute_storage::set(size_t index, const bool& value); -template void rocks_db_attribute_storage::set(size_t index, const boost::logic::tribool& value); -template void rocks_db_attribute_storage::set(size_t index, const double& value); -template void rocks_db_attribute_storage::set(size_t index, const std::string& value); -template void rocks_db_attribute_storage::set>(size_t index, const boost::dynamic_bitset<>& value); -template void rocks_db_attribute_storage::set(size_t index, const EnumerationReference& value); -template void rocks_db_attribute_storage::set(size_t index, IfcUtil::IfcBaseClass* const& value); -template void rocks_db_attribute_storage::set>(size_t index, const std::vector& value); -template void rocks_db_attribute_storage::set>(size_t index, const std::vector& value); -template void rocks_db_attribute_storage::set>(size_t index, const std::vector& value); -template void rocks_db_attribute_storage::set>>(size_t index, const std::vector>& value); -template void rocks_db_attribute_storage::set(size_t index, const aggregate_of_instance::ptr& value); -template void rocks_db_attribute_storage::set>>(size_t index, const std::vector>& value); -template void rocks_db_attribute_storage::set>>(size_t index, const std::vector>& value); -template void rocks_db_attribute_storage::set(size_t index, const aggregate_of_aggregate_of_instance::ptr& value); +template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const Blank& value); +template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const int& value); +template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const bool& value); +template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const boost::logic::tribool& value); +template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const double& value); +template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::string& value); +template void rocks_db_attribute_storage::set>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const boost::dynamic_bitset<>& value); +template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const EnumerationReference& value); +template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, IfcUtil::IfcBaseClass* const& value); +template void rocks_db_attribute_storage::set>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector& value); +template void rocks_db_attribute_storage::set>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector& value); +template void rocks_db_attribute_storage::set>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector& value); +template void rocks_db_attribute_storage::set>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector>& value); +template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const aggregate_of_instance::ptr& value); +template void rocks_db_attribute_storage::set>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector>& value); +template void rocks_db_attribute_storage::set>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector>& value); +template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const aggregate_of_aggregate_of_instance::ptr& value); // @todo why do these need to be included, but are not in BaseEntity::set()? -template void rocks_db_attribute_storage::set(size_t index, const Derived& value); -template void rocks_db_attribute_storage::set(size_t index, const empty_aggregate_t& value); -template void rocks_db_attribute_storage::set(size_t index, const empty_aggregate_of_aggregate_t& value); +template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const Derived& value); +template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const empty_aggregate_t& value); +template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const empty_aggregate_of_aggregate_t& value); diff --git a/src/ifcparse/IfcEntityInstanceData.h b/src/ifcparse/IfcEntityInstanceData.h index 2954c1cf1d..afe61b8238 100644 --- a/src/ifcparse/IfcEntityInstanceData.h +++ b/src/ifcparse/IfcEntityInstanceData.h @@ -172,11 +172,6 @@ namespace impl { template struct is_contiguous_container> : std::true_type {}; - template ::value && is_contiguous_container::value, int>::type = 0> - bool serialize(std::string& val, const T& t) { - return false; - } - template ::value && !is_contiguous_container::value, int>::type = 0> bool serialize(std::string& val, const T& t) { auto s = sizeof(typename T::value_type) * t.size(); @@ -186,6 +181,22 @@ namespace impl { return true; } + template ::value&& is_contiguous_container::value, int>::type = 0> + bool serialize(std::string& val, const T& t) { + val = std::string(1, TypeEncoder::encode_type()); + for (auto& tt : t) { + std::string v2; + serialize(v2, tt); + std::string len(sizeof(size_t), 0); + size_t s = v2.size() - 1; + memcpy(len.data(), &s, sizeof(size_t)); + // @todo horribly inefficient + // @todo strip off type label? + val += len + v2.substr(1); + } + return true; + } + template || std::is_floating_point_v, int>::type = 0> bool serialize(std::string& val, const T& t) { val.resize(sizeof(T) + 1); @@ -212,20 +223,41 @@ namespace impl { bool serialize(std::string& val, const aggregate_of_aggregate_of_instance::ptr& t); - template ::value, int>::type = 0> - bool deserialize(std::string& val, T& t) { - // @todo vector of vector - if (val[0] != TypeEncoder::encode_type()) { + template ::value && !is_contiguous_container::value, int>::type = 0> + bool deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, T& t, bool prefixed = true) { + if (prefixed && val[0] != TypeEncoder::encode_type()) { return false; } - auto s = (val.size() - 1) / sizeof(typename T::value_type); + auto s = (val.size() - (prefixed ? 1 : 0)) / sizeof(typename T::value_type); t.resize(s); - memcpy(t.data(), val.data() + 1, s * sizeof(typename T::value_type)); + memcpy(t.data(), val.data() + (prefixed ? 1 : 0), s * sizeof(typename T::value_type)); + return true; + } + + template ::value && is_contiguous_container::value, int>::type = 0> + bool deserialize(IfcParse::impl::rocks_db_file_storage* storage, const std::string& val, T& t) { + // @todo + auto ptr = val.data(); + if (*ptr != TypeEncoder::encode_type()) { + return false; + } + ptr++; + t.clear(); + while (ptr < val.data() + val.size()) { + size_t s; + memcpy(&s, ptr, sizeof(size_t)); + // @todo view + ptr += sizeof(size_t); + std::string part(ptr, s); + t.emplace_back(); + deserialize(storage, part, t.back(), false); + ptr += s; + } return true; } template || std::is_floating_point_v, int>::type = 0> - bool deserialize(std::string & val, T & t) { + bool deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, T & t) { if (val[0] != TypeEncoder::encode_type()) { return false; } @@ -234,13 +266,13 @@ namespace impl { return true; } - bool deserialize(std::string& val, boost::logic::tribool& t); + bool deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, boost::logic::tribool& t); - bool deserialize(std::string& val, boost::dynamic_bitset<>& t); + bool deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, boost::dynamic_bitset<>& t); - bool deserialize(std::string& val, aggregate_of_instance::ptr& t); + bool deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, aggregate_of_instance::ptr& t); - bool deserialize(std::string& val, aggregate_of_aggregate_of_instance::ptr& t); + bool deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, aggregate_of_aggregate_of_instance::ptr& t); } @@ -250,7 +282,7 @@ struct AttributeValue { uint8_t storage_model_ = 0; size_t instance_name_; // @todo couple with db_ptr; - IfcParse::schema_definition* schema_; + const IfcParse::schema_definition* schema_; union pointer_type { const in_memory_attribute_storage* storage_ptr; IfcParse::impl::rocks_db_file_storage* db_ptr; @@ -271,7 +303,7 @@ struct AttributeValue { , storage_model_(0) {} - AttributeValue(IfcParse::schema_definition* schema, IfcParse::impl::rocks_db_file_storage* db, size_t instance_name, uint8_t index) + AttributeValue(const IfcParse::schema_definition* schema, IfcParse::impl::rocks_db_file_storage* db, size_t instance_name, uint8_t index) : index_(index) , array_(db) , storage_model_(1) @@ -307,11 +339,6 @@ struct AttributeValue { struct rocks_db_attribute_storage { private: - // @todo not needed as call always passes through EntityInstanceData - IfcParse::impl::rocks_db_file_storage* fs_; - // @todo not needed should be passed from call stack - const char* prefix_; - template auto apply_visitor_impl(Visitor&& visitor, std::size_t idx, std::integral_constant) const { return apply_visitor_impl(std::forward(visitor), idx, std::integral_constant{}); @@ -323,59 +350,31 @@ private: } public: - rocks_db_attribute_storage(IfcParse::impl::rocks_db_file_storage* fs, const char* const prefix) - : fs_(fs) - , prefix_(prefix) - {} - - rocks_db_attribute_storage(rocks_db_attribute_storage& other) - : fs_(other.fs_) - , prefix_(other.prefix_) - {} - - rocks_db_attribute_storage(rocks_db_attribute_storage&& other) - : fs_(other.fs_) - , prefix_(other.prefix_) - {} - - rocks_db_attribute_storage& operator=(const rocks_db_attribute_storage& other) { - if (this != &other) { - fs_ = other.fs_; - prefix_ = other.prefix_; - } - return *this; - } - - rocks_db_attribute_storage& operator=(const rocks_db_attribute_storage&& other) { - if (this != &other) { - fs_ = other.fs_; - prefix_ = other.prefix_; - } - return *this; - } - - size_t size() const { + size_t size(void*, const IfcParse::declaration*, std::size_t identity) const { // @todo is this actually needed? return 8; } + // @todo void* is obviously very ugly here template - void set(std::size_t index, const T& value); + void set(void* storage, const IfcParse::declaration*, std::size_t identity, std::size_t index, const T& value); template - bool has(std::size_t index) const { + bool has(void* storage, const IfcParse::declaration*, std::size_t identity, std::size_t index) const { // @todo return false; } template - auto apply_visitor(Visitor&& visitor, std::size_t index) const { + auto apply_visitor(void* storage, const IfcParse::declaration*, std::size_t identity, std::size_t index, Visitor&& visitor) const { return apply_visitor_impl(std::forward(visitor), index, std::integral_constant{}); } }; class IFC_PARSE_API IfcEntityInstanceData { public: + // @todo since rocks_db_attribute_storage has no members anymore, change to in_memory_attribute_storage*? + // 24 -> 8 bytes... std::variant storage_; IfcEntityInstanceData(in_memory_attribute_storage&& storage) @@ -390,7 +389,8 @@ class IFC_PARSE_API IfcEntityInstanceData { : storage_(std::move(other.storage_)) {} - IfcEntityInstanceData(const IfcEntityInstanceData& data); + // No copy-constructor anymore because we need the instance for storage model context + IfcEntityInstanceData(const IfcEntityInstanceData&) = delete; IfcEntityInstanceData& operator=(IfcEntityInstanceData&& other) { if (this != &other) { @@ -399,34 +399,52 @@ class IFC_PARSE_API IfcEntityInstanceData { return *this; } - AttributeValue get_attribute_value(size_t index) const; + AttributeValue get_attribute_value(void* storage, const IfcParse::declaration*, std::size_t identity, size_t index) const; template - void set_attribute_value(std::size_t index, T&& value) { - std::visit([&index, &value](auto& x) { - return x.set(index, value); + void set_attribute_value(void* storage, const IfcParse::declaration* decl, std::size_t identity, std::size_t index, T&& value) { + std::visit([&index, &value, storage, decl, identity](auto& x) { + if constexpr (std::is_same_v, in_memory_attribute_storage>) { + return x.set(index, value); + } else { + return x.set(storage, decl, identity, index, value); + } }, storage_); } template - bool has_attribute_value(std::size_t index) const { - return std::visit([&index](const auto& x) { - return x.has(index); + bool has_attribute_value(void* storage, const IfcParse::declaration* decl, std::size_t identity, std::size_t index) const { + return std::visit([&index, storage, decl, identity](const auto& x) { + if constexpr (std::is_same_v, in_memory_attribute_storage>) { + return x.has(index); + } else { + return x.has(storage, decl, identity, index); + } }, storage_); } template - auto apply_visitor(Visitor&& visitor, std::size_t index) const { - return std::visit([&index, &visitor](const auto& x) { - return x.apply_visitor(std::forward(visitor), index); + auto apply_visitor(void* storage, const IfcParse::declaration* decl, std::size_t identity, Visitor&& visitor, std::size_t index) const { + return std::visit([&index, &visitor, storage, decl, identity](const auto& x) { + if constexpr (std::is_same_v, in_memory_attribute_storage>) { + return x.apply_visitor(std::forward(visitor), index); + } else { + return x.apply_visitor(storage, decl, identity, index, std::forward(visitor)); + } }, storage_); } - size_t size() const { - return std::visit([](const auto& x) { return x.size(); }, storage_); + size_t size(void* storage, const IfcParse::declaration* decl, std::size_t identity) const { + return std::visit([storage, decl, identity](const auto& x) { + if constexpr (std::is_same_v, in_memory_attribute_storage>) { + return x.size(); + } else { + return x.size(storage, decl, identity); + } + }, storage_); } - void toString(std::ostream&, bool upper = false, const IfcParse::entity* ent = nullptr) const; + void toString(void* storage, const IfcParse::declaration*, std::size_t identity, std::ostream&, bool upper = false) const; }; #endif diff --git a/src/ifcparse/IfcFile.cpp b/src/ifcparse/IfcFile.cpp index bc2dc7a3dc..8941e970e7 100644 --- a/src/ifcparse/IfcFile.cpp +++ b/src/ifcparse/IfcFile.cpp @@ -337,7 +337,7 @@ IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::rocksdb_instance_i if (jt != storage_->instance_cache_.end()) { return jt->second; } else { - return storage_->assert_existance(it->second); + return storage_->assert_existance(it->first, by_name); } } } @@ -346,46 +346,94 @@ const IfcParse::declaration* IfcParse::impl::rocks_db_file_storage::rocksdb_type return storage_->file->schema()->declarations()[*read_id_()]; } -IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::assert_existance(size_t instanceId) { +IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::assert_existance(size_t number, instance_ref r) { + size_t name, identity; std::string v; - rocksdb::Status s = db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(instanceId) + "|t", &v); + if (r == by_identity) { + name = 0; + identity = number; + } else { + name = number; + auto it = byid_.find(name); + if (it == byid_.end()) { + throw std::runtime_error("Unable to lookup identity of name: #" + std::to_string(number)); + } + identity = it->second; + } + + decltype(instance_cache_)::const_iterator it = instance_cache_.find(identity); + if (it != instance_cache_.end()) { + return it->second; + } + + rocksdb::Status s = db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(identity) + "|t", &v); if (s.ok()) { size_t s; memcpy(&s, v.data(), sizeof(size_t)); + if (s >= file->schema()->declarations().size()) { + throw std::runtime_error(""); + } auto decl = file->schema()->declarations()[s]; - IfcEntityInstanceData data(rocks_db_attribute_storage(this, "i|")); + bool is_entity = decl->as_entity() != nullptr; + if (is_entity != (r == by_name)) { + throw std::runtime_error("Incorrect reference"); + } + IfcEntityInstanceData data(rocks_db_attribute_storage{}); auto inst = file->schema()->instantiate(decl, std::move(data)); - inst->id_ = instanceId; + inst->id_ = name; + inst->file_ = file; instance_cache_.insert({ inst->identity(), inst }); - byid_.insert({ inst->id(), inst->identity() }); + if (is_entity) { + byid_.insert({ inst->id(), inst->identity() }); + } return inst; } throw std::runtime_error(""); } +namespace { + rocksdb::DB* init_db(const std::string& filepath) { + rocksdb::DB* db; + rocksdb::Options options; + options.create_if_missing = true; + // options.merge_operator.reset(new ConcatenateIdMergeOperator()); + rocksdb::Status status = rocksdb::DB::Open(options, filepath, &db); + if (!status.ok()) { + throw std::runtime_error(status.ToString()); + } + return db; + } +} + // @todo naming IfcParse::impl::rocks_db_file_storage::rocks_db_file_storage(const std::string& filepath, IfcParse::IfcFile* ffile) : file(ffile) - // @todo db is not initialized here yet + , db(init_db(filepath)) , byguid_internal_(db, "g|") - , byguid_(&byguid_internal_, [this](size_t v) { return assert_existance(v); }, [](IfcUtil::IfcBaseClass* v) { return v->identity(); }) + , byguid_(&byguid_internal_, [this](size_t v) { return assert_existance(v, by_name); }, [](IfcUtil::IfcBaseClass* v) { return v->identity(); }) , byid_(db, "d|") , bytype_(db, "t|") - , byidentity_(&byid_, [this](size_t v) { return assert_existance(v); }, [](IfcUtil::IfcBaseClass* v) { return v->identity(); }) + // @todo by_identity is probably not correct here, this mapping is Name -> Identity, so Fn should have access to full pair? + , byidentity_(&byid_, [this](size_t v) { return assert_existance(v, by_identity); }, [](IfcUtil::IfcBaseClass* v) { return v->identity(); }) +{} + +IfcParse::impl::rocks_db_file_storage::~rocks_db_file_storage() { - rocksdb::Options options; - options.create_if_missing = true; - options.merge_operator.reset(new ConcatenateIdMergeOperator()); - rocksdb::Status status = rocksdb::DB::Open(options, filepath, &db); - if (!status.ok()) { - throw std::runtime_error(status.ToString()); - } + rocksdb::FlushOptions flush_options; + flush_options.allow_write_stall = true; + flush_options.wait = true; // Wait until flush completes. + rocksdb::Status s = db->Flush(flush_options); + assert(s.ok()); + + db->Close(); + delete db; } + IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::instance_by_id(int id) { // @todo rename assert_existance() -> instance_by_id(); - return assert_existance(id); + return assert_existance(id, by_name); } void IfcParse::impl::rocks_db_file_storage::process_deletion_inverse(IfcUtil::IfcBaseClass* inst) diff --git a/src/ifcparse/IfcFile.h b/src/ifcparse/IfcFile.h index 924cd09611..3ec8afdee4 100644 --- a/src/ifcparse/IfcFile.h +++ b/src/ifcparse/IfcFile.h @@ -37,17 +37,18 @@ #include #include -#include "rocksdb/merge_operator.h" - +// #include "rocksdb/merge_operator.h" +/* namespace { // @todo move to a proper place class ConcatenateIdMergeOperator : public rocksdb::AssociativeMergeOperator { public: - virtual bool Merge(const rocksdb::Slice& key, + virtual bool Merge(const rocksdb::Slice&, const rocksdb::Slice* existing_value, const rocksdb::Slice& value, std::string* new_value, - rocksdb::Logger* logger) const override { + rocksdb::Logger*) const override + { if (existing_value) { new_value->assign(existing_value->data(), existing_value->size()); new_value->append(value.data(), value.size()); @@ -62,6 +63,7 @@ namespace { } }; } +*/ namespace IfcParse { @@ -348,7 +350,11 @@ namespace impl { IfcUtil::IfcBaseClass* create(const IfcParse::declaration* decl); }; - struct rocks_db_file_storage { + class rocks_db_file_storage { + public: + rocksdb::DB* db; + IfcParse::IfcFile* file; + // to make sure that instance pointer are constant during file lifetime // cache instances because we want stable pointers // @todo this is silly, but we cannot have the same type, this should be just a pointer then on the IfcFile side? @@ -375,20 +381,18 @@ namespace impl { typedef map_transformer, std::function, std::function< size_t(IfcUtil::IfcBaseClass*)>> entity_by_guid_t; entity_by_guid_t byguid_; - rocksdb::DB* db; - IfcParse::IfcFile* file; - // @todo naming - rocks_db_file_storage(const std::string& filepath, IfcParse::IfcFile* ffile); + rocks_db_file_storage(const std::string& filepath, IfcParse::IfcFile* file); + ~rocks_db_file_storage(); - bool read_schema(const IfcParse::schema_definition*& schema) { - // @todo - schema = nullptr; - return true; - } + bool read_schema(const IfcParse::schema_definition*& schema); + enum instance_ref { + by_name, + by_identity + }; - IfcUtil::IfcBaseClass* assert_existance(size_t instanceId); + IfcUtil::IfcBaseClass* assert_existance(size_t instanceId, instance_ref r); // @todo this could be another map_adapter? class rocksdb_instance_iterator { @@ -396,7 +400,7 @@ namespace impl { rocksdb::Iterator* state_; rocks_db_file_storage* storage_; - static constexpr char prefix_[] = "a|"; + static constexpr char prefix_[] = "i|"; boost::optional read_id_() const { auto sv = state_->key().ToStringView(); @@ -810,29 +814,37 @@ IFC_PARSE_API IfcFile* parse_ifcxml(const std::string& filename); template T* IfcParse::impl::in_memory_file_storage::create() { + IfcUtil::IfcBaseClass* inst = nullptr; if constexpr (std::is_same_v>, IfcParse::entity>) { - return file->addEntity(new T(in_memory_attribute_storage(T::Class().attribute_count())))->as(); + inst = new T(in_memory_attribute_storage(T::Class().attribute_count())); } else if constexpr (std::is_same_v>, IfcParse::type_declaration>) { - return file->addEntity(new T(in_memory_attribute_storage(1)))->as(); + inst = new T(in_memory_attribute_storage(1)); } else { static_assert(false, "Requires and entity or type declaration"); } + inst->file_ = file; + return file->addEntity(inst)->as(); } IfcUtil::IfcBaseClass* IfcParse::impl::in_memory_file_storage::create(const IfcParse::declaration* decl) { + IfcUtil::IfcBaseClass* inst = nullptr; if (auto* ent = decl->as_entity()) { - return file->addEntity(file->schema()->instantiate(decl, in_memory_attribute_storage(ent->attribute_count()))); + inst = file->schema()->instantiate(decl, in_memory_attribute_storage(ent->attribute_count())); } else if (auto* typedecl = decl->as_type_declaration()) { - return file->addEntity(file->schema()->instantiate(decl, in_memory_attribute_storage(1))); + inst = file->schema()->instantiate(decl, in_memory_attribute_storage(1)); } else { throw std::runtime_error("Requires and entity or type declaration"); } + inst->file_ = file; + return file->addEntity(inst); } template T* IfcParse::impl::rocks_db_file_storage::create() { if constexpr (std::is_same_v>, IfcParse::entity> || std::is_same_v>, IfcParse::type_declaration>) { - return file->addEntity(new T(rocks_db_attribute_storage{}))->as(); + auto* inst = new T(rocks_db_attribute_storage{}); + inst->file_ = file; + return file->addEntity(inst)->as(); } else { static_assert(false, "Requires and entity or type declaration"); } @@ -840,7 +852,9 @@ T* IfcParse::impl::rocks_db_file_storage::create() { IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::create(const IfcParse::declaration* decl) { if (decl->as_entity() || decl->as_type_declaration()) { - return file->addEntity(file->schema()->instantiate(decl, rocks_db_attribute_storage(this, "i|"))); + auto* inst = file->schema()->instantiate(decl, rocks_db_attribute_storage{}); + inst->file_ = file; + return file->addEntity(inst); } else { throw std::runtime_error("Requires and entity or type declaration"); } diff --git a/src/ifcparse/IfcHierarchyHelper.h b/src/ifcparse/IfcHierarchyHelper.h index 11a64caaf0..4393cb9089 100644 --- a/src/ifcparse/IfcHierarchyHelper.h +++ b/src/ifcparse/IfcHierarchyHelper.h @@ -434,20 +434,17 @@ class IFC_PARSE_API IfcHierarchyHelper : public IfcParse::IfcFile { aggregate_of_instance::ptr related_objects(new aggregate_of_instance); related_objects->push(related_object); - IfcEntityInstanceData data = IfcEntityInstanceData(in_memory_attribute_storage(T::Class().attribute_count())); - data.set_attribute_value(0, (std::string)IfcParse::IfcGlobalId()); - data.set_attribute_value(1, owner_hist); + T* t = create(&T::Class())->as(); + t->set_attribute_value(0, (std::string)IfcParse::IfcGlobalId()); + t->set_attribute_value(1, owner_hist); int relating_index = 4; int related_index = 5; if (T::Class().name() == "IfcRelContainedInSpatialStructure" || std::is_base_of::value) { // some classes have attributes reversed. std::swap(relating_index, related_index); } - data.set_attribute_value(relating_index, relating_object); - data.set_attribute_value(related_index, related_objects); - - T* t = (T*)Schema::get_schema().instantiate(&T::Class(), std::move(data)); - addEntity(t); + t->set_attribute_value(relating_index, relating_object); + t->set_attribute_value(related_index, related_objects); } } diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index 001446671c..4c6848cb23 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -791,10 +791,21 @@ void IfcParse::impl::rocks_db_file_storage::register_inverse(unsigned id_from, c size_t v = id_from; s.resize(sizeof(size_t)); memcpy(s.data(), &v, sizeof(size_t)); + + /* + // no merges yet, because python client doesn't support them db->Merge( rocksdb::WriteOptions{}, - "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), + , s); + */ + { + std::string current; + 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->Get(rocksdb::ReadOptions{}, key, ¤t); + auto new_val = current + s; + db->Put(rocksdb::WriteOptions{}, key, new_val); + } } void IfcParse::impl::rocks_db_file_storage::unregister_inverse(unsigned id_from, const IfcParse::entity* from_entity, IfcUtil::IfcBaseClass* inst, int attribute_index) { @@ -813,10 +824,28 @@ void IfcParse::impl::rocks_db_file_storage::unregister_inverse(unsigned id_from, void IfcParse::impl::rocks_db_file_storage::add_type_ref(IfcUtil::IfcBaseClass* new_entity) { - size_t v = new_entity->identity(); + if (!new_entity->declaration().as_entity()) { + throw std::runtime_error("Type refs are only supposed to be used for entities"); + } + + size_t v = new_entity->id(); std::string s(sizeof(size_t), ' '); memcpy(s.data(), &v, sizeof(size_t)); - db->Merge(rocksdb::WriteOptions{}, "t|" + std::to_string(new_entity->declaration().index_in_schema()), s); + + // no merges yet, because the python client doesn't support them + // db->Merge(rocksdb::WriteOptions{}, "t|" + std::to_string(new_entity->declaration().index_in_schema()), s); + { + std::string current; + auto key = "t|" + std::to_string(new_entity->declaration().index_in_schema()); + db->Get(rocksdb::ReadOptions{}, key, ¤t); + auto new_val = current + s; + db->Put(rocksdb::WriteOptions{}, key, new_val); + } + + // not only mapping also register type + v = new_entity->declaration().index_in_schema(); + memcpy(s.data(), &v, sizeof(size_t)); + db->Put(rocksdb::WriteOptions{}, "i|" + std::to_string(new_entity->identity()) + "|t", s); } void IfcParse::impl::rocks_db_file_storage::remove_type_ref(IfcUtil::IfcBaseClass* new_entity) @@ -826,11 +855,13 @@ void IfcParse::impl::rocks_db_file_storage::remove_type_ref(IfcUtil::IfcBaseClas if (db->Get(rocksdb::ReadOptions{}, key, &s).ok()) { std::vector 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->identity())); + 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()); db->Put(rocksdb::WriteOptions{}, key, s); } + + db->Delete(rocksdb::WriteOptions{}, "i|" + std::to_string(new_entity->identity()) + "|t"); } namespace { @@ -1032,25 +1063,26 @@ namespace { // Returns a string representation of the entity // Note that this initializes the entity if it is not initialized // -void IfcEntityInstanceData::toString(std::ostream& ss, bool upper, const entity* decl) const { +void IfcEntityInstanceData::toString(void* storage, const IfcParse::declaration* decl, std::size_t identity, std::ostream& ss, bool upper) const { ss.imbue(std::locale::classic()); ss << "("; StringBuilderVisitor vis(ss, upper); - for (size_t i = 0; i < size(); ++i) { + // @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) { if (i != 0) { ss << ","; } - if (has_attribute_value(i)) { - if (decl != nullptr && decl->derived()[i]) { + if (has_attribute_value(storage, decl, identity, i)) { + if (decl != nullptr && decl->as_entity() && decl->as_entity()->derived()[i]) { ss << "*"; } else { ss << "$"; } } else { - apply_visitor(vis, i); + apply_visitor(storage, decl, identity, vis, i); } } ss << ")"; @@ -1132,9 +1164,11 @@ class add_to_instance_list_visitor { class apply_individual_instance_visitor { private: boost::optional attribute_; - IfcEntityInstanceData* data_; int attribute_index_; + const IfcUtil::IfcBaseClass* inst_; + + template void apply_attribute_(T& t, const AttributeValue& attr, int index) const { if (attr.type() == IfcUtil::Argument_ENTITY_INSTANCE) { @@ -1161,8 +1195,8 @@ class apply_individual_instance_visitor { , attribute_index_(idx) {} - apply_individual_instance_visitor(IfcEntityInstanceData* data) - : data_(data) + apply_individual_instance_visitor(const IfcUtil::IfcBaseClass* data) + : inst_(data) {} template @@ -1170,8 +1204,9 @@ class apply_individual_instance_visitor { if (attribute_) { apply_attribute_(t, *attribute_, attribute_index_); } else { - for (size_t i = 0; i < data_->size(); ++i) { - auto attr = data_->get_attribute_value(i); + 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); apply_attribute_(t, attr, (int) i); } } @@ -1180,7 +1215,7 @@ class apply_individual_instance_visitor { template void IfcUtil::IfcBaseClass::set_attribute_value(size_t i, const T& t) { - auto current_attribute = data_.get_attribute_value(i); + auto current_attribute = get_attribute_value(i); if (file_ != nullptr) { // Deregister old attribute guid in file guid map. @@ -1188,8 +1223,11 @@ void IfcUtil::IfcBaseClass::set_attribute_value(size_t i, const T& t) { try { auto guid = (std::string) current_attribute; auto it = file_->internal_guid_map().find(guid); - if (it != file_->internal_guid_map().end() && it->second == this) { - file_->internal_guid_map().erase(it); + if (it != file_->internal_guid_map().end()) { + const std::pair& p = *it; + if (p.second == this) { + file_->internal_guid_map().erase(it); + } } } catch (IfcParse::IfcException& e) { Logger::Error(e); @@ -1200,22 +1238,25 @@ void IfcUtil::IfcBaseClass::set_attribute_value(size_t i, const T& t) { unregister_inverse_visitor visitor(*file_, this); apply_individual_instance_visitor(current_attribute, (int) i).apply(visitor); } - - if constexpr (std::is_pointer_v) { - if (t) { - data_.set_attribute_value(i, t); + { + void* const storage = file_ ? std::visit([](const auto& m) { return (void*)&m; }, file_->storage_) : nullptr; + if constexpr (std::is_pointer_v) { + if (t) { + data_.set_attribute_value(storage, &declaration(), identity(), i, t); + } else { + data_.set_attribute_value(storage, &declaration(), identity(), i, Blank{}); + } } else { - data_.set_attribute_value(i, Blank{}); + data_.set_attribute_value(storage, &declaration(), identity(),i, t); } - } else { - data_.set_attribute_value(i, t); } - auto new_attribute = data_.get_attribute_value(i); + auto new_attribute = get_attribute_value(i); if (file_ != nullptr) { // Register inverse indices in file - register_inverse_visitor visitor(*file_, this); - apply_individual_instance_visitor(new_attribute, (int) i).apply(visitor); + // @todo verify no longer necessary? + // register_inverse_visitor visitor(*file_, this); + // apply_individual_instance_visitor(new_attribute, (int) i).apply(visitor); // Register new attribute guid in guid map if (i == 0 && (file_->ifcroot_type() != nullptr) && this->declaration().is(*file_->ifcroot_type())) { @@ -1225,7 +1266,7 @@ void IfcUtil::IfcBaseClass::set_attribute_value(size_t i, const T& t) { if (it != file_->internal_guid_map().end()) { Logger::Warning("Duplicate guid " + guid); } - file_->internal_guid_map().insert({ guid, file_->instance_by_id(this->id()) }); + file_->internal_guid_map().insert({ guid, this }); } catch (IfcParse::IfcException& e) { Logger::Error(e); } @@ -1257,10 +1298,19 @@ IfcFile::IfcFile(const std::string& path, filetype ty) { // @todo assign in constructor std::get(storage_).file = this; std::get(storage_).read_from_stream(&s, schema_, max_id_); + + // @todo unify these names, it's already confusing enough as it stands + byid_ = decltype(byid_)(&std::get(storage_).byid_); + idenbyid_ = decltype(idenbyid_)(&std::get(storage_).idenbyid_); + byidentity_ = decltype(byidentity_)(&std::get(storage_).byidentity_); } else { // @todo this can only be used for databases that already exist, because otherwise there is no way to specify the schema - storage_ = impl::rocks_db_file_storage(path, this); + storage_.emplace<2>(path, this); std::get(storage_).read_schema(schema_); + + byid_ = decltype(byid_)(&std::get(storage_).byidentity_); + idenbyid_ = decltype(idenbyid_)(&std::get(storage_).byid_); + byidentity_ = decltype(byidentity_)(&std::get(storage_).instance_cache_); } ifcroot_type_ = schema_->declaration_by_name("IfcRoot"); } @@ -1294,8 +1344,17 @@ IfcFile::IfcFile(const IfcParse::schema_definition* schema, filetype ty, const s { if (ty == ifcspf) { storage_.emplace<1>(); + std::get(storage_).file = this; + + byid_ = decltype(byid_)(&std::get(storage_).byid_); + idenbyid_ = decltype(idenbyid_)(&std::get(storage_).idenbyid_); + byidentity_ = decltype(byidentity_)(&std::get(storage_).byidentity_); } else { storage_.emplace<2>(path, this); + + byid_ = decltype(byid_)(&std::get(storage_).byidentity_); + idenbyid_ = decltype(idenbyid_)(&std::get(storage_).byid_); + byidentity_ = decltype(byidentity_)(&std::get(storage_).instance_cache_); } setDefaultHeaderValues(); } @@ -1323,7 +1382,7 @@ void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::IfcSpfSt if (file->header().tryRead()) { try { - schemas = file->header().file_schema().schema_identifiers(); + schemas = file->header().file_schema()->schema_identifiers(); } catch (...) { // Purposely empty catch block } @@ -1402,7 +1461,8 @@ void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::IfcSpfSt if (instance->declaration().is(*ifcroot_type_)) { try { - const std::string guid = instance->data().get_attribute_value(0); + // @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; @@ -1488,10 +1548,10 @@ void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::IfcSpfSt 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"); } else { - byidentity_[idenbyid_[p.first.name_]]->data().set_attribute_value(p.first.index_, it->second); + byidentity_[idenbyid_[p.first.name_]]->data().set_attribute_value(nullptr, nullptr, 0, p.first.index_, it->second); } } else if (auto* inst = boost::get(v)) { - byidentity_[idenbyid_[p.first.name_]]->data().set_attribute_value(p.first.index_, *inst); + byidentity_[idenbyid_[p.first.name_]]->data().set_attribute_value(nullptr, nullptr, 0, p.first.index_, *inst); } } else if (auto* v = boost::get>(&p.second)) { aggregate_of_instance::ptr instances(new aggregate_of_instance); @@ -1508,7 +1568,7 @@ void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::IfcSpfSt instances->push(*inst); } } - byidentity_[idenbyid_[p.first.name_]]->data().set_attribute_value(p.first.index_, instances); + byidentity_[idenbyid_[p.first.name_]]->data().set_attribute_value(nullptr, nullptr, 0, p.first.index_, instances); } else if (auto* v = boost::get>>(&p.second)) { aggregate_of_aggregate_of_instance::ptr instances(new aggregate_of_aggregate_of_instance); for (const auto& vi : *v) { @@ -1527,7 +1587,7 @@ void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::IfcSpfSt } instances->push(inner); } - byidentity_[idenbyid_[p.first.name_]]->data().set_attribute_value(p.first.index_, instances); + byidentity_[idenbyid_[p.first.name_]]->data().set_attribute_value(nullptr, nullptr, 0, p.first.index_, instances); } } @@ -1614,7 +1674,7 @@ void traverse_(IfcUtil::IfcBaseClass* instance, std::set } traversal_visitor visit(visited, list, level + 1, max_level); - apply_individual_instance_visitor(&instance->data()).apply(visit); + apply_individual_instance_visitor(instance).apply(visit); } void traversal_visitor::operator()(IfcUtil::IfcBaseClass* inst, int /* index */) { @@ -1712,16 +1772,42 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id) // container and entity is created. The attribute references // need to be updated to point to instances in this file. IfcFile* other_file = entity->file_; + + 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; - IfcEntityInstanceData we(entity->data()); - new_entity = schema()->instantiate(&entity->declaration(), std::move(we)); - + 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_); + for (size_t i = 0; i < (entity->declaration().as_entity() ? entity->declaration().as_entity()->attribute_count() : 1); ++i) { + entity->data().apply_visitor(other_storage, decl, entity->identity(), [this, i, decl, new_entity, own_storage](const auto& v) { + using U = std::decay_t; + // only need to copy non-instance attribute values, others are assigned below after mapping + if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { + } else { + new_entity->set_attribute_value(i, v); + } + }, i); + } + // In case an entity is added that contains geometry, the unit // information needs to be accounted for for IfcLengthMeasures. double conversion_factor = std::numeric_limits::quiet_NaN(); - for (size_t i = 0; i < new_entity->data().size(); ++i) { - auto attr = new_entity->data().get_attribute_value(i); + 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); IfcUtil::ArgumentType attr_type = attr.type(); IfcParse::declaration* decl = 0; @@ -1741,8 +1827,8 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id) if (eit == entity_file_map_.end()) { throw IfcParse::IfcException("Unable to map instance to file"); } - // We directly use storage set not to trigger inverse recalculation which happens at the end - new_entity->data().set_attribute_value(i, eit->second); + // @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); } else if (attr_type == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) { aggregate_of_instance::ptr instances = attr; aggregate_of_instance::ptr new_instances(new aggregate_of_instance); @@ -1754,7 +1840,7 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id) new_instances->push(eit->second); } - new_entity->data().set_attribute_value(i, new_instances); + new_entity->set_attribute_value(i, new_instances); } else if (attr_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) { aggregate_of_aggregate_of_instance::ptr instances = attr; aggregate_of_aggregate_of_instance::ptr new_instances(new aggregate_of_aggregate_of_instance); @@ -1770,7 +1856,7 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id) new_instances->push(list); } - new_entity->data().set_attribute_value(i, new_instances); + new_entity->set_attribute_value(i, new_instances); } else if ((decl != nullptr) && decl->is(*schema()->declaration_by_name("IfcLengthMeasure"))) { if (boost::math::isnan(conversion_factor)) { std::pair this_file_unit = {nullptr, 1.0}; @@ -1789,13 +1875,13 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id) if (attr_type == IfcUtil::Argument_DOUBLE) { double v = attr; v *= conversion_factor; - new_entity->data().set_attribute_value(i, v); + new_entity->set_attribute_value(i, v); } else if (attr_type == IfcUtil::Argument_AGGREGATE_OF_DOUBLE) { std::vector v = attr; for (std::vector::iterator it = v.begin(); it != v.end(); ++it) { (*it) *= conversion_factor; } - new_entity->data().set_attribute_value(i, v); + new_entity->set_attribute_value(i, v); } else if (attr_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE) { std::vector> v = attr; for (std::vector>::iterator it = v.begin(); it != v.end(); ++it) { @@ -1804,14 +1890,13 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id) (*jt) *= conversion_factor; } } - new_entity->data().set_attribute_value(i, v); + new_entity->set_attribute_value(i, v); } } } // A new entity instance name is generated and // the instance is pointed to this file. - new_entity->file_ = this; if (new_entity->declaration().as_entity() != nullptr) { if (id == -1) { new_entity->as()->set_id(FreshId()); @@ -1829,7 +1914,7 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id) // For subtypes of IfcRoot, the GUID mapping needs to be updated. if (new_entity->declaration().is(*ifcroot_type_)) { try { - const std::string guid = new_entity->data().get_attribute_value(0); + const std::string guid = new_entity->get_attribute_value(0); if (byguid_.find(guid) != byguid_.end()) { std::stringstream ss; ss << "Overwriting entity with guid " << guid; @@ -1884,9 +1969,12 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id) byidentity_.insert({ new_entity->identity(), new_entity }); } + /* + // @todo not needed anymore, because these are now calculated by using baseclass::set() ? if ((ty->as_entity() != nullptr)) { build_inverses_(new_entity); } + */ return new_entity; } @@ -1930,8 +2018,9 @@ void IfcFile::removeEntity(IfcUtil::IfcBaseClass* entity) { continue; } - for (size_t i = 0; i < related_instance->data().size(); ++i) { - auto attr = related_instance->data().get_attribute_value(i); + 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); if (attr.isNull()) { continue; } @@ -1978,8 +2067,8 @@ void IfcFile::removeEntity(IfcUtil::IfcBaseClass* entity) { } } - if (entity->declaration().is(*ifcroot_type_) && !entity->data().get_attribute_value(0).isNull()) { - const std::string global_id = entity->data().get_attribute_value(0); + if (entity->declaration().is(*ifcroot_type_) && !entity->get_attribute_value(0).isNull()) { + const std::string global_id = entity->get_attribute_value(0); auto it = byguid_.find(global_id); if (it != byguid_.end()) { byguid_.erase(it); @@ -2088,12 +2177,14 @@ aggregate_of_instance::ptr IfcFile::instances_by_type_excl_subtypes(const IfcPar } else if constexpr (std::is_same_v, impl::rocks_db_file_storage>) { aggregate_of_instance::ptr ret(new aggregate_of_instance); auto it = x.bytype_.find(t->index_in_schema()); - const auto& s = it->second; - // @todo generalize this, bytype_ should be a map_adapter - std::vector vals(s.size() / sizeof(size_t)); - memcpy(vals.data(), s.data(), s.size()); - for (auto& v : vals) { - ret->push(x.assert_existance(v)); + if (it != x.bytype_.end()) { + const auto& s = it->second; + // @todo generalize this, bytype_ should be a map_adapter + std::vector vals(s.size() / sizeof(size_t)); + memcpy(vals.data(), s.data(), s.size()); + for (auto& v : vals) { + ret->push(x.assert_existance(v, IfcParse::impl::rocks_db_file_storage::by_name)); + } } return ret; } else { @@ -2360,18 +2451,18 @@ void IfcFile::setDefaultHeaderValues() { schema_identifiers.push_back(schema()->name()); } - header().file_description().description(file_description); - header().file_description().implementation_level("2;1"); + header().file_description()->setdescription(file_description); + header().file_description()->setimplementation_level("2;1"); - header().file_name().name(empty_string); - header().file_name().time_stamp(createTimestamp()); - header().file_name().author(string_vector); - header().file_name().organization(string_vector); - header().file_name().preprocessor_version("IfcOpenShell " IFCOPENSHELL_VERSION); - header().file_name().originating_system("IfcOpenShell " IFCOPENSHELL_VERSION); - header().file_name().authorization(empty_string); + 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); - header().file_schema().schema_identifiers(schema_identifiers); + header().file_schema()->setschema_identifiers(schema_identifiers); } std::pair IfcFile::getUnit(const std::string& unit_type) { @@ -2388,16 +2479,16 @@ std::pair IfcFile::getUnit(const std::string& un if (projects && projects->size() == 1) { IfcUtil::IfcBaseClass* project = *projects->begin(); - IfcUtil::IfcBaseClass* unit_assignment = project->data().get_attribute_value( + IfcUtil::IfcBaseClass* unit_assignment = project->get_attribute_value( project->declaration().as_entity()->attribute_index("UnitsInContext")); - aggregate_of_instance::ptr units = unit_assignment->data().get_attribute_value( + aggregate_of_instance::ptr units = unit_assignment->get_attribute_value( 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")) { - const std::string file_unit_type = unit->data().get_attribute_value( + const std::string file_unit_type = unit->get_attribute_value( unit->declaration().as_entity()->attribute_index("UnitType")); if (file_unit_type != unit_type) { @@ -2406,16 +2497,16 @@ std::pair IfcFile::getUnit(const std::string& un IfcUtil::IfcBaseClass* siunit = 0; if (unit->declaration().is("IfcConversionBasedUnit")) { - IfcUtil::IfcBaseClass* mu = unit->data().get_attribute_value( + IfcUtil::IfcBaseClass* mu = unit->get_attribute_value( unit->declaration().as_entity()->attribute_index("ConversionFactor")); - IfcUtil::IfcBaseClass* vlc = mu->data().get_attribute_value( + IfcUtil::IfcBaseClass* vlc = mu->get_attribute_value( mu->declaration().as_entity()->attribute_index("ValueComponent")); - IfcUtil::IfcBaseClass* unc = mu->data().get_attribute_value( + IfcUtil::IfcBaseClass* unc = mu->get_attribute_value( mu->declaration().as_entity()->attribute_index("UnitComponent")); - return_value.second *= static_cast(vlc->data().get_attribute_value(0)); + return_value.second *= static_cast(vlc->get_attribute_value(0)); return_value.first = unit; if (unc->declaration().is("IfcSIUnit")) { @@ -2427,7 +2518,7 @@ std::pair IfcFile::getUnit(const std::string& un } if (siunit != nullptr) { - AttributeValue prefix = siunit->data().get_attribute_value( + AttributeValue prefix = siunit->get_attribute_value( siunit->declaration().as_entity()->attribute_index("Prefix")); if (!prefix.isNull()) { @@ -2458,7 +2549,7 @@ void IfcParse::IfcFile::build_inverses_(IfcUtil::IfcBaseClass* inst) { } }; - apply_individual_instance_visitor(&inst->data()).apply(fn); + apply_individual_instance_visitor(inst).apply(fn); } void IfcParse::IfcFile::build_inverses() { @@ -2494,11 +2585,13 @@ std::atomic_uint32_t IfcUtil::IfcBaseClass::counter_(0); // bool IfcParse::IfcFile::guid_map_ = true; void IfcUtil::IfcBaseClass::unset_attribute_value(size_t index) { - data_.set_attribute_value(index, Blank{}); + void* storage = file_ ? std::visit([](const auto& m) { return (void*)&m; }, file_->storage_) : nullptr; + data_.set_attribute_value(storage, &declaration(), identity(), index, Blank{}); } AttributeValue IfcUtil::IfcBaseClass::get_attribute_value(size_t index) const { - return data_.get_attribute_value(index); + void* storage = file_ ? std::visit([](const auto& m) { return (void*)&m; }, file_->storage_) : nullptr; + return data_.get_attribute_value(storage, &declaration(), identity(), index); } void IfcUtil::IfcBaseClass::toString(std::ostream& out, bool upper) const @@ -2512,57 +2605,48 @@ void IfcUtil::IfcBaseClass::toString(std::ostream& out, bool upper) const } else { out << declaration().name(); } - data().toString(out, upper, ent); + void* storage = file_ ? std::visit([](const auto& m) { return (void*)&m; }, file_->storage_) : nullptr; + data().toString(storage, &declaration(), identity(), out, upper); } +/* IfcEntityInstanceData::IfcEntityInstanceData(const IfcEntityInstanceData& data) : storage_(data.size()) { - for (size_t i = 0; i < data.size(); ++i) { - data.apply_visitor([this, i](const auto& v) { - using U = std::decay_t; - if constexpr (std::is_same_v) { - // @todo why did we ever choose shared_ptrs for these - // aggregates? Now we need to explicit copies. - aggregate_of_instance::ptr v2(new aggregate_of_instance); - if (v) { - v2->reserve(v->size()); - for (auto& i : *v) { - v2->push(i); - } - } - set_attribute_value(i, v2); - } else if constexpr (std::is_same_v) { - aggregate_of_aggregate_of_instance::ptr v2(new aggregate_of_aggregate_of_instance); - if (v) { - for (auto& i : *v) { - v2->push(i); - } - } - set_attribute_value(i, v2); - } else { - set_attribute_value(i, v); - } - }, i); - } + } +*/ -AttributeValue IfcEntityInstanceData::get_attribute_value(size_t index) const +AttributeValue IfcEntityInstanceData::get_attribute_value(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const { - return std::visit([index](const auto& x) { + return std::visit([this, storage, decl, identity, index](const auto& x) { if constexpr (std::is_same_v, in_memory_attribute_storage>) { return AttributeValue(&x, (uint8_t)index); } else if constexpr (std::is_same_v, rocks_db_attribute_storage>) { // @todo - return AttributeValue{}; + return AttributeValue(decl->schema(), (IfcParse::impl::rocks_db_file_storage*) storage, identity, index); } else { return AttributeValue{}; } }, storage_); } +bool IfcParse::impl::rocks_db_file_storage::read_schema(const IfcParse::schema_definition*& schema) { + std::string value; + auto key = "h|file_schema|0"; + db->Get(rocksdb::ReadOptions{}, key, &value); + std::vector strings; + if (::impl::deserialize(this, value, strings) && strings.size() == 1) { + schema = schema_by_name(strings[0]); + return true; + } + return false; +} + + template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value(size_t index, const Blank& value); +template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value(size_t index, const Derived& value); template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value(size_t index, const int& value); template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value(size_t index, const bool& value); template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value(size_t index, const boost::logic::tribool& value); @@ -2581,6 +2665,7 @@ template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value(size_t index, const aggregate_of_aggregate_of_instance::ptr& value); template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value(const std::string& name, const Blank& value); +template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value(const std::string& name, const Derived& value); template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value(const std::string& name, const int& value); template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value(const std::string& name, const bool& value); template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value(const std::string& name, const boost::logic::tribool& value); diff --git a/src/ifcparse/IfcSIPrefix.cpp b/src/ifcparse/IfcSIPrefix.cpp index 48b87fb6f6..09a768102a 100644 --- a/src/ifcparse/IfcSIPrefix.cpp +++ b/src/ifcparse/IfcSIPrefix.cpp @@ -120,7 +120,8 @@ double IfcParse::get_SI_equivalent(typename Schema::IfcNamedUnit* named_unit) { if (component->declaration().is(Schema::IfcSIUnit::Class())) { si_unit = component->template as(); typename Schema::IfcValue* value = factor->ValueComponent(); - scale = value->data().get_attribute_value(0); + // @todo provide sufficient context + scale = value->data().get_attribute_value(nullptr, nullptr, 0, 0); } } else if (named_unit->declaration().is(Schema::IfcSIUnit::Class())) { si_unit = named_unit->template as(); diff --git a/src/ifcparse/IfcSpfHeader.cpp b/src/ifcparse/IfcSpfHeader.cpp index ab2830e396..71661cb64a 100644 --- a/src/ifcparse/IfcSpfHeader.cpp +++ b/src/ifcparse/IfcSpfHeader.cpp @@ -24,15 +24,8 @@ static const char* const ISO_10303_21 = "ISO-10303-21"; static const char* const HEADER = "HEADER"; -static const char* const FILE_DESCRIPTION = "FILE_DESCRIPTION"; -static const char* const FILE_NAME = "FILE_NAME"; -static const char* const FILE_SCHEMA = "FILE_SCHEMA"; static const char* const ENDSEC = "ENDSEC"; static const char* const DATA = "DATA"; -// The following header entities are not normally encountered in IFC files and are not parsed. -// static const char * const FILE_POPULATION = "FILE_POPULATION"; -// static const char * const SECTION_LANGUAGE = "SECTION_LANGUAGE"; -// static const char * const SECTION_CONTEXT = "SECTION_CONTEXT"; using namespace IfcParse; @@ -52,20 +45,6 @@ namespace { } } -HeaderEntity::HeaderEntity(const char* const datatype, size_t size, IfcFile* file) - : datatype_(datatype) - , file_(file) - , data_((file && file->storage_.index() == 1) - ? read_from_spf_file(file, size) - : (file && file->storage_.index() == 2) - ? IfcEntityInstanceData(rocks_db_attribute_storage(&std::get(file->storage_), "h|")) - : IfcEntityInstanceData(in_memory_attribute_storage(size)) - ) -{} - -HeaderEntity::~HeaderEntity() { -} - void IfcSpfHeader::readSemicolon() { std::visit([](auto& m) { if constexpr (std::is_same_v, IfcParse::impl::in_memory_file_storage>) { @@ -78,18 +57,6 @@ void IfcSpfHeader::readSemicolon() { }, file_->storage_); } -void IfcSpfHeader::readParen() { - std::visit([](auto& m) { - if constexpr (std::is_same_v, IfcParse::impl::in_memory_file_storage>) { - if (!TokenFunc::isOperator(m.tokens->Next(), '(')) { - throw IfcException(std::string("Expected (")); - } - } else { - // std::unreachable(); - } - }, file_->storage_); -} - void IfcSpfHeader::readTerminal(const std::string& term, Trail trail) { std::visit([this, term, trail](auto& m) { if constexpr (std::is_same_v, IfcParse::impl::in_memory_file_storage>) { @@ -98,8 +65,6 @@ void IfcSpfHeader::readTerminal(const std::string& term, Trail trail) { } if (trail == TRAILING_SEMICOLON) { readSemicolon(); - } else if (trail == TRAILING_PAREN) { - readParen(); } } else { // std::unreachable(); @@ -107,6 +72,29 @@ void IfcSpfHeader::readTerminal(const std::string& term, Trail trail) { }, file_->storage_); } +IfcParse::IfcSpfHeader::IfcSpfHeader(IfcParse::IfcFile* file) + : file_(file), + file_description_(nullptr), + file_name_(nullptr), + file_schema_(nullptr) +{ + if (file == nullptr) { + // overwritten later in IfcFile::setDefaultHeaderValues() when we know the schema identifier + file_description_ = new Header_section_schema::file_description({}, ""); + file_description_->file_ = file_; + file_name_ = new Header_section_schema::file_name("", "", {}, {}, "", "", ""); + file_name_->file_ = file_; + file_schema_ = new Header_section_schema::file_schema({}); + file_schema_->file_ = file_; + } +} + +IfcParse::IfcSpfHeader::~IfcSpfHeader() { + delete file_schema_; + delete file_name_; + delete file_description_; +} + void IfcSpfHeader::read() { readTerminal(ISO_10303_21, TRAILING_SEMICOLON); readTerminal(HEADER, TRAILING_SEMICOLON); @@ -121,22 +109,22 @@ void IfcSpfHeader::read() { // // ISO 10303-21 Second edition 2002-01-15 p. 16 - readTerminal(FILE_DESCRIPTION, NONE); + readTerminal(Header_section_schema::file_description::Class().name_uc(), NONE); delete file_description_; - // readParen(); - file_description_ = new FileDescription(file_); + file_description_ = new Header_section_schema::file_description(read_from_spf_file(file_, Header_section_schema::file_description::Class().attribute_count())); + file_description_->file_ = file_; readSemicolon(); - readTerminal(FILE_NAME, NONE); + readTerminal(Header_section_schema::file_name::Class().name_uc(), NONE); delete file_name_; - // readParen(); - file_name_ = new FileName(file_); + file_name_ = new Header_section_schema::file_name(read_from_spf_file(file_, Header_section_schema::file_name::Class().attribute_count())); + file_name_->file_ = file_; readSemicolon(); - readTerminal(FILE_SCHEMA, NONE); + readTerminal(Header_section_schema::file_schema::Class().name_uc(), NONE); delete file_schema_; - // readParen(); - file_schema_ = new FileSchema(file_); + file_schema_ = new Header_section_schema::file_schema(read_from_spf_file(file_, Header_section_schema::file_schema::Class().attribute_count())); + file_schema_->file_ = file_; readSemicolon(); } @@ -155,11 +143,14 @@ void IfcSpfHeader::write(std::ostream& out) const { << "\n"; out << HEADER << ";" << "\n"; - out << file_description().toString(true) << ";" + file_description()->toString(out, true); + out << ";" << "\n"; - out << file_name().toString(true) << ";" + file_name()->toString(out, true); + out << ";" << "\n"; - out << file_schema().toString(true) << ";" + file_schema()->toString(out, true); + out << ";" << "\n"; out << ENDSEC << ";" << "\n"; @@ -167,48 +158,93 @@ void IfcSpfHeader::write(std::ostream& out) const { << "\n"; } -const FileDescription& IfcSpfHeader::file_description() const { +const Header_section_schema::file_description* IfcParse::IfcSpfHeader::file_description() const { if (file_description_ == nullptr) { - throw IfcException("File description not set"); + std::visit([this](auto& m) { + if constexpr (std::is_same_v, impl::rocks_db_file_storage>) { + file_description_ = new Header_section_schema::file_description(rocks_db_attribute_storage{}); + } else if constexpr (std::is_same_v, impl::in_memory_file_storage>) { + file_description_ = new Header_section_schema::file_description(in_memory_attribute_storage(Header_section_schema::file_description::Class().attribute_count())); + } + }, file_->storage_); + file_description_->file_ = file_; } - return *file_description_; + return file_description_; } -const FileName& IfcSpfHeader::file_name() const { +const Header_section_schema::file_name* IfcParse::IfcSpfHeader::file_name() const { if (file_name_ == nullptr) { - throw IfcException("File name not set"); + std::visit([this](auto& m) { + if constexpr (std::is_same_v, impl::rocks_db_file_storage>) { + file_name_ = new Header_section_schema::file_name(rocks_db_attribute_storage{}); + } else if constexpr (std::is_same_v, impl::in_memory_file_storage>) { + file_name_ = new Header_section_schema::file_name(in_memory_attribute_storage(Header_section_schema::file_name::Class().attribute_count())); + } + }, file_->storage_); + file_name_->file_ = file_; } - return *file_name_; + + return file_name_; } -const FileSchema& IfcSpfHeader::file_schema() const { +const Header_section_schema::file_schema* IfcParse::IfcSpfHeader::file_schema() const { if (file_schema_ == nullptr) { - throw IfcException("File schema not set"); + std::visit([this](auto& m) { + if constexpr (std::is_same_v, impl::rocks_db_file_storage>) { + file_schema_ = new Header_section_schema::file_schema(rocks_db_attribute_storage{}); + } else if constexpr (std::is_same_v, impl::in_memory_file_storage>) { + file_schema_ = new Header_section_schema::file_schema(in_memory_attribute_storage(Header_section_schema::file_schema::Class().attribute_count())); + } + }, file_->storage_); + file_schema_->file_ = file_; } - return *file_schema_; + + return file_schema_; } -FileDescription& IfcSpfHeader::file_description() { +Header_section_schema::file_description* IfcParse::IfcSpfHeader::file_description() { if (file_description_ == nullptr) { - file_description_ = new FileDescription(file_); + std::visit([this](auto& m) { + if constexpr (std::is_same_v, impl::rocks_db_file_storage>) { + file_description_ = new Header_section_schema::file_description(rocks_db_attribute_storage{}); + } else if constexpr (std::is_same_v, impl::in_memory_file_storage>) { + file_description_ = new Header_section_schema::file_description(in_memory_attribute_storage(Header_section_schema::file_description::Class().attribute_count())); + } + }, file_->storage_); + file_description_->file_ = file_; } - return *file_description_; + + return file_description_; } -FileName& IfcSpfHeader::file_name() { +Header_section_schema::file_name* IfcParse::IfcSpfHeader::file_name() { if (file_name_ == nullptr) { - file_name_ = new FileName(file_); + std::visit([this](auto& m) { + if constexpr (std::is_same_v, impl::rocks_db_file_storage>) { + file_name_ = new Header_section_schema::file_name(rocks_db_attribute_storage{}); + } else if constexpr (std::is_same_v, impl::in_memory_file_storage>) { + file_name_ = new Header_section_schema::file_name(in_memory_attribute_storage(Header_section_schema::file_name::Class().attribute_count())); + } + }, file_->storage_); + file_name_->file_ = file_; } - return *file_name_; + + return file_name_; } -FileSchema& IfcSpfHeader::file_schema() { +Header_section_schema::file_schema* IfcParse::IfcSpfHeader::file_schema() { if (file_schema_ == nullptr) { - file_schema_ = new FileSchema(file_); + std::visit([this](auto& m) { + if constexpr (std::is_same_v, impl::rocks_db_file_storage>) { + file_schema_ = new Header_section_schema::file_schema(rocks_db_attribute_storage{}); + } else if constexpr (std::is_same_v, impl::in_memory_file_storage>) { + file_schema_ = new Header_section_schema::file_schema(in_memory_attribute_storage(Header_section_schema::file_schema::Class().attribute_count())); + } + }, file_->storage_); + file_schema_->file_ = file_; } - return *file_schema_; + + return file_schema_; } -FileDescription::FileDescription(IfcFile* file) : HeaderEntity(FILE_DESCRIPTION, 2, file) {} -FileName::FileName(IfcFile* file) : HeaderEntity(FILE_NAME, 7, file) {} -FileSchema::FileSchema(IfcFile* file) : HeaderEntity(FILE_SCHEMA, 1, file) {} +static auto& _ = Header_section_schema::get_schema(); diff --git a/src/ifcparse/IfcSpfHeader.h b/src/ifcparse/IfcSpfHeader.h index f357c11230..c036bb84fb 100644 --- a/src/ifcparse/IfcSpfHeader.h +++ b/src/ifcparse/IfcSpfHeader.h @@ -22,115 +22,29 @@ #include "ifc_parse_api.h" #include "IfcEntityInstanceData.h" +#include "Header_section_schema.h" namespace IfcParse { - class IfcFile; -class IFC_PARSE_API HeaderEntity { - private: - const char* const datatype_; - IfcFile* file_; - - HeaderEntity(const HeaderEntity&); //N/A - HeaderEntity& operator=(const HeaderEntity&); //N/A - protected: - IfcEntityInstanceData data_; - - HeaderEntity(const char* const datatype, size_t size, IfcParse::IfcFile* file); - virtual ~HeaderEntity(); - - public: - virtual size_t getArgumentCount() const { - return data_.size(); - } - - AttributeValue getArgument(size_t index) const { - return data_.get_attribute_value(index); - } - - std::string toString(bool upper = false) const { - std::stringstream stream; - stream << datatype_; - data_.toString(stream, upper); - return stream.str(); - } -}; - -class IFC_PARSE_API FileDescription : public HeaderEntity { - public: - explicit FileDescription(IfcFile* = 0); - - std::vector description() const { return data_.get_attribute_value(0); } - std::string implementation_level() const { return data_.get_attribute_value(1); } - - void description(const std::vector& value) { data_.set_attribute_value(0, value); } - void implementation_level(const std::string& value) { data_.set_attribute_value(1, value); } -}; - -class IFC_PARSE_API FileName : public HeaderEntity { - public: - explicit FileName(IfcFile* = 0); - - std::string name() const { return data_.get_attribute_value(0); } - std::string time_stamp() const { return data_.get_attribute_value(1); } - std::vector author() const { return data_.get_attribute_value(2); } - std::vector organization() const { return data_.get_attribute_value(3); } - std::string preprocessor_version() const { return data_.get_attribute_value(4); } - std::string originating_system() const { return data_.get_attribute_value(5); } - std::string authorization() const { return data_.get_attribute_value(6); } - - void name(const std::string& value) { data_.set_attribute_value(0, value); } - void time_stamp(const std::string& value) { data_.set_attribute_value(1, value); } - void author(const std::vector& value) { data_.set_attribute_value(2, value); } - void organization(const std::vector& value) { data_.set_attribute_value(3, value); } - void preprocessor_version(const std::string& value) { data_.set_attribute_value(4, value); } - void originating_system(const std::string& value) { data_.set_attribute_value(5, value); } - void authorization(const std::string& value) { data_.set_attribute_value(6, value); } -}; - -class IFC_PARSE_API FileSchema : public HeaderEntity { - public: - explicit FileSchema(IfcFile* = 0); - - std::vector schema_identifiers() const { return data_.get_attribute_value(0); } - - void schema_identifiers(const std::vector& value) { data_.set_attribute_value(0, value); } -}; +class IfcFile; class IFC_PARSE_API IfcSpfHeader { private: IfcFile* file_; - FileDescription* file_description_; - FileName* file_name_; - FileSchema* file_schema_; - void readParen(); + mutable Header_section_schema::file_description* file_description_; + mutable Header_section_schema::file_name* file_name_; + mutable Header_section_schema::file_schema* file_schema_; void readSemicolon(); enum Trail { TRAILING_SEMICOLON, - TRAILING_PAREN, NONE }; void readTerminal(const std::string& term, Trail trail); public: - explicit IfcSpfHeader(IfcParse::IfcFile* file = nullptr) - : file_(file), - file_description_(0), - file_name_(0), - file_schema_(0) - { - if (file == nullptr) { - file_description_ = new FileDescription(file_); - file_name_ = new FileName(file_); - file_schema_ = new FileSchema(file_); - } - } + explicit IfcSpfHeader(IfcParse::IfcFile* file = nullptr); - ~IfcSpfHeader() { - delete file_schema_; - delete file_name_; - delete file_description_; - } + ~IfcSpfHeader(); IfcParse::IfcFile* file() { return file_; } void file(IfcParse::IfcFile* file) { file_ = file; } @@ -140,13 +54,13 @@ class IFC_PARSE_API IfcSpfHeader { void write(std::ostream& out) const; - const FileDescription& file_description() const; - const FileName& file_name() const; - const FileSchema& file_schema() const; + const Header_section_schema::file_description* file_description() const; + const Header_section_schema::file_name* file_name() const; + const Header_section_schema::file_schema* file_schema() const; - FileDescription& file_description(); - FileName& file_name(); - FileSchema& file_schema(); + Header_section_schema::file_description* file_description(); + Header_section_schema::file_name* file_name(); + Header_section_schema::file_schema* file_schema(); }; } // namespace IfcParse diff --git a/src/ifcparse/IfcUtil.cpp b/src/ifcparse/IfcUtil.cpp index 2f65218da2..7aab44d391 100644 --- a/src/ifcparse/IfcUtil.cpp +++ b/src/ifcparse/IfcUtil.cpp @@ -209,7 +209,7 @@ IfcUtil::IfcBaseEntity::IfcBaseEntity(IfcEntityInstanceData&& data) void IfcUtil::IfcBaseEntity::populate_derived() { for (auto it = declaration().as_entity()->derived().begin(); it != declaration().as_entity()->derived().end(); ++it) { if (*it) { - this->data().set_attribute_value( + set_attribute_value( std::distance(declaration().as_entity()->derived().begin(), it), Derived{} ); @@ -224,7 +224,7 @@ AttributeValue IfcUtil::IfcBaseEntity::get(const std::string& name) const size_t idx = 0; for (; iter != attrs.end(); ++iter, ++idx) { if ((*iter)->name() == name) { - return data().get_attribute_value(idx); + return get_attribute_value(idx); } } throw IfcParse::IfcException(name + " not found on " + declaration().name()); diff --git a/src/ifcparse/parse_ifcxml.cpp b/src/ifcparse/parse_ifcxml.cpp index 9aec98007d..4887654b9f 100644 --- a/src/ifcparse/parse_ifcxml.cpp +++ b/src/ifcparse/parse_ifcxml.cpp @@ -279,7 +279,7 @@ static void end_element(void* user, const xmlChar* tag) { } */ // @todo - // back.inst()->data().set_attribute_value(back.idx(), elems); + // back.inst()->set_attribute_value(back.idx(), elems); } if (state->dialect == ifcxml_dialect_ifc2x3 && state->stack.back().ntype() == stack_node::node_instance) { @@ -325,28 +325,28 @@ static void process_characters(void* user, const xmlChar* character, int len) { if (!val.empty()) { // type declaration always at idx 0 visit_any([&state](auto& v) { - state->stack.back().inst()->data().set_attribute_value(0, v); + state->stack.back().inst()->set_attribute_value(0, v); }, val); } } else if (state_type == stack_node::node_header_entry) { const std::string tagname = boost::replace_all_copy(state->stack.back().tagname(), "ex:", ""); auto& header = state->file->header(); if (tagname == "name") { - header.file_name().name(txt); + header.file_name()->setname(txt); } else if (tagname == "time_stamp") { - header.file_name().time_stamp(txt); + header.file_name()->settime_stamp(txt); } else if (tagname == "author") { - header.file_name().author({txt}); + header.file_name()->setauthor({txt}); } else if (tagname == "organization") { - header.file_name().organization({txt}); + header.file_name()->setorganization({txt}); } else if (tagname == "preprocessor_version") { - header.file_name().preprocessor_version(txt); + header.file_name()->setpreprocessor_version(txt); } else if (tagname == "originating_system") { - header.file_name().originating_system(txt); + header.file_name()->setoriginating_system(txt); } else if (tagname == "authorization") { - header.file_name().authorization(txt); + header.file_name()->setauthorisation(txt); } else if (tagname == "documentation") { - header.file_description().description({txt}); + header.file_description()->setdescription({txt}); } else { Logger::Error("Unrecognized header entry " + tagname); } @@ -531,7 +531,7 @@ static void start_element(void* user, const xmlChar* tag, const xmlChar** attrs) IfcUtil::IfcBaseClass* inst; auto inst_ = create_instance(decl); instance_to_attribute(inst_, state->stack.back().idx(), inst); - // state->stack.back().inst()->data().set_attribute_value(state->stack.back().idx(), attr); + // state->stack.back().inst()->set_attribute_value(state->stack.back().idx(), attr); state->stack.push_back(stack_node::instance(id, inst)); } else if (state_type == stack_node::node_aggregate) { @@ -592,7 +592,7 @@ static void start_element(void* user, const xmlChar* tag, const xmlChar** attrs) if (inst != nullptr) { int idx = (*found)->entity_reference()->attribute_index( (*found)->attribute_reference()); - inst->data().set_attribute_value(idx, state->stack.back().inst()); + inst->set_attribute_value(idx, state->stack.back().inst()); state->stack.push_back(stack_node::instance(id, inst)); } else { Logger::Error("Unknown attribute " + tagname); @@ -663,12 +663,12 @@ static void start_element(void* user, const xmlChar* tag, const xmlChar** attrs) int idx = state->stack.back().inv_attr()->entity_reference()->attribute_index( state->stack.back().inv_attr()->attribute_reference()); if (inst != nullptr) { - inst->data().set_attribute_value(idx, state->stack.back().inst()); + inst->set_attribute_value(idx, state->stack.back().inst()); } else { Logger::Error("Internal error, inverse attribute not processed"); } } else if (state_type == stack_node::node_instance_attribute) { - state->stack.back().inst()->data().set_attribute_value(state->stack.back().idx(), inst); + state->stack.back().inst()->set_attribute_value(state->stack.back().idx(), inst); } if (entity == nullptr) { diff --git a/src/ifcparse/rocksdb_map_adapter.h b/src/ifcparse/rocksdb_map_adapter.h index 44ffbbb592..49f8b58339 100644 --- a/src/ifcparse/rocksdb_map_adapter.h +++ b/src/ifcparse/rocksdb_map_adapter.h @@ -34,18 +34,14 @@ template <> struct DefaultCodec { std::string encode(const size_t& v) const { std::string s(sizeof(v), 0); - size_t temp = v; - for (size_t i = 0; i < sizeof(v); i++) { - s[sizeof(v) - i - 1] = static_cast(temp & 0xFF); - temp >>= 8; - } + memcpy(s.data(), &v, sizeof(v)); return s; } size_t decode(const std::string& s) const { size_t v = 0; - for (size_t i = 0; i < s.size(); i++) { - v = (v << 8) | static_cast(s[i]); - } + // @todo take min of sizeof(v), len(s) + // @todo unify all serialization primitives + memcpy(&v, s.data(), sizeof(v)); return v; } }; diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index b46035e41f..7733889648 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -508,7 +508,7 @@ namespace { continue; } IfcUtil::IfcBaseClass* v = ((IfcUtil::IfcBaseEntity*) prop)->get("NominalValue"); - auto value = v->data().get_attribute_value(0); + auto value = v->get_attribute_value(0); if (value.type() == IfcUtil::Argument_STRING) { std::string v_str = value; *output_it++ = string_property{ pset_name, name, v_str }; diff --git a/src/serializers/schema_dependent/XmlSerializer.cpp b/src/serializers/schema_dependent/XmlSerializer.cpp index 3aefa71d7a..8288a09e19 100644 --- a/src/serializers/schema_dependent/XmlSerializer.cpp +++ b/src/serializers/schema_dependent/XmlSerializer.cpp @@ -106,7 +106,7 @@ boost::optional format_attribute(ifcopenshell::geometry::abstract_m IfcUtil::IfcBaseClass* e = argument; if (!e->declaration().as_entity()) { IfcUtil::IfcBaseType* f = e->as(); - value = format_attribute(mapping, f->data().get_attribute_value(0), f->data().get_attribute_value(0).type(), argument_name); + value = format_attribute(mapping, f->get_attribute_value(0), f->get_attribute_value(0).type(), argument_name); } else if (e->declaration().is(IfcSchema::IfcSIUnit::Class()) || e->declaration().is(IfcSchema::IfcConversionBasedUnit::Class())) { // Some string concatenation to have a unit name as a XML attribute. @@ -154,12 +154,12 @@ ptree* format_entity_instance(ifcopenshell::geometry::abstract_mapping* mapping, const unsigned n = instance->declaration().as_entity()->attribute_count(); for (unsigned i = 0; i < n; ++i) { try { - instance->data().get_attribute_value(i); + instance->get_attribute_value(i); } catch (const std::exception&) { Logger::Error("Expected " + boost::lexical_cast(n) + " attributes for:", instance); break; } - auto argument = instance->data().get_attribute_value(i); + auto argument = instance->get_attribute_value(i); if (argument.isNull()) continue; std::string argument_name = instance->declaration().as_entity()->attribute_by_index(i)->name(); @@ -168,7 +168,7 @@ ptree* format_entity_instance(ifcopenshell::geometry::abstract_mapping* mapping, if (argument_name_it != POSTFIX_SCHEMA(argument_name_map).end()) { argument_name = argument_name_it->second; } - const IfcUtil::ArgumentType argument_type = instance->data().get_attribute_value(i).type(); + const IfcUtil::ArgumentType argument_type = instance->get_attribute_value(i).type(); const std::string qualified_name = instance->declaration().name() + "." + argument_name; boost::optional value; @@ -559,20 +559,20 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() { }; // Write the SPF header as XML nodes. - BOOST_FOREACH(const std::string & s, catch_exceptions([this]() { return file->header().file_description().description(); })) { + BOOST_FOREACH(const std::string & s, catch_exceptions([this]() { return file->header().file_description()->description(); })) { header.add_child("file_description.description", ptree(s)); } - BOOST_FOREACH(const std::string& s, catch_exceptions([this]() { return file->header().file_name().author(); })) { + BOOST_FOREACH(const std::string& s, catch_exceptions([this]() { return file->header().file_name()->author(); })) { header.add_child("file_name.author", ptree(s)); } - BOOST_FOREACH(const std::string& s, catch_exceptions([this]() { return file->header().file_name().organization(); })) { + BOOST_FOREACH(const std::string& s, catch_exceptions([this]() { return file->header().file_name()->organization(); })) { header.add_child("file_name.organization", ptree(s)); } - BOOST_FOREACH(const std::string& s, catch_exceptions([this]() { return file->header().file_schema().schema_identifiers(); })) { + BOOST_FOREACH(const std::string& s, catch_exceptions([this]() { return file->header().file_schema()->schema_identifiers(); })) { header.add_child("file_schema.schema_identifiers", ptree(s)); } try { - header.put("file_description.implementation_level", file->header().file_description().implementation_level()); + header.put("file_description.implementation_level", file->header().file_description()->implementation_level()); } catch (const IfcParse::IfcException& ex) { std::stringstream ss; @@ -580,7 +580,7 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() { Logger::Message(Logger::LOG_ERROR, ss.str()); } try { - header.put("file_name.name", file->header().file_name().name()); + header.put("file_name.name", file->header().file_name()->name()); } catch (const IfcParse::IfcException& ex) { std::stringstream ss; @@ -588,7 +588,7 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() { Logger::Message(Logger::LOG_ERROR, ss.str()); } try { - header.put("file_name.time_stamp", file->header().file_name().time_stamp()); + header.put("file_name.time_stamp", file->header().file_name()->time_stamp()); } catch (const IfcParse::IfcException& ex) { std::stringstream ss; @@ -596,7 +596,7 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() { Logger::Message(Logger::LOG_ERROR, ss.str()); } try { - header.put("file_name.preprocessor_version", file->header().file_name().preprocessor_version()); + header.put("file_name.preprocessor_version", file->header().file_name()->preprocessor_version()); } catch (const IfcParse::IfcException& ex) { std::stringstream ss; @@ -604,7 +604,7 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() { Logger::Message(Logger::LOG_ERROR, ss.str()); } try { - header.put("file_name.originating_system", file->header().file_name().originating_system()); + header.put("file_name.originating_system", file->header().file_name()->originating_system()); } catch (const IfcParse::IfcException& ex) { std::stringstream ss; @@ -612,7 +612,8 @@ void POSTFIX_SCHEMA(XmlSerializer)::finalize() { Logger::Message(Logger::LOG_ERROR, ss.str()); } try { - header.put("file_name.authorization", file->header().file_name().authorization()); + // @nb inconsistent spelling + header.put("file_name.authorization", file->header().file_name()->authorisation()); } catch (const IfcParse::IfcException& ex) { std::stringstream ss; diff --git a/win/build-deps.cmd b/win/build-deps.cmd index 93b6935072..5e2cf7e3d3 100644 --- a/win/build-deps.cmd +++ b/win/build-deps.cmd @@ -565,8 +565,9 @@ call :GitCloneAndCheckoutRevision https://gitlab.com/libeigen/eigen.git "%DEPEND :rocksdb set DEPENDENCY_NAME=rocksdb -set DEPENDENCY_DIR=%INSTALL_DIR%\%DEPENDENCY_NAME% -call :GitCloneAndCheckoutRevision https://github.com/facebook/rocksdb "%DEPENDENCY_DIR%" v9.9.3 +set DEPENDENCY_DIR=%DEPS_DIR%\%DEPENDENCY_NAME% +:: this is a 3y old version due to conda-forge's python-rocksdb depending on v6 +call :GitCloneAndCheckoutRevision https://github.com/facebook/rocksdb "%DEPENDENCY_DIR%" v6.29.5 IF NOT %ERRORLEVEL%==0 GOTO :Error cd "%DEPENDENCY_DIR%" call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\rocksdb" ^