traverse: use deque and popleft (#48353)
Avoids a quadratic time operation. In practice it is not really felt, cause it has a tiny constant. But maybe in very large DAGs it is.
This commit is contained in:
parent
9fa1654102
commit
53d1665a8b
@ -2,7 +2,7 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict, deque
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Any,
|
||||||
Callable,
|
Callable,
|
||||||
@ -225,13 +225,13 @@ def get_visitor_from_args(
|
|||||||
|
|
||||||
|
|
||||||
def with_artificial_edges(specs):
|
def with_artificial_edges(specs):
|
||||||
"""Initialize a list of edges from an imaginary root node to the root specs."""
|
"""Initialize a deque of edges from an artificial root node to the root specs."""
|
||||||
return [
|
return deque(
|
||||||
EdgeAndDepth(
|
EdgeAndDepth(
|
||||||
edge=spack.spec.DependencySpec(parent=None, spec=s, depflag=0, virtuals=()), depth=0
|
edge=spack.spec.DependencySpec(parent=None, spec=s, depflag=0, virtuals=()), depth=0
|
||||||
)
|
)
|
||||||
for s in specs
|
for s in specs
|
||||||
]
|
)
|
||||||
|
|
||||||
|
|
||||||
def traverse_depth_first_edges_generator(edges, visitor, post_order=False, root=True, depth=False):
|
def traverse_depth_first_edges_generator(edges, visitor, post_order=False, root=True, depth=False):
|
||||||
@ -272,9 +272,9 @@ def traverse_depth_first_edges_generator(edges, visitor, post_order=False, root=
|
|||||||
yield (edge.depth, edge.edge) if depth else edge.edge
|
yield (edge.depth, edge.edge) if depth else edge.edge
|
||||||
|
|
||||||
|
|
||||||
def traverse_breadth_first_edges_generator(queue, visitor, root=True, depth=False):
|
def traverse_breadth_first_edges_generator(queue: deque, visitor, root=True, depth=False):
|
||||||
while len(queue) > 0:
|
while len(queue) > 0:
|
||||||
edge = queue.pop(0)
|
edge = queue.popleft()
|
||||||
|
|
||||||
# If the visitor doesn't accept the node, we don't yield it nor follow its edges.
|
# If the visitor doesn't accept the node, we don't yield it nor follow its edges.
|
||||||
if not visitor.accept(edge):
|
if not visitor.accept(edge):
|
||||||
@ -297,7 +297,7 @@ def traverse_breadth_first_with_visitor(specs, visitor):
|
|||||||
"""
|
"""
|
||||||
queue = with_artificial_edges(specs)
|
queue = with_artificial_edges(specs)
|
||||||
while len(queue) > 0:
|
while len(queue) > 0:
|
||||||
edge = queue.pop(0)
|
edge = queue.popleft()
|
||||||
|
|
||||||
# If the visitor doesn't accept the node, we don't traverse it further.
|
# If the visitor doesn't accept the node, we don't traverse it further.
|
||||||
if not visitor.accept(edge):
|
if not visitor.accept(edge):
|
||||||
@ -418,10 +418,10 @@ def traverse_topo_edges_generator(edges, visitor, key=id, root=True, all_edges=F
|
|||||||
parent_id = key(edge.parent) if edge.parent is not None else None
|
parent_id = key(edge.parent) if edge.parent is not None else None
|
||||||
node_to_edges[parent_id].append(edge)
|
node_to_edges[parent_id].append(edge)
|
||||||
|
|
||||||
queue = [None]
|
queue = deque((None,))
|
||||||
|
|
||||||
while queue:
|
while queue:
|
||||||
for edge in node_to_edges[queue.pop(0)]:
|
for edge in node_to_edges[queue.popleft()]:
|
||||||
child_id = key(edge.spec)
|
child_id = key(edge.spec)
|
||||||
in_edge_count[child_id] -= 1
|
in_edge_count[child_id] -= 1
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user