Skip to content

Commit 8df6288

Browse files
committed
Added some manual tail recursion unwrapping
1 parent 2f7e339 commit 8df6288

File tree

1 file changed

+31
-20
lines changed

1 file changed

+31
-20
lines changed

Microsoft.Toolkit.Uwp.UI/Extensions/Tree/LogicalTree.cs

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ public static class LogicalTree
104104
where T : notnull, FrameworkElement
105105
where TPredicate : struct, IPredicate<T>
106106
{
107+
// Jump label to manually optimize the tail recursive paths for elements with a single
108+
// child by just overwriting the current element and jumping back to the start of the
109+
// method. This avoids a recursive call and one stack frame every time.
110+
Start:
111+
107112
if (element is Panel panel)
108113
{
109114
foreach (UIElement child in panel.Children)
@@ -157,7 +162,9 @@ public static class LogicalTree
157162

158163
if (userControl.Content is FrameworkElement content)
159164
{
160-
return FindChild<T, TPredicate>(content, ref predicate);
165+
element = content;
166+
167+
goto Start;
161168
}
162169
}
163170
else if (element is ContentControl contentControl)
@@ -169,7 +176,9 @@ public static class LogicalTree
169176

170177
if (contentControl.Content is FrameworkElement content)
171178
{
172-
return FindChild<T, TPredicate>(content, ref predicate);
179+
element = content;
180+
181+
goto Start;
173182
}
174183
}
175184
else if (element is Border border)
@@ -181,7 +190,9 @@ public static class LogicalTree
181190

182191
if (border.Child is FrameworkElement child)
183192
{
184-
return FindChild<T, TPredicate>(child, ref predicate);
193+
element = child;
194+
195+
goto Start;
185196
}
186197
}
187198
else if (element.GetContentControl() is FrameworkElement containedControl)
@@ -191,7 +202,9 @@ public static class LogicalTree
191202
return result;
192203
}
193204

194-
return FindChild<T, TPredicate>(containedControl, ref predicate);
205+
element = containedControl;
206+
207+
goto Start;
195208
}
196209

197210
return null;
@@ -299,6 +312,8 @@ public static class LogicalTree
299312
/// <returns>All the child <see cref="FrameworkElement"/> instance from <paramref name="element"/>.</returns>
300313
public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement element)
301314
{
315+
Start:
316+
302317
if (element is Panel panel)
303318
{
304319
foreach (UIElement child in panel.Children)
@@ -339,10 +354,9 @@ public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement e
339354
{
340355
yield return content;
341356

342-
foreach (FrameworkElement childOfContent in FindChildren(content))
343-
{
344-
yield return childOfContent;
345-
}
357+
element = content;
358+
359+
goto Start;
346360
}
347361
}
348362
else if (element is ContentControl contentControl)
@@ -351,10 +365,9 @@ public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement e
351365
{
352366
yield return content;
353367

354-
foreach (FrameworkElement childOfContent in FindChildren(content))
355-
{
356-
yield return childOfContent;
357-
}
368+
element = content;
369+
370+
goto Start;
358371
}
359372
}
360373
else if (element is Border border)
@@ -363,20 +376,18 @@ public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement e
363376
{
364377
yield return child;
365378

366-
foreach (FrameworkElement childOfChild in FindChildren(child))
367-
{
368-
yield return childOfChild;
369-
}
379+
element = child;
380+
381+
goto Start;
370382
}
371383
}
372384
else if (element.GetContentControl() is FrameworkElement containedControl)
373385
{
374386
yield return containedControl;
375387

376-
foreach (FrameworkElement childOfChild in FindChildren(containedControl))
377-
{
378-
yield return childOfChild;
379-
}
388+
element = containedControl;
389+
390+
goto Start;
380391
}
381392
}
382393

0 commit comments

Comments
 (0)