// RichTextKit // Copyright © 2019-2020 Topten Software. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this product except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.Text; namespace Topten.RichTextKit.Utils { /// /// Extension methods for binary searching an IReadOnlyList collection /// public static class BinarySearchExtension { private static int GetMedian(int low, int hi) { System.Diagnostics.Debug.Assert(low <= hi); System.Diagnostics.Debug.Assert( hi - low >= 0, "Length overflow!"); return low + ((hi - low) >> 1); } /// /// Performs a binary search on the entire contents of an IReadOnlyList /// /// The list element type /// The list to be searched /// The value to search for /// The index of the found item; otherwise the bitwise complement of the index of the next larger item public static int BinarySearch(this IReadOnlyList list, T value) where T : IComparable { return list.BinarySearch(value, (a, b) => a.CompareTo(b)); } /// /// Performs a binary search on the entire contents of an IReadOnlyList /// /// The list element type /// The value type being searched for /// The list to be searched /// The value to search for /// A comparison function /// The index of the found item; otherwise the bitwise complement of the index of the next larger item public static int BinarySearch(this IReadOnlyList list, U value, Func compare) { return BinarySearch(list, 0, list.Count, value, compare); } /// /// Performs a binary search on a a subset of an IReadOnlyList /// /// The list element type /// The value type being searched for /// The list to be searched /// The start of the range to be searched /// The length of the range to be searched /// The value to search for /// A comparison function /// The index of the found item; otherwise the bitwise complement of the index of the next larger item public static int BinarySearch(this IReadOnlyList list, int index, int length, U value, Func compare) { // Based on this: https://referencesource.microsoft.com/#mscorlib/system/array.cs,957 int lo = index; int hi = index + length - 1; while (lo <= hi) { int i = GetMedian(lo, hi); int c = compare(list[i], value); if (c == 0) return i; if (c < 0) { lo = i + 1; } else { hi = i - 1; } } return ~lo; } } }