diff --git a/AK/Forward.h b/AK/Forward.h index dd1ef71bd6..163e144a96 100644 --- a/AK/Forward.h +++ b/AK/Forward.h @@ -28,6 +28,7 @@ class Utf16StringData; enum class TrailingCodePointTransformation : u8; +class AtomicRefCountedBase; class BigEndianInputBitStream; class BigEndianOutputBitStream; class Bitmap; @@ -86,6 +87,9 @@ using Bytes = Span; template class Atomic; +template +class AtomicRefCounted; + template class SinglyLinkedList; @@ -176,6 +180,8 @@ class [[nodiscard]] ErrorOr; #if USING_AK_GLOBALLY using AK::Array; using AK::Atomic; +using AK::AtomicRefCounted; +using AK::AtomicRefCountedBase; using AK::Badge; using AK::BigEndianInputBitStream; using AK::BigEndianOutputBitStream; diff --git a/AK/WeakPtr.h b/AK/WeakPtr.h index c074ed140d..3db75ac6f7 100644 --- a/AK/WeakPtr.h +++ b/AK/WeakPtr.h @@ -6,6 +6,7 @@ #pragma once +#include #include namespace AK { @@ -173,6 +174,16 @@ private: RefPtr m_link; }; +template +auto weak_callback(T& obj, Callback&& callback) +requires(!IsBaseOf) +{ + return [weak = obj.template make_weak_ptr(), cb = forward(callback)](auto&&... args) { + if (weak) + cb(*weak, forward(args)...); + }; +} + template struct Formatter> : Formatter { ErrorOr format(FormatBuilder& builder, WeakPtr const& value) @@ -193,5 +204,6 @@ struct Traits> : public DefaultTraits> { } #if USING_AK_GLOBALLY +using AK::weak_callback; using AK::WeakPtr; #endif diff --git a/Libraries/LibDevTools/Actors/FrameActor.cpp b/Libraries/LibDevTools/Actors/FrameActor.cpp index 4b2e3180a4..aee33fff1e 100644 --- a/Libraries/LibDevTools/Actors/FrameActor.cpp +++ b/Libraries/LibDevTools/Actors/FrameActor.cpp @@ -45,10 +45,9 @@ FrameActor::FrameActor(DevToolsServer& devtools, String name, WeakPtr devtools.delegate().listen_for_console_messages( tab->description(), - [weak_self = make_weak_ptr()](WebView::ConsoleOutput console_output) { - if (auto self = weak_self.strong_ref()) - self->on_console_message(move(console_output)); - }); + weak_callback(*this, [](auto& self, WebView::ConsoleOutput console_output) { + self.on_console_message(move(console_output)); + })); // FIXME: We should adopt WebContent to inform us when style sheets are available or removed. devtools.delegate().retrieve_style_sheets(tab->description(), @@ -58,33 +57,27 @@ FrameActor::FrameActor(DevToolsServer& devtools, String name, WeakPtr devtools.delegate().listen_for_network_events( tab->description(), - [weak_self = make_weak_ptr()](DevToolsDelegate::NetworkRequestData data) { - if (auto self = weak_self.strong_ref()) - self->on_network_request_started(move(data)); - }, - [weak_self = make_weak_ptr()](DevToolsDelegate::NetworkResponseData data) { - if (auto self = weak_self.strong_ref()) - self->on_network_response_headers_received(move(data)); - }, - [weak_self = make_weak_ptr()](u64 request_id, ByteBuffer data) { - if (auto self = weak_self.strong_ref()) - self->on_network_response_body_received(request_id, move(data)); - }, - [weak_self = make_weak_ptr()](DevToolsDelegate::NetworkRequestCompleteData data) { - if (auto self = weak_self.strong_ref()) - self->on_network_request_finished(move(data)); - }); + weak_callback(*this, [](auto& self, DevToolsDelegate::NetworkRequestData data) { + self.on_network_request_started(move(data)); + }), + weak_callback(*this, [](auto& self, DevToolsDelegate::NetworkResponseData data) { + self.on_network_response_headers_received(move(data)); + }), + weak_callback(*this, [](auto& self, u64 request_id, ByteBuffer data) { + self.on_network_response_body_received(request_id, move(data)); + }), + weak_callback(*this, [](auto& self, DevToolsDelegate::NetworkRequestCompleteData data) { + self.on_network_request_finished(move(data)); + })); devtools.delegate().listen_for_navigation_events( tab->description(), - [weak_self = make_weak_ptr()](String url) { - if (auto self = weak_self.strong_ref()) - self->on_navigation_started(move(url)); - }, - [weak_self = make_weak_ptr()](String url, String title) { - if (auto self = weak_self.strong_ref()) - self->on_navigation_finished(move(url), move(title)); - }); + weak_callback(*this, [](auto& self, String url) { + self.on_navigation_started(move(url)); + }), + weak_callback(*this, [](auto& self, String url, String title) { + self.on_navigation_finished(move(url), move(title)); + })); } } diff --git a/Libraries/LibDevTools/Actors/PageStyleActor.cpp b/Libraries/LibDevTools/Actors/PageStyleActor.cpp index 5f03d213d6..60c1f2cb34 100644 --- a/Libraries/LibDevTools/Actors/PageStyleActor.cpp +++ b/Libraries/LibDevTools/Actors/PageStyleActor.cpp @@ -122,10 +122,9 @@ PageStyleActor::PageStyleActor(DevToolsServer& devtools, String name, WeakPtrdescription(), - [weak_self = make_weak_ptr()](WebView::DOMNodeProperties const& properties) { - if (auto self = weak_self.strong_ref()) - self->received_dom_node_properties(properties); - }); + weak_callback(*this, [](auto& self, WebView::DOMNodeProperties const& properties) { + self.received_dom_node_properties(properties); + })); } } diff --git a/Libraries/LibDevTools/Actors/StyleSheetsActor.cpp b/Libraries/LibDevTools/Actors/StyleSheetsActor.cpp index db1d5d62ac..ca0f305e1c 100644 --- a/Libraries/LibDevTools/Actors/StyleSheetsActor.cpp +++ b/Libraries/LibDevTools/Actors/StyleSheetsActor.cpp @@ -25,10 +25,9 @@ StyleSheetsActor::StyleSheetsActor(DevToolsServer& devtools, String name, WeakPt if (auto tab = m_tab.strong_ref()) { devtools.delegate().listen_for_style_sheet_sources( tab->description(), - [weak_self = make_weak_ptr()](Web::CSS::StyleSheetIdentifier const& style_sheet, String source) { - if (auto self = weak_self.strong_ref()) - self->style_sheet_source_received(style_sheet, move(source)); - }); + weak_callback(*this, [](auto& self, Web::CSS::StyleSheetIdentifier const& style_sheet, String source) { + self.style_sheet_source_received(style_sheet, move(source)); + })); } } diff --git a/Libraries/LibDevTools/Actors/WalkerActor.cpp b/Libraries/LibDevTools/Actors/WalkerActor.cpp index aaa42dbfcf..4b6c4958a6 100644 --- a/Libraries/LibDevTools/Actors/WalkerActor.cpp +++ b/Libraries/LibDevTools/Actors/WalkerActor.cpp @@ -31,10 +31,9 @@ WalkerActor::WalkerActor(DevToolsServer& devtools, String name, WeakPtrdescription(), - [weak_self = make_weak_ptr()](WebView::Mutation mutation) { - if (auto self = weak_self.strong_ref()) - self->new_dom_node_mutation(move(mutation)); - }); + weak_callback(*this, [](auto& self, WebView::Mutation mutation) { + self.new_dom_node_mutation(move(mutation)); + })); } } diff --git a/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp index 6071efa1e4..5018f7497a 100644 --- a/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp @@ -69,21 +69,21 @@ void ImageStyleValue::load_any_resources(DOM::Document& document) if (m_resource_request) { m_resource_request->add_callbacks( - [this, weak_this = make_weak_ptr()] { - if (!weak_this || !m_document) + weak_callback(*this, [](auto& self) { + if (!self.m_document) return; - for (auto* client : m_clients) - client->image_style_value_did_update(*this); + for (auto* client : self.m_clients) + client->image_style_value_did_update(self); - auto image_data = m_resource_request->image_data(); + auto image_data = self.m_resource_request->image_data(); if (image_data->is_animated() && image_data->frame_count() > 1) { - m_timer = Platform::Timer::create(m_document->heap()); - m_timer->set_interval(image_data->frame_duration(0)); - m_timer->on_timeout = GC::create_function(m_document->heap(), [this] { animate(); }); - m_timer->start(); + self.m_timer = Platform::Timer::create(self.m_document->heap()); + self.m_timer->set_interval(image_data->frame_duration(0)); + self.m_timer->on_timeout = GC::create_function(self.m_document->heap(), [ptr = &self] { ptr->animate(); }); + self.m_timer->start(); } - }, + }), nullptr); } } diff --git a/Services/RequestServer/ConnectionFromClient.cpp b/Services/RequestServer/ConnectionFromClient.cpp index b38e9ac73e..6c567849e1 100644 --- a/Services/RequestServer/ConnectionFromClient.cpp +++ b/Services/RequestServer/ConnectionFromClient.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff --git a/Tests/AK/TestWeakPtr.cpp b/Tests/AK/TestWeakPtr.cpp index 4cb725478a..61b749b0b4 100644 --- a/Tests/AK/TestWeakPtr.cpp +++ b/Tests/AK/TestWeakPtr.cpp @@ -20,10 +20,22 @@ class SimpleWeakable : public Weakable public: SimpleWeakable() = default; + int member() const { return m_member; } + private: int m_member { 123 }; }; +class NonRefCountedWeakable : public Weakable { +public: + NonRefCountedWeakable() = default; + + int value() const { return m_value; } + +private: + int m_value { 456 }; +}; + #if defined(AK_COMPILER_CLANG) # pragma clang diagnostic pop #endif @@ -64,3 +76,72 @@ TEST_CASE(weakptr_move) EXPECT_EQ(weak2.is_null(), true); } + +TEST_CASE(weak_callback_ref_counted) +{ + bool was_called = false; + + { + auto simple = adopt_ref(*new SimpleWeakable); + auto cb = weak_callback(*simple, [&was_called](auto& self) { + was_called = true; + EXPECT_EQ(self.member(), 123); + }); + + cb(); + EXPECT(was_called); + } +} + +TEST_CASE(weak_callback_ref_counted_dead) +{ + auto cb = [&] { + auto simple = adopt_ref(*new SimpleWeakable); + return weak_callback(*simple, [](auto&) { + VERIFY_NOT_REACHED(); + }); + }(); + + cb(); +} + +TEST_CASE(weak_callback_ref_counted_with_args) +{ + int received_value = 0; + + auto simple = adopt_ref(*new SimpleWeakable); + auto cb = weak_callback(*simple, [&received_value](auto& self, int value) { + received_value = value + self.member(); + }); + + cb(42); + EXPECT_EQ(received_value, 42 + 123); +} + +TEST_CASE(weak_callback_non_ref_counted) +{ + bool was_called = false; + + { + NonRefCountedWeakable obj; + auto cb = weak_callback(obj, [&was_called](auto& self) { + was_called = true; + EXPECT_EQ(self.value(), 456); + }); + + cb(); + EXPECT(was_called); + } +} + +TEST_CASE(weak_callback_non_ref_counted_dead) +{ + auto cb = [&] { + NonRefCountedWeakable obj; + return weak_callback(obj, [](auto&) { + VERIFY_NOT_REACHED(); + }); + }(); + + cb(); +}