diff --git a/AK/BinarySearch.h b/AK/BinarySearch.h index 1fafb777fe..14e630089f 100644 --- a/AK/BinarySearch.h +++ b/AK/BinarySearch.h @@ -32,14 +32,16 @@ namespace AK { -template -constexpr int integral_compare(const typename RemoveConst::Type& a, const typename RemoveConst::Type& b) -{ - return a - b; -} +struct IntegralComparator { + constexpr auto operator()(auto& lhs, auto& rhs) { return lhs - rhs; } +}; -template -constexpr T* binary_search(Span haystack, const typename RemoveConst::Type& needle, Compare compare = integral_compare, size_t* nearby_index = nullptr) +template +constexpr auto binary_search( + Container&& haystack, + Needle&& needle, + size_t* nearby_index = nullptr, + Comparator comparator = Comparator {}) -> decltype(&haystack[0]) { if (haystack.size() == 0) { if (nearby_index) @@ -51,7 +53,7 @@ constexpr T* binary_search(Span haystack, const typename RemoveConst::Type size_t high = haystack.size() - 1; while (low <= high) { size_t middle = low + ((high - low) / 2); - int comparison = compare(needle, haystack[middle]); + auto comparison = comparator(needle, haystack[middle]); if (comparison < 0) if (middle != 0) high = middle - 1; diff --git a/AK/Tests/TestBinarySearch.cpp b/AK/Tests/TestBinarySearch.cpp index f4e0e2e3fd..d39d536b53 100644 --- a/AK/Tests/TestBinarySearch.cpp +++ b/AK/Tests/TestBinarySearch.cpp @@ -38,24 +38,32 @@ TEST_CASE(vector_ints) ints.append(2); ints.append(3); - auto test1 = *binary_search(ints.span(), 1, AK::integral_compare); - auto test2 = *binary_search(ints.span(), 2, AK::integral_compare); - auto test3 = *binary_search(ints.span(), 3, AK::integral_compare); + auto test1 = *binary_search(ints, 1); + auto test2 = *binary_search(ints, 2); + auto test3 = *binary_search(ints, 3); EXPECT_EQ(test1, 1); EXPECT_EQ(test2, 2); EXPECT_EQ(test3, 3); } +TEST_CASE(span_rvalue_reference) +{ + Array array { 1, 2, 3 }; + + size_t nearby_index = 0; + auto* pointer = binary_search(array.span(), 2, &nearby_index); + + EXPECT_EQ(nearby_index, 1u); + EXPECT_EQ(pointer, &array[1]); +} + TEST_CASE(array_doubles) { - double doubles[] = { 1.1, 9.9, 33.33 }; + Array array { 1.1, 9.9, 33.33 }; - auto test1 = *binary_search(Span { doubles, 3 }, 1.1, AK::integral_compare); - auto test2 = *binary_search(Span { doubles, 3 }, 9.9, AK::integral_compare); - auto test3 = *binary_search(Span { doubles, 3 }, 33.33, AK::integral_compare); - EXPECT_EQ(test1, 1.1); - EXPECT_EQ(test2, 9.9); - EXPECT_EQ(test3, 33.33); + EXPECT_EQ(binary_search(array, 1.1), &array[0]); + EXPECT_EQ(binary_search(array, 33.33), &array[2]); + EXPECT_EQ(binary_search(array, 9.9), &array[1]); } TEST_CASE(vector_strings) @@ -68,9 +76,9 @@ TEST_CASE(vector_strings) auto string_compare = [](const String& a, const String& b) -> int { return strcmp(a.characters(), b.characters()); }; - auto test1 = *binary_search(strings.span(), String("bat"), string_compare); - auto test2 = *binary_search(strings.span(), String("cat"), string_compare); - auto test3 = *binary_search(strings.span(), String("dog"), string_compare); + auto test1 = *binary_search(strings, String("bat"), nullptr, string_compare); + auto test2 = *binary_search(strings, String("cat"), nullptr, string_compare); + auto test3 = *binary_search(strings, String("dog"), nullptr, string_compare); EXPECT_EQ(test1, String("bat")); EXPECT_EQ(test2, String("cat")); EXPECT_EQ(test3, String("dog")); @@ -81,7 +89,7 @@ TEST_CASE(single_element) Vector ints; ints.append(1); - auto test1 = *binary_search(ints.span(), 1, AK::integral_compare); + auto test1 = *binary_search(ints, 1); EXPECT_EQ(test1, 1); } @@ -92,9 +100,9 @@ TEST_CASE(not_found) ints.append(2); ints.append(3); - auto test1 = binary_search(ints.span(), -1, AK::integral_compare); - auto test2 = binary_search(ints.span(), 0, AK::integral_compare); - auto test3 = binary_search(ints.span(), 4, AK::integral_compare); + auto test1 = binary_search(ints, -1); + auto test2 = binary_search(ints, 0); + auto test3 = binary_search(ints, 4); EXPECT_EQ(test1, nullptr); EXPECT_EQ(test2, nullptr); EXPECT_EQ(test3, nullptr); @@ -104,7 +112,7 @@ TEST_CASE(no_elements) { Vector ints; - auto test1 = binary_search(ints.span(), 1, AK::integral_compare); + auto test1 = binary_search(ints, 1); EXPECT_EQ(test1, nullptr); } @@ -112,15 +120,9 @@ TEST_CASE(constexpr_array_search) { constexpr Array array = { 1, 17, 42 }; - constexpr auto test1 = *binary_search(array.span(), 1, AK::integral_compare); - constexpr auto test2 = *binary_search(array.span(), 17, AK::integral_compare); - constexpr auto test3 = *binary_search(array.span(), 42, AK::integral_compare); - constexpr auto test4 = binary_search(array.span(), 99, AK::integral_compare); - - static_assert(test1 == 1, "Binary search should find value at compile-time."); - static_assert(test2 == 17, "Binary search should find value at compile-time."); - static_assert(test3 == 42, "Binary search should find value at compile-time."); - static_assert(test4 == nullptr, "Binary search should return nullptr for missing value at compile-time."); + static_assert(binary_search(array, 42) == &array[2]); + static_assert(binary_search(array, 17) == &array[1]); + static_assert(binary_search(array, 3) == nullptr); } TEST_MAIN(BinarySearch) diff --git a/Kernel/VM/RangeAllocator.cpp b/Kernel/VM/RangeAllocator.cpp index 932a03fc88..49160dda35 100644 --- a/Kernel/VM/RangeAllocator.cpp +++ b/Kernel/VM/RangeAllocator.cpp @@ -181,10 +181,10 @@ void RangeAllocator::deallocate(Range range) size_t nearby_index = 0; auto* existing_range = binary_search( - m_available_ranges.span(), range, [](auto& a, auto& b) { - return a.base().get() - b.end().get(); - }, - &nearby_index); + m_available_ranges.span(), + range, + &nearby_index, + [](auto& a, auto& b) { return a.base().get() - b.end().get(); }); size_t inserted_index = 0; if (existing_range) { diff --git a/Libraries/LibCompress/Deflate.cpp b/Libraries/LibCompress/Deflate.cpp index 3f21fa0c9d..840cb6d3b7 100644 --- a/Libraries/LibCompress/Deflate.cpp +++ b/Libraries/LibCompress/Deflate.cpp @@ -112,7 +112,7 @@ u32 CanonicalCode::read_symbol(InputBitStream& stream) const // FIXME: This seems really inefficient, this could be an index into an array instead. size_t index; - if (AK::binary_search(m_symbol_codes.span(), code_bits, AK::integral_compare, &index)) + if (AK::binary_search(m_symbol_codes.span(), code_bits, &index)) return m_symbol_values[index]; } } diff --git a/Libraries/LibLine/XtermSuggestionDisplay.cpp b/Libraries/LibLine/XtermSuggestionDisplay.cpp index 18eb0483f0..f69e028f3f 100644 --- a/Libraries/LibLine/XtermSuggestionDisplay.cpp +++ b/Libraries/LibLine/XtermSuggestionDisplay.cpp @@ -187,12 +187,14 @@ size_t XtermSuggestionDisplay::fit_to_page_boundary(size_t selection_index) size_t index = 0; auto* match = binary_search( - m_pages.span(), { selection_index, selection_index }, [](auto& a, auto& b) -> int { + m_pages.span(), + PageRange { selection_index, selection_index }, + &index, + [](auto& a, auto& b) -> int { if (a.start >= b.start && a.start < b.end) return 0; return a.start - b.start; - }, - &index); + }); if (!match) return m_pages.size() - 1; diff --git a/Shell/Shell.cpp b/Shell/Shell.cpp index 06279fb032..6ef5a6efa7 100644 --- a/Shell/Shell.cpp +++ b/Shell/Shell.cpp @@ -543,9 +543,11 @@ bool Shell::is_runnable(const StringView& name) if (access(name.to_string().characters(), X_OK) == 0) return true; - return !!binary_search(cached_path.span(), name.to_string(), [](const String& name, const String& program) -> int { - return strcmp(name.characters(), program.characters()); - }); + return binary_search( + cached_path.span(), + name.to_string(), + nullptr, + [](auto& name, auto& program) { return strcmp(name.characters(), program.characters()); }); } int Shell::run_command(const StringView& cmd) @@ -1154,10 +1156,10 @@ void Shell::add_entry_to_cache(const String& entry) { size_t index = 0; auto match = binary_search( - cached_path.span(), entry, [](const String& name, const String& program) -> int { - return strcmp(name.characters(), program.characters()); - }, - &index); + cached_path.span(), + entry, + &index, + [](auto& name, auto& program) { return strcmp(name.characters(), program.characters()); }); if (match) return; @@ -1263,9 +1265,11 @@ Vector Shell::complete_path(const String& base, cons Vector Shell::complete_program_name(const String& name, size_t offset) { - auto match = binary_search(cached_path.span(), name, [](const String& name, const String& program) -> int { - return strncmp(name.characters(), program.characters(), name.length()); - }); + auto match = binary_search( + cached_path.span(), + name, + nullptr, + [](auto& name, auto& program) { return strncmp(name.characters(), program.characters(), name.length()); }); if (!match) return complete_path("", name, offset);