Do not delete attached specs after compilation.

Also, copy them when copying the spec.

PiperOrigin-RevId: 688998464
Change-Id: I7229fd8032eafede582194ccf73ab4160fe06768
This commit is contained in:
Alessio Quaglino
2024-10-23 09:41:07 -07:00
committed by Copybara-Service
parent e14aebfd16
commit d17d9e835c
9 changed files with 95 additions and 10 deletions
+9
View File
@@ -4139,6 +4139,15 @@ mjs_getSpec
Get spec from body.
.. _mjs_findSpec:
mjs_findSpec
~~~~~~~~~~~~
.. mujoco-include:: mjs_findSpec
Find spec (model asset) by name.
.. _mjs_findBody:
mjs_findBody
+1
View File
@@ -3600,6 +3600,7 @@ mjsSkin* mjs_addSkin(mjSpec* s);
mjsTexture* mjs_addTexture(mjSpec* s);
mjsMaterial* mjs_addMaterial(mjSpec* s, mjsDefault* def);
mjSpec* mjs_getSpec(mjsElement* element);
mjSpec* mjs_findSpec(mjSpec* spec, const char* name);
mjsBody* mjs_findBody(mjSpec* s, const char* name);
mjsElement* mjs_findElement(mjSpec* s, mjtObj type, const char* name);
mjsBody* mjs_findChild(mjsBody* body, const char* name);
+3
View File
@@ -1534,6 +1534,9 @@ MJAPI mjsMaterial* mjs_addMaterial(mjSpec* s, mjsDefault* def);
// Get spec from body.
MJAPI mjSpec* mjs_getSpec(mjsElement* element);
// Find spec (model asset) by name.
MJAPI mjSpec* mjs_findSpec(mjSpec* spec, const char* name);
// Find body in spec by name.
MJAPI mjsBody* mjs_findBody(mjSpec* s, const char* name);
+22
View File
@@ -9742,6 +9742,28 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
),
doc='Get spec from body.',
)),
('mjs_findSpec',
FunctionDecl(
name='mjs_findSpec',
return_type=PointerType(
inner_type=ValueType(name='mjSpec'),
),
parameters=(
FunctionParameterDecl(
name='spec',
type=PointerType(
inner_type=ValueType(name='mjSpec'),
),
),
FunctionParameterDecl(
name='name',
type=PointerType(
inner_type=ValueType(name='char', is_const=True),
),
),
),
doc='Find spec (model asset) by name.',
)),
('mjs_findBody',
FunctionDecl(
name='mjs_findBody',
+3 -6
View File
@@ -388,6 +388,9 @@ mjCModel& mjCModel::operator+=(const mjCModel& other) {
}
CopyList(numerics_, other.numerics_);
CopyList(texts_, other.texts_);
for (const auto* s : other.specs_) {
specs_.push_back(mj_copySpec(s));
}
}
CopyList(flexes_, other.flexes_);
CopyList(pairs_, other.pairs_);
@@ -3648,12 +3651,6 @@ mjModel* mjCModel::Compile(const mjVFS* vfs, mjModel** m) {
return nullptr;
}
// destroy attached specs
for (auto spec : specs_) {
mj_deleteSpec(spec);
}
specs_.clear();
// restore error handler, mark as compiled, return mjModel
_mjPRIVATE__set_tls_error_fn(save_error);
_mjPRIVATE__set_tls_warning_fn(save_warning);
+2 -2
View File
@@ -387,11 +387,11 @@ mjSpec* ParseXML(const char* filename, const mjVFS* vfs,
return spec;
}
mjSpec* ParseSpecFromString(std::string_view xml, char* error, int nerror) {
mjSpec* ParseSpecFromString(std::string_view xml, const mjVFS* vfs, char* error, int nerror) {
RegisterResourceProvider();
std::string xml2 = {xml.begin(), xml.end()};
std::string str = "LoadModelFromString:" + xml2;
return ParseXML(str.c_str(), nullptr, error, nerror);
return ParseXML(str.c_str(), vfs, error, nerror);
}
// Main writer function - calls mjXWrite
+2 -1
View File
@@ -26,7 +26,8 @@ mjSpec* ParseXML(const char* filename, const mjVFS* vfs, char* error, int nerror
// Returns a newly-allocated mjSpec, loaded from the contents of xml.
// On failure returns nullptr and populates the error array if present.
mjSpec* ParseSpecFromString(std::string_view xml, char* error = nullptr, int nerror = 0);
mjSpec* ParseSpecFromString(std::string_view xml, const mjVFS* vfs = nullptr,
char* error = nullptr, int nerror = 0);
// Main writer function
std::string WriteXML(const mjModel* m, const mjSpec* spec, char* error, int nerror);
+1 -1
View File
@@ -221,7 +221,7 @@ mjSpec* mj_parseXML(const char* filename, const mjVFS* vfs, char* error, int err
// parse spec from string
mjSpec* mj_parseXMLString(const char* xml, const mjVFS* vfs, char* error, int error_sz) {
return ParseSpecFromString(xml, error, error_sz);
return ParseSpecFromString(xml, vfs, error, error_sz);
}
+52
View File
@@ -1849,5 +1849,57 @@ TEST_F(MujocoTest, DifferentUnitsNotAllowed) {
mj_deleteSpec(spec_2);
}
TEST_F(MujocoTest, CopyAttachedSpec) {
static constexpr char xml_parent[] = R"(
<mujoco>
<asset>
<model name="child" file="xml_child.xml"/>
</asset>
<worldbody>
<body name="parent">
<geom name="geom" size="2"/>
<attach model="child" body="body" prefix="other"/>
</body>
</worldbody>
</mujoco>
)";
static constexpr char xml_child[] = R"(
<mujoco>
<worldbody>
<body name="body">
<geom name="geom" size="1" pos="2 0 0"/>
</body>
</worldbody>
</mujoco>
)";
auto vfs = std::make_unique<mjVFS>();
mj_defaultVFS(vfs.get());
mj_addBufferVFS(vfs.get(), "xml_child.xml", xml_child, sizeof(xml_child));
std::array<char, 1024> er;
mjSpec* spec = mj_parseXMLString(xml_parent, vfs.get(), er.data(), er.size());
EXPECT_THAT(spec, NotNull()) << er.data();
mjModel* model = mj_compile(spec, vfs.get());
EXPECT_THAT(model, NotNull()) << er.data();
mjSpec* child = mjs_findSpec(spec, "child");
EXPECT_THAT(child, NotNull());
mjSpec* copy = mj_copySpec(spec);
EXPECT_THAT(copy, NotNull());
mjSpec* child_copy = mjs_findSpec(copy, "child");
EXPECT_THAT(child_copy, NotNull());
EXPECT_NE(child_copy, child);
mj_deleteSpec(spec);
mj_deleteSpec(copy);
mj_deleteModel(model);
mj_deleteVFS(vfs.get());
}
} // namespace
} // namespace mujoco