search.c (grow_bfs_bases): New subroutine of bfs_walk.

* cp/search.c (grow_bfs_bases): New subroutine of bfs_walk.
	(bfs_walk): Rewritten using circular queue of BINFO_BASETYPES
	vectors, for speed.

From-SVN: r63088
This commit is contained in:
Zack Weinberg 2003-02-19 04:27:47 +00:00 committed by Zack Weinberg
parent 78bd5210e7
commit 860c9ea661
2 changed files with 108 additions and 36 deletions

View File

@ -1,3 +1,9 @@
2003-02-18 Zack Weinberg <zack@codesourcery.com>
* cp/search.c (grow_bfs_bases): New subroutine of bfs_walk.
(bfs_walk): Rewritten using circular queue of BINFO_BASETYPES
vectors, for speed.
2003-02-18 Mark Mitchell <mark@codesourcery.com>
PR c++/9704

View File

@ -102,6 +102,7 @@ static int look_for_overrides_r (tree, tree);
static struct search_level *push_search_level (struct stack_level *,
struct obstack *);
static struct search_level *pop_search_level (struct stack_level *);
static void grow_bfs_bases (tree **, size_t *, size_t *);
static tree bfs_walk (tree, tree (*) (tree, void *),
tree (*) (tree, void *), void *);
static tree lookup_field_queue_p (tree, void *);
@ -1620,6 +1621,43 @@ adjust_result_of_qualified_name_lookup (tree decl,
}
/* Start with enough room for ten concurrent base classes. That
will be enough for most hierarchies. */
#define BFS_WALK_INITIAL_QUEUE_SIZE 10
/* Subroutine of bfs_walk; enlarges the buffer it uses for its
circular queue. */
static void
grow_bfs_bases (tree **basep, size_t *sizep, size_t *headp)
{
tree *base;
size_t size = *sizep;
size_t head = *headp;
/* If the size is BFS_WALK_INITIAL_QUEUE_SIZE, the old array is on
the stack. */
if (size == BFS_WALK_INITIAL_QUEUE_SIZE)
{
base = xmalloc (size * 2 * sizeof(tree));
memcpy (base, *basep, size * sizeof(tree));
}
else
base = xrealloc (*basep, size * 2 * sizeof(tree));
*basep = base;
*sizep = size * 2;
/* Shift all the elements between head and the former end of the
array, opening up a gap between tail and head. If head==0 we
don't need to do anything to achieve this. */
if (head != 0)
{
memmove (&base[head + size], &base[head],
(size - head) * sizeof (tree));
*headp = head + size;
}
}
/* Walk the class hierarchy dominated by TYPE. FN is called for each
type in the hierarchy, in a breadth-first preorder traversal.
If it ever returns a non-NULL value, that value is immediately
@ -1629,61 +1667,89 @@ adjust_result_of_qualified_name_lookup (tree decl,
value returned is nonzero, the base-class is walked; otherwise it
is not. If QFN is NULL, it is treated as a function which always
returns 1. Both FN and QFN are passed the DATA whenever they are
called. */
called.
Implementation notes: Uses a circular queue, which starts off on
the stack but gets moved to the malloc arena if it needs to be
enlarged. The underflow and overflow conditions are
indistinguishable except by context: if head == tail and we just
moved the head pointer, the queue is empty, but if we just moved
the tail pointer, the queue is full. Base class vectors are only
put on the queue if they are nonempty, which is why it's safe to
use do-while for the inner loop. */
static tree
bfs_walk (tree binfo, tree (*fn) (tree, void *),
tree (*qfn) (tree, void *), void *data)
{
size_t head;
size_t tail;
tree rval = NULL_TREE;
/* An array of the base classes of BINFO. These will be built up in
breadth-first order, except where QFN prunes the search. */
varray_type bfs_bases;
/* Start with enough room for ten base classes. That will be enough
for most hierarchies. */
VARRAY_TREE_INIT (bfs_bases, 10, "search_stack");
tree bfs_bases_initial[BFS_WALK_INITIAL_QUEUE_SIZE];
/* A circular queue of the base classes of BINFO. These will be
built up in breadth-first order, except where QFN prunes the
search. */
size_t head, tail;
size_t bfs_bases_size = BFS_WALK_INITIAL_QUEUE_SIZE;
tree *bfs_bases = bfs_bases_initial;
/* Put the first type into the stack. */
VARRAY_TREE (bfs_bases, 0) = binfo;
tail = 1;
/* Is the first one what we're looking for? If so, we're done. */
rval = fn (binfo, data);
if (rval)
return rval;
for (head = 0; head < tail; ++head)
/* If it has no base types, we are also done. */
if (BINFO_BASETYPES (binfo) == 0
|| TREE_VEC_LENGTH (BINFO_BASETYPES (binfo)) == 0)
return 0;
/* Otherwise, initialize the queue with its basetypes vector
and proceed. */
head = tail = 0;
bfs_bases[tail++] = BINFO_BASETYPES (binfo);
do
{
int i;
int n_baselinks;
int i, n_baselinks;
tree binfos;
binfos = bfs_bases[head++];
if (head == bfs_bases_size)
head = 0;
/* Pull the next type out of the queue. */
binfo = VARRAY_TREE (bfs_bases, head);
/* If this is the one we're looking for, we're done. */
rval = (*fn) (binfo, data);
if (rval)
break;
/* Queue up the base types. */
binfos = BINFO_BASETYPES (binfo);
n_baselinks = binfos ? TREE_VEC_LENGTH (binfos): 0;
for (i = 0; i < n_baselinks; i++)
i = 0;
n_baselinks = TREE_VEC_LENGTH (binfos);
do
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
binfo = TREE_VEC_ELT (binfos, i);
i++;
if (qfn)
base_binfo = (*qfn) (base_binfo, data);
binfo = qfn (binfo, data);
if (!binfo)
continue;
if (base_binfo)
{
if (tail == VARRAY_SIZE (bfs_bases))
VARRAY_GROW (bfs_bases, 2 * VARRAY_SIZE (bfs_bases));
VARRAY_TREE (bfs_bases, tail) = base_binfo;
++tail;
}
rval = fn (binfo, data);
if (rval)
goto done;
if (BINFO_BASETYPES (binfo) == 0
|| TREE_VEC_LENGTH (BINFO_BASETYPES (binfo)) == 0)
continue;
bfs_bases[tail++] = BINFO_BASETYPES (binfo);
if (tail == bfs_bases_size)
tail = 0;
if (tail == head)
grow_bfs_bases (&bfs_bases, &bfs_bases_size, &head);
}
while (i < n_baselinks);
}
while (head != tail);
done:
if (bfs_bases != bfs_bases_initial)
free (bfs_bases);
return rval;
}