// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 #pragma once #include #include #include #include #include #ifdef __APPLE__ # include #endif namespace vtable { template struct VRefMut { const T *vtable; void *instance; }; struct Layout { std::size_t size; std::size_t align; }; // For the C++'s purpose, they are all the same template using VRef = VRefMut; template using Pin = T; template struct VBox { const T *vtable = nullptr; void *instance = nullptr; explicit VBox(const T *vtable, void *instance) : vtable(vtable), instance(instance) { } VBox(const VBox &) = delete; VBox() = default; VBox &operator=(const VBox &) = delete; ~VBox() { if (vtable && instance) { vtable->drop({ vtable, instance }); } } }; struct AllowPin; template struct VOffset { const T *vtable; std::uintptr_t offset; }; template struct VRcInner { template friend class VRc; template friend class VWeak; private: VRcInner() : layout {} { } const VTable *vtable = &X::static_vtable; std::atomic strong_ref = 1; std::atomic weak_ref = 1; std::uint16_t data_offset = offsetof(VRcInner, data); union { X data; Layout layout; }; void *data_ptr() { return reinterpret_cast(this) + data_offset; } ~VRcInner() = delete; }; struct Dyn { }; template class VRc { VRcInner *inner; VRc(VRcInner *inner) : inner(inner) { } template friend class VWeak; public: ~VRc() { if (!--inner->strong_ref) { Layout layout = inner->vtable->drop_in_place({ inner->vtable, &inner->data }); layout.size = std::max(layout.size, sizeof(Layout)); // because of the union layout.size += inner->data_offset; layout.align = std::max(layout.align, alignof(VRcInner)); inner->layout = layout; if (!--inner->weak_ref) { inner->vtable->dealloc(inner->vtable, reinterpret_cast(inner), layout); } } } VRc(const VRc &other) : inner(other.inner) { inner->strong_ref++; } VRc &operator=(const VRc &other) { if (inner == other.inner) return *this; this->~VRc(); new (this) VRc(other); return *this; } /// Construct a new VRc holding an X. /// /// The type X must have a static member `static_vtable` of type VTable template static VRc make(Args... args) { #if !defined(__APPLE__) || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 auto mem = ::operator new(sizeof(VRcInner), static_cast(alignof(VRcInner))); #else auto mem = ::operator new(sizeof(VRcInner)); #endif auto inner = new (mem) VRcInner; new (&inner->data) X(args...); return VRc(inner); } const X *operator->() const { return &inner->data; } const X &operator*() const { return inner->data; } X *operator->() { return &inner->data; } X &operator*() { return inner->data; } const VRc &into_dyn() const { return *reinterpret_cast *>(this); } VRef borrow() const { return { inner->vtable, inner->data_ptr() }; } friend bool operator==(const VRc &a, const VRc &b) { return a.inner == b.inner; } friend bool operator!=(const VRc &a, const VRc &b) { return a.inner != b.inner; } const VTable *vtable() const { return inner->vtable; } }; template class VWeak { VRcInner *inner = nullptr; public: VWeak() = default; ~VWeak() { if (inner && !--inner->weak_ref) { inner->vtable->dealloc(inner->vtable, reinterpret_cast(inner), inner->layout); } } VWeak(const VWeak &other) : inner(other.inner) { inner && inner->weak_ref++; } VWeak(const VRc &other) : inner(other.inner) { inner && inner->weak_ref++; } VWeak &operator=(const VWeak &other) { if (inner == other.inner) return *this; this->~VWeak(); new (this) VWeak(other); return *this; } std::optional> lock() const { if (!inner || inner->strong_ref == 0) return {}; inner->strong_ref++; return { VRc(inner) }; } const VWeak &into_dyn() const { return *reinterpret_cast *>(this); } friend bool operator==(const VWeak &a, const VWeak &b) { return a.inner == b.inner; } friend bool operator!=(const VWeak &a, const VWeak &b) { return a.inner != b.inner; } const VTable *vtable() const { return inner ? inner->vtable : nullptr; } }; template class VRcMapped { VRc parent_strong; MappedType *object; template friend class VWeakMapped; public: /// Constructs a pointer to MappedType that shares ownership with parent_strong. template explicit VRcMapped(VRc parent_strong, MappedType *object) : parent_strong(parent_strong.into_dyn()), object(object) { } const MappedType *operator->() const { return object; } const MappedType &operator*() const { return *object; } MappedType *operator->() { return object; } MappedType &operator*() { return *object; } }; template class VWeakMapped { VWeak parent_weak; MappedType *object = nullptr; public: VWeakMapped(const VRcMapped &strong) : parent_weak(strong.parent_strong), object(strong.object) { } VWeakMapped() = default; std::optional> lock() const { if (auto parent = parent_weak.lock()) { return VRcMapped(std::move(*parent), object); } else { return {}; } } }; } // namespace vtable