mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-30 00:31:14 +00:00
06f82901b7
This gives us much better error messages when you try to use them. Without this change, it would complain about the absence of functions named ref() and deref() on RefPtr itself. With it, we instead get a "hey, this function is deleted" error. Change operator=(T&) to operator=T(const T&) also, to keep assigning a const T& to a NonnullRefPtr working.
248 lines
5.1 KiB
C++
248 lines
5.1 KiB
C++
#pragma once
|
|
|
|
#include <AK/Assertions.h>
|
|
#include <AK/LogStream.h>
|
|
#include <AK/Types.h>
|
|
|
|
namespace AK {
|
|
|
|
template<typename T>
|
|
class OwnPtr;
|
|
template<typename T>
|
|
class RefPtr;
|
|
|
|
template<typename T>
|
|
inline void ref_if_not_null(T* ptr)
|
|
{
|
|
if (ptr)
|
|
ptr->ref();
|
|
}
|
|
|
|
template<typename T>
|
|
inline void deref_if_not_null(T* ptr)
|
|
{
|
|
if (ptr)
|
|
ptr->deref();
|
|
}
|
|
|
|
template<typename T>
|
|
class CONSUMABLE(unconsumed) NonnullRefPtr {
|
|
public:
|
|
typedef T ElementType;
|
|
|
|
enum AdoptTag { Adopt };
|
|
|
|
RETURN_TYPESTATE(unconsumed)
|
|
NonnullRefPtr(const T& object)
|
|
: m_ptr(const_cast<T*>(&object))
|
|
{
|
|
m_ptr->ref();
|
|
}
|
|
template<typename U>
|
|
RETURN_TYPESTATE(unconsumed)
|
|
NonnullRefPtr(const U& object)
|
|
: m_ptr(&const_cast<T&>(static_cast<const T&>(object)))
|
|
{
|
|
m_ptr->ref();
|
|
}
|
|
RETURN_TYPESTATE(unconsumed)
|
|
NonnullRefPtr(AdoptTag, T& object)
|
|
: m_ptr(&object)
|
|
{
|
|
}
|
|
RETURN_TYPESTATE(unconsumed)
|
|
NonnullRefPtr(NonnullRefPtr&& other)
|
|
: m_ptr(&other.leak_ref())
|
|
{
|
|
}
|
|
template<typename U>
|
|
RETURN_TYPESTATE(unconsumed)
|
|
NonnullRefPtr(NonnullRefPtr<U>&& other)
|
|
: m_ptr(static_cast<T*>(&other.leak_ref()))
|
|
{
|
|
}
|
|
RETURN_TYPESTATE(unconsumed)
|
|
NonnullRefPtr(const NonnullRefPtr& other)
|
|
: m_ptr(const_cast<T*>(other.ptr()))
|
|
{
|
|
m_ptr->ref();
|
|
}
|
|
template<typename U>
|
|
RETURN_TYPESTATE(unconsumed)
|
|
NonnullRefPtr(const NonnullRefPtr<U>& other)
|
|
: m_ptr(const_cast<T*>(static_cast<const T*>((other.ptr()))))
|
|
{
|
|
m_ptr->ref();
|
|
}
|
|
~NonnullRefPtr()
|
|
{
|
|
deref_if_not_null(m_ptr);
|
|
m_ptr = nullptr;
|
|
#ifdef SANITIZE_PTRS
|
|
if constexpr (sizeof(T*) == 8)
|
|
m_ptr = (T*)(0xb0b0b0b0b0b0b0b0);
|
|
else
|
|
m_ptr = (T*)(0xb0b0b0b0);
|
|
#endif
|
|
}
|
|
|
|
template<typename U>
|
|
NonnullRefPtr(const OwnPtr<U>&) = delete;
|
|
template<typename U>
|
|
NonnullRefPtr& operator=(const OwnPtr<U>&) = delete;
|
|
|
|
template<typename U>
|
|
NonnullRefPtr(const RefPtr<U>&) = delete;
|
|
template<typename U>
|
|
NonnullRefPtr& operator=(const RefPtr<U>&) = delete;
|
|
NonnullRefPtr(const RefPtr<T>&) = delete;
|
|
NonnullRefPtr& operator=(const RefPtr<T>&) = delete;
|
|
|
|
NonnullRefPtr& operator=(const NonnullRefPtr& other)
|
|
{
|
|
if (m_ptr != other.m_ptr) {
|
|
deref_if_not_null(m_ptr);
|
|
m_ptr = const_cast<T*>(other.ptr());
|
|
m_ptr->ref();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template<typename U>
|
|
NonnullRefPtr& operator=(const NonnullRefPtr<U>& other)
|
|
{
|
|
if (m_ptr != other.ptr()) {
|
|
deref_if_not_null(m_ptr);
|
|
m_ptr = const_cast<T*>(static_cast<const T*>(other.ptr()));
|
|
m_ptr->ref();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
NonnullRefPtr& operator=(NonnullRefPtr&& other)
|
|
{
|
|
if (this != &other) {
|
|
deref_if_not_null(m_ptr);
|
|
m_ptr = &other.leak_ref();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template<typename U>
|
|
NonnullRefPtr& operator=(NonnullRefPtr<U>&& other)
|
|
{
|
|
if (this != static_cast<void*>(&other)) {
|
|
deref_if_not_null(m_ptr);
|
|
m_ptr = static_cast<T*>(&other.leak_ref());
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
NonnullRefPtr& operator=(const T& object)
|
|
{
|
|
if (m_ptr != &object) {
|
|
deref_if_not_null(m_ptr);
|
|
m_ptr = const_cast<T*>(&object);
|
|
m_ptr->ref();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
CALLABLE_WHEN(unconsumed)
|
|
SET_TYPESTATE(consumed)
|
|
T& leak_ref()
|
|
{
|
|
ASSERT(m_ptr);
|
|
T* leakedPtr = m_ptr;
|
|
m_ptr = nullptr;
|
|
return *leakedPtr;
|
|
}
|
|
|
|
CALLABLE_WHEN("unconsumed","unknown")
|
|
T* ptr()
|
|
{
|
|
ASSERT(m_ptr);
|
|
return m_ptr;
|
|
}
|
|
CALLABLE_WHEN("unconsumed","unknown")
|
|
const T* ptr() const
|
|
{
|
|
ASSERT(m_ptr);
|
|
return m_ptr;
|
|
}
|
|
|
|
CALLABLE_WHEN(unconsumed)
|
|
T* operator->()
|
|
{
|
|
ASSERT(m_ptr);
|
|
return m_ptr;
|
|
}
|
|
CALLABLE_WHEN(unconsumed)
|
|
const T* operator->() const
|
|
{
|
|
ASSERT(m_ptr);
|
|
return m_ptr;
|
|
}
|
|
|
|
CALLABLE_WHEN(unconsumed)
|
|
T& operator*()
|
|
{
|
|
ASSERT(m_ptr);
|
|
return *m_ptr;
|
|
}
|
|
CALLABLE_WHEN(unconsumed)
|
|
const T& operator*() const
|
|
{
|
|
ASSERT(m_ptr);
|
|
return *m_ptr;
|
|
}
|
|
|
|
CALLABLE_WHEN(unconsumed)
|
|
operator T*()
|
|
{
|
|
ASSERT(m_ptr);
|
|
return m_ptr;
|
|
}
|
|
CALLABLE_WHEN(unconsumed)
|
|
operator const T*() const
|
|
{
|
|
ASSERT(m_ptr);
|
|
return m_ptr;
|
|
}
|
|
|
|
CALLABLE_WHEN(unconsumed)
|
|
operator T&()
|
|
{
|
|
ASSERT(m_ptr);
|
|
return *m_ptr;
|
|
}
|
|
CALLABLE_WHEN(unconsumed)
|
|
operator const T&() const
|
|
{
|
|
ASSERT(m_ptr);
|
|
return *m_ptr;
|
|
}
|
|
|
|
private:
|
|
NonnullRefPtr() = delete;
|
|
|
|
T* m_ptr { nullptr };
|
|
};
|
|
|
|
template<typename T>
|
|
inline NonnullRefPtr<T> adopt(T& object)
|
|
{
|
|
return NonnullRefPtr<T>(NonnullRefPtr<T>::Adopt, object);
|
|
}
|
|
|
|
template<typename T>
|
|
inline const LogStream& operator<<(const LogStream& stream, const NonnullRefPtr<T>& value)
|
|
{
|
|
return stream << value.ptr();
|
|
}
|
|
|
|
}
|
|
|
|
using AK::adopt;
|
|
using AK::NonnullRefPtr;
|