Bug 998507 - add BinarySearch (r=sunfish)

--HG--
extra : rebase_source : 6ba04575a5dd8a886235e6799bc790c7a3afc64f
This commit is contained in:
Luke Wagner 2014-04-15 21:30:26 -05:00
parent f359659e38
commit 854107dda5
5 changed files with 155 additions and 20 deletions

View File

@ -6,6 +6,8 @@
#include "jit/AsmJSSignalHandlers.h"
#include "mozilla/BinarySearch.h"
#include "assembler/assembler/MacroAssembler.h"
#include "jit/AsmJSModule.h"
@ -207,35 +209,29 @@ SetXMMRegToNaN(bool isFloat32, T *xmm_reg)
}
}
struct GetHeapAccessOffset
{
const AsmJSModule &module;
explicit GetHeapAccessOffset(const AsmJSModule &module) : module(module) {}
uintptr_t operator[](size_t index) const {
return module.heapAccess(index).offset();
}
};
// Perform a binary search on the projected offsets of the known heap accesses
// in the module.
static const AsmJSHeapAccess *
LookupHeapAccess(const AsmJSModule &module, uint8_t *pc)
{
JS_ASSERT(module.containsPC(pc));
size_t targetOffset = pc - module.codeBase();
if (module.numHeapAccesses() == 0)
uintptr_t pcOff = pc - module.codeBase();
size_t match;
if (!BinarySearch(GetHeapAccessOffset(module), 0, module.numHeapAccesses(), pcOff, &match))
return nullptr;
size_t low = 0;
size_t high = module.numHeapAccesses() - 1;
while (high - low >= 2) {
size_t mid = low + (high - low) / 2;
uint32_t midOffset = module.heapAccess(mid).offset();
if (targetOffset == midOffset)
return &module.heapAccess(mid);
if (targetOffset < midOffset)
high = mid;
else
low = mid;
}
if (targetOffset == module.heapAccess(low).offset())
return &module.heapAccess(low);
if (targetOffset == module.heapAccess(high).offset())
return &module.heapAccess(high);
return nullptr;
return &module.heapAccess(match);
}
#endif

62
mfbt/BinarySearch.h Normal file
View File

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_BinarySearch_h
#define mozilla_BinarySearch_h
#include "mozilla/Assertions.h"
#include <stddef.h>
namespace mozilla {
/*
* The algorithm searches the given container 'c' over the sorted index range
* [begin, end) for an index 'i' where 'c[i] == target'. If such an index 'i' is
* found, BinarySearch returns 'true' and the index is returned via the outparam
* 'matchOrInsertionPoint'. If no index is found, BinarySearch returns 'false'
* and the outparam returns the first index in [begin, end] where 'target' can
* be inserted to maintain sorted order.
*
* Example:
*
* Vector<int> sortedInts = ...
*
* size_t match;
* if (BinarySearch(sortedInts, 0, sortedInts.length(), 13, &match))
* printf("found 13 at %lu\n", match);
*/
template <typename Container, typename T>
bool
BinarySearch(const Container &c, size_t begin, size_t end, T target, size_t *matchOrInsertionPoint)
{
MOZ_ASSERT(begin <= end);
size_t low = begin;
size_t high = end;
while (low != high) {
size_t middle = low + (high - low) / 2;
const T &middleValue = c[middle];
if (target == middleValue) {
*matchOrInsertionPoint = middle;
return true;
}
if (target < middleValue)
high = middle;
else
low = middle + 1;
}
*matchOrInsertionPoint = low;
return false;
}
} // namespace mozilla
#endif // mozilla_BinarySearch_h

View File

@ -16,6 +16,7 @@ EXPORTS.mozilla = [
'Assertions.h',
'Atomics.h',
'Attributes.h',
'BinarySearch.h',
'BloomFilter.h',
'Casting.h',
'ChaosMode.h',

View File

@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/Assertions.h"
#include "mozilla/BinarySearch.h"
#include "mozilla/Vector.h"
using mozilla::Vector;
using mozilla::BinarySearch;
struct Person
{
int age;
int id;
Person(int age, int id) : age(age), id(id) {}
};
struct GetAge
{
Vector<Person> &v;
GetAge(Vector<Person> &v) : v(v) {}
int operator[](size_t index) const { return v[index].age; }
};
int main()
{
size_t m;
Vector<int> v1;
v1.append(2);
v1.append(4);
v1.append(6);
v1.append(8);
MOZ_ASSERT(!BinarySearch(v1, 0, v1.length(), 1, &m) && m == 0);
MOZ_ASSERT( BinarySearch(v1, 0, v1.length(), 2, &m) && m == 0);
MOZ_ASSERT(!BinarySearch(v1, 0, v1.length(), 3, &m) && m == 1);
MOZ_ASSERT( BinarySearch(v1, 0, v1.length(), 4, &m) && m == 1);
MOZ_ASSERT(!BinarySearch(v1, 0, v1.length(), 5, &m) && m == 2);
MOZ_ASSERT( BinarySearch(v1, 0, v1.length(), 6, &m) && m == 2);
MOZ_ASSERT(!BinarySearch(v1, 0, v1.length(), 7, &m) && m == 3);
MOZ_ASSERT( BinarySearch(v1, 0, v1.length(), 8, &m) && m == 3);
MOZ_ASSERT(!BinarySearch(v1, 0, v1.length(), 9, &m) && m == 4);
MOZ_ASSERT(!BinarySearch(v1, 1, 3, 1, &m) && m == 1);
MOZ_ASSERT(!BinarySearch(v1, 1, 3, 2, &m) && m == 1);
MOZ_ASSERT(!BinarySearch(v1, 1, 3, 3, &m) && m == 1);
MOZ_ASSERT( BinarySearch(v1, 1, 3, 4, &m) && m == 1);
MOZ_ASSERT(!BinarySearch(v1, 1, 3, 5, &m) && m == 2);
MOZ_ASSERT( BinarySearch(v1, 1, 3, 6, &m) && m == 2);
MOZ_ASSERT(!BinarySearch(v1, 1, 3, 7, &m) && m == 3);
MOZ_ASSERT(!BinarySearch(v1, 1, 3, 8, &m) && m == 3);
MOZ_ASSERT(!BinarySearch(v1, 1, 3, 9, &m) && m == 3);
MOZ_ASSERT(!BinarySearch(v1, 0, 0, 0, &m) && m == 0);
MOZ_ASSERT(!BinarySearch(v1, 0, 0, 9, &m) && m == 0);
Vector<int> v2;
MOZ_ASSERT(!BinarySearch(v2, 0, 0, 0, &m) && m == 0);
MOZ_ASSERT(!BinarySearch(v2, 0, 0, 9, &m) && m == 0);
Vector<Person> v3;
v3.append(Person(2, 42));
v3.append(Person(4, 13));
v3.append(Person(6, 360));
MOZ_ASSERT(!BinarySearch(GetAge(v3), 0, v3.length(), 1, &m) && m == 0);
MOZ_ASSERT( BinarySearch(GetAge(v3), 0, v3.length(), 2, &m) && m == 0);
MOZ_ASSERT(!BinarySearch(GetAge(v3), 0, v3.length(), 3, &m) && m == 1);
MOZ_ASSERT( BinarySearch(GetAge(v3), 0, v3.length(), 4, &m) && m == 1);
MOZ_ASSERT(!BinarySearch(GetAge(v3), 0, v3.length(), 5, &m) && m == 2);
MOZ_ASSERT( BinarySearch(GetAge(v3), 0, v3.length(), 6, &m) && m == 2);
MOZ_ASSERT(!BinarySearch(GetAge(v3), 0, v3.length(), 7, &m) && m == 3);
}

View File

@ -6,6 +6,7 @@
CPP_UNIT_TESTS += [
'TestAtomics.cpp',
'TestBinarySearch.cpp',
'TestBloomFilter.cpp',
'TestCasting.cpp',
'TestCeilingFloor.cpp',