Simplify struct header generation by merging the internal _build_struct_header_internal function into build_struct_header
PiperOrigin-RevId: 830878041 Change-Id: I6867984ac6ec091daaf2172fbde0e6ac6f38d1f3
This commit is contained in:
committed by
Copybara-Service
parent
1b2206fc50
commit
75774b2a35
@@ -37,8 +37,10 @@ class WrappedFieldData:
|
||||
# Line for struct field definition
|
||||
definition: str = ""
|
||||
|
||||
# Initialization code for fields that require it
|
||||
initialization: str = ""
|
||||
# Used for constructor fields that are class types and need to be initialized
|
||||
# with a pointer to the corresponding member in the native struct
|
||||
# (e.g., ", alt(&ptr_->alt)").
|
||||
ptr_initialization: str = ""
|
||||
|
||||
# Statement to reset the inner pointer when copying the field
|
||||
ptr_copy_reset: str = ""
|
||||
@@ -132,7 +134,7 @@ def _generate_field_data(
|
||||
definition=f"{common.uppercase_first_letter(f.type.name)} {f.name};",
|
||||
typename=_get_field_struct_type(f.type),
|
||||
binding=_simple_property_binding(f, w, setter=False, reference=True),
|
||||
initialization=f", {f.name}(&ptr_->{f.name})",
|
||||
ptr_initialization=f", {f.name}(&ptr_->{f.name})",
|
||||
ptr_copy_reset=f"{f.name}.set(&ptr_->{f.name});",
|
||||
is_primitive_or_fixed_size=True,
|
||||
)
|
||||
@@ -149,7 +151,7 @@ def _generate_field_data(
|
||||
return WrappedFieldData(
|
||||
binding=_simple_property_binding(f, w, setter=False, reference=True),
|
||||
typename=_get_field_struct_type(f.type),
|
||||
initialization=f", {f.name}(&ptr_->{f.name})",
|
||||
ptr_initialization=f", {f.name}(&ptr_->{f.name})",
|
||||
ptr_copy_reset=f"{f.name}.set(&ptr_->{f.name});",
|
||||
is_primitive_or_fixed_size=True,
|
||||
)
|
||||
@@ -254,7 +256,7 @@ def _generate_field_data(
|
||||
definition=f"{wrapper_field_name} {f.name};",
|
||||
typename=_get_field_struct_type(f.type),
|
||||
binding=_simple_property_binding(f, w, setter=False, reference=True),
|
||||
initialization=f", {f.name}(ptr_->{f.name})",
|
||||
ptr_initialization=f", {f.name}(ptr_->{f.name})",
|
||||
)
|
||||
|
||||
builder = code_builder.CodeBuilder()
|
||||
@@ -280,64 +282,6 @@ def _generate_field_data(
|
||||
)
|
||||
|
||||
|
||||
def _has_nested_wrapper_members(struct_info: ast_nodes.StructDecl) -> bool:
|
||||
"""Checks if the struct contains other wrapped structs as direct members."""
|
||||
for field in struct_info.fields:
|
||||
member_type = cast(ast_nodes.StructFieldDecl, field).type
|
||||
if isinstance(member_type, (ast_nodes.ArrayType, ast_nodes.PointerType)):
|
||||
member_type = member_type.inner_type
|
||||
if isinstance(member_type, ast_nodes.ValueType):
|
||||
return member_type.name in constants.STRUCTS_TO_BIND
|
||||
return False
|
||||
|
||||
|
||||
def _build_struct_header_internal(
|
||||
struct_name: str,
|
||||
wrapped_fields: List[WrappedFieldData],
|
||||
fields_with_init: List[WrappedFieldData],
|
||||
is_mjs: bool = False,
|
||||
):
|
||||
"""Builds the C++ header file code for a struct."""
|
||||
s = struct_name
|
||||
w = common.uppercase_first_letter(s)
|
||||
|
||||
shallow_copy = use_shallow_copy(wrapped_fields)
|
||||
|
||||
builder = code_builder.CodeBuilder()
|
||||
with builder.struct(f"{w}"):
|
||||
builder.line(f"explicit {w}({s} *ptr);")
|
||||
builder.line(f"~{w}();")
|
||||
|
||||
if not is_mjs:
|
||||
builder.line(f"{w}();")
|
||||
|
||||
if shallow_copy and not is_mjs:
|
||||
builder.line(f"{w}(const {w} &);")
|
||||
builder.line(f"{w} &operator=(const {w} &);")
|
||||
builder.line(f"std::unique_ptr<{w}> copy();")
|
||||
|
||||
builder.line(f"{s}* get() const;")
|
||||
builder.line(f"void set({s}* ptr);")
|
||||
|
||||
for field in wrapped_fields:
|
||||
if field.definition and field not in fields_with_init:
|
||||
for line in field.definition.splitlines():
|
||||
builder.line(line)
|
||||
|
||||
builder.private()
|
||||
builder.line(f"{s}* ptr_;")
|
||||
if not is_mjs:
|
||||
builder.line("bool owned_ = false;")
|
||||
|
||||
if is_mjs and fields_with_init:
|
||||
builder.public()
|
||||
for field in fields_with_init:
|
||||
if field.definition:
|
||||
builder.line(f"{field.definition}")
|
||||
|
||||
return builder.to_string() + ";"
|
||||
|
||||
|
||||
def _default_function_statement(struct_name: str) -> str:
|
||||
"""Returns the default function name for the given struct."""
|
||||
if struct_name == "mjvGeom":
|
||||
@@ -365,15 +309,15 @@ def _delete_ptr_statement(struct_name: str) -> str:
|
||||
return "delete ptr_;"
|
||||
|
||||
|
||||
def _find_fields_with_init(
|
||||
def _find_member_inits(
|
||||
wrapped_fields: List[WrappedFieldData],
|
||||
) -> List[WrappedFieldData]:
|
||||
"""Finds the fields with initialization in the wrapped fields list."""
|
||||
fields_with_init = []
|
||||
"""Finds the fields with ptr_initialization in the wrapped fields list."""
|
||||
member_inits = []
|
||||
for field in wrapped_fields:
|
||||
if field.initialization:
|
||||
fields_with_init.append(field)
|
||||
return fields_with_init
|
||||
if field.ptr_initialization:
|
||||
member_inits.append(field)
|
||||
return member_inits
|
||||
|
||||
|
||||
def use_shallow_copy(
|
||||
@@ -391,32 +335,55 @@ def build_struct_header(
|
||||
wrapped_fields: List[WrappedFieldData],
|
||||
):
|
||||
"""Builds the C++ header file code for a struct."""
|
||||
struct_info = introspect_structs.STRUCTS.get(struct_name)
|
||||
s = struct_name
|
||||
w = common.uppercase_first_letter(s)
|
||||
|
||||
if struct_name.startswith("mjs"):
|
||||
fields_with_init = _find_fields_with_init(wrapped_fields)
|
||||
return _build_struct_header_internal(
|
||||
struct_name,
|
||||
wrapped_fields,
|
||||
fields_with_init,
|
||||
is_mjs=True,
|
||||
)
|
||||
|
||||
is_anonymous_struct = struct_name in constants.ANONYMOUS_STRUCTS.keys()
|
||||
is_hardcoded_wrapper_struct = (
|
||||
common.uppercase_first_letter(struct_name) in constants.MANUAL_STRUCTS
|
||||
)
|
||||
if w in constants.MANUAL_STRUCTS:
|
||||
return ""
|
||||
|
||||
if (
|
||||
not is_hardcoded_wrapper_struct
|
||||
and struct_info
|
||||
and not _has_nested_wrapper_members(struct_info)
|
||||
or is_anonymous_struct
|
||||
s not in constants.ANONYMOUS_STRUCTS and
|
||||
s not in introspect_structs.STRUCTS
|
||||
):
|
||||
return _build_struct_header_internal(
|
||||
struct_name, wrapped_fields, [], is_mjs=False
|
||||
)
|
||||
return ""
|
||||
raise RuntimeError(f"Struct {s} not found in introspect structs")
|
||||
|
||||
is_mjs = w.startswith("Mjs")
|
||||
member_inits = _find_member_inits(wrapped_fields)
|
||||
shallow_copy = use_shallow_copy(wrapped_fields)
|
||||
builder = code_builder.CodeBuilder()
|
||||
|
||||
with builder.struct(f"{w}"):
|
||||
builder.line(f"explicit {w}({s} *ptr);")
|
||||
builder.line(f"~{w}();")
|
||||
|
||||
if not is_mjs:
|
||||
builder.line(f"{w}();")
|
||||
|
||||
if shallow_copy and not is_mjs:
|
||||
builder.line(f"{w}(const {w} &);")
|
||||
builder.line(f"{w} &operator=(const {w} &);")
|
||||
builder.line(f"std::unique_ptr<{w}> copy();")
|
||||
|
||||
builder.line(f"{s}* get() const;")
|
||||
builder.line(f"void set({s}* ptr);")
|
||||
|
||||
for field in wrapped_fields:
|
||||
if field.definition and field not in member_inits:
|
||||
for line in field.definition.splitlines():
|
||||
builder.line(line)
|
||||
|
||||
builder.private()
|
||||
builder.line(f"{s}* ptr_;")
|
||||
if not is_mjs:
|
||||
builder.line("bool owned_ = false;")
|
||||
|
||||
if member_inits:
|
||||
builder.public()
|
||||
for f in member_inits:
|
||||
if f.definition:
|
||||
builder.line(f"{f.definition}")
|
||||
|
||||
return builder.to_string() + ";"
|
||||
|
||||
|
||||
def build_struct_source(
|
||||
@@ -438,13 +405,13 @@ def build_struct_source(
|
||||
w = common.uppercase_first_letter(s)
|
||||
is_mjs = w.startswith("Mjs")
|
||||
|
||||
fields_with_init = _find_fields_with_init(wrapped_fields)
|
||||
member_inits = _find_member_inits(wrapped_fields)
|
||||
shallow_copy = use_shallow_copy(wrapped_fields)
|
||||
|
||||
fields_init = ""
|
||||
if fields_with_init:
|
||||
if member_inits:
|
||||
fields_init = "".join(
|
||||
field_with_init.initialization for field_with_init in fields_with_init
|
||||
mjs_field.ptr_initialization for mjs_field in member_inits
|
||||
)
|
||||
|
||||
builder = code_builder.CodeBuilder()
|
||||
@@ -472,18 +439,18 @@ def build_struct_source(
|
||||
# copy constructor
|
||||
with builder.function(f"{w}::{w}(const {w} &other) : {w}()"):
|
||||
builder.line("*ptr_ = *other.get();")
|
||||
for field_with_init in fields_with_init:
|
||||
if field_with_init.ptr_copy_reset is not None:
|
||||
builder.line(field_with_init.ptr_copy_reset)
|
||||
for f in member_inits:
|
||||
if f.ptr_copy_reset is not None:
|
||||
builder.line(f.ptr_copy_reset)
|
||||
|
||||
# assignment operator
|
||||
with builder.function(f"{w}& {w}::operator=(const {w} &other)"):
|
||||
with builder.block("if (this == &other)"):
|
||||
builder.line("return *this;")
|
||||
builder.line("*ptr_ = *other.get();")
|
||||
for field_with_init in fields_with_init:
|
||||
if field_with_init.ptr_copy_reset is not None:
|
||||
builder.line(field_with_init.ptr_copy_reset)
|
||||
for f in member_inits:
|
||||
if f.ptr_copy_reset is not None:
|
||||
builder.line(f.ptr_copy_reset)
|
||||
builder.line("return *this;")
|
||||
|
||||
# explicit copy function
|
||||
|
||||
@@ -782,7 +782,7 @@ emscripten::val buffer() const {
|
||||
'.property("element", &MjsTexture::element, reference())',
|
||||
)
|
||||
self.assertEqual(
|
||||
wrapped_field_data.initialization,
|
||||
wrapped_field_data.ptr_initialization,
|
||||
", element(ptr_->element)",
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user