slint/api/sixtyfps-cpp/include/vtable.h
Olivier Goffart 3194dd21ca Expose VRc to the C++ API
(Not yet in use in the code gen)
2020-11-10 12:43:19 +01:00

152 lines
3.4 KiB
C++

/* LICENSE BEGIN
This file is part of the SixtyFPS Project -- https://sixtyfps.io
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
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 <cstddef>
#include <new>
#include <algorithm>
#include <optional>
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 VBox = VRefMut<T>;
template<typename T>
using Pin = T;
/*
template<typename T>
struct VBox {
const T *vtable;
void *instance;
};
template<typename T>
struct VRef {
const T *vtable;
const void *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:
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