mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
* add some clang-format offs. * add formats. * format the world. * AllowShortIfStatementsOnASingleLine * off REGION. * Rollback vm.hpp * Disable insert.
114 lines
3.0 KiB
C++
114 lines
3.0 KiB
C++
#pragma once
|
|
|
|
#include "pocketpy/common/traits.hpp"
|
|
|
|
#include <typeindex>
|
|
#include <cassert>
|
|
#include <utility>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
namespace pkpy {
|
|
|
|
template <typename T>
|
|
constexpr inline bool is_any_sso_v = is_pod_v<T> && sizeof(T) <= sizeof(void*);
|
|
|
|
struct any {
|
|
struct vtable {
|
|
const std::type_index type;
|
|
void (*deleter)(void*);
|
|
|
|
template <typename T>
|
|
inline static vtable* get() {
|
|
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
|
if constexpr(is_any_sso_v<T>) {
|
|
static vtable vt{typeid(T), nullptr};
|
|
return &vt;
|
|
} else {
|
|
static vtable vt{typeid(T), [](void* ptr) {
|
|
delete static_cast<T*>(ptr);
|
|
}};
|
|
return &vt;
|
|
}
|
|
}
|
|
};
|
|
|
|
void* data;
|
|
vtable* _vt;
|
|
|
|
any() : data(nullptr), _vt(nullptr) {}
|
|
|
|
explicit operator bool () const { return _vt != nullptr; }
|
|
|
|
template <typename T>
|
|
any(T&& value) {
|
|
using U = std::decay_t<T>;
|
|
static_assert(!std::is_same_v<U, any>, "any(const any&) is deleted");
|
|
static_assert(sizeof(U) == sizeof(T));
|
|
if constexpr(is_any_sso_v<U>) {
|
|
std::memcpy(&data, &value, sizeof(U));
|
|
} else {
|
|
data = new U(std::forward<T>(value));
|
|
}
|
|
_vt = vtable::get<U>();
|
|
}
|
|
|
|
any(any&& other) noexcept;
|
|
any& operator= (any&& other) noexcept;
|
|
|
|
const std::type_index type_id() const { return _vt ? _vt->type : typeid(void); }
|
|
|
|
any(const any& other) = delete;
|
|
any& operator= (const any& other) = delete;
|
|
|
|
~any() {
|
|
if(_vt && _vt->deleter) _vt->deleter(data);
|
|
}
|
|
|
|
template <typename T>
|
|
T& _cast() const noexcept {
|
|
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
|
if constexpr(is_any_sso_v<T>) {
|
|
return *((T*)(&data));
|
|
} else {
|
|
return *(static_cast<T*>(data));
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
T& cast() const {
|
|
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
|
if(type_id() != typeid(T)) __bad_any_cast(typeid(T), type_id());
|
|
return _cast<T>();
|
|
}
|
|
|
|
static void __bad_any_cast(const std::type_index expected, const std::type_index actual);
|
|
};
|
|
|
|
template <typename T>
|
|
struct function;
|
|
|
|
template <typename Ret, typename... Params>
|
|
struct function<Ret(Params...)> {
|
|
any _impl;
|
|
Ret (*_wrapper)(const any&, Params...);
|
|
|
|
function() : _impl(), _wrapper(nullptr) {}
|
|
|
|
explicit operator bool () const { return _wrapper != nullptr; }
|
|
|
|
template <typename F>
|
|
function(F&& f) : _impl(std::forward<F>(f)) {
|
|
_wrapper = [](const any& impl, Params... params) -> Ret {
|
|
return impl._cast<std::decay_t<F>>()(std::forward<Params>(params)...);
|
|
};
|
|
}
|
|
|
|
Ret operator() (Params... params) const {
|
|
assert(_wrapper);
|
|
return _wrapper(_impl, std::forward<Params>(params)...);
|
|
}
|
|
};
|
|
|
|
} // namespace pkpy
|