Skip to content

Commit a629604

Browse files
authored
Merge pull request #4333 from Sergio0694/feature/extended-tree-helpers
Feature/extended tree helpers
2 parents 62c4934 + 888ec93 commit a629604

File tree

7 files changed

+1016
-47
lines changed

7 files changed

+1016
-47
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace Microsoft.Toolkit.Uwp.UI
6+
{
7+
/// <summary>
8+
/// Indicates a type of search for elements in a visual or logical tree.
9+
/// </summary>
10+
public enum SearchType
11+
{
12+
/// <summary>
13+
/// Depth-first search, where each branch is recursively explored until the end before moving to the next one.
14+
/// </summary>
15+
DepthFirst,
16+
17+
/// <summary>
18+
/// Breadth-first search, where each depthwise level is completely explored before moving to the next one.
19+
/// This is particularly useful if the target element to find is known to not be too distant from the starting
20+
/// point and the whole visual/logical tree from the root is large enough, as it can reduce the traversal time.
21+
/// </summary>
22+
BreadthFirst
23+
}
24+
}

Microsoft.Toolkit.Uwp.UI/Extensions/DependencyObjectExtensions.cs

Lines changed: 541 additions & 33 deletions
Large diffs are not rendered by default.

Microsoft.Toolkit.Uwp.UI/Extensions/FrameworkElement/FrameworkElementExtensions.LogicalTree.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public static partial class FrameworkElementExtensions
6363
/// </summary>
6464
/// <typeparam name="T">The type of elements to match.</typeparam>
6565
/// <param name="element">The root element.</param>
66-
/// <param name="predicate">The predicatee to use to match the child nodes.</param>
66+
/// <param name="predicate">The predicate to use to match the child nodes.</param>
6767
/// <returns>The child that was found, or <see langword="null"/>.</returns>
6868
public static T? FindChild<T>(this FrameworkElement element, Func<T, bool> predicate)
6969
where T : notnull, FrameworkElement
@@ -80,7 +80,7 @@ public static partial class FrameworkElementExtensions
8080
/// <typeparam name="TState">The type of state to use when matching nodes.</typeparam>
8181
/// <param name="element">The root element.</param>
8282
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
83-
/// <param name="predicate">The predicatee to use to match the child nodes.</param>
83+
/// <param name="predicate">The predicate to use to match the child nodes.</param>
8484
/// <returns>The child that was found, or <see langword="null"/>.</returns>
8585
public static T? FindChild<T, TState>(this FrameworkElement element, TState state, Func<T, TState, bool> predicate)
8686
where T : notnull, FrameworkElement
@@ -96,7 +96,7 @@ public static partial class FrameworkElementExtensions
9696
/// <typeparam name="T">The type of elements to match.</typeparam>
9797
/// <typeparam name="TPredicate">The type of predicate in use.</typeparam>
9898
/// <param name="element">The root element.</param>
99-
/// <param name="predicate">The predicatee to use to match the child nodes.</param>
99+
/// <param name="predicate">The predicate to use to match the child nodes.</param>
100100
/// <returns>The child that was found, or <see langword="null"/>.</returns>
101101
private static T? FindChild<T, TPredicate>(this FrameworkElement element, ref TPredicate predicate)
102102
where T : notnull, FrameworkElement
@@ -296,7 +296,7 @@ public static partial class FrameworkElementExtensions
296296
/// </summary>
297297
/// <typeparam name="T">The type of elements to match.</typeparam>
298298
/// <param name="element">The root element.</param>
299-
/// <param name="predicate">The predicatee to use to match the child nodes.</param>
299+
/// <param name="predicate">The predicate to use to match the child nodes.</param>
300300
/// <returns>The child (or self) that was found, or <see langword="null"/>.</returns>
301301
public static T? FindChildOrSelf<T>(this FrameworkElement element, Func<T, bool> predicate)
302302
where T : notnull, FrameworkElement
@@ -316,7 +316,7 @@ public static partial class FrameworkElementExtensions
316316
/// <typeparam name="TState">The type of state to use when matching nodes.</typeparam>
317317
/// <param name="element">The root element.</param>
318318
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
319-
/// <param name="predicate">The predicatee to use to match the child nodes.</param>
319+
/// <param name="predicate">The predicate to use to match the child nodes.</param>
320320
/// <returns>The child (or self) that was found, or <see langword="null"/>.</returns>
321321
public static T? FindChildOrSelf<T, TState>(this FrameworkElement element, TState state, Func<T, TState, bool> predicate)
322322
where T : notnull, FrameworkElement
@@ -490,7 +490,7 @@ public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement e
490490
/// </summary>
491491
/// <typeparam name="T">The type of elements to match.</typeparam>
492492
/// <param name="element">The starting element.</param>
493-
/// <param name="predicate">The predicatee to use to match the parent nodes.</param>
493+
/// <param name="predicate">The predicate to use to match the parent nodes.</param>
494494
/// <returns>The parent that was found, or <see langword="null"/>.</returns>
495495
public static T? FindParent<T>(this FrameworkElement element, Func<T, bool> predicate)
496496
where T : notnull, FrameworkElement
@@ -507,7 +507,7 @@ public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement e
507507
/// <typeparam name="TState">The type of state to use when matching nodes.</typeparam>
508508
/// <param name="element">The starting element.</param>
509509
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
510-
/// <param name="predicate">The predicatee to use to match the parent nodes.</param>
510+
/// <param name="predicate">The predicate to use to match the parent nodes.</param>
511511
/// <returns>The parent that was found, or <see langword="null"/>.</returns>
512512
public static T? FindParent<T, TState>(this FrameworkElement element, TState state, Func<T, TState, bool> predicate)
513513
where T : notnull, FrameworkElement
@@ -523,7 +523,7 @@ public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement e
523523
/// <typeparam name="T">The type of elements to match.</typeparam>
524524
/// <typeparam name="TPredicate">The type of predicate in use.</typeparam>
525525
/// <param name="element">The starting element.</param>
526-
/// <param name="predicate">The predicatee to use to match the parent nodes.</param>
526+
/// <param name="predicate">The predicate to use to match the parent nodes.</param>
527527
/// <returns>The parent that was found, or <see langword="null"/>.</returns>
528528
private static T? FindParent<T, TPredicate>(this FrameworkElement element, ref TPredicate predicate)
529529
where T : notnull, FrameworkElement
@@ -600,7 +600,7 @@ public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement e
600600
/// </summary>
601601
/// <typeparam name="T">The type of elements to match.</typeparam>
602602
/// <param name="element">The starting element.</param>
603-
/// <param name="predicate">The predicatee to use to match the parent nodes.</param>
603+
/// <param name="predicate">The predicate to use to match the parent nodes.</param>
604604
/// <returns>The parent (or self) that was found, or <see langword="null"/>.</returns>
605605
public static T? FindParentOrSelf<T>(this FrameworkElement element, Func<T, bool> predicate)
606606
where T : notnull, FrameworkElement
@@ -620,7 +620,7 @@ public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement e
620620
/// <typeparam name="TState">The type of state to use when matching nodes.</typeparam>
621621
/// <param name="element">The starting element.</param>
622622
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
623-
/// <param name="predicate">The predicatee to use to match the parent nodes.</param>
623+
/// <param name="predicate">The predicate to use to match the parent nodes.</param>
624624
/// <returns>The parent (or self) that was found, or <see langword="null"/>.</returns>
625625
public static T? FindParentOrSelf<T, TState>(this FrameworkElement element, TState state, Func<T, TState, bool> predicate)
626626
where T : notnull, FrameworkElement

Microsoft.Toolkit.Uwp.UI/Extensions/Predicates/PredicateByFunc{T,TState}.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ namespace Microsoft.Toolkit.Uwp.UI.Predicates
2121
private readonly TState state;
2222

2323
/// <summary>
24-
/// The predicatee to use to match items.
24+
/// The predicate to use to match items.
2525
/// </summary>
2626
private readonly Func<T, TState, bool> predicate;
2727

2828
/// <summary>
2929
/// Initializes a new instance of the <see cref="PredicateByFunc{T, TState}"/> struct.
3030
/// </summary>
3131
/// <param name="state">The state to give as input to <paramref name="predicate"/>.</param>
32-
/// <param name="predicate">The predicatee to use to match items.</param>
32+
/// <param name="predicate">The predicate to use to match items.</param>
3333
public PredicateByFunc(TState state, Func<T, TState, bool> predicate)
3434
{
3535
this.state = state;

Microsoft.Toolkit.Uwp.UI/Extensions/Predicates/PredicateByFunc{T}.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Predicates
1515
where T : class
1616
{
1717
/// <summary>
18-
/// The predicatee to use to match items.
18+
/// The predicate to use to match items.
1919
/// </summary>
2020
private readonly Func<T, bool> predicate;
2121

2222
/// <summary>
2323
/// Initializes a new instance of the <see cref="PredicateByFunc{T}"/> struct.
2424
/// </summary>
25-
/// <param name="predicate">The predicatee to use to match items.</param>
25+
/// <param name="predicate">The predicate to use to match items.</param>
2626
public PredicateByFunc(Func<T, bool> predicate)
2727
{
2828
this.predicate = predicate;
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Buffers;
7+
using System.Diagnostics.Contracts;
8+
using System.Runtime.CompilerServices;
9+
10+
namespace Microsoft.Toolkit.Uwp.UI.Helpers.Internals
11+
{
12+
/// <summary>
13+
/// A simple buffer writer implementation using pooled arrays.
14+
/// </summary>
15+
/// <typeparam name="T">The type of items to store in the list.</typeparam>
16+
/// <remarks>
17+
/// This type is a <see langword="ref"/> <see langword="struct"/> to avoid the object allocation and to
18+
/// enable the pattern-based <see cref="IDisposable"/> support. We aren't worried with consumers not
19+
/// using this type correctly since it's private and only accessible within the parent type.
20+
/// </remarks>
21+
internal struct ArrayPoolBufferWriter<T> : IDisposable
22+
{
23+
/// <summary>
24+
/// The default buffer size to use to expand empty arrays.
25+
/// </summary>
26+
private const int DefaultInitialBufferSize = 128;
27+
28+
/// <summary>
29+
/// The underlying <typeparamref name="T"/> array.
30+
/// </summary>
31+
private T[] array;
32+
33+
/// <summary>
34+
/// The starting offset within <see cref="array"/>.
35+
/// </summary>
36+
private int index;
37+
38+
/// <summary>
39+
/// Creates a new instance of the <see cref="ArrayPoolBufferWriter{T}"/> struct.
40+
/// </summary>
41+
/// <returns>A new <see cref="ArrayPoolBufferWriter{T}"/> instance.</returns>
42+
[Pure]
43+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
44+
public static ArrayPoolBufferWriter<T> Create()
45+
{
46+
return new() { array = ArrayPool<T>.Shared.Rent(DefaultInitialBufferSize) };
47+
}
48+
49+
/// <summary>
50+
/// Gets the total number of items stored in the current instance.
51+
/// </summary>
52+
public int Count
53+
{
54+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
55+
get => this.array.Length;
56+
}
57+
58+
/// <summary>
59+
/// Gets the item at the specified offset into the current buffer in use.
60+
/// </summary>
61+
/// <param name="index">The index of the element to retrieve.</param>
62+
/// <returns>The item at the specified offset into the current buffer in use.</returns>
63+
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="index"/> is out of range.</exception>
64+
public T this[int index]
65+
{
66+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
67+
get
68+
{
69+
if ((uint)index >= this.index)
70+
{
71+
static void Throw() => throw new ArgumentOutOfRangeException(nameof(index));
72+
73+
Throw();
74+
}
75+
76+
return this.array[index];
77+
}
78+
}
79+
80+
/// <summary>
81+
/// Adds a new item to the current collection.
82+
/// </summary>
83+
/// <param name="item">The item to add.</param>
84+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
85+
public void Add(T item)
86+
{
87+
if (this.index == this.array.Length)
88+
{
89+
ResizeBuffer();
90+
}
91+
92+
this.array[this.index++] = item;
93+
}
94+
95+
/// <summary>
96+
/// Resets the underlying array and the stored items.
97+
/// </summary>
98+
public void Reset()
99+
{
100+
Array.Clear(this.array, 0, this.index);
101+
102+
this.index = 0;
103+
}
104+
105+
/// <summary>
106+
/// Resizes <see cref="array"/> when there is no space left for new items.
107+
/// </summary>
108+
[MethodImpl(MethodImplOptions.NoInlining)]
109+
private void ResizeBuffer()
110+
{
111+
T[] rent = ArrayPool<T>.Shared.Rent(this.index << 2);
112+
113+
Array.Copy(this.array, 0, rent, 0, this.index);
114+
Array.Clear(this.array, 0, this.index);
115+
116+
ArrayPool<T>.Shared.Return(this.array);
117+
118+
this.array = rent;
119+
}
120+
121+
/// <inheritdoc cref="IDisposable.Dispose"/>
122+
public void Dispose()
123+
{
124+
Array.Clear(this.array, 0, this.index);
125+
126+
ArrayPool<T>.Shared.Return(this.array);
127+
}
128+
}
129+
}

0 commit comments

Comments
 (0)