436 lines
12 KiB
C++
436 lines
12 KiB
C++
// https://github.com/vinniefalco/LuaBridge
|
|
// Copyright 2020, Dmitry Tarakanov
|
|
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#pragma once
|
|
|
|
#include <LuaBridge/detail/Config.h>
|
|
#include <LuaBridge/detail/TypeList.h>
|
|
|
|
#include <functional>
|
|
|
|
namespace luabridge {
|
|
|
|
namespace detail {
|
|
|
|
/**
|
|
Since the throw specification is part of a function signature, the FuncTraits
|
|
family of templates needs to be specialized for both types. The
|
|
LUABRIDGE_THROWSPEC macro controls whether we use the 'throw ()' form, or
|
|
'noexcept' (if C++11 is available) to distinguish the functions.
|
|
*/
|
|
#if defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__clang__) || defined(__GNUC__) || \
|
|
(defined(_MSC_VER) && (_MSC_VER >= 1700))
|
|
// Do not define LUABRIDGE_THROWSPEC since the Xcode and gcc compilers do not
|
|
// distinguish the throw specification in the function signature.
|
|
#define LUABRIDGE_THROWSPEC
|
|
#else
|
|
// Visual Studio 10 and earlier pay too much mind to useless throw () spec.
|
|
//
|
|
#define LUABRIDGE_THROWSPEC throw()
|
|
#endif
|
|
|
|
//==============================================================================
|
|
/**
|
|
* Traits class for unrolling the type list values into function arguments.
|
|
*/
|
|
template<class ReturnType, size_t NUM_PARAMS>
|
|
struct Caller;
|
|
|
|
template<class ReturnType>
|
|
struct Caller<ReturnType, 0>
|
|
{
|
|
template<class Fn, class Params>
|
|
static ReturnType f(Fn& fn, TypeListValues<Params>&)
|
|
{
|
|
return fn();
|
|
}
|
|
|
|
template<class T, class MemFn, class Params>
|
|
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>&)
|
|
{
|
|
return (obj->*fn)();
|
|
}
|
|
};
|
|
|
|
template<class ReturnType>
|
|
struct Caller<ReturnType, 1>
|
|
{
|
|
template<class Fn, class Params>
|
|
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return fn(tvl.hd);
|
|
}
|
|
|
|
template<class T, class MemFn, class Params>
|
|
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return (obj->*fn)(tvl.hd);
|
|
}
|
|
};
|
|
|
|
template<class ReturnType>
|
|
struct Caller<ReturnType, 2>
|
|
{
|
|
template<class Fn, class Params>
|
|
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return fn(tvl.hd, tvl.tl.hd);
|
|
}
|
|
|
|
template<class T, class MemFn, class Params>
|
|
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return (obj->*fn)(tvl.hd, tvl.tl.hd);
|
|
}
|
|
};
|
|
|
|
template<class ReturnType>
|
|
struct Caller<ReturnType, 3>
|
|
{
|
|
template<class Fn, class Params>
|
|
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd);
|
|
}
|
|
|
|
template<class T, class MemFn, class Params>
|
|
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd);
|
|
}
|
|
};
|
|
|
|
template<class ReturnType>
|
|
struct Caller<ReturnType, 4>
|
|
{
|
|
template<class Fn, class Params>
|
|
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd);
|
|
}
|
|
|
|
template<class T, class MemFn, class Params>
|
|
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd);
|
|
}
|
|
};
|
|
|
|
template<class ReturnType>
|
|
struct Caller<ReturnType, 5>
|
|
{
|
|
template<class Fn, class Params>
|
|
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd);
|
|
}
|
|
|
|
template<class T, class MemFn, class Params>
|
|
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd);
|
|
}
|
|
};
|
|
|
|
template<class ReturnType>
|
|
struct Caller<ReturnType, 6>
|
|
{
|
|
template<class Fn, class Params>
|
|
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return fn(tvl.hd,
|
|
tvl.tl.hd,
|
|
tvl.tl.tl.hd,
|
|
tvl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.hd);
|
|
}
|
|
|
|
template<class T, class MemFn, class Params>
|
|
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return (obj->*fn)(tvl.hd,
|
|
tvl.tl.hd,
|
|
tvl.tl.tl.hd,
|
|
tvl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.hd);
|
|
}
|
|
};
|
|
|
|
template<class ReturnType>
|
|
struct Caller<ReturnType, 7>
|
|
{
|
|
template<class Fn, class Params>
|
|
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return fn(tvl.hd,
|
|
tvl.tl.hd,
|
|
tvl.tl.tl.hd,
|
|
tvl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.tl.hd);
|
|
}
|
|
|
|
template<class T, class MemFn, class Params>
|
|
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return (obj->*fn)(tvl.hd,
|
|
tvl.tl.hd,
|
|
tvl.tl.tl.hd,
|
|
tvl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.tl.hd);
|
|
}
|
|
};
|
|
|
|
template<class ReturnType>
|
|
struct Caller<ReturnType, 8>
|
|
{
|
|
template<class Fn, class Params>
|
|
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return fn(tvl.hd,
|
|
tvl.tl.hd,
|
|
tvl.tl.tl.hd,
|
|
tvl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.tl.tl.hd);
|
|
}
|
|
|
|
template<class T, class MemFn, class Params>
|
|
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return (obj->*fn)(tvl.hd,
|
|
tvl.tl.hd,
|
|
tvl.tl.tl.hd,
|
|
tvl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.tl.tl.hd);
|
|
}
|
|
};
|
|
|
|
template<class ReturnType>
|
|
struct Caller<ReturnType, 9>
|
|
{
|
|
template<class Fn, class Params>
|
|
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return fn(tvl.hd,
|
|
tvl.tl.hd,
|
|
tvl.tl.tl.hd,
|
|
tvl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.tl.tl.tl.hd);
|
|
}
|
|
|
|
template<class T, class MemFn, class Params>
|
|
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return (obj->*fn)(tvl.hd,
|
|
tvl.tl.hd,
|
|
tvl.tl.tl.hd,
|
|
tvl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.tl.tl.hd,
|
|
tvl.tl.tl.tl.tl.tl.tl.tl.tl.hd);
|
|
}
|
|
};
|
|
|
|
template<class ReturnType, class Fn, class Params>
|
|
ReturnType doCall(Fn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return Caller<ReturnType, TypeListSize<Params>::value>::f(fn, tvl);
|
|
}
|
|
|
|
template<class ReturnType, class T, class MemFn, class Params>
|
|
ReturnType doCall(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return Caller<ReturnType, TypeListSize<Params>::value>::f(obj, fn, tvl);
|
|
}
|
|
|
|
//==============================================================================
|
|
/**
|
|
Traits for function pointers.
|
|
|
|
There are three types of functions: global, non-const member, and const
|
|
member. These templates determine the type of function, which class type it
|
|
belongs to if it is a class member, the const-ness if it is a member
|
|
function, and the type information for the return value and argument list.
|
|
|
|
Expansions are provided for functions with up to 8 parameters. This can be
|
|
manually extended, or expanded to an arbitrary amount using C++11 features.
|
|
*/
|
|
template<class MemFn, class D = MemFn>
|
|
struct FuncTraits
|
|
{
|
|
};
|
|
|
|
/* Ordinary function pointers. */
|
|
|
|
template<class R, class... ParamList>
|
|
struct FuncTraits<R (*)(ParamList...)>
|
|
{
|
|
static bool const isMemberFunction = false;
|
|
using DeclType = R (*)(ParamList...);
|
|
using ReturnType = R;
|
|
using Params = typename MakeTypeList<ParamList...>::Result;
|
|
|
|
static R call(const DeclType& fp, TypeListValues<Params>& tvl) { return doCall<R>(fp, tvl); }
|
|
};
|
|
|
|
/* Windows: WINAPI (a.k.a. __stdcall) function pointers. */
|
|
|
|
#ifdef _M_IX86 // Windows 32bit only
|
|
|
|
template<class R, class... ParamList>
|
|
struct FuncTraits<R(__stdcall*)(ParamList...)>
|
|
{
|
|
static bool const isMemberFunction = false;
|
|
using DeclType = R(__stdcall*)(ParamList...);
|
|
using ReturnType = R;
|
|
using Params = typename MakeTypeList<ParamList...>::Result;
|
|
|
|
static R call(const DeclType& fp, TypeListValues<Params>& tvl) { return doCall<R>(fp, tvl); }
|
|
};
|
|
|
|
#endif // _M_IX86
|
|
|
|
/* Non-const member function pointers. */
|
|
|
|
template<class T, class R, class... ParamList>
|
|
struct FuncTraits<R (T::*)(ParamList...)>
|
|
{
|
|
static bool const isMemberFunction = true;
|
|
static bool const isConstMemberFunction = false;
|
|
using DeclType = R (T::*)(ParamList...);
|
|
using ClassType = T;
|
|
using ReturnType = R;
|
|
using Params = typename MakeTypeList<ParamList...>::Result;
|
|
|
|
static R call(ClassType* obj, const DeclType& fp, TypeListValues<Params>& tvl)
|
|
{
|
|
return doCall<R>(obj, fp, tvl);
|
|
}
|
|
};
|
|
|
|
/* Const member function pointers. */
|
|
|
|
template<class T, class R, class... ParamList>
|
|
struct FuncTraits<R (T::*)(ParamList...) const>
|
|
{
|
|
static bool const isMemberFunction = true;
|
|
static bool const isConstMemberFunction = true;
|
|
using DeclType = R (T::*)(ParamList...) const;
|
|
using ClassType = T;
|
|
using ReturnType = R;
|
|
using Params = typename MakeTypeList<ParamList...>::Result;
|
|
|
|
static R call(const ClassType* obj, const DeclType& fp, TypeListValues<Params>& tvl)
|
|
{
|
|
return doCall<R>(obj, fp, tvl);
|
|
}
|
|
};
|
|
|
|
/* std::function */
|
|
|
|
template<class R, class... ParamList>
|
|
struct FuncTraits<std::function<R(ParamList...)>>
|
|
{
|
|
static bool const isMemberFunction = false;
|
|
static bool const isConstMemberFunction = false;
|
|
using DeclType = std::function<R(ParamList...)>;
|
|
using ReturnType = R;
|
|
using Params = typename MakeTypeList<ParamList...>::Result;
|
|
|
|
static ReturnType call(DeclType& fn, TypeListValues<Params>& tvl)
|
|
{
|
|
return doCall<ReturnType>(fn, tvl);
|
|
}
|
|
};
|
|
|
|
template<class ReturnType, class Params, int startParam>
|
|
struct Invoke
|
|
{
|
|
template<class Fn>
|
|
static int run(lua_State* L, Fn& fn)
|
|
{
|
|
try
|
|
{
|
|
ArgList<Params, startParam> args(L);
|
|
Stack<ReturnType>::push(L, FuncTraits<Fn>::call(fn, args));
|
|
return 1;
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
return luaL_error(L, e.what());
|
|
}
|
|
}
|
|
|
|
template<class T, class MemFn>
|
|
static int run(lua_State* L, T* object, const MemFn& fn)
|
|
{
|
|
try
|
|
{
|
|
ArgList<Params, startParam> args(L);
|
|
Stack<ReturnType>::push(L, FuncTraits<MemFn>::call(object, fn, args));
|
|
return 1;
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
return luaL_error(L, e.what());
|
|
}
|
|
}
|
|
};
|
|
|
|
template<class Params, int startParam>
|
|
struct Invoke<void, Params, startParam>
|
|
{
|
|
template<class Fn>
|
|
static int run(lua_State* L, Fn& fn)
|
|
{
|
|
try
|
|
{
|
|
ArgList<Params, startParam> args(L);
|
|
FuncTraits<Fn>::call(fn, args);
|
|
return 0;
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
return luaL_error(L, e.what());
|
|
}
|
|
}
|
|
|
|
template<class T, class MemFn>
|
|
static int run(lua_State* L, T* object, const MemFn& fn)
|
|
{
|
|
try
|
|
{
|
|
ArgList<Params, startParam> args(L);
|
|
FuncTraits<MemFn>::call(object, fn, args);
|
|
return 0;
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
return luaL_error(L, e.what());
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
} // namespace luabridge
|