| Index: tools/testing/dart/dependency_graph.dart
|
| diff --git a/tools/testing/dart/dependency_graph.dart b/tools/testing/dart/dependency_graph.dart
|
| index 688987868366c0d5aafd4409db9f98cf64d7908b..a3e04fc2c82dc383f1aab0010dc16a8c23666a5b 100644
|
| --- a/tools/testing/dart/dependency_graph.dart
|
| +++ b/tools/testing/dart/dependency_graph.dart
|
| @@ -2,66 +2,75 @@
|
| // for details. All rights reserved. Use of this source code is governed by a
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| -library dependency_graph;
|
| -
|
| import 'dart:async';
|
| +
|
| import 'utils.dart';
|
|
|
| -/*
|
| - * [Graph] represents a datastructure for representing an DAG (directed acyclic
|
| - * graph). Each node in the graph is in a given [NodeState] and can have data
|
| - * attached to it with [Node.userData].
|
| - *
|
| - * It's interface consists basically of these methods:
|
| - * - newNode: Adds a new node to the graph with the given dependencies and
|
| - * the given user data. The node is in the [NodeState.Initialized]
|
| - * state.
|
| - * - changeState: Changes the state of a node.
|
| - * - sealGraph: Makes the graph immutable.
|
| - * - stateCount: Counts the number of nodes who are in a given [NodeState].
|
| - *
|
| - * Users of a [Graph] can listen for events by subscribing to the [events]
|
| - * stream. Three types of events will be fired (after the graph was modified):
|
| - * - NodeAddedEvent: Fired after a node was added ot the graph.
|
| - * - StateChangedEvent: Fired after the state of a node changed.
|
| - * - GraphSealedEvent: Fired after the graph was marked as immutable/sealed.
|
| - */
|
| -class Graph {
|
| - final _nodes = new Set<Node>();
|
| - final StreamController<GraphEvent> _eventController;
|
| +/// A directed acyclic graph where each node is in a [NodeState] and can have
|
| +/// data attached to it with [Node.data].
|
| +///
|
| +/// The graph exposes a few broadcast streams that can be subscribed to in
|
| +/// order to be notified of modifications to the graph.
|
| +class Graph<T> {
|
| + final _nodes = new Set<Node<T>>();
|
| final _stateCounts = <NodeState, int>{};
|
| - final Stream<GraphEvent> _eventStream;
|
| bool _isSealed = false;
|
|
|
| + /// Notifies when nodes are added to the graph.
|
| + final Stream<Node<T>> added;
|
| + final StreamController<Node<T>> _addedController;
|
| +
|
| + /// Notifies when a node's state has changed.
|
| + final Stream<StateChangedEvent<T>> changed;
|
| + final StreamController<StateChangedEvent<T>> _changedController;
|
| +
|
| + /// Notifies when the graph is sealed.
|
| + final Stream<Null> sealed;
|
| + final StreamController<Null> _sealedController;
|
| +
|
| factory Graph() {
|
| - var controller = new StreamController<GraphEvent>();
|
| - return new Graph._(controller, controller.stream.asBroadcastStream());
|
| + var added = new StreamController<Node<T>>();
|
| + var changed = new StreamController<StateChangedEvent<T>>();
|
| + var sealed = new StreamController<Null>();
|
| +
|
| + return new Graph._(
|
| + added,
|
| + added.stream.asBroadcastStream(),
|
| + changed,
|
| + changed.stream.asBroadcastStream(),
|
| + sealed,
|
| + sealed.stream.asBroadcastStream());
|
| }
|
|
|
| - Graph._(this._eventController, this._eventStream);
|
| + Graph._(this._addedController, this.added, this._changedController,
|
| + this.changed, this._sealedController, this.sealed);
|
|
|
| - Iterable<Node> get nodes => _nodes;
|
| - Stream<GraphEvent> get events => _eventStream;
|
| + Iterable<Node<T>> get nodes => _nodes;
|
| bool get isSealed => _isSealed;
|
|
|
| + /// Counts the number of nodes who are in [state].
|
| int stateCount(NodeState state) {
|
| int count = _stateCounts[state];
|
| return count == null ? 0 : count;
|
| }
|
|
|
| - void DumpCounts() {
|
| + void dumpCounts() {
|
| for (var state in _stateCounts.keys) {
|
| print("Count[$state] = ${_stateCounts[state]}");
|
| }
|
| }
|
|
|
| - void sealGraph() {
|
| + /// Makes the graph immutable.
|
| + void seal() {
|
| assert(!_isSealed);
|
| _isSealed = true;
|
| - _emitEvent(new GraphSealedEvent());
|
| + _emitEvent(_sealedController, null);
|
| }
|
|
|
| - Node newNode(Object userData, Iterable<Node> dependencies) {
|
| + /// Adds a new node to the graph with [dependencies] and [userData].
|
| + ///
|
| + /// The node is in the [NodeState.initialized] state.
|
| + Node<T> add(T userData, Iterable<Node<T>> dependencies) {
|
| assert(!_isSealed);
|
|
|
| var node = new Node._(userData);
|
| @@ -72,7 +81,7 @@ class Graph {
|
| node._dependencies.add(dependency);
|
| }
|
|
|
| - _emitEvent(new NodeAddedEvent(node));
|
| + _emitEvent(_addedController, node);
|
|
|
| _stateCounts.putIfAbsent(node.state, () => 0);
|
| _stateCounts[node.state] += 1;
|
| @@ -80,68 +89,60 @@ class Graph {
|
| return node;
|
| }
|
|
|
| - void changeState(Node node, NodeState newState) {
|
| + /// Changes the state of [node] to [state].
|
| + void changeState(Node<T> node, NodeState state) {
|
| var fromState = node.state;
|
| - node._state = newState;
|
| + node._state = state;
|
|
|
| _stateCounts[fromState] -= 1;
|
| - _stateCounts.putIfAbsent(newState, () => 0);
|
| - _stateCounts[newState] += 1;
|
| + _stateCounts.putIfAbsent(state, () => 0);
|
| + _stateCounts[state] += 1;
|
|
|
| - _emitEvent(new StateChangedEvent(node, fromState, newState));
|
| + _emitEvent(
|
| + _changedController, new StateChangedEvent(node, fromState, state));
|
| }
|
|
|
| - void _emitEvent(GraphEvent event) {
|
| - // We emit events asynchronously so the graph can be build up in small
|
| - // batches and the events are delivered in small batches.
|
| + /// We emit events asynchronously so the graph can be build up in small
|
| + /// batches and the events are delivered in small batches.
|
| + void _emitEvent<E>(StreamController<E> controller, E event) {
|
| Timer.run(() {
|
| - _eventController.add(event);
|
| + controller.add(event);
|
| });
|
| }
|
| }
|
|
|
| -class Node extends UniqueObject {
|
| - final Object _userData;
|
| - NodeState _state = NodeState.Initialized;
|
| - Set<Node> _dependencies = new Set<Node>();
|
| - Set<Node> _neededFor = new Set<Node>();
|
| +/// A single node in a [Graph].
|
| +class Node<T> extends UniqueObject {
|
| + final T data;
|
| + NodeState _state = NodeState.initialized;
|
| + final Set<Node<T>> _dependencies = new Set();
|
| + final Set<Node<T>> _neededFor = new Set();
|
|
|
| - Node._(this._userData);
|
| + Node._(this.data);
|
|
|
| - Object get userData => _userData;
|
| NodeState get state => _state;
|
| - Iterable<Node> get dependencies => _dependencies;
|
| - Iterable<Node> get neededFor => _neededFor;
|
| + Iterable<Node<T>> get dependencies => _dependencies;
|
| + Iterable<Node<T>> get neededFor => _neededFor;
|
| }
|
|
|
| -class NodeState extends UniqueObject {
|
| - static NodeState Initialized = new NodeState._("Initialized");
|
| - static NodeState Waiting = new NodeState._("Waiting");
|
| - static NodeState Enqueuing = new NodeState._("Enqueuing");
|
| - static NodeState Processing = new NodeState._("Running");
|
| - static NodeState Successful = new NodeState._("Successful");
|
| - static NodeState Failed = new NodeState._("Failed");
|
| - static NodeState UnableToRun = new NodeState._("UnableToRun");
|
| +class NodeState {
|
| + static const initialized = const NodeState._("Initialized");
|
| + static const waiting = const NodeState._("Waiting");
|
| + static const enqueuing = const NodeState._("Enqueuing");
|
| + static const processing = const NodeState._("Running");
|
| + static const successful = const NodeState._("Successful");
|
| + static const failed = const NodeState._("Failed");
|
| + static const unableToRun = const NodeState._("UnableToRun");
|
|
|
| final String name;
|
|
|
| - NodeState._(this.name);
|
| + const NodeState._(this.name);
|
|
|
| String toString() => name;
|
| }
|
|
|
| -abstract class GraphEvent {}
|
| -
|
| -class GraphSealedEvent extends GraphEvent {}
|
| -
|
| -class NodeAddedEvent extends GraphEvent {
|
| - final Node node;
|
| -
|
| - NodeAddedEvent(this.node);
|
| -}
|
| -
|
| -class StateChangedEvent extends GraphEvent {
|
| - final Node node;
|
| +class StateChangedEvent<T> {
|
| + final Node<T> node;
|
| final NodeState from;
|
| final NodeState to;
|
|
|
|
|