]> git.mxchange.org Git - simgear.git/commitdiff
Maik JUSTUS:
authormfranz <mfranz>
Sun, 11 Feb 2007 11:05:23 +0000 (11:05 +0000)
committermfranz <mfranz>
Sun, 11 Feb 2007 11:05:23 +0000 (11:05 +0000)
"""
- 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
simgear/props/props.hxx

index 3ce2687da62d906a14f56e7a877024c78765432e..fe3001129f475e27b1f708933e1023ae06ec5bc4 100644 (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.
  */
@@ -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<hash_table *>::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
index 7c38fcb14b755851029eb115da0551cc733d448c..249676397d84afc376bc66d043679e0be342c0eb 100644 (file)
@@ -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<SGPropertyNode_ptr> _children;
   vector<SGPropertyNode_ptr> _removedChildren;
+  vector<hash_table *> _linkedNodes;
   mutable string _path;
   mutable string _buffer;
   hash_table * _path_cache;
@@ -1223,9 +1230,16 @@ private:
   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);
+
+
 \f
   /**
-   * 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);