From e34e21367e73b7bc6e8959f47a2bb3fe2aa01fad Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 9 Aug 2022 12:32:27 +0200 Subject: [PATCH] LibJS: Add GCPtr and NonnullGCPtr These are two new smart pointers that are really just raw pointers under the hood. The initial benefit is all in the names, they allow us to declare that we're pointing at something in the GC heap. Later we may also find ways to add debugging logic or static analysis to these types. --- Userland/Libraries/LibJS/Heap/GCPtr.h | 239 ++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 Userland/Libraries/LibJS/Heap/GCPtr.h diff --git a/Userland/Libraries/LibJS/Heap/GCPtr.h b/Userland/Libraries/LibJS/Heap/GCPtr.h new file mode 100644 index 0000000000..1d809166b4 --- /dev/null +++ b/Userland/Libraries/LibJS/Heap/GCPtr.h @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace JS { + +template +class GCPtr; + +template +class NonnullGCPtr { +public: + NonnullGCPtr() = delete; + + NonnullGCPtr(T& ptr) + : m_ptr(&ptr) + { + } + + NonnullGCPtr(T const& ptr) + : m_ptr(&const_cast(ptr)) + { + } + + template + NonnullGCPtr(U& ptr) requires(IsConvertible) + : m_ptr(&static_cast(ptr)) + { + } + + template + NonnullGCPtr(U const& ptr) requires(IsConvertible) + : m_ptr(&const_cast(static_cast(ptr))) + { + } + + template + NonnullGCPtr(NonnullGCPtr ptr) requires(IsConvertible) + : m_ptr(ptr) + { + } + + NonnullGCPtr& operator=(GCPtr const& other) + { + m_ptr = const_cast(other.ptr()); + return *this; + } + + NonnullGCPtr& operator=(T const& other) + { + m_ptr = &const_cast(other); + return *this; + } + + template + NonnullGCPtr& operator=(U const& other) requires(IsConvertible) + { + m_ptr = &const_cast(static_cast(other)); + return *this; + } + + template + NonnullGCPtr& operator=(NonnullGCPtr const& other) requires(IsConvertible) + { + m_ptr = const_cast(static_cast(other.ptr())); + return *this; + } + + T* operator->() { return m_ptr; } + T const* operator->() const { return m_ptr; } + + T& operator*() { return *m_ptr; } + T const& operator*() const { return *m_ptr; } + + T* ptr() { return m_ptr; } + T const* ptr() const { return m_ptr; } + + operator T*() { return m_ptr; } + operator T const*() const { return m_ptr; } + + operator T&() { return *m_ptr; } + operator T const&() const { return *m_ptr; } + +private: + T* m_ptr { nullptr }; +}; + +template +class GCPtr { +public: + GCPtr() = default; + + GCPtr(T& ptr) + : m_ptr(&ptr) + { + } + + GCPtr(T const& ptr) + : m_ptr(&const_cast(ptr)) + { + } + + GCPtr(T* ptr) + : m_ptr(ptr) + { + } + + GCPtr(T const* ptr) + : m_ptr(const_cast(ptr)) + { + } + + GCPtr(NonnullGCPtr ptr) + : m_ptr(ptr) + { + } + + template + GCPtr(NonnullGCPtr ptr) requires(IsConvertible) + : m_ptr(ptr) + { + } + + GCPtr(std::nullptr_t) + : m_ptr(nullptr) + { + } + + GCPtr(GCPtr const&) = default; + GCPtr& operator=(GCPtr const&) = default; + + template + GCPtr& operator=(GCPtr const& other) requires(IsConvertible) + { + m_ptr = const_cast(static_cast(other.ptr())); + return *this; + } + + GCPtr& operator=(NonnullGCPtr const& other) + { + m_ptr = const_cast(other.ptr()); + return *this; + } + + template + GCPtr& operator=(NonnullGCPtr const& other) requires(IsConvertible) + { + m_ptr = const_cast(static_cast(other.ptr())); + return *this; + } + + GCPtr& operator=(T const& other) + { + m_ptr = &const_cast(other); + return *this; + } + + template + GCPtr& operator=(U const& other) requires(IsConvertible) + { + m_ptr = &const_cast(static_cast(other)); + return *this; + } + + GCPtr& operator=(T const* other) + { + m_ptr = const_cast(other); + return *this; + } + + template + GCPtr& operator=(U const* other) requires(IsConvertible) + { + m_ptr = const_cast(static_cast(other)); + return *this; + } + + T* operator->() { return m_ptr; } + T const* operator->() const { return m_ptr; } + + T& operator*() { return *m_ptr; } + T const& operator*() const { return *m_ptr; } + + T* ptr() { return m_ptr; } + T const* ptr() const { return m_ptr; } + + operator bool() const { return !!m_ptr; } + bool operator!() const { return !m_ptr; } + + operator T*() { return m_ptr; } + operator T const*() const { return m_ptr; } + +private: + T* m_ptr { nullptr }; +}; + +template +inline bool operator==(GCPtr const& a, GCPtr const& b) +{ + return a.ptr() == b.ptr(); +} + +template +inline bool operator==(GCPtr const& a, NonnullGCPtr const& b) +{ + return a.ptr() == b.ptr(); +} + +template +inline bool operator==(NonnullGCPtr const& a, NonnullGCPtr const& b) +{ + return a.ptr() == b.ptr(); +} + +template +inline bool operator==(NonnullGCPtr const& a, GCPtr const& b) +{ + return a.ptr() == b.ptr(); +} + +template +inline bool operator==(NonnullGCPtr const& a, U const* b) +{ + return a.ptr() == b; +} + +template +inline bool operator==(GCPtr const& a, U const* b) +{ + return a.ptr() == b; +} + +}