715 lines
22 KiB
C++
715 lines
22 KiB
C++
/*
|
|
* Copyright (c) 2010-2013 Alexander Ames
|
|
* Alexander.Ames@gmail.com
|
|
* See Copyright Notice at the end of this file
|
|
*/
|
|
|
|
// API Summary:
|
|
//
|
|
// This is a set of utility functions that add to the functionalit of
|
|
// LuaWrapper. Over time I found myself repeating a few patterns, such as
|
|
// writing many trvial getter and setter functions, and wanting pass ownership
|
|
// of one object to another and have the Lua script properly handle that case.
|
|
//
|
|
// This file contains the additional functions that I've added but that do
|
|
// not really belong in the core API.
|
|
|
|
#ifndef LUAWRAPPERUTILS_HPP_
|
|
#define LUAWRAPPERUTILS_HPP_
|
|
|
|
#include "luawrapper.hpp"
|
|
|
|
#ifndef LUAW_NO_CXX11
|
|
#include <type_traits>
|
|
#endif
|
|
|
|
#ifndef LUAW_STD
|
|
#define LUAW_STD std
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// A set of templated luaL_check and lua_push functions for use in the getters
|
|
// and setters below
|
|
//
|
|
// It is often useful to override luaU_check, luaU_to and/or luaU_push to
|
|
// operate on your own simple types rather than register your type with
|
|
// LuaWrapper, especially with small objects.
|
|
//
|
|
|
|
template<typename U, typename = void>
|
|
struct luaU_Impl
|
|
{
|
|
static U luaU_check(lua_State* L, int index);
|
|
static U luaU_to (lua_State* L, int index);
|
|
static void luaU_push (lua_State* L, const U& value);
|
|
static void luaU_push (lua_State* L, U& value);
|
|
};
|
|
|
|
template<typename U> U luaU_check(lua_State* L, int index) { return luaU_Impl<U>::luaU_check(L, index); }
|
|
template<typename U> U luaU_to (lua_State* L, int index) { return luaU_Impl<U>::luaU_to (L, index); }
|
|
template<typename U> void luaU_push (lua_State* L, const U& value) { luaU_Impl<U>::luaU_push (L, value); }
|
|
template<typename U> void luaU_push (lua_State* L, U& value) { luaU_Impl<U>::luaU_push (L, value); }
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// This is slightly different than the previous three functions in that you
|
|
// shouldn't need to write your own version of it, since it uses luaU_check
|
|
// automatically.
|
|
//
|
|
template<typename U>
|
|
U luaU_opt(lua_State* L, int index, const U& fallback = U())
|
|
{
|
|
if (lua_isnil(L, index))
|
|
return fallback;
|
|
else
|
|
return luaU_Impl<U>::luaU_check(L, index);
|
|
}
|
|
|
|
template<>
|
|
struct luaU_Impl<bool>
|
|
{
|
|
static bool luaU_check(lua_State* L, int index) { return lua_toboolean (L, index) != 0; }
|
|
static bool luaU_to (lua_State* L, int index) { return lua_toboolean (L, index) != 0; }
|
|
static void luaU_push (lua_State* L, const bool& value) { lua_pushboolean(L, value); }
|
|
};
|
|
|
|
template<>
|
|
struct luaU_Impl<const char*>
|
|
{
|
|
static const char* luaU_check(lua_State* L, int index) { return luaL_checkstring(L, index); }
|
|
static const char* luaU_to (lua_State* L, int index) { return lua_tostring (L, index); }
|
|
static void luaU_push (lua_State* L, const char* const& value) { lua_pushstring (L, value); }
|
|
};
|
|
|
|
template<>
|
|
struct luaU_Impl<unsigned int>
|
|
{
|
|
static unsigned int luaU_check(lua_State* L, int index) { return static_cast<unsigned int>(luaL_checkinteger(L, index)); }
|
|
static unsigned int luaU_to (lua_State* L, int index) { return static_cast<unsigned int>(lua_tointeger (L, index)); }
|
|
static void luaU_push (lua_State* L, const unsigned int& value) { lua_pushinteger (L, value); }
|
|
};
|
|
|
|
template<>
|
|
struct luaU_Impl<int>
|
|
{
|
|
static int luaU_check(lua_State* L, int index) { return static_cast<int>(luaL_checkinteger(L, index)); }
|
|
static int luaU_to (lua_State* L, int index) { return static_cast<int>(lua_tointeger (L, index)); }
|
|
static void luaU_push (lua_State* L, const int& value) { lua_pushinteger (L, value); }
|
|
};
|
|
|
|
template<>
|
|
struct luaU_Impl<unsigned char>
|
|
{
|
|
static unsigned char luaU_check(lua_State* L, int index) { return static_cast<unsigned char>(luaL_checkinteger(L, index)); }
|
|
static unsigned char luaU_to (lua_State* L, int index) { return static_cast<unsigned char>(lua_tointeger (L, index)); }
|
|
static void luaU_push (lua_State* L, const unsigned char& value) { lua_pushinteger (L, value); }
|
|
};
|
|
|
|
template<>
|
|
struct luaU_Impl<char>
|
|
{
|
|
static char luaU_check(lua_State* L, int index) { return static_cast<char>(luaL_checkinteger(L, index)); }
|
|
static char luaU_to (lua_State* L, int index) { return static_cast<char>(lua_tointeger (L, index)); }
|
|
static void luaU_push (lua_State* L, const char& value) { lua_pushinteger (L, value); }
|
|
};
|
|
|
|
template<>
|
|
struct luaU_Impl<float>
|
|
{
|
|
static float luaU_check(lua_State* L, int index) { return static_cast<float>(luaL_checknumber(L, index)); }
|
|
static float luaU_to (lua_State* L, int index) { return static_cast<float>(lua_tonumber (L, index)); }
|
|
static void luaU_push (lua_State* L, const float& value) { lua_pushnumber (L, value); }
|
|
};
|
|
|
|
template<>
|
|
struct luaU_Impl<double>
|
|
{
|
|
static double luaU_check(lua_State* L, int index) { return static_cast<double>(luaL_checknumber(L, index)); }
|
|
static double luaU_to (lua_State* L, int index) { return static_cast<double>(lua_tonumber (L, index)); }
|
|
static void luaU_push (lua_State* L, const double& value) { lua_pushnumber (L, value); }
|
|
};
|
|
|
|
#ifndef LUAW_NO_CXX11
|
|
template<typename T>
|
|
struct luaU_Impl<T, typename LUAW_STD::enable_if<LUAW_STD::is_enum<T>::value>::type>
|
|
{
|
|
static T luaU_check(lua_State* L, int index) { return static_cast<T>(luaL_checkinteger (L, index)); }
|
|
static T luaU_to (lua_State* L, int index) { return static_cast<T>(lua_tointeger (L, index)); }
|
|
static void luaU_push (lua_State* L, const T& value) { lua_pushnumber(L, static_cast<int>(value )); }
|
|
};
|
|
|
|
template<typename T>
|
|
struct luaU_Impl<T*, typename LUAW_STD::enable_if<LUAW_STD::is_class<T>::value>::type>
|
|
{
|
|
static T* luaU_check( lua_State* L, int index) { return luaW_check<T>(L, index); }
|
|
static T* luaU_to ( lua_State* L, int index) { return luaW_to <T>(L, index); }
|
|
static void luaU_push ( lua_State* L, T*& value) { luaW_push <T>(L, value); }
|
|
static void luaU_push ( lua_State* L, T* value) { luaW_push <T>(L, value); }
|
|
};
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// These are just some functions I've always felt should exist
|
|
//
|
|
|
|
template <typename U>
|
|
inline U luaU_getfield(lua_State* L, int index, const char* field)
|
|
{
|
|
#ifndef LUAW_NO_CXX11
|
|
static_assert(!std::is_same<U, const char*>::value,
|
|
"luaU_getfield is not safe to use on const char*'s. (The string will be popped from the stack.)");
|
|
#endif
|
|
lua_getfield(L, index, field);
|
|
U val = luaU_to<U>(L, -1);
|
|
lua_pop(L, 1);
|
|
return val;
|
|
}
|
|
|
|
template <typename U>
|
|
inline U luaU_checkfield(lua_State* L, int index, const char* field)
|
|
{
|
|
#ifndef LUAW_NO_CXX11
|
|
static_assert(!std::is_same<U, const char*>::value,
|
|
"luaU_checkfield is not safe to use on const char*'s. (The string will be popped from the stack.)");
|
|
#endif
|
|
lua_getfield(L, index, field);
|
|
U val = luaU_check<U>(L, -1);
|
|
lua_pop(L, 1);
|
|
return val;
|
|
}
|
|
|
|
template <typename U>
|
|
inline void luaU_setfield(lua_State* L, int index, const char* field, U val)
|
|
{
|
|
luaU_push<U>(L, val);
|
|
lua_setfield(L, luaW_correctindex(L, index, 1), field);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// A set of trivial getter and setter templates. These templates are designed
|
|
// to call trivial getters or setters.
|
|
//
|
|
// There are four forms:
|
|
// 1. Getting or setting a public member variable that is of a primitive type
|
|
// 2. Getting or setting a public member variable that is a pointer to an
|
|
// object
|
|
// 3. Getting or setting a private member variable that is of a primitive type
|
|
// through a getter or setter
|
|
// 3. Getting or setting a private member variable that is is a pointer to an
|
|
// object through a getter or setter
|
|
//
|
|
// The interface to all of them is the same however. In addition to plain
|
|
// getter and setter functions, there is a getset which does both - if an
|
|
// argument is supplied it attempts to set the value, and in either case it
|
|
// returns the value. In your lua table declaration in C++ rather than write
|
|
// individiual wrappers for each getter and setter you may do the following:
|
|
//
|
|
// static luaL_reg Foo_metatable[] =
|
|
// {
|
|
// { "GetBar", luaU_get<Foo, bool, &Widget::GetBar> },
|
|
// { "SetBar", luaU_set<Foo, bool, &Widget::SetBar> },
|
|
// { "Bar", luaU_getset<Foo, bool, &Widget::GetBar, &Widget::SetBar> },
|
|
// { NULL, NULL }
|
|
// }
|
|
//
|
|
// Getters and setters must have one of the following signatures:
|
|
// void T::Setter(U value);
|
|
// void T::Setter(U* value);
|
|
// void T::Setter(const U& value);
|
|
// U Getter() const;
|
|
// U* Getter() const;
|
|
//
|
|
// In this example, the variable Foo::bar is private and so it is accessed
|
|
// through getter and setter functions. If Foo::bar were public, it could be
|
|
// accessed directly, like so:
|
|
//
|
|
// static luaL_reg Foo_metatable[] =
|
|
// {
|
|
// { "GetBar", luaU_get<Foo, bool, &Widget::bar> },
|
|
// { "SetBar", luaU_set<Foo, bool, &Widget::bar> },
|
|
// { "Bar", luaU_getset<Foo, bool, &Widget::bar> },
|
|
// }
|
|
//
|
|
// In a Lua script, you can now use foo:GetBar(), foo:SetBar() and foo:Bar()
|
|
//
|
|
|
|
template <typename T, typename U, U T::*Member>
|
|
int luaU_get(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
luaU_push<U>(L, obj->*Member);
|
|
return 1;
|
|
}
|
|
|
|
template <typename T, typename U, U* T::*Member>
|
|
int luaU_get(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
luaW_push<U>(L, obj->*Member);
|
|
return 1;
|
|
}
|
|
|
|
template <typename T, typename U, U (T::*Getter)() const>
|
|
int luaU_get(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
luaU_push<U>(L, (obj->*Getter)());
|
|
return 1;
|
|
}
|
|
|
|
template <typename T, typename U, const U& (T::*Getter)() const>
|
|
int luaU_get(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
luaU_push<U>(L, (obj->*Getter)());
|
|
return 1;
|
|
}
|
|
|
|
template <typename T, typename U, U* (T::*Getter)() const>
|
|
int luaU_get(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
luaW_push<U>(L, (obj->*Getter)());
|
|
return 1;
|
|
}
|
|
|
|
template <typename T, typename U, U T::*Member>
|
|
int luaU_set(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj)
|
|
obj->*Member = luaU_check<U>(L, 2);
|
|
return 0;
|
|
}
|
|
|
|
template <typename T, typename U, U* T::*Member>
|
|
int luaU_set(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj)
|
|
{
|
|
U* member = luaW_opt<U>(L, 2);
|
|
obj->*Member = member;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <typename T, typename U, const U* T::*Member>
|
|
int luaU_set(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj)
|
|
{
|
|
U* member = luaW_opt<U>(L, 2);
|
|
obj->*Member = member;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <typename T, typename U, const U* T::*Member>
|
|
int luaU_setandrelease(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj)
|
|
{
|
|
U* member = luaW_opt<U>(L, 2);
|
|
obj->*Member = member;
|
|
if (member)
|
|
luaW_release<U>(L, member);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <typename T, typename U, void (T::*Setter)(U)>
|
|
int luaU_set(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj)
|
|
(obj->*Setter)(luaU_check<U>(L, 2));
|
|
return 0;
|
|
}
|
|
|
|
template <typename T, typename U, void (T::*Setter)(const U&)>
|
|
int luaU_set(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj)
|
|
(obj->*Setter)(luaU_check<U>(L, 2));
|
|
return 0;
|
|
}
|
|
|
|
template <typename T, typename U, void (T::*Setter)(U*)>
|
|
int luaU_set(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj)
|
|
{
|
|
U* member = luaW_opt<U>(L, 2);
|
|
(obj->*Setter)(member);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <typename T, typename U, void (T::*Setter)(U*)>
|
|
int luaU_setandrelease(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj)
|
|
{
|
|
U* member = luaW_opt<U>(L, 2);
|
|
(obj->*Setter)(member);
|
|
if (member)
|
|
luaW_release<U>(L, member);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <typename T, typename U, U T::*Member>
|
|
int luaU_getset(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj && lua_gettop(L) >= 2)
|
|
{
|
|
obj->*Member = luaU_check<U>(L, 2);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
luaU_push<U>(L, obj->*Member);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
template <typename T, typename U, U* T::*Member>
|
|
int luaU_getset(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj && lua_gettop(L) >= 2)
|
|
{
|
|
U* member = luaW_opt<U>(L, 2);
|
|
obj->*Member = member;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
luaW_push<U>(L, obj->*Member);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
template <typename T, typename U, U* T::*Member>
|
|
int luaU_getsetandrelease(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj && lua_gettop(L) >= 2)
|
|
{
|
|
U* member = luaW_opt<U>(L, 2);
|
|
obj->*Member = member;
|
|
if (member)
|
|
luaW_release<U>(L, member);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
luaW_push<U>(L, obj->*Member);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
template <typename T, typename U, U (T::*Getter)() const, void (T::*Setter)(U)>
|
|
int luaU_getset(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj && lua_gettop(L) >= 2)
|
|
{
|
|
(obj->*Setter)(luaU_check<U>(L, 2));
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
luaU_push<U>(L, (obj->*Getter)());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
template <typename T, typename U, U (T::*Getter)() const, void (T::*Setter)(const U&)>
|
|
int luaU_getset(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj && lua_gettop(L) >= 2)
|
|
{
|
|
(obj->*Setter)(luaU_check<U>(L, 2));
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
luaU_push<U>(L, (obj->*Getter)());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
template <typename T, typename U, const U& (T::*Getter)() const, void (T::*Setter)(const U&)>
|
|
int luaU_getset(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj && lua_gettop(L) >= 2)
|
|
{
|
|
(obj->*Setter)(luaU_check<U>(L, 2));
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
luaU_push<U>(L, (obj->*Getter)());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
template <typename T, typename U, U* (T::*Getter)() const, void (T::*Setter)(U*)>
|
|
int luaU_getset(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj && lua_gettop(L) >= 2)
|
|
{
|
|
U* member = luaW_opt<U>(L, 2);
|
|
(obj->*Setter)(member);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
luaW_push<U>(L, (obj->*Getter)());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
template <typename T, typename U, U* (T::*Getter)() const, void (T::*Setter)(U*)>
|
|
int luaU_getsetandrelease(lua_State* L)
|
|
{
|
|
T* obj = luaW_check<T>(L, 1);
|
|
if (obj && lua_gettop(L) >= 2)
|
|
{
|
|
U* member = luaW_opt<U>(L, 2);
|
|
(obj->*Setter)(member);
|
|
if (member)
|
|
luaW_release<U>(L, member);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
luaW_push<U>(L, (obj->*Getter)());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
#if !defined(_WIN32) && !defined(LUAW_NO_CXX11)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// luaU_func is a special macro that expands into a simple function wrapper.
|
|
// Unlike the getter setters above, you merely need to name the function you
|
|
// would like to wrap.
|
|
//
|
|
// For example,
|
|
//
|
|
// struct Foo
|
|
// {
|
|
// int DoSomething(int, const char*);
|
|
// };
|
|
//
|
|
// static luaL_reg Foo_metatable[] =
|
|
// {
|
|
// { "DoSomething", luaU_func(&Foo::DoSomething) },
|
|
// { NULL, NULL }
|
|
// }
|
|
//
|
|
// This macro will expand based on the function signature of Foo::DoSomething
|
|
// In this example, it would expand into the following wrapper:
|
|
//
|
|
// luaU_push(luaW_check<T>(L, 1)->DoSomething(luaU_check<int>(L, 2), luaU_check<const char*>(L, 3)));
|
|
// return 1;
|
|
//
|
|
// In this example there is only one member function called DoSomething. In some
|
|
// cases there may be multiple overrides for a function. For those cases, an
|
|
// additional macro has been provided, luaU_funcsig, which takes the entire
|
|
// function signature. The arguments to the macro reflect the order they would
|
|
// appear in the function signature: return type, type name, function name, and
|
|
// finally a list of all the argument types. For example:
|
|
//
|
|
// struct Foo
|
|
// {
|
|
// int DoSomething (const char*);
|
|
// int DoSomething (const char*, int);
|
|
// };
|
|
//
|
|
// const struct luaL_Reg Foo_metatable[] =
|
|
// {
|
|
// {"DoSomething1", luaU_funcsig(int, Foo, DoSomething, const char*)) },
|
|
// {"DoSomething1", luaU_funcsig(int, Foo, DoSomething, const char*, int)) },
|
|
// { NULL, NULL }
|
|
// };
|
|
//
|
|
// These macros and it's underlying templates are somewhat experimental and some
|
|
// refinements are probably needed. There are cases where it does not
|
|
// currently work and I expect some changes can be made to refine its behavior.
|
|
//
|
|
|
|
#define luaU_func(memberfunc) &luaU_FuncWrapper<decltype(memberfunc),memberfunc>::call
|
|
#define luaU_funcsig(returntype, type, funcname, ...) luaU_func(static_cast<returntype (type::*)(__VA_ARGS__)>(&type::funcname))
|
|
|
|
template<int... ints> struct luaU_IntPack { };
|
|
template<int start, int count, int... tail> struct luaU_MakeIntRangeType { typedef typename luaU_MakeIntRangeType<start, count-1, start+count-1, tail...>::type type; };
|
|
template<int start, int... tail> struct luaU_MakeIntRangeType<start, 0, tail...> { typedef luaU_IntPack<tail...> type; };
|
|
template<int start, int count> inline typename luaU_MakeIntRangeType<start, count>::type luaU_makeIntRange() { return typename luaU_MakeIntRangeType<start, count>::type(); }
|
|
template<class MemFunPtrType, MemFunPtrType MemberFunc> struct luaU_FuncWrapper;
|
|
|
|
template<class T, class ReturnType, class... Args, ReturnType(T::*MemberFunc)(Args...)>
|
|
struct luaU_FuncWrapper<ReturnType (T::*)(Args...), MemberFunc>
|
|
{
|
|
public:
|
|
static int call(lua_State* L)
|
|
{
|
|
return callImpl(L, luaU_makeIntRange<2,sizeof...(Args)>());
|
|
}
|
|
|
|
private:
|
|
template<int... indices>
|
|
static int callImpl(lua_State* L, luaU_IntPack<indices...>)
|
|
{
|
|
luaU_push<ReturnType>(L, (luaW_check<T>(L, 1)->*MemberFunc)(luaU_check<Args>(L, indices)...));
|
|
return 1;
|
|
}
|
|
};
|
|
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Calls the copy constructor for an object of type T.
|
|
// Arguments may be passed in, in case they're needed for the postconstructor
|
|
//
|
|
// e.g.
|
|
//
|
|
// C++:
|
|
// luaL_reg Foo_Metatable[] =
|
|
// {
|
|
// { "clone", luaU_clone<Foo> },
|
|
// { NULL, NULL }
|
|
// };
|
|
//
|
|
// Lua:
|
|
// foo = Foo.new()
|
|
// foo2 = foo:clone()
|
|
//
|
|
template <typename T>
|
|
int luaU_clone(lua_State* L)
|
|
{
|
|
// obj ...
|
|
T* obj = new T(*luaW_check<T>(L, 1));
|
|
lua_remove(L, 1); // ...
|
|
int numargs = lua_gettop(L);
|
|
luaW_push<T>(L, obj); // ... clone
|
|
luaW_hold<T>(L, obj);
|
|
luaW_postconstructor<T>(L, numargs);
|
|
return 1;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// luaU_build is intended to be used to initialize many values by passing in a
|
|
// table. They keys of the table are used as function names, and values are
|
|
// used as arguments to the function. This is intended to be used on functions
|
|
// that are simple setters.
|
|
//
|
|
// For example, if luaU_build is set as the post constructor, you can
|
|
// initialize an object as so:
|
|
//
|
|
// f = Foo.new
|
|
// {
|
|
// X = 10;
|
|
// Y = 20;
|
|
// }
|
|
//
|
|
// After the object is constructed, luaU_build will do the equivalent of
|
|
// calling f:X(10) and f:Y(20).
|
|
//
|
|
template <typename T>
|
|
int luaU_build(lua_State* L)
|
|
{
|
|
// obj {}
|
|
lua_insert(L, -2); // {} obj
|
|
if (lua_type(L, 1) == LUA_TTABLE)
|
|
{
|
|
for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1))
|
|
{
|
|
// {} obj k v
|
|
lua_pushvalue(L, -2); // {} obj k v k
|
|
lua_gettable(L, -4); // {} obj k v ud[k]
|
|
lua_pushvalue(L, -4); // {} obj k v ud[k] ud
|
|
lua_pushvalue(L, -3); // {} obj k v ud[k] ud v
|
|
lua_call(L, 2, 0); // {} obj k v
|
|
}
|
|
// {} ud
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Takes the object of type T at the top of the stack and stores it in on a
|
|
// table with the name storagetable, on the table at the specified index.
|
|
//
|
|
// You may manually call luaW_hold and luaW_release to handle pointer
|
|
// ownership, but it is often easier to simply store a Lua userdata on a table
|
|
// that is owned by its parent. This ensures that your object will not be
|
|
// prematurely freed, and that it can only be destoryed after its parent.
|
|
//
|
|
// e.g.
|
|
//
|
|
// Foo* parent = luaW_check<Foo>(L, 1);
|
|
// Bar* child = luaW_check<Bar>(L, 2);
|
|
// if (parent && child)
|
|
// {
|
|
// luaU_store<Bar>(L, 1, "Children");
|
|
// parent->AddChild(child);
|
|
// }
|
|
//
|
|
template <typename T>
|
|
void luaU_store(lua_State* L, int index, const char* storagetable, const char* key = NULL)
|
|
{
|
|
// ... store ... obj
|
|
lua_getfield(L, index, storagetable); // ... store ... obj store.storagetable
|
|
if (key)
|
|
lua_pushstring(L, key); // ... store ... obj store.storagetable key
|
|
else
|
|
LuaWrapper<T>::identifier(L, luaW_to<T>(L, -2)); // ... store ... obj store.storagetable key
|
|
lua_pushvalue(L, -3); // ... store ... obj store.storagetable key obj
|
|
lua_settable(L, -3); // ... store ... obj store.storagetable
|
|
lua_pop(L, 1); // ... store ... obj
|
|
}
|
|
|
|
/*
|
|
* Copyright (c) 2010-2011 Alexander Ames
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
* IN THE SOFTWARE.
|
|
*/
|
|
|
|
#endif // LUAWRAPPERUTILS_HPP_
|