dungeon/libs/kaguya-1.3.2/include/kaguya/object.hpp

808 lines
28 KiB
C++
Raw Normal View History

// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <string>
#include <cstring>
#include <typeinfo>
#include <algorithm>
#include "kaguya/config.hpp"
#include "kaguya/utility.hpp"
#include "kaguya/traits.hpp"
#include "kaguya/exception.hpp"
namespace kaguya {
namespace types {
template <typename T> struct typetag {};
}
inline void *metatable_name_key() {
static int key;
return &key;
}
inline void *metatable_type_table_key() {
static int key;
return &key;
}
template <typename T> const std::type_info &metatableType() {
return typeid(typename traits::decay<T>::type);
}
template <typename T> inline std::string metatableName() {
return util::pretty_name(metatableType<T>());
}
struct ObjectWrapperBase {
virtual const void *cget() = 0;
virtual void *get() = 0;
virtual const std::type_info &type() = 0;
virtual const std::type_info &native_type() { return type(); }
virtual void *native_get() { return get(); }
ObjectWrapperBase() {}
virtual ~ObjectWrapperBase() {}
private:
// noncopyable
ObjectWrapperBase(const ObjectWrapperBase &);
ObjectWrapperBase &operator=(const ObjectWrapperBase &);
};
template <class T> struct ObjectWrapper : ObjectWrapperBase {
#if KAGUYA_USE_CPP11
template <class... Args>
ObjectWrapper(Args &&... args) : object_(std::forward<Args>(args)...) {}
#else
ObjectWrapper() : object_() {}
#define KAGUYA_OBJECT_WRAPPER_CONSTRUCTOR_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
ObjectWrapper(KAGUYA_PP_ARG_DEF_REPEAT(N)) \
: object_(KAGUYA_PP_ARG_REPEAT(N)) {}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS,
KAGUYA_OBJECT_WRAPPER_CONSTRUCTOR_DEF)
#undef KAGUYA_OBJECT_WRAPPER_CONSTRUCTOR_DEF
#endif
virtual const std::type_info &type() { return metatableType<T>(); }
virtual void *get() { return &object_; }
virtual const void *cget() { return &object_; }
private:
T object_;
};
struct ObjectSharedPointerWrapper : ObjectWrapperBase {
template <typename T>
ObjectSharedPointerWrapper(const standard::shared_ptr<T> &sptr)
: object_(standard::const_pointer_cast<
typename standard::remove_const<T>::type>(sptr)),
type_(metatableType<T>()),
shared_ptr_type_(
metatableType<
standard::shared_ptr<typename traits::decay<T>::type> >()),
const_value_(traits::is_const<T>::value) {}
#if KAGUYA_USE_RVALUE_REFERENCE
template <typename T>
ObjectSharedPointerWrapper(standard::shared_ptr<T> &&sptr)
: object_(std::move(standard::const_pointer_cast<
typename standard::remove_const<T>::type>(sptr))),
type_(metatableType<T>()),
shared_ptr_type_(
metatableType<
standard::shared_ptr<typename traits::decay<T>::type> >()),
const_value_(traits::is_const<T>::value) {}
#endif
virtual const std::type_info &type() { return type_; }
virtual void *get() { return const_value_ ? 0 : object_.get(); }
virtual const void *cget() { return object_.get(); }
standard::shared_ptr<void> object() const {
return const_value_ ? standard::shared_ptr<void>() : object_;
}
standard::shared_ptr<const void> const_object() const { return object_; }
const std::type_info &shared_ptr_type() const { return shared_ptr_type_; }
virtual const std::type_info &native_type() {
return metatableType<standard::shared_ptr<void> >();
}
virtual void *native_get() { return &object_; }
private:
standard::shared_ptr<void> object_;
const std::type_info &type_;
const std::type_info &shared_ptr_type_;
bool const_value_;
};
template <typename T, typename ElementType = typename T::element_type>
struct ObjectSmartPointerWrapper : ObjectWrapperBase {
ObjectSmartPointerWrapper(const T &sptr) : object_(sptr) {}
#if KAGUYA_USE_RVALUE_REFERENCE
ObjectSmartPointerWrapper(T &&sptr) : object_(std::move(sptr)) {}
#endif
virtual const std::type_info &type() { return metatableType<ElementType>(); }
virtual void *get() { return object_ ? &(*object_) : 0; }
virtual const void *cget() { return object_ ? &(*object_) : 0; }
virtual const std::type_info &native_type() { return metatableType<T>(); }
virtual void *native_get() { return &object_; }
private:
T object_;
};
template <class T> struct ObjectPointerWrapper : ObjectWrapperBase {
ObjectPointerWrapper(T *ptr) : object_(ptr) {}
virtual const std::type_info &type() { return metatableType<T>(); }
virtual void *get() {
if (traits::is_const<T>::value) {
return 0;
}
return const_cast<void *>(static_cast<const void *>(object_));
}
virtual const void *cget() { return object_; }
~ObjectPointerWrapper() {}
protected:
T *object_;
};
// Customizable for ObjectPointerWrapper
template <class T, class Enable = void> struct ObjectPointerWrapperType {
typedef ObjectPointerWrapper<T> type;
};
// for internal use
struct PointerConverter {
template <typename T, typename F> static void *base_pointer_cast(void *from) {
return static_cast<T *>(static_cast<F *>(from));
}
template <typename T, typename F>
static standard::shared_ptr<void>
base_shared_pointer_cast(const standard::shared_ptr<void> &from) {
return standard::shared_ptr<T>(standard::static_pointer_cast<F>(from));
}
typedef void *(*convert_function_type)(void *);
typedef standard::shared_ptr<void> (*shared_ptr_convert_function_type)(
const standard::shared_ptr<void> &);
typedef std::pair<std::string, std::string> convert_map_key;
template <typename ToType, typename FromType> void add_type_conversion() {
add_function(metatableType<ToType>(), metatableType<FromType>(),
&base_pointer_cast<ToType, FromType>);
add_function(metatableType<standard::shared_ptr<ToType> >(),
metatableType<standard::shared_ptr<FromType> >(),
&base_shared_pointer_cast<ToType, FromType>);
}
template <typename TO> TO *get_pointer(ObjectWrapperBase *from) const {
const std::type_info &to_type = metatableType<TO>();
// unreachable
// if (to_type == from->type())
//{
// return static_cast<TO*>(from->get());
//}
std::map<convert_map_key,
std::vector<convert_function_type> >::const_iterator match =
function_map_.find(
convert_map_key(to_type.name(), from->type().name()));
if (match != function_map_.end()) {
return static_cast<TO *>(pcvt_list_apply(from->get(), match->second));
}
return 0;
}
template <typename TO>
const TO *get_const_pointer(ObjectWrapperBase *from) const {
const std::type_info &to_type = metatableType<TO>();
// unreachable
// if (to_type == from->type())
//{
// return static_cast<const TO*>(from->cget());
//}
std::map<convert_map_key,
std::vector<convert_function_type> >::const_iterator match =
function_map_.find(
convert_map_key(to_type.name(), from->type().name()));
if (match != function_map_.end()) {
return static_cast<const TO *>(
pcvt_list_apply(const_cast<void *>(from->cget()), match->second));
}
return 0;
}
template <typename TO>
standard::shared_ptr<TO>
get_shared_pointer(ObjectSharedPointerWrapper *from) const {
const std::type_info &to_type = metatableType<
standard::shared_ptr<typename traits::decay<TO>::type> >();
// unreachable
// if (to_type == from->type())
// {
// return
//standard::static_pointer_cast<TO>(from->object());
// }
const std::type_info &from_type = from->shared_ptr_type();
std::map<convert_map_key,
std::vector<shared_ptr_convert_function_type> >::const_iterator
match = shared_ptr_function_map_.find(
convert_map_key(to_type.name(), from_type.name()));
if (match != shared_ptr_function_map_.end()) {
standard::shared_ptr<void> sptr = from->object();
if (!sptr && standard::is_const<TO>::value) {
sptr = standard::const_pointer_cast<void>(from->const_object());
}
return standard::static_pointer_cast<TO>(
pcvt_list_apply(sptr, match->second));
}
return standard::shared_ptr<TO>();
}
template <class T>
T *get_pointer(ObjectWrapperBase *from, types::typetag<T>) {
return get_pointer<T>(from);
}
template <class T>
standard::shared_ptr<T>
get_pointer(ObjectWrapperBase *from,
types::typetag<standard::shared_ptr<T> >) {
ObjectSharedPointerWrapper *ptr =
dynamic_cast<ObjectSharedPointerWrapper *>(from);
if (ptr) {
return get_shared_pointer<T>(ptr);
}
return standard::shared_ptr<T>();
}
static int deleter(lua_State *state) {
PointerConverter *ptr = (PointerConverter *)lua_touserdata(state, 1);
ptr->~PointerConverter();
return 0;
}
static PointerConverter &get(lua_State *state) {
static char kaguya_ptrcvt_key_ptr;
util::ScopedSavedStack save(state);
lua_pushlightuserdata(state, &kaguya_ptrcvt_key_ptr);
lua_rawget(state, LUA_REGISTRYINDEX);
if (lua_isuserdata(state, -1)) {
return *static_cast<PointerConverter *>(lua_touserdata(state, -1));
} else {
void *ptr = lua_newuserdata(
state, sizeof(PointerConverter)); // dummy data for gc call
PointerConverter *converter = new (ptr) PointerConverter();
lua_createtable(state, 0, 2);
lua_pushcclosure(state, &deleter, 0);
lua_setfield(state, -2, "__gc");
lua_pushvalue(state, -1);
lua_setfield(state, -2, "__index");
lua_setmetatable(state, -2); // set to userdata
lua_pushlightuserdata(state, &kaguya_ptrcvt_key_ptr);
lua_pushvalue(state, -2);
lua_rawset(state, LUA_REGISTRYINDEX);
return *converter;
}
}
private:
void add_function(const std::type_info &to_type,
const std::type_info &from_type, convert_function_type f) {
std::map<convert_map_key, std::vector<convert_function_type> > add_map;
for (std::map<convert_map_key,
std::vector<convert_function_type> >::iterator it =
function_map_.begin();
it != function_map_.end(); ++it) {
if (it->first.second == to_type.name()) {
std::vector<convert_function_type> newlist;
newlist.push_back(f);
newlist.insert(newlist.end(), it->second.begin(), it->second.end());
add_map[convert_map_key(it->first.first, from_type.name())] = newlist;
}
}
function_map_.insert(add_map.begin(), add_map.end());
std::vector<convert_function_type> flist;
flist.push_back(f);
function_map_[convert_map_key(to_type.name(), from_type.name())] = flist;
}
void add_function(const std::type_info &to_type,
const std::type_info &from_type,
shared_ptr_convert_function_type f) {
std::map<convert_map_key, std::vector<shared_ptr_convert_function_type> >
add_map;
for (std::map<convert_map_key,
std::vector<shared_ptr_convert_function_type> >::iterator it =
shared_ptr_function_map_.begin();
it != shared_ptr_function_map_.end(); ++it) {
if (it->first.second == to_type.name()) {
std::vector<shared_ptr_convert_function_type> newlist;
newlist.push_back(f);
newlist.insert(newlist.end(), it->second.begin(), it->second.end());
add_map[convert_map_key(it->first.first, from_type.name())] = newlist;
}
}
shared_ptr_function_map_.insert(add_map.begin(), add_map.end());
std::vector<shared_ptr_convert_function_type> flist;
flist.push_back(f);
shared_ptr_function_map_[convert_map_key(to_type.name(),
from_type.name())] = flist;
}
void *pcvt_list_apply(void *ptr,
const std::vector<convert_function_type> &flist) const {
for (std::vector<convert_function_type>::const_iterator i = flist.begin();
i != flist.end(); ++i) {
ptr = (*i)(ptr);
}
return ptr;
}
standard::shared_ptr<void> pcvt_list_apply(
standard::shared_ptr<void> ptr,
const std::vector<shared_ptr_convert_function_type> &flist) const {
for (std::vector<shared_ptr_convert_function_type>::const_iterator i =
flist.begin();
i != flist.end(); ++i) {
#if KAGUYA_USE_CPP11
ptr = (*i)(std::move(ptr));
#else
ptr = (*i)(ptr);
#endif
}
return ptr;
}
PointerConverter() {}
std::map<convert_map_key, std::vector<convert_function_type> > function_map_;
std::map<convert_map_key, std::vector<shared_ptr_convert_function_type> >
shared_ptr_function_map_;
PointerConverter(PointerConverter &);
PointerConverter &operator=(PointerConverter &);
};
namespace detail {
inline bool object_wrapper_type_check(lua_State *l, int index) {
#if KAGUYA_NO_USERDATA_TYPE_CHECK
return lua_isuserdata(l, index) && !lua_islightuserdata(l, index);
#endif
if (lua_getmetatable(l, index)) {
int type = lua_rawgetp_rtype(l, -1, metatable_name_key());
lua_pop(l, 2);
return type == LUA_TSTRING;
}
return false;
}
}
inline ObjectWrapperBase *object_wrapper(lua_State *l, int index) {
if (detail::object_wrapper_type_check(l, index)) {
ObjectWrapperBase *ptr =
static_cast<ObjectWrapperBase *>(lua_touserdata(l, index));
return ptr;
}
return 0;
}
template <typename RequireType>
inline ObjectWrapperBase *
object_wrapper(lua_State *l, int index, bool convert = true,
types::typetag<RequireType> = types::typetag<RequireType>()) {
if (detail::object_wrapper_type_check(l, index)) {
ObjectWrapperBase *ptr =
static_cast<ObjectWrapperBase *>(lua_touserdata(l, index));
if (ptr->type() == metatableType<RequireType>()) {
return ptr;
} else if (convert) {
PointerConverter &pcvt = PointerConverter::get(l);
return pcvt.get_pointer(ptr, types::typetag<RequireType>()) ? ptr : 0;
}
return 0;
}
return 0;
}
template <class T> T *get_pointer(lua_State *l, int index, types::typetag<T>) {
int type = lua_type(l, index);
if (type == LUA_TLIGHTUSERDATA) {
return (T *)lua_topointer(l, index);
} else if (type != LUA_TUSERDATA) {
return 0;
} else {
ObjectWrapperBase *objwrapper = object_wrapper(l, index);
if (objwrapper) {
const std::type_info &to_type = metatableType<T>();
if (objwrapper->type() == to_type) {
return static_cast<T *>(objwrapper->get());
}
if (objwrapper->native_type() == to_type) {
return static_cast<T *>(objwrapper->native_get());
} else {
PointerConverter &pcvt = PointerConverter::get(l);
return pcvt.get_pointer<T>(objwrapper);
}
}
}
return 0;
}
template <class T>
const T *get_const_pointer(lua_State *l, int index, types::typetag<T>) {
int type = lua_type(l, index);
if (type == LUA_TLIGHTUSERDATA) {
return (T *)lua_topointer(l, index);
} else if (type != LUA_TUSERDATA) {
return 0;
} else {
ObjectWrapperBase *objwrapper = object_wrapper(l, index);
if (objwrapper) {
if (objwrapper->type() == metatableType<T>()) {
return static_cast<const T *>(objwrapper->cget());
} else {
PointerConverter &pcvt = PointerConverter::get(l);
return pcvt.get_const_pointer<T>(objwrapper);
}
}
}
return 0;
}
template <class T>
const T *get_pointer(lua_State *l, int index, types::typetag<const T>) {
return get_const_pointer<T>(l, index, types::typetag<T>());
}
template <class T>
standard::shared_ptr<T> get_shared_pointer(lua_State *l, int index,
types::typetag<T>) {
ObjectSharedPointerWrapper *ptr =
dynamic_cast<ObjectSharedPointerWrapper *>(object_wrapper(l, index));
if (ptr) {
const std::type_info &from_type = ptr->shared_ptr_type();
const std::type_info &to_type =
metatableType<standard::shared_ptr<typename traits::decay<T>::type> >();
if (from_type == to_type) {
if (standard::is_const<T>::value) {
return standard::static_pointer_cast<T>(
standard::const_pointer_cast<void>(ptr->const_object()));
} else {
return standard::static_pointer_cast<T>(ptr->object());
}
}
PointerConverter &pcvt = PointerConverter::get(l);
return pcvt.get_shared_pointer<T>(ptr);
}
return standard::shared_ptr<T>();
}
inline standard::shared_ptr<void> get_shared_pointer(lua_State *l, int index,
types::typetag<void>) {
ObjectSharedPointerWrapper *ptr =
dynamic_cast<ObjectSharedPointerWrapper *>(object_wrapper(l, index));
if (ptr) {
return ptr->object();
}
return standard::shared_ptr<void>();
}
inline standard::shared_ptr<const void>
get_shared_pointer(lua_State *l, int index, types::typetag<const void>) {
ObjectSharedPointerWrapper *ptr =
dynamic_cast<ObjectSharedPointerWrapper *>(object_wrapper(l, index));
if (ptr) {
return ptr->const_object();
}
return standard::shared_ptr<const void>();
}
namespace class_userdata {
template <typename T> inline void destructor(T *pointer) {
if (pointer) {
pointer->~T();
}
}
inline bool get_metatable(lua_State *l, const std::type_info &typeinfo) {
int ttype = lua_rawgetp_rtype(
l, LUA_REGISTRYINDEX,
metatable_type_table_key()); // get metatable registry table
if (ttype != LUA_TTABLE) {
lua_newtable(l);
lua_rawsetp(l, LUA_REGISTRYINDEX, metatable_type_table_key());
return false;
}
int type = lua_rawgetp_rtype(l, -1, &typeinfo);
lua_remove(l, -2); // remove metatable registry table
return type != LUA_TNIL;
}
template <typename T> bool get_metatable(lua_State *l) {
return get_metatable(l, metatableType<T>());
}
template <typename T> bool available_metatable(lua_State *l) {
util::ScopedSavedStack save(l);
return get_metatable<T>(l);
}
inline bool newmetatable(lua_State *l, const std::type_info &typeinfo,
const char *name) {
if (get_metatable(l, typeinfo)) // already register
{
return false; //
}
lua_pop(l, 1);
lua_rawgetp_rtype(l, LUA_REGISTRYINDEX,
metatable_type_table_key()); // get metatable registry table
int metaregindex = lua_absindex(l, -1);
lua_createtable(l, 0, 2);
lua_pushstring(l, name);
lua_pushvalue(l, -1);
lua_setfield(l, -3, "__name"); // metatable.__name = name
lua_rawsetp(l, -2, metatable_name_key());
lua_pushvalue(l, -1);
lua_rawsetp(l, metaregindex, &typeinfo);
lua_remove(l, metaregindex); // remove metatable registry table
return true;
}
template <typename T> bool newmetatable(lua_State *l) {
return newmetatable(l, metatableType<T>(), metatableName<T>().c_str());
}
template <typename T> inline int deleter(lua_State *state) {
T *ptr = (T *)lua_touserdata(state, 1);
ptr->~T();
return 0;
}
struct UnknownType {};
inline void setmetatable(lua_State *l, const std::type_info &typeinfo) {
// if not available metatable, set unknown class metatable
if (!get_metatable(l, typeinfo)) {
lua_pop(l, 1);
if (!get_metatable<UnknownType>(l)) {
lua_pop(l, 1);
newmetatable<UnknownType>(l);
lua_pushcclosure(l, &deleter<ObjectWrapperBase>, 0);
lua_setfield(l, -2, "__gc");
}
}
lua_setmetatable(l, -2);
}
template <typename T> void setmetatable(lua_State *l) {
setmetatable(l, metatableType<T>());
}
}
template <typename T>
bool available_metatable(lua_State *l,
types::typetag<T> = types::typetag<T>()) {
return class_userdata::available_metatable<T>(l);
}
namespace util {
template <typename T> inline bool object_checkType(lua_State *l, int index) {
return object_wrapper<T>(l, index) != 0;
}
template <typename T>
inline bool object_strictCheckType(lua_State *l, int index) {
return object_wrapper<T>(l, index, false) != 0;
}
template <typename T>
inline optional<T> object_getopt(lua_State *l, int index) {
const typename traits::remove_reference<T>::type *pointer = get_const_pointer(
l, index, types::typetag<typename traits::remove_reference<T>::type>());
if (!pointer) {
return optional<T>();
}
return *pointer;
}
template <typename T> inline T object_get(lua_State *l, int index) {
const typename traits::remove_reference<T>::type *pointer = get_const_pointer(
l, index, types::typetag<typename traits::remove_reference<T>::type>());
if (!pointer) {
throw LuaTypeMismatch();
}
return *pointer;
}
template <typename To> struct ConvertibleRegisterHelperProxy {
template <typename DataType>
ConvertibleRegisterHelperProxy(DataType v)
: holder_(new DataHolder<DataType>(v)) {}
operator To() { return holder_->get(); }
private:
struct DataHolderBase {
virtual To get() const = 0;
virtual ~DataHolderBase() {}
};
template <typename Type> class DataHolder : public DataHolderBase {
typedef typename traits::decay<Type>::type DataType;
public:
explicit DataHolder(DataType v) : data_(v) {}
virtual To get() const { return To(data_); }
private:
DataType data_;
};
standard::shared_ptr<DataHolderBase> holder_;
};
#if KAGUYA_USE_CPP11
template <typename T> inline int object_push(lua_State *l, T &&v) {
typedef ObjectWrapper<typename traits::remove_const_and_reference<T>::type>
wrapper_type;
void *storage = lua_newuserdata(l, sizeof(wrapper_type));
new (storage) wrapper_type(std::forward<T>(v));
class_userdata::setmetatable<T>(l);
return 1;
}
namespace conv_helper_detail {
template <class To> bool checkType(lua_State *, int) { return false; }
template <class To, class From, class... Remain>
bool checkType(lua_State *l, int index) {
return lua_type_traits<From>::checkType(l, index) ||
checkType<To, Remain...>(l, index);
}
template <class To> bool strictCheckType(lua_State *, int) { return false; }
template <class To, class From, class... Remain>
bool strictCheckType(lua_State *l, int index) {
return lua_type_traits<From>::strictCheckType(l, index) ||
strictCheckType<To, Remain...>(l, index);
;
}
template <class To> To get(lua_State *, int) { throw LuaTypeMismatch(); }
template <class To, class From, class... Remain>
To get(lua_State *l, int index) {
typedef optional<typename lua_type_traits<From>::get_type> opt_type;
if (auto opt = lua_type_traits<opt_type>::get(l, index)) {
return *opt;
}
return get<To, Remain...>(l, index);
}
}
template <class To, class... From> struct ConvertibleRegisterHelper {
typedef To get_type;
static bool checkType(lua_State *l, int index) {
if (object_checkType<To>(l, index)) {
return true;
}
return conv_helper_detail::checkType<To, From...>(l, index);
}
static bool strictCheckType(lua_State *l, int index) {
if (object_strictCheckType<To>(l, index)) {
return true;
}
return conv_helper_detail::strictCheckType<To, From...>(l, index);
}
static get_type get(lua_State *l, int index) {
if (auto opt = object_getopt<To>(l, index)) {
return *opt;
}
return conv_helper_detail::get<get_type, From...>(l, index);
}
};
#else
template <typename T> inline int object_push(lua_State *l, T v) {
typedef ObjectWrapper<typename traits::remove_const_and_reference<T>::type>
wrapper_type;
void *storage = lua_newuserdata(l, sizeof(wrapper_type));
new (storage) wrapper_type(v);
class_userdata::setmetatable<T>(l);
return 1;
}
namespace conv_helper_detail {
#define KAGUYA_CONVERTIBLE_REG_HELPER_CHECK_TYPE_REP(N) \
|| lua_type_traits<KAGUYA_PP_CAT(A, N)>::checkType(state, index)
#define KAGUYA_CONVERTIBLE_REG_HELPER_STRICT_CHECK_TYPE_REP(N) \
|| lua_type_traits<KAGUYA_PP_CAT(A, N)>::strictCheckType(state, index)
#define KAGUYA_CONVERTIBLE_REG_HELPER_GET_OPT_TYPEDEF(N) \
typedef optional<typename lua_type_traits<KAGUYA_PP_CAT(A, N)>::get_type> \
KAGUYA_PP_CAT(opt_type, N);
#define KAGUYA_CONVERTIBLE_REG_HELPER_GET_REP(N) \
if (KAGUYA_PP_CAT(opt_type, N) opt = \
lua_type_traits<KAGUYA_PP_CAT(opt_type, N)>::get(state, index)) { \
return *opt; \
} else
template <typename To> bool checkType(lua_State *, int, TypeTuple<>) {
return false;
}
#define KAGUYA_CONVERTIBLE_REG_HELPER_CHECK_TYPE_DEF(N) \
template <typename To, KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
bool checkType(lua_State *state, int index, \
TypeTuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)>) { \
return false KAGUYA_PP_REPEAT( \
N, KAGUYA_CONVERTIBLE_REG_HELPER_CHECK_TYPE_REP); \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS,
KAGUYA_CONVERTIBLE_REG_HELPER_CHECK_TYPE_DEF)
#undef KAGUYA_CONVERTIBLE_REG_HELPER_CHECK_TYPE_DEF
template <typename To> bool strictCheckType(lua_State *, int, TypeTuple<>) {
return false;
}
#define KAGUYA_CONVERTIBLE_REG_HELPER_ST_CHECK_TYPE_DEF(N) \
template <typename To, KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
bool strictCheckType(lua_State *state, int index, \
TypeTuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)>) { \
return false KAGUYA_PP_REPEAT( \
N, KAGUYA_CONVERTIBLE_REG_HELPER_STRICT_CHECK_TYPE_REP); \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS,
KAGUYA_CONVERTIBLE_REG_HELPER_ST_CHECK_TYPE_DEF)
#undef KAGUYA_CONVERTIBLE_REG_HELPER_ST_CHECK_TYPE_DEF
#define KAGUYA_CONVERTIBLE_REG_HELPER_GET_DEF(N) \
template <typename To, KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
To get(lua_State *state, int index, \
TypeTuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)>) { \
KAGUYA_PP_REPEAT(N, KAGUYA_CONVERTIBLE_REG_HELPER_GET_OPT_TYPEDEF) \
KAGUYA_PP_REPEAT(N, KAGUYA_CONVERTIBLE_REG_HELPER_GET_REP) { \
throw LuaTypeMismatch(); \
} \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS,
KAGUYA_CONVERTIBLE_REG_HELPER_GET_DEF)
#undef KAGUYA_CONVERTIBLE_REG_HELPER_GET_DEF
#undef KAGUYA_CONVERTIBLE_REG_HELPER_CHECK_TYPE_REP
#undef KAGUYA_CONVERTIBLE_REG_HELPER_STRICT_CHECK_TYPE_REP
#undef KAGUYA_CONVERTIBLE_REG_HELPER_ST_GET_REP
#undef KAGUYA_CONVERTIBLE_REG_HELPER_GET_REP
}
#define KAGUYA_PP_CONVERTIBLE_REG_HELPER_DEF_REP(N) \
KAGUYA_PP_CAT(typename A, N) = null_type
#define KAGUYA_PP_CONVERTIBLE_REG_HELPER_DEF_REPEAT(N) \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_CONVERTIBLE_REG_HELPER_DEF_REP)
template <typename To,
KAGUYA_PP_CONVERTIBLE_REG_HELPER_DEF_REPEAT(KAGUYA_FUNCTION_MAX_ARGS)>
struct ConvertibleRegisterHelper {
typedef To get_type;
typedef TypeTuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(KAGUYA_FUNCTION_MAX_ARGS)>
conv_types;
static bool checkType(lua_State *l, int index) {
if (object_checkType<To>(l, index)) {
return true;
}
return conv_helper_detail::checkType<To>(l, index, conv_types());
}
static bool strictCheckType(lua_State *l, int index) {
if (object_strictCheckType<To>(l, index)) {
return true;
}
return conv_helper_detail::strictCheckType<To>(l, index, conv_types());
}
static get_type get(lua_State *l, int index) {
if (optional<To> opt = object_getopt<To>(l, index)) {
return *opt;
}
return conv_helper_detail::get<get_type>(l, index, conv_types());
}
};
#undef KAGUYA_PP_CONVERTIBLE_REG_HELPER_DEF_REP
#undef KAGUYA_PP_CONVERTIBLE_REG_HELPER_DEF_REPEAT
#endif
}
}