Browse Source

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.
Andreas Kling 2 năm trước cách đây
mục cha
commit
e34e21367e
1 tập tin đã thay đổi với 239 bổ sung0 xóa
  1. 239 0
      Userland/Libraries/LibJS/Heap/GCPtr.h

+ 239 - 0
Userland/Libraries/LibJS/Heap/GCPtr.h

@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Types.h>
+
+namespace JS {
+
+template<typename T>
+class GCPtr;
+
+template<typename T>
+class NonnullGCPtr {
+public:
+    NonnullGCPtr() = delete;
+
+    NonnullGCPtr(T& ptr)
+        : m_ptr(&ptr)
+    {
+    }
+
+    NonnullGCPtr(T const& ptr)
+        : m_ptr(&const_cast<T&>(ptr))
+    {
+    }
+
+    template<typename U>
+    NonnullGCPtr(U& ptr) requires(IsConvertible<U*, T*>)
+        : m_ptr(&static_cast<T&>(ptr))
+    {
+    }
+
+    template<typename U>
+    NonnullGCPtr(U const& ptr) requires(IsConvertible<U*, T*>)
+        : m_ptr(&const_cast<T&>(static_cast<T const&>(ptr)))
+    {
+    }
+
+    template<typename U>
+    NonnullGCPtr(NonnullGCPtr<U> ptr) requires(IsConvertible<U*, T*>)
+        : m_ptr(ptr)
+    {
+    }
+
+    NonnullGCPtr& operator=(GCPtr<T> const& other)
+    {
+        m_ptr = const_cast<T*>(other.ptr());
+        return *this;
+    }
+
+    NonnullGCPtr& operator=(T const& other)
+    {
+        m_ptr = &const_cast<T&>(other);
+        return *this;
+    }
+
+    template<typename U>
+    NonnullGCPtr& operator=(U const& other) requires(IsConvertible<U*, T*>)
+    {
+        m_ptr = &const_cast<T&>(static_cast<T const&>(other));
+        return *this;
+    }
+
+    template<typename U>
+    NonnullGCPtr& operator=(NonnullGCPtr<U> const& other) requires(IsConvertible<U*, T*>)
+    {
+        m_ptr = const_cast<T*>(static_cast<T const*>(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<typename T>
+class GCPtr {
+public:
+    GCPtr() = default;
+
+    GCPtr(T& ptr)
+        : m_ptr(&ptr)
+    {
+    }
+
+    GCPtr(T const& ptr)
+        : m_ptr(&const_cast<T&>(ptr))
+    {
+    }
+
+    GCPtr(T* ptr)
+        : m_ptr(ptr)
+    {
+    }
+
+    GCPtr(T const* ptr)
+        : m_ptr(const_cast<T*>(ptr))
+    {
+    }
+
+    GCPtr(NonnullGCPtr<T> ptr)
+        : m_ptr(ptr)
+    {
+    }
+
+    template<typename U>
+    GCPtr(NonnullGCPtr<U> ptr) requires(IsConvertible<U*, T*>)
+        : m_ptr(ptr)
+    {
+    }
+
+    GCPtr(std::nullptr_t)
+        : m_ptr(nullptr)
+    {
+    }
+
+    GCPtr(GCPtr const&) = default;
+    GCPtr& operator=(GCPtr const&) = default;
+
+    template<typename U>
+    GCPtr& operator=(GCPtr<U> const& other) requires(IsConvertible<U*, T*>)
+    {
+        m_ptr = const_cast<T*>(static_cast<T const*>(other.ptr()));
+        return *this;
+    }
+
+    GCPtr& operator=(NonnullGCPtr<T> const& other)
+    {
+        m_ptr = const_cast<T*>(other.ptr());
+        return *this;
+    }
+
+    template<typename U>
+    GCPtr& operator=(NonnullGCPtr<U> const& other) requires(IsConvertible<U*, T*>)
+    {
+        m_ptr = const_cast<T*>(static_cast<T const*>(other.ptr()));
+        return *this;
+    }
+
+    GCPtr& operator=(T const& other)
+    {
+        m_ptr = &const_cast<T&>(other);
+        return *this;
+    }
+
+    template<typename U>
+    GCPtr& operator=(U const& other) requires(IsConvertible<U*, T*>)
+    {
+        m_ptr = &const_cast<T&>(static_cast<T const&>(other));
+        return *this;
+    }
+
+    GCPtr& operator=(T const* other)
+    {
+        m_ptr = const_cast<T*>(other);
+        return *this;
+    }
+
+    template<typename U>
+    GCPtr& operator=(U const* other) requires(IsConvertible<U*, T*>)
+    {
+        m_ptr = const_cast<T*>(static_cast<T const*>(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<typename T, typename U>
+inline bool operator==(GCPtr<T> const& a, GCPtr<U> const& b)
+{
+    return a.ptr() == b.ptr();
+}
+
+template<typename T, typename U>
+inline bool operator==(GCPtr<T> const& a, NonnullGCPtr<U> const& b)
+{
+    return a.ptr() == b.ptr();
+}
+
+template<typename T, typename U>
+inline bool operator==(NonnullGCPtr<T> const& a, NonnullGCPtr<U> const& b)
+{
+    return a.ptr() == b.ptr();
+}
+
+template<typename T, typename U>
+inline bool operator==(NonnullGCPtr<T> const& a, GCPtr<U> const& b)
+{
+    return a.ptr() == b.ptr();
+}
+
+template<typename T, typename U>
+inline bool operator==(NonnullGCPtr<T> const& a, U const* b)
+{
+    return a.ptr() == b;
+}
+
+template<typename T, typename U>
+inline bool operator==(GCPtr<T> const& a, U const* b)
+{
+    return a.ptr() == b;
+}
+
+}