serenity/AK/OwnPtr.h
Ali Mohammad Pur f96a3c002a Everywhere: Stop shoving things into ::std and mentioning them as such
Note that this still keeps the old behaviour of putting things in std by
default on serenity so the tools can be happy, but if USING_AK_GLOBALLY
is unset, AK behaves like a good citizen and doesn't try to put things
in the ::std namespace.

std::nothrow_t and its friends get to stay because I'm being told that
compilers assume things about them and I can't yeet them into a
different namespace...for now.
2022-12-14 11:44:32 +01:00

233 lines
5 KiB
C++

/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Error.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/RefCounted.h>
#define OWNPTR_SCRUB_BYTE 0xf0
namespace AK {
template<typename T>
class [[nodiscard]] OwnPtr {
public:
OwnPtr() = default;
OwnPtr(decltype(nullptr))
: m_ptr(nullptr)
{
}
OwnPtr(OwnPtr&& other)
: m_ptr(other.leak_ptr())
{
}
template<typename U>
OwnPtr(NonnullOwnPtr<U>&& other)
: m_ptr(other.leak_ptr())
{
}
template<typename U>
OwnPtr(OwnPtr<U>&& other)
: m_ptr(other.leak_ptr())
{
}
~OwnPtr()
{
clear();
#ifdef SANITIZE_PTRS
m_ptr = (T*)(explode_byte(OWNPTR_SCRUB_BYTE));
#endif
}
OwnPtr(OwnPtr const&) = delete;
template<typename U>
OwnPtr(OwnPtr<U> const&) = delete;
OwnPtr& operator=(OwnPtr const&) = delete;
template<typename U>
OwnPtr& operator=(OwnPtr<U> const&) = delete;
template<typename U>
OwnPtr(NonnullOwnPtr<U> const&) = delete;
template<typename U>
OwnPtr& operator=(NonnullOwnPtr<U> const&) = delete;
template<typename U>
OwnPtr(RefPtr<U> const&) = delete;
template<typename U>
OwnPtr(NonnullRefPtr<U> const&) = delete;
template<typename U>
OwnPtr(WeakPtr<U> const&) = delete;
template<typename U>
OwnPtr& operator=(RefPtr<U> const&) = delete;
template<typename U>
OwnPtr& operator=(NonnullRefPtr<U> const&) = delete;
template<typename U>
OwnPtr& operator=(WeakPtr<U> const&) = delete;
OwnPtr& operator=(OwnPtr&& other)
{
OwnPtr ptr(move(other));
swap(ptr);
return *this;
}
template<typename U>
OwnPtr& operator=(OwnPtr<U>&& other)
{
OwnPtr ptr(move(other));
swap(ptr);
return *this;
}
template<typename U>
OwnPtr& operator=(NonnullOwnPtr<U>&& other)
{
OwnPtr ptr(move(other));
swap(ptr);
VERIFY(m_ptr);
return *this;
}
OwnPtr& operator=(T* ptr) = delete;
OwnPtr& operator=(nullptr_t)
{
clear();
return *this;
}
void clear()
{
delete m_ptr;
m_ptr = nullptr;
}
bool operator!() const { return !m_ptr; }
[[nodiscard]] T* leak_ptr()
{
T* leaked_ptr = m_ptr;
m_ptr = nullptr;
return leaked_ptr;
}
NonnullOwnPtr<T> release_nonnull()
{
VERIFY(m_ptr);
return NonnullOwnPtr<T>(NonnullOwnPtr<T>::Adopt, *leak_ptr());
}
template<typename U>
NonnullOwnPtr<U> release_nonnull()
{
VERIFY(m_ptr);
return NonnullOwnPtr<U>(NonnullOwnPtr<U>::Adopt, static_cast<U&>(*leak_ptr()));
}
T* ptr() const { return m_ptr; }
T* operator->() const
{
VERIFY(m_ptr);
return m_ptr;
}
T& operator*() const
{
VERIFY(m_ptr);
return *m_ptr;
}
operator T*() const { return m_ptr; }
operator bool() { return !!m_ptr; }
void swap(OwnPtr& other)
{
::swap(m_ptr, other.m_ptr);
}
template<typename U>
void swap(OwnPtr<U>& other)
{
::swap(m_ptr, other.m_ptr);
}
static OwnPtr lift(T* ptr)
{
return OwnPtr { ptr };
}
protected:
explicit OwnPtr(T* ptr)
: m_ptr(ptr)
{
static_assert(
requires { requires typename T::AllowOwnPtr()(); } || !requires { requires !typename T::AllowOwnPtr()(); declval<T>().ref(); declval<T>().unref(); }, "Use RefPtr<> for RefCounted types");
}
private:
T* m_ptr = nullptr;
};
template<typename T, typename U>
inline void swap(OwnPtr<T>& a, OwnPtr<U>& b)
{
a.swap(b);
}
template<typename T>
inline OwnPtr<T> adopt_own_if_nonnull(T* object)
{
if (object)
return OwnPtr<T>::lift(object);
return {};
}
template<typename T>
inline ErrorOr<NonnullOwnPtr<T>> adopt_nonnull_own_or_enomem(T* object)
{
auto result = adopt_own_if_nonnull(object);
if (!result)
return Error::from_errno(ENOMEM);
return result.release_nonnull();
}
template<typename T, class... Args>
requires(IsConstructible<T, Args...>) inline ErrorOr<NonnullOwnPtr<T>> try_make(Args&&... args)
{
return adopt_nonnull_own_or_enomem(new (nothrow) T(forward<Args>(args)...));
}
// FIXME: Remove once P0960R3 is available in Clang.
template<typename T, class... Args>
inline ErrorOr<NonnullOwnPtr<T>> try_make(Args&&... args)
{
return adopt_nonnull_own_or_enomem(new (nothrow) T { forward<Args>(args)... });
}
template<typename T>
struct Traits<OwnPtr<T>> : public GenericTraits<OwnPtr<T>> {
using PeekType = T*;
using ConstPeekType = T const*;
static unsigned hash(OwnPtr<T> const& p) { return ptr_hash(p.ptr()); }
static bool equals(OwnPtr<T> const& a, OwnPtr<T> const& b) { return a.ptr() == b.ptr(); }
};
}
#if USING_AK_GLOBALLY
using AK::adopt_nonnull_own_or_enomem;
using AK::adopt_own_if_nonnull;
using AK::OwnPtr;
using AK::try_make;
#endif