mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-11 05:25:32 +03:00
Vector: Implement find
, find_if
, find_first_matching
in terms of AK::find*
Problem: - The implementation of `find` is coupled to the implementation of `Vector`. - `Vector::find` takes the predicate by value which might be expensive. Solution: - Decouple the implementation of `find` from `Vector` by using a generic `find` algorithm. - Change the name of `find` with a predicate to `find_if` so that a binding reference can be used and the predicate can be forwarded to avoid copies. - Change all the `find(pred)` call sites to use `find_if`.
This commit is contained in:
parent
4333a9a8d6
commit
f99d1d3bd7
Notes:
sideshowbarker
2024-07-18 23:56:20 +09:00
Author: https://github.com/ldm5180 Commit: https://github.com/SerenityOS/serenity/commit/f99d1d3bd7d Pull-request: https://github.com/SerenityOS/serenity/pull/4894 Reviewed-by: https://github.com/awesomekling Reviewed-by: https://github.com/linusg
@ -394,4 +394,30 @@ TEST_CASE(should_compare_vectors_of_different_sizes)
|
|||||||
EXPECT(a != b);
|
EXPECT(a != b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE(should_find_value)
|
||||||
|
{
|
||||||
|
AK::Vector<int> v { 1, 2, 3, 4, 0, 6, 7, 8, 0, 0 };
|
||||||
|
|
||||||
|
const auto expected = v.begin() + 4;
|
||||||
|
|
||||||
|
EXPECT_EQ(expected, v.find(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE(should_find_predicate)
|
||||||
|
{
|
||||||
|
AK::Vector<int> v { 1, 2, 3, 4, 0, 6, 7, 8, 0, 0 };
|
||||||
|
|
||||||
|
const auto expected = v.begin() + 4;
|
||||||
|
|
||||||
|
EXPECT_EQ(expected, v.find_if([](const auto v) { return v == 0; }));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE(should_find_index)
|
||||||
|
{
|
||||||
|
AK::Vector<int> v { 1, 2, 3, 4, 0, 6, 7, 8, 0, 0 };
|
||||||
|
|
||||||
|
EXPECT_EQ(4u, v.find_first_index(0).value());
|
||||||
|
EXPECT(!v.find_first_index(42).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_MAIN(Vector)
|
TEST_MAIN(Vector)
|
||||||
|
31
AK/Vector.h
31
AK/Vector.h
@ -27,6 +27,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Assertions.h>
|
#include <AK/Assertions.h>
|
||||||
|
#include <AK/Find.h>
|
||||||
#include <AK/Forward.h>
|
#include <AK/Forward.h>
|
||||||
#include <AK/Iterator.h>
|
#include <AK/Iterator.h>
|
||||||
#include <AK/Optional.h>
|
#include <AK/Optional.h>
|
||||||
@ -538,41 +539,33 @@ public:
|
|||||||
ConstIterator end() const { return ConstIterator::end(*this); }
|
ConstIterator end() const { return ConstIterator::end(*this); }
|
||||||
Iterator end() { return Iterator::end(*this); }
|
Iterator end() { return Iterator::end(*this); }
|
||||||
|
|
||||||
template<typename Finder>
|
template<typename TUnaryPredicate>
|
||||||
ConstIterator find(Finder finder) const
|
ConstIterator find_if(TUnaryPredicate&& finder) const
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_size; ++i) {
|
return AK::find_if(begin(), end(), forward<TUnaryPredicate>(finder));
|
||||||
if (finder(at(i)))
|
|
||||||
return ConstIterator(*this, i);
|
|
||||||
}
|
|
||||||
return end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Finder>
|
template<typename TUnaryPredicate>
|
||||||
Iterator find(Finder finder)
|
Iterator find_if(TUnaryPredicate&& finder)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_size; ++i) {
|
return AK::find_if(begin(), end(), forward<TUnaryPredicate>(finder));
|
||||||
if (finder(at(i)))
|
|
||||||
return Iterator { *this, i };
|
|
||||||
}
|
|
||||||
return end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstIterator find(const T& value) const
|
ConstIterator find(const T& value) const
|
||||||
{
|
{
|
||||||
return find([&](auto& other) { return Traits<T>::equals(value, other); });
|
return AK::find(begin(), end(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator find(const T& value)
|
Iterator find(const T& value)
|
||||||
{
|
{
|
||||||
return find([&](auto& other) { return Traits<T>::equals(value, other); });
|
return AK::find(begin(), end(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<size_t> find_first_index(const T& value)
|
Optional<size_t> find_first_index(const T& value)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_size; ++i) {
|
if (const auto index = AK::find_index(begin(), end(), value);
|
||||||
if (Traits<T>::equals(value, at(i)))
|
index < size()) {
|
||||||
return i;
|
return index;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ void Cell::reference_from(Cell* other)
|
|||||||
if (!other || other == this)
|
if (!other || other == this)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!m_referencing_cells.find([other](auto& ptr) { return ptr.ptr() == other; }).is_end())
|
if (!m_referencing_cells.find_if([other](const auto& ptr) { return ptr.ptr() == other; }).is_end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_referencing_cells.append(other->make_weak_ptr());
|
m_referencing_cells.append(other->make_weak_ptr());
|
||||||
|
@ -244,7 +244,7 @@ XSV::Field XSV::read_one_unquoted_field()
|
|||||||
StringView XSV::Row::operator[](StringView name) const
|
StringView XSV::Row::operator[](StringView name) const
|
||||||
{
|
{
|
||||||
ASSERT(!m_xsv.m_names.is_empty());
|
ASSERT(!m_xsv.m_names.is_empty());
|
||||||
auto it = m_xsv.m_names.find([&](auto&& entry) { return name == entry; });
|
auto it = m_xsv.m_names.find_if([&](const auto& entry) { return name == entry; });
|
||||||
ASSERT(!it.is_end());
|
ASSERT(!it.is_end());
|
||||||
|
|
||||||
return (*this)[it.index()];
|
return (*this)[it.index()];
|
||||||
|
@ -182,7 +182,7 @@ void DevicesModel::update()
|
|||||||
unsigned _major = major(statbuf.st_rdev);
|
unsigned _major = major(statbuf.st_rdev);
|
||||||
unsigned _minor = minor(statbuf.st_rdev);
|
unsigned _minor = minor(statbuf.st_rdev);
|
||||||
|
|
||||||
auto it = m_devices.find([_major, _minor](auto& device_info) {
|
auto it = m_devices.find_if([_major, _minor](const auto& device_info) {
|
||||||
return device_info.major == _major && device_info.minor == _minor;
|
return device_info.major == _major && device_info.minor == _minor;
|
||||||
});
|
});
|
||||||
if (it != m_devices.end()) {
|
if (it != m_devices.end()) {
|
||||||
|
@ -80,7 +80,7 @@ static String variable_value_as_string(const Debug::DebugInfo::VariableInfo& var
|
|||||||
if (variable.is_enum_type()) {
|
if (variable.is_enum_type()) {
|
||||||
auto value = Debugger::the().session()->peek((u32*)variable_address);
|
auto value = Debugger::the().session()->peek((u32*)variable_address);
|
||||||
ASSERT(value.has_value());
|
ASSERT(value.has_value());
|
||||||
auto it = variable.type->members.find([enumerator_value = value.value()](auto& enumerator) {
|
auto it = variable.type->members.find_if([&enumerator_value = value.value()](const auto& enumerator) {
|
||||||
return enumerator->constant_data.as_u32 == enumerator_value;
|
return enumerator->constant_data.as_u32 == enumerator_value;
|
||||||
});
|
});
|
||||||
ASSERT(!it.is_end());
|
ASSERT(!it.is_end());
|
||||||
@ -116,7 +116,7 @@ static Optional<u32> string_to_variable_value(const StringView& string_value, co
|
|||||||
if (string_value.starts_with(prefix_string))
|
if (string_value.starts_with(prefix_string))
|
||||||
string_to_use = string_value.substring_view(prefix_string.length(), string_value.length() - prefix_string.length());
|
string_to_use = string_value.substring_view(prefix_string.length(), string_value.length() - prefix_string.length());
|
||||||
|
|
||||||
auto it = variable.type->members.find([string_to_use](auto& enumerator) {
|
auto it = variable.type->members.find_if([string_to_use](const auto& enumerator) {
|
||||||
return enumerator->name == string_to_use;
|
return enumerator->name == string_to_use;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ bool ArgsParser::parse(int argc, char** argv, bool exit_on_failure)
|
|||||||
index_of_found_long_option = -1;
|
index_of_found_long_option = -1;
|
||||||
} else {
|
} else {
|
||||||
// It was a short option, look it up.
|
// It was a short option, look it up.
|
||||||
auto it = m_options.find([c](auto& opt) { return c == opt.short_name; });
|
auto it = m_options.find_if([c](auto& opt) { return c == opt.short_name; });
|
||||||
ASSERT(!it.is_end());
|
ASSERT(!it.is_end());
|
||||||
found_option = &*it;
|
found_option = &*it;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ String Text::render_to_html() const
|
|||||||
{ "b", &Style::strong },
|
{ "b", &Style::strong },
|
||||||
{ "code", &Style::code }
|
{ "code", &Style::code }
|
||||||
};
|
};
|
||||||
auto it = open_tags.find([&](const String& open_tag) {
|
auto it = open_tags.find_if([&](const String& open_tag) {
|
||||||
if (open_tag == "a" && current_style.href != span.style.href)
|
if (open_tag == "a" && current_style.href != span.style.href)
|
||||||
return true;
|
return true;
|
||||||
if (open_tag == "img" && current_style.img != span.style.img)
|
if (open_tag == "img" && current_style.img != span.style.img)
|
||||||
|
@ -398,7 +398,7 @@ ssize_t TLSv12::handle_payload(ReadonlyBytes vbuffer)
|
|||||||
}
|
}
|
||||||
payload_res = handle_certificate(buffer.slice(1, payload_size));
|
payload_res = handle_certificate(buffer.slice(1, payload_size));
|
||||||
if (m_context.certificates.size()) {
|
if (m_context.certificates.size()) {
|
||||||
auto it = m_context.certificates.find([&](auto& cert) { return cert.is_valid(); });
|
auto it = m_context.certificates.find_if([](const auto& cert) { return cert.is_valid(); });
|
||||||
|
|
||||||
if (it.is_end()) {
|
if (it.is_end()) {
|
||||||
// no valid certificates
|
// no valid certificates
|
||||||
|
@ -162,7 +162,7 @@ void MenuManager::event(Core::Event& event)
|
|||||||
if (event.type() == Event::KeyDown) {
|
if (event.type() == Event::KeyDown) {
|
||||||
|
|
||||||
if (key_event.key() == Key_Left) {
|
if (key_event.key() == Key_Left) {
|
||||||
auto it = m_open_menu_stack.find([&](auto& other) { return m_current_menu == other.ptr(); });
|
auto it = m_open_menu_stack.find_if([&](const auto& other) { return m_current_menu == other.ptr(); });
|
||||||
ASSERT(!it.is_end());
|
ASSERT(!it.is_end());
|
||||||
|
|
||||||
// Going "back" a menu should be the previous menu in the stack
|
// Going "back" a menu should be the previous menu in the stack
|
||||||
@ -390,7 +390,7 @@ void MenuManager::open_menu(Menu& menu, bool as_current_menu)
|
|||||||
menu.menu_window()->set_visible(true);
|
menu.menu_window()->set_visible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_open_menu_stack.find([&menu](auto& other) { return &menu == other.ptr(); }).is_end())
|
if (m_open_menu_stack.find_if([&menu](auto& other) { return &menu == other.ptr(); }).is_end())
|
||||||
m_open_menu_stack.append(menu);
|
m_open_menu_stack.append(menu);
|
||||||
|
|
||||||
if (as_current_menu || !current_menu()) {
|
if (as_current_menu || !current_menu()) {
|
||||||
|
Loading…
Reference in New Issue
Block a user