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.
"""
This commit is contained in:
mfranz
2007-02-11 11:05:23 +00:00
parent 6c5d35d6ce
commit 8663c265d8
2 changed files with 81 additions and 5 deletions
+62 -2
View File
@@ -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. * Remove child by position.
*/ */
@@ -927,8 +942,8 @@ SGPropertyNode::removeChild (int pos, bool keep)
if (keep) { if (keep) {
_removedChildren.push_back(node); _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->setAttribute(REMOVED, true);
node->clearValue(); node->clearValue();
fireChildRemoved(node); 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<hash_table *>::iterator it = _linkedNodes.begin();
it += i;
_linkedNodes.erase(it);
return true;
}
}
return false;
}
const char * const char *
SGPropertyNode::getDisplayName (bool simplify) const 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 () SGPropertyNode::hash_table::hash_table ()
: _data_length(0), : _data_length(0),
@@ -2254,6 +2301,7 @@ SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
} }
entry * e = _data[index]->get_entry(key, true); entry * e = _data[index]->get_entry(key, true);
e->set_value(value); e->set_value(value);
value->add_linked_node(this);
} }
void void
@@ -2264,7 +2312,19 @@ SGPropertyNode::hash_table::erase (const char * key)
unsigned int index = hashcode(key) % _data_length; unsigned int index = hashcode(key) % _data_length;
if (_data[index] == 0) if (_data[index] == 0)
return; return;
_data[index]->get_entry(key, true)->get_value()->remove_linked_node(this);
_data[index]->erase(key); _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 unsigned int
+19 -3
View File
@@ -1183,6 +1183,12 @@ private:
void trace_write () const; 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; class hash_table;
int _index; int _index;
@@ -1193,6 +1199,7 @@ private:
SGPropertyNode * _parent; SGPropertyNode * _parent;
vector<SGPropertyNode_ptr> _children; vector<SGPropertyNode_ptr> _children;
vector<SGPropertyNode_ptr> _removedChildren; vector<SGPropertyNode_ptr> _removedChildren;
vector<hash_table *> _linkedNodes;
mutable string _path; mutable string _path;
mutable string _buffer; mutable string _buffer;
hash_table * _path_cache; hash_table * _path_cache;
@@ -1223,9 +1230,16 @@ private:
vector <SGPropertyChangeListener *> * _listeners; vector <SGPropertyChangeListener *> * _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 { class hash_table {
public: public:
@@ -1255,7 +1269,8 @@ private:
bucket (); bucket ();
~bucket (); ~bucket ();
entry * get_entry (const char * key, bool create = false); entry * get_entry (const char * key, bool create = false);
void erase(const char * key); void erase (const char * key);
bool erase (SGPropertyNode * node);
private: private:
int _length; int _length;
entry ** _entries; entry ** _entries;
@@ -1267,7 +1282,8 @@ private:
~hash_table (); ~hash_table ();
SGPropertyNode * get (const char * key); SGPropertyNode * get (const char * key);
void put (const char * key, SGPropertyNode * value); void put (const char * key, SGPropertyNode * value);
void erase(const char * key); void erase (const char * key);
bool erase (SGPropertyNode * node);
private: private:
unsigned int hashcode (const char * key); unsigned int hashcode (const char * key);