AK+Everywhere: Move custom deleter capability to OwnPtr

`OwnPtrWithCustomDeleter` was a decorator which provided the ability
to add a custom deleter to `OwnPtr` by wrapping and taking the deleter
as a run-time argument to the constructor. This solution means that no
additional space is needed for the `OwnPtr` because it doesn't need to
store a pointer to the deleter, but comes at the cost of having an
extra type that stores a pointer for every instance.

This logic is moved directly into `OwnPtr` by adding a template
argument that is defaulted to the default deleter for the type. This
means that the type itself stores the pointer to the deleter instead
of every instance and adds some type safety by encoding the deleter in
the type itself instead of taking a run-time argument.
This commit is contained in:
Lenny Maiorani 2022-12-15 20:51:55 -07:00 committed by Tim Flynn
parent 53133b4359
commit f2336d0144
Notes: sideshowbarker 2024-07-17 03:03:05 +09:00
12 changed files with 74 additions and 63 deletions

35
AK/DefaultDelete.h Normal file
View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
namespace AK {
template<class T>
struct DefaultDelete {
constexpr DefaultDelete() = default;
constexpr void operator()(T* t)
{
delete t;
}
};
template<class T>
struct DefaultDelete<T[]> {
constexpr DefaultDelete() = default;
constexpr void operator()(T* t)
{
delete[] t;
}
};
}
#ifdef USING_AK_GLOBALLY
using AK::DefaultDelete;
#endif

View file

@ -6,6 +6,7 @@
#pragma once
#include <AK/DefaultDelete.h>
#include <AK/Types.h>
namespace AK {
@ -133,7 +134,7 @@ class LockRefPtr;
template<typename T>
class RefPtr;
template<typename T>
template<typename T, typename TDeleter = DefaultDelete<T>>
class OwnPtr;
template<typename T>

View file

@ -16,8 +16,6 @@
namespace AK {
template<typename T>
class OwnPtr;
template<typename T>
class RefPtr;

View file

@ -7,6 +7,7 @@
#pragma once
#include <AK/Error.h>
#include <AK/Forward.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/RefCounted.h>
@ -14,7 +15,7 @@
namespace AK {
template<typename T>
template<typename T, typename TDeleter>
class [[nodiscard]] OwnPtr {
public:
OwnPtr() = default;
@ -105,7 +106,7 @@ public:
void clear()
{
delete m_ptr;
TDeleter {}(m_ptr);
m_ptr = nullptr;
}

View file

@ -1,41 +0,0 @@
/*
* Copyright (c) 2022, Lucas Chollet <lucas.chollet@free.fr>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Function.h>
#include <AK/Noncopyable.h>
#include <AK/StdLibExtras.h>
template<typename T>
struct OwnPtrWithCustomDeleter {
AK_MAKE_NONCOPYABLE(OwnPtrWithCustomDeleter);
public:
OwnPtrWithCustomDeleter(T* ptr, Function<void(T*)> deleter)
: m_ptr(ptr)
, m_deleter(move(deleter))
{
}
OwnPtrWithCustomDeleter(OwnPtrWithCustomDeleter&& other)
{
swap(m_ptr, other.m_ptr);
swap(m_deleter, other.m_deleter);
};
~OwnPtrWithCustomDeleter()
{
if (m_ptr) {
VERIFY(m_deleter);
m_deleter(m_ptr);
}
}
private:
T* m_ptr { nullptr };
Function<void(T*)> m_deleter {};
};

View file

@ -12,6 +12,7 @@
#include <AK/Atomic.h>
#include <AK/Error.h>
#include <AK/Format.h>
#include <AK/Forward.h>
#include <AK/NonnullRefPtr.h>
#include <AK/StdLibExtras.h>
#include <AK/Traits.h>
@ -19,9 +20,6 @@
namespace AK {
template<typename T>
class OwnPtr;
template<typename T>
class [[nodiscard]] RefPtr {
template<typename U>

View file

@ -23,9 +23,6 @@
namespace AK {
template<typename T>
class OwnPtr;
template<typename T>
struct LockRefPtrTraits {
ALWAYS_INLINE static T* as_ptr(FlatPtr bits)

View file

@ -21,8 +21,6 @@
namespace AK {
template<typename T>
class OwnPtr;
template<typename T, typename PtrTraits>
class LockRefPtr;

View file

@ -52,6 +52,7 @@ set(AK_TEST_SOURCES
TestNonnullRefPtr.cpp
TestNumberFormat.cpp
TestOptional.cpp
TestOwnPtr.cpp
TestPrint.cpp
TestQueue.cpp
TestQuickSort.cpp

23
Tests/AK/TestOwnPtr.cpp Normal file
View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibTest/TestCase.h>
#include <AK/OwnPtr.h>
static u64 deleter_call_count = 0;
TEST_CASE(should_call_custom_deleter)
{
auto deleter = [](auto* p) { if (p) ++deleter_call_count; };
auto ptr = OwnPtr<u64, decltype(deleter)> {};
ptr.clear();
EXPECT_EQ(0u, deleter_call_count);
ptr = adopt_own_if_nonnull(&deleter_call_count);
EXPECT_EQ(0u, deleter_call_count);
ptr.clear();
EXPECT_EQ(1u, deleter_call_count);
}

View file

@ -1334,11 +1334,7 @@ ErrorOr<AddressInfoVector> getaddrinfo(char const* nodename, char const* servnam
for (auto* result = results; result != nullptr; result = result->ai_next)
TRY(addresses.try_append(*result));
return AddressInfoVector { move(addresses), results,
[](struct addrinfo* ptr) {
if (ptr)
::freeaddrinfo(ptr);
} };
return AddressInfoVector { move(addresses), results };
}
ErrorOr<void> getsockopt(int sockfd, int level, int option, void* value, socklen_t* value_size)

View file

@ -10,7 +10,7 @@
#include <AK/Error.h>
#include <AK/Noncopyable.h>
#include <AK/OwnPtrWithCustomDeleter.h>
#include <AK/OwnPtr.h>
#include <AK/StringView.h>
#include <AK/Vector.h>
#include <dirent.h>
@ -226,14 +226,18 @@ public:
private:
friend ErrorOr<AddressInfoVector> getaddrinfo(char const* nodename, char const* servname, struct addrinfo const& hints);
AddressInfoVector(Vector<struct addrinfo>&& addresses, struct addrinfo* ptr, AK::Function<void(struct addrinfo*)> deleter)
AddressInfoVector(Vector<struct addrinfo>&& addresses, struct addrinfo* ptr)
: m_addresses(move(addresses))
, m_ptr(ptr, move(deleter))
, m_ptr(adopt_own_if_nonnull(ptr))
{
}
struct AddrInfoDeleter {
void operator()(struct addrinfo* ptr) { ::freeaddrinfo(ptr); }
};
Vector<struct addrinfo> m_addresses {};
OwnPtrWithCustomDeleter<struct addrinfo> m_ptr;
OwnPtr<struct addrinfo, AddrInfoDeleter> m_ptr {};
};
ErrorOr<AddressInfoVector> getaddrinfo(char const* nodename, char const* servname, struct addrinfo const& hints);