Lua: Add support for default arguments

Former-commit-id: a319bcadf39b7e1633aaa23f360059a1f7449590
This commit is contained in:
Lynix 2015-12-09 15:11:57 +01:00
parent d72db3bf4b
commit d2584b7c33
4 changed files with 244 additions and 107 deletions

View File

@ -42,12 +42,13 @@ namespace Nz
void SetFinalizer(FinalizerFunc finalizer); void SetFinalizer(FinalizerFunc finalizer);
void SetGetter(ClassIndexFunc getter); void SetGetter(ClassIndexFunc getter);
void SetMethod(const String& name, ClassFunc method); void SetMethod(const String& name, ClassFunc method);
template<typename R, typename P, typename... Args> std::enable_if_t<std::is_base_of<P, T>::value> SetMethod(const String& name, R(P::*func)(Args...)); template<typename R, typename P, typename... Args, typename... DefArgs> std::enable_if_t<std::is_base_of<P, T>::value> SetMethod(const String& name, R(P::*func)(Args...), DefArgs... defArgs);
template<typename R, typename P, typename... Args> std::enable_if_t<std::is_base_of<P, T>::value> SetMethod(const String& name, R(P::*func)(Args...) const); template<typename R, typename P, typename... Args, typename... DefArgs> std::enable_if_t<std::is_base_of<P, T>::value> SetMethod(const String& name, R(P::*func)(Args...) const, DefArgs... defArgs);
void SetBindMode(LuaBindMode mode);
void SetSetter(ClassIndexFunc setter); void SetSetter(ClassIndexFunc setter);
void SetStaticGetter(StaticIndexFunc getter); void SetStaticGetter(StaticIndexFunc getter);
void SetStaticMethod(const String& name, StaticFunc func); void SetStaticMethod(const String& name, StaticFunc func);
template<typename R, typename... Args> void SetStaticMethod(const String& name, R(*func)(Args...)); template<typename R, typename... Args, typename... DefArgs> void SetStaticMethod(const String& name, R(*func)(Args...), DefArgs... defArgs);
void SetStaticSetter(StaticIndexFunc getter); void SetStaticSetter(StaticIndexFunc getter);
private: private:

View File

@ -176,12 +176,12 @@ namespace Nz
} }
template<class T> template<class T>
template<typename R, typename P, typename... Args> template<typename R, typename P, typename... Args, typename... DefArgs>
std::enable_if_t<std::is_base_of<P, T>::value> LuaClass<T>::SetMethod(const String& name, R(P::*func)(Args...)) std::enable_if_t<std::is_base_of<P, T>::value> LuaClass<T>::SetMethod(const String& name, R(P::*func)(Args...), DefArgs... defArgs)
{ {
SetMethod(name, [func] (LuaInstance& instance, T& object) -> int SetMethod(name, [func, defArgs...] (LuaInstance& instance, T& object) -> int
{ {
LuaImplMethodProxy<T, Args...> handler(instance, object); LuaImplMethodProxy<T, Args...>::Impl<DefArgs...> handler(instance, object, defArgs...);
handler.ProcessArgs(); handler.ProcessArgs();
return handler.Invoke(func); return handler.Invoke(func);
@ -189,12 +189,12 @@ namespace Nz
} }
template<class T> template<class T>
template<typename R, typename P, typename... Args> template<typename R, typename P, typename... Args, typename... DefArgs>
std::enable_if_t<std::is_base_of<P, T>::value> LuaClass<T>::SetMethod(const String& name, R(P::*func)(Args...) const) std::enable_if_t<std::is_base_of<P, T>::value> LuaClass<T>::SetMethod(const String& name, R(P::*func)(Args...) const, DefArgs... defArgs)
{ {
SetMethod(name, [func] (LuaInstance& instance, T& object) -> int SetMethod(name, [func, defArgs...] (LuaInstance& instance, T& object) -> int
{ {
LuaImplMethodProxy<T, Args...> handler(instance, object); LuaImplMethodProxy<T, Args...>::Impl<DefArgs...> handler(instance, object, defArgs...);
handler.ProcessArgs(); handler.ProcessArgs();
return handler.Invoke(func); return handler.Invoke(func);
@ -220,12 +220,12 @@ namespace Nz
} }
template<class T> template<class T>
template<typename R, typename... Args> template<typename R, typename... Args, typename... DefArgs>
void LuaClass<T>::SetStaticMethod(const String& name, R(*func)(Args...)) void LuaClass<T>::SetStaticMethod(const String& name, R(*func)(Args...), DefArgs... defArgs)
{ {
SetStaticMethod(name, [func] (LuaInstance& instance) -> int SetStaticMethod(name, [func, defArgs...] (LuaInstance& instance) -> int
{ {
LuaImplFunctionProxy<Args...> handler(instance); LuaImplFunctionProxy<Args...>::Impl<DefArgs...> handler(instance);
handler.ProcessArgs(); handler.ProcessArgs();
return handler.Invoke(func); return handler.Invoke(func);

View File

@ -43,6 +43,7 @@ namespace Nz
bool Call(unsigned int argCount, unsigned int resultCount); bool Call(unsigned int argCount, unsigned int resultCount);
template<typename T> T Check(int index); template<typename T> T Check(int index);
template<typename T> T Check(int index, T defValue);
void CheckAny(int index) const; void CheckAny(int index) const;
bool CheckBoolean(int index) const; bool CheckBoolean(int index) const;
bool CheckBoolean(int index, bool defValue) const; bool CheckBoolean(int index, bool defValue) const;
@ -115,7 +116,7 @@ namespace Nz
void PushBoolean(bool value); void PushBoolean(bool value);
void PushCFunction(LuaCFunction func, unsigned int upvalueCount = 0); void PushCFunction(LuaCFunction func, unsigned int upvalueCount = 0);
void PushFunction(LuaFunction func); void PushFunction(LuaFunction func);
template<typename R, typename... Args> void PushFunction(R(*func)(Args...)); template<typename R, typename... Args, typename... DefArgs> void PushFunction(R(*func)(Args...), DefArgs... defArgs);
void PushInteger(long long value); void PushInteger(long long value);
void PushLightUserdata(void* value); void PushLightUserdata(void* value);
void PushMetatable(const char* str); void PushMetatable(const char* str);

View File

@ -4,6 +4,7 @@
#include <Nazara/Core/Algorithm.hpp> #include <Nazara/Core/Algorithm.hpp>
#include <string> #include <string>
#include <type_traits>
namespace Nz namespace Nz
{ {
@ -13,32 +14,68 @@ namespace Nz
return instance.CheckBoolean(index); return instance.CheckBoolean(index);
} }
inline bool LuaImplQueryArg(LuaInstance& instance, unsigned int index, bool defValue, TypeTag<bool>)
{
return instance.CheckBoolean(index, defValue);
}
inline double LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<double>) inline double LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<double>)
{ {
return instance.CheckNumber(index); return instance.CheckNumber(index);
} }
inline double LuaImplQueryArg(LuaInstance& instance, unsigned int index, double defValue, TypeTag<double>)
{
return instance.CheckNumber(index, defValue);
}
inline float LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<float>) inline float LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<float>)
{ {
return static_cast<float>(instance.CheckNumber(index)); return static_cast<float>(instance.CheckNumber(index));
} }
inline float LuaImplQueryArg(LuaInstance& instance, unsigned int index, float defValue, TypeTag<float>)
{
return static_cast<float>(instance.CheckNumber(index, defValue));
}
template<typename T> template<typename T>
std::enable_if_t<std::is_enum<T>::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<T>) std::enable_if_t<std::is_enum<T>::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<T>)
{ {
return static_cast<T>(LuaImplQueryArg(instance, index, TypeTag<typename std::underlying_type<T>::type>())); return static_cast<T>(LuaImplQueryArg(instance, index, TypeTag<typename std::underlying_type<T>::type>()));
} }
template<typename T>
std::enable_if_t<std::is_enum<T>::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, T defValue, TypeTag<T>)
{
using UnderlyingT = std::underlying_type_t<T>;
return static_cast<T>(LuaImplQueryArg(instance, index, static_cast<UnderlyingT>(defValue), TypeTag<UnderlyingT>()));
}
template<typename T> template<typename T>
std::enable_if_t<std::is_integral<T>::value && !std::is_unsigned<T>::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<T>) std::enable_if_t<std::is_integral<T>::value && !std::is_unsigned<T>::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<T>)
{ {
return static_cast<T>(instance.CheckInteger(index)); return static_cast<T>(instance.CheckInteger(index));
} }
template<typename T>
std::enable_if_t<std::is_integral<T>::value && !std::is_unsigned<T>::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, T defValue, TypeTag<T>)
{
return static_cast<T>(instance.CheckInteger(index, defValue));
}
template<typename T> template<typename T>
std::enable_if_t<std::is_unsigned<T>::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<T>) std::enable_if_t<std::is_unsigned<T>::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<T>)
{ {
return static_cast<T>(LuaImplQueryArg(instance, index, TypeTag<typename std::make_signed<T>::type>())); using SignedT = std::make_signed_t<T>;
return static_cast<T>(LuaImplQueryArg(instance, index, TypeTag<SignedT>()));
}
template<typename T>
std::enable_if_t<std::is_unsigned<T>::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, T defValue, TypeTag<T>)
{
using SignedT = std::make_signed_t<T>;
return static_cast<T>(LuaImplQueryArg(instance, index, static_cast<SignedT>(defValue), TypeTag<SignedT>()));
} }
inline std::string LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<std::string>) inline std::string LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<std::string>)
@ -49,6 +86,14 @@ namespace Nz
return std::string(str, strLength); return std::string(str, strLength);
} }
inline std::string LuaImplQueryArg(LuaInstance& instance, unsigned int index, const std::string& defValue, TypeTag<std::string>)
{
std::size_t strLength = 0;
const char* str = instance.CheckString(index, defValue.c_str(), &strLength);
return std::string(str, strLength);
}
inline String LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<String>) inline String LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<String>)
{ {
std::size_t strLength = 0; std::size_t strLength = 0;
@ -57,12 +102,35 @@ namespace Nz
return String(str, strLength); return String(str, strLength);
} }
inline String LuaImplQueryArg(LuaInstance& instance, unsigned int index, const String& defValue, TypeTag<String>)
{
std::size_t strLength = 0;
const char* str = instance.CheckString(index, defValue.GetConstBuffer(), &strLength);
return String(str, strLength);
}
template<typename T> template<typename T>
T LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<const T&>) T LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<const T&>)
{ {
return LuaImplQueryArg(instance, index, TypeTag<T>()); return LuaImplQueryArg(instance, index, TypeTag<T>());
} }
template<typename T>
T LuaImplQueryArg(LuaInstance& instance, unsigned int index, const T& defValue, TypeTag<T> tag)
{
if (instance.IsValid(index))
return LuaImplQueryArg(instance, index, tag);
else
return defValue;
}
template<typename T>
T LuaImplQueryArg(LuaInstance& instance, unsigned int index, const T& defValue, TypeTag<const T&>)
{
return LuaImplQueryArg(instance, index, defValue, TypeTag<T>());
}
// Function returns // Function returns
inline int LuaImplReplyVal(LuaInstance& instance, bool val, TypeTag<bool>) inline int LuaImplReplyVal(LuaInstance& instance, bool val, TypeTag<bool>)
{ {
@ -128,120 +196,181 @@ namespace Nz
return retVal; return retVal;
} }
template<typename hasDefault>
struct LuaImplArgProcesser;
template<>
struct LuaImplArgProcesser<std::true_type>
{
template<std::size_t N, std::size_t FirstDefArg, typename ArgType, typename ArgContainer, typename DefArgContainer>
static void Process(LuaInstance& instance, ArgContainer& args, DefArgContainer& defArgs)
{
std::get<N>(args) = std::move(LuaImplQueryArg(instance, N + 1, std::get<N - FirstDefArg>(defArgs), TypeTag<ArgType>()));
}
};
template<>
struct LuaImplArgProcesser<std::false_type>
{
template<std::size_t N, std::size_t FirstDefArg, typename ArgType, typename ArgContainer, typename DefArgContainer>
static void Process(LuaInstance& instance, ArgContainer& args, DefArgContainer& defArgs)
{
NazaraUnused(defArgs);
std::get<N>(args) = std::move(LuaImplQueryArg(instance, N + 1, TypeTag<ArgType>()));
}
};
template<typename... Args> template<typename... Args>
class LuaImplFunctionProxy class LuaImplFunctionProxy
{ {
public: public:
LuaImplFunctionProxy(LuaInstance& instance) : template<typename... DefArgs>
m_instance(instance) class Impl
{ {
} static constexpr std::size_t ArgCount = sizeof...(Args);
static constexpr std::size_t DefArgCount = sizeof...(DefArgs);
template<unsigned int N> static_assert(ArgCount >= DefArgCount, "There cannot be more default arguments than argument");
void ProcessArgs()
{
// No argument to process
}
template<unsigned int N, typename ArgType> static constexpr std::size_t FirstDefArg = ArgCount - DefArgCount;
void ProcessArgs()
{
std::get<N>(m_args) = std::move(LuaImplQueryArg(m_instance, N+1, TypeTag<ArgType>()));
}
template<int N, typename ArgType1, typename ArgType2, typename... Rest> public:
void ProcessArgs() Impl(LuaInstance& instance, DefArgs... defArgs) :
{ m_defaultArgs(std::forward<DefArgs>(defArgs)...),
ProcessArgs<N, ArgType1>(); m_instance(instance),
ProcessArgs<N+1, ArgType2, Rest...>(); {
} }
void ProcessArgs() void ProcessArgs()
{ {
ProcessArgs<0, Args...>(); ProcessArgs<0, Args...>();
} }
int Invoke(void (*func)(Args...)) int Invoke(void (*func)(Args...))
{ {
Apply(func, m_args); Apply(func, m_args);
return 0; return 0;
} }
template<typename Ret> template<typename Ret>
int Invoke(Ret (*func)(Args...)) int Invoke(Ret (*func)(Args...))
{ {
return LuaImplReplyVal(m_instance, std::move(Apply(func, m_args)), TypeTag<decltype(Apply(func, m_args))>()); return LuaImplReplyVal(m_instance, std::move(Apply(func, m_args)), TypeTag<decltype(Apply(func, m_args))>());
} }
private: private:
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> m_args; using ArgContainer = std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>;
LuaInstance& m_instance; using DefArgContainer = std::tuple<std::remove_cv_t<std::remove_reference_t<DefArgs>>...>;
template<std::size_t N>
void ProcessArgs()
{
// No argument to process
}
template<std::size_t N, typename ArgType>
void ProcessArgs()
{
using CheckDefValue = typename std::integral_constant<bool, N >= FirstDefArg>;
LuaImplArgProcesser<CheckDefValue>::Process<N, FirstDefArg, ArgType>(m_instance, m_args, m_defaultArgs);
}
template<std::size_t N, typename ArgType1, typename ArgType2, typename... Rest>
void ProcessArgs()
{
ProcessArgs<N, ArgType1>();
ProcessArgs<N + 1, ArgType2, Rest...>();
}
ArgContainer m_args;
DefArgContainer m_defaultArgs;
LuaInstance& m_instance;
};
}; };
template<typename T, typename... Args> template<typename T, typename... Args>
class LuaImplMethodProxy class LuaImplMethodProxy
{ {
public: public:
LuaImplMethodProxy(LuaInstance& instance, T& object) : template<typename... DefArgs>
m_instance(instance), class Impl
m_object(object)
{ {
} static constexpr std::size_t ArgCount = sizeof...(Args);
static constexpr std::size_t DefArgCount = sizeof...(DefArgs);
template<unsigned int N> static_assert(ArgCount >= DefArgCount, "There cannot be more default arguments than argument");
void ProcessArgs()
{
// No argument to process
}
template<unsigned int N, typename ArgType> static constexpr std::size_t FirstDefArg = ArgCount - DefArgCount;
void ProcessArgs()
{
std::get<N>(m_args) = std::move(LuaImplQueryArg(m_instance, N + 1, TypeTag<ArgType>()));
}
template<unsigned int N, typename ArgType1, typename ArgType2, typename... Rest> public:
void ProcessArgs() Impl(LuaInstance& instance, T& object, DefArgs... defArgs) :
{ m_defaultArgs(std::forward<DefArgs>(defArgs)...),
ProcessArgs<N, ArgType1>(); m_instance(instance),
ProcessArgs<N + 1, ArgType2, Rest...>(); m_object(object)
} {
}
void ProcessArgs() void ProcessArgs()
{ {
ProcessArgs<0, Args...>(); ProcessArgs<0, Args...>();
} }
template<typename P> template<typename P>
std::enable_if_t<std::is_base_of<P, T>::value, int> Invoke(void(P::*func)(Args...)) std::enable_if_t<std::is_base_of<P, T>::value, int> Invoke(void(P::*func)(Args...))
{ {
Apply(m_object, func, m_args); Apply(m_object, func, m_args);
return 0; return 0;
} }
template<typename P, typename Ret> template<typename P, typename Ret>
std::enable_if_t<std::is_base_of<P, T>::value, int> Invoke(Ret(P::*func)(Args...)) std::enable_if_t<std::is_base_of<P, T>::value, int> Invoke(Ret(P::*func)(Args...))
{ {
return LuaImplReplyVal(m_instance, std::move(Apply(m_object, func, m_args)), TypeTag<decltype(Apply(m_object, func, m_args))>()); return LuaImplReplyVal(m_instance, std::move(Apply(m_object, func, m_args)), TypeTag<decltype(Apply(m_object, func, m_args))>());
} }
template<typename P> template<typename P>
std::enable_if_t<std::is_base_of<P, T>::value, int> Invoke(void(P::*func)(Args...) const) std::enable_if_t<std::is_base_of<P, T>::value, int> Invoke(void(P::*func)(Args...) const)
{ {
Apply(m_object, func, m_args); Apply(m_object, func, m_args);
return 0; return 0;
} }
template<typename P, typename Ret> template<typename P, typename Ret>
std::enable_if_t<std::is_base_of<P, T>::value, int> Invoke(Ret(P::*func)(Args...) const) std::enable_if_t<std::is_base_of<P, T>::value, int> Invoke(Ret(P::*func)(Args...) const)
{ {
return LuaImplReplyVal(m_instance, std::move(Apply(m_object, func, m_args)), TypeTag<decltype(Apply(m_object, func, m_args))>()); return LuaImplReplyVal(m_instance, std::move(Apply(m_object, func, m_args)), TypeTag<decltype(Apply(m_object, func, m_args))>());
} }
private: private:
std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> m_args; using ArgContainer = std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>;
LuaInstance& m_instance; using DefArgContainer = std::tuple<std::remove_cv_t<std::remove_reference_t<DefArgs>>...>;
T& m_object;
template<std::size_t N>
void ProcessArgs()
{
// No argument to process
}
template<std::size_t N, typename ArgType>
void ProcessArgs()
{
using CheckDefValue = typename std::integral_constant<bool, N >= FirstDefArg>;
LuaImplArgProcesser<CheckDefValue>::Process<N, FirstDefArg, ArgType>(m_instance, m_args, m_defaultArgs);
}
template<std::size_t N, typename ArgType1, typename ArgType2, typename... Rest>
void ProcessArgs()
{
ProcessArgs<N, ArgType1>();
ProcessArgs<N + 1, ArgType2, Rest...>();
}
ArgContainer m_args;
DefArgContainer m_defaultArgs;
LuaInstance& m_instance;
T& m_object;
};
}; };
template<typename T> template<typename T>
@ -250,18 +379,24 @@ namespace Nz
return LuaImplQueryArg(*this, index, TypeTag<T>()); return LuaImplQueryArg(*this, index, TypeTag<T>());
} }
template<typename T>
T LuaInstance::Check(int index, T defValue)
{
return LuaImplQueryArg(*this, index, defValue, TypeTag<T>());
}
template<typename T> template<typename T>
int LuaInstance::Push(T arg) int LuaInstance::Push(T arg)
{ {
return LuaImplReplyVal(*this, std::move(arg), TypeTag<T>()); return LuaImplReplyVal(*this, std::move(arg), TypeTag<T>());
} }
template<typename R, typename... Args> template<typename R, typename... Args, typename... DefArgs>
void LuaInstance::PushFunction(R (*func)(Args...)) void LuaInstance::PushFunction(R (*func)(Args...), DefArgs... defArgs)
{ {
PushFunction([func](LuaInstance& instance) -> int PushFunction([func, defArgs...](LuaInstance& instance) -> int
{ {
LuaImplFunctionProxy<Args...> handler(instance); LuaImplFunctionProxy<Args...>::Impl<DefArgs...> handler(instance);
handler.ProcessArgs(); handler.ProcessArgs();
return handler.Invoke(func); return handler.Invoke(func);