Merge branch 'NDK-Refactor' into NDK

Conflicts:
	examples/HardwareInfo/main.cpp
	include/Nazara/Renderer/Enums.hpp
	include/Nazara/Renderer/GpuQuery.hpp
	include/Nazara/Renderer/OpenGL.hpp
	include/Nazara/Renderer/RenderBuffer.hpp
	include/Nazara/Renderer/RenderTexture.hpp
	include/Nazara/Renderer/Texture.hpp
	src/Nazara/Graphics/AbstractRenderTechnique.cpp
	src/Nazara/Graphics/DeferredRenderTechnique.cpp
	src/Nazara/Graphics/Material.cpp
	src/Nazara/Graphics/SkyboxBackground.cpp
	src/Nazara/Renderer/GpuQuery.cpp
	src/Nazara/Renderer/OpenGL.cpp
	src/Nazara/Renderer/RenderBuffer.cpp
	src/Nazara/Renderer/RenderTexture.cpp
	src/Nazara/Renderer/Renderer.cpp
	src/Nazara/Renderer/Shader.cpp
	src/Nazara/Renderer/ShaderStage.cpp
	src/Nazara/Renderer/Texture.cpp

Former-commit-id: 2f1c7e9f9766f59ab83d9405856a1898ac4ab48f
This commit is contained in:
Lynix
2015-09-25 23:16:58 +02:00
613 changed files with 68051 additions and 66125 deletions

View File

@@ -7,49 +7,49 @@
#ifndef NAZARA_ENUMS_LUA_HPP
#define NAZARA_ENUMS_LUA_HPP
enum nzLuaComparison
enum LuaComparison
{
nzLuaComparison_Equality,
nzLuaComparison_Less,
nzLuaComparison_LessOrEqual,
LuaComparison_Equality,
LuaComparison_Less,
LuaComparison_LessOrEqual,
nzLuaComparison_Max = nzLuaComparison_LessOrEqual
LuaComparison_Max = LuaComparison_LessOrEqual
};
enum nzLuaOperation
enum LuaOperation
{
nzLuaOperation_Addition,
nzLuaOperation_BitwiseAnd,
nzLuaOperation_BitwiseLeftShift,
nzLuaOperation_BitwiseNot,
nzLuaOperation_BitwiseOr,
nzLuaOperation_BitwideRightShift,
nzLuaOperation_BitwiseXOr,
nzLuaOperation_Division,
nzLuaOperation_Exponentiation,
nzLuaOperation_FloorDivision,
nzLuaOperation_Modulo,
nzLuaOperation_Multiplication,
nzLuaOperation_Negation,
nzLuaOperation_Substraction,
LuaOperation_Addition,
LuaOperation_BitwiseAnd,
LuaOperation_BitwiseLeftShift,
LuaOperation_BitwiseNot,
LuaOperation_BitwiseOr,
LuaOperation_BitwideRightShift,
LuaOperation_BitwiseXOr,
LuaOperation_Division,
LuaOperation_Exponentiation,
LuaOperation_FloorDivision,
LuaOperation_Modulo,
LuaOperation_Multiplication,
LuaOperation_Negation,
LuaOperation_Substraction,
nzLuaOperation_Max = nzLuaOperation_Substraction
LuaOperation_Max = LuaOperation_Substraction
};
enum nzLuaType
enum LuaType
{
nzLuaType_Boolean,
nzLuaType_Function,
nzLuaType_LightUserdata,
nzLuaType_Nil,
nzLuaType_Number,
nzLuaType_None,
nzLuaType_String,
nzLuaType_Table,
nzLuaType_Thread,
nzLuaType_Userdata,
LuaType_Boolean,
LuaType_Function,
LuaType_LightUserdata,
LuaType_Nil,
LuaType_Number,
LuaType_None,
LuaType_String,
LuaType_Table,
LuaType_Thread,
LuaType_Userdata,
nzLuaType_Max = nzLuaType_Userdata
LuaType_Max = LuaType_Userdata
};
#endif // NAZARA_ENUMS_LUA_HPP

View File

@@ -11,20 +11,23 @@
#include <Nazara/Core/Initializer.hpp>
#include <Nazara/Lua/Config.hpp>
class NAZARA_LUA_API NzLua
namespace Nz
{
public:
NzLua() = delete;
~NzLua() = delete;
class NAZARA_LUA_API Lua
{
public:
Lua() = delete;
~Lua() = delete;
static bool Initialize();
static bool Initialize();
static bool IsInitialized();
static bool IsInitialized();
static void Uninitialize();
static void Uninitialize();
private:
static unsigned int s_moduleReferenceCounter;
};
private:
static unsigned int s_moduleReferenceCounter;
};
}
#endif // NAZARA_LUA_HPP

View File

@@ -14,65 +14,68 @@
#include <memory>
//#include <type_traits>
template<class T/*, class P = void*/>
class NzLuaClass
namespace Nz
{
//static_assert(std::is_same<P, void>::value || std::is_base_of<P, T>::value, "P must be a base of T");
template<class T/*, class P = void*/>
class LuaClass
{
//static_assert(std::is_same<P, void>::value || std::is_base_of<P, T>::value, "P must be a base of T");
public:
using ClassFunc = int (*)(NzLuaInstance& lua, T& instance);
using ClassIndexFunc = bool (*)(NzLuaInstance& lua, T& instance);
using ConstructorFunc = T* (*)(NzLuaInstance& lua);
using FinalizerFunc = bool (*)(NzLuaInstance& lua, T& instance);
using StaticIndexFunc = bool (*)(NzLuaInstance& lua);
using StaticFunc = int (*)(NzLuaInstance& lua);
public:
using ClassFunc = int (*)(LuaInstance& lua, T& instance);
using ClassIndexFunc = bool (*)(LuaInstance& lua, T& instance);
using ConstructorFunc = T* (*)(LuaInstance& lua);
using FinalizerFunc = bool (*)(LuaInstance& lua, T& instance);
using StaticIndexFunc = bool (*)(LuaInstance& lua);
using StaticFunc = int (*)(LuaInstance& lua);
NzLuaClass(const NzString& name);
LuaClass(const String& name);
//void Inherit(NzLuaClass<P>& parent);
//void Inherit(LuaClass<P>& parent);
void Register(NzLuaInstance& lua);
void Register(LuaInstance& lua);
void PushGlobalTable(NzLuaInstance& lua);
void PushGlobalTable(LuaInstance& lua);
void SetConstructor(ConstructorFunc constructor);
void SetFinalizer(FinalizerFunc finalizer);
void SetGetter(ClassIndexFunc getter);
void SetMethod(const NzString& name, ClassFunc method);
void SetSetter(ClassIndexFunc setter);
void SetStaticGetter(StaticIndexFunc getter);
void SetStaticMethod(const NzString& name, StaticFunc func);
void SetStaticSetter(StaticIndexFunc getter);
void SetConstructor(ConstructorFunc constructor);
void SetFinalizer(FinalizerFunc finalizer);
void SetGetter(ClassIndexFunc getter);
void SetMethod(const String& name, ClassFunc method);
void SetSetter(ClassIndexFunc setter);
void SetStaticGetter(StaticIndexFunc getter);
void SetStaticMethod(const String& name, StaticFunc func);
void SetStaticSetter(StaticIndexFunc getter);
private:
static int ConstructorProxy(lua_State* state);
static int FinalizerProxy(lua_State* state);
static int InfoDestructor(lua_State* state);
static int GetterProxy(lua_State* state);
static int MethodProxy(lua_State* state);
static int SetterProxy(lua_State* state);
static int StaticGetterProxy(lua_State* state);
static int StaticMethodProxy(lua_State* state);
static int StaticSetterProxy(lua_State* state);
private:
static int ConstructorProxy(lua_State* state);
static int FinalizerProxy(lua_State* state);
static int InfoDestructor(lua_State* state);
static int GetterProxy(lua_State* state);
static int MethodProxy(lua_State* state);
static int SetterProxy(lua_State* state);
static int StaticGetterProxy(lua_State* state);
static int StaticMethodProxy(lua_State* state);
static int StaticSetterProxy(lua_State* state);
struct ClassInfo
{
std::vector<ClassFunc> methods;
std::vector<StaticFunc> staticMethods;
ClassIndexFunc getter = nullptr;
ClassIndexFunc setter = nullptr;
ConstructorFunc constructor = nullptr;
FinalizerFunc finalizer = nullptr;
StaticIndexFunc staticGetter = nullptr;
StaticIndexFunc staticSetter = nullptr;
NzString name;
int globalTableRef = -1;
};
struct ClassInfo
{
std::vector<ClassFunc> methods;
std::vector<StaticFunc> staticMethods;
ClassIndexFunc getter = nullptr;
ClassIndexFunc setter = nullptr;
ConstructorFunc constructor = nullptr;
FinalizerFunc finalizer = nullptr;
StaticIndexFunc staticGetter = nullptr;
StaticIndexFunc staticSetter = nullptr;
String name;
int globalTableRef = -1;
};
std::map<NzString, ClassFunc> m_methods;
std::map<NzString, StaticFunc> m_staticMethods;
std::shared_ptr<ClassInfo> m_info;
};
std::map<String, ClassFunc> m_methods;
std::map<String, StaticFunc> m_staticMethods;
std::shared_ptr<ClassInfo> m_info;
};
}
#include <Nazara/Lua/LuaClass.inl>

View File

@@ -6,357 +6,360 @@
#include <Nazara/Core/MemoryHelper.hpp>
#include <Nazara/Lua/Debug.hpp>
template<class T>
NzLuaClass<T>::NzLuaClass(const NzString& name) :
m_info(new ClassInfo)
namespace Nz
{
m_info->name = name;
}
/*
template<class T>
void NzLuaClass<T>::Inherit(NzLuaClass<P>& parent)
{
static_assert(std::is_base_of<P, T>::value, "P must be a base of T");
m_info->parentInfo = parent.m_info;
}
*/
template<class T>
void NzLuaClass<T>::Register(NzLuaInstance& lua)
{
// Le ClassInfo doit rester en vie jusqu'à la fin du script
// Obliger l'instance de LuaClass à rester en vie dans cette fin serait contraignant pour l'utilisateur
// J'utilise donc une astuce, la stocker dans une UserData associée avec chaque fonction de la metatable du type,
// cette UserData disposera d'un finalizer qui libérera le ClassInfo
// Ainsi c'est Lua qui va s'occuper de la destruction pour nous :-)
// De même, l'utilisation d'un shared_ptr permet de garder la structure en vie même si l'instance est libérée avant le LuaClass
void* info = lua.PushUserdata(sizeof(std::shared_ptr<ClassInfo>));
NzPlacementNew<std::shared_ptr<ClassInfo>>(info, m_info);
// On créé la table qui contiendra une méthode (Le finalizer) pour libérer le ClassInfo
lua.PushTable(0, 1);
lua.PushLightUserdata(info);
lua.PushCFunction(InfoDestructor, 1);
lua.SetField("__gc");
lua.SetMetatable(-2); // La table devient la metatable de l'UserData
// Maintenant, nous allons associer l'UserData avec chaque fonction, de sorte qu'il reste en vie
// aussi longtemps que nécessaire, et que le pointeur soit transmis à chaque méthode
if (!lua.NewMetatable(m_info->name))
NazaraWarning("Class \"" + m_info->name + "\" already registred in this instance");
template<class T>
LuaClass<T>::LuaClass(const String& name) :
m_info(new ClassInfo)
{
lua.PushValue(1); // On associe l'UserData avec la fonction
lua.PushCFunction(FinalizerProxy, 1);
lua.SetField("__gc"); // Finalizer
m_info->name = name;
}
/*
template<class T>
void LuaClass<T>::Inherit(LuaClass<P>& parent)
{
static_assert(std::is_base_of<P, T>::value, "P must be a base of T");
if (m_info->getter)
m_info->parentInfo = parent.m_info;
}
*/
template<class T>
void LuaClass<T>::Register(LuaInstance& lua)
{
// Le ClassInfo doit rester en vie jusqu'à la fin du script
// Obliger l'instance de LuaClass à rester en vie dans cette fin serait contraignant pour l'utilisateur
// J'utilise donc une astuce, la stocker dans une UserData associée avec chaque fonction de la metatable du type,
// cette UserData disposera d'un finalizer qui libérera le ClassInfo
// Ainsi c'est Lua qui va s'occuper de la destruction pour nous :-)
// De même, l'utilisation d'un shared_ptr permet de garder la structure en vie même si l'instance est libérée avant le LuaClass
void* info = lua.PushUserdata(sizeof(std::shared_ptr<ClassInfo>));
PlacementNew<std::shared_ptr<ClassInfo>>(info, m_info);
// On créé la table qui contiendra une méthode (Le finalizer) pour libérer le ClassInfo
lua.PushTable(0, 1);
lua.PushLightUserdata(info);
lua.PushCFunction(InfoDestructor, 1);
lua.SetField("__gc");
lua.SetMetatable(-2); // La table devient la metatable de l'UserData
// Maintenant, nous allons associer l'UserData avec chaque fonction, de sorte qu'il reste en vie
// aussi longtemps que nécessaire, et que le pointeur soit transmis à chaque méthode
if (!lua.NewMetatable(m_info->name))
NazaraWarning("Class \"" + m_info->name + "\" already registred in this instance");
{
lua.PushValue(1);
lua.PushValue(1); // On associe l'UserData avec la fonction
lua.PushCFunction(FinalizerProxy, 1);
lua.SetField("__gc"); // Finalizer
if (m_info->getter)
{
lua.PushValue(1);
lua.PushValue(-2);
lua.PushCFunction(GetterProxy, 2);
}
else
// Optimisation, plutôt que de rediriger vers une fonction C qui ne fera rien d'autre que rechercher
// dans la table, nous envoyons directement la table, de sorte que Lua fasse directement la recherche
// Ceci n'est possible que si nous n'avons ni getter, ni parent
lua.PushValue(-1);
lua.SetField("__index"); // Getter
if (m_info->setter)
{
lua.PushValue(1);
lua.PushCFunction(SetterProxy, 1);
lua.SetField("__newindex"); // Setter
}
m_info->methods.reserve(m_methods.size());
for (auto& pair : m_methods)
{
m_info->methods.push_back(pair.second);
lua.PushValue(1);
lua.PushInteger(m_info->methods.size() - 1);
lua.PushCFunction(MethodProxy, 2);
lua.SetField(pair.first); // Méthode
}
}
lua.Pop(); // On pop la metatable
if (m_info->constructor || m_info->staticGetter || m_info->staticSetter || !m_info->staticMethods.empty())
{
// Création de l'instance globale
lua.PushTable(); // Class = {}
// Création de la metatable associée à la table globale
lua.PushTable(); // ClassMeta = {}
if (m_info->constructor)
{
lua.PushValue(1); // ClassInfo
lua.PushCFunction(ConstructorProxy, 1);
lua.SetField("__call"); // ClassMeta.__call = ConstructorProxy
}
if (m_info->staticGetter)
{
lua.PushValue(1);
lua.PushValue(-2);
lua.PushCFunction(StaticGetterProxy, 2);
}
else
// Optimisation, plutôt que de rediriger vers une fonction C qui ne fera rien d'autre que rechercher
// dans la table, nous envoyons directement la table, de sorte que Lua fasse directement la recherche
// Ceci n'est possible que si nous n'avons ni getter, ni parent
lua.PushValue(-1);
lua.SetField("__index"); // ClassMeta.__index = StaticGetterProxy/ClassMeta
if (m_info->staticSetter)
{
lua.PushValue(1);
lua.PushCFunction(StaticSetterProxy, 1);
lua.SetField("__newindex"); // ClassMeta.__newindex = StaticSetterProxy
}
m_info->staticMethods.reserve(m_staticMethods.size());
for (auto& pair : m_staticMethods)
{
m_info->staticMethods.push_back(pair.second);
lua.PushValue(1);
lua.PushInteger(m_info->staticMethods.size() - 1);
lua.PushCFunction(StaticMethodProxy, 2);
lua.SetField(pair.first); // ClassMeta.method = StaticMethodProxy
}
lua.SetMetatable(-2); // setmetatable(Class, ClassMeta)
lua.PushValue(-1); // Copie
lua.SetGlobal(m_info->name); // Class
m_info->globalTableRef = lua.CreateReference();
}
lua.Pop(); // On pop l'Userdata (contenant nos informations)
}
template<class T>
void LuaClass<T>::PushGlobalTable(LuaInstance& lua)
{
lua.PushReference(m_info->globalTableRef);
}
template<class T>
void LuaClass<T>::SetConstructor(ConstructorFunc constructor)
{
m_info->constructor = constructor;
}
template<class T>
void LuaClass<T>::SetFinalizer(FinalizerFunc finalizer)
{
m_info->finalizer = finalizer;
}
template<class T>
void LuaClass<T>::SetGetter(ClassIndexFunc getter)
{
m_info->getter = getter;
}
template<class T>
void LuaClass<T>::SetMethod(const String& name, ClassFunc method)
{
m_methods[name] = method;
}
template<class T>
void LuaClass<T>::SetSetter(ClassIndexFunc setter)
{
m_info->setter = setter;
}
template<class T>
void LuaClass<T>::SetStaticGetter(StaticIndexFunc getter)
{
m_info->staticGetter = getter;
}
template<class T>
void LuaClass<T>::SetStaticMethod(const String& name, StaticFunc method)
{
m_staticMethods[name] = method;
}
template<class T>
void LuaClass<T>::SetStaticSetter(StaticIndexFunc setter)
{
m_info->staticSetter = setter;
}
template<class T>
int LuaClass<T>::ConstructorProxy(lua_State* state)
{
LuaInstance& lua = *LuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
ConstructorFunc constructor = info->constructor;
lua.Remove(1); // On enlève l'argument "table" du stack
T* instance = constructor(lua);
if (!instance)
{
lua.Error("Constructor failed");
return 0; // Normalement jamais exécuté (l'erreur provoquant une exception)
}
T** ud = static_cast<T**>(lua.PushUserdata(sizeof(T*)));
*ud = instance;
lua.SetMetatable(info->name);
return 1;
}
template<class T>
int LuaClass<T>::FinalizerProxy(lua_State* state)
{
LuaInstance& lua = *LuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
FinalizerFunc finalizer = info->finalizer;
T* instance = *static_cast<T**>(lua.CheckUserdata(1, info->name));
if (!finalizer || finalizer(lua, *instance))
delete instance;
return 0;
}
template<class T>
int LuaClass<T>::InfoDestructor(lua_State* state)
{
LuaInstance& lua = *LuaInstance::GetInstance(state);
std::shared_ptr<ClassInfo>& infoPtr = *static_cast<std::shared_ptr<ClassInfo>*>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
lua.DestroyReference(infoPtr->globalTableRef);
using namespace std; // Obligatoire pour le destructeur
infoPtr.~shared_ptr(); // Si vous voyez une autre façon de faire, je suis preneur
return 0;
}
template<class T>
int LuaClass<T>::GetterProxy(lua_State* state)
{
LuaInstance& lua = *LuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
ClassIndexFunc getter = info->getter;
T& instance = *(*static_cast<T**>(lua.CheckUserdata(1, info->name)));
if (!getter(lua, instance))
{
// On accède alors à la table
lua.PushValue(lua.GetIndexOfUpValue(2));
lua.PushValue(-2);
lua.PushCFunction(GetterProxy, 2);
}
else
// Optimisation, plutôt que de rediriger vers une fonction C qui ne fera rien d'autre que rechercher
// dans la table, nous envoyons directement la table, de sorte que Lua fasse directement la recherche
// Ceci n'est possible que si nous n'avons ni getter, ni parent
lua.PushValue(-1);
lua.SetField("__index"); // Getter
if (m_info->setter)
{
lua.PushValue(1);
lua.PushCFunction(SetterProxy, 1);
lua.SetField("__newindex"); // Setter
lua.GetTable();
}
m_info->methods.reserve(m_methods.size());
for (auto& pair : m_methods)
{
m_info->methods.push_back(pair.second);
lua.PushValue(1);
lua.PushInteger(m_info->methods.size() - 1);
lua.PushCFunction(MethodProxy, 2);
lua.SetField(pair.first); // Méthode
}
return 1;
}
lua.Pop(); // On pop la metatable
if (m_info->constructor || m_info->staticGetter || m_info->staticSetter || !m_info->staticMethods.empty())
template<class T>
int LuaClass<T>::MethodProxy(lua_State* state)
{
// Création de l'instance globale
lua.PushTable(); // Class = {}
LuaInstance& lua = *LuaInstance::GetInstance(state);
// Création de la metatable associée à la table globale
lua.PushTable(); // ClassMeta = {}
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
unsigned int index = static_cast<unsigned int>(lua.ToInteger(lua.GetIndexOfUpValue(2)));
ClassFunc method = info->methods[index];
if (m_info->constructor)
T& instance = *(*static_cast<T**>(lua.CheckUserdata(1, info->name)));
lua.Remove(1); // On enlève l'argument "userdata" du stack
return method(lua, instance);
}
template<class T>
int LuaClass<T>::SetterProxy(lua_State* state)
{
LuaInstance& lua = *LuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
ClassIndexFunc setter = info->setter;
T& instance = *(*static_cast<T**>(lua.CheckUserdata(1, info->name)));
if (!setter(lua, instance))
{
lua.PushValue(1); // ClassInfo
lua.PushCFunction(ConstructorProxy, 1);
lua.SetField("__call"); // ClassMeta.__call = ConstructorProxy
std::size_t length;
const char* str = lua.ToString(2, &length);
lua.Error("Class \"" + info->name + "\" has no field \"" + String(str, length) + ')');
}
if (m_info->staticGetter)
return 1;
}
template<class T>
int LuaClass<T>::StaticGetterProxy(lua_State* state)
{
LuaInstance& lua = *LuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
StaticIndexFunc getter = info->staticGetter;
if (!getter(lua))
{
lua.PushValue(1);
// On accède alors à la table
lua.PushValue(lua.GetIndexOfUpValue(2));
lua.PushValue(-2);
lua.PushCFunction(StaticGetterProxy, 2);
lua.GetTable();
}
else
// Optimisation, plutôt que de rediriger vers une fonction C qui ne fera rien d'autre que rechercher
// dans la table, nous envoyons directement la table, de sorte que Lua fasse directement la recherche
// Ceci n'est possible que si nous n'avons ni getter, ni parent
lua.PushValue(-1);
lua.SetField("__index"); // ClassMeta.__index = StaticGetterProxy/ClassMeta
return 1;
}
if (m_info->staticSetter)
template<class T>
int LuaClass<T>::StaticMethodProxy(lua_State* state)
{
LuaInstance& lua = *LuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
unsigned int index = static_cast<unsigned int>(lua.ToInteger(lua.GetIndexOfUpValue(2)));
StaticFunc method = info->staticMethods[index];
return method(lua);
}
template<class T>
int LuaClass<T>::StaticSetterProxy(lua_State* state)
{
LuaInstance& lua = *LuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
StaticIndexFunc setter = info->staticSetter;
if (!setter(lua))
{
lua.PushValue(1);
lua.PushCFunction(StaticSetterProxy, 1);
lua.SetField("__newindex"); // ClassMeta.__newindex = StaticSetterProxy
std::size_t length;
const char* str = lua.ToString(2, &length);
lua.Error("Class \"" + info->name + "\" has no static field \"" + String(str, length) + ')');
}
m_info->staticMethods.reserve(m_staticMethods.size());
for (auto& pair : m_staticMethods)
{
m_info->staticMethods.push_back(pair.second);
lua.PushValue(1);
lua.PushInteger(m_info->staticMethods.size() - 1);
lua.PushCFunction(StaticMethodProxy, 2);
lua.SetField(pair.first); // ClassMeta.method = StaticMethodProxy
}
lua.SetMetatable(-2); // setmetatable(Class, ClassMeta)
lua.PushValue(-1); // Copie
lua.SetGlobal(m_info->name); // Class
m_info->globalTableRef = lua.CreateReference();
return 1;
}
lua.Pop(); // On pop l'Userdata (contenant nos informations)
}
template<class T>
void NzLuaClass<T>::PushGlobalTable(NzLuaInstance& lua)
{
lua.PushReference(m_info->globalTableRef);
}
template<class T>
void NzLuaClass<T>::SetConstructor(ConstructorFunc constructor)
{
m_info->constructor = constructor;
}
template<class T>
void NzLuaClass<T>::SetFinalizer(FinalizerFunc finalizer)
{
m_info->finalizer = finalizer;
}
template<class T>
void NzLuaClass<T>::SetGetter(ClassIndexFunc getter)
{
m_info->getter = getter;
}
template<class T>
void NzLuaClass<T>::SetMethod(const NzString& name, ClassFunc method)
{
m_methods[name] = method;
}
template<class T>
void NzLuaClass<T>::SetSetter(ClassIndexFunc setter)
{
m_info->setter = setter;
}
template<class T>
void NzLuaClass<T>::SetStaticGetter(StaticIndexFunc getter)
{
m_info->staticGetter = getter;
}
template<class T>
void NzLuaClass<T>::SetStaticMethod(const NzString& name, StaticFunc method)
{
m_staticMethods[name] = method;
}
template<class T>
void NzLuaClass<T>::SetStaticSetter(StaticIndexFunc setter)
{
m_info->staticSetter = setter;
}
template<class T>
int NzLuaClass<T>::ConstructorProxy(lua_State* state)
{
NzLuaInstance& lua = *NzLuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
ConstructorFunc constructor = info->constructor;
lua.Remove(1); // On enlève l'argument "table" du stack
T* instance = constructor(lua);
if (!instance)
{
lua.Error("Constructor failed");
return 0; // Normalement jamais exécuté (l'erreur provoquant une exception)
}
T** ud = static_cast<T**>(lua.PushUserdata(sizeof(T*)));
*ud = instance;
lua.SetMetatable(info->name);
return 1;
}
template<class T>
int NzLuaClass<T>::FinalizerProxy(lua_State* state)
{
NzLuaInstance& lua = *NzLuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
FinalizerFunc finalizer = info->finalizer;
T* instance = *static_cast<T**>(lua.CheckUserdata(1, info->name));
if (!finalizer || finalizer(lua, *instance))
delete instance;
return 0;
}
template<class T>
int NzLuaClass<T>::InfoDestructor(lua_State* state)
{
NzLuaInstance& lua = *NzLuaInstance::GetInstance(state);
std::shared_ptr<ClassInfo>& infoPtr = *static_cast<std::shared_ptr<ClassInfo>*>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
lua.DestroyReference(infoPtr->globalTableRef);
using namespace std; // Obligatoire pour le destructeur
infoPtr.~shared_ptr(); // Si vous voyez une autre façon de faire, je suis preneur
return 0;
}
template<class T>
int NzLuaClass<T>::GetterProxy(lua_State* state)
{
NzLuaInstance& lua = *NzLuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
ClassIndexFunc getter = info->getter;
T& instance = *(*static_cast<T**>(lua.CheckUserdata(1, info->name)));
if (!getter(lua, instance))
{
// On accède alors à la table
lua.PushValue(lua.GetIndexOfUpValue(2));
lua.PushValue(-2);
lua.GetTable();
}
return 1;
}
template<class T>
int NzLuaClass<T>::MethodProxy(lua_State* state)
{
NzLuaInstance& lua = *NzLuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
unsigned int index = static_cast<unsigned int>(lua.ToInteger(lua.GetIndexOfUpValue(2)));
ClassFunc method = info->methods[index];
T& instance = *(*static_cast<T**>(lua.CheckUserdata(1, info->name)));
lua.Remove(1); // On enlève l'argument "userdata" du stack
return method(lua, instance);
}
template<class T>
int NzLuaClass<T>::SetterProxy(lua_State* state)
{
NzLuaInstance& lua = *NzLuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
ClassIndexFunc setter = info->setter;
T& instance = *(*static_cast<T**>(lua.CheckUserdata(1, info->name)));
if (!setter(lua, instance))
{
std::size_t length;
const char* str = lua.ToString(2, &length);
lua.Error("Class \"" + info->name + "\" has no field \"" + NzString(str, length) + ')');
}
return 1;
}
template<class T>
int NzLuaClass<T>::StaticGetterProxy(lua_State* state)
{
NzLuaInstance& lua = *NzLuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
StaticIndexFunc getter = info->staticGetter;
if (!getter(lua))
{
// On accède alors à la table
lua.PushValue(lua.GetIndexOfUpValue(2));
lua.PushValue(-2);
lua.GetTable();
}
return 1;
}
template<class T>
int NzLuaClass<T>::StaticMethodProxy(lua_State* state)
{
NzLuaInstance& lua = *NzLuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
unsigned int index = static_cast<unsigned int>(lua.ToInteger(lua.GetIndexOfUpValue(2)));
StaticFunc method = info->staticMethods[index];
return method(lua);
}
template<class T>
int NzLuaClass<T>::StaticSetterProxy(lua_State* state)
{
NzLuaInstance& lua = *NzLuaInstance::GetInstance(state);
ClassInfo* info = *static_cast<ClassInfo**>(lua.ToUserdata(lua.GetIndexOfUpValue(1)));
StaticIndexFunc setter = info->staticSetter;
if (!setter(lua))
{
std::size_t length;
const char* str = lua.ToString(2, &length);
lua.Error("Class \"" + info->name + "\" has no static field \"" + NzString(str, length) + ')');
}
return 1;
}
#include <Nazara/Lua/DebugOff.hpp>

View File

@@ -10,7 +10,6 @@
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Core/Clock.hpp>
#include <Nazara/Core/InputStream.hpp>
#include <Nazara/Core/NonCopyable.hpp>
#include <Nazara/Core/String.hpp>
#include <Nazara/Lua/Config.hpp>
#include <Nazara/Lua/Enums.hpp>
@@ -20,152 +19,160 @@
struct lua_Debug;
struct lua_State;
class NzLuaInstance;
using NzLuaCFunction = int (*)(lua_State* state);
using NzLuaFunction = std::function<int(NzLuaInstance& instance)>;
class NAZARA_LUA_API NzLuaInstance : NzNonCopyable
namespace Nz
{
public:
NzLuaInstance();
~NzLuaInstance();
class LuaInstance;
void ArgCheck(bool condition, unsigned int argNum, const char* error);
void ArgCheck(bool condition, unsigned int argNum, const NzString& error);
int ArgError(unsigned int argNum, const char* error);
int ArgError(unsigned int argNum, const NzString& error);
using LuaCFunction = int (*)(lua_State* state);
using LuaFunction = std::function<int(LuaInstance& instance)>;
bool Call(unsigned int argCount);
bool Call(unsigned int argCount, unsigned int resultCount);
class NAZARA_LUA_API LuaInstance
{
public:
LuaInstance();
LuaInstance(const LuaInstance&) = delete;
LuaInstance(LuaInstance&&) = delete; ///TODO
~LuaInstance();
void CheckAny(int index) const;
bool CheckBoolean(int index) const;
bool CheckBoolean(int index, bool defValue) const;
long long CheckInteger(int index) const;
long long CheckInteger(int index, long long defValue) const;
double CheckNumber(int index) const;
double CheckNumber(int index, double defValue) const;
void CheckStack(int space, const char* error = nullptr) const;
void CheckStack(int space, const NzString& error) const;
const char* CheckString(int index, std::size_t* length = nullptr) const;
const char* CheckString(int index, const char* defValue, std::size_t* length = nullptr) const;
void CheckType(int index, nzLuaType type) const;
void* CheckUserdata(int index, const char* tname) const;
void* CheckUserdata(int index, const NzString& tname) const;
void ArgCheck(bool condition, unsigned int argNum, const char* error);
void ArgCheck(bool condition, unsigned int argNum, const String& error);
int ArgError(unsigned int argNum, const char* error);
int ArgError(unsigned int argNum, const String& error);
bool Compare(int index1, int index2, nzLuaComparison comparison) const;
void Compute(nzLuaOperation operation);
bool Call(unsigned int argCount);
bool Call(unsigned int argCount, unsigned int resultCount);
void Concatenate(int count);
void CheckAny(int index) const;
bool CheckBoolean(int index) const;
bool CheckBoolean(int index, bool defValue) const;
long long CheckInteger(int index) const;
long long CheckInteger(int index, long long defValue) const;
double CheckNumber(int index) const;
double CheckNumber(int index, double defValue) const;
void CheckStack(int space, const char* error = nullptr) const;
void CheckStack(int space, const String& error) const;
const char* CheckString(int index, std::size_t* length = nullptr) const;
const char* CheckString(int index, const char* defValue, std::size_t* length = nullptr) const;
void CheckType(int index, LuaType type) const;
void* CheckUserdata(int index, const char* tname) const;
void* CheckUserdata(int index, const String& tname) const;
int CreateReference();
void DestroyReference(int ref);
bool Compare(int index1, int index2, LuaComparison comparison) const;
void Compute(LuaOperation operation);
NzString DumpStack() const;
void Concatenate(int count);
void Error(const char* message);
void Error(const NzString& message);
int CreateReference();
void DestroyReference(int ref);
bool Execute(const NzString& code);
bool ExecuteFromFile(const NzString& filePath);
bool ExecuteFromMemory(const void* data, unsigned int size);
bool ExecuteFromStream(NzInputStream& stream);
String DumpStack() const;
int GetAbsIndex(int index) const;
nzLuaType GetField(const char* fieldName, int index = -1) const;
nzLuaType GetField(const NzString& fieldName, int index = -1) const;
nzLuaType GetGlobal(const char* name) const;
nzLuaType GetGlobal(const NzString& name) const;
lua_State* GetInternalState() const;
NzString GetLastError() const;
nzUInt32 GetMemoryLimit() const;
nzUInt32 GetMemoryUsage() const;
nzLuaType GetMetatable(const char* tname) const;
nzLuaType GetMetatable(const NzString& tname) const;
bool GetMetatable(int index) const;
unsigned int GetStackTop() const;
nzLuaType GetTable(int index = -2) const;
nzUInt32 GetTimeLimit() const;
nzLuaType GetType(int index) const;
const char* GetTypeName(nzLuaType type) const;
void Error(const char* message);
void Error(const String& message);
void Insert(int index);
bool Execute(const String& code);
bool ExecuteFromFile(const String& filePath);
bool ExecuteFromMemory(const void* data, unsigned int size);
bool ExecuteFromStream(InputStream& stream);
bool IsOfType(int index, nzLuaType type) const;
bool IsOfType(int index, const char* tname) const;
bool IsOfType(int index, const NzString& tname) const;
bool IsValid(int index) const;
int GetAbsIndex(int index) const;
LuaType GetField(const char* fieldName, int index = -1) const;
LuaType GetField(const String& fieldName, int index = -1) const;
LuaType GetGlobal(const char* name) const;
LuaType GetGlobal(const String& name) const;
lua_State* GetInternalState() const;
String GetLastError() const;
UInt32 GetMemoryLimit() const;
UInt32 GetMemoryUsage() const;
LuaType GetMetatable(const char* tname) const;
LuaType GetMetatable(const String& tname) const;
bool GetMetatable(int index) const;
unsigned int GetStackTop() const;
LuaType GetTable(int index = -2) const;
UInt32 GetTimeLimit() const;
LuaType GetType(int index) const;
const char* GetTypeName(LuaType type) const;
long long Length(int index) const;
void Insert(int index);
void MoveTo(NzLuaInstance* instance, int n);
bool IsOfType(int index, LuaType type) const;
bool IsOfType(int index, const char* tname) const;
bool IsOfType(int index, const String& tname) const;
bool IsValid(int index) const;
bool NewMetatable(const char* str);
bool NewMetatable(const NzString& str);
bool Next(int index = -2);
long long Length(int index) const;
void Pop(unsigned int n = 1U);
void MoveTo(LuaInstance* instance, int n);
void PushBoolean(bool value);
void PushCFunction(NzLuaCFunction func, unsigned int upvalueCount = 0);
void PushFunction(NzLuaFunction func);
template<typename R, typename... Args> void PushFunction(R(*func)(Args...));
void PushInteger(long long value);
void PushLightUserdata(void* value);
void PushMetatable(const char* str);
void PushMetatable(const NzString& str);
void PushNil();
void PushNumber(double value);
void PushReference(int ref);
void PushString(const char* str);
void PushString(const char* str, unsigned int size);
void PushString(const NzString& str);
void PushTable(unsigned int sequenceElementCount = 0, unsigned int arrayElementCount = 0);
void* PushUserdata(unsigned int size);
void PushValue(int index);
bool NewMetatable(const char* str);
bool NewMetatable(const String& str);
bool Next(int index = -2);
void Remove(int index);
void Replace(int index);
void Pop(unsigned int n = 1U);
void SetField(const char* name, int index = -2);
void SetField(const NzString& name, int index = -2);
void SetGlobal(const char* name);
void SetGlobal(const NzString& name);
void SetMetatable(const char* tname);
void SetMetatable(const NzString& tname);
void SetMetatable(int index);
void SetMemoryLimit(nzUInt32 memoryLimit);
void SetTable(int index = -3);
void SetTimeLimit(nzUInt32 timeLimit);
void PushBoolean(bool value);
void PushCFunction(LuaCFunction func, unsigned int upvalueCount = 0);
void PushFunction(LuaFunction func);
template<typename R, typename... Args> void PushFunction(R(*func)(Args...));
void PushInteger(long long value);
void PushLightUserdata(void* value);
void PushMetatable(const char* str);
void PushMetatable(const String& str);
void PushNil();
void PushNumber(double value);
void PushReference(int ref);
void PushString(const char* str);
void PushString(const char* str, unsigned int size);
void PushString(const String& str);
void PushTable(unsigned int sequenceElementCount = 0, unsigned int arrayElementCount = 0);
void* PushUserdata(unsigned int size);
void PushValue(int index);
bool ToBoolean(int index) const;
long long ToInteger(int index, bool* succeeded = nullptr) const;
double ToNumber(int index, bool* succeeded = nullptr) const;
const void* ToPointer(int index) const;
const char* ToString(int index, std::size_t* length = nullptr) const;
void* ToUserdata(int index) const;
void* ToUserdata(int index, const char* tname) const;
void* ToUserdata(int index, const NzString& tname) const;
void Remove(int index);
void Replace(int index);
static int GetIndexOfUpValue(int upValue);
static NzLuaInstance* GetInstance(lua_State* state);
void SetField(const char* name, int index = -2);
void SetField(const String& name, int index = -2);
void SetGlobal(const char* name);
void SetGlobal(const String& name);
void SetMetatable(const char* tname);
void SetMetatable(const String& tname);
void SetMetatable(int index);
void SetMemoryLimit(UInt32 memoryLimit);
void SetTable(int index = -3);
void SetTimeLimit(UInt32 timeLimit);
private:
bool Run(int argCount, int resultCount);
bool ToBoolean(int index) const;
long long ToInteger(int index, bool* succeeded = nullptr) const;
double ToNumber(int index, bool* succeeded = nullptr) const;
const void* ToPointer(int index) const;
const char* ToString(int index, std::size_t* length = nullptr) const;
void* ToUserdata(int index) const;
void* ToUserdata(int index, const char* tname) const;
void* ToUserdata(int index, const String& tname) const;
static void* MemoryAllocator(void *ud, void *ptr, std::size_t osize, std::size_t nsize);
static int ProxyFunc(lua_State* state);
static void TimeLimiter(lua_State* state, lua_Debug* debug);
LuaInstance& operator=(const LuaInstance&) = delete;
LuaInstance& operator=(LuaInstance&&) = delete; ///TODO
nzUInt32 m_memoryLimit;
nzUInt32 m_memoryUsage;
nzUInt32 m_timeLimit;
NzClock m_clock;
NzString m_lastError;
lua_State* m_state;
unsigned int m_level;
};
static int GetIndexOfUpValue(int upValue);
static LuaInstance* GetInstance(lua_State* state);
private:
bool Run(int argCount, int resultCount);
static void* MemoryAllocator(void *ud, void *ptr, std::size_t osize, std::size_t nsize);
static int ProxyFunc(lua_State* state);
static void TimeLimiter(lua_State* state, lua_Debug* debug);
UInt32 m_memoryLimit;
UInt32 m_memoryUsage;
UInt32 m_timeLimit;
Clock m_clock;
String m_lastError;
lua_State* m_state;
unsigned int m_level;
};
}
#include <Nazara/Lua/LuaInstance.inl>

View File

@@ -5,163 +5,166 @@
#include <Nazara/Core/Algorithm.hpp>
#include <string>
// Functions args
bool NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<bool>)
namespace Nz
{
return instance.CheckBoolean(index);
}
double NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<double>)
{
return instance.CheckNumber(index);
}
float NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<float>)
{
return static_cast<float>(instance.CheckNumber(index));
}
int NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<int>)
{
return static_cast<int>(instance.CheckInteger(index));
}
std::string NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<std::string>)
{
std::size_t strLength = 0;
const char* str = instance.CheckString(index, &strLength);
return std::string(str, strLength);
}
NzString NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<NzString>)
{
std::size_t strLength = 0;
const char* str = instance.CheckString(index, &strLength);
return NzString(str, strLength);
}
template<typename T>
T NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<const T&>)
{
return NzLuaImplQueryArg(instance, index, NzTypeTag<T>());
}
template<typename T>
std::enable_if_t<std::is_unsigned<T>::value, T> NzLuaImplQueryArg(NzLuaInstance& instance, unsigned int index, NzTypeTag<T>)
{
return static_cast<T>(NzLuaImplQueryArg(instance, index, NzTypeTag<typename std::make_signed<T>::type>()));
}
// Function returns
int NzLuaImplReplyVal(NzLuaInstance& instance, bool&& val, NzTypeTag<bool>)
{
instance.PushBoolean(val);
return 1;
}
int NzLuaImplReplyVal(NzLuaInstance& instance, double&& val, NzTypeTag<double>)
{
instance.PushNumber(val);
return 1;
}
int NzLuaImplReplyVal(NzLuaInstance& instance, float&& val, NzTypeTag<float>)
{
instance.PushNumber(val);
return 1;
}
int NzLuaImplReplyVal(NzLuaInstance& instance, int&& val, NzTypeTag<int>)
{
instance.PushInteger(val);
return 1;
}
int NzLuaImplReplyVal(NzLuaInstance& instance, std::string&& val, NzTypeTag<std::string>)
{
instance.PushString(val.c_str(), val.size());
return 1;
}
int NzLuaImplReplyVal(NzLuaInstance& instance, NzString&& val, NzTypeTag<NzString>)
{
instance.PushString(std::move(val));
return 1;
}
template<typename T1, typename T2>
int NzLuaImplReplyVal(NzLuaInstance& instance, std::pair<T1, T2>&& val, NzTypeTag<std::pair<T1, T2>>)
{
int retVal = 0;
retVal += NzLuaImplReplyVal(instance, std::move(val.first), NzTypeTag<T1>());
retVal += NzLuaImplReplyVal(instance, std::move(val.second), NzTypeTag<T2>());
return retVal;
}
template<typename T>
std::enable_if_t<std::is_unsigned<T>::value, int> NzLuaImplReplyVal(NzLuaInstance& instance, T&& val, NzTypeTag<T>)
{
using SignedT = typename std::make_signed<T>::type;
return NzLuaImplReplyVal(instance, val, NzTypeTag<SignedT>());
}
template<typename... Args>
class NzLuaImplFunctionProxy
{
public:
NzLuaImplFunctionProxy(NzLuaInstance& instance) :
m_instance(instance)
{
}
template<unsigned int N, typename ArgType>
void ProcessArgs()
{
std::get<N>(m_args) = std::move(NzLuaImplQueryArg(m_instance, N+1, NzTypeTag<ArgType>()));
}
template<int N, typename ArgType1, typename ArgType2, typename... Rest>
void ProcessArgs()
{
ProcessArgs<N, ArgType1>();
ProcessArgs<N+1, ArgType2, Rest...>();
}
void ProcessArgs()
{
ProcessArgs<0, Args...>();
}
int Invoke(void (*func)(Args...))
{
NzApply(func, m_args);
return 0;
}
template<typename Ret>
int Invoke(Ret (*func)(Args...))
{
return NzLuaImplReplyVal(m_instance, std::move(NzApply(func, m_args)), NzTypeTag<decltype(NzApply(func, m_args))>());
}
private:
NzLuaInstance& m_instance;
std::tuple<Args...> m_args;
};
template<typename R, typename... Args>
void NzLuaInstance::PushFunction(R(*func)(Args...))
{
PushFunction([func](NzLuaInstance& instance) -> int
// Functions args
bool LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<bool>)
{
NzLuaImplFunctionProxy<Args...> handler(instance);
handler.ProcessArgs();
return instance.CheckBoolean(index);
}
return handler.Invoke(func);
});
double LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<double>)
{
return instance.CheckNumber(index);
}
float LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<float>)
{
return static_cast<float>(instance.CheckNumber(index));
}
int LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<int>)
{
return static_cast<int>(instance.CheckInteger(index));
}
std::string LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<std::string>)
{
std::size_t strLength = 0;
const char* str = instance.CheckString(index, &strLength);
return std::string(str, strLength);
}
String LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<String>)
{
std::size_t strLength = 0;
const char* str = instance.CheckString(index, &strLength);
return String(str, strLength);
}
template<typename T>
T LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag<const T&>)
{
return LuaImplQueryArg(instance, index, TypeTag<T>());
}
template<typename 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>()));
}
// Function returns
int LuaImplReplyVal(LuaInstance& instance, bool&& val, TypeTag<bool>)
{
instance.PushBoolean(val);
return 1;
}
int LuaImplReplyVal(LuaInstance& instance, double&& val, TypeTag<double>)
{
instance.PushNumber(val);
return 1;
}
int LuaImplReplyVal(LuaInstance& instance, float&& val, TypeTag<float>)
{
instance.PushNumber(val);
return 1;
}
int LuaImplReplyVal(LuaInstance& instance, int&& val, TypeTag<int>)
{
instance.PushInteger(val);
return 1;
}
int LuaImplReplyVal(LuaInstance& instance, std::string&& val, TypeTag<std::string>)
{
instance.PushString(val.c_str(), val.size());
return 1;
}
int LuaImplReplyVal(LuaInstance& instance, String&& val, TypeTag<String>)
{
instance.PushString(std::move(val));
return 1;
}
template<typename T1, typename T2>
int LuaImplReplyVal(LuaInstance& instance, std::pair<T1, T2>&& val, TypeTag<std::pair<T1, T2>>)
{
int retVal = 0;
retVal += LuaImplReplyVal(instance, std::move(val.first), TypeTag<T1>());
retVal += LuaImplReplyVal(instance, std::move(val.second), TypeTag<T2>());
return retVal;
}
template<typename T>
std::enable_if_t<std::is_unsigned<T>::value, int> LuaImplReplyVal(LuaInstance& instance, T&& val, TypeTag<T>)
{
using SignedT = typename std::make_signed<T>::type;
return LuaImplReplyVal(instance, val, TypeTag<SignedT>());
}
template<typename... Args>
class LuaImplFunctionProxy
{
public:
LuaImplFunctionProxy(LuaInstance& instance) :
m_instance(instance)
{
}
template<unsigned int N, typename ArgType>
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>
void ProcessArgs()
{
ProcessArgs<N, ArgType1>();
ProcessArgs<N+1, ArgType2, Rest...>();
}
void ProcessArgs()
{
ProcessArgs<0, Args...>();
}
int Invoke(void (*func)(Args...))
{
Apply(func, m_args);
return 0;
}
template<typename Ret>
int Invoke(Ret (*func)(Args...))
{
return LuaImplReplyVal(m_instance, std::move(Apply(func, m_args)), TypeTag<decltype(Apply(func, m_args))>());
}
private:
LuaInstance& m_instance;
std::tuple<Args...> m_args;
};
template<typename R, typename... Args>
void LuaInstance::PushFunction(R(*func)(Args...))
{
PushFunction([func](LuaInstance& instance) -> int
{
LuaImplFunctionProxy<Args...> handler(instance);
handler.ProcessArgs();
return handler.Invoke(func);
});
}
}