diff --git a/src/ifcopenshell-python/ifcopenshell/express/implementation.py b/src/ifcopenshell-python/ifcopenshell/express/implementation.py index 24123532ba..b19e2cf23a 100644 --- a/src/ifcopenshell-python/ifcopenshell/express/implementation.py +++ b/src/ifcopenshell-python/ifcopenshell/express/implementation.py @@ -41,6 +41,17 @@ class Implementation(codegen.Base): write = lambda str, **kwargs: enumeration_functions.append(str % kwargs) + collections_by_type = ( + ("entity", mapping.schema.entities), + ("type_declaration", mapping.schema.simpletypes), + ("select_type", mapping.schema.selects), + ("enumeration_type", mapping.schema.enumerations), + ) + self.names = [] + for _, collection in collections_by_type: + self.names.extend(collection.keys()) + self.names.sort(key=str.lower) + for name, enum in mapping.schema.enumerations.items(): short_name = name[:-4] if name.endswith("Enum") else name context = locals() @@ -50,6 +61,7 @@ class Implementation(codegen.Base): name=name, schema_name=schema_name, schema_name_upper=schema_name_upper, + index_in_schema=self.names.index(str(name)), values=catc(map(stringify, enum.values)), from_string_statements=catnl( templates.enum_from_string_stmt % dict(context, **locals()) for value in enum.values @@ -61,7 +73,8 @@ class Implementation(codegen.Base): templates.select_function, name=name, schema_name=schema_name, - schema_name_upper=schema_name_upper + schema_name_upper=schema_name_upper, + index_in_schema=self.names.index(str(name)), ) write = lambda str, **kwargs: entity_implementations.append(str % kwargs) @@ -208,6 +221,7 @@ class Implementation(codegen.Base): "body": templates.get_inverse % { "type": i.entity, + "type_index": self.names.index(i.entity), "index": get_attribute_index(i.entity, i.attribute), "schema_name": schema_name, "schema_name_upper": schema_name_upper, @@ -233,6 +247,7 @@ class Implementation(codegen.Base): superclass=superclass, schema_name=schema_name, schema_name_upper=schema_name_upper, + index_in_schema=self.names.index(str(name)), ) selectable_simple_types = sorted( @@ -306,6 +321,7 @@ class Implementation(codegen.Base): def compose(params, schema_name=schema_name, schema_name_upper=schema_name_upper): class_name, attr_type, superclass, superclass_init, name, tmpl, return_type, args, body = params + index_in_schema = self.names.index(str(class_name)) underlying_type = mapping.list_instance_type(type) arguments = ",".join(args) body = body % locals() @@ -347,6 +363,7 @@ class Implementation(codegen.Base): ) simple_type_impl.append("") + """ external_definitions = ( [("extern entity* %s_%%s_type;" % schema_name_upper) % n for n in mapping.schema.entities.keys()] + [ @@ -362,6 +379,8 @@ class Implementation(codegen.Base): for n in mapping.schema.selects.keys() ] ) + """ + external_definitions = ["extern declaration* %s_types[%d];" % (schema_name_upper, len(self.names))] self.str = templates.implementation % { "schema_name_upper": schema_name_upper, diff --git a/src/ifcopenshell-python/ifcopenshell/express/schema_class.py b/src/ifcopenshell-python/ifcopenshell/express/schema_class.py index 583a8e5bd7..a478a34e16 100644 --- a/src/ifcopenshell-python/ifcopenshell/express/schema_class.py +++ b/src/ifcopenshell-python/ifcopenshell/express/schema_class.py @@ -18,6 +18,7 @@ import operator +import re import nodes import codegen @@ -146,11 +147,14 @@ class EarlyBoundCodeWriter: def declare(self, definition_type, name): schema_name = self.schema_name - self.statements.append("%(definition_type)s* %(schema_name)s_%(name)s_type = 0;" % locals()) + # self.statements.append("%(definition_type)s* %(schema_name)s_%(name)s_type = 0;" % locals()) self.names.append(name) def begin_schema(self): self.names.sort(key=str.lower) + schema_name = self.schema_name + num_names = len(self.names) + self.statements.append("declaration* %(schema_name)s_types[%(num_names)d] = {nullptr};" % locals()) self.statements.append("{factory_placeholder}") @@ -172,7 +176,7 @@ __attribute__((optnone)) schema_name = self.schema_name index_in_schema = self.names.index(name) self.statements.append( - ' %(schema_name)s_%(name)s_type = new type_declaration("%(name)s", %(index_in_schema)d, %(declared_type)s);' + ' %(schema_name)s_types[%(index_in_schema)d] = new type_declaration("%(name)s", %(index_in_schema)d, %(declared_type)s);' % locals() ) @@ -183,7 +187,7 @@ __attribute__((optnone)) self.statements.append(" std::vector items; items.reserve(%d);" % len(enum.values)) self.statements.extend(map(lambda v: ' items.push_back("%s");' % v, sorted(enum.values))) self.statements.append( - ' %(schema_name)s_%(name)s_type = new enumeration_type("%(name)s", %(index_in_schema)d, items);' + ' %(schema_name)s_types[%(index_in_schema)d] = new enumeration_type("%(name)s", %(index_in_schema)d, items);' % locals() ) self.statements.append(" }") @@ -191,10 +195,10 @@ __attribute__((optnone)) def entity(self, name, type): schema_name = self.schema_name index_in_schema = self.names.index(name) - supertype = "0" if len(type.supertypes) == 0 else "%s_%s_type" % (self.schema_name, type.supertypes[0]) + supertype = "0" if len(type.supertypes) == 0 else "%s_types[%d]" % (self.schema_name, self.names.index(type.supertypes[0])) is_abstract = "true" if type.abstract else "false" self.statements.append( - ' %(schema_name)s_%(name)s_type = new entity("%(name)s", %(is_abstract)s, %(index_in_schema)d, %(supertype)s);' + ' %(schema_name)s_types[%(index_in_schema)d] = new entity("%(name)s", %(is_abstract)s, %(index_in_schema)d, (entity*) %(supertype)s);' % locals() ) @@ -204,15 +208,16 @@ __attribute__((optnone)) self.statements.append(" {") self.statements.append(" std::vector items; items.reserve(%d);" % len(type.values)) self.statements.extend( - map(lambda v: " items.push_back(%s_%s_type);" % (self.schema_name, v), sorted(map(str, type.values))) + map(lambda v: " items.push_back(%s_types[%d]);" % (self.schema_name, self.names.index(v)), sorted(map(str, type.values))) ) self.statements.append( - ' %(schema_name)s_%(name)s_type = new select_type("%(name)s", %(index_in_schema)d, items);' + ' %(schema_name)s_types[%(index_in_schema)d] = new select_type("%(name)s", %(index_in_schema)d, items);' % locals() ) self.statements.append(" }") def entity_attributes(self, name, attribute_definitions, is_derived): + index_in_schema = self.names.index(name) schema_name = self.schema_name self.statements.append(" {") self.statements.append( @@ -228,31 +233,37 @@ __attribute__((optnone)) self.statements.append( " " + " ".join(map(lambda b: "derived.push_back(%s);" % str(b).lower(), is_derived)) ) - self.statements.append(" %(schema_name)s_%(name)s_type->set_attributes(attributes, derived);" % locals()) + self.statements.append(" ((entity*)%(schema_name)s_types[%(index_in_schema)d])->set_attributes(attributes, derived);" % locals()) self.statements.append(" }") def inverse_attributes(self, name, inv_attrs): schema_name = self.schema_name + index_in_schema = self.names.index(name) self.statements.append(" {") self.statements.append( " std::vector attributes; attributes.reserve(%d);" % len(inv_attrs) ) for attr_name, aggr_type, bound1, bound2, entity_ref, attribute_entity, attribute_entity_index in inv_attrs: + opposite_index_in_schema = self.names.index(entity_ref) + opposite1 = '%(schema_name)s_types[%(opposite_index_in_schema)d]' % locals() + opposite_index_in_schema = self.names.index(attribute_entity) + opposite2 = '%(schema_name)s_types[%(opposite_index_in_schema)d]' % locals() self.statements.append( - ' attributes.push_back(new inverse_attribute("%(attr_name)s", inverse_attribute::%(aggr_type)s_type, %(bound1)d, %(bound2)d, %(schema_name)s_%(entity_ref)s_type, %(schema_name)s_%(attribute_entity)s_type->attributes()[%(attribute_entity_index)d]));' + ' attributes.push_back(new inverse_attribute("%(attr_name)s", inverse_attribute::%(aggr_type)s_type, %(bound1)d, %(bound2)d, ((entity*) %(opposite1)s), ((entity*) %(opposite2)s)->attributes()[%(attribute_entity_index)d]));' % locals() ) - self.statements.append(" %(schema_name)s_%(name)s_type->set_inverse_attributes(attributes);" % locals()) + self.statements.append(" ((entity*) %(schema_name)s_types[%(index_in_schema)d])->set_inverse_attributes(attributes);" % locals()) self.statements.append(" }") def entity_subtypes(self, name, tys): schema_name = self.schema_name + index_in_schema = self.names.index(name) self.statements.append(" {") self.statements.append(" std::vector defs; defs.reserve(%d);" % len(tys)) self.statements.append( - (" " + "".join(map(lambda t: ("defs.push_back(%%(schema_name)s_%s_type);" % t), tys))) % locals() + (" " + "".join(map(lambda t: ("defs.push_back(((entity*) %%(schema_name)s_types[%d]));" % self.names.index(t)), tys))) % locals() ) - self.statements.append(" %(schema_name)s_%(name)s_type->set_subtypes(defs);" % locals()) + self.statements.append(" ((entity*) %(schema_name)s_types[%(index_in_schema)d])->set_subtypes(defs);" % locals()) self.statements.append(" }") def finalize(self, can_be_instantiated_set): @@ -266,7 +277,8 @@ __attribute__((optnone)) " std::vector declarations; declarations.reserve(%(num_declarations)d);" % locals() ) for type_name in self.names: - self.statements.append(" declarations.push_back(%(schema_name)s_%(type_name)s_type);" % locals()) + index_in_schema = self.names.index(type_name) + self.statements.append(" declarations.push_back(%(schema_name)s_types[%(index_in_schema)d]);" % locals()) self.statements.append( ' return new schema_definition("%(schema_name)s", declarations, new %(schema_name)s_instance_factory());' @@ -352,6 +364,23 @@ class SchemaClass(codegen.Base): x = code(schema_name) + def transform_to_indexed(fn): + def wrapper(*args, **kwargs): + declared_type = fn(*args, **kwargs) + if 'simple_type' in declared_type: + pass + else: + match = re.search(r'\((\w+?_[\w+]+?_\w+?)\)', declared_type) + if match: + old_decl = match.group(1) + tn = old_decl.rsplit('_', 2)[1] + idx = x.names.index(tn) + snu = schema_name.upper() + declared_type = declared_type.replace(old_decl, '%(snu)s_types[%(idx)d]' % locals()) + return declared_type + return wrapper if code == EarlyBoundCodeWriter else fn + + @transform_to_indexed def get_declared_type(type, emitted_names=None): if isinstance(type, nodes.SimpleType): type = type.type @@ -469,9 +498,8 @@ class SchemaClass(codegen.Base): if write(name): emitted.add(name.lower()) declarations_by_index.append(name) - declared_types.append("%(schema_name)s_%(name)s_type" % locals()) - num_declarations = len(declared_types) + num_declarations = len(emitted) for name, type in mapping.schema.entities.items(): derived = set(mapping.derived_in_supertype(type)) diff --git a/src/ifcopenshell-python/ifcopenshell/express/templates.py b/src/ifcopenshell-python/ifcopenshell/express/templates.py index ad9ef898de..1dfdafdd58 100644 --- a/src/ifcopenshell-python/ifcopenshell/express/templates.py +++ b/src/ifcopenshell-python/ifcopenshell/express/templates.py @@ -124,19 +124,19 @@ simpletype_impl_argument_type = 'if (i == 0) { return %(attr_type)s; } else { th simpletype_impl_argument = "return data_->getArgument(i);" simpletype_impl_is_with_supertype = "return v == %(class_name)s_type || %(superclass)s::is(v);" simpletype_impl_is_without_supertype = "return v == %(class_name)s_type;" -simpletype_impl_type = "return *%(schema_name_upper)s_%(class_name)s_type;" -simpletype_impl_class = "return *%(schema_name_upper)s_%(class_name)s_type;" +simpletype_impl_type = "return *((IfcParse::type_declaration*)%(schema_name_upper)s_types[%(index_in_schema)d]);" +simpletype_impl_class = "return *((IfcParse::type_declaration*)%(schema_name_upper)s_types[%(index_in_schema)d]);" simpletype_impl_explicit_constructor = "data_ = e;" simpletype_impl_constructor = ( - "data_ = new IfcEntityInstanceData(%(schema_name_upper)s_%(class_name)s_type); {IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(v" + "data_ = new IfcEntityInstanceData(%(schema_name_upper)s_types[%(index_in_schema)d]); {IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(v" + "); data_->setArgument(0, attr);}" ) -simpletype_impl_constructor_templated = "data_ = new IfcEntityInstanceData(%(schema_name_upper)s_%(class_name)s_type); {IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(v->generalize()); data_->setArgument(0, attr);}" +simpletype_impl_constructor_templated = "data_ = new IfcEntityInstanceData(%(schema_name_upper)s_types[%(index_in_schema)d]); {IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(v->generalize()); data_->setArgument(0, attr);}" simpletype_impl_cast = "return *data_->getArgument(0);" simpletype_impl_cast_templated = ( "aggregate_of_instance::ptr es = *data_->getArgument(0); return es->as< %(underlying_type)s >();" ) -simpletype_impl_declaration = "return *%(schema_name_upper)s_%(class_name)s_type;" +simpletype_impl_declaration = "return *((IfcParse::type_declaration*)%(schema_name_upper)s_types[%(index_in_schema)d]);" select = """%(documentation)s class IFC_PARSE_API %(name)s : public virtual IfcUtil::IfcBaseInterface { @@ -174,26 +174,26 @@ public: """ select_function = """ -const IfcParse::select_type& %(schema_name)s::%(name)s::Class() { return *%(schema_name_upper)s_%(name)s_type; } +const IfcParse::select_type& %(schema_name)s::%(name)s::Class() { return *((IfcParse::select_type*)%(schema_name_upper)s_types[%(index_in_schema)d]); } """ enumeration_function = """ -const IfcParse::enumeration_type& %(schema_name)s::%(name)s::declaration() const { return *%(schema_name_upper)s_%(name)s_type; } -const IfcParse::enumeration_type& %(schema_name)s::%(name)s::Class() { return *%(schema_name_upper)s_%(name)s_type; } +const IfcParse::enumeration_type& %(schema_name)s::%(name)s::declaration() const { return *((IfcParse::enumeration_type*)%(schema_name_upper)s_types[%(index_in_schema)d]); } +const IfcParse::enumeration_type& %(schema_name)s::%(name)s::Class() { return *((IfcParse::enumeration_type*)%(schema_name_upper)s_types[%(index_in_schema)d]); } %(schema_name)s::%(name)s::%(name)s(IfcEntityInstanceData* e) { data_ = e; } %(schema_name)s::%(name)s::%(name)s(Value v) { - data_ = new IfcEntityInstanceData(%(schema_name_upper)s_%(name)s_type); + data_ = new IfcEntityInstanceData(%(schema_name_upper)s_types[%(index_in_schema)d]); IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(IfcWrite::IfcWriteArgument::EnumerationReference(v,ToString(v))); data_->setArgument(0,attr); } %(schema_name)s::%(name)s::%(name)s(const std::string& v) { - data_ = new IfcEntityInstanceData(%(schema_name_upper)s_%(name)s_type); + data_ = new IfcEntityInstanceData(%(schema_name_upper)s_types[%(index_in_schema)d]); IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument(); attr->set(IfcWrite::IfcWriteArgument::EnumerationReference(FromString(v),ToString(FromString(v)))); data_->setArgument(0,attr); @@ -218,10 +218,10 @@ const char* %(schema_name)s::%(name)s::ToString(Value v) { entity_implementation = """// Function implementations for %(name)s %(attributes)s %(inverse)s -const IfcParse::entity& %(schema_name)s::%(name)s::declaration() const { return *%(schema_name_upper)s_%(name)s_type; } -const IfcParse::entity& %(schema_name)s::%(name)s::Class() { return *%(schema_name_upper)s_%(name)s_type; } -%(schema_name)s::%(name)s::%(name)s(IfcEntityInstanceData* e) : %(superclass)s { if (!e) return; if (e->type() != %(schema_name_upper)s_%(name)s_type) throw IfcException("Unable to find keyword in schema"); data_ = e; } -%(schema_name)s::%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s {data_ = new IfcEntityInstanceData(%(schema_name_upper)s_%(name)s_type); %(constructor_implementation)s } +const IfcParse::entity& %(schema_name)s::%(name)s::declaration() const { return *((IfcParse::entity*)%(schema_name_upper)s_types[%(index_in_schema)d]); } +const IfcParse::entity& %(schema_name)s::%(name)s::Class() { return *((IfcParse::entity*)%(schema_name_upper)s_types[%(index_in_schema)d]); } +%(schema_name)s::%(name)s::%(name)s(IfcEntityInstanceData* e) : %(superclass)s { if (!e) return; if (e->type() != %(schema_name_upper)s_types[%(index_in_schema)d]) throw IfcException("Unable to find keyword in schema"); data_ = e; } +%(schema_name)s::%(name)s::%(name)s(%(constructor_arguments)s) : %(superclass)s {data_ = new IfcEntityInstanceData(%(schema_name_upper)s_types[%(index_in_schema)d]); %(constructor_implementation)s } """ optional_attribute_description = "/// Whether the optional attribute %s is defined for this %s" @@ -257,7 +257,7 @@ get_attr_stmt_entity = "%(null_check)s return ((IfcUtil::IfcBaseClass*)(*data_-> get_attr_stmt_array = "%(null_check)s aggregate_of_instance::ptr es = *data_->getArgument(%(index)d); return es->as< %(list_instance_type)s >();" get_attr_stmt_nested_array = "%(null_check)s aggregate_of_aggregate_of_instance::ptr es = *data_->getArgument(%(index)d); return es->as< %(list_instance_type)s >();" -get_inverse = "return data_->getInverse(%(schema_name_upper)s_%(type)s_type, %(index)d)->as<%(type)s>();" +get_inverse = "return data_->getInverse(%(schema_name_upper)s_types[%(type_index)d], %(index)d)->as<%(type)s>();" set_attr_stmt = ( "{IfcWrite::IfcWriteArgument* attr = new IfcWrite::IfcWriteArgument();%(check_optional_set_begin)sattr->set(%(star_if_optional)sv"