Do not copy the spec during attach.

Use a reference count for managing the memory.

PiperOrigin-RevId: 716169486
Change-Id: Id270c4858c17b9250115e9544d5ea143584e2d5f
This commit is contained in:
Alessio Quaglino
2025-01-16 03:52:31 -08:00
committed by Copybara-Service
parent 6436055c6c
commit c2138c3fb0
19 changed files with 505 additions and 173 deletions
+136 -72
View File
@@ -763,6 +763,7 @@ mjCBody::mjCBody(mjCModel* _model) {
model = _model;
if (_model) compiler = &_model->spec.compiler;
refcount = 1;
mjs_defaultBody(&spec);
elemtype = mjOBJ_BODY;
parent = nullptr;
@@ -872,22 +873,28 @@ mjCBody& mjCBody::operator+=(const mjCFrame& other) {
other.model->prefix = other.prefix;
other.model->suffix = other.suffix;
other.model->StoreKeyframes(model);
mjCModel* other_model = other.model;
// attach defaults
if (other.model != model) {
mjCDef* subdef = new mjCDef(*other.model->Default());
subdef->NameSpace(other.model);
if (other_model != model) {
mjCDef* subdef = new mjCDef(*other_model->Default());
subdef->NameSpace(other_model);
*model += *subdef;
}
// copy input frame
mjSpec* origin = model->FindSpec(other.compiler);
frames.push_back(new mjCFrame(other));
mjCFrame* newframe(model->deepcopy_ ? new mjCFrame(other) : (mjCFrame*)&other);
frames.push_back(newframe);
frames.back()->body = this;
frames.back()->model = model;
frames.back()->compiler = origin ? &origin->compiler : &model->spec.compiler;
frames.back()->frame = other.frame;
frames.back()->NameSpace(other.model);
if (model->deepcopy_) {
frames.back()->NameSpace(other_model);
} else {
frames.back()->AddRef();
}
int i = frames.size();
last_attached = &frames.back()->spec;
@@ -909,30 +916,43 @@ mjCBody& mjCBody::operator+=(const mjCFrame& other) {
CopyList(cameras, subtree->cameras, fmap, &other);
CopyList(lights, subtree->lights, fmap, &other);
if (!model->deepcopy_) {
subtree->SetModel(model);
subtree->NameSpace(other_model);
}
int nbodies = (int)subtree->bodies.size();
for (int i=0; i<nbodies; i++) {
if (!other.IsAncestor(subtree->bodies[i]->frame)) {
continue;
}
bodies.push_back(new mjCBody(*subtree->bodies[i], model)); // triggers recursive call
if (model->deepcopy_) {
mjCBody* newbody(new mjCBody(*subtree->bodies[i], model)); // triggers recursive call
bodies.push_back(newbody);
subtree->bodies[i]->ForgetKeyframes();
bodies.back()->NameSpace_(other_model, /*propagate=*/ false);
} else {
bodies.push_back(subtree->bodies[i]);
bodies.back()->SetModel(model);
bodies.back()->ResetId();
bodies.back()->AddRef();
}
bodies.back()->parent = this;
bodies.back()->frame =
subtree->bodies[i]->frame ? frames[fmap[subtree->bodies[i]->frame]] : nullptr;
bodies.back()->NameSpace_(other.model, /*propagate=*/ false);
subtree->bodies[i]->ForgetKeyframes();
}
// attach referencing elements
*model += *other.model;
*model += *other_model;
// leave the source model in a clean state
if (other.model != model) {
other.model->key_pending_.clear();
if (other_model != model) {
other_model->key_pending_.clear();
}
// clear namespace and return body
other.model->prefix.clear();
other.model->suffix.clear();
other_model->prefix.clear();
other_model->suffix.clear();
return *this;
}
@@ -948,7 +968,8 @@ void mjCBody::CopyList(std::vector<T*>& dst, const std::vector<T*>& src,
continue; // skip if the element is not inside pframe
}
mjSpec* origin = model->FindSpec(src[i]->compiler);
dst.push_back(new T(*src[i]));
T* new_obj = model->deepcopy_ ? new T(*src[i]) : src[i];
dst.push_back(new_obj);
dst.back()->body = this;
dst.back()->model = model;
dst.back()->compiler = origin ? &origin->compiler : &model->spec.compiler;
@@ -956,6 +977,11 @@ void mjCBody::CopyList(std::vector<T*>& dst, const std::vector<T*>& src,
dst.back()->CopyPlugin();
dst.back()->classname = src[i]->classname;
// increment refcount if shallow copy is made
if (!model->deepcopy_) {
dst.back()->AddRef();
}
// assign dst frame to src frame
dst.back()->frame = src[i]->frame ? frames[fmap[src[i]->frame]] : nullptr;
@@ -981,6 +1007,73 @@ mjCBody& mjCBody::operator-=(const mjCBody& subtree) {
// set model of this body and its subtree
void mjCBody::SetModel(mjCModel* _model) {
model = _model;
mjSpec* origin = model->FindSpec(mjs_getString(model->spec.modelname));
compiler = origin ? &origin->compiler : &model->spec.compiler;
for (auto& body : bodies) {
body->SetModel(_model);
}
for (auto& frame : frames) {
frame->model = _model;
frame->compiler = compiler;
}
for (auto& geom : geoms) {
geom->model = _model;
geom->compiler = compiler;
}
for (auto& joint : joints) {
joint->model = _model;
joint->compiler = compiler;
}
for (auto& site : sites) {
site->model = _model;
site->compiler = compiler;
}
for (auto& camera : cameras) {
camera->model = _model;
camera->compiler = compiler;
}
for (auto& light : lights) {
light->model = _model;
light->compiler = compiler;
}
}
// reset ids of all objects in this body
void mjCBody::ResetId() {
id = -1;
for (auto& body : bodies) {
body->ResetId();
}
for (auto& frame : frames) {
frame->id = -1;
}
for (auto& geom : geoms) {
geom->id = -1;
}
for (auto& joint : joints) {
joint->id = -1;
joint->qposadr_ = -1;
joint->dofadr_ = -1;
}
for (auto& site : sites) {
site->id = -1;
}
for (auto& camera : cameras) {
camera->id = -1;
}
for (auto& light : lights) {
light->id = -1;
}
}
void mjCBody::PointToLocal() {
spec.element = static_cast<mjsElement*>(this);
spec.name = &name;
@@ -1012,26 +1105,13 @@ void mjCBody::CopyPlugin() {
// destructor
mjCBody::~mjCBody() {
// delete objects allocated here
for (int i=0; i<bodies.size(); i++) delete bodies[i];
for (int i=0; i<geoms.size(); i++) delete geoms[i];
for (int i=0; i<frames.size(); i++) delete frames[i];
for (int i=0; i<joints.size(); i++) delete joints[i];
for (int i=0; i<sites.size(); i++) delete sites[i];
for (int i=0; i<cameras.size(); i++) delete cameras[i];
for (int i=0; i<lights.size(); i++) delete lights[i];
bodies.clear();
geoms.clear();
frames.clear();
joints.clear();
sites.clear();
cameras.clear();
lights.clear();
if (spec.plugin.active && spec.plugin.name->empty() && model) {
model->DeleteElement(spec.plugin.element);
}
for (int i=0; i<bodies.size(); i++) bodies[i]->Release();
for (int i=0; i<geoms.size(); i++) geoms[i]->Release();
for (int i=0; i<frames.size(); i++) frames[i]->Release();
for (int i=0; i<joints.size(); i++) joints[i]->Release();
for (int i=0; i<sites.size(); i++) sites[i]->Release();
for (int i=0; i<cameras.size(); i++) cameras[i]->Release();
for (int i=0; i<lights.size(); i++) lights[i]->Release();
}
@@ -1840,19 +1920,27 @@ mjCFrame& mjCFrame::operator+=(const mjCBody& other) {
other.model->StoreKeyframes(model);
other.model->prefix = "";
other.model->suffix = "";
mjCModel* other_model = other.model;
mjCBody* subtree = new mjCBody(other, model);
other.ForgetKeyframes();
other.model->prefix = subtree->prefix;
other.model->suffix = subtree->suffix;
// attach or copy the subtree
mjCBody* subtree = model->deepcopy_ ? new mjCBody(other, model) : (mjCBody*)&other;
if (model->deepcopy_) {
other.ForgetKeyframes();
} else {
subtree->SetModel(model);
subtree->ResetId();
subtree->AddRef();
}
other_model->prefix = subtree->prefix;
other_model->suffix = subtree->suffix;
subtree->SetParent(body);
subtree->SetFrame(this);
subtree->NameSpace(other.model);
subtree->NameSpace(other_model);
// attach defaults
if (other.model != model) {
mjCDef* subdef = new mjCDef(*other.model->Default());
subdef->NameSpace(other.model);
if (other_model != model) {
mjCDef* subdef = new mjCDef(*other_model->Default());
subdef->NameSpace(other_model);
*model += *subdef;
}
@@ -1861,16 +1949,16 @@ mjCFrame& mjCFrame::operator+=(const mjCBody& other) {
last_attached = &body->bodies.back()->spec;
// attach referencing elements
*model += *other.model;
*model += *other_model;
// leave the source model in a clean state
if (other.model != model) {
other.model->key_pending_.clear();
if (other_model != model) {
other_model->key_pending_.clear();
}
// clear suffixes and return
other.model->suffix.clear();
other.model->prefix.clear();
other_model->suffix.clear();
other_model->prefix.clear();
return *this;
}
@@ -2221,14 +2309,6 @@ mjCGeom::mjCGeom(const mjCGeom& other) {
mjCGeom::~mjCGeom() {
if (spec.plugin.active && spec.plugin.name->empty() && model) {
model->DeleteElement(spec.plugin.element);
}
}
mjCGeom& mjCGeom::operator=(const mjCGeom& other) {
if (this != &other) {
this->spec = other.spec;
@@ -4591,7 +4671,7 @@ void mjCMaterial::CopyFromSpec() {
void mjCMaterial::NameSpace(const mjCModel* m) {
mjCBase::NameSpace(m);
for (int i=0; i<mjNTEXROLE; i++) {
if (!spec_textures_[i].empty() && model != m) {
if (!spec_textures_[i].empty()) {
spec_textures_[i] = m->prefix + spec_textures_[i] + m->suffix;
}
}
@@ -5657,14 +5737,6 @@ mjCActuator::mjCActuator(const mjCActuator& other) {
mjCActuator::~mjCActuator() {
if (spec.plugin.active && spec.plugin.name->empty() && model) {
model->DeleteElement(spec.plugin.element);
}
}
mjCActuator& mjCActuator::operator=(const mjCActuator& other) {
if (this != &other) {
this->spec = other.spec;
@@ -6033,14 +6105,6 @@ mjCSensor::mjCSensor(const mjCSensor& other) {
mjCSensor::~mjCSensor() {
if (spec.plugin.active && spec.plugin.name->empty() && model) {
model->DeleteElement(spec.plugin.element);
}
}
mjCSensor& mjCSensor::operator=(const mjCSensor& other) {
if (this != &other) {
this->spec = other.spec;