From 8663c265d8da5d1401e3fb2d11c4bd274fb0794f Mon Sep 17 00:00:00 2001 From: mfranz Date: Sun, 11 Feb 2007 11:05:23 +0000 Subject: [PATCH] Maik JUSTUS: """ - make every node maintain list of properties that link to it - add functions to erase node by address from hash bucket/entry in their path caches, so that all references can be removed - if a node is removed, it (and all children, grandchildren, ...) calls all linked properties to remove them from their path-cache This fixes problems with the aerotow over multiplayer and maybe some other problems, where nodes are queried by name. """ --- simgear/props/props.cxx | 64 +++++++++++++++++++++++++++++++++++++++-- simgear/props/props.hxx | 22 ++++++++++++-- 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/simgear/props/props.cxx b/simgear/props/props.cxx index 3ce2687d..fe300112 100644 --- a/simgear/props/props.cxx +++ b/simgear/props/props.cxx @@ -910,6 +910,21 @@ SGPropertyNode::getChildren (const char * name) const } +/** + * Remove this node from all nodes that link to it in their path cache. + */ +void +SGPropertyNode::remove_from_path_caches () +{ + for (unsigned int i = 0; i < _linkedNodes.size(); i++) + _linkedNodes[i]->erase(this); + + _linkedNodes.clear(); + for (unsigned int i = 0; i < _children.size(); ++i) + _children[i]->remove_from_path_caches(); +} + + /** * Remove child by position. */ @@ -927,8 +942,8 @@ SGPropertyNode::removeChild (int pos, bool keep) if (keep) { _removedChildren.push_back(node); } - if (_path_cache) - _path_cache->erase(node->getName()); // EMH - TODO: Take "index" into account! + + node->remove_from_path_caches(); node->setAttribute(REMOVED, true); node->clearValue(); fireChildRemoved(node); @@ -967,6 +982,24 @@ SGPropertyNode::removeChildren (const char * name, bool keep) } +/** + * Remove a linked node. + */ +bool +SGPropertyNode::remove_linked_node (hash_table * node) +{ + for (unsigned int i = 0; i < _linkedNodes.size(); i++) { + if (_linkedNodes[i] == node) { + vector::iterator it = _linkedNodes.begin(); + it += i; + _linkedNodes.erase(it); + return true; + } + } + return false; +} + + const char * SGPropertyNode::getDisplayName (bool simplify) const { @@ -2210,6 +2243,20 @@ SGPropertyNode::hash_table::bucket::erase (const char * key) } } +bool +SGPropertyNode::hash_table::bucket::erase (SGPropertyNode * node) +{ + for (int i = 0; i < _length; i++) { + if (_entries[i]->get_value() == node) { + for (++i; i < _length; i++) { + _entries[i-1] = _entries[i]; + } + _length--; + return true; + } + } + return false; +} SGPropertyNode::hash_table::hash_table () : _data_length(0), @@ -2254,6 +2301,7 @@ SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value) } entry * e = _data[index]->get_entry(key, true); e->set_value(value); + value->add_linked_node(this); } void @@ -2264,7 +2312,19 @@ SGPropertyNode::hash_table::erase (const char * key) unsigned int index = hashcode(key) % _data_length; if (_data[index] == 0) return; + _data[index]->get_entry(key, true)->get_value()->remove_linked_node(this); _data[index]->erase(key); + _data[index] = 0; +} + +bool +SGPropertyNode::hash_table::erase (SGPropertyNode * node) +{ + for (unsigned int d = 0; d < _data_length; d++) + if (_data[d] && _data[d]->erase(node)) + return true; + + return false; } unsigned int diff --git a/simgear/props/props.hxx b/simgear/props/props.hxx index 7c38fcb1..24967639 100644 --- a/simgear/props/props.hxx +++ b/simgear/props/props.hxx @@ -1183,6 +1183,12 @@ private: void trace_write () const; + /** + * Remove this node from all nodes that link to it in their path cache. + */ + void remove_from_path_caches(); + + class hash_table; int _index; @@ -1193,6 +1199,7 @@ private: SGPropertyNode * _parent; vector _children; vector _removedChildren; + vector _linkedNodes; mutable string _path; mutable string _buffer; hash_table * _path_cache; @@ -1223,9 +1230,16 @@ private: vector * _listeners; + /** + * Register/unregister node that links to this node in its path cache. + */ + void add_linked_node (hash_table * node) { _linkedNodes.push_back(node); } + bool remove_linked_node (hash_table * node); + + /** - * A very simple hash table with no remove functionality. + * A very simple hash table. */ class hash_table { public: @@ -1255,7 +1269,8 @@ private: bucket (); ~bucket (); entry * get_entry (const char * key, bool create = false); - void erase(const char * key); + void erase (const char * key); + bool erase (SGPropertyNode * node); private: int _length; entry ** _entries; @@ -1267,7 +1282,8 @@ private: ~hash_table (); SGPropertyNode * get (const char * key); void put (const char * key, SGPropertyNode * value); - void erase(const char * key); + void erase (const char * key); + bool erase (SGPropertyNode * node); private: unsigned int hashcode (const char * key); -- 2.39.5