mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1059179 - Add BinarySearchIf(). r=waldo
This commit is contained in:
parent
6d86e1e263
commit
e1bff79b5b
@ -14,8 +14,9 @@
|
||||
namespace mozilla {
|
||||
|
||||
/*
|
||||
* The algorithm searches the given container |aContainer| over the sorted
|
||||
* index range [aBegin, aEnd) for an index |i| where |aContainer[i] == aTarget|.
|
||||
* The BinarySearch() algorithm searches the given container |aContainer| over
|
||||
* the sorted index range [aBegin, aEnd) for an index |i| where
|
||||
* |aContainer[i] == aTarget|.
|
||||
* If such an index |i| is found, BinarySearch returns |true| and the index is
|
||||
* returned via the outparam |aMatchOrInsertionPoint|. If no index is found,
|
||||
* BinarySearch returns |false| and the outparam returns the first index in
|
||||
@ -29,34 +30,61 @@ namespace mozilla {
|
||||
* if (BinarySearch(sortedInts, 0, sortedInts.length(), 13, &match)) {
|
||||
* printf("found 13 at %lu\n", match);
|
||||
* }
|
||||
*
|
||||
* The BinarySearchIf() version behaves similar, but takes |aComparator|, a
|
||||
* functor to compare the values with, instead of a value to find.
|
||||
* That functor should take one argument - the value to compare - and return an
|
||||
* |int| with the comparison result:
|
||||
*
|
||||
* * 0, if the argument is equal to,
|
||||
* * less than 0, if the argument is greater than,
|
||||
* * greater than 0, if the argument is less than
|
||||
*
|
||||
* the value.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* struct Comparator {
|
||||
* int operator()(int val) const {
|
||||
* if (mTarget < val) return -1;
|
||||
* if (mValue > val) return 1;
|
||||
* return 0;
|
||||
* }
|
||||
* Comparator(int target) : mTarget(target) {}
|
||||
const int mTarget;
|
||||
* };
|
||||
*
|
||||
* Vector<int> sortedInts = ...
|
||||
*
|
||||
* size_t match;
|
||||
* if (BinarySearchIf(sortedInts, 0, sortedInts.length(), Comparator(13), &match)) {
|
||||
* printf("found 13 at %lu\n", match);
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
template <typename Container, typename T>
|
||||
template<typename Container, typename Comparator>
|
||||
bool
|
||||
BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd,
|
||||
T aTarget, size_t* aMatchOrInsertionPoint)
|
||||
BinarySearchIf(const Container& aContainer, size_t aBegin, size_t aEnd,
|
||||
const Comparator& aCompare, size_t* aMatchOrInsertionPoint)
|
||||
{
|
||||
MOZ_ASSERT(aBegin <= aEnd);
|
||||
|
||||
size_t low = aBegin;
|
||||
size_t high = aEnd;
|
||||
while (low != high) {
|
||||
while (high != low) {
|
||||
size_t middle = low + (high - low) / 2;
|
||||
|
||||
// Allow any intermediate type so long as it provides a suitable ordering
|
||||
// relation.
|
||||
const auto& middleValue = aContainer[middle];
|
||||
const int result = aCompare(aContainer[middle]);
|
||||
|
||||
MOZ_ASSERT(aContainer[low] <= aContainer[middle]);
|
||||
MOZ_ASSERT(aContainer[middle] <= aContainer[high - 1]);
|
||||
MOZ_ASSERT(aContainer[low] <= aContainer[high - 1]);
|
||||
|
||||
if (aTarget == middleValue) {
|
||||
if (result == 0) {
|
||||
*aMatchOrInsertionPoint = middle;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aTarget < middleValue) {
|
||||
if (result < 0) {
|
||||
high = middle;
|
||||
} else {
|
||||
low = middle + 1;
|
||||
@ -67,6 +95,45 @@ BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd,
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
class BinarySearchDefaultComparator
|
||||
{
|
||||
public:
|
||||
BinarySearchDefaultComparator(const T& aTarget)
|
||||
: mTarget(aTarget)
|
||||
{}
|
||||
|
||||
template <class U>
|
||||
int operator()(const U& val) const {
|
||||
if (mTarget == val) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mTarget < val) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private:
|
||||
const T& mTarget;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename Container, typename T>
|
||||
bool
|
||||
BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd,
|
||||
T aTarget, size_t* aMatchOrInsertionPoint)
|
||||
{
|
||||
return BinarySearchIf(aContainer, aBegin, aEnd,
|
||||
detail::BinarySearchDefaultComparator<T>(aTarget),
|
||||
aMatchOrInsertionPoint);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_BinarySearch_h
|
||||
|
@ -8,8 +8,12 @@
|
||||
#include "mozilla/BinarySearch.h"
|
||||
#include "mozilla/Vector.h"
|
||||
|
||||
using mozilla::Vector;
|
||||
using mozilla::ArrayLength;
|
||||
using mozilla::BinarySearch;
|
||||
using mozilla::BinarySearchIf;
|
||||
using mozilla::Vector;
|
||||
|
||||
#define A(a) MOZ_RELEASE_ASSERT(a)
|
||||
|
||||
struct Person
|
||||
{
|
||||
@ -25,8 +29,18 @@ struct GetAge
|
||||
int operator[](size_t index) const { return mV[index].mAge; }
|
||||
};
|
||||
|
||||
int
|
||||
main()
|
||||
struct RangeFinder {
|
||||
const int mLower, mUpper;
|
||||
RangeFinder(int lower, int upper) : mLower(lower), mUpper(upper) {}
|
||||
int operator()(int val) const {
|
||||
if (val >= mUpper) return -1;
|
||||
if (val < mLower) return 1;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
TestBinarySearch()
|
||||
{
|
||||
size_t m;
|
||||
|
||||
@ -68,7 +82,6 @@ main()
|
||||
v3.append(Person(4, 13));
|
||||
v3.append(Person(6, 360));
|
||||
|
||||
#define A(a) MOZ_RELEASE_ASSERT(a)
|
||||
A(!BinarySearch(GetAge(v3), 0, v3.length(), 1, &m) && m == 0);
|
||||
A( BinarySearch(GetAge(v3), 0, v3.length(), 2, &m) && m == 0);
|
||||
A(!BinarySearch(GetAge(v3), 0, v3.length(), 3, &m) && m == 1);
|
||||
@ -76,5 +89,25 @@ main()
|
||||
A(!BinarySearch(GetAge(v3), 0, v3.length(), 5, &m) && m == 2);
|
||||
A( BinarySearch(GetAge(v3), 0, v3.length(), 6, &m) && m == 2);
|
||||
A(!BinarySearch(GetAge(v3), 0, v3.length(), 7, &m) && m == 3);
|
||||
}
|
||||
|
||||
static void
|
||||
TestBinarySearchIf()
|
||||
{
|
||||
const int v1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
const size_t len = ArrayLength(v1);
|
||||
size_t m;
|
||||
|
||||
A( BinarySearchIf(v1, 0, len, RangeFinder( 2, 3), &m) && m == 2);
|
||||
A(!BinarySearchIf(v1, 0, len, RangeFinder(-5, -2), &m) && m == 0);
|
||||
A( BinarySearchIf(v1, 0, len, RangeFinder( 3, 5), &m) && m >= 3 && m < 5);
|
||||
A(!BinarySearchIf(v1, 0, len, RangeFinder(10, 12), &m) && m == 10);
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
TestBinarySearch();
|
||||
TestBinarySearchIf();
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user