From 5c48c685695456db2ac29f60ef826440ae5283ed Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 9 Apr 2003 15:59:53 +0000 Subject: [PATCH] reduce overhead on NodePath::find() operations --- panda/src/pgraph/findApproxLevelEntry.I | 17 ++++---- panda/src/pgraph/findApproxLevelEntry.cxx | 50 +++++++++++++---------- panda/src/pgraph/findApproxLevelEntry.h | 16 ++++---- panda/src/pgraph/nodePath.cxx | 9 ++-- panda/src/pgraph/workingNodePath.I | 36 ++++++++++++++++ panda/src/pgraph/workingNodePath.cxx | 40 ++++++++++++++++-- panda/src/pgraph/workingNodePath.h | 9 ++++ 7 files changed, 133 insertions(+), 44 deletions(-) diff --git a/panda/src/pgraph/findApproxLevelEntry.I b/panda/src/pgraph/findApproxLevelEntry.I index aff0365bfe..f80fe8b3a1 100644 --- a/panda/src/pgraph/findApproxLevelEntry.I +++ b/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 ©) : +FindApproxLevelEntry(const FindApproxLevelEntry ©, 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 ©) { _node_path = copy._node_path; _i = copy._i; nassertv(&_approx_path == ©._approx_path); + nassertv(_node_path.is_valid()); } @@ -63,8 +66,8 @@ operator = (const FindApproxLevelEntry ©) { // 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()); } diff --git a/panda/src/pgraph/findApproxLevelEntry.cxx b/panda/src/pgraph/findApproxLevelEntry.cxx index 6ad8a75f91..1ef57465b1 100644 --- a/panda/src/pgraph/findApproxLevelEntry.cxx +++ b/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); } } diff --git a/panda/src/pgraph/findApproxLevelEntry.h b/panda/src/pgraph/findApproxLevelEntry.h index 4b2ba58f9b..6eb8348cc7 100644 --- a/panda/src/pgraph/findApproxLevelEntry.h +++ b/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 ©); + INLINE FindApproxLevelEntry(const FindApproxLevelEntry ©, int increment = 0); INLINE void operator = (const FindApproxLevelEntry ©); - 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 diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index b1397d05b6..7c8aa498d1 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/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) { diff --git a/panda/src/pgraph/workingNodePath.I b/panda/src/pgraph/workingNodePath.I index c19df9298f..102e9f5113 100644 --- a/panda/src/pgraph/workingNodePath.I +++ b/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 ©) : + _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 ©) { + _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; +} diff --git a/panda/src/pgraph/workingNodePath.cxx b/panda/src/pgraph/workingNodePath.cxx index 11adaaac7b..d49804e3d4 100644 --- a/panda/src/pgraph/workingNodePath.cxx +++ b/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; } diff --git a/panda/src/pgraph/workingNodePath.h b/panda/src/pgraph/workingNodePath.h index fc1589adf8..cfee1c5615 100644 --- a/panda/src/pgraph/workingNodePath.h +++ b/panda/src/pgraph/workingNodePath.h @@ -49,15 +49,22 @@ class EXPCL_PANDA WorkingNodePath { public: INLINE WorkingNodePath(const NodePath &start); + INLINE WorkingNodePath(const WorkingNodePath ©); INLINE WorkingNodePath(const WorkingNodePath &parent, PandaNode *child); INLINE ~WorkingNodePath(); + INLINE void operator = (const WorkingNodePath ©); + + 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