From 24f908d9be3b6db5fe56e0071917ae9a42df3d46 Mon Sep 17 00:00:00 2001 From: ehofman Date: Mon, 27 Jun 2005 13:49:28 +0000 Subject: [PATCH] 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. --- simgear/props/props.cxx | 72 ++++++++++++++++++++++++++++++++--------- simgear/props/props.hxx | 12 +++++-- 2 files changed, 66 insertions(+), 18 deletions(-) diff --git a/simgear/props/props.cxx b/simgear/props/props.cxx index dd8cb0c0..7c004b5a 100644 --- a/simgear/props/props.cxx +++ b/simgear/props/props.cxx @@ -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::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); + } + } + 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::iterator it = _children.end(); + vector::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); } - 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; } diff --git a/simgear/props/props.hxx b/simgear/props/props.hxx index 9ce7df4b..75da1a0c 100644 --- a/simgear/props/props.hxx +++ b/simgear/props/props.hxx @@ -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); // -- 2.39.5