/* * 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; } }