/* * Copyright (c) 2020, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include namespace GC { class RootImpl : public RefCounted { AK_MAKE_NONCOPYABLE(RootImpl); AK_MAKE_NONMOVABLE(RootImpl); public: ~RootImpl(); Cell* cell() { return m_cell; } Cell const* cell() const { return m_cell; } SourceLocation const& source_location() const { return m_location; } private: template friend class Root; explicit RootImpl(Cell*, SourceLocation location); Ptr m_cell; SourceLocation m_location; IntrusiveListNode m_list_node; public: using List = IntrusiveList<&RootImpl::m_list_node>; }; template class Root { public: Root() = default; static Root create(T* cell, SourceLocation location = SourceLocation::current()) { return Root(adopt_ref(*new RootImpl(const_cast*>(cell), location))); } Root(T* cell, SourceLocation location = SourceLocation::current()) { if (cell) m_impl = adopt_ref(*new RootImpl(cell, location)); } Root(T& cell, SourceLocation location = SourceLocation::current()) : m_impl(adopt_ref(*new RootImpl(&cell, location))) { } Root(Ptr cell, SourceLocation location = SourceLocation::current()) : Root(cell.ptr(), location) { } Root(Ref cell, SourceLocation location = SourceLocation::current()) : Root(*cell, location) { } T* cell() const { if (!m_impl) return nullptr; return static_cast(m_impl->cell()); } T* ptr() const { return cell(); } bool is_null() const { return m_impl.is_null(); } T* operator->() const { return cell(); } [[nodiscard]] T& operator*() const { return *cell(); } bool operator!() const { return !cell(); } operator bool() const { return cell(); } operator T*() const { return cell(); } private: explicit Root(NonnullRefPtr impl) : m_impl(move(impl)) { } RefPtr m_impl; }; template inline Root make_root(T* cell, SourceLocation location = SourceLocation::current()) { if (!cell) return Root {}; return Root::create(cell, location); } template inline Root make_root(T& cell, SourceLocation location = SourceLocation::current()) { return Root::create(&cell, location); } template inline Root make_root(Ptr cell, SourceLocation location = SourceLocation::current()) { if (!cell) return Root {}; return Root::create(cell.ptr(), location); } template inline Root make_root(Ref cell, SourceLocation location = SourceLocation::current()) { return Root::create(cell.ptr(), location); } } namespace AK { template struct Traits> : public DefaultTraits> { static unsigned hash(GC::Root const& handle) { return Traits::hash(handle); } }; namespace Detail { template inline constexpr bool IsHashCompatible, T> = true; template inline constexpr bool IsHashCompatible> = true; } }