ladybird/Userland/Libraries/LibJS/Heap/Handle.h
MacDue 66a428ae03 LibJS+LibWeb: Return non-const types from Ptr class operators
Even if the pointer value is const, the value they point to is not
necessarily const, so these functions should not add the qualifier.

This also removes the redundant non-const implementations of these
operators.
2022-11-19 14:37:31 +00:00

162 lines
2.8 KiB
C++

/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Badge.h>
#include <AK/IntrusiveList.h>
#include <AK/Noncopyable.h>
#include <AK/RefCounted.h>
#include <AK/RefPtr.h>
#include <LibJS/Forward.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
class HandleImpl : public RefCounted<HandleImpl> {
AK_MAKE_NONCOPYABLE(HandleImpl);
AK_MAKE_NONMOVABLE(HandleImpl);
public:
~HandleImpl();
Cell* cell() { return m_cell; }
Cell const* cell() const { return m_cell; }
private:
template<class T>
friend class Handle;
explicit HandleImpl(Cell*);
Cell* m_cell { nullptr };
IntrusiveListNode<HandleImpl> m_list_node;
public:
using List = IntrusiveList<&HandleImpl::m_list_node>;
};
template<class T>
class Handle {
public:
Handle() = default;
static Handle create(T* cell)
{
return Handle(adopt_ref(*new HandleImpl(cell)));
}
Handle(T* cell)
{
if (cell)
m_impl = adopt_ref(*new HandleImpl(cell));
}
Handle(T& cell)
: m_impl(adopt_ref(*new HandleImpl(&cell)))
{
}
T* cell() const
{
if (!m_impl)
return nullptr;
return static_cast<T*>(m_impl->cell());
}
T* ptr() const
{
return cell();
}
bool is_null() const
{
return m_impl.is_null();
}
T* operator->() const
{
return cell();
}
T& operator*() const
{
return *cell();
}
bool operator!() const
{
return !cell();
}
operator bool() const
{
return cell();
}
operator T*() const { return cell(); }
private:
explicit Handle(NonnullRefPtr<HandleImpl> impl)
: m_impl(move(impl))
{
}
RefPtr<HandleImpl> m_impl;
};
template<class T>
inline Handle<T> make_handle(T* cell)
{
if (!cell)
return Handle<T> {};
return Handle<T>::create(cell);
}
template<class T>
inline Handle<T> make_handle(T& cell)
{
return Handle<T>::create(&cell);
}
template<>
class Handle<Value> {
public:
Handle() = default;
static Handle create(Value value)
{
if (value.is_cell())
return Handle(value, &value.as_cell());
return Handle(value);
}
auto cell() { return m_handle.cell(); }
auto cell() const { return m_handle.cell(); }
auto value() const { return *m_value; }
bool is_null() const { return m_handle.is_null() && !m_value.has_value(); }
private:
explicit Handle(Value value)
: m_value(value)
{
}
explicit Handle(Value value, Cell* cell)
: m_value(value)
, m_handle(Handle<Cell>::create(cell))
{
}
Optional<Value> m_value;
Handle<Cell> m_handle;
};
inline Handle<Value> make_handle(Value value)
{
return Handle<Value>::create(value);
}
}