Forráskód Böngészése

reduce overhead on NodePath::find() operations

David Rose 23 éve
szülő
commit
5c48c68569

+ 10 - 7
panda/src/pgraph/findApproxLevelEntry.I

@@ -23,11 +23,12 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE FindApproxLevelEntry::
-FindApproxLevelEntry(const NodePath &node_path, FindApproxPath &approx_path) :
+FindApproxLevelEntry(const WorkingNodePath &node_path, FindApproxPath &approx_path) :
   _node_path(node_path),
   _approx_path(approx_path)
 {
   _i = 0;
+  nassertv(_node_path.is_valid());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -36,11 +37,12 @@ FindApproxLevelEntry(const NodePath &node_path, FindApproxPath &approx_path) :
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE FindApproxLevelEntry::
-FindApproxLevelEntry(const FindApproxLevelEntry &copy) :
+FindApproxLevelEntry(const FindApproxLevelEntry &copy, int increment) :
   _node_path(copy._node_path),
-  _i(copy._i),
+  _i(copy._i + increment),
   _approx_path(copy._approx_path)
 {
+  nassertv(_node_path.is_valid());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -53,6 +55,7 @@ operator = (const FindApproxLevelEntry &copy) {
   _node_path = copy._node_path;
   _i = copy._i;
   nassertv(&_approx_path == &copy._approx_path);
+  nassertv(_node_path.is_valid());
 }
 
 
@@ -63,8 +66,8 @@ operator = (const FindApproxLevelEntry &copy) {
 //               must be a stashed node, false otherwise.
 ////////////////////////////////////////////////////////////////////
 INLINE bool FindApproxLevelEntry::
-next_is_stashed() const {
-  return _approx_path.matches_stashed(_i);
+next_is_stashed(int increment) const {
+  return _approx_path.matches_stashed(_i + increment);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -75,6 +78,6 @@ next_is_stashed() const {
 //               been successfully matched.
 ////////////////////////////////////////////////////////////////////
 INLINE bool FindApproxLevelEntry::
-is_solution() const {
-  return (_i >= _approx_path.get_num_components());
+is_solution(int increment) const {
+  return (_i + increment >= _approx_path.get_num_components());
 }

+ 28 - 22
panda/src/pgraph/findApproxLevelEntry.cxx

@@ -30,7 +30,7 @@
 void FindApproxLevelEntry::
 output(ostream &out) const {
   out << "(" << _node_path << "):";
-  if (is_solution()) {
+  if (is_solution(0)) {
     out << " solution!";
   } else {
     out << "(";
@@ -46,34 +46,39 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 void FindApproxLevelEntry::
 consider_node(NodePathCollection &result, FindApproxLevel &next_level,
-              int max_matches) const {
-  nassertv(_i < _approx_path.get_num_components());
+              int max_matches, int increment) const {
+  nassertv(_i + increment < _approx_path.get_num_components());
 
-  if (_approx_path.is_component_match_many(_i)) {
+  if (_approx_path.is_component_match_many(_i + increment)) {
     // Match any number, zero or more, levels of nodes.  This is the
     // tricky case that requires this whole nutty breadth-first thing.
 
     // This means we must reconsider our own entry with the next path
     // entry, before we consider the next entry--this supports
     // matching zero levels of nodes.
-    FindApproxLevelEntry reconsider(*this);
-    ++reconsider._i;
 
-    if (reconsider.is_solution()) {
+    // We used to make a temporary copy of our own record, and then
+    // increment _i on that copy, but we can't do that nowadays
+    // because the WorkingNodePath object stores a pointer to each
+    // previous generation, which means we can't use any temporary
+    // FindApproxLevelEntry objects.  Instead, we pass around the
+    // increment parameter, which increments _i on the fly.
+
+    if (is_solution(increment + 1)) {
       // Does this now represent a solution?
-      result.add_path(reconsider._node_path);
-      if (max_matches > 0 && result.get_num_paths() >= max_matches) {
+      result.add_path(_node_path.get_node_path());
+      if (max_matches > 0 && result.get_num_paths() >= max_matches) { 
         return;
       }
     } else {
-      reconsider.consider_node(result, next_level, max_matches);
+      consider_node(result, next_level, max_matches, increment + 1);
     }
   }
 
   PandaNode *this_node = _node_path.node();
   nassertv(this_node != (PandaNode *)NULL);
 
-  bool stashed_only = next_is_stashed();
+  bool stashed_only = next_is_stashed(increment);
 
   if (!stashed_only) {
     // Check the normal list of children.
@@ -81,7 +86,7 @@ consider_node(NodePathCollection &result, FindApproxLevel &next_level,
     for (int i = 0; i < num_children; i++) {
       PandaNode *child_node = this_node->get_child(i);
       
-      consider_next_step(result, child_node, next_level, max_matches);
+      consider_next_step(result, child_node, next_level, max_matches, increment);
       if (max_matches > 0 && result.get_num_paths() >= max_matches) {
         return;
       }
@@ -94,7 +99,7 @@ consider_node(NodePathCollection &result, FindApproxLevel &next_level,
     for (int i = 0; i < num_stashed; i++) {
       PandaNode *stashed_node = this_node->get_stashed(i);
       
-      consider_next_step(result, stashed_node, next_level, max_matches);
+      consider_next_step(result, stashed_node, next_level, max_matches, increment);
       if (max_matches > 0 && result.get_num_paths() >= max_matches) {
         return;
       }
@@ -115,7 +120,8 @@ consider_node(NodePathCollection &result, FindApproxLevel &next_level,
 ////////////////////////////////////////////////////////////////////
 void FindApproxLevelEntry::
 consider_next_step(NodePathCollection &result, PandaNode *child_node,
-                   FindApproxLevel &next_level, int max_matches) const {
+                   FindApproxLevel &next_level, int max_matches,
+                   int increment) const {
   if (!_approx_path.return_hidden() &&
       child_node->get_draw_mask().is_zero()) {
     // If the approx path does not allow us to return hidden nodes,
@@ -124,25 +130,25 @@ consider_next_step(NodePathCollection &result, PandaNode *child_node,
     return;
   }
 
-  nassertv(_i < _approx_path.get_num_components());
+  nassertv(_i + increment < _approx_path.get_num_components());
 
-  if (_approx_path.is_component_match_many(_i)) {
+  if (_approx_path.is_component_match_many(_i + increment)) {
     // Match any number, zero or more, levels of nodes.  This is the
     // tricky case that requires this whole nutty breadth-first thing.
 
     // And now we just add the next entry without incrementing its
     // path entry.
 
-    FindApproxLevelEntry next(*this);
-    next._node_path = NodePath(_node_path, child_node);
+    FindApproxLevelEntry next(*this, increment);
+    next._node_path = WorkingNodePath(_node_path, child_node);
     next_level.add_entry(next);
 
   } else {
-    if (_approx_path.matches_component(_i, child_node)) {
+    if (_approx_path.matches_component(_i + increment, child_node)) {
       // That matched, and it consumes one path entry.
-      FindApproxLevelEntry next(*this);
-      ++next._i;
-      next._node_path = NodePath(_node_path, child_node);
+      FindApproxLevelEntry next(*this, increment);
+      next._i++;
+      next._node_path = WorkingNodePath(_node_path, child_node);
       next_level.add_entry(next);
     }
   }

+ 8 - 8
panda/src/pgraph/findApproxLevelEntry.h

@@ -22,7 +22,7 @@
 #include "pandabase.h"
 
 #include "findApproxPath.h"
-#include "nodePath.h"
+#include "workingNodePath.h"
 
 class FindApproxLevel;
 class NodePathCollection;
@@ -36,25 +36,25 @@ class NodePathCollection;
 ////////////////////////////////////////////////////////////////////
 class FindApproxLevelEntry {
 public:
-  INLINE FindApproxLevelEntry(const NodePath &node_path,
+  INLINE FindApproxLevelEntry(const WorkingNodePath &node_path,
                               FindApproxPath &approx_path);
-  INLINE FindApproxLevelEntry(const FindApproxLevelEntry &copy);
+  INLINE FindApproxLevelEntry(const FindApproxLevelEntry &copy, int increment = 0);
   INLINE void operator = (const FindApproxLevelEntry &copy);
 
-  INLINE bool next_is_stashed() const;
+  INLINE bool next_is_stashed(int increment) const;
 
   void consider_node(NodePathCollection &result, FindApproxLevel &next_level,
-                     int max_matches) const;
+                     int max_matches, int increment) const;
   void consider_next_step(NodePathCollection &result,
                           PandaNode *child_node, FindApproxLevel &next_level,
-                          int max_matches) const;
-  INLINE bool is_solution() const;
+                          int max_matches, int increment) const;
+  INLINE bool is_solution(int increment) const;
 
   void output(ostream &out) const;
 
   // _node_path represents the most recent node that we have
   // previously accepted as being a partial solution.
-  NodePath _node_path;
+  WorkingNodePath _node_path;
 
   // _i represents the next component in the approx_path that must be
   // matched against all of the children of _node_path, above.  If _i

+ 5 - 4
panda/src/pgraph/nodePath.cxx

@@ -3083,7 +3083,8 @@ find_matches(NodePathCollection &result, FindApproxPath &approx_path,
       << "Attempt to extend an empty NodePath by: " << approx_path << ".\n";
     return;
   }
-  FindApproxLevelEntry start(*this, approx_path);
+  FindApproxLevelEntry start(WorkingNodePath(*this), approx_path);
+  nassertv(start._node_path.is_valid());
   FindApproxLevel level;
   level.add_entry(start);
   r_find_matches(result, level, max_matches, _max_search_depth);
@@ -3114,11 +3115,11 @@ r_find_matches(NodePathCollection &result,
   for (li = level._v.begin(); li != level._v.end() && okflag; ++li) {
     const FindApproxLevelEntry &entry = (*li);
 
-    if (entry.is_solution()) {
+    if (entry.is_solution(0)) {
       // Does this entry already represent a solution?
-      result.add_path(entry._node_path);
+      result.add_path(entry._node_path.get_node_path());
     } else {
-      entry.consider_node(result, next_level, max_matches);
+      entry.consider_node(result, next_level, max_matches, 0);
     }
 
     if (max_matches > 0 && result.get_num_paths() >= max_matches) {

+ 36 - 0
panda/src/pgraph/workingNodePath.I

@@ -33,6 +33,21 @@ WorkingNodePath(const NodePath &start) {
   _node = start.node();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: WorkingNodePath::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE WorkingNodePath::
+WorkingNodePath(const WorkingNodePath &copy) :
+  _next(copy._next),
+  _start(copy._start),
+  _node(copy._node)
+{
+  nassertv(_next != (WorkingNodePath *)NULL ||
+           _start != (NodePathComponent *)NULL);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: WorkingNodePath::Constructor
 //       Access: Public
@@ -57,6 +72,21 @@ INLINE WorkingNodePath::
 ~WorkingNodePath() {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: WorkingNodePath::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void WorkingNodePath::
+operator = (const WorkingNodePath &copy) {
+  _next = copy._next;
+  _start = copy._start;
+  _node = copy._node;
+
+  nassertv(_next != (WorkingNodePath *)NULL ||
+           _start != (NodePathComponent *)NULL);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: WorkingNodePath::get_node_path
 //       Access: Public
@@ -80,3 +110,9 @@ INLINE PandaNode *WorkingNodePath::
 node() const {
   return _node;
 }
+
+INLINE ostream &
+operator << (ostream &out, const WorkingNodePath &node_path) {
+  node_path.output(out);
+  return out;
+}

+ 37 - 3
panda/src/pgraph/workingNodePath.cxx

@@ -19,9 +19,27 @@
 #include "workingNodePath.h"
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: WorkingNodePath::is_valid
+//       Access: Public
+//  Description: Returns true if the WorkingNodePath object appears to
+//               be a valid NodePath reference, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool WorkingNodePath::
+is_valid() const {
+  if (_node == (PandaNode *)NULL) {
+    return false;
+  }
+  if (_next == (WorkingNodePath *)NULL) {
+    return (_start != (NodePathComponent *)NULL);
+  }
+
+  return _next->is_valid();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: WorkingNodePath::get_num_nodes
-//       Access: Published
+//       Access: Public
 //  Description: Returns the number of nodes in the path from the root
 //               to the current node.
 //
@@ -40,7 +58,7 @@ get_num_nodes() const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: WorkingNodePath::get_node
-//       Access: Published
+//       Access: Public
 //  Description: Returns the nth node of the path, where 0 is the
 //               referenced (bottom) node and get_num_nodes() - 1 is
 //               the top node.  This requires iterating through the
@@ -60,6 +78,18 @@ get_node(int index) const {
   return _next->get_node(index - 1);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: WorkingNodePath::output
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void WorkingNodePath::
+output(ostream &out) const {
+  // Cheesy and slow, but when you're outputting the thing, presumably
+  // you're not in a hurry.
+  get_node_path().output(out);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: WorkingNodePath::r_get_node_path
 //       Access: Private
@@ -70,6 +100,7 @@ get_node(int index) const {
 PT(NodePathComponent) WorkingNodePath::
 r_get_node_path() const {
   if (_next == (WorkingNodePath *)NULL) {
+    nassertr(_start != (NodePathComponent *)NULL, NULL);
     return _start;
   }
 
@@ -78,5 +109,8 @@ r_get_node_path() const {
 
   PT(NodePathComponent) comp = _next->r_get_node_path();
   nassertr(comp != (NodePathComponent *)NULL, NULL);
-  return PandaNode::get_component(comp, _node);
+
+  PT(NodePathComponent) result = PandaNode::get_component(comp, _node);
+  nassertr(result != (NodePathComponent *)NULL, NULL);
+  return result;
 }

+ 9 - 0
panda/src/pgraph/workingNodePath.h

@@ -49,15 +49,22 @@
 class EXPCL_PANDA WorkingNodePath {
 public:
   INLINE WorkingNodePath(const NodePath &start);
+  INLINE WorkingNodePath(const WorkingNodePath &copy);
   INLINE WorkingNodePath(const WorkingNodePath &parent, PandaNode *child);
   INLINE ~WorkingNodePath();
 
+  INLINE void operator = (const WorkingNodePath &copy);
+
+  bool is_valid() const;
+
   INLINE NodePath get_node_path() const;
   INLINE PandaNode *node() const;
 
   int get_num_nodes() const;
   PandaNode *get_node(int index) const;
 
+  void output(ostream &out) const;
+
 private:
   PT(NodePathComponent) r_get_node_path() const;
 
@@ -70,6 +77,8 @@ private:
   PandaNode *_node;
 };
 
+INLINE ostream &operator << (ostream &out, const WorkingNodePath &node_path);
+
 #include "workingNodePath.I"
 
 #endif