70 lines
2.2 KiB
C++

#pragma once
#include <cstring>
#include <utility>
// Duplicate VTable
template <typename T>
T *extend_dup_vtable(T *vtable) {
// Get Size
const unsigned char *const real_vtable = ((const unsigned char *) vtable) - sizeof(void *);
constexpr size_t real_vtable_size = sizeof(T) + sizeof(void *);
// Allocate
unsigned char *const new_vtable = (unsigned char *) ::operator new(real_vtable_size);
T *ret = (T *) (new_vtable + sizeof(void *));
new (ret) T;
// Copy
memcpy(new_vtable, real_vtable, real_vtable_size);
// Return
return ret;
}
// Customize VTable
template <typename T, void (*setup_vtable)(T *)>
T *extend_get_vtable() {
static T *vtable = nullptr;
if (!vtable) {
vtable = extend_dup_vtable(T::base);
setup_vtable(vtable);
}
return vtable;
}
#define CUSTOM_VTABLE(name, parent) \
static void setup_##name##_vtable(parent##_vtable *); \
static parent##_vtable *get_##name##_vtable() { \
return extend_get_vtable<parent##_vtable, setup_##name##_vtable>(); \
} \
static void setup_##name##_vtable(parent##_vtable *vtable)
// Extend MCPI Classes
template <typename Self, typename Data>
Data *extend_get_data(Self *self) {
return (Data *) (self + 1);
}
template <typename Data, typename Self = typename Data::_Self>
auto extend_struct(auto&&... args) -> decltype(Self::allocate()) {
constexpr size_t size = sizeof(Self) + sizeof(Data);
Self *out = (Self *) ::operator new(size);
Data *data = extend_get_data<Self, Data>(out);
new (data) Data(std::forward<decltype(args)>(args)...);
return out;
}
// Helpers
#define CREATE_HELPER(name) \
struct Custom##name { \
using _Self = name; \
explicit Custom##name(auto&&... args): self(((name *) this) - 1) { \
self->constructor(std::forward<decltype(args)>(args)...); \
self->vtable = get_vtable(); \
} \
_Self *const self; \
static name##_vtable *get_vtable(); \
private: \
static void setup_vtable(name##_vtable *vtable); \
protected: \
virtual ~Custom##name() = default; \
public:
#include "Screen.h"
#include "DynamicTexture.h"
#undef CREATE_HELPER