Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 993a54c

Browse files
Optimize algorithm by sorting in-place
This finishes the optimizations by relying on the fact that we're passing a reference to the list which means we can modify it in-place. We sort the whole list of symbols on the first pass only, and then as sort children into parents' buckets we *move* them by adding them to `parent.Children` and removing them from the current list, and then recurse and modify those lists until we're done. I don't normally like relying on side-effects such as modifying in the called function, but it makes the most sense in this case for optimizations and is duly noted.
1 parent d8033b7 commit 993a54c

File tree

1 file changed

+39
-26
lines changed

1 file changed

+39
-26
lines changed

‎src/PowerShellEditorServices/Services/TextDocument/Handlers/DocumentSymbolHandler.cs‎

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License.
33

44
using System.Collections.Generic;
5+
using System.Diagnostics;
56
using System.Threading;
67
using System.Threading.Tasks;
78
using Microsoft.Extensions.Logging;
@@ -40,63 +41,75 @@ public PsesDocumentSymbolHandler(ILoggerFactory factory, WorkspaceService worksp
4041
DocumentSelector = LspUtils.PowerShellDocumentSelector
4142
};
4243

43-
// This turns a flat list of symbols into a hierarchical list.
44-
private static asyncTask<List<HierarchicalSymbol>> SortHierarchicalSymbols(List<HierarchicalSymbol> symbols, CancellationToken cancellationToken)
44+
// Modifies a flat list of symbols into a hierarchical list.
45+
private static Task SortHierarchicalSymbols(List<HierarchicalSymbol> symbols, CancellationToken cancellationToken)
4546
{
4647
// Sort by the start of the symbol definition (they're probably sorted but we need to be
47-
// certain otherwise this algorithm won't work).
48+
// certain otherwise this algorithm won't work). We only need to sort the list once, and
49+
// since the implementation is recursive, it's easiest to use the stack to track that
50+
// this is the first call.
4851
symbols.Sort((x1, x2) => x1.Range.Start.CompareTo(x2.Range.Start));
52+
return SortHierarchicalSymbolsImpl(symbols, cancellationToken);
53+
}
4954

50-
List<HierarchicalSymbol> parents=new();
51-
52-
foreach(HierarchicalSymbolsymbolinsymbols)
55+
privatestaticasyncTaskSortHierarchicalSymbolsImpl(List<HierarchicalSymbol> symbols,CancellationTokencancellationToken)
56+
{
57+
for(inti=0;i<symbols.Count;i++)
5358
{
5459
// This async method is pretty dense with synchronous code
5560
// so it's helpful to add some yields.
5661
await Task.Yield();
5762
if (cancellationToken.IsCancellationRequested)
5863
{
59-
returnparents;
64+
return;
6065
}
61-
// Base case where we haven't found any parents yet.
62-
if (parents.Count == 0)
66+
67+
HierarchicalSymbol symbol = symbols[i];
68+
69+
// Base case where we haven't found any parents yet (the first symbol must be a
70+
// parent by definition).
71+
if (i == 0)
6372
{
64-
parents.Add(symbol);
73+
continue;
6574
}
6675
// If the symbol starts after end of last symbol parsed then it's a new parent.
67-
else if (symbol.Range.Start > parents[parents.Count - 1].Range.End)
76+
else if (symbol.Range.Start > symbols[i - 1].Range.End)
6877
{
69-
parents.Add(symbol);
78+
continue;
7079
}
71-
// Otherwise it's a child, we just need to figure out whose child it is.
80+
// Otherwise it's a child, we just need to figure out whose child it is and move it there (which also means removing it from the current list).
7281
else
7382
{
74-
foreach(HierarchicalSymbolparentinparents)
83+
for(intj=0;j<=i;j++)
7584
{
85+
// While we should only check up to j < i, we iterate up to j <= i so that
86+
// we can check this assertion that we didn't exhaust the parents.
87+
Debug.Assert(j != i, "We didn't find the child's parent!");
88+
89+
HierarchicalSymbol parent = symbols[j];
7690
// If the symbol starts after the parent starts and ends before the parent
7791
// ends then its a child.
7892
if (symbol.Range.Start > parent.Range.Start && symbol.Range.End < parent.Range.End)
7993
{
94+
// Add it to the parent's list.
8095
parent.Children.Add(symbol);
96+
// Remove it from this "parents" list (because it's a child) and adjust
97+
// our loop counter because it's been removed.
98+
symbols.RemoveAt(i);
99+
i--;
81100
break;
82101
}
83102
}
84-
// TODO: If we somehow exist the list of parents and didn't find a place for the
85-
// child...we have a problem.
86103
}
87104
}
88105

89106
// Now recursively sort the children into nested buckets of children too.
90-
foreach (HierarchicalSymbol parent in parents)
107+
foreach (HierarchicalSymbol parent in symbols)
91108
{
92-
List<HierarchicalSymbol> sortedChildren = await SortHierarchicalSymbols(parent.Children, cancellationToken).ConfigureAwait(false);
93-
// Since this is a foreach we can't just assign to parent.Children and have to do
94-
// this instead.
95-
parent.Children.Clear();
96-
parent.Children.AddRange(sortedChildren);
109+
// Since this modifies in place we just recurse, no re-assignment or clearing from
110+
// parent.Children necessary.
111+
await SortHierarchicalSymbols(parent.Children, cancellationToken).ConfigureAwait(false);
97112
}
98-
99-
return parents;
100113
}
101114

102115
// This struct and the mapping function below exist to allow us to skip a *bunch* of
@@ -174,8 +187,8 @@ public override async Task<SymbolInformationOrDocumentSymbolContainer> Handle(Do
174187
return s_emptySymbolInformationOrDocumentSymbolContainer;
175188
}
176189

177-
// Otherwise slowly sort them into a hierarchy.
178-
hierarchicalSymbols=await SortHierarchicalSymbols(hierarchicalSymbols, cancellationToken).ConfigureAwait(false);
190+
// Otherwise slowly sort them into a hierarchy (this modifies the list).
191+
await SortHierarchicalSymbols(hierarchicalSymbols, cancellationToken).ConfigureAwait(false);
179192

180193
// And finally convert them to the silly SymbolInformationOrDocumentSymbol wrapper.
181194
List<SymbolInformationOrDocumentSymbol> container = new();

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /