/* * 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 #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 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 U luaU_check(lua_State* L, int index) { return luaU_Impl::luaU_check(L, index); } template U luaU_to (lua_State* L, int index) { return luaU_Impl::luaU_to (L, index); } template void luaU_push (lua_State* L, const U& value) { luaU_Impl::luaU_push (L, value); } template void luaU_push (lua_State* L, U& value) { luaU_Impl::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 U luaU_opt(lua_State* L, int index, const U& fallback = U()) { if (lua_isnil(L, index)) return fallback; else return luaU_Impl::luaU_check(L, index); } template<> struct luaU_Impl { 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 { 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 { static unsigned int luaU_check(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } static unsigned int luaU_to (lua_State* L, int index) { return static_cast(lua_tointeger (L, index)); } static void luaU_push (lua_State* L, const unsigned int& value) { lua_pushinteger (L, value); } }; template<> struct luaU_Impl { static int luaU_check(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } static int luaU_to (lua_State* L, int index) { return static_cast(lua_tointeger (L, index)); } static void luaU_push (lua_State* L, const int& value) { lua_pushinteger (L, value); } }; template<> struct luaU_Impl { static unsigned char luaU_check(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } static unsigned char luaU_to (lua_State* L, int index) { return static_cast(lua_tointeger (L, index)); } static void luaU_push (lua_State* L, const unsigned char& value) { lua_pushinteger (L, value); } }; template<> struct luaU_Impl { static char luaU_check(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } static char luaU_to (lua_State* L, int index) { return static_cast(lua_tointeger (L, index)); } static void luaU_push (lua_State* L, const char& value) { lua_pushinteger (L, value); } }; template<> struct luaU_Impl { static float luaU_check(lua_State* L, int index) { return static_cast(luaL_checknumber(L, index)); } static float luaU_to (lua_State* L, int index) { return static_cast(lua_tonumber (L, index)); } static void luaU_push (lua_State* L, const float& value) { lua_pushnumber (L, value); } }; template<> struct luaU_Impl { static double luaU_check(lua_State* L, int index) { return static_cast(luaL_checknumber(L, index)); } static double luaU_to (lua_State* L, int index) { return static_cast(lua_tonumber (L, index)); } static void luaU_push (lua_State* L, const double& value) { lua_pushnumber (L, value); } }; #ifndef LUAW_NO_CXX11 template struct luaU_Impl::value>::type> { static T luaU_check(lua_State* L, int index) { return static_cast(luaL_checkinteger (L, index)); } static T luaU_to (lua_State* L, int index) { return static_cast(lua_tointeger (L, index)); } static void luaU_push (lua_State* L, const T& value) { lua_pushnumber(L, static_cast(value )); } }; template struct luaU_Impl::value>::type> { static T* luaU_check( lua_State* L, int index) { return luaW_check(L, index); } static T* luaU_to ( lua_State* L, int index) { return luaW_to (L, index); } static void luaU_push ( lua_State* L, T*& value) { luaW_push (L, value); } static void luaU_push ( lua_State* L, T* value) { luaW_push (L, value); } }; #endif /////////////////////////////////////////////////////////////////////////////// // // These are just some functions I've always felt should exist // template inline U luaU_getfield(lua_State* L, int index, const char* field) { #ifndef LUAW_NO_CXX11 static_assert(!std::is_same::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(L, -1); lua_pop(L, 1); return val; } template inline U luaU_checkfield(lua_State* L, int index, const char* field) { #ifndef LUAW_NO_CXX11 static_assert(!std::is_same::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(L, -1); lua_pop(L, 1); return val; } template inline void luaU_setfield(lua_State* L, int index, const char* field, U val) { luaU_push(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 }, // { "SetBar", luaU_set }, // { "Bar", luaU_getset }, // { 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 }, // { "SetBar", luaU_set }, // { "Bar", luaU_getset }, // } // // In a Lua script, you can now use foo:GetBar(), foo:SetBar() and foo:Bar() // template int luaU_get(lua_State* L) { T* obj = luaW_check(L, 1); luaU_push(L, obj->*Member); return 1; } template int luaU_get(lua_State* L) { T* obj = luaW_check(L, 1); luaW_push(L, obj->*Member); return 1; } template int luaU_get(lua_State* L) { T* obj = luaW_check(L, 1); luaU_push(L, (obj->*Getter)()); return 1; } template int luaU_get(lua_State* L) { T* obj = luaW_check(L, 1); luaU_push(L, (obj->*Getter)()); return 1; } template int luaU_get(lua_State* L) { T* obj = luaW_check(L, 1); luaW_push(L, (obj->*Getter)()); return 1; } template int luaU_set(lua_State* L) { T* obj = luaW_check(L, 1); if (obj) obj->*Member = luaU_check(L, 2); return 0; } template int luaU_set(lua_State* L) { T* obj = luaW_check(L, 1); if (obj) { U* member = luaW_opt(L, 2); obj->*Member = member; } return 0; } template int luaU_set(lua_State* L) { T* obj = luaW_check(L, 1); if (obj) { U* member = luaW_opt(L, 2); obj->*Member = member; } return 0; } template int luaU_setandrelease(lua_State* L) { T* obj = luaW_check(L, 1); if (obj) { U* member = luaW_opt(L, 2); obj->*Member = member; if (member) luaW_release(L, member); } return 0; } template int luaU_set(lua_State* L) { T* obj = luaW_check(L, 1); if (obj) (obj->*Setter)(luaU_check(L, 2)); return 0; } template int luaU_set(lua_State* L) { T* obj = luaW_check(L, 1); if (obj) (obj->*Setter)(luaU_check(L, 2)); return 0; } template int luaU_set(lua_State* L) { T* obj = luaW_check(L, 1); if (obj) { U* member = luaW_opt(L, 2); (obj->*Setter)(member); } return 0; } template int luaU_setandrelease(lua_State* L) { T* obj = luaW_check(L, 1); if (obj) { U* member = luaW_opt(L, 2); (obj->*Setter)(member); if (member) luaW_release(L, member); } return 0; } template int luaU_getset(lua_State* L) { T* obj = luaW_check(L, 1); if (obj && lua_gettop(L) >= 2) { obj->*Member = luaU_check(L, 2); return 0; } else { luaU_push(L, obj->*Member); return 1; } } template int luaU_getset(lua_State* L) { T* obj = luaW_check(L, 1); if (obj && lua_gettop(L) >= 2) { U* member = luaW_opt(L, 2); obj->*Member = member; return 0; } else { luaW_push(L, obj->*Member); return 1; } } template int luaU_getsetandrelease(lua_State* L) { T* obj = luaW_check(L, 1); if (obj && lua_gettop(L) >= 2) { U* member = luaW_opt(L, 2); obj->*Member = member; if (member) luaW_release(L, member); return 0; } else { luaW_push(L, obj->*Member); return 1; } } template int luaU_getset(lua_State* L) { T* obj = luaW_check(L, 1); if (obj && lua_gettop(L) >= 2) { (obj->*Setter)(luaU_check(L, 2)); return 0; } else { luaU_push(L, (obj->*Getter)()); return 1; } } template int luaU_getset(lua_State* L) { T* obj = luaW_check(L, 1); if (obj && lua_gettop(L) >= 2) { (obj->*Setter)(luaU_check(L, 2)); return 0; } else { luaU_push(L, (obj->*Getter)()); return 1; } } template int luaU_getset(lua_State* L) { T* obj = luaW_check(L, 1); if (obj && lua_gettop(L) >= 2) { (obj->*Setter)(luaU_check(L, 2)); return 0; } else { luaU_push(L, (obj->*Getter)()); return 1; } } template int luaU_getset(lua_State* L) { T* obj = luaW_check(L, 1); if (obj && lua_gettop(L) >= 2) { U* member = luaW_opt(L, 2); (obj->*Setter)(member); return 0; } else { luaW_push(L, (obj->*Getter)()); return 1; } } template int luaU_getsetandrelease(lua_State* L) { T* obj = luaW_check(L, 1); if (obj && lua_gettop(L) >= 2) { U* member = luaW_opt(L, 2); (obj->*Setter)(member); if (member) luaW_release(L, member); return 0; } else { luaW_push(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(L, 1)->DoSomething(luaU_check(L, 2), luaU_check(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::call #define luaU_funcsig(returntype, type, funcname, ...) luaU_func(static_cast(&type::funcname)) template struct luaU_IntPack { }; template struct luaU_MakeIntRangeType { typedef typename luaU_MakeIntRangeType::type type; }; template struct luaU_MakeIntRangeType { typedef luaU_IntPack type; }; template inline typename luaU_MakeIntRangeType::type luaU_makeIntRange() { return typename luaU_MakeIntRangeType::type(); } template struct luaU_FuncWrapper; template struct luaU_FuncWrapper { public: static int call(lua_State* L) { return callImpl(L, luaU_makeIntRange<2,sizeof...(Args)>()); } private: template static int callImpl(lua_State* L, luaU_IntPack) { luaU_push(L, (luaW_check(L, 1)->*MemberFunc)(luaU_check(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 }, // { NULL, NULL } // }; // // Lua: // foo = Foo.new() // foo2 = foo:clone() // template int luaU_clone(lua_State* L) { // obj ... T* obj = new T(*luaW_check(L, 1)); lua_remove(L, 1); // ... int numargs = lua_gettop(L); luaW_push(L, obj); // ... clone luaW_hold(L, obj); luaW_postconstructor(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 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(L, 1); // Bar* child = luaW_check(L, 2); // if (parent && child) // { // luaU_store(L, 1, "Children"); // parent->AddChild(child); // } // template 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::identifier(L, luaW_to(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_