@@ -10,6 +10,8 @@ export class CycleError<T> extends Error {
10
10
}
11
11
}
12
12
export default class DirectedAcyclicGraph < T > extends DirectedGraph < T > {
13
+ private _topologicallySortedNodes ?: Array < T > ;
14
+
13
15
static fromDirectedGraph < T > ( graph : DirectedGraph < T > ) : DirectedAcyclicGraph < T > {
14
16
if ( ! graph . isAcyclic ( ) ) {
15
17
throw new CycleError ( "Can't convert that graph to a DAG because it contains a cycle" )
@@ -27,11 +29,26 @@ export default class DirectedAcyclicGraph<T> extends DirectedGraph<T> {
27
29
if ( this . wouldAddingEdgeCreateCyle ( node1Identity , node2Identity ) ) {
28
30
throw new CycleError ( `Can't add edge from ${ node1Identity } to ${ node2Identity } it would create a cycle` )
29
31
}
32
+
33
+ // Invalidate cache of toposorted nodes
34
+ this . _topologicallySortedNodes = undefined ;
30
35
super . addEdge ( node1Identity , node2Identity , true )
31
36
}
32
37
38
+ // Maintain topo sort when inserting node
39
+ insert ( node : T ) : string {
40
+ if ( this . _topologicallySortedNodes )
41
+ this . _topologicallySortedNodes = [ node , ...this . _topologicallySortedNodes ] ;
42
+
43
+ return super . insert ( node )
44
+ }
45
+
33
46
// This is an implementation of Kahn's algorithim
34
47
topologicallySortedNodes ( ) : Array < T > {
48
+ if ( this . _topologicallySortedNodes != undefined ) {
49
+ return this . _topologicallySortedNodes ;
50
+ }
51
+
35
52
const nodeIndices = Array . from ( this . nodes . keys ( ) ) ;
36
53
const nodeInDegrees = new Map ( Array . from ( this . nodes . keys ( ) ) . map ( n => [ n , this . inDegreeOfNode ( n ) ] ) )
37
54
@@ -40,7 +57,9 @@ export default class DirectedAcyclicGraph<T> extends DirectedGraph<T> {
40
57
let toSearch = Array . from ( nodeInDegrees ) . filter ( pair => pair [ 1 ] === 0 )
41
58
42
59
if ( toSearch . length === this . nodes . size ) {
43
- return Array . from ( this . nodes . values ( ) )
60
+ const arrayOfNodes = Array . from ( this . nodes . values ( ) ) ;
61
+ this . _topologicallySortedNodes = arrayOfNodes
62
+ return arrayOfNodes
44
63
}
45
64
46
65
let toReturn : Array < T > = [ ]
@@ -63,6 +82,9 @@ export default class DirectedAcyclicGraph<T> extends DirectedGraph<T> {
63
82
} )
64
83
}
65
84
85
+ // Update cache
86
+ this . _topologicallySortedNodes = toReturn ;
87
+
66
88
// we shouldn't need to account for the error case of there being a cycle because it shouldn't
67
89
// be possible to instantiate this class in a state (or put it in a state) where there is a cycle.
68
90
0 commit comments