BinarySearch.h 3.5 KB

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