-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Interval tree refactorings. #73846
Interval tree refactorings. #73846
Conversation
@@ -27,7 +27,7 @@ internal sealed partial class TagSpanIntervalTree<TTag>(SpanTrackingMode spanTra | |||
public static readonly TagSpanIntervalTree<TTag> Empty = new(SpanTrackingMode.EdgeInclusive); | |||
|
|||
private readonly SpanTrackingMode _spanTrackingMode = spanTrackingMode; | |||
private readonly IntervalTree<TagSpan<TTag>> _tree = IntervalTree<TagSpan<TTag>>.Empty; | |||
private readonly BinaryIntervalTree<TagSpan<TTag>> _tree = BinaryIntervalTree<TagSpan<TTag>>.Empty; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renaming to add 'Binary' for clarity here. The upcoming interval tree will probably be called FlatArrayIntervalTree or something like that.
@@ -57,10 +57,10 @@ private static TagSpan<TTag> GetTranslatedTagSpan(TagSpan<TTag> originalTagSpan, | |||
: new(GetTranslatedSpan(originalTagSpan, textSnapshot, trackingMode), originalTagSpan.Tag); | |||
|
|||
public bool HasSpanThatContains(SnapshotPoint point) | |||
=> _tree.HasIntervalThatContains(point.Position, length: 0, new IntervalIntrospector(point.Snapshot, _spanTrackingMode)); | |||
=> _tree.Algorithms.HasIntervalThatContains(point.Position, length: 0, new IntervalIntrospector(point.Snapshot, _spanTrackingMode)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these helpers could not be extensions for two reasons:
- the types themselves have some existing intance methods that have hte same name. and we never look up extensions if we find a matching instance name (even if it fails).
- The extensions were on a
TIntervalTree
so that they can operate without calling through an interface once instantiated. but the inference required there is beyond what C# can do today. So i used the pattern of asking the instance for a wrapper struct that itself then exposes the operations. The property handles the initial part of generic inference, meaning that the only inference has to happen on the TIntrospector type, which works fine.
var interpolationInteriorSpans = new TextSpanIntervalTree(); | ||
var restrictedSpans = new TextSpanIntervalTree(); | ||
var interpolationInteriorSpans = new SegmentedList<TextSpan>(); | ||
var restrictedSpans = new SegmentedList<TextSpan>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moving to tree construction at end, instead of as we go along.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tree construction at end. this will move to the FlatArrayIntervalTree in next pr.
// models given any position in the file with any particular text snapshot. | ||
using var _ = SegmentedListPool.GetPooledList<DocumentSymbolDataViewModel>(out var models); | ||
AddAllModels(newViewModelItems, models); | ||
var intervalTree = BinaryIntervalTree.Create(new IntervalIntrospector(), models); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tree construction at end. this will move to the FlatArrayIntervalTree in next pr.
/// <summary> | ||
/// Mutable. Must only be accessed from the UI thread. | ||
/// </summary> | ||
private SimpleBinaryIntervalTree<GlyphData, GlyphDataIntrospector> _glyphDataTree; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tree construction at end. this will move to the FlatArrayIntervalTree in next pr.
finalParts.Add(part); | ||
} | ||
} | ||
|
||
var semanticPartsTree = new SimpleBinaryIntervalTree<TClassifiedSpan, TClassifiedSpanIntervalIntrospector>(default, values: semanticSpans); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tree construction at end. this will move to the FlatArrayIntervalTree in next pr.
/// example checking if an interval 'contains', 'intersects', or 'overlaps' with a requested span. | ||
/// </summary> | ||
internal delegate bool TestInterval<T, TIntrospector>(T value, int start, int length, in TIntrospector introspector) | ||
where TIntrospector : struct, IIntervalIntrospector<T>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new core types taht power the BinaryIntervalTree, and will power the upcoming FlatArrayIntervalTree.
/// involved here is too complex for C# to handle (specifically using a <c>TIntervalTree</c> type), which would make | ||
/// ergonomics extremely painful as the callsites would have to pass three type arguments along explicitly. | ||
/// </summary> | ||
internal readonly struct IntervalTreeAlgorithms<T, TIntervalTree>(TIntervalTree tree) where TIntervalTree : IIntervalTree<T> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all the algorithms that will work fine on any interval tree impl (binary, or flat array). extracted out from the Binary version.
/// <summary> | ||
/// Provides access to lots of common algorithms on this interval tree. | ||
/// </summary> | ||
public IntervalTreeAlgorithms<T, BinaryIntervalTree<T>> Algorithms => new(this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is how we get type inference to work. a user just calls .Algorithms, and the T and TIntervalTree types are already solved for them on the Algorithms wrapper they get back.
@@ -101,102 +104,7 @@ public static IntervalTree<T> CreateFromSorted<TIntrospector>(in TIntrospector i | |||
return node; | |||
} | |||
|
|||
protected static bool Contains<TIntrospector>(T value, int start, int length, in TIntrospector introspector) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to the Algorithms type.
private int FillWithIntervalsThatMatch<TIntrospector>( | ||
int start, int length, TestInterval<TIntrospector> testInterval, | ||
int IIntervalTree<T>.FillWithIntervalsThatMatch<TIntrospector>( | ||
int start, int length, TestInterval<T, TIntrospector> testInterval, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
switched to explicit impl as nothing should call this directly, just the algorithms type.
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Collections/IIntervalTree`1.cs
Outdated
Show resolved
Hide resolved
int FillWithIntervalsThatMatch<TIntrospector>( | ||
int start, int length, TestInterval<T, TIntrospector> testInterval, | ||
ref TemporaryArray<T> builder, in TIntrospector introspector, | ||
bool stopAfterFirst) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keeping the same logic for now. will change after flag goes in.
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Collections/IIntervalTree`1.cs
Outdated
Show resolved
Hide resolved
src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel.cs
Outdated
Show resolved
Hide resolved
@@ -130,7 +134,7 @@ public void SetSnapshotAndUpdate(ITextSnapshot snapshot, IList<ITextViewLine> ne | |||
{ | |||
// Go through all the existing visuals and invalidate or transform as appropriate. | |||
var allGlyphData = _glyphDataTree.ToImmutableArray(); | |||
_glyphDataTree.ClearInPlace(); | |||
_glyphDataTree = new(new GlyphDataIntrospector(), values: null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are some small-scale refactorings to the interval tree refactoring to prepare for a larger piece of work coming next.
The future change is that we want to provide a new impl of the interval tree that is much faster and more space efficient than the existing binary-tree form for clients (like tagging) that know all the intervals up front and which can produce the tree in one go. That tree will actually be stored directly in a flat, immutable, array, in a much more compact form as it doesn't have to ever change.
The changes in this pr are as follows: