1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . Linq ;
4+ using System . Collections ;
5+ using Open . Disposable ;
6+
7+ namespace Open . Hierarchy
8+ {
9+
10+ public sealed class Node < T > : ICollection < Node < T > > , IHaveRoot < Node < T > > , IParent < Node < T > >
11+ {
12+ Node < T > _parent ;
13+ public Node < T > Parent => _parent ;
14+
15+ readonly List < Node < T > > _children ;
16+ public IReadOnlyList < Node < T > > Children { get ; private set ; }
17+ IReadOnlyList < object > IParent . Children => Children ;
18+
19+ public T Value { get ; set ; }
20+
21+ Node ( )
22+ {
23+ _children = new List < Node < T > > ( ) ;
24+ Children = _children . AsReadOnly ( ) ;
25+ }
26+ #region ICollection<Node<T>> Implementation
27+ public bool IsReadOnly => false ;
28+
29+ public bool Contains ( Node < T > node )
30+ {
31+ return _children . Contains ( node ) ;
32+ }
33+
34+ public bool Remove ( Node < T > node )
35+ {
36+ if ( _children . Remove ( node ) )
37+ {
38+ node . _parent = null ; // Need to be very careful about retaining parent references as it may cause a 'leak' per-se.
39+ return true ;
40+ }
41+ return false ;
42+ }
43+
44+ public void Add ( Node < T > node )
45+ {
46+ if ( node . _parent != null )
47+ {
48+ if ( node . _parent == this )
49+ throw new InvalidOperationException ( "Adding a child node more than once." ) ;
50+ throw new InvalidOperationException ( "Adding a node that belongs to another parent." ) ;
51+ }
52+ node . _parent = this ;
53+ _children . Add ( node ) ;
54+ }
55+
56+ public void Clear ( )
57+ {
58+ foreach ( var c in _children )
59+ c . _parent = null ;
60+ _children . Clear ( ) ;
61+ }
62+
63+
64+ public int Count => _children . Count ;
65+
66+ public IEnumerator < Node < T > > GetEnumerator ( )
67+ {
68+ return _children . GetEnumerator ( ) ;
69+ }
70+
71+ IEnumerator IEnumerable . GetEnumerator ( )
72+ {
73+ return GetEnumerator ( ) ;
74+ }
75+
76+ public void CopyTo ( Node < T > [ ] array , int arrayIndex )
77+ {
78+ _children . CopyTo ( array , arrayIndex ) ;
79+ }
80+ #endregion
81+
82+ public void Replace ( Node < T > node , Node < T > replacement )
83+ {
84+ if ( replacement . _parent != null )
85+ throw new InvalidOperationException ( "Replacement node belongs to another parent." ) ;
86+ var i = _children . IndexOf ( node ) ;
87+ if ( i == - 1 )
88+ throw new InvalidOperationException ( "Node being replaced does not belong to this parent." ) ;
89+ _children [ i ] = replacement ;
90+ node . _parent = null ;
91+ replacement . _parent = this ;
92+ }
93+
94+ public void Detatch ( )
95+ {
96+ _parent ? . Remove ( this ) ;
97+ _parent = null ;
98+ }
99+
100+
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+
128+ /// <summary>
129+ /// Finds the root node of this tree.
130+ /// </summary>
131+ public Node < T > Root
132+ {
133+ get
134+ {
135+ var current = this ;
136+ while ( current . _parent != null )
137+ current = current . _parent ;
138+ return current ;
139+ }
140+ }
141+
142+ internal void Teardown ( Factory factory = null )
143+ {
144+ Value = default ( T ) ;
145+ Detatch ( ) ; // If no parent then this does nothing...
146+ if ( factory == null )
147+ {
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+ }
153+ }
154+ else
155+ {
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+ }
161+ }
162+ _children . Clear ( ) ;
163+ }
164+
165+
166+ /// <summary>
167+ /// Used for mapping a tree of evaluations which do not have access to their parent nodes.
168+ /// </summary>
169+ public class Factory : DisposableBase
170+ {
171+ #region Creation, Recycling, and Disposal
172+ public Factory ( )
173+ {
174+ Pool = new ConcurrentQueueObjectPool < Node < T > > (
175+ ( ) => new Node < T > ( ) , PrepareForPool , ushort . MaxValue ) ;
176+ }
177+
178+ protected override void OnDispose ( bool calledExplicitly )
179+ {
180+ if ( calledExplicitly )
181+ {
182+ DisposeOf ( ref Pool ) ;
183+ }
184+ }
185+
186+ ConcurrentQueueObjectPool < Node < T > > Pool ;
187+
188+ public void Recycle ( Node < T > n )
189+ {
190+ AssertIsAlive ( ) ;
191+
192+ RecycleInternal ( n ) ;
193+ }
194+
195+ internal void RecycleInternal ( Node < T > n )
196+ {
197+ var p = Pool ;
198+ if ( p == null ) n . Teardown ( ) ;
199+ else p . Give ( n ) ;
200+ }
201+
202+ void PrepareForPool ( Node < T > n )
203+ {
204+ n . Teardown ( this ) ;
205+ }
206+ #endregion
207+
208+ // WARNING: Care must be taken not to have duplicate nodes anywhere in the tree but having duplicate values are allowed.
209+
210+ /// <summary>
211+ /// Clones a node by recreating the tree and copying the values.
212+ /// </summary>
213+ /// <param name="target">The node to replicate.</param>
214+ /// <param name="newParentForClone">If a parent is specified it will use that node as its parent. By default it ends up being detatched.</param>
215+ /// <param name="onNodeCloned">A function that recieves the old node and its clone.</param>
216+ /// <returns>The copy of the tree/branch.</returns>
217+ public Node < T > Clone (
218+ Node < T > target ,
219+ Node < T > newParentForClone = null ,
220+ Action < Node < T > , Node < T > > onNodeCloned = null )
221+ {
222+ AssertIsAlive ( ) ;
223+
224+ var clone = Pool . Take ( ) ;
225+ clone . Value = target . Value ;
226+ newParentForClone ? . Add ( clone ) ;
227+
228+ foreach ( var child in target . _children )
229+ clone . Add ( Clone ( child , clone , onNodeCloned ) ) ;
230+
231+ onNodeCloned ? . Invoke ( target , clone ) ;
232+
233+ return clone ;
234+ }
235+
236+
237+ /// <summary>
238+ /// Clones a node by recreating the tree and copying the values.
239+ /// </summary>
240+ /// <param name="target">The node to replicate.</param>
241+ /// <param name="onNodeCloned">A function that recieves the old node and its clone.</param>
242+ /// <returns>The copy of the tree/branch.</returns>
243+ public Node < T > Clone ( Node < T > target , Action < Node < T > , Node < T > > onNodeCloned )
244+ {
245+ return Clone ( target , null , onNodeCloned ) ;
246+ }
247+
248+ /// <summary>
249+ /// Create's a clone of the entire tree but only returns the clone of this node.
250+ /// </summary>
251+ /// <returns>A clone of this node as part of a newly cloned tree.</returns>
252+ public Node < T > CloneTree ( Node < T > target )
253+ {
254+ Node < T > node = null ;
255+ Clone ( target . Root , ( n , clone ) =>
256+ {
257+ if ( n == target ) node = clone ;
258+ } ) ;
259+ return node ;
260+ }
261+
262+ /// <summary>
263+ /// Generates a full hierarchy if the root is an IParent and uses the root as the value of the hierarchy.
264+ /// Essentially building a map of the tree.
265+ /// </summary>
266+ /// <typeparam name="T">Child type.</typeparam>
267+ /// <typeparam name="TRoot">The type of the root.</typeparam>
268+ /// <param name="root">The root instance.</param>
269+ /// <returns>The full map of the root.</returns>
270+ public Node < T > Map < TRoot > ( TRoot root )
271+ where TRoot : T
272+ {
273+ AssertIsAlive ( ) ;
274+
275+ var current = Pool . Take ( ) ;
276+ current . Value = root ;
277+
278+ if ( root is IParent < T > parent )
279+ {
280+ foreach ( var child in parent . Children )
281+ {
282+ current . Add ( Map < T > ( child ) ) ;
283+ }
284+ }
285+
286+ return current ;
287+ }
288+
289+ /// <summary>
290+ /// Generates a full hierarchy if the root is an IParent and uses the root as the value of the hierarchy.
291+ /// Essentially building a map of the tree.
292+ /// </summary>
293+ /// <typeparam name="T">The type of the root.</typeparam>
294+ /// <param name="root">The root instance.</param>
295+ /// <returns>The full map of the root.</returns>
296+ public Node < T > Map ( T root )
297+ {
298+ return Map < T > ( root ) ;
299+ }
300+
301+ /// <summary>
302+ /// Generates a full hierarchy if the root of the container is an IParent and uses the root as the value of the hierarchy.
303+ /// Essentially building a map of the tree.
304+ /// </summary>
305+ /// <typeparam name="T">The type of the root.</typeparam>
306+ /// <param name="container">The container of the root instance.</param>
307+ /// <returns>The full map of the root.</returns>
308+ public Node < T > Map < TRoot > ( IHaveRoot < TRoot > container )
309+ where TRoot : T
310+ {
311+ return Map ( container . Root ) ;
312+ }
313+
314+ }
315+
316+ }
317+
318+ }
0 commit comments