Optimize scene node child removal to constant time (#275)

This commit is contained in:
Lars Müller 2024-01-08 18:43:24 +01:00 committed by GitHub
parent 73e62f8676
commit 3983c29645
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 27 additions and 27 deletions

View File

@ -15,6 +15,7 @@
#include "matrix4.h" #include "matrix4.h"
#include "IAttributes.h" #include "IAttributes.h"
#include <list> #include <list>
#include <optional>
namespace irr namespace irr
{ {
@ -275,31 +276,31 @@ namespace scene
child->grab(); child->grab();
child->remove(); // remove from old parent child->remove(); // remove from old parent
Children.push_back(child); // Note: This iterator is not invalidated until we erase it.
child->ThisIterator = Children.insert(Children.end(), child);
child->Parent = this; child->Parent = this;
} }
} }
//! Removes a child from this scene node. //! Removes a child from this scene node.
/** If found in the children list, the child pointer is also /**
dropped and might be deleted if no other grab exists.
\param child A pointer to the child which shall be removed. \param child A pointer to the child which shall be removed.
\return True if the child was removed, and false if not, \return True if the child was removed, and false if not,
e.g. because it couldn't be found in the children list. */ e.g. because it belongs to a different parent or no parent. */
virtual bool removeChild(ISceneNode* child) virtual bool removeChild(ISceneNode* child)
{ {
ISceneNodeList::iterator it = Children.begin(); if (child->Parent != this)
for (; it != Children.end(); ++it) return false;
if ((*it) == child)
{
(*it)->Parent = 0;
(*it)->drop();
Children.erase(it);
return true;
}
return false; // The iterator must be set since the parent is not null.
_IRR_DEBUG_BREAK_IF(!child->ThisIterator.has_value());
auto it = *child->ThisIterator;
child->ThisIterator = std::nullopt;
child->Parent = nullptr;
child->drop();
Children.erase(it);
return true;
} }
@ -309,13 +310,11 @@ namespace scene
*/ */
virtual void removeAll() virtual void removeAll()
{ {
ISceneNodeList::iterator it = Children.begin(); for (auto &child : Children) {
for (; it != Children.end(); ++it) child->Parent = nullptr;
{ child->ThisIterator = std::nullopt;
(*it)->Parent = 0; child->drop();
(*it)->drop();
} }
Children.clear(); Children.clear();
} }
@ -508,10 +507,8 @@ namespace scene
grab(); grab();
remove(); remove();
Parent = newParent; if (newParent)
newParent->addChild(this);
if (Parent)
Parent->addChild(this);
drop(); drop();
} }
@ -618,12 +615,15 @@ namespace scene
//! Relative scale of the scene node. //! Relative scale of the scene node.
core::vector3df RelativeScale; core::vector3df RelativeScale;
//! Pointer to the parent
ISceneNode* Parent;
//! List of all children of this node //! List of all children of this node
std::list<ISceneNode*> Children; std::list<ISceneNode*> Children;
//! Iterator pointing to this node in the parent's child list.
std::optional<ISceneNodeList::iterator> ThisIterator;
//! Pointer to the parent
ISceneNode* Parent;
//! Pointer to the scene manager //! Pointer to the scene manager
ISceneManager* SceneManager; ISceneManager* SceneManager;