diff --git a/src/ifcopenshell-python/ifcopenshell/express/schema_class.py b/src/ifcopenshell-python/ifcopenshell/express/schema_class.py index a478a34e16..522801dd50 100644 --- a/src/ifcopenshell-python/ifcopenshell/express/schema_class.py +++ b/src/ifcopenshell-python/ifcopenshell/express/schema_class.py @@ -117,8 +117,26 @@ class LateBoundSchemaInstantiator: elem.this.disown() +class string_pool: + def __init__(self, fn): + self.di = {} + self.fn = fn + def append(self, v): + def _(): + if i := self.di.get(v): + return i + else: + i = len(self.di) + self.di[v] = i + return i + return self.fn(_()) + def __iter__(self): + return iter(self.di.keys()) + + class EarlyBoundCodeWriter: def __init__(self, schema_name): + self.strings = string_pool(lambda i: "strings[%d]" % i) self.schema_name = schema_name self.schema_name_title = schema_name.capitalize() @@ -126,7 +144,9 @@ class EarlyBoundCodeWriter: "", '#include "../ifcparse/IfcSchema.h"', '#include "../ifcparse/%(schema_name_title)s.h"' % self.__dict__, + '#include ', "", + 'using namespace std::string_literals;', "using namespace IfcParse;", "", ] @@ -156,6 +176,8 @@ class EarlyBoundCodeWriter: 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( @@ -175,117 +197,97 @@ __attribute__((optnone)) def typedef(self, name, declared_type): schema_name = self.schema_name index_in_schema = self.names.index(name) + ref = self.strings.append(name) self.statements.append( - ' %(schema_name)s_types[%(index_in_schema)d] = new type_declaration("%(name)s", %(index_in_schema)d, %(declared_type)s);' + ' %(schema_name)s_types[%(index_in_schema)d] = new type_declaration(%(ref)s, %(index_in_schema)d, %(declared_type)s);' % locals() ) def enumeration(self, name, enum): schema_name = self.schema_name index_in_schema = self.names.index(name) - self.statements.append(" {") - 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))) + ref = self.strings.append(name) + items = ",".join(self.strings.append(v) for v in sorted(enum.values)) self.statements.append( - ' %(schema_name)s_types[%(index_in_schema)d] = new enumeration_type("%(name)s", %(index_in_schema)d, items);' + ' %(schema_name)s_types[%(index_in_schema)d] = new enumeration_type(%(ref)s, %(index_in_schema)d, {%(items)s});' % locals() ) - self.statements.append(" }") def entity(self, name, type): schema_name = self.schema_name 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])) is_abstract = "true" if type.abstract else "false" self.statements.append( - ' %(schema_name)s_types[%(index_in_schema)d] = new entity("%(name)s", %(is_abstract)s, %(index_in_schema)d, (entity*) %(supertype)s);' + ' %(schema_name)s_types[%(index_in_schema)d] = new entity(%(ref)s, %(is_abstract)s, %(index_in_schema)d, (entity*) %(supertype)s);' % locals() ) def select(self, name, type): schema_name = self.schema_name index_in_schema = self.names.index(name) - 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_types[%d]);" % (self.schema_name, self.names.index(v)), sorted(map(str, type.values))) + ref = self.strings.append(name) + items = ",".join( + map(lambda v: "%s_types[%d]" % (self.schema_name, self.names.index(v)), sorted(map(str, type.values))) ) self.statements.append( - ' %(schema_name)s_types[%(index_in_schema)d] = new select_type("%(name)s", %(index_in_schema)d, items);' + ' %(schema_name)s_types[%(index_in_schema)d] = new select_type(%(ref)s, %(index_in_schema)d, {%(items)s});' % 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( - " std::vector attributes; attributes.reserve(%d);" % len(attribute_definitions) - ) - for attr_name, decl_type, optional in attribute_definitions: - optional_cpp = str(optional).lower() - self.statements.append( - ' attributes.push_back(new attribute("%(attr_name)s", %(decl_type)s, %(optional_cpp)s));' - % locals() - ) - self.statements.append(" std::vector derived; derived.reserve(%d);" % len(is_derived)) - self.statements.append( - " " + " ".join(map(lambda b: "derived.push_back(%s);" % str(b).lower(), is_derived)) - ) - self.statements.append(" ((entity*)%(schema_name)s_types[%(index_in_schema)d])->set_attributes(attributes, derived);" % locals()) - self.statements.append(" }") + index_in_schema = self.names.index(name) + def _(): + index_in_schema = self.names.index(name) + schema_name = self.schema_name + for attr_name, decl_type, optional in attribute_definitions: + attr_name_ref = self.strings.append(attr_name) + optional_cpp = str(optional).lower() + yield 'new attribute(%(attr_name_ref)s, %(decl_type)s, %(optional_cpp)s)' % locals() + attributes = ",".join(_()) + derived = ",".join(map(lambda b: str(b).lower(), is_derived)) + 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 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, ((entity*) %(opposite1)s), ((entity*) %(opposite2)s)->attributes()[%(attribute_entity_index)d]));' - % locals() - ) - self.statements.append(" ((entity*) %(schema_name)s_types[%(index_in_schema)d])->set_inverse_attributes(attributes);" % locals()) - self.statements.append(" }") + def _(): + schema_name = self.schema_name + index_in_schema = self.names.index(name) + for attr_name, aggr_type, bound1, bound2, entity_ref, attribute_entity, attribute_entity_index in inv_attrs: + attr_name_ref = self.strings.append(attr_name) + 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() + yield 'new inverse_attribute(%(attr_name_ref)s, inverse_attribute::%(aggr_type)s_type, %(bound1)d, %(bound2)d, ((entity*) %(opposite1)s), ((entity*) %(opposite2)s)->attributes()[%(attribute_entity_index)d])' % locals() + attributes = ",".join(_()) + 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 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(((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(defs);" % locals()) - self.statements.append(" }") + 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_title = self.schema_name.capitalize() - - num_declarations = len(self.names) - - self.statements.append("") + def _(): + schema_name = self.schema_name + schema_name_title = self.schema_name.capitalize() + for type_name in self.names: + index_in_schema = self.names.index(type_name) + yield "%(schema_name)s_types[%(index_in_schema)d]" % locals() + declarations = ",".join(_()) + schema_name_ref = self.strings.append(schema_name) self.statements.append( - " std::vector declarations; declarations.reserve(%(num_declarations)d);" % locals() - ) - for type_name in self.names: - 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());' + ' return new schema_definition(%(schema_name_ref)s, {%(declarations)s}, new %(schema_name)s_instance_factory());' % locals() ) - - self.statements.extend(("}", "")) + self.statements.append("}"); self.statements.append( """ @@ -348,6 +350,14 @@ class %(schema_name)s_instance_factory : public IfcParse::instance_factory { % locals() ) + "" + self.statements[self.statements.index("{string_pool_placeholder}")] = ( + """ +const std::string strings[] = {%s}; +""" + % ",".join(map(lambda s: '"%s"s' % s, self.strings)) + ) + def __str__(self): return "\n".join(self.statements)