/* LICENSE BEGIN This file is part of the SixtyFPS Project -- https://sixtyfps.io Copyright (c) 2020 Olivier Goffart Copyright (c) 2020 Simon Hausmann SPDX-License-Identifier: GPL-3.0-only This file is also available under commercial licensing terms. Please contact info@sixtyfps.io for more information. LICENSE END */ #pragma once #include #include #include #include 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 VBox = VRefMut; template using Pin = T; /* template struct VBox { const T *vtable; void *instance; }; template struct VRef { const T *vtable; const void *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: const VTable *vtable; int strong_ref; int weak_ref; union { X data; Layout layout; }; }; 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->data); layout.size += sizeof(const VTable *) + 2 * sizeof(int); layout.align = std::max(layout.align, alignof(VRcInner)); inner->layout = layout; if (--inner->weak_ref) { inner->vtable->dealloc(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; } template static VRc make(Args... args) { return VRc(new VRcInner{ X::component_type, 1, 1, X(args...) }); } const X* operator->() const { return inner->data; } }; template class VWeak { VRcInner *inner = nullptr; public: VWeak() = default; ~VWeak() { if (inner && --inner->weak_ref) { inner->vtable->dealloc(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) }; } }; } //namespace vtable