@@ -35,55 +35,69 @@ private readonly struct Edge {
35
35
// ┌─╚═╗
36
36
// [x] [y]
37
37
//
38
- // will be stored as list of pairs: (2, a ), (0, i), (1, y)
38
+ // will be stored as list of pairs: (2, c ), (0, i), (1, y)
39
39
//
40
40
// To provide immutability, it must be changed only by calling List<T>.Add
41
- private readonly ImmutableArray < ( int index , Node node ) > _vertices ;
42
- private readonly int _index ;
41
+ private readonly ImmutableArray < ( int nodeIndexInParent , Node node ) > _pathFromRoot ;
43
42
44
- public Node Start => IsFirst ? default : _vertices [ _index - 1 ] . node ;
45
- public int EndIndex => _vertices [ _index ] . index ;
46
- public Node End => _vertices [ _index ] . node ;
47
- public Edge Previous => IsFirst ? default : new Edge ( _vertices , _index - 1 ) ;
48
- public Edge Next => IsLast ? default : new Edge ( _vertices , _index + 1 ) ;
49
- public int PathLength => _vertices . Count ;
50
- public bool IsFirst => _index == 0 ;
51
- public bool IsNonRooted => _vertices . Count > 0 && _vertices [ 0 ] . node . Name == "*" ;
52
- public bool IsEmpty => _vertices . Count == 0 ;
53
- private bool IsLast => _index == _vertices . Count - 1 ;
43
+ // indicates which entry in the _pathFromRoot correspond to this edge.
44
+ private readonly int _indexInPath ;
45
+
46
+ public Node ParentNode => IsFirst ? default : _pathFromRoot [ _indexInPath - 1 ] . node ;
47
+ public int NodeIndexInParent => _pathFromRoot [ _indexInPath ] . nodeIndexInParent ;
48
+ public Node Node => _pathFromRoot [ _indexInPath ] . node ;
49
+ public Edge Previous => IsFirst ? default : new Edge ( _pathFromRoot , _indexInPath - 1 ) ;
50
+ public Edge Next => IsLast ? default : new Edge ( _pathFromRoot , _indexInPath + 1 ) ;
51
+ public int PathLength => _pathFromRoot . Count ;
52
+ public bool IsFirst => _indexInPath == 0 ;
53
+ public bool IsNonRooted => _pathFromRoot . Count > 0 && _pathFromRoot [ 0 ] . node . Name == "*" ;
54
+ public bool IsEmpty => _pathFromRoot . Count == 0 ;
55
+ private bool IsLast => _indexInPath == _pathFromRoot . Count - 1 ;
54
56
55
57
public Edge ( int startIndex , Node start ) {
56
- _vertices = ImmutableArray < ( int , Node ) > . Empty . Add ( ( startIndex , start ) ) ;
57
- _index = 0 ;
58
+ _pathFromRoot = ImmutableArray < ( int , Node ) > . Empty . Add ( ( startIndex , start ) ) ;
59
+ _indexInPath = 0 ;
58
60
}
59
61
60
- public Edge FirstEdge => new Edge ( _vertices , 0 ) ;
61
- public Edge GetPrevious ( int count ) => count > _index ? default : new Edge ( _vertices , _index - count ) ;
62
- public Edge GetNext ( int count ) => _index + count > _vertices . Count - 1 ? default : new Edge ( _vertices , _index + count ) ;
62
+ public Edge FirstEdge => new Edge ( _pathFromRoot , indexInVertices : 0 ) ;
63
+ public Edge GetPrevious ( int count ) => count > _indexInPath ? default : new Edge ( _pathFromRoot , _indexInPath - count ) ;
64
+ public Edge GetNext ( int count ) => _indexInPath + count > _pathFromRoot . Count - 1 ? default : new Edge ( _pathFromRoot , _indexInPath + count ) ;
65
+
66
+ private Edge ( ImmutableArray < ( int index , Node node ) > vertices , int indexInVertices ) {
67
+ // Node has only down pointers for the immutable tree so that when tree needs to be updated
68
+ // it can update only spine of the tree and reuse all other tree nodes. basically making
69
+ // the tree incrementally updatable.
70
+ // but not having Parent pointer makes using the tree data structure hard. so
71
+ // Edge tracks the spine (provide Back/Parent pointer) but only created on demand for
72
+ // a specific node requested.
73
+ //
74
+ // concept is similar to green-red tree.
75
+ // see https://blog.yaakov.online/red-green-trees/
76
+ // https://blogs.msdn.microsoft.com/ericlippert/2012/06/08/persistence-facades-and-roslyns-red-green-trees/
77
+ // https://github.com/KirillOsenkov/Bliki/wiki/Roslyn-Immutable-Trees
63
78
64
- private Edge ( ImmutableArray < ( int index , Node node ) > vertices , int index ) {
65
- _vertices = vertices ;
66
- _index = index ;
79
+ _pathFromRoot = vertices ;
80
+ _indexInPath = indexInVertices ;
67
81
}
68
82
69
83
/// <summary>
70
84
/// Appends new arc to the end vertex of current arc
71
85
/// </summary>
72
- /// <param name="nextVertexIndex "></param>
86
+ /// <param name="childVertexIndexToAppened "></param>
73
87
/// <returns>New last arc</returns>
74
- public Edge Append ( int nextVertexIndex ) {
75
- var nextVertex = End . Children [ nextVertexIndex ] ;
76
- var trimLength = _vertices . Count - _index - 1 ;
77
- var vertices = _vertices . ReplaceAt ( _index + 1 , trimLength , ( nextVertexIndex , nextVertex ) ) ;
78
- return new Edge ( vertices , _index + 1 ) ;
88
+ public Edge Append ( int childVertexIndexToAppened ) {
89
+ var nextVertex = Node . Children [ childVertexIndexToAppened ] ;
90
+ var trimLength = _pathFromRoot . Count - _indexInPath - 1 ;
91
+ var vertices = _pathFromRoot . ReplaceAt ( _indexInPath + 1 , trimLength , ( childVertexIndexToAppened , nextVertex ) ) ;
92
+ return new Edge ( vertices , _indexInPath + 1 ) ;
79
93
}
80
94
81
95
public override bool Equals ( object obj ) => obj is Edge other && Equals ( other ) ;
82
- public bool Equals ( Edge other ) => Equals ( _vertices , other . _vertices ) && _index == other . _index ;
96
+ public bool Equals ( Edge other ) => Equals ( _pathFromRoot , other . _pathFromRoot ) && _indexInPath == other . _indexInPath ;
83
97
84
98
public override int GetHashCode ( ) {
85
99
unchecked {
86
- return ( _vertices . GetHashCode ( ) * 397 ) ^ _index ;
100
+ return ( _pathFromRoot . GetHashCode ( ) * 397 ) ^ _indexInPath ;
87
101
}
88
102
}
89
103
@@ -92,9 +106,9 @@ public override int GetHashCode() {
92
106
93
107
private string DebuggerDisplay {
94
108
get {
95
- var start = _index > 0 ? _vertices [ _index - 1 ] . node . Name : "null" ;
96
- var endIndex = _vertices [ _index ] . index . ToString ( ) ;
97
- var end = _vertices [ _index ] . node . Name ;
109
+ var start = _indexInPath > 0 ? _pathFromRoot [ _indexInPath - 1 ] . node . Name : "null" ;
110
+ var endIndex = _pathFromRoot [ _indexInPath ] . nodeIndexInParent . ToString ( ) ;
111
+ var end = _pathFromRoot [ _indexInPath ] . node . Name ;
98
112
return $ "[{ start } ]-{ endIndex } -[{ end } ]";
99
113
}
100
114
}
0 commit comments