Expose VRc to the C++ API

(Not yet in use in the code gen)
This commit is contained in:
Olivier Goffart 2020-11-10 12:43:19 +01:00
parent 503567d84c
commit 3194dd21ca
3 changed files with 138 additions and 8 deletions

View file

@ -272,7 +272,7 @@ inline FocusEventResult process_focus_event(ComponentRef component, int64_t &foc
void dealloc(const ComponentVTable*, uint8_t *ptr, vtable::Layout layout) {
#ifdef __cpp_sized_deallocation
::operator delete(reinterpret_cast<void*>(ptr), layout.size, layout.align);
::operator delete(reinterpret_cast<void*>(ptr), layout.size, static_cast<std::align_val_t>(layout.align));
#else
::operator delete(reinterpret_cast<void*>(ptr));
#endif
@ -281,10 +281,44 @@ void dealloc(const ComponentVTable*, uint8_t *ptr, vtable::Layout layout) {
template<typename T> vtable::Layout drop_in_place(ComponentRef component) {
reinterpret_cast<T*>(component.instance)->~T();
return vtable::Layout { sizeof(T), std::align_val_t(alignof(T)) };
return vtable::Layout { sizeof(T), alignof(T) };
}
} // namespace private_api
template<typename T> class ComponentWeakHandle;
/// The component handle is like a shared pointer to a component in the generated code.
/// In order to get a component, use `T::create()` where T is the name of the component
/// in the .60 file. This give you a `ComponentHandle<T>`
template<typename T>
class ComponentHandle {
vtable::VRc<private_api::ComponentVTable, T> inner;
friend class ComponentWeakHandle<T>;
public:
/// internal constructor
ComponentHandle(const vtable::VRc<private_api::ComponentVTable, T> &inner) : inner(inner) { }
const T* operator->() const {
return inner.operator->();
}
};
/// A weak reference to the component. Can be constructed from a `ComponentHandle<T>`
template<typename T>
class ComponentWeakHandle {
vtable::VWeak<private_api::ComponentVTable, T> inner;
public:
ComponentWeakHandle() = default;
ComponentWeakHandle(const ComponentHandle<T>&other) : inner(other.inner) {}
std::optional<ComponentHandle<T>> lock() {
if (auto l = inner.lock()) {
return { ComponentHandle(*l) };
} else {
return {};
}
}
};
// layouts:
using cbindgen_private::grid_layout_info;
using cbindgen_private::GridLayoutCellData;

View file

@ -11,6 +11,8 @@ LICENSE END */
#include <cstddef>
#include <new>
#include <algorithm>
#include <optional>
namespace vtable {
@ -23,7 +25,7 @@ struct VRefMut
struct Layout {
std::size_t size;
std::align_val_t align;
std::size_t align;
};
// For the C++'s purpose, they are all the same
@ -58,5 +60,93 @@ struct VOffset
std::uintptr_t offset;
};
template<typename VTable, typename X>
struct VRcInner {
template<typename VTable_, typename X_> friend class VRc;
template<typename VTable_, typename X_> friend class VWeak;
private:
const VTable *vtable;
int strong_ref;
int weak_ref;
union {
X data;
Layout layout;
};
};
struct Dyn {};
template<typename VTable, typename X = Dyn>
class VRc {
VRcInner<VTable, X> *inner;
VRc(VRcInner<VTable, X> inner) : inner(inner) {}
template<typename VTable_, typename X_> 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<size_t>(layout.align, alignof(VRcInner<VTable, Dyn>));
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<typename ...Args> static VRc make(Args... args) {
return VRc(new VRcInner<VTable, X>{
X::component_type, 1, 1, X(args...)
});
}
const X* operator->() const {
return inner->data;
}
};
template<typename VTable, typename X = Dyn>
class VWeak {
VRcInner<VTable, X> *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<VTable, X> &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<VRc<VTable, X>> lock() const {
if (!inner || inner->strong_ref == 0)
return {};
inner->strong_ref++;
return { VRc<VTable, X>(inner) };
}
};
} //namespace vtable

View file

@ -10,9 +10,9 @@ LICENSE END */
//! implementation of vtable::Vrc
use core::cell::Cell;
use super::*;
use core::cell::Cell;
use core::convert::TryInto;
/// This trait is implemented by the `#[vtable]` macro.
///
@ -85,7 +85,13 @@ impl<VTable: VTableMetaDropInPlace + 'static, X: ?Sized> Drop for VRc<VTable, X>
inner.strong_ref.set(inner.strong_ref.get() - 1);
if inner.strong_ref.get() == 0 {
let data = &inner.data as *const _ as *const u8 as *mut u8;
let layout = VTable::drop_in_place(inner.vtable, data);
let mut layout = VTable::drop_in_place(inner.vtable, data);
layout = core::alloc::Layout::new::<VRcInner<VTable, ()>>()
.extend(layout.try_into().unwrap())
.unwrap()
.0
.pad_to_align()
.into();
inner.weak_ref.set(inner.weak_ref.get() - 1);
if inner.weak_ref.get() == 0 {
let vtable = inner.vtable;
@ -106,7 +112,7 @@ impl<VTable: VTableMetaDropInPlace, X: HasStaticVTable<VTable>> VRc<VTable, X> {
/// (the `HasStaticVTable` is implemented by the `“MyTrait”VTable_static!` macro generated by
/// the #[vtable] macro)
pub fn new(data: X) -> Self {
let layout = core::alloc::Layout::new::<VRcInner<VTable, X>>();
let layout = core::alloc::Layout::new::<VRcInner<VTable, X>>().pad_to_align();
// We must ensure the size is enough to hold a Layout when stonr_count becomes 0
let layout_with_layout = core::alloc::Layout::new::<VRcInner<VTable, Layout>>();
let layout = core::alloc::Layout::from_size_align(