mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-03 18:29:09 +00:00

In the compiler this is still very primitive, but an attempt to start a generic interface. The basic assumption is that all item functions will eventually need access to the window adapter and itemrc. Support for additional arguments is still missing. Also missing is support for the function access via rtti in the interpreter, hence the hardcoding at the moment.
221 lines
5.2 KiB
C++
221 lines
5.2 KiB
C++
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
|
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
|
|
|
#pragma once
|
|
|
|
#include <cstddef>
|
|
#include <new>
|
|
#include <algorithm>
|
|
#include <optional>
|
|
#include <atomic>
|
|
|
|
#ifdef __APPLE__
|
|
# include <AvailabilityMacros.h>
|
|
#endif
|
|
|
|
namespace vtable {
|
|
|
|
template<typename T>
|
|
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<typename T>
|
|
using VRef = VRefMut<T>;
|
|
|
|
template<typename T>
|
|
using Pin = T;
|
|
|
|
template<typename T>
|
|
struct VBox
|
|
{
|
|
const T *vtable = nullptr;
|
|
void *instance = nullptr;
|
|
VBox(const VBox &) = delete;
|
|
VBox() = default;
|
|
VBox &operator=(const VBox &) = delete;
|
|
~VBox()
|
|
{
|
|
if (vtable && instance) {
|
|
vtable->drop({ vtable, instance });
|
|
}
|
|
}
|
|
};
|
|
|
|
struct AllowPin;
|
|
|
|
template<typename Base, typename T, typename Flag = void>
|
|
struct VOffset
|
|
{
|
|
const T *vtable;
|
|
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:
|
|
VRcInner() : layout {} { }
|
|
const VTable *vtable = &X::static_vtable;
|
|
std::atomic<int> strong_ref = 1;
|
|
std::atomic<int> weak_ref = 1;
|
|
std::uint16_t data_offset = offsetof(VRcInner, data);
|
|
union {
|
|
X data;
|
|
Layout layout;
|
|
};
|
|
|
|
void *data_ptr() { return reinterpret_cast<char *>(this) + data_offset; }
|
|
~VRcInner() = delete;
|
|
};
|
|
|
|
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->vtable, &inner->data });
|
|
layout.size += inner->data_offset;
|
|
layout.align = std::max<size_t>(layout.align, alignof(VRcInner<VTable, Dyn>));
|
|
inner->layout = layout;
|
|
if (!--inner->weak_ref) {
|
|
inner->vtable->dealloc(inner->vtable, reinterpret_cast<uint8_t *>(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<typename... Args>
|
|
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<VTable, X>),
|
|
static_cast<std::align_val_t>(alignof(VRcInner<VTable, X>)));
|
|
#else
|
|
auto mem = ::operator new(sizeof(VRcInner<VTable, X>));
|
|
#endif
|
|
auto inner = new (mem) VRcInner<VTable, X>;
|
|
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<VTable, Dyn> &into_dyn() const
|
|
{
|
|
return *reinterpret_cast<const VRc<VTable, Dyn> *>(this);
|
|
}
|
|
|
|
VRef<VTable> 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<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->vtable, reinterpret_cast<uint8_t *>(inner),
|
|
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) };
|
|
}
|
|
|
|
const VWeak<VTable, Dyn> &into_dyn() const
|
|
{
|
|
return *reinterpret_cast<const VWeak<VTable, Dyn> *>(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; }
|
|
};
|
|
|
|
} // namespace vtable
|