AK: Deal with unsigned integers in binary search.

This commit is contained in:
asynts 2021-01-01 21:32:59 +01:00 committed by Andreas Kling
parent febc8a5ac7
commit e77031ce67
3 changed files with 32 additions and 6 deletions

View file

@ -32,11 +32,21 @@
namespace AK {
struct IntegralComparator {
constexpr auto operator()(auto& lhs, auto& rhs) { return lhs - rhs; }
struct DefaultComparator {
template<typename T, typename S>
constexpr int operator()(T& lhs, S& rhs)
{
if (lhs > rhs)
return 1;
if (lhs < rhs)
return -1;
return 0;
}
};
template<typename Container, typename Needle, typename Comparator = IntegralComparator>
template<typename Container, typename Needle, typename Comparator = DefaultComparator>
constexpr auto binary_search(
Container&& haystack,
Needle&& needle,
@ -52,8 +62,10 @@ constexpr auto binary_search(
size_t low = 0;
size_t high = haystack.size() - 1;
while (low <= high) {
size_t middle = low + ((high - low) / 2);
auto comparison = comparator(needle, haystack[middle]);
size_t middle = low + (high - low) / 2;
int comparison = comparator(needle, haystack[middle]);
if (comparison < 0)
if (middle != 0)
high = middle - 1;

View file

@ -125,4 +125,16 @@ TEST_CASE(constexpr_array_search)
static_assert(binary_search(array, 3) == nullptr);
}
TEST_CASE(unsigned_to_signed_regression)
{
const Array<u32, 5> input { 0, 1, 2, 3, 4 };
// The algorithm computes 1 - input[2] = -1, and if this is (incorrectly) cast
// to an unsigned then it will look in the wrong direction and miss the 1.
size_t nearby_index = 1;
EXPECT_EQ(binary_search(input, 1u, &nearby_index), &input[1]);
EXPECT_EQ(nearby_index, 1u);
}
TEST_MAIN(BinarySearch)

View file

@ -109,8 +109,10 @@ u32 CanonicalCode::read_symbol(InputBitStream& stream) const
for (;;) {
code_bits = code_bits << 1 | stream.read_bits(1);
ASSERT(code_bits < (1 << 16));
// FIXME: This seems really inefficient, this could be an index into an array instead.
// FIXME: This is very inefficent and could greatly be improved by implementing this
// algorithm: https://www.hanshq.net/zip.html#huffdec
size_t index;
if (AK::binary_search(m_symbol_codes.span(), code_bits, &index))
return m_symbol_values[index];