internal override int BinarySearch(TreeSpan span, T item, IComparer <T> comparer) { Debug.Assert(span.IsSubspanOf(Span), $"Assertion failed: {nameof(span)}.IsSubspanOf({nameof(Span)})"); Debug.Assert(comparer != null, $"Assertion failed: {nameof(comparer)} != null"); return(~0); }
internal override int FindLastIndex(TreeSpan span, Predicate <T> match) { Debug.Assert(span.IsSubspanOf(Span), $"Assertion failed: {nameof(span)}.IsSubspanOf({nameof(Span)})"); Debug.Assert(match != null, $"Assertion failed: {nameof(match)} != null"); return(Array.FindLastIndex(_data, span.EndInclusive, span.Count, match)); }
internal override int BinarySearch(TreeSpan span, T item, IComparer <T> comparer) { Debug.Assert(span.IsSubspanOf(Span), $"Assertion failed: {nameof(span)}.IsSubspanOf({nameof(Span)})"); Debug.Assert(comparer != null, $"Assertion failed: {nameof(comparer)} != null"); return(Array.BinarySearch(_data, span.Start, span.Count, item, comparer)); }
internal override int FindLastIndex(TreeSpan span, Predicate <T> match) { Debug.Assert(span.IsSubspanOf(Span), $"Assertion failed: {nameof(span)}.IsSubspanOf({nameof(Span)})"); Debug.Assert(match != null, $"Assertion failed: {nameof(match)} != null"); return(-1); }
internal override void Sort(TreeSpan span, IComparer <T> comparer) { Debug.Assert(span.IsSubspanOf(Span), $"Assertion failed: {nameof(span)}.IsSubspanOf({nameof(Span)})"); Debug.Assert(comparer != null, $"Assertion failed: {nameof(comparer)} != null"); Array.Sort(_data, span.Start, span.Count, comparer); }
internal override int BinarySearch(TreeSpan span, T item, IComparer <T> comparer) { Debug.Assert(span.IsSubspanOf(Span), $"Assertion failed: {nameof(span)}.IsSubspanOf({nameof(Span)})"); Debug.Assert(comparer != null, $"Assertion failed: {nameof(comparer)} != null"); // Since accessing FirstLeaf is O(1), at each index level we are only looking for the correct child page int firstPage = FindLowerBound(_offsets, _nodeCount, span.Start); int lastPage = FindLowerBound(_offsets, _nodeCount, span.EndInclusive); int lowPage = firstPage; int highPage = lastPage; while (lowPage < highPage) { // Avoid choosing page == lowPage because we won't have enough information to make progress int page = lowPage + ((highPage - lowPage + 1) >> 1); Debug.Assert(page > firstPage, $"Assertion failed: {nameof(page)} > {nameof(firstPage)}"); T value = _nodes[page].FirstLeaf[0]; int c; try { c = comparer.Compare(value, item); } catch (Exception e) { throw new InvalidOperationException("Failed to compare two elements in the list.", e); } if (c == 0) { // Binary search allows any index once found return(_offsets[page]); } if (c < 0) { lowPage = page; } else { highPage = page - 1; } } Debug.Assert(lowPage >= 0 && lowPage < _nodeCount, $"Assertion failed: {nameof(lowPage)} >= 0 && {nameof(lowPage)} < {nameof(_nodeCount)}"); int result = _nodes[lowPage].BinarySearch(MapSpanDownToChild(span, lowPage), item, comparer); if (result < 0) { return(~(~result + _offsets[lowPage])); } else { return(result + _offsets[lowPage]); } }
internal Enumerator(TreeList <T> list, TreeSpan span) { _list = list; _span = span; _version = list._version; _index = -1; _leafNode = null; _leafIndex = -1; _current = default !;
private TreeSpan MapSpanDownToChild(TreeSpan span, int childIndex) { Debug.Assert(childIndex >= 0 && childIndex < _nodeCount, $"Assertion failed: {nameof(childIndex)} >= 0 && {nameof(childIndex)} < {nameof(_nodeCount)}"); // Offset the input span TreeSpan mappedFullSpan = span.Offset(-_offsets[childIndex]); // Return the intersection return(TreeSpan.Intersect(mappedFullSpan, _nodes[childIndex].Span)); }
internal void Reverse(TreeSpan span) { int firstIndex = span.Start; int lastIndex = firstIndex + span.Count - 1; while (lastIndex > firstIndex) { T temp = this[firstIndex]; this[firstIndex] = this[lastIndex]; this[lastIndex] = temp; firstIndex++; lastIndex--; } }
internal override int BinarySearch(TreeSpan span, T item, IComparer <T> comparer) { Debug.Assert(span.IsSubspanOf(Span), $"Assertion failed: {nameof(span)}.IsSubspanOf({nameof(Span)})"); Debug.Assert(comparer != null, $"Assertion failed: {nameof(comparer)} != null"); // Since accessing FirstLeaf is O(1), at each index level we are only looking for the correct child page int firstPage = FindLowerBound(_offsets, _nodeCount, span.Start); int lastPage = FindLowerBound(_offsets, _nodeCount, span.EndInclusive); int lowPage = firstPage; int highPage = lastPage; while (lowPage < highPage) { // Avoid choosing page == lowPage because we won't have enough information to make progress int page = lowPage + ((highPage - lowPage + 1) >> 1); Debug.Assert(page > firstPage, $"Assertion failed: {nameof(page)} > {nameof(firstPage)}"); T value = _nodes[page].FirstLeaf ![0];
internal override int LastIndexOf(T item, TreeSpan span) { Debug.Assert(span.IsSubspanOf(Span), $"Assertion failed: {nameof(span)}.IsSubspanOf({nameof(Span)})"); for (int i = FindLowerBound(_offsets, _nodeCount, span.EndInclusive); i >= 0; i--) { TreeSpan mappedSpan = MapSpanDownToChild(span, i); if (mappedSpan.IsEmpty) { return(-1); } int foundIndex = _nodes[i].LastIndexOf(item, mappedSpan); if (foundIndex >= 0) { return(_offsets[i] + foundIndex); } } return(-1); }
internal override int FindLastIndex(TreeSpan span, Predicate <T> match) { Debug.Assert(span.IsSubspanOf(Span), $"Assertion failed: {nameof(span)}.IsSubspanOf({nameof(Span)})"); Debug.Assert(match != null, $"Assertion failed: {nameof(match)} != null"); for (int i = FindLowerBound(_offsets, _nodeCount, span.EndInclusive); i >= 0; i--) { TreeSpan mappedSpan = MapSpanDownToChild(span, i); if (mappedSpan.IsEmpty) { return(-1); } int foundIndex = _nodes[i].FindLastIndex(mappedSpan, match); if (foundIndex >= 0) { return(_offsets[i] + foundIndex); } } return(-1); }
internal override void Sort(TreeSpan span, IComparer <T> comparer) { Debug.Assert(span.IsSubspanOf(Span), $"Assertion failed: {nameof(span)}.IsSubspanOf({nameof(Span)})"); Debug.Assert(comparer != null, $"Assertion failed: {nameof(comparer)} != null"); int firstPage = FindLowerBound(_offsets, _nodeCount, span.Start); int lastPage = firstPage; for (int i = firstPage; i < _nodeCount; i++) { TreeSpan mappedSpan = MapSpanDownToChild(span, i); if (mappedSpan.IsEmpty) { break; } lastPage = i; _nodes[i].Sort(mappedSpan, comparer); } if (firstPage != lastPage) { // Need to merge the results int pageCount = lastPage - firstPage + 1; for (int mergeSegmentSize = 1; mergeSegmentSize < pageCount; mergeSegmentSize *= 2) { for (int firstSegment = firstPage; firstSegment < lastPage; firstSegment += mergeSegmentSize * 2) { int secondSegment = firstSegment + mergeSegmentSize; if (secondSegment > lastPage) { break; } TreeSpan firstSpan = GetSegmentSpan(span, firstSegment, mergeSegmentSize); TreeSpan secondSpan = GetSegmentSpan(span, secondSegment, mergeSegmentSize); MergeSegments(firstSpan, secondSpan); } } } // Local functions TreeSpan GetSegmentSpan(TreeSpan bounds, int firstPageOfSegment, int segmentPageCount) { int lastPageOfSegment = Math.Min(_nodeCount - 1, firstPageOfSegment + segmentPageCount - 1); int startIndex = _offsets[firstPageOfSegment]; int endIndexExclusive = _offsets[lastPageOfSegment] + _nodes[lastPageOfSegment].Count; return(TreeSpan.Intersect(bounds, TreeSpan.FromBounds(startIndex, endIndexExclusive))); } void MergeSegments(TreeSpan first, TreeSpan second) { Debug.Assert(first.IsSubspanOf(Span), $"Assertion failed: {nameof(first)}.IsSubspanOf({nameof(Span)})"); Debug.Assert(second.IsSubspanOf(Span), $"Assertion failed: {nameof(second)}.IsSubspanOf({nameof(Span)})"); Debug.Assert(first.EndExclusive == second.Start, $"Assertion failed: first.EndExclusive == second.Start"); // Stop immediately if already ordered if (comparer.Compare(this[first.EndInclusive], this[second.Start]) <= 0) { return; } int i = first.Start; int j = second.Start; while (true) { if (i == first.EndExclusive) { break; } Debug.Assert(j < second.EndExclusive, $"Assertion failed: j < second.EndExclusive"); int c = comparer.Compare(this[i], this[j]); if (c == 0) { i++; } else if (c < 0) { i++; } else { T temp = this[i]; this[i] = this[j]; this[j] = temp; i++; while (i < first.EndExclusive && j < second.EndExclusive - 1 && comparer.Compare(temp, this[j + 1]) > 0) { j++; T temp2 = this[i]; this[i] = this[j]; this[j] = temp2; i++; } if (j > 1 && j + 1 < second.EndExclusive) { MergeSegments(TreeSpan.FromBounds(second.Start, j + 1), TreeSpan.FromBounds(j + 1, second.EndExclusive)); } j = second.Start; } } } }
internal abstract int LastIndexOf(T item, TreeSpan span);
internal override int LastIndexOf(T item, TreeSpan span) { Debug.Assert(span.IsSubspanOf(Span), $"Assertion failed: {nameof(span)}.IsSubspanOf({nameof(Span)})"); return(Array.LastIndexOf(_data, item, span.EndInclusive, span.Count)); }
internal abstract void Sort(TreeSpan span, IComparer <T> comparer);
internal abstract int FindLastIndex(TreeSpan span, Predicate <T> match);
internal abstract int BinarySearch(TreeSpan span, T item, IComparer <T> comparer);
internal override int IndexOf(T item, TreeSpan span) { Debug.Assert(span.IsSubspanOf(Span), $"Assertion failed: {nameof(span)}.IsSubspanOf({nameof(Span)})"); return(-1); }
internal override int LastIndexOf(T item, TreeSpan span) { throw ExceptionUtilities.Unreachable; }