mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-08-17 01:10:28 +03:00
AK: Add NonnullOwnPtr.
This is just like OwnPtr (also single-owner), except it cannot be null. NonnullOwnPtr is perfect as the return type of functions that never need to return nullptr. It's also useful as an argument type to encode the fact that the argument must not be nullptr. The make<Foo>() helper is changed to return NonnullOwnPtr<Foo>. Note: You can move() out of a NonnullOwnPtr, and after that the object is in an invalid state. Internally it will be a nullptr at this point, so we'll still catch misuse, but the only thing that should be done in this state is running the destructor. I've used consumable annotations to generate some warnings when using a NonnullOwnPtr after moving from it, but these only work when compiling with clang, so be aware of that.
This commit is contained in:
parent
ecc35876af
commit
28da5b002f
Notes:
sideshowbarker
2024-07-19 13:04:44 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/28da5b002f1
157
AK/NonnullOwnPtr.h
Normal file
157
AK/NonnullOwnPtr.h
Normal file
@ -0,0 +1,157 @@
|
||||
#pragma once
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/LogStream.h>
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <AK/Traits.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename T>
|
||||
class RefPtr;
|
||||
template<typename T>
|
||||
class NonnullRefPtr;
|
||||
template<typename T>
|
||||
class WeakPtr;
|
||||
|
||||
template<typename T>
|
||||
class CONSUMABLE(unconsumed) NonnullOwnPtr {
|
||||
public:
|
||||
enum AdoptTag { Adopt };
|
||||
|
||||
RETURN_TYPESTATE(unconsumed)
|
||||
NonnullOwnPtr(AdoptTag, T& ptr)
|
||||
: m_ptr(&ptr)
|
||||
{
|
||||
}
|
||||
RETURN_TYPESTATE(unconsumed)
|
||||
NonnullOwnPtr(NonnullOwnPtr&& other)
|
||||
: m_ptr(other.leak_ptr())
|
||||
{
|
||||
ASSERT(m_ptr);
|
||||
}
|
||||
template<typename U>
|
||||
RETURN_TYPESTATE(unconsumed)
|
||||
NonnullOwnPtr(NonnullOwnPtr<U>&& other)
|
||||
: m_ptr(static_cast<T*>(other.leak_ptr()))
|
||||
{
|
||||
ASSERT(m_ptr);
|
||||
}
|
||||
~NonnullOwnPtr()
|
||||
{
|
||||
clear();
|
||||
#ifdef SANITIZE_PTRS
|
||||
if constexpr (sizeof(T*) == 8)
|
||||
m_ptr = (T*)(0xe3e3e3e3e3e3e3e3);
|
||||
else
|
||||
m_ptr = (T*)(0xe3e3e3e3);
|
||||
#endif
|
||||
}
|
||||
|
||||
NonnullOwnPtr(const NonnullOwnPtr&) = delete;
|
||||
template<typename U>
|
||||
NonnullOwnPtr(const NonnullOwnPtr<U>&) = delete;
|
||||
NonnullOwnPtr& operator=(const NonnullOwnPtr&) = delete;
|
||||
template<typename U>
|
||||
NonnullOwnPtr& operator=(const NonnullOwnPtr<U>&) = delete;
|
||||
|
||||
template<typename U>
|
||||
NonnullOwnPtr(const RefPtr<U>&) = delete;
|
||||
template<typename U>
|
||||
NonnullOwnPtr(const NonnullRefPtr<U>&) = delete;
|
||||
template<typename U>
|
||||
NonnullOwnPtr(const WeakPtr<U>&) = delete;
|
||||
template<typename U>
|
||||
NonnullOwnPtr& operator=(const RefPtr<U>&) = delete;
|
||||
template<typename U>
|
||||
NonnullOwnPtr& operator=(const NonnullRefPtr<U>&) = delete;
|
||||
template<typename U>
|
||||
NonnullOwnPtr& operator=(const WeakPtr<U>&) = delete;
|
||||
|
||||
RETURN_TYPESTATE(unconsumed)
|
||||
NonnullOwnPtr& operator=(NonnullOwnPtr&& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
delete m_ptr;
|
||||
m_ptr = other.leak_ptr();
|
||||
ASSERT(m_ptr);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
RETURN_TYPESTATE(unconsumed)
|
||||
NonnullOwnPtr& operator=(NonnullOwnPtr<U>&& other)
|
||||
{
|
||||
if (this != static_cast<void*>(&other)) {
|
||||
delete m_ptr;
|
||||
m_ptr = other.leak_ptr();
|
||||
ASSERT(m_ptr);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CALLABLE_WHEN(unconsumed)
|
||||
SET_TYPESTATE(consumed)
|
||||
T* leak_ptr()
|
||||
{
|
||||
return exchange(m_ptr, nullptr);
|
||||
}
|
||||
|
||||
CALLABLE_WHEN(unconsumed)
|
||||
T* ptr() { return m_ptr; }
|
||||
CALLABLE_WHEN(unconsumed)
|
||||
const T* ptr() const { return m_ptr; }
|
||||
|
||||
CALLABLE_WHEN(unconsumed)
|
||||
T* operator->() { return m_ptr; }
|
||||
CALLABLE_WHEN(unconsumed)
|
||||
const T* operator->() const { return m_ptr; }
|
||||
|
||||
CALLABLE_WHEN(unconsumed)
|
||||
T& operator*() { return *m_ptr; }
|
||||
CALLABLE_WHEN(unconsumed)
|
||||
const T& operator*() const { return *m_ptr; }
|
||||
|
||||
CALLABLE_WHEN(unconsumed)
|
||||
operator const T*() const { return m_ptr; }
|
||||
CALLABLE_WHEN(unconsumed)
|
||||
operator T*() { return m_ptr; }
|
||||
|
||||
private:
|
||||
void clear()
|
||||
{
|
||||
if (!m_ptr)
|
||||
return;
|
||||
delete m_ptr;
|
||||
m_ptr = nullptr;
|
||||
}
|
||||
|
||||
T* m_ptr = nullptr;
|
||||
};
|
||||
|
||||
template<class T, class... Args>
|
||||
inline NonnullOwnPtr<T>
|
||||
make(Args&&... args)
|
||||
{
|
||||
return NonnullOwnPtr<T>(NonnullOwnPtr<T>::Adopt, *new T(forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct Traits<NonnullOwnPtr<T>> : public GenericTraits<NonnullOwnPtr<T>> {
|
||||
static unsigned hash(const NonnullOwnPtr<T>& p) { return (unsigned)p.ptr(); }
|
||||
static void dump(const NonnullOwnPtr<T>& p) { kprintf("%p", p.ptr()); }
|
||||
static bool equals(const NonnullOwnPtr<T>& a, const NonnullOwnPtr<T>& b) { return a.ptr() == b.ptr(); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline const LogStream& operator<<(const LogStream& stream, const NonnullOwnPtr<T>& value)
|
||||
{
|
||||
return stream << value.ptr();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using AK::make;
|
||||
using AK::NonnullOwnPtr;
|
46
AK/OwnPtr.h
46
AK/OwnPtr.h
@ -1,19 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <AK/LogStream.h>
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <AK/Traits.h>
|
||||
#include <AK/Types.h>
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename T>
|
||||
class RefPtr;
|
||||
template<typename T>
|
||||
class NonnullRefPtr;
|
||||
template<typename T>
|
||||
class WeakPtr;
|
||||
|
||||
template<typename T>
|
||||
class OwnPtr {
|
||||
public:
|
||||
@ -26,6 +16,12 @@ public:
|
||||
: m_ptr(other.leak_ptr())
|
||||
{
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
OwnPtr(NonnullOwnPtr<U>&& other)
|
||||
: m_ptr(static_cast<T*>(other.leak_ptr()))
|
||||
{
|
||||
}
|
||||
template<typename U>
|
||||
OwnPtr(OwnPtr<U>&& other)
|
||||
: m_ptr(static_cast<T*>(other.leak_ptr()))
|
||||
@ -43,6 +39,13 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
OwnPtr(const OwnPtr&) = delete;
|
||||
template<typename U>
|
||||
OwnPtr(const OwnPtr<U>&) = delete;
|
||||
OwnPtr& operator=(const OwnPtr&) = delete;
|
||||
template<typename U>
|
||||
OwnPtr& operator=(const OwnPtr<U>&) = delete;
|
||||
|
||||
template<typename U>
|
||||
OwnPtr(const RefPtr<U>&) = delete;
|
||||
template<typename U>
|
||||
@ -75,6 +78,15 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
OwnPtr& operator=(NonnullOwnPtr<U>&& other)
|
||||
{
|
||||
ASSERT(m_ptr != other.ptr());
|
||||
delete m_ptr;
|
||||
m_ptr = other.leak_ptr();
|
||||
return *this;
|
||||
}
|
||||
|
||||
OwnPtr& operator=(T* ptr)
|
||||
{
|
||||
if (m_ptr != ptr)
|
||||
@ -99,9 +111,9 @@ public:
|
||||
|
||||
T* leak_ptr()
|
||||
{
|
||||
T* leakedPtr = m_ptr;
|
||||
T* leaked_ptr = m_ptr;
|
||||
m_ptr = nullptr;
|
||||
return leakedPtr;
|
||||
return leaked_ptr;
|
||||
}
|
||||
|
||||
T* ptr() { return m_ptr; }
|
||||
@ -122,13 +134,6 @@ private:
|
||||
T* m_ptr = nullptr;
|
||||
};
|
||||
|
||||
template<class T, class... Args>
|
||||
inline OwnPtr<T>
|
||||
make(Args&&... args)
|
||||
{
|
||||
return OwnPtr<T>(new T(AK::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct Traits<OwnPtr<T>> : public GenericTraits<OwnPtr<T>> {
|
||||
static unsigned hash(const OwnPtr<T>& p) { return (unsigned)p.ptr(); }
|
||||
@ -144,5 +149,4 @@ inline const LogStream& operator<<(const LogStream& stream, const OwnPtr<T>& val
|
||||
|
||||
}
|
||||
|
||||
using AK::make;
|
||||
using AK::OwnPtr;
|
||||
|
Loading…
Reference in New Issue
Block a user