// 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;
}
}
}