BinarySearch.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #ifndef mozilla_BinarySearch_h
  6. #define mozilla_BinarySearch_h
  7. #include "mozilla/Assertions.h"
  8. #include <stddef.h>
  9. namespace mozilla {
  10. /*
  11. * The BinarySearch() algorithm searches the given container |aContainer| over
  12. * the sorted index range [aBegin, aEnd) for an index |i| where
  13. * |aContainer[i] == aTarget|.
  14. * If such an index |i| is found, BinarySearch returns |true| and the index is
  15. * returned via the outparam |aMatchOrInsertionPoint|. If no index is found,
  16. * BinarySearch returns |false| and the outparam returns the first index in
  17. * [aBegin, aEnd] where |aTarget| can be inserted to maintain sorted order.
  18. *
  19. * Example:
  20. *
  21. * Vector<int> sortedInts = ...
  22. *
  23. * size_t match;
  24. * if (BinarySearch(sortedInts, 0, sortedInts.length(), 13, &match)) {
  25. * printf("found 13 at %lu\n", match);
  26. * }
  27. *
  28. * The BinarySearchIf() version behaves similarly, but takes |aComparator|, a
  29. * functor to compare the values with, instead of a value to find.
  30. * That functor should take one argument - the value to compare - and return an
  31. * |int| with the comparison result:
  32. *
  33. * * 0, if the argument is equal to,
  34. * * less than 0, if the argument is greater than,
  35. * * greater than 0, if the argument is less than
  36. *
  37. * the value.
  38. *
  39. * Example:
  40. *
  41. * struct Comparator {
  42. * int operator()(int aVal) const {
  43. * if (mTarget < aVal) { return -1; }
  44. * if (mTarget > aVal) { return 1; }
  45. * return 0;
  46. * }
  47. * explicit Comparator(int aTarget) : mTarget(aTarget) {}
  48. * const int mTarget;
  49. * };
  50. *
  51. * Vector<int> sortedInts = ...
  52. *
  53. * size_t match;
  54. * if (BinarySearchIf(sortedInts, 0, sortedInts.length(), Comparator(13), &match)) {
  55. * printf("found 13 at %lu\n", match);
  56. * }
  57. *
  58. */
  59. template<typename Container, typename Comparator>
  60. bool
  61. BinarySearchIf(const Container& aContainer, size_t aBegin, size_t aEnd,
  62. const Comparator& aCompare, size_t* aMatchOrInsertionPoint)
  63. {
  64. MOZ_ASSERT(aBegin <= aEnd);
  65. size_t low = aBegin;
  66. size_t high = aEnd;
  67. while (high != low) {
  68. size_t middle = low + (high - low) / 2;
  69. // Allow any intermediate type so long as it provides a suitable ordering
  70. // relation.
  71. const int result = aCompare(aContainer[middle]);
  72. if (result == 0) {
  73. *aMatchOrInsertionPoint = middle;
  74. return true;
  75. }
  76. if (result < 0) {
  77. high = middle;
  78. } else {
  79. low = middle + 1;
  80. }
  81. }
  82. *aMatchOrInsertionPoint = low;
  83. return false;
  84. }
  85. namespace detail {
  86. template<class T>
  87. class BinarySearchDefaultComparator
  88. {
  89. public:
  90. explicit BinarySearchDefaultComparator(const T& aTarget)
  91. : mTarget(aTarget)
  92. {}
  93. template <class U>
  94. int operator()(const U& aVal) const {
  95. if (mTarget == aVal) {
  96. return 0;
  97. }
  98. if (mTarget < aVal) {
  99. return -1;
  100. }
  101. return 1;
  102. }
  103. private:
  104. const T& mTarget;
  105. };
  106. } // namespace detail
  107. template <typename Container, typename T>
  108. bool
  109. BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd,
  110. T aTarget, size_t* aMatchOrInsertionPoint)
  111. {
  112. return BinarySearchIf(aContainer, aBegin, aEnd,
  113. detail::BinarySearchDefaultComparator<T>(aTarget),
  114. aMatchOrInsertionPoint);
  115. }
  116. } // namespace mozilla
  117. #endif // mozilla_BinarySearch_h