Skip to content

Commit 5c3480f

Browse files
author
electricessence
committed
Added more finite interfaces for adaptablility.
Moved GetDescendants and GetNodes to ParentExtensions.
1 parent c1b72cf commit 5c3480f

6 files changed

Lines changed: 162 additions & 51 deletions

File tree

IChild.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System.Collections.Generic;
2+
3+
namespace Open.Hierarchy
4+
{
5+
public interface IChild
6+
{
7+
object Parent { get; }
8+
}
9+
10+
public interface IChild<out TParent> : IChild
11+
{
12+
new TParent Parent { get; }
13+
}
14+
15+
public static class ChildExtensions
16+
{
17+
public static IEnumerable<TNode> GetAncestors<TNode>(
18+
this TNode node)
19+
where TNode : IChild<TNode>
20+
{
21+
TNode parent;
22+
while ((parent = node.Parent) != null)
23+
{
24+
yield return parent;
25+
node = parent;
26+
}
27+
}
28+
29+
public static TNode GetRoot<TNode>(
30+
this TNode node)
31+
where TNode : IChild<TNode>
32+
{
33+
TNode parent;
34+
while ((parent = node.Parent) != null)
35+
{
36+
node = parent;
37+
}
38+
return node;
39+
}
40+
}
41+
42+
}

IHaveRoot.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
namespace Open.Hierarchy
22
{
3-
public interface IHaveRoot<TRoot>
3+
public interface IHaveRoot
4+
{
5+
object Root { get; }
6+
}
7+
8+
public interface IHaveRoot<out TRoot> : IHaveRoot
49
{
5-
TRoot Root { get; }
10+
new TRoot Root { get; }
611
}
712
}

INode.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System.Collections.Generic;
2+
3+
namespace Open.Hierarchy
4+
{
5+
public interface INode<TNode> : ICollection<TNode>, IChild<TNode>, IParent<TNode>, IHaveRoot<TNode>
6+
where TNode : INode<TNode>
7+
{
8+
}
9+
10+
}

IParent.cs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using System.Linq;
23

34
namespace Open.Hierarchy
45
{
@@ -12,4 +13,63 @@ public interface IParent<out TChild> : IParent
1213
new IReadOnlyList<TChild> Children { get; }
1314
}
1415

16+
public static class ParentExtensions
17+
{
18+
19+
/// <summary>
20+
/// Returns all descendant nodes.
21+
/// </summary>
22+
/// <param name="traversal">The mode by which the tree is traversed.</param>
23+
/// <returns>The enumeration of all the descendant nodes.</returns>
24+
public static IEnumerable<TNode> GetDescendants<TNode>(
25+
this TNode node, TraversalMode traversal = TraversalMode.BreadthFirst)
26+
where TNode : IParent<TNode>
27+
{
28+
// Attempt to be more breadth first.
29+
switch (traversal)
30+
{
31+
case TraversalMode.BreadthFirst:
32+
foreach (var child in node.Children)
33+
yield return child;
34+
35+
var grandchildren = node.Children.SelectMany(c => c.Children);
36+
foreach (var grandchild in grandchildren)
37+
yield return grandchild;
38+
39+
foreach (var descendant in grandchildren
40+
.SelectMany(c => c.GetDescendants()))
41+
yield return descendant;
42+
43+
break;
44+
45+
46+
case TraversalMode.DepthFirst:
47+
48+
foreach (var descendant in node.Children
49+
.SelectMany(c => c.GetDescendants(TraversalMode.DepthFirst)))
50+
yield return descendant;
51+
52+
break;
53+
}
54+
55+
}
56+
57+
/// <summary>
58+
/// Returns all descendant nodes and includes this node.
59+
/// Breadth first returns this node first. Depth first returns this node last.
60+
/// </summary>
61+
/// <param name="traversal">The mode by which the tree is traversed.</param>
62+
/// <returns>The enumeration of all the descendant nodes including this one.</returns>
63+
public static IEnumerable<TNode> GetNodes<TNode>(
64+
this TNode node, TraversalMode traversal = TraversalMode.BreadthFirst)
65+
where TNode : IParent<TNode>
66+
{
67+
if (traversal == TraversalMode.BreadthFirst)
68+
yield return node;
69+
foreach (var descendant in node.GetDescendants(traversal))
70+
yield return descendant;
71+
if (traversal == TraversalMode.DepthFirst)
72+
yield return node;
73+
}
74+
}
1575
}

Node.cs

Lines changed: 35 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,19 @@
66

77
namespace Open.Hierarchy
88
{
9-
10-
public sealed class Node<T> : ICollection<Node<T>>, IHaveRoot<Node<T>>, IParent<Node<T>>
9+
public sealed class Node<T> : INode<Node<T>>
1110
{
11+
#region IChild<Node<T>> Implementation
1212
Node<T> _parent;
1313
public Node<T> Parent => _parent;
14+
object IChild.Parent => _parent;
15+
#endregion
1416

17+
#region IParent<Node<T>> Implementation
1518
readonly List<Node<T>> _children;
1619
public IReadOnlyList<Node<T>> Children { get; private set; }
1720
IReadOnlyList<object> IParent.Children => Children;
21+
#endregion
1822

1923
public T Value { get; set; }
2024

@@ -23,6 +27,9 @@ public sealed class Node<T> : ICollection<Node<T>>, IHaveRoot<Node<T>>, IParent<
2327
_children = new List<Node<T>>();
2428
Children = _children.AsReadOnly();
2529
}
30+
31+
// WARNING: Care must be taken not to have duplicate nodes anywhere in the tree but having duplicate values are allowed.
32+
2633
#region ICollection<Node<T>> Implementation
2734
public bool IsReadOnly => false;
2835

@@ -98,66 +105,47 @@ public void Detatch()
98105
}
99106

100107

101-
/// <summary>
102-
/// Iterates through all of the descendants of this node starting breadth first.
103-
/// </summary>
104-
/// <returns>All the descendants of this node.</returns>
105-
public IEnumerable<Node<T>> GetDescendants()
106-
{
107-
// Attempt to be more breadth first.
108-
109-
foreach (var child in _children)
110-
yield return child;
111-
112-
var grandchildren = _children.SelectMany(c => c);
113-
foreach (var grandchild in grandchildren)
114-
yield return grandchild;
115-
116-
foreach (var descendant in grandchildren.SelectMany(c => c.GetDescendants()))
117-
yield return descendant;
118-
}
119-
120-
/// <returns>This and all of its descendants.</returns>
121-
public IEnumerable<Node<T>> GetNodes()
122-
{
123-
yield return this;
124-
foreach (var descendant in GetDescendants())
125-
yield return descendant;
126-
}
127-
128108
/// <summary>
129109
/// Finds the root node of this tree.
130110
/// </summary>
131111
public Node<T> Root
132112
{
133113
get
134114
{
135-
var current = this;
136-
while (current._parent != null)
137-
current = current._parent;
115+
Node<T> current = this;
116+
Node<T> parent;
117+
while ((parent = current._parent) != null)
118+
{
119+
current = parent;
120+
}
138121
return current;
139122
}
140123
}
141124

142-
internal void Teardown(Factory factory = null)
125+
object IHaveRoot.Root => Root;
126+
127+
internal void Teardown()
143128
{
144129
Value = default(T);
145130
Detatch(); // If no parent then this does nothing...
146-
if (factory == null)
131+
foreach (var c in _children)
147132
{
148-
foreach (var c in _children)
149-
{
150-
c._parent = null; // Don't initiate a 'Detach' (which does a lookup) since we are clearing here;
151-
c.Teardown();
152-
}
133+
c._parent = null; // Don't initiate a 'Detach' (which does a lookup) since we are clearing here;
134+
c.Teardown();
153135
}
154-
else
136+
_children.Clear();
137+
}
138+
139+
internal void Recycle(Factory factory)
140+
{
141+
if (factory == null) throw new ArgumentNullException("factory");
142+
143+
Value = default(T);
144+
Detatch(); // If no parent then this does nothing...
145+
foreach (var c in _children)
155146
{
156-
foreach (var c in _children)
157-
{
158-
c._parent = null; // Don't initiate a 'Detach' (which does a lookup) since we are clearing here;
159-
factory.RecycleInternal(c);
160-
}
147+
c._parent = null; // Don't initiate a 'Detach' (which does a lookup) since we are clearing here;
148+
factory.RecycleInternal(c);
161149
}
162150
_children.Clear();
163151
}
@@ -201,12 +189,10 @@ internal void RecycleInternal(Node<T> n)
201189

202190
void PrepareForPool(Node<T> n)
203191
{
204-
n.Teardown(this);
192+
n.Recycle(this);
205193
}
206194
#endregion
207195

208-
// WARNING: Care must be taken not to have duplicate nodes anywhere in the tree but having duplicate values are allowed.
209-
210196
/// <summary>
211197
/// Clones a node by recreating the tree and copying the values.
212198
/// </summary>
@@ -268,7 +254,7 @@ public Node<T> CloneTree(Node<T> target)
268254
/// <param name="root">The root instance.</param>
269255
/// <returns>The full map of the root.</returns>
270256
public Node<T> Map<TRoot>(TRoot root)
271-
where TRoot : T
257+
where TRoot : T
272258
{
273259
AssertIsAlive();
274260

TraversalMode.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Open.Hierarchy
2+
{
3+
public enum TraversalMode
4+
{
5+
DepthFirst,
6+
BreadthFirst
7+
}
8+
}

0 commit comments

Comments
 (0)