diff options
author | Sebastian Thiel <byronimo@gmail.com> | 2010-06-06 12:48:25 +0200 |
---|---|---|
committer | Sebastian Thiel <byronimo@gmail.com> | 2010-06-06 12:48:25 +0200 |
commit | ec28ad575ce1d7bb6a616ffc404f32bbb1af67b2 (patch) | |
tree | 90003f8f93becbb0b8aacd4c2ff7119842fa8003 /lib/git/async/graph.py | |
parent | b72e2704022d889f116e49abf3e1e5d3e3192d3b (diff) | |
download | gitpython-ec28ad575ce1d7bb6a616ffc404f32bbb1af67b2.tar.gz |
thread: adjusted worker thread not to provide an output queue anymore - this is handled by the task system
graph: implemented it including test according to the pools requirements
pool: implemented set_pool_size
Diffstat (limited to 'lib/git/async/graph.py')
-rw-r--r-- | lib/git/async/graph.py | 84 |
1 files changed, 74 insertions, 10 deletions
diff --git a/lib/git/async/graph.py b/lib/git/async/graph.py index 0c0a2137..b4d6aa00 100644 --- a/lib/git/async/graph.py +++ b/lib/git/async/graph.py @@ -6,31 +6,95 @@ class Node(object): we need""" __slots__ = ('in_nodes', 'out_nodes') + def __init__(self): + self.in_nodes = list() + self.out_nodes = list() + class Graph(object): """A simple graph implementation, keeping nodes and providing basic access and - editing functions""" + editing functions. The performance is only suitable for small graphs of not + more than 10 nodes !""" __slots__ = "nodes" def __init__(self): self.nodes = list() def add_node(self, node): - """Add a new node to the graph""" - raise NotImplementedError() + """Add a new node to the graph + :return: the newly added node""" + self.nodes.append(node) + return node def del_node(self, node): - """Delete a node from the graph""" - raise NotImplementedError() + """Delete a node from the graph + :return: self""" + # clear connections + for outn in node.out_nodes: + del(outn.in_nodes[outn.in_nodes.index(node)]) + for inn in node.in_nodes: + del(inn.out_nodes[inn.out_nodes.index(node)]) + del(self.nodes[self.nodes.index(node)]) + return self def add_edge(self, u, v): """Add an undirected edge between the given nodes u and v. + + return: self :raise ValueError: If the new edge would create a cycle""" - raise NotImplementedError() + if u is v: + raise ValueError("Cannot connect a node with itself") + + # are they already connected ? + if u in v.in_nodes and v in u.out_nodes or \ + v in u.in_nodes and u in v.out_nodes: + return self + # END handle connection exists + + # cycle check - if we can reach any of the two by following either ones + # history, its a cycle + for start, end in ((u, v), (v,u)): + if not start.in_nodes: + continue + nodes = start.in_nodes[:] + seen = set() + # depth first search - its faster + while nodes: + n = nodes.pop() + if n in seen: + continue + seen.add(n) + if n is end: + raise ValueError("Connecting u with v would create a cycle") + nodes.extend(n.in_nodes) + # END while we are searching + # END for each direction to look + + # connection is valid, set it up + u.out_nodes.append(v) + v.in_nodes.append(u) + + return self - def visit_input_depth_first(self, node, visitor=lambda n: True ): + def visit_input_inclusive_depth_first(self, node, visitor=lambda n: True ): """Visit all input nodes of the given node, depth first, calling visitor for each node on our way. If the function returns False, the traversal - will not go any deeper, but continue at the next branch""" - raise NotImplementedError() - + will not go any deeper, but continue at the next branch + It will return the actual input node in the end !""" + nodes = node.in_nodes[:] + seen = set() + + # depth first + while nodes: + n = nodes.pop() + if n in seen: + continue + seen.add(n) + + # only proceed in that direction if visitor is fine with it + if visitor(n): + nodes.extend(n.in_nodes) + # END call visitor + # END while walking + visitor(node) + |