Add and use LowerBound methods in IdList. NFC.

Clearer and less error-prone to use standard-supplied algorithms.
This commit is contained in:
Ryan Pavlik 2019-05-22 16:02:17 -05:00 committed by whitequark
parent 0c941aedb1
commit 3340392bf0

View File

@ -315,6 +315,17 @@ public:
} }
}; };
// Comparison functor used by IdList and related classes
template <class T, class H>
struct CompareId {
bool operator()(T const& lhs, T const& rhs) const {
return lhs.h.v < rhs.h.v;
}
bool operator()(T const& lhs, H rhs) const {
return lhs.h.v < rhs.v;
}
};
// A list, where each element has an integer identifier. The list is kept // A list, where each element has an integer identifier. The list is kept
// sorted by that identifier, and items can be looked up in log n time by // sorted by that identifier, and items can be looked up in log n time by
// id. // id.
@ -325,6 +336,8 @@ public:
int n; int n;
int elemsAllocated; int elemsAllocated;
using Compare = CompareId<T, H>;
bool IsEmpty() const { bool IsEmpty() const {
return n == 0; return n == 0;
} }
@ -344,6 +357,31 @@ public:
return t->h; return t->h;
} }
T * LowerBound(T const& t) {
if(IsEmpty()) {
return nullptr;
}
auto it = std::lower_bound(begin(), end(), t, Compare());
return it;
}
T * LowerBound(H const& h) {
if(IsEmpty()) {
return nullptr;
}
auto it = std::lower_bound(begin(), end(), h, Compare());
return it;
}
int LowerBoundIndex(T const& t) {
if(IsEmpty()) {
return 0;
}
auto it = LowerBound(t);
auto idx = std::distance(begin(), it);
auto i = static_cast<int>(idx);
return i;
}
void ReserveMore(int howMuch) { void ReserveMore(int howMuch) {
if(n + howMuch > elemsAllocated) { if(n + howMuch > elemsAllocated) {
elemsAllocated = n + howMuch; elemsAllocated = n + howMuch;
@ -361,21 +399,12 @@ public:
if(n >= elemsAllocated) { if(n >= elemsAllocated) {
ReserveMore((elemsAllocated + 32)*2 - n); ReserveMore((elemsAllocated + 32)*2 - n);
} }
auto newIndex = LowerBoundIndex(*t);
int first = 0, last = n; if (newIndex < n) {
// We know that we must insert within the closed interval [first,last] H hm = elem[newIndex].h;
while(first != last) {
int mid = (first + last)/2;
H hm = elem[mid].h;
ssassert(hm.v != t->h.v, "Handle isn't unique"); ssassert(hm.v != t->h.v, "Handle isn't unique");
if(hm.v > t->h.v) {
last = mid;
} else if(hm.v < t->h.v) {
first = mid + 1;
}
} }
int i = static_cast<int>(newIndex);
int i = first;
new(&elem[n]) T(); new(&elem[n]) T();
std::move_backward(elem + i, elem + n, elem + n + 1); std::move_backward(elem + i, elem + n, elem + n + 1);
elem[i] = *t; elem[i] = *t;
@ -392,17 +421,10 @@ public:
if(IsEmpty()) { if(IsEmpty()) {
return -1; return -1;
} }
int first = 0, last = n-1; auto it = LowerBound(h);
while(first <= last) { auto idx = std::distance(begin(), it);
int mid = (first + last)/2; if (idx < n) {
H hm = elem[mid].h; return idx;
if(hm.v > h.v) {
last = mid-1; // and first stays the same
} else if(hm.v < h.v) {
first = mid+1; // and last stays the same
} else {
return mid;
}
} }
return -1; return -1;
} }
@ -411,19 +433,14 @@ public:
if(IsEmpty()) { if(IsEmpty()) {
return nullptr; return nullptr;
} }
int first = 0, last = n-1; auto it = LowerBound(h);
while(first <= last) { if (it == nullptr || it == end()) {
int mid = (first + last)/2; return nullptr;
H hm = elem[mid].h;
if(hm.v > h.v) {
last = mid-1; // and first stays the same
} else if(hm.v < h.v) {
first = mid+1; // and last stays the same
} else {
return &(elem[mid]);
}
} }
return NULL; if (it->h.v == h.v) {
return it;
}
return nullptr;
} }
T *First() { T *First() {