Merge "Use the node built-in 'dfs_iter' instead of recursion"

This commit is contained in:
Jenkins 2015-10-15 04:27:42 +00:00 committed by Gerrit Code Review
commit 4677fdb30e
3 changed files with 62 additions and 28 deletions

View File

@ -21,7 +21,11 @@ LOG = logging.getLogger(__name__)
def _depth_first_reverse_iterate(node, idx=-1):
"""Iterates connected (in reverse) nodes in tree (from starting node)."""
"""Iterates connected (in reverse) nodes (from starting node).
Jumps through nodes with ``FLOW`` ``kind`` attribute (does not yield
them back).
"""
# Always go left to right, since right to left is the pattern order
# and we want to go backwards and not forwards through that ordering...
if idx == -1:
@ -29,15 +33,11 @@ def _depth_first_reverse_iterate(node, idx=-1):
else:
children_iter = reversed(node[0:idx])
for child in children_iter:
child_kind = child.metadata['kind']
if child_kind == co.FLOW:
if child.metadata['kind'] == co.FLOW:
# Jump through these...
#
# TODO(harlowja): make this non-recursive and remove this
# style of doing this when
# https://review.openstack.org/#/c/205731/ merges...
for atom in _depth_first_reverse_iterate(child):
yield atom
for child_child in child.dfs_iter(right_to_left=False):
if child_child.metadata['kind'] in co.ATOMS:
yield child_child.item
else:
yield child.item

View File

@ -467,24 +467,38 @@ CEO
self.assertEqual(set(['animal', 'reptile', 'mammal', 'horse',
'primate', 'monkey', 'human']), set(things))
def test_dfs_itr_order(self):
def test_dfs_itr_left_to_right(self):
root = self._make_species()
it = root.dfs_iter(include_self=False, right_to_left=False)
things = list([n.item for n in it])
self.assertEqual(['reptile', 'mammal', 'primate',
'human', 'monkey', 'horse'], things)
def test_dfs_itr_no_self(self):
root = self._make_species()
things = list([n.item for n in root.dfs_iter(include_self=True)])
self.assertEqual(['animal', 'mammal', 'horse', 'primate',
'monkey', 'human', 'reptile'], things)
things = list([n.item for n in root.dfs_iter(include_self=False)])
self.assertEqual(['mammal', 'horse', 'primate',
'monkey', 'human', 'reptile'], things)
def test_bfs_iter(self):
def test_bfs_itr(self):
root = self._make_species()
things = list([n.item for n in root.bfs_iter(include_self=True)])
self.assertEqual(['animal', 'reptile', 'mammal', 'primate',
'horse', 'human', 'monkey'], things)
def test_bfs_itr_no_self(self):
root = self._make_species()
things = list([n.item for n in root.bfs_iter(include_self=False)])
self.assertEqual(['reptile', 'mammal', 'primate',
'horse', 'human', 'monkey'], things)
def test_bfs_itr_right_to_left(self):
root = self._make_species()
it = root.bfs_iter(include_self=False, right_to_left=True)
things = list([n.item for n in it])
self.assertEqual(['mammal', 'reptile', 'horse',
'primate', 'monkey', 'human'], things)
class OrderedSetTest(test.TestCase):

View File

@ -36,8 +36,9 @@ class FrozenNode(Exception):
class _DFSIter(object):
"""Depth first iterator (non-recursive) over the child nodes."""
def __init__(self, root, include_self=False):
def __init__(self, root, include_self=False, right_to_left=True):
self.root = root
self.right_to_left = bool(right_to_left)
self.include_self = bool(include_self)
def __iter__(self):
@ -45,20 +46,28 @@ class _DFSIter(object):
if self.include_self:
stack.append(self.root)
else:
if self.right_to_left:
stack.extend(self.root.reverse_iter())
else:
# Traverse the left nodes first to the right nodes.
stack.extend(iter(self.root))
while stack:
node = stack.pop()
# Visit the node.
node = stack.pop()
yield node
# Traverse the left & right subtree.
if self.right_to_left:
stack.extend(node.reverse_iter())
else:
# Traverse the left nodes first to the right nodes.
stack.extend(iter(node))
class _BFSIter(object):
"""Breadth first iterator (non-recursive) over the child nodes."""
def __init__(self, root, include_self=False):
def __init__(self, root, include_self=False, right_to_left=False):
self.root = root
self.right_to_left = bool(right_to_left)
self.include_self = bool(include_self)
def __iter__(self):
@ -66,12 +75,19 @@ class _BFSIter(object):
if self.include_self:
q.append(self.root)
else:
if self.right_to_left:
q.extend(iter(self.root))
else:
# Traverse the left nodes first to the right nodes.
q.extend(self.root.reverse_iter())
while q:
node = q.popleft()
# Visit the node.
node = q.popleft()
yield node
# Traverse the left & right subtree.
if self.right_to_left:
q.extend(iter(node))
else:
# Traverse the left nodes first to the right nodes.
q.extend(node.reverse_iter())
@ -361,10 +377,14 @@ class Node(object):
raise ValueError("%s is not contained in any child" % (item))
return index_at
def dfs_iter(self, include_self=False):
def dfs_iter(self, include_self=False, right_to_left=True):
"""Depth first iteration (non-recursive) over the child nodes."""
return _DFSIter(self, include_self=include_self)
return _DFSIter(self,
include_self=include_self,
right_to_left=right_to_left)
def bfs_iter(self, include_self=False):
def bfs_iter(self, include_self=False, right_to_left=False):
"""Breadth first iteration (non-recursive) over the child nodes."""
return _BFSIter(self, include_self=include_self)
return _BFSIter(self,
include_self=include_self,
right_to_left=right_to_left)