968 lines
37 KiB
C++
968 lines
37 KiB
C++
|
// 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 <vector>
|
||
|
#include <iterator>
|
||
|
|
||
|
#include "kaguya/config.hpp"
|
||
|
#include "kaguya/utility.hpp"
|
||
|
#include "kaguya/type.hpp"
|
||
|
#include "kaguya/lua_ref.hpp"
|
||
|
|
||
|
#if KAGUYA_USE_CPP11
|
||
|
#include "kaguya/native_function_cxx11.hpp"
|
||
|
#else
|
||
|
#include "kaguya/native_function_cxx03.hpp"
|
||
|
#endif
|
||
|
|
||
|
#include "kaguya/function_tuple_def.hpp"
|
||
|
|
||
|
namespace kaguya {
|
||
|
struct FunctionImpl {
|
||
|
virtual int invoke(lua_State *state) = 0;
|
||
|
virtual std::string argTypesName() const = 0;
|
||
|
virtual bool checkArgTypes(lua_State *state) const = 0;
|
||
|
virtual bool strictCheckArgTypes(lua_State *state) const = 0;
|
||
|
virtual int minArgCount() const = 0;
|
||
|
virtual int maxArgCount() const = 0;
|
||
|
virtual ~FunctionImpl() {}
|
||
|
};
|
||
|
struct PolymorphicInvoker {
|
||
|
typedef standard::shared_ptr<FunctionImpl> holder_type;
|
||
|
PolymorphicInvoker(const holder_type &fptr) : fnc(fptr) {}
|
||
|
int invoke(lua_State *state) const { return fnc->invoke(state); }
|
||
|
std::string argTypesName() const { return fnc->argTypesName(); }
|
||
|
bool checkArgTypes(lua_State *state) const {
|
||
|
return fnc->checkArgTypes(state);
|
||
|
}
|
||
|
bool strictCheckArgTypes(lua_State *state) const {
|
||
|
return fnc->strictCheckArgTypes(state);
|
||
|
}
|
||
|
int minArgCount() const { return fnc->minArgCount(); }
|
||
|
int maxArgCount() const { return fnc->maxArgCount(); }
|
||
|
~PolymorphicInvoker() {}
|
||
|
|
||
|
private:
|
||
|
holder_type fnc;
|
||
|
};
|
||
|
struct PolymorphicMemberInvoker : PolymorphicInvoker {
|
||
|
PolymorphicMemberInvoker(const holder_type &fptr)
|
||
|
: PolymorphicInvoker(fptr) {}
|
||
|
};
|
||
|
|
||
|
namespace nativefunction {
|
||
|
template <size_t INDEX, typename F>
|
||
|
typename lua_type_traits<typename util::ArgumentType<INDEX, F>::type>::get_type
|
||
|
getArgument(lua_State *state) {
|
||
|
return lua_type_traits<typename util::ArgumentType<INDEX, F>::type>::get(
|
||
|
state, INDEX + 1);
|
||
|
}
|
||
|
|
||
|
template <typename T, typename Enable = void>
|
||
|
struct is_callable
|
||
|
: traits::integral_constant<
|
||
|
bool, !traits::is_same<
|
||
|
void, typename util::FunctionSignature<T>::type>::value> {};
|
||
|
|
||
|
template <class MemType, class T>
|
||
|
struct is_callable<MemType T::*> : traits::integral_constant<bool, true> {};
|
||
|
|
||
|
template <typename T>
|
||
|
struct is_callable<ConstructorFunctor<T> >
|
||
|
: traits::integral_constant<bool, true> {};
|
||
|
|
||
|
// for constructors
|
||
|
template <class T> int call(lua_State *state, ConstructorFunctor<T> &con) {
|
||
|
return con(state);
|
||
|
}
|
||
|
template <class T>
|
||
|
int call(lua_State *state, const ConstructorFunctor<T> &con) {
|
||
|
return con(state);
|
||
|
}
|
||
|
template <class T>
|
||
|
bool checkArgTypes(lua_State *state, const ConstructorFunctor<T> &con,
|
||
|
int opt_count = 0) {
|
||
|
return con.checkArgTypes(state, opt_count);
|
||
|
}
|
||
|
template <class T>
|
||
|
bool strictCheckArgTypes(lua_State *state, const ConstructorFunctor<T> &con,
|
||
|
int opt_count = 0) {
|
||
|
return con.strictCheckArgTypes(state, opt_count);
|
||
|
}
|
||
|
template <class T> std::string argTypesName(const ConstructorFunctor<T> &con) {
|
||
|
return con.argTypesName();
|
||
|
}
|
||
|
template <class T> int minArgCount(const ConstructorFunctor<T> &) {
|
||
|
return ConstructorFunctor<T>::signature_type::argument_count;
|
||
|
}
|
||
|
template <class T> int maxArgCount(const ConstructorFunctor<T> &) {
|
||
|
return ConstructorFunctor<T>::signature_type::argument_count;
|
||
|
}
|
||
|
|
||
|
// for data member
|
||
|
// using is_member_function_pointer in MSVC2010 : fatal error LNK1179: invalid
|
||
|
// or corrupt file: duplicate COMDAT
|
||
|
// '?value@?$result_@P8ABC@test_02_classreg@@AE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ@?$is_mem_fun_pointer_select@$0A@@detail@boost@@2_NB'
|
||
|
template <class MemType, class T>
|
||
|
typename traits::enable_if<traits::is_object<MemType>::value, int>::type
|
||
|
call(lua_State *state, MemType T::*mptr) {
|
||
|
T *this_ = lua_type_traits<T *>::get(state, 1);
|
||
|
if (lua_gettop(state) == 1) {
|
||
|
if (!this_) {
|
||
|
const T &this_ = lua_type_traits<const T &>::get(state, 1);
|
||
|
if (is_usertype<MemType>::value && !traits::is_pointer<MemType>::value) {
|
||
|
return util::push_args(
|
||
|
state, standard::reference_wrapper<const MemType>(this_.*mptr));
|
||
|
} else {
|
||
|
return util::push_args(state, this_.*mptr);
|
||
|
}
|
||
|
} else {
|
||
|
if (is_usertype<MemType>::value && !traits::is_pointer<MemType>::value) {
|
||
|
return util::push_args(
|
||
|
state, standard::reference_wrapper<MemType>(this_->*mptr));
|
||
|
} else {
|
||
|
return util::push_args(state, this_->*mptr);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
if (!this_) {
|
||
|
throw LuaTypeMismatch();
|
||
|
}
|
||
|
this_->*mptr = lua_type_traits<MemType>::get(state, 2);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
template <class MemType, class T>
|
||
|
typename traits::enable_if<traits::is_object<MemType>::value, bool>::type
|
||
|
checkArgTypes(lua_State *state, MemType T::*, int opt_count = 0) {
|
||
|
KAGUYA_UNUSED(opt_count);
|
||
|
if (lua_gettop(state) >= 2) {
|
||
|
// setter typecheck
|
||
|
return lua_type_traits<MemType>::checkType(state, 2) &&
|
||
|
lua_type_traits<T>::checkType(state, 1);
|
||
|
}
|
||
|
// getter typecheck
|
||
|
return lua_type_traits<T>::checkType(state, 1);
|
||
|
}
|
||
|
template <class MemType, class T>
|
||
|
typename traits::enable_if<traits::is_object<MemType>::value, bool>::type
|
||
|
strictCheckArgTypes(lua_State *state, MemType T::*, int opt_count = 0) {
|
||
|
KAGUYA_UNUSED(opt_count);
|
||
|
if (lua_gettop(state) == 2) {
|
||
|
// setter typecheck
|
||
|
return lua_type_traits<MemType>::strictCheckType(state, 2) &&
|
||
|
lua_type_traits<T>::strictCheckType(state, 1);
|
||
|
}
|
||
|
// getter typecheck
|
||
|
return lua_type_traits<T>::strictCheckType(state, 1);
|
||
|
}
|
||
|
template <class MemType, class T>
|
||
|
typename traits::enable_if<traits::is_object<MemType>::value, std::string>::type
|
||
|
argTypesName(MemType T::*) {
|
||
|
return util::pretty_name(typeid(T *)) + ",[OPT] " +
|
||
|
util::pretty_name(typeid(MemType));
|
||
|
}
|
||
|
template <class MemType, class T>
|
||
|
typename traits::enable_if<traits::is_object<MemType>::value, int>::type
|
||
|
minArgCount(MemType T::*) {
|
||
|
return 1;
|
||
|
}
|
||
|
template <class MemType, class T>
|
||
|
typename traits::enable_if<traits::is_object<MemType>::value, int>::type
|
||
|
maxArgCount(MemType T::*) {
|
||
|
return 2;
|
||
|
}
|
||
|
|
||
|
inline int call(lua_State *state, const PolymorphicInvoker &f) {
|
||
|
return f.invoke(state);
|
||
|
}
|
||
|
inline int call(lua_State *state, PolymorphicInvoker &f) {
|
||
|
return f.invoke(state);
|
||
|
}
|
||
|
inline bool checkArgTypes(lua_State *state, const PolymorphicInvoker &f) {
|
||
|
return f.checkArgTypes(state);
|
||
|
}
|
||
|
inline bool strictCheckArgTypes(lua_State *state, const PolymorphicInvoker &f) {
|
||
|
return f.strictCheckArgTypes(state);
|
||
|
}
|
||
|
inline std::string argTypesName(const PolymorphicInvoker &f) {
|
||
|
return f.argTypesName();
|
||
|
}
|
||
|
inline int minArgCount(const PolymorphicInvoker &f) { return f.minArgCount(); }
|
||
|
inline int maxArgCount(const PolymorphicInvoker &f) { return f.maxArgCount(); }
|
||
|
|
||
|
template <>
|
||
|
struct is_callable<PolymorphicInvoker> : traits::integral_constant<bool, true> {
|
||
|
};
|
||
|
|
||
|
inline int call(lua_State *state, const PolymorphicMemberInvoker &f) {
|
||
|
return f.invoke(state);
|
||
|
}
|
||
|
inline int call(lua_State *state, PolymorphicMemberInvoker &f) {
|
||
|
return f.invoke(state);
|
||
|
}
|
||
|
inline bool checkArgTypes(lua_State *state, const PolymorphicMemberInvoker &f) {
|
||
|
return f.checkArgTypes(state);
|
||
|
}
|
||
|
inline bool strictCheckArgTypes(lua_State *state,
|
||
|
const PolymorphicMemberInvoker &f) {
|
||
|
return f.strictCheckArgTypes(state);
|
||
|
}
|
||
|
inline std::string argTypesName(const PolymorphicMemberInvoker &f) {
|
||
|
return f.argTypesName();
|
||
|
}
|
||
|
inline int minArgCount(const PolymorphicMemberInvoker &f) {
|
||
|
return f.minArgCount();
|
||
|
}
|
||
|
inline int maxArgCount(const PolymorphicMemberInvoker &f) {
|
||
|
return f.maxArgCount();
|
||
|
}
|
||
|
|
||
|
template <>
|
||
|
struct is_callable<PolymorphicMemberInvoker>
|
||
|
: traits::integral_constant<bool, true> {};
|
||
|
}
|
||
|
|
||
|
class VariadicArgType {
|
||
|
public:
|
||
|
VariadicArgType(lua_State *state, int startIndex)
|
||
|
: state_(state), startIndex_(startIndex),
|
||
|
endIndex_(lua_gettop(state) + 1) {
|
||
|
if (startIndex_ > endIndex_) {
|
||
|
endIndex_ = startIndex_;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <typename T> operator std::vector<T>() const {
|
||
|
if (startIndex_ >= endIndex_) {
|
||
|
return std::vector<T>();
|
||
|
}
|
||
|
std::vector<T> result;
|
||
|
result.reserve(endIndex_ - startIndex_);
|
||
|
for (int index = startIndex_; index < endIndex_; ++index) {
|
||
|
result.push_back(lua_type_traits<T>::get(state_, index));
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
struct reference : public Ref::StackRef,
|
||
|
public detail::LuaVariantImpl<reference> {
|
||
|
reference(lua_State *s, int index) : Ref::StackRef(s, index, false) {}
|
||
|
|
||
|
const reference *operator->() const { return this; }
|
||
|
};
|
||
|
|
||
|
struct iterator {
|
||
|
typedef std::random_access_iterator_tag iterator_category;
|
||
|
typedef VariadicArgType::reference reference;
|
||
|
typedef int difference_type;
|
||
|
typedef reference value_type;
|
||
|
typedef reference *pointer;
|
||
|
|
||
|
iterator() : state_(0), stack_index_(0) {}
|
||
|
iterator(lua_State *state, int index)
|
||
|
: state_(state), stack_index_(index) {}
|
||
|
reference operator*() const { return reference(state_, stack_index_); }
|
||
|
reference operator->() const { return reference(state_, stack_index_); }
|
||
|
iterator &operator++() {
|
||
|
stack_index_++;
|
||
|
return *this;
|
||
|
}
|
||
|
iterator operator++(int) { return iterator(state_, stack_index_++); }
|
||
|
|
||
|
iterator &operator+=(int n) {
|
||
|
stack_index_ += n;
|
||
|
return *this;
|
||
|
}
|
||
|
iterator operator+(int n) const {
|
||
|
return iterator(state_, stack_index_ + n);
|
||
|
}
|
||
|
iterator &operator--() {
|
||
|
stack_index_--;
|
||
|
return *this;
|
||
|
}
|
||
|
iterator operator--(int) { return iterator(state_, stack_index_--); }
|
||
|
iterator &operator-=(int n) {
|
||
|
stack_index_ -= n;
|
||
|
return *this;
|
||
|
}
|
||
|
iterator operator-(int n) const {
|
||
|
return iterator(state_, stack_index_ - n);
|
||
|
}
|
||
|
difference_type operator-(const iterator &n) {
|
||
|
return stack_index_ - n.stack_index_;
|
||
|
}
|
||
|
|
||
|
reference operator[](difference_type offset) const {
|
||
|
return reference(state_, stack_index_ + offset);
|
||
|
}
|
||
|
/**
|
||
|
* @name relational operators
|
||
|
* @brief
|
||
|
*/
|
||
|
//@{
|
||
|
bool operator==(const iterator &other) const {
|
||
|
return state_ == other.state_ && stack_index_ == other.stack_index_;
|
||
|
}
|
||
|
bool operator!=(const iterator &other) const { return !(*this == other); }
|
||
|
bool operator<(const iterator &other) const {
|
||
|
return stack_index_ < other.stack_index_;
|
||
|
}
|
||
|
bool operator>(const iterator &other) const { return other < *this; }
|
||
|
bool operator<=(const iterator &other) const { return other >= *this; }
|
||
|
bool operator>=(const iterator &other) const { return !(*this < other); }
|
||
|
//@}
|
||
|
private:
|
||
|
lua_State *state_;
|
||
|
int stack_index_;
|
||
|
};
|
||
|
typedef iterator const_iterator;
|
||
|
typedef reference const_reference;
|
||
|
typedef reference value_type;
|
||
|
|
||
|
iterator begin() { return iterator(state_, startIndex_); }
|
||
|
iterator end() { return iterator(state_, endIndex_); }
|
||
|
const_iterator cbegin() { return const_iterator(state_, startIndex_); }
|
||
|
const_iterator cend() { return const_iterator(state_, endIndex_); }
|
||
|
|
||
|
template <typename T>
|
||
|
typename lua_type_traits<T>::get_type at(size_t index) const {
|
||
|
if (index >= size()) {
|
||
|
throw std::out_of_range("variadic arguments out of range");
|
||
|
}
|
||
|
return lua_type_traits<T>::get(state_,
|
||
|
startIndex_ + static_cast<int>(index));
|
||
|
}
|
||
|
|
||
|
reference at(size_t index) const {
|
||
|
if (index >= size()) {
|
||
|
throw std::out_of_range("variadic arguments out of range");
|
||
|
}
|
||
|
return reference(state_, startIndex_ + static_cast<int>(index));
|
||
|
}
|
||
|
|
||
|
reference operator[](size_t index) const {
|
||
|
return reference(state_, startIndex_ + static_cast<int>(index));
|
||
|
}
|
||
|
size_t size() const { return endIndex_ - startIndex_; }
|
||
|
size_t empty() const { return endIndex_ == startIndex_; }
|
||
|
|
||
|
private:
|
||
|
lua_State *state_;
|
||
|
int startIndex_;
|
||
|
int endIndex_;
|
||
|
};
|
||
|
|
||
|
inline VariadicArgType::iterator operator+(int n,
|
||
|
const VariadicArgType::iterator &i) {
|
||
|
return i + n;
|
||
|
}
|
||
|
|
||
|
/// @ingroup lua_type_traits
|
||
|
/// @brief lua_type_traits for VariadicArgType
|
||
|
template <> struct lua_type_traits<VariadicArgType> {
|
||
|
typedef VariadicArgType get_type;
|
||
|
|
||
|
static bool strictCheckType(lua_State *l, int index) {
|
||
|
KAGUYA_UNUSED(l);
|
||
|
KAGUYA_UNUSED(index);
|
||
|
return true;
|
||
|
}
|
||
|
static bool checkType(lua_State *l, int index) {
|
||
|
KAGUYA_UNUSED(l);
|
||
|
KAGUYA_UNUSED(index);
|
||
|
return true;
|
||
|
}
|
||
|
static get_type get(lua_State *l, int index) {
|
||
|
return VariadicArgType(l, index);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
namespace nativefunction {
|
||
|
static const int MAX_OVERLOAD_SCORE = 255;
|
||
|
template <typename Fn>
|
||
|
uint8_t compute_function_matching_score(lua_State *state, const Fn &fn) {
|
||
|
int argcount = lua_gettop(state);
|
||
|
|
||
|
if (strictCheckArgTypes(state, fn)) {
|
||
|
const int minargcount = minArgCount(fn);
|
||
|
const int maxargcount = maxArgCount(fn);
|
||
|
if (minargcount <= argcount && maxargcount >= argcount) {
|
||
|
return MAX_OVERLOAD_SCORE;
|
||
|
} else {
|
||
|
int diff = std::min(std::abs(argcount - minargcount),
|
||
|
std::abs(argcount - maxargcount));
|
||
|
return std::max(100 - diff, 51);
|
||
|
}
|
||
|
} else if (checkArgTypes(state, fn)) {
|
||
|
const int minargcount = minArgCount(fn);
|
||
|
const int maxargcount = maxArgCount(fn);
|
||
|
if (minargcount <= argcount && maxargcount >= argcount) {
|
||
|
return 200;
|
||
|
} else {
|
||
|
int diff = std::min(std::abs(argcount - minargcount),
|
||
|
std::abs(argcount - maxargcount));
|
||
|
return std::max(50 - diff, 1);
|
||
|
}
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
inline int pushArgmentTypeNames(lua_State *state, int top) {
|
||
|
for (int i = 1; i <= top; i++) {
|
||
|
if (i != 1) {
|
||
|
lua_pushliteral(state, ",");
|
||
|
}
|
||
|
|
||
|
int type = lua_type(state, i);
|
||
|
if (type == LUA_TUSERDATA) {
|
||
|
int nametype = luaL_getmetafield(state, i, "__name");
|
||
|
if (nametype != LUA_TSTRING) {
|
||
|
lua_pop(state, 1);
|
||
|
lua_pushstring(state, lua_typename(state, type));
|
||
|
}
|
||
|
} else {
|
||
|
lua_pushstring(state, lua_typename(state, type));
|
||
|
}
|
||
|
}
|
||
|
return lua_gettop(state) - top;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if KAGUYA_USE_CPP11
|
||
|
|
||
|
namespace detail {
|
||
|
template <typename Fn, typename... Functions>
|
||
|
void function_match_scoring(lua_State *state, uint8_t *score_array,
|
||
|
int current_index, const Fn &fn) {
|
||
|
score_array[current_index] =
|
||
|
nativefunction::compute_function_matching_score(state, fn);
|
||
|
}
|
||
|
template <typename Fn, typename... Functions>
|
||
|
void function_match_scoring(lua_State *state, uint8_t *score_array,
|
||
|
int current_index, const Fn &fn,
|
||
|
const Functions &... fns) {
|
||
|
score_array[current_index] =
|
||
|
nativefunction::compute_function_matching_score(state, fn);
|
||
|
if (score_array[current_index] < nativefunction::MAX_OVERLOAD_SCORE) {
|
||
|
function_match_scoring(state, score_array, current_index + 1, fns...);
|
||
|
}
|
||
|
}
|
||
|
template <typename... Functions>
|
||
|
int best_function_index(lua_State *state, const Functions &... fns) {
|
||
|
static const int fncount = sizeof...(fns);
|
||
|
uint8_t score[fncount] = {};
|
||
|
function_match_scoring(state, score, 0, fns...);
|
||
|
uint8_t best_score = 0;
|
||
|
int best_score_index = -1;
|
||
|
for (int i = 0; i < fncount; ++i) {
|
||
|
if (best_score < score[i]) {
|
||
|
best_score = score[i];
|
||
|
best_score_index = i;
|
||
|
if (best_score == nativefunction::MAX_OVERLOAD_SCORE) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return best_score_index;
|
||
|
}
|
||
|
template <typename Fn>
|
||
|
int invoke_index(lua_State *state, int index, int current_index, Fn &&fn) {
|
||
|
KAGUYA_UNUSED(index);
|
||
|
KAGUYA_UNUSED(current_index);
|
||
|
return nativefunction::call(state, fn);
|
||
|
}
|
||
|
template <typename Fn, typename... Functions>
|
||
|
int invoke_index(lua_State *state, int index, int current_index, Fn &&fn,
|
||
|
Functions &&... fns) {
|
||
|
if (index == current_index) {
|
||
|
return nativefunction::call(state, fn);
|
||
|
} else {
|
||
|
return invoke_index(state, index, current_index + 1, fns...);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <typename Fun> int best_match_invoke(lua_State *state, Fun &&fn) {
|
||
|
return nativefunction::call(state, fn);
|
||
|
}
|
||
|
|
||
|
template <typename Fun, typename... Functions>
|
||
|
int best_match_invoke(lua_State *state, Fun &&fn, Functions &&... fns) {
|
||
|
int index = best_function_index(state, fn, fns...);
|
||
|
if (index >= 0) {
|
||
|
assert(size_t(index) <= sizeof...(fns));
|
||
|
return invoke_index(state, index, 0, fn, fns...);
|
||
|
} else {
|
||
|
throw LuaTypeMismatch();
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
template <typename TupleType, std::size_t... S>
|
||
|
int invoke_tuple_impl(lua_State *state, TupleType &&tuple,
|
||
|
nativefunction::index_tuple<S...>) {
|
||
|
return best_match_invoke(state, fntuple::get<S>(tuple)...);
|
||
|
}
|
||
|
template <typename TupleType>
|
||
|
int invoke_tuple(lua_State *state, TupleType &&tuple) {
|
||
|
typedef typename std::decay<TupleType>::type ttype;
|
||
|
|
||
|
typedef typename nativefunction::index_range<
|
||
|
0, fntuple::tuple_size<ttype>::value>::type indexrange;
|
||
|
|
||
|
return invoke_tuple_impl(state, tuple, indexrange());
|
||
|
}
|
||
|
|
||
|
template <typename Fun>
|
||
|
void push_arg_typename(lua_State *state, const Fun &fn) {
|
||
|
lua_pushliteral(state, "\t\t");
|
||
|
lua_pushstring(state, nativefunction::argTypesName(fn).c_str());
|
||
|
lua_pushliteral(state, "\n");
|
||
|
}
|
||
|
|
||
|
template <typename Fun, typename... Functions>
|
||
|
void push_arg_typename(lua_State *state, const Fun &fn,
|
||
|
const Functions &... fns) {
|
||
|
lua_pushliteral(state, "\t\t");
|
||
|
lua_pushstring(state, nativefunction::argTypesName(fn).c_str());
|
||
|
lua_pushliteral(state, "\n");
|
||
|
push_arg_typename(state, fns...);
|
||
|
}
|
||
|
template <typename TupleType, std::size_t... S>
|
||
|
void push_arg_typename_tuple_impl(lua_State *state, TupleType &&tuple,
|
||
|
nativefunction::index_tuple<S...>) {
|
||
|
return push_arg_typename(state, fntuple::get<S>(tuple)...);
|
||
|
}
|
||
|
template <typename TupleType>
|
||
|
void push_arg_typename_tuple(lua_State *state, TupleType &&tuple) {
|
||
|
typedef typename std::decay<TupleType>::type ttype;
|
||
|
typedef typename nativefunction::index_range<
|
||
|
0, fntuple::tuple_size<ttype>::value>::type indexrange;
|
||
|
|
||
|
return push_arg_typename_tuple_impl(state, tuple, indexrange());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
namespace detail {
|
||
|
#define KAGUYA_FUNCTION_SCOREING(N) \
|
||
|
if (currentbestscore < nativefunction::MAX_OVERLOAD_SCORE) { \
|
||
|
int score = nativefunction::compute_function_matching_score( \
|
||
|
state, fntuple::get<N - 1>(tuple)); \
|
||
|
if (currentbestscore < score) { \
|
||
|
currentbestscore = score; \
|
||
|
currentbestindex = N; \
|
||
|
} \
|
||
|
}
|
||
|
#define KAGUYA_FUNCTION_INVOKE(N) \
|
||
|
if (currentbestindex == N) { \
|
||
|
return nativefunction::call(state, fntuple::get<N - 1>(tuple)); \
|
||
|
}
|
||
|
|
||
|
#define KAGUYA_ARG_PUSH_TYPENAMES(N) \
|
||
|
lua_pushliteral(state, "\t\t"); \
|
||
|
lua_pushstring( \
|
||
|
state, \
|
||
|
nativefunction::argTypesName(fntuple::get<N - 1>(tuple)).c_str()); \
|
||
|
lua_pushliteral(state, "\n");
|
||
|
#define KAGUYA_TEMPLATE_PARAMETER(N) template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)>
|
||
|
#define KAGUYA_TUPLE_INVOKE_DEF(N) \
|
||
|
KAGUYA_TEMPLATE_PARAMETER(N) \
|
||
|
int invoke_tuple(lua_State *state, \
|
||
|
fntuple::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> &tuple) { \
|
||
|
if (N == 1) { \
|
||
|
return nativefunction::call(state, fntuple::get<0>(tuple)); \
|
||
|
} \
|
||
|
int32_t currentbestscore = 0; \
|
||
|
int32_t currentbestindex = -1; \
|
||
|
KAGUYA_PP_REPEAT(N, KAGUYA_FUNCTION_SCOREING); \
|
||
|
KAGUYA_PP_REPEAT(N, KAGUYA_FUNCTION_INVOKE); \
|
||
|
throw LuaTypeMismatch(); \
|
||
|
} \
|
||
|
KAGUYA_TEMPLATE_PARAMETER(N) \
|
||
|
void push_arg_typename_tuple( \
|
||
|
lua_State *state, \
|
||
|
fntuple::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> &tuple) { \
|
||
|
KAGUYA_PP_REPEAT(N, KAGUYA_ARG_PUSH_TYPENAMES); \
|
||
|
}
|
||
|
|
||
|
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS, KAGUYA_TUPLE_INVOKE_DEF)
|
||
|
#undef KAGUYA_TEMPLATE_PARAMETER
|
||
|
#undef KAGUYA_TUPLE_INVOKE_DEF
|
||
|
#undef KAGUYA_ARG_TYPENAMES
|
||
|
#undef KAGUYA_FUNCTION_INVOKE
|
||
|
#undef KAGUYA_FUNCTION_SCOREING
|
||
|
|
||
|
template <typename TupleType>
|
||
|
int invoke_tuple(lua_State *state, TupleType &tuple) {
|
||
|
KAGUYA_UNUSED(state);
|
||
|
KAGUYA_UNUSED(tuple);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
template <typename FunctionTuple> struct FunctionInvokerType {
|
||
|
FunctionTuple functions;
|
||
|
FunctionInvokerType(const FunctionTuple &t) : functions(t) {}
|
||
|
};
|
||
|
|
||
|
template <typename T>
|
||
|
inline FunctionInvokerType<fntuple::tuple<T> > function(T f) {
|
||
|
KAGUYA_STATIC_ASSERT(
|
||
|
nativefunction::is_callable<typename traits::decay<T>::type>::value,
|
||
|
"argument need callable");
|
||
|
return FunctionInvokerType<fntuple::tuple<T> >(fntuple::tuple<T>(f));
|
||
|
}
|
||
|
|
||
|
template <typename FTYPE, typename T>
|
||
|
inline FunctionInvokerType<fntuple::tuple<standard::function<FTYPE> > >
|
||
|
function(T f) {
|
||
|
return FunctionInvokerType<fntuple::tuple<standard::function<FTYPE> > >(
|
||
|
fntuple::tuple<standard::function<FTYPE> >(standard::function<FTYPE>(f)));
|
||
|
}
|
||
|
#if KAGUYA_USE_CPP11
|
||
|
|
||
|
template <typename... Functions>
|
||
|
FunctionInvokerType<fntuple::tuple<Functions...> > overload(Functions... fns) {
|
||
|
return FunctionInvokerType<fntuple::tuple<Functions...> >(
|
||
|
fntuple::tuple<Functions...>(fns...));
|
||
|
}
|
||
|
#else
|
||
|
#define KAGUYA_FOVERLOAD_DEF(N) \
|
||
|
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
|
||
|
FunctionInvokerType<fntuple::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> > \
|
||
|
overload(KAGUYA_PP_ARG_DEF_REPEAT(N)) { \
|
||
|
typedef typename fntuple::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> ttype; \
|
||
|
return FunctionInvokerType<ttype>(ttype(KAGUYA_PP_ARG_REPEAT(N))); \
|
||
|
}
|
||
|
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS, KAGUYA_FOVERLOAD_DEF)
|
||
|
#undef KAGUYA_FOVERLOAD_DEF
|
||
|
#endif
|
||
|
|
||
|
struct luacfunction {
|
||
|
lua_CFunction ptr;
|
||
|
|
||
|
luacfunction(lua_CFunction f) : ptr(f) {}
|
||
|
operator lua_CFunction() { return ptr; }
|
||
|
};
|
||
|
|
||
|
/// @ingroup lua_type_traits
|
||
|
/// @brief lua_type_traits for FunctionInvokerType
|
||
|
template <typename FunctionTuple>
|
||
|
struct lua_type_traits<FunctionInvokerType<FunctionTuple> > {
|
||
|
typedef FunctionInvokerType<FunctionTuple> userdatatype;
|
||
|
typedef const FunctionInvokerType<FunctionTuple> &push_type;
|
||
|
|
||
|
static const char *build_arg_error_message(lua_State *state, const char *msg,
|
||
|
FunctionTuple *tuple) {
|
||
|
int stack_top = lua_gettop(state);
|
||
|
if (msg) {
|
||
|
lua_pushstring(state, msg);
|
||
|
}
|
||
|
lua_pushliteral(state, "Argument mismatch:");
|
||
|
nativefunction::pushArgmentTypeNames(state, stack_top);
|
||
|
|
||
|
lua_pushliteral(state, "\t candidate is:\n");
|
||
|
detail::push_arg_typename_tuple(state, *tuple);
|
||
|
|
||
|
lua_concat(state, lua_gettop(state) - stack_top);
|
||
|
return lua_tostring(state, -1);
|
||
|
}
|
||
|
|
||
|
static int invoke(lua_State *state) {
|
||
|
FunctionTuple *t = static_cast<FunctionTuple *>(
|
||
|
lua_touserdata(state, lua_upvalueindex(1)));
|
||
|
|
||
|
if (t) {
|
||
|
try {
|
||
|
return detail::invoke_tuple(state, *t);
|
||
|
} catch (LuaTypeMismatch &e) {
|
||
|
if (strcmp(e.what(), "type mismatch!!") == 0) {
|
||
|
util::traceBack(state, build_arg_error_message(state, "maybe...", t));
|
||
|
} else {
|
||
|
util::traceBack(state, e.what());
|
||
|
}
|
||
|
} catch (std::exception &e) {
|
||
|
util::traceBack(state, e.what());
|
||
|
} catch (...) {
|
||
|
util::traceBack(state, "Unknown exception");
|
||
|
}
|
||
|
}
|
||
|
return lua_error(state);
|
||
|
}
|
||
|
|
||
|
inline static int tuple_destructor(lua_State *state) {
|
||
|
FunctionTuple *f = static_cast<FunctionTuple *>(lua_touserdata(state, 1));
|
||
|
if (f) {
|
||
|
f->~FunctionTuple();
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int push(lua_State *state, push_type fns) {
|
||
|
void *ptr = lua_newuserdata(state, sizeof(FunctionTuple));
|
||
|
new (ptr) FunctionTuple(fns.functions);
|
||
|
lua_createtable(state, 0, 2);
|
||
|
lua_pushcclosure(state, &tuple_destructor, 0);
|
||
|
lua_setfield(state, -2, "__gc");
|
||
|
lua_pushvalue(state, -1);
|
||
|
lua_setfield(state, -1, "__index");
|
||
|
lua_setmetatable(state, -2);
|
||
|
lua_pushcclosure(state, &invoke, 1);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/// @ingroup lua_type_traits
|
||
|
/// @brief lua_type_traits for c function
|
||
|
template <typename T>
|
||
|
struct lua_type_traits<
|
||
|
T, typename traits::enable_if<traits::is_function<
|
||
|
typename traits::remove_pointer<T>::type>::value>::type> {
|
||
|
static int push(lua_State *l, T f) {
|
||
|
return util::one_push(l, kaguya::function(f));
|
||
|
}
|
||
|
};
|
||
|
/// @ingroup lua_type_traits
|
||
|
/// @brief lua_type_traits for luacfunction
|
||
|
template <> struct lua_type_traits<luacfunction> {
|
||
|
typedef luacfunction push_type;
|
||
|
typedef luacfunction get_type;
|
||
|
static bool strictCheckType(lua_State *l, int index) {
|
||
|
return lua_iscfunction(l, index) != 0;
|
||
|
}
|
||
|
static bool checkType(lua_State *l, int index) {
|
||
|
return lua_iscfunction(l, index) != 0;
|
||
|
}
|
||
|
static get_type get(lua_State *l, int index) {
|
||
|
return lua_tocfunction(l, index);
|
||
|
}
|
||
|
static int push(lua_State *l, push_type f) {
|
||
|
lua_pushcfunction(l, f);
|
||
|
return 1;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/// @ingroup lua_type_traits
|
||
|
/// @brief lua_type_traits for std::function or boost::function
|
||
|
template <typename T> struct lua_type_traits<standard::function<T> > {
|
||
|
typedef const standard::function<T> &push_type;
|
||
|
typedef standard::function<T> get_type;
|
||
|
|
||
|
static bool strictCheckType(lua_State *l, int index) {
|
||
|
return lua_type(l, index) == LUA_TFUNCTION;
|
||
|
}
|
||
|
static bool checkType(lua_State *l, int index) {
|
||
|
return lua_type(l, index) == LUA_TFUNCTION;
|
||
|
}
|
||
|
static get_type get(lua_State *l, int index) {
|
||
|
if (!l || lua_type(l, index) != LUA_TFUNCTION) {
|
||
|
return get_type();
|
||
|
}
|
||
|
lua_pushvalue(l, index);
|
||
|
return get_type(LuaFunction(l, StackTop()));
|
||
|
}
|
||
|
|
||
|
static int push(lua_State *l, push_type v) {
|
||
|
return util::one_push(l, kaguya::function(v));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <typename F,
|
||
|
typename Ret = typename util::FunctionSignature<F>::type::result_type>
|
||
|
struct OverloadFunctionImpl : kaguya::FunctionImpl {
|
||
|
typedef Ret result_type;
|
||
|
typedef typename util::FunctionSignature<F>::type::c_function_type
|
||
|
c_function_type;
|
||
|
|
||
|
virtual result_type invoke_type(lua_State *state) = 0;
|
||
|
|
||
|
virtual int invoke(lua_State *state) {
|
||
|
return util::push_args(state, invoke_type(state));
|
||
|
}
|
||
|
virtual std::string argTypesName() const {
|
||
|
return nativefunction::argTypesName(c_function_type(0),
|
||
|
maxArgCount() - minArgCount());
|
||
|
}
|
||
|
virtual bool checkArgTypes(lua_State *state) const {
|
||
|
return kaguya::nativefunction::checkArgTypes(state, c_function_type(0),
|
||
|
maxArgCount() - minArgCount());
|
||
|
}
|
||
|
virtual bool strictCheckArgTypes(lua_State *state) const {
|
||
|
return kaguya::nativefunction::strictCheckArgTypes(
|
||
|
state, c_function_type(0), maxArgCount() - minArgCount());
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <typename F>
|
||
|
struct OverloadFunctionImpl<F, void> : kaguya::FunctionImpl {
|
||
|
typedef void result_type;
|
||
|
typedef typename util::FunctionSignature<F>::type::c_function_type
|
||
|
c_function_type;
|
||
|
|
||
|
virtual result_type invoke_type(lua_State *state) = 0;
|
||
|
|
||
|
virtual int invoke(lua_State *state) {
|
||
|
invoke_type(state);
|
||
|
return 0;
|
||
|
}
|
||
|
virtual std::string argTypesName() const {
|
||
|
return nativefunction::argTypesName(c_function_type(0),
|
||
|
maxArgCount() - minArgCount());
|
||
|
}
|
||
|
virtual bool checkArgTypes(lua_State *state) const {
|
||
|
return kaguya::nativefunction::checkArgTypes(state, c_function_type(0),
|
||
|
maxArgCount() - minArgCount());
|
||
|
}
|
||
|
virtual bool strictCheckArgTypes(lua_State *state) const {
|
||
|
return kaguya::nativefunction::strictCheckArgTypes(
|
||
|
state, c_function_type(0), maxArgCount() - minArgCount());
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
#define KAGUYA_INTERNAL_OVERLOAD_FUNCTION_GET_REP(N) \
|
||
|
getArgument<N - 1, F>(state)
|
||
|
#define KAGUYA_INTERNAL_OVERLOAD_FUNCTION_GET_REPEAT(N) \
|
||
|
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_INTERNAL_OVERLOAD_FUNCTION_GET_REP)
|
||
|
#define KAGUYA_INTERNAL_OVERLOAD_FUNCTION_INVOKE(N, FNAME, MINARG, MAXARG) \
|
||
|
if (argcount == KAGUYA_PP_ADD(MINARG, KAGUYA_PP_DEC(N))) { \
|
||
|
return FNAME(KAGUYA_INTERNAL_OVERLOAD_FUNCTION_GET_REPEAT( \
|
||
|
KAGUYA_PP_ADD(MINARG, KAGUYA_PP_DEC(N)))); \
|
||
|
}
|
||
|
|
||
|
#define KAGUYA_FUNCTION_OVERLOADS_INTERNAL(GENERATE_NAME, FNAME, MINARG, \
|
||
|
MAXARG, CREATE_FN) \
|
||
|
\
|
||
|
struct GENERATE_NAME \
|
||
|
{ \
|
||
|
template <typename F> struct Function : kaguya::OverloadFunctionImpl<F> { \
|
||
|
typedef \
|
||
|
typename kaguya::OverloadFunctionImpl<F>::result_type result_type; \
|
||
|
virtual result_type invoke_type(lua_State *state) { \
|
||
|
using namespace kaguya::nativefunction; \
|
||
|
int argcount = lua_gettop(state); \
|
||
|
KAGUYA_PP_REPEAT_DEF_VA_ARG( \
|
||
|
KAGUYA_PP_INC(KAGUYA_PP_SUB(MAXARG, MINARG)), \
|
||
|
KAGUYA_INTERNAL_OVERLOAD_FUNCTION_INVOKE, FNAME, MINARG, MAXARG) \
|
||
|
throw kaguya::LuaTypeMismatch("argument count mismatch"); \
|
||
|
} \
|
||
|
virtual int minArgCount() const { return MINARG; } \
|
||
|
virtual int maxArgCount() const { return MAXARG; } \
|
||
|
}; \
|
||
|
template <typename F> kaguya::PolymorphicInvoker::holder_type create(F) { \
|
||
|
kaguya::OverloadFunctionImpl<F> *ptr = new Function<F>(); \
|
||
|
return kaguya::PolymorphicInvoker::holder_type(ptr); \
|
||
|
} \
|
||
|
template <typename F> kaguya::PolymorphicInvoker::holder_type create() { \
|
||
|
kaguya::OverloadFunctionImpl<F> *ptr = new Function<F>(); \
|
||
|
return kaguya::PolymorphicInvoker::holder_type(ptr); \
|
||
|
} \
|
||
|
kaguya::PolymorphicInvoker operator()() { return CREATE_FN; } \
|
||
|
\
|
||
|
} \
|
||
|
GENERATE_NAME;
|
||
|
|
||
|
#define KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_GET_REP(N) \
|
||
|
getArgument<N, F>(state)
|
||
|
#define KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_GET_REPEAT(N) \
|
||
|
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_GET_REP)
|
||
|
#define KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_INVOKE(N, FNAME, MINARG, \
|
||
|
MAXARG) \
|
||
|
if (argcount == 1 + KAGUYA_PP_ADD(MINARG, KAGUYA_PP_DEC(N))) { \
|
||
|
return (getArgument<0, F>(state)) \
|
||
|
.FNAME(KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_GET_REPEAT( \
|
||
|
KAGUYA_PP_ADD(MINARG, KAGUYA_PP_DEC(N)))); \
|
||
|
}
|
||
|
|
||
|
#define KAGUYA_MEMBER_FUNCTION_OVERLOADS_INTERNAL(GENERATE_NAME, CLASS, FNAME, \
|
||
|
MINARG, MAXARG, CREATE_FN) \
|
||
|
\
|
||
|
struct GENERATE_NAME \
|
||
|
{ \
|
||
|
template <typename F> struct Function : kaguya::OverloadFunctionImpl<F> { \
|
||
|
typedef \
|
||
|
typename kaguya::OverloadFunctionImpl<F>::result_type result_type; \
|
||
|
virtual result_type invoke_type(lua_State *state) { \
|
||
|
using namespace kaguya::nativefunction; \
|
||
|
int argcount = lua_gettop(state); \
|
||
|
KAGUYA_PP_REPEAT_DEF_VA_ARG( \
|
||
|
KAGUYA_PP_INC(KAGUYA_PP_SUB(MAXARG, MINARG)), \
|
||
|
KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_INVOKE, FNAME, MINARG, \
|
||
|
MAXARG) \
|
||
|
throw kaguya::LuaTypeMismatch("argument count mismatch"); \
|
||
|
} \
|
||
|
virtual int minArgCount() const { return MINARG + 1; } \
|
||
|
virtual int maxArgCount() const { return MAXARG + 1; } \
|
||
|
}; \
|
||
|
template <typename F> \
|
||
|
kaguya::PolymorphicMemberInvoker::holder_type create(F f) { \
|
||
|
KAGUYA_UNUSED(f); \
|
||
|
kaguya::OverloadFunctionImpl<F> *ptr = new Function<F>(); \
|
||
|
return kaguya::PolymorphicMemberInvoker::holder_type(ptr); \
|
||
|
} \
|
||
|
template <typename F> \
|
||
|
kaguya::PolymorphicMemberInvoker::holder_type create() { \
|
||
|
kaguya::OverloadFunctionImpl<F> *ptr = new Function<F>(); \
|
||
|
return kaguya::PolymorphicMemberInvoker::holder_type(ptr); \
|
||
|
} \
|
||
|
kaguya::PolymorphicMemberInvoker operator()() { return CREATE_FN; } \
|
||
|
\
|
||
|
} \
|
||
|
GENERATE_NAME;
|
||
|
|
||
|
/// @brief Generate wrapper function object for count based overloads with
|
||
|
/// nonvoid return function. Include default arguments parameter function
|
||
|
/// @param GENERATE_NAME generate function object name
|
||
|
/// @param FNAME target function name
|
||
|
/// @param MINARG minimum arguments count
|
||
|
/// @param MAXARG maximum arguments count
|
||
|
#define KAGUYA_FUNCTION_OVERLOADS(GENERATE_NAME, FNAME, MINARG, MAXARG) \
|
||
|
KAGUYA_FUNCTION_OVERLOADS_INTERNAL(GENERATE_NAME, FNAME, MINARG, MAXARG, \
|
||
|
create(FNAME))
|
||
|
|
||
|
/// @brief Generate wrapper function object for count based overloads with
|
||
|
/// nonvoid return function. Include default arguments parameter function
|
||
|
/// @param GENERATE_NAME generate function object name
|
||
|
/// @param FNAME target function name
|
||
|
/// @param MINARG minimum arguments count
|
||
|
/// @param MAXARG maximum arguments count
|
||
|
/// @param SIGNATURE function signature. e,g, int(int)
|
||
|
#define KAGUYA_FUNCTION_OVERLOADS_WITH_SIGNATURE(GENERATE_NAME, FNAME, MINARG, \
|
||
|
MAXARG, SIGNATURE) \
|
||
|
KAGUYA_FUNCTION_OVERLOADS_INTERNAL(GENERATE_NAME, FNAME, MINARG, MAXARG, \
|
||
|
create<SIGNATURE>())
|
||
|
|
||
|
/// @brief Generate wrapper function object for count based overloads with
|
||
|
/// nonvoid return function. Include default arguments parameter function
|
||
|
/// @param GENERATE_NAME generate function object name
|
||
|
/// @param CLASS target class name
|
||
|
/// @param FNAME target function name
|
||
|
/// @param MINARG minimum arguments count
|
||
|
/// @param MAXARG maximum arguments count
|
||
|
#define KAGUYA_MEMBER_FUNCTION_OVERLOADS(GENERATE_NAME, CLASS, FNAME, MINARG, \
|
||
|
MAXARG) \
|
||
|
KAGUYA_MEMBER_FUNCTION_OVERLOADS_INTERNAL( \
|
||
|
GENERATE_NAME, CLASS, FNAME, MINARG, MAXARG, create(&CLASS::FNAME))
|
||
|
|
||
|
/// @brief Generate wrapper function object for count based overloads with
|
||
|
/// nonvoid return function. Include default arguments parameter function
|
||
|
/// @param GENERATE_NAME generate function object name
|
||
|
/// @param CLASS target class name
|
||
|
/// @param FNAME target function name
|
||
|
/// @param MINARG minimum arguments count
|
||
|
/// @param MAXARG maximum arguments count
|
||
|
/// @param SIGNATURE function signature. e,g, int(Test::*)(int)
|
||
|
#define KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE( \
|
||
|
GENERATE_NAME, CLASS, FNAME, MINARG, MAXARG, SIGNATURE) \
|
||
|
KAGUYA_MEMBER_FUNCTION_OVERLOADS_INTERNAL( \
|
||
|
GENERATE_NAME, CLASS, FNAME, MINARG, MAXARG, create<SIGNATURE>())
|