AK: Add lower_bound_index to binary search helpers
Add a helper for finding the first position in a sorted container where needle can be inserted while preserving sort order. This gives callers a lower-bound insertion point. Cover empty inputs, duplicate values, custom comparators, and constexpr use in TestBinarySearch.
This commit is contained in:
parent
2dab9f53d2
commit
1859ecbb24
2 changed files with 68 additions and 0 deletions
|
|
@ -25,6 +25,27 @@ struct DefaultComparator {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename Container, typename Needle, typename Comparator = DefaultComparator>
|
||||
[[nodiscard]] constexpr size_t lower_bound_index(
|
||||
Container&& haystack,
|
||||
Needle&& needle,
|
||||
Comparator comparator = Comparator {})
|
||||
{
|
||||
size_t low = 0;
|
||||
size_t high = haystack.size();
|
||||
|
||||
while (low < high) {
|
||||
size_t middle = low + (high - low) / 2;
|
||||
|
||||
if (comparator(haystack[middle], needle) < 0)
|
||||
low = middle + 1;
|
||||
else
|
||||
high = middle;
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
template<typename Container, typename Needle, typename Comparator = DefaultComparator>
|
||||
constexpr auto binary_search(
|
||||
Container&& haystack,
|
||||
|
|
@ -69,4 +90,5 @@ constexpr auto binary_search(
|
|||
|
||||
#if USING_AK_GLOBALLY
|
||||
using AK::binary_search;
|
||||
using AK::lower_bound_index;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -108,6 +108,52 @@ TEST_CASE(constexpr_array_search)
|
|||
static_assert(binary_search(array, 3) == nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE(lower_bound_index)
|
||||
{
|
||||
Array<int, 7> array { 1, 3, 3, 3, 7, 9, 11 };
|
||||
|
||||
EXPECT_EQ(lower_bound_index(array, 0), 0u);
|
||||
EXPECT_EQ(lower_bound_index(array, 1), 0u);
|
||||
EXPECT_EQ(lower_bound_index(array, 2), 1u);
|
||||
EXPECT_EQ(lower_bound_index(array, 3), 1u);
|
||||
EXPECT_EQ(lower_bound_index(array, 4), 4u);
|
||||
EXPECT_EQ(lower_bound_index(array, 12), 7u);
|
||||
}
|
||||
|
||||
TEST_CASE(lower_bound_index_empty)
|
||||
{
|
||||
Vector<int> vector;
|
||||
|
||||
EXPECT_EQ(lower_bound_index(vector, 1), 0u);
|
||||
}
|
||||
|
||||
TEST_CASE(lower_bound_index_custom_comparator)
|
||||
{
|
||||
Vector<ByteString> strings;
|
||||
strings.append("bat");
|
||||
strings.append("cat");
|
||||
strings.append("dog");
|
||||
|
||||
auto string_compare = [](ByteString const& a, ByteString const& b) -> int {
|
||||
return strcmp(a.characters(), b.characters());
|
||||
};
|
||||
|
||||
EXPECT_EQ(lower_bound_index(strings, ByteString("ant"), string_compare), 0u);
|
||||
EXPECT_EQ(lower_bound_index(strings, ByteString("cat"), string_compare), 1u);
|
||||
EXPECT_EQ(lower_bound_index(strings, ByteString("cow"), string_compare), 2u);
|
||||
EXPECT_EQ(lower_bound_index(strings, ByteString("elk"), string_compare), 3u);
|
||||
}
|
||||
|
||||
TEST_CASE(constexpr_lower_bound_index)
|
||||
{
|
||||
constexpr Array<int, 3> array = { 1, 17, 42 };
|
||||
|
||||
static_assert(lower_bound_index(array, 0) == 0);
|
||||
static_assert(lower_bound_index(array, 17) == 1);
|
||||
static_assert(lower_bound_index(array, 18) == 2);
|
||||
static_assert(lower_bound_index(array, 43) == 3);
|
||||
}
|
||||
|
||||
TEST_CASE(unsigned_to_signed_regression)
|
||||
{
|
||||
Array<u32, 5> const input { 0, 1, 2, 3, 4 };
|
||||
|
|
|
|||
Loading…
Reference in a new issue