BinarySearchExtension.cs 4.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // RichTextKit
  2. // Copyright © 2019-2020 Topten Software. All Rights Reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. // not use this product except in compliance with the License. You may obtain
  6. // a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. // License for the specific language governing permissions and limitations
  14. // under the License.
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Text;
  18. namespace Topten.RichTextKit.Utils
  19. {
  20. /// <summary>
  21. /// Extension methods for binary searching an IReadOnlyList collection
  22. /// </summary>
  23. public static class BinarySearchExtension
  24. {
  25. private static int GetMedian(int low, int hi)
  26. {
  27. System.Diagnostics.Debug.Assert(low <= hi);
  28. System.Diagnostics.Debug.Assert( hi - low >= 0, "Length overflow!");
  29. return low + ((hi - low) >> 1);
  30. }
  31. /// <summary>
  32. /// Performs a binary search on the entire contents of an IReadOnlyList
  33. /// </summary>
  34. /// <typeparam name="T">The list element type</typeparam>
  35. /// <param name="list">The list to be searched</param>
  36. /// <param name="value">The value to search for</param>
  37. /// <returns>The index of the found item; otherwise the bitwise complement of the index of the next larger item</returns>
  38. public static int BinarySearch<T>(this IReadOnlyList<T> list, T value) where T : IComparable
  39. {
  40. return list.BinarySearch(value, (a, b) => a.CompareTo(b));
  41. }
  42. /// <summary>
  43. /// Performs a binary search on the entire contents of an IReadOnlyList
  44. /// </summary>
  45. /// <typeparam name="T">The list element type</typeparam>
  46. /// <typeparam name="U">The value type being searched for</typeparam>
  47. /// <param name="list">The list to be searched</param>
  48. /// <param name="value">The value to search for</param>
  49. /// <param name="compare">A comparison function</param>
  50. /// <returns>The index of the found item; otherwise the bitwise complement of the index of the next larger item</returns>
  51. public static int BinarySearch<T, U>(this IReadOnlyList<T> list, U value, Func<T, U, int> compare)
  52. {
  53. return BinarySearch(list, 0, list.Count, value, compare);
  54. }
  55. /// <summary>
  56. /// Performs a binary search on a a subset of an IReadOnlyList
  57. /// </summary>
  58. /// <typeparam name="T">The list element type</typeparam>
  59. /// <typeparam name="U">The value type being searched for</typeparam>
  60. /// <param name="list">The list to be searched</param>
  61. /// <param name="index">The start of the range to be searched</param>
  62. /// <param name="length">The length of the range to be searched</param>
  63. /// <param name="value">The value to search for</param>
  64. /// <param name="compare">A comparison function</param>
  65. /// <returns>The index of the found item; otherwise the bitwise complement of the index of the next larger item</returns>
  66. public static int BinarySearch<T, U>(this IReadOnlyList<T> list, int index, int length, U value, Func<T, U, int> compare)
  67. {
  68. // Based on this: https://referencesource.microsoft.com/#mscorlib/system/array.cs,957
  69. int lo = index;
  70. int hi = index + length - 1;
  71. while (lo <= hi)
  72. {
  73. int i = GetMedian(lo, hi);
  74. int c = compare(list[i], value);
  75. if (c == 0) return i;
  76. if (c < 0) {
  77. lo = i + 1;
  78. }
  79. else {
  80. hi = i - 1;
  81. }
  82. }
  83. return ~lo;
  84. }
  85. }
  86. }