in vsintegration/src/FSharp.LanguageService.Base/PatternMatcher/NormalizedTextSpanCollection.cs [252:336]
public static NormalizedTextSpanCollection Difference(NormalizedTextSpanCollection left, NormalizedTextSpanCollection right)
{
if (left == null)
{
throw new ArgumentNullException(nameof(left));
}
if (right == null)
{
throw new ArgumentNullException(nameof(right));
}
if (left.Count == 0)
{
return left;
}
if (right.Count == 0)
{
return left;
}
OrderedSpanList spans = new OrderedSpanList();
int index1 = 0;
int index2 = 0;
int lastEnd = -1;
do
{
TextSpan span1 = left[index1];
TextSpan span2 = right[index2];
if ((span2.Length == 0) || (span1.Start >= span2.End))
{
++index2;
}
else if (span1.End <= span2.Start)
{
// lastEnd is set to the end of the previously encountered intersecting span
// from right when it ended before the end of span1 (so it must still be less
// than the end of span1).
Debug.Assert(lastEnd < span1.End);
spans.Add(TextSpan.FromBounds(Math.Max(lastEnd, span1.Start), span1.End));
++index1;
}
else
{
// The spans intersect, so add anything from span1 that extends to the left of span2.
if (span1.Start < span2.Start)
{
// lastEnd is set to the end of the previously encountered intersecting span
// on span2, so it must be less than the start of the current span on span2.
Debug.Assert(lastEnd < span2.Start);
spans.Add(TextSpan.FromBounds(Math.Max(lastEnd, span1.Start), span2.Start));
}
if (span1.End < span2.End)
{
++index1;
}
else if (span1.End == span2.End)
{
// Both spans ended at the same place so we're done with both.
++index1;
++index2;
}
else
{
// span2 ends before span1, so keep track of where it ended so that we don't
// try to add the excluded portion the next time we add a span.
lastEnd = span2.End;
++index2;
}
}
}
while ((index1 < left.Count) && (index2 < right.Count));
while (index1 < left.Count)
{
TextSpan span1 = left[index1++];
spans.Add(TextSpan.FromBounds(Math.Max(lastEnd, span1.Start), span1.End));
}
return new NormalizedTextSpanCollection(spans);
}