reduce overhead on NodePath::find() operations

This commit is contained in:
David Rose 2003-04-09 15:59:53 +00:00
parent c231386f16
commit 5c48c68569
7 changed files with 133 additions and 44 deletions

View File

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

View File

@ -30,7 +30,7 @@
void FindApproxLevelEntry:: void FindApproxLevelEntry::
output(ostream &out) const { output(ostream &out) const {
out << "(" << _node_path << "):"; out << "(" << _node_path << "):";
if (is_solution()) { if (is_solution(0)) {
out << " solution!"; out << " solution!";
} else { } else {
out << "("; out << "(";
@ -46,34 +46,39 @@ output(ostream &out) const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void FindApproxLevelEntry:: void FindApproxLevelEntry::
consider_node(NodePathCollection &result, FindApproxLevel &next_level, consider_node(NodePathCollection &result, FindApproxLevel &next_level,
int max_matches) const { int max_matches, int increment) const {
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 // Match any number, zero or more, levels of nodes. This is the
// tricky case that requires this whole nutty breadth-first thing. // tricky case that requires this whole nutty breadth-first thing.
// This means we must reconsider our own entry with the next path // This means we must reconsider our own entry with the next path
// entry, before we consider the next entry--this supports // entry, before we consider the next entry--this supports
// matching zero levels of nodes. // 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? // Does this now represent a solution?
result.add_path(reconsider._node_path); result.add_path(_node_path.get_node_path());
if (max_matches > 0 && result.get_num_paths() >= max_matches) { if (max_matches > 0 && result.get_num_paths() >= max_matches) {
return; return;
} }
} else { } else {
reconsider.consider_node(result, next_level, max_matches); consider_node(result, next_level, max_matches, increment + 1);
} }
} }
PandaNode *this_node = _node_path.node(); PandaNode *this_node = _node_path.node();
nassertv(this_node != (PandaNode *)NULL); nassertv(this_node != (PandaNode *)NULL);
bool stashed_only = next_is_stashed(); bool stashed_only = next_is_stashed(increment);
if (!stashed_only) { if (!stashed_only) {
// Check the normal list of children. // 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++) { for (int i = 0; i < num_children; i++) {
PandaNode *child_node = this_node->get_child(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) { if (max_matches > 0 && result.get_num_paths() >= max_matches) {
return; return;
} }
@ -94,7 +99,7 @@ consider_node(NodePathCollection &result, FindApproxLevel &next_level,
for (int i = 0; i < num_stashed; i++) { for (int i = 0; i < num_stashed; i++) {
PandaNode *stashed_node = this_node->get_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) { if (max_matches > 0 && result.get_num_paths() >= max_matches) {
return; return;
} }
@ -115,7 +120,8 @@ consider_node(NodePathCollection &result, FindApproxLevel &next_level,
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void FindApproxLevelEntry:: void FindApproxLevelEntry::
consider_next_step(NodePathCollection &result, PandaNode *child_node, 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() && if (!_approx_path.return_hidden() &&
child_node->get_draw_mask().is_zero()) { child_node->get_draw_mask().is_zero()) {
// If the approx path does not allow us to return hidden nodes, // 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; 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 // Match any number, zero or more, levels of nodes. This is the
// tricky case that requires this whole nutty breadth-first thing. // tricky case that requires this whole nutty breadth-first thing.
// And now we just add the next entry without incrementing its // And now we just add the next entry without incrementing its
// path entry. // path entry.
FindApproxLevelEntry next(*this); FindApproxLevelEntry next(*this, increment);
next._node_path = NodePath(_node_path, child_node); next._node_path = WorkingNodePath(_node_path, child_node);
next_level.add_entry(next); next_level.add_entry(next);
} else { } 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. // That matched, and it consumes one path entry.
FindApproxLevelEntry next(*this); FindApproxLevelEntry next(*this, increment);
++next._i; next._i++;
next._node_path = NodePath(_node_path, child_node); next._node_path = WorkingNodePath(_node_path, child_node);
next_level.add_entry(next); next_level.add_entry(next);
} }
} }

View File

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

View File

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

View File

@ -33,6 +33,21 @@ WorkingNodePath(const NodePath &start) {
_node = start.node(); _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 // Function: WorkingNodePath::Constructor
// Access: Public // Access: Public
@ -57,6 +72,21 @@ INLINE WorkingNodePath::
~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 // Function: WorkingNodePath::get_node_path
// Access: Public // Access: Public
@ -80,3 +110,9 @@ INLINE PandaNode *WorkingNodePath::
node() const { node() const {
return _node; return _node;
} }
INLINE ostream &
operator << (ostream &out, const WorkingNodePath &node_path) {
node_path.output(out);
return out;
}

View File

@ -19,9 +19,27 @@
#include "workingNodePath.h" #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 // Function: WorkingNodePath::get_num_nodes
// Access: Published // Access: Public
// Description: Returns the number of nodes in the path from the root // Description: Returns the number of nodes in the path from the root
// to the current node. // to the current node.
// //
@ -40,7 +58,7 @@ get_num_nodes() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: WorkingNodePath::get_node // Function: WorkingNodePath::get_node
// Access: Published // Access: Public
// Description: Returns the nth node of the path, where 0 is the // Description: Returns the nth node of the path, where 0 is the
// referenced (bottom) node and get_num_nodes() - 1 is // referenced (bottom) node and get_num_nodes() - 1 is
// the top node. This requires iterating through the // the top node. This requires iterating through the
@ -60,6 +78,18 @@ get_node(int index) const {
return _next->get_node(index - 1); 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 // Function: WorkingNodePath::r_get_node_path
// Access: Private // Access: Private
@ -70,6 +100,7 @@ get_node(int index) const {
PT(NodePathComponent) WorkingNodePath:: PT(NodePathComponent) WorkingNodePath::
r_get_node_path() const { r_get_node_path() const {
if (_next == (WorkingNodePath *)NULL) { if (_next == (WorkingNodePath *)NULL) {
nassertr(_start != (NodePathComponent *)NULL, NULL);
return _start; return _start;
} }
@ -78,5 +109,8 @@ r_get_node_path() const {
PT(NodePathComponent) comp = _next->r_get_node_path(); PT(NodePathComponent) comp = _next->r_get_node_path();
nassertr(comp != (NodePathComponent *)NULL, NULL); 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;
} }

View File

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