Melchior FRANZ:

- introduce removeChildren() and removeChildren(name)  to remove all children
  or all with a given name
- let removeChild() and removeChildren() also remove child trees, and let them
  return a "dirty" boolean that indicates if one or more subnodes had to be
  kept because of refcounting (removeChild returned a SGPropertyNode_ptr before)
- make alias/unalias increase/decrease the refcounter
- don't remove refcounted or tied nodes

This patch makes the SGPropertyNode_ptr actually useful. Until today, they did
proper refcounting (except for aliases), but no other part did check this counter.

But SGPropertyNode_ptr aren't only useful for the first time, they are now
highly recommended for every place that relies on a node address, and wants
to "lock" it (so that removeChild(ren) will never try to remove them). This
is not guaranteed for SGPropertyNode* (and never was). Of course, that's not
an imminent problem, as only four places currently use removeChild(ren) and
these are careful to only remove their own data.
This commit is contained in:
ehofman
2005-06-27 13:49:28 +00:00
parent f62ff0ad66
commit 24f908d9be
2 changed files with 65 additions and 17 deletions

View File

@@ -778,6 +778,7 @@ SGPropertyNode::alias (SGPropertyNode * target)
clearValue();
_value.alias = target;
_type = ALIAS;
_value.alias->incrementRef();
return true;
}
@@ -801,6 +802,7 @@ SGPropertyNode::unalias ()
if (_type != ALIAS)
return false;
_type = NONE;
_value.alias->decrementRef();
_value.alias = 0;
return true;
}
@@ -912,29 +914,69 @@ SGPropertyNode::getChildren (const char * name) const
/**
* Remove a child node
* Remove a child node, and all children that aren't referenced.
* "keep" does only apply to the outmost item. Returns "true" if
* not all nodes could be removed.
*/
SGPropertyNode_ptr
bool
SGPropertyNode::removeChild (const char * name, int index, bool keep)
{
SGPropertyNode_ptr ret;
bool dirty = false;
int pos = find_child(name, index, _children);
if (pos >= 0) {
vector<SGPropertyNode_ptr>::iterator it = _children.begin();
it += pos;
SGPropertyNode_ptr node = _children[pos];
_children.erase(it);
if (keep) {
_removedChildren.push_back(node);
SGPropertyNode *node = _children[pos];
if (node->nChildren() && node->removeChildren())
dirty = true;
if (node->_count == 1 && !node->nChildren()) {
if (keep)
_removedChildren.push_back(node);
if (_path_cache)
_path_cache->erase(name); // EMH - TODO: Take "index" into account!
node->setAttribute(REMOVED, true);
node->clearValue();
fireChildRemoved(node);
_children.erase(it);
}
if (_path_cache)
_path_cache->erase(name); // EMH - TODO: Take "index" into account!
node->setAttribute(REMOVED, true);
node->clearValue();
ret = node;
fireChildRemoved(node);
}
return ret;
return dirty;
}
/**
* Remove all children nodes, or all with a given name. Returns
* "true" if not all nodes could be removed.
*/
bool
SGPropertyNode::removeChildren(const char *name)
{
bool dirty = false;
vector<SGPropertyNode_ptr>::iterator it = _children.end();
vector<SGPropertyNode_ptr>::iterator begin = _children.begin();
while (it-- != begin) {
SGPropertyNode *node = *it;
if (name && !compare_strings(node->getName(), name))
continue;
if (node->nChildren() && node->removeChildren())
dirty = true;
if (node->isTied() || node->_count != 1 || node->nChildren())
dirty = true;
else {
if (_path_cache)
_path_cache->erase(node->getName());
node->setAttribute(REMOVED, true);
node->clearValue();
fireChildRemoved(node);
_children.erase(it);
}
}
return dirty;
}

View File

@@ -707,10 +707,16 @@ public:
/**
* Remove a child node
* Remove a child node (returns true if at least one node had to remain,
* because it was tied, aliased, or refcounted through SGPropertyNode_ptr.
*/
SGPropertyNode_ptr removeChild (const char * name, int index = 0,
bool keep = true);
bool removeChild (const char * name, int index = 0, bool keep = true);
/**
* Remove all children nodes, or all with a given name.
*/
bool removeChildren(const char * name = 0);
//