From 12a58015a3810ed9df4661cee88be2563ea3db4e Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sun, 21 Feb 2016 19:25:42 +0100 Subject: customize LuaBridge * introduce boost::shared_ptr support * support enum & const * allow to add non-class member functions * STL iterators (vector, list, set, bitset & map) * support reference arguments (framecnt_t&) * add support for arrays of basic types (e.g. float*, int*) * fix compiler warnings --- libs/lua/LuaBridge/LuaBridge.h | 16 +- libs/lua/LuaBridge/detail/CFunctions.h | 569 ++++++++++++++++++++++++++++++++- libs/lua/LuaBridge/detail/LuaRef.h | 1 + libs/lua/LuaBridge/detail/Namespace.h | 440 +++++++++++++++++++++++++ libs/lua/LuaBridge/detail/Stack.h | 65 ++++ libs/lua/LuaBridge/detail/TypeTraits.h | 10 + libs/lua/LuaBridge/detail/Userdata.h | 55 ++-- libs/lua/LuaBridge/detail/dump.h | 4 +- 8 files changed, 1137 insertions(+), 23 deletions(-) diff --git a/libs/lua/LuaBridge/LuaBridge.h b/libs/lua/LuaBridge/LuaBridge.h index 1928e9a1f0..fb61340bcc 100644 --- a/libs/lua/LuaBridge/LuaBridge.h +++ b/libs/lua/LuaBridge/LuaBridge.h @@ -1,7 +1,8 @@ //------------------------------------------------------------------------------ /* https://github.com/vinniefalco/LuaBridge - + + Copyright 2016, Robin Gareus Copyright 2012, Vinnie Falco Copyright 2007, Nathan Reed @@ -39,6 +40,17 @@ #include #include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + #define LUABRIDGE_MAJOR_VERSION 2 #define LUABRIDGE_MINOR_VERSION 0 #define LUABRIDGE_VERSION 200 @@ -137,6 +149,6 @@ inline void setHideMetatables (bool shouldHide) Security::setHideMetatables (shouldHide); } -} +} // end Namespace #endif diff --git a/libs/lua/LuaBridge/detail/CFunctions.h b/libs/lua/LuaBridge/detail/CFunctions.h index ebf962ed15..1c0caa84ac 100644 --- a/libs/lua/LuaBridge/detail/CFunctions.h +++ b/libs/lua/LuaBridge/detail/CFunctions.h @@ -1,7 +1,8 @@ //------------------------------------------------------------------------------ /* https://github.com/vinniefalco/LuaBridge - + + Copyright 2016, Robin Gareus Copyright 2012, Vinnie Falco License: The MIT License (http://www.opensource.org/licenses/mit-license.php) @@ -290,6 +291,95 @@ struct CFunc } }; + template ::ReturnType> + struct CallMemberPtr + { + typedef typename FuncTraits ::Params Params; + + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + boost::shared_ptr* const t = Userdata::get > (L, 1, false); + T* const tt = t->get(); + if (!tt) { + return luaL_error (L, "shared_ptr is nil"); + } + MemFnPtr const& fnptr = *static_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + ArgList args (L); + Stack ::push (L, FuncTraits ::call (tt, fnptr, args)); + return 1; + } + }; + + template + struct CastMemberPtr + { + static int f (lua_State* L) + { + boost::shared_ptr t = luabridge::Stack >::get (L, 1); + Stack >::push (L, boost::dynamic_pointer_cast (t)); + return 1; + } + }; + + template + struct PtrNullCheck + { + static int f (lua_State* L) + { + boost::shared_ptr t = luabridge::Stack >::get (L, 1); + Stack ::push (L, t == 0); + return 1; + } + }; + + template + struct WPtrNullCheck + { + static int f (lua_State* L) + { + bool rv = true; + boost::weak_ptr tw = luabridge::Stack >::get (L, 1); + boost::shared_ptr const t = tw.lock(); + if (t) { + T* const tt = t.get(); + rv = (tt == 0); + } + Stack ::push (L, rv); + return 1; + } + }; + + template ::ReturnType> + struct CallMemberWPtr + { + typedef typename FuncTraits ::Params Params; + + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + boost::weak_ptr* const tw = Userdata::get > (L, 1, false); + boost::shared_ptr const t = tw->lock(); + if (!t) { + return luaL_error (L, "cannot lock weak_ptr"); + } + T* const tt = t.get(); + if (!tt) { + return luaL_error (L, "weak_ptr is nil"); + } + MemFnPtr const& fnptr = *static_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + ArgList args (L); + Stack ::push (L, FuncTraits ::call (tt, fnptr, args)); + return 1; + } + }; + + + //---------------------------------------------------------------------------- /** lua_CFunction to call a class member function with no return value. @@ -333,6 +423,51 @@ struct CFunc } }; + template + struct CallMemberPtr + { + typedef typename FuncTraits ::Params Params; + + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + boost::shared_ptr* const t = Userdata::get > (L, 1, false); + T* const tt = t->get(); + MemFnPtr const& fnptr = *static_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + ArgList args (L); + FuncTraits ::call (tt, fnptr, args); + return 0; + } + }; + + template + struct CallMemberWPtr + { + typedef typename FuncTraits ::Params Params; + + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + boost::weak_ptr* const tw = Userdata::get > (L, 1, false); + boost::shared_ptr const t = tw->lock(); + if (!t) { + return luaL_error (L, "cannot lock weak_ptr"); + } + T* const tt = t.get(); + if (!tt) { + return luaL_error (L, "weak_ptr is nil"); + } + MemFnPtr const& fnptr = *static_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + ArgList args (L); + FuncTraits ::call (tt, fnptr, args); + return 0; + } + }; + + + //-------------------------------------------------------------------------- /** lua_CFunction to call a class member lua_CFunction. @@ -396,6 +531,30 @@ struct CFunc } }; + template + struct CallMemberPtrFunctionHelper + { + typedef typename FuncTraits ::ClassType T; + static void add (lua_State* L, char const* name, MemFnPtr mf) + { + new (lua_newuserdata (L, sizeof (MemFnPtr))) MemFnPtr (mf); + lua_pushcclosure (L, &CallMemberPtr ::f, 1); + rawsetfield (L, -3, name); // class table + } + }; + + template + struct CallMemberWPtrFunctionHelper + { + typedef typename FuncTraits ::ClassType T; + static void add (lua_State* L, char const* name, MemFnPtr mf) + { + new (lua_newuserdata (L, sizeof (MemFnPtr))) MemFnPtr (mf); + lua_pushcclosure (L, &CallMemberWPtr ::f, 1); + rawsetfield (L, -3, name); // class table + } + }; + //-------------------------------------------------------------------------- /** __gc metamethod for a class. @@ -408,6 +567,11 @@ struct CFunc return 0; } + static int gcNOOPMethod (lua_State* L) + { + return 0; + } + //-------------------------------------------------------------------------- /** lua_CFunction to get a class data member. @@ -424,6 +588,20 @@ struct CFunc return 1; } + //-------------------------------------------------------------------------- + + /** + lua_CFunction to get a constant (enum) + */ + template + static int getConst (lua_State* L) + { + U *v = static_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (v); + Stack ::push (L, *v); + return 1; + } + //-------------------------------------------------------------------------- /** lua_CFunction to set a class data member. @@ -439,4 +617,393 @@ struct CFunc c->**mp = Stack ::get (L, 2); return 0; } + + //-------------------------------------------------------------------------- + + // metatable callback for "array[index]" + template + static int array_index (lua_State* L) { + T** parray = (T**) luaL_checkudata (L, 1, typeid(T).name()); + int const index = luabridge::Stack::get (L, 2); + luabridge::Stack::push (L, (*parray)[index-1]); + return 1; + } + + // metatable callback for "array[index] = value" + template + static int array_newindex (lua_State* L) { + T** parray = (T**) luaL_checkudata (L, 1, typeid(T).name()); + int const index = luabridge::Stack::get (L, 2); + T const value = luabridge::Stack::get (L, 3); + (*parray)[index-1] = value; + return 0; + } + + template + static int getArray (lua_State* L) { + T *v = luabridge::Stack::get (L, 1); + T** parray = (T**) lua_newuserdata(L, sizeof(T**)); + *parray = v; + luaL_getmetatable(L, typeid(T).name()); + lua_setmetatable(L, -2); + return 1; + } + + // copy complete c array to lua table + template + static int getTable (lua_State* L) { + T *v = luabridge::Stack::get (L, 1); + const int cnt = luabridge::Stack::get (L, 2); + LuaRef t (L); + t = newTable (L); + for (int i = 0; i < cnt; ++i) { + t[i + 1] = v[i]; + } + t.push(L); + return 1; + } + + // copy lua table to c array + template + static int setTable (lua_State* L) { + T *v = luabridge::Stack::get (L, 1); + LuaRef t (LuaRef::fromStack(L, 2)); + const int cnt = luabridge::Stack::get (L, 3); + for (int i = 0; i < cnt; ++i) { + v[i] = t[i + 1]; + } + return 0; + } + + + //-------------------------------------------------------------------------- + /** + C++ STL iterators + */ + + // read lua table into C++ std::list + template + static int tableToListHelper (lua_State *L, C * const t) + { + if (!t) { return luaL_error (L, "invalid pointer to std::list<>/std::vector"); } + if (!lua_istable (L, -1)) { return luaL_error (L, "argument is not a table"); } + lua_pushvalue (L, -1); + lua_pushnil (L); + while (lua_next (L, -2)) { + lua_pushvalue (L, -2); + T const value = Stack::get (L, -2); + t->push_back (value); + lua_pop (L, 2); + } + lua_pop (L, 1); + lua_pop (L, 2); + Stack::push (L, *t); + return 1; + } + + template + static int tableToList (lua_State *L) + { + C * const t = Userdata::get (L, 1, false); + return tableToListHelper (L, t); + } + + template + static int ptrTableToList (lua_State *L) + { + boost::shared_ptr const* const t = Userdata::get > (L, 1, true); + if (!t) { return luaL_error (L, "cannot derefencee shared_ptr"); } + return tableToListHelper (L, t->get()); + } + + //-------------------------------------------------------------------------- + template + static int listIterIter (lua_State *L) { + typedef typename C::const_iterator IterType; + IterType * const end = static_cast (lua_touserdata (L, lua_upvalueindex (2))); + IterType * const iter = static_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (end); + assert (iter); + if ((*iter) == (*end)) { + return 0; + } + Stack ::push (L, **iter); + ++(*iter); + return 1; + } + + // generate an iterator + template + static int listIterHelper (lua_State *L, C * const t) + { + if (!t) { return luaL_error (L, "invalid pointer to std::list<>/std::vector"); } + typedef typename C::const_iterator IterType; + new (lua_newuserdata (L, sizeof (IterType*))) IterType (t->begin()); + new (lua_newuserdata (L, sizeof (IterType*))) IterType (t->end()); + lua_pushcclosure (L, listIterIter, 2); + return 1; + } + + template + static int listIter (lua_State *L) + { + C * const t = Userdata::get (L, 1, false); + return listIterHelper (L, t); + } + + template + static int ptrListIter (lua_State *L) + { + boost::shared_ptr const* const t = Userdata::get >(L, 1, true); + if (!t) { return luaL_error (L, "cannot derefencee shared_ptr"); } + return listIterHelper (L, t->get()); + } + + //-------------------------------------------------------------------------- + // generate table from std::list + template + static int listToTableHelper (lua_State *L, C const* const t) + { + if (!t) { return luaL_error (L, "invalid pointer to std::list<>/std::vector"); } +#if 0 // direct lua api + lua_createtable(L, t->size(), 0); + int newTable = lua_gettop(L); + int index = 1; + for (typename C::const_iterator iter = t->begin(); iter != t->end(); ++iter, ++index) { + Stack::push(L, (*iter)); + lua_rawseti (L, newTable, index); + } +#else // luabridge way + LuaRef v (L); + v = newTable (L); + int index = 1; + for (typename C::const_iterator iter = t->begin(); iter != t->end(); ++iter, ++index) { + v[index] = (*iter); + } + v.push(L); +#endif + return 1; + } + + template + static int listToTable (lua_State *L) + { + C const* const t = Userdata::get (L, 1, true); + return listToTableHelper (L, t); + } + + template + static int ptrListToTable (lua_State *L) + { + boost::shared_ptr const* const t = Userdata::get > (L, 1, true); + if (!t) { return luaL_error (L, "cannot derefencee shared_ptr"); } + return listToTableHelper (L, t->get()); + } + + //-------------------------------------------------------------------------- + // generate std::map from table + + template + static int tableToMap (lua_State *L) + { + typedef std::map C; + C * const t = Userdata::get (L, 1, true); + if (!t) { return luaL_error (L, "invalid pointer to std::map"); } + if (!lua_istable (L, -1)) { return luaL_error (L, "argument is not a table"); } + + lua_pushvalue (L, -1); + lua_pushnil (L); + while (lua_next (L, -2)) { + lua_pushvalue (L, -2); + K const key = Stack::get (L, -1); + V const value = Stack::get (L, -2); + t->insert (std::pair (key, value)); + //(*t)[key] = value; + lua_pop (L, 2); + } + lua_pop (L, 1); + lua_pop (L, 2); + Stack::push (L, *t); + return 1; + } + + // iterate over a std::map + template + static int mapIterIter (lua_State *L) + { + typedef std::map C; + typedef typename C::const_iterator IterType; + IterType * const end = static_cast (lua_touserdata (L, lua_upvalueindex (2))); + IterType * const iter = static_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (end); + assert (iter); + if ((*iter) == (*end)) { + return 0; + } + Stack ::push (L, (*iter)->first); + Stack ::push (L, (*iter)->second); + ++(*iter); + return 2; + } + + // generate iterator + template + static int mapIter (lua_State *L) + { + typedef std::map C; + C * const t = Userdata::get (L, 1, false); + if (!t) { return luaL_error (L, "invalid pointer to std::map"); } + typedef typename C::const_iterator IterType; + new (lua_newuserdata (L, sizeof (IterType*))) IterType (t->begin()); + new (lua_newuserdata (L, sizeof (IterType*))) IterType (t->end()); + lua_pushcclosure (L, mapIterIter, 2); + return 1; + } + + // generate table from std::map + template + static int mapToTable (lua_State *L) + { + typedef std::map C; + C const* const t = Userdata::get (L, 1, true); + if (!t) { return luaL_error (L, "invalid pointer to std::map"); } + + LuaRef v (L); + v = newTable (L); + for (typename C::const_iterator iter = t->begin(); iter != t->end(); ++iter) { + v[(*iter).first] = (*iter).second; + } + v.push(L); + return 1; + } + + //-------------------------------------------------------------------------- + // generate std::set from table keys ( table[member] = true ) + // http://www.lua.org/pil/11.5.html + + template + static int tableToSet (lua_State *L) + { + typedef std::set C; + C * const t = Userdata::get (L, 1, true); + if (!t) { return luaL_error (L, "invalid pointer to std::set"); } + if (!lua_istable (L, -1)) { return luaL_error (L, "argument is not a table"); } + + lua_pushvalue (L, -1); + lua_pushnil (L); + while (lua_next (L, -2)) { + lua_pushvalue (L, -2); + T const member = Stack::get (L, -1); + bool const v = Stack::get (L, -2); + if (v) { + t->insert (member); + } + lua_pop (L, 2); + } + lua_pop (L, 1); + lua_pop (L, 2); + Stack::push (L, *t); + return 1; + } + + // iterate over a std::set, explicit "true" value. + // compare to http://www.lua.org/pil/11.5.html + template + static int setIterIter (lua_State *L) + { + typedef std::set C; + typedef typename C::const_iterator IterType; + IterType * const end = static_cast (lua_touserdata (L, lua_upvalueindex (2))); + IterType * const iter = static_cast (lua_touserdata (L, lua_upvalueindex (1))); + assert (end); + assert (iter); + if ((*iter) == (*end)) { + return 0; + } + Stack ::push (L, **iter); + Stack ::push (L, true); + ++(*iter); + return 2; + } + + // generate iterator + template + static int setIter (lua_State *L) + { + typedef std::set C; + C * const t = Userdata::get (L, 1, false); + if (!t) { return luaL_error (L, "invalid pointer to std::set"); } + typedef typename C::const_iterator IterType; + new (lua_newuserdata (L, sizeof (IterType*))) IterType (t->begin()); + new (lua_newuserdata (L, sizeof (IterType*))) IterType (t->end()); + lua_pushcclosure (L, setIterIter, 2); + return 1; + } + + // generate table from std::set + template + static int setToTable (lua_State *L) + { + typedef std::set C; + C const* const t = Userdata::get (L, 1, true); + if (!t) { return luaL_error (L, "invalid pointer to std::set"); } + + LuaRef v (L); + v = newTable (L); + for (typename C::const_iterator iter = t->begin(); iter != t->end(); ++iter) { + v[(*iter)] = true; + } + v.push(L); + return 1; + } + + //-------------------------------------------------------------------------- + // bitset { num = true } + // compare to http://www.lua.org/pil/11.5.html + template + static int tableToBitSet (lua_State *L) + { + typedef std::bitset C; + C * const t = Userdata::get (L, 1, true); + if (!t) { return luaL_error (L, "invalid pointer to std::bitset"); } + if (!lua_istable (L, -1)) { return luaL_error (L, "argument is not a table"); } + + lua_pushvalue (L, -1); + lua_pushnil (L); + while (lua_next (L, -2)) { + lua_pushvalue (L, -2); + unsigned int const member = Stack::get (L, -1); + bool const v = Stack::get (L, -2); + if (member < T && v) { + t->set (member); + } + lua_pop (L, 2); + } + lua_pop (L, 1); + lua_pop (L, 2); + Stack::push (L, *t); + return 1; + } + + // generate table from std::bitset + template + static int bitSetToTable (lua_State *L) + { + typedef std::bitset C; + C const* const t = Userdata::get (L, 1, true); + if (!t) { return luaL_error (L, "invalid pointer to std::bitset"); } + + LuaRef v (L); + v = newTable (L); + for (unsigned int i = 0; i < T; ++i) { + if (t->test (i)) { + v[i] = true; + } + } + v.push(L); + return 1; + } + }; + +/* vim: set et sw=2: */ diff --git a/libs/lua/LuaBridge/detail/LuaRef.h b/libs/lua/LuaBridge/detail/LuaRef.h index d3e3fe6d68..8fae1c038a 100644 --- a/libs/lua/LuaBridge/detail/LuaRef.h +++ b/libs/lua/LuaBridge/detail/LuaRef.h @@ -237,6 +237,7 @@ private: } inline bool isNil () const { return type () == LUA_TNIL; } + inline bool isBoolean () const { return type () == LUA_TBOOLEAN; } inline bool isNumber () const { return type () == LUA_TNUMBER; } inline bool isString () const { return type () == LUA_TSTRING; } inline bool isTable () const { return type () == LUA_TTABLE; } diff --git a/libs/lua/LuaBridge/detail/Namespace.h b/libs/lua/LuaBridge/detail/Namespace.h index f7f484b118..464d9d08a0 100644 --- a/libs/lua/LuaBridge/detail/Namespace.h +++ b/libs/lua/LuaBridge/detail/Namespace.h @@ -2,6 +2,7 @@ /* https://github.com/vinniefalco/LuaBridge + Copyright 2016, Robin Gareus Copyright 2012, Vinnie Falco Copyright 2007, Nathan Reed @@ -482,6 +483,8 @@ private: } else { + lua_pop (L, 1); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::getStaticKey ()); rawgetfield (L, -1, "__class"); rawgetfield (L, -1, "__const"); @@ -674,6 +677,7 @@ private: return *this; } + //-------------------------------------------------------------------------- /** Add or replace a property member. @@ -797,6 +801,21 @@ private: return *this; } + template + Class & addPtrFunction (char const* name, MemFn mf) + { + CFunc::CallMemberPtrFunctionHelper ::add (L, name, mf); + return *this; + } + + template + Class & addWPtrFunction (char const* name, MemFn mf) + { + CFunc::CallMemberWPtrFunctionHelper ::add (L, name, mf); + return *this; + } + + //-------------------------------------------------------------------------- /** Add or replace a member lua_CFunction. @@ -812,6 +831,16 @@ private: return *this; } + // custom callback - extend existing classes + // with non-class member functions (e.g STL iterator) + Class & addExtCFunction (char const* name, int (*const fp)(lua_State*)) + { + assert (lua_istable (L, -1)); + lua_pushcclosure (L, fp, 0); + rawsetfield (L, -3, name); // class table + return *this; + } + //-------------------------------------------------------------------------- /** Add or replace a const member lua_CFunction. @@ -829,6 +858,28 @@ private: return *this; } + /** + Add or replace a static const data + */ + template + Class & addConst (char const* name, const U val) + { + assert (lua_istable (L, -1)); + + rawgetfield (L, -1, "__propget"); // static + new (lua_newuserdata (L, sizeof (val))) U (val); + lua_pushcclosure (L, &CFunc::getConst , 1); + rawsetfield (L, -2, name); + lua_pop (L, 1); + + rawgetfield (L, -1, "__propset"); // static + lua_pushstring (L, name); + lua_pushcclosure (L, &CFunc::readOnlyError, 1); + rawsetfield (L, -2, name); + lua_pop (L, 1); + return *this; + } + //-------------------------------------------------------------------------- /** Add or replace a primary Constructor. @@ -859,8 +910,216 @@ private: return *this; } + + Class & addVoidConstructor () + { + return addConstructor (); + } + + }; + + /** C Array to/from table */ + template + class Array : public ClassBase + { + public: + Array (char const* name, Namespace const* parent) : ClassBase (parent->L) + { + m_stackSize = parent->m_stackSize + 3; + parent->m_stackSize = 0; + +#if 0 // don't allow to duplicates handlers for same array-type + assert (lua_istable (L, -1)); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::getClassKey ()); + if (lua_istable (L, -1)) { + lua_pushnil (L); + lua_pushnil (L); + return; + } + lua_pop (L, 1); +#endif + + assert (lua_istable (L, -1)); + rawgetfield (L, -1, name); + + if (lua_isnil (L, -1)) + { + lua_pop (L, 1); + + // register array access in global namespace + luaL_newmetatable (L, typeid(T).name()); + lua_pushcclosure (L, CFunc::array_index, 0); + lua_setfield(L, -2, "__index"); + lua_pushcclosure (L, CFunc::array_newindex, 0); + lua_setfield(L, -2, "__newindex"); + lua_pop (L, 1); + + createConstTable (name); + lua_pushcfunction (L, &CFunc::gcMetaMethod ); + rawsetfield (L, -2, "__gc"); + + createClassTable (name); + lua_pushcfunction (L, &CFunc::gcMetaMethod ); + rawsetfield (L, -2, "__gc"); + + createStaticTable (name); + + // Map T back to its tables. + lua_pushvalue (L, -1); + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo ::getStaticKey ()); + lua_pushvalue (L, -2); + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo ::getClassKey ()); + lua_pushvalue (L, -3); + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo ::getConstKey ()); + + assert (lua_istable (L, -1)); + lua_pushcclosure (L, &CFunc::getArray , 0); + rawsetfield (L, -3, "array"); // class table + + lua_pushcclosure (L, &CFunc::getTable , 0); + rawsetfield (L, -3, "get_table"); // class table + + lua_pushcclosure (L, &CFunc::setTable , 0); + rawsetfield (L, -3, "set_table"); // class table + } + else + { + lua_pushnil (L); + lua_pushnil (L); + } + } + + Namespace endArray () + { + return Namespace (this); + } + }; + + /** Boost Weak & Shared Pointer Class Wrapper */ + template + class WSPtrClass : public ClassBase + { + public: + WSPtrClass (char const* name, Namespace const* parent) + : ClassBase (parent->L) + , weak (name, parent) + , shared (name, parent) + { + m_stackSize = weak.m_stackSize; + parent->m_stackSize = weak.m_stackSize = shared.m_stackSize = 0; + lua_pop (L, 3); + } + + WSPtrClass (char const* name, Namespace const* parent, void const* const sharedkey, void const* const weakkey) + : ClassBase (parent->L) + , weak (name, parent, weakkey) + , shared (name, parent, sharedkey) + { + m_stackSize = weak.m_stackSize; + parent->m_stackSize = weak.m_stackSize = shared.m_stackSize = 0; + lua_pop (L, 3); + } + + template + WSPtrClass & addFunction (char const* name, MemFn mf) + { + set_weak_class (); + CFunc::CallMemberWPtrFunctionHelper ::add (L, name, mf); + + set_shared_class (); + CFunc::CallMemberPtrFunctionHelper ::add (L, name, mf); + return *this; + } + + template + WSPtrClass & addConstructor () + { + set_weak_class (); + lua_pushcclosure (L, + &weak.ctorPlacementProxy ::Params, boost::weak_ptr >, 0); + rawsetfield(L, -2, "__call"); + + set_shared_class (); + lua_pushcclosure (L, + &shared.ctorPlacementProxy ::Params, boost::shared_ptr >, 0); + rawsetfield(L, -2, "__call"); + return *this; + } + + WSPtrClass & addVoidConstructor () + { + return addConstructor (); + } + + WSPtrClass & addExtCFunction (char const* name, int (*const fp)(lua_State*)) + { + set_weak_class (); + assert (lua_istable (L, -1)); + lua_pushcclosure (L, fp, 0); + rawsetfield (L, -3, name); // class table + + set_shared_class (); + assert (lua_istable (L, -1)); + lua_pushcclosure (L, fp, 0); + rawsetfield (L, -3, name); // class table + + return *this; + } + + template + WSPtrClass & addCast (char const* name) + { + // TODO weak ptr + set_shared_class (); + assert (lua_istable (L, -1)); + lua_pushcclosure (L, &CFunc::CastMemberPtr ::f, 0); + rawsetfield (L, -3, name); // class table + return *this; + } + + WSPtrClass & addNullCheck () + { + set_weak_class (); + assert (lua_istable (L, -1)); + lua_pushcclosure (L, &CFunc::WPtrNullCheck ::f, 0); + rawsetfield (L, -3, "isnil"); // class table + + set_shared_class (); + assert (lua_istable (L, -1)); + lua_pushcclosure (L, &CFunc::PtrNullCheck ::f, 0); + rawsetfield (L, -3, "isnil"); // class table + + return *this; + } + + + Namespace endClass () + { + return Namespace (this); + } + + private: + void set_weak_class () { + lua_pop (L, 3); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo >::getStaticKey ()); + rawgetfield (L, -1, "__class"); + rawgetfield (L, -1, "__const"); + lua_insert (L, -3); + lua_insert (L, -2); + } + void set_shared_class () { + lua_pop (L, 3); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo >::getStaticKey ()); + rawgetfield (L, -1, "__class"); + rawgetfield (L, -1, "__const"); + lua_insert (L, -3); + lua_insert (L, -2); + } + Class > weak; + Class > shared; }; + private: //---------------------------------------------------------------------------- /** @@ -1032,6 +1291,25 @@ public: return *this; } + template + Namespace& addConst (char const* name, const U val) + { + assert (lua_istable (L, -1)); + rawgetfield (L, -1, "__propget"); + new (lua_newuserdata (L, sizeof (val))) U (val); + lua_pushcclosure (L, &CFunc::getConst , 1); + rawsetfield (L, -2, name); + lua_pop (L, 1); + + rawgetfield (L, -1, "__propset"); + assert (lua_istable (L, -1)); + lua_pushstring (L, name); + lua_pushcclosure (L, &CFunc::readOnlyError, 1); + rawsetfield (L, -2, name); + lua_pop (L, 1); + return *this; + } + //---------------------------------------------------------------------------- /** Add or replace a property. @@ -1086,6 +1364,19 @@ public: return *this; } + + //---------------------------------------------------------------------------- + /** + Add or replace a array type + */ + + template + Namespace registerArray (char const* name) + { + return Array (name, this).endArray(); + } + + //---------------------------------------------------------------------------- /** Add or replace a lua_CFunction. @@ -1108,6 +1399,143 @@ public: return Class (name, this); } + /** weak & shared pointer class */ + template + WSPtrClass beginWSPtrClass (char const* name) + { + return WSPtrClass (name, this) + .addNullCheck(); + } + + //---------------------------------------------------------------------------- + + template + Class > beginStdMap (char const* name) + { + typedef std::map LT; + typedef std::pair T; + + return beginClass (name) + .addVoidConstructor () + .addFunction ("empty", <::empty) + .addFunction ("size", <::size) + .addFunction ("clear", (void (LT::*)())<::clear) + .addFunction ("count", (void (LT::*)())<::count) + .addExtCFunction ("add", &CFunc::tableToMap) + .addExtCFunction ("iter", &CFunc::mapIter) + .addExtCFunction ("table", &CFunc::mapToTable); + } + + template + Class > beginStdSet (char const* name) + { + typedef std::set LT; + return beginClass (name) + .addVoidConstructor () + .addFunction ("clear", (void (LT::*)())<::clear) + .addFunction ("empty", <::empty) + .addFunction ("size", <::size) + .addExtCFunction ("add", &CFunc::tableToSet) + .addExtCFunction ("iter", &CFunc::setIter) + .addExtCFunction ("table", &CFunc::setToTable); + } + + template + Class > beginStdBitSet (char const* name) + { + typedef std::bitset BS; + return beginClass (name) + .addVoidConstructor () + .addFunction ("reset", (BS& (BS::*)())&BS::reset) + .addFunction ("set", (BS& (BS::*)(size_t, bool))&BS::set) + .addFunction ("count", &BS::count) + .addFunction ("any", &BS::any) + .addFunction ("none", &BS::none) + .addFunction ("test", &BS::test) + .addFunction ("size", &BS::size) + .addExtCFunction ("add", &CFunc::tableToBitSet) + .addExtCFunction ("table", &CFunc::bitSetToTable); + } + + template + Class > beginConstStdList (char const* name) + { + typedef std::list LT; + return beginClass (name) + .addVoidConstructor () + .addFunction ("empty", <::empty) + .addFunction ("size", <::size) + .addFunction ("reverse", <::reverse) + .addExtCFunction ("iter", &CFunc::listIter) + .addExtCFunction ("table", &CFunc::listToTable); + } + + template + Class > beginStdList (char const* name) + { + typedef std::list LT; + return beginConstStdList (name) + .addFunction ("unique", (void (LT::*)())<::unique) + .addFunction ("push_back", (void (LT::*)(const T&))<::push_back) + .addExtCFunction ("add", &CFunc::tableToList); + } + + template + Class > beginStdVector (char const* name) + { + typedef std::vector LT; + typedef typename std::vector::reference T_REF; + typedef typename std::vector::size_type T_SIZE; + + return beginClass (name) + .addVoidConstructor () + .addFunction ("empty", <::empty) + .addFunction ("size", <::size) + .addFunction ("push_back", (void (LT::*)(const T&))<::push_back) + .addFunction ("at", (T_REF (LT::*)(T_SIZE))<::at) + .addExtCFunction ("add", &CFunc::tableToList) + .addExtCFunction ("iter", &CFunc::listIter) + .addExtCFunction ("table", &CFunc::listToTable); + } + + //---------------------------------------------------------------------------- + + template + Class > > beginPtrStdList (char const* name) + { + typedef std::list LT; + + return beginClass > (name) + .addVoidConstructor () + .addPtrFunction ("empty", <::empty) + .addPtrFunction ("size", <::size) + .addPtrFunction ("reverse", <::reverse) + .addPtrFunction ("unique", (void (LT::*)())<::unique) + .addPtrFunction ("push_back", (void (LT::*)(const T&))<::push_back) + .addExtCFunction ("add", &CFunc::ptrTableToList) + .addExtCFunction ("iter", &CFunc::ptrListIter) + .addExtCFunction ("table", &CFunc::ptrListToTable); + } + + template + Class > > beginPtrStdVector (char const* name) + { + typedef std::vector LT; + typedef typename std::vector::reference T_REF; + typedef typename std::vector::size_type T_SIZE; + + return beginClass > (name) + .addVoidConstructor () + .addPtrFunction ("empty", <::empty) + .addPtrFunction ("empty", <::empty) + .addPtrFunction ("size", <::size) + .addPtrFunction ("push_back", (void (LT::*)(const T&))<::push_back) + .addPtrFunction ("at", (T_REF (LT::*)(T_SIZE))<::at) + .addExtCFunction ("add", &CFunc::ptrTableToList) + .addExtCFunction ("iter", &CFunc::ptrListIter) + .addExtCFunction ("table", &CFunc::ptrListToTable); + } + //---------------------------------------------------------------------------- /** Derive a new class for registrations. @@ -1120,6 +1548,16 @@ public: { return Class (name, this, ClassInfo ::getStaticKey ()); } + + template + WSPtrClass deriveWSPtrClass (char const* name) + { + return WSPtrClass (name, this, + ClassInfo >::getStaticKey (), + ClassInfo >::getStaticKey ()) + .addNullCheck(); + } + }; //------------------------------------------------------------------------------ @@ -1134,3 +1572,5 @@ inline Namespace getGlobalNamespace (lua_State* L) { return Namespace::getGlobalNamespace (L); } + +/* vim: set et sw=2: */ diff --git a/libs/lua/LuaBridge/detail/Stack.h b/libs/lua/LuaBridge/detail/Stack.h index 2914e7432e..a569093ad1 100644 --- a/libs/lua/LuaBridge/detail/Stack.h +++ b/libs/lua/LuaBridge/detail/Stack.h @@ -2,6 +2,7 @@ /* https://github.com/vinniefalco/LuaBridge + Copyright 2016, Robin Gareus Copyright 2012, Vinnie Falco Copyright 2007, Nathan Reed @@ -281,6 +282,70 @@ struct Stack } }; +//------------------------------------------------------------------------------ +/** + Stack specialization for `long long`. +*/ +template <> +struct Stack +{ + static inline void push (lua_State* L, long long value) + { + lua_pushinteger (L, static_cast (value)); + } + + static inline long long get (lua_State* L, int index) + { + return static_cast (luaL_checkinteger (L, index)); + } +}; + +template <> +struct Stack +{ + static inline void push (lua_State* L, long long value) + { + lua_pushnumber (L, static_cast (value)); + } + + static inline long long get (lua_State* L, int index) + { + return static_cast (luaL_checknumber (L, index)); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `unsigned long long`. +*/ +template <> +struct Stack +{ + static inline void push (lua_State* L, unsigned long long value) + { + lua_pushinteger (L, static_cast (value)); + } + + static inline unsigned long long get (lua_State* L, int index) + { + return static_cast (luaL_checkinteger (L, index)); + } +}; + +template <> +struct Stack +{ + static inline void push (lua_State* L, unsigned long long value) + { + lua_pushnumber (L, static_cast (value)); + } + + static inline unsigned long long get (lua_State* L, int index) + { + return static_cast (luaL_checknumber (L, index)); + } +}; + //------------------------------------------------------------------------------ /** Stack specialization for `float`. diff --git a/libs/lua/LuaBridge/detail/TypeTraits.h b/libs/lua/LuaBridge/detail/TypeTraits.h index a6b9323393..ffb437f658 100644 --- a/libs/lua/LuaBridge/detail/TypeTraits.h +++ b/libs/lua/LuaBridge/detail/TypeTraits.h @@ -89,6 +89,16 @@ struct TypeTraits static const bool value = sizeof (test >(0)) == sizeof (yes); }; + /** Determine if T is an enum */ + template + class isEnum + { + public: + //static const bool value = std::is_enum::value; // C++11 + static const bool value = boost::is_enum::value; + }; + + /** Determine if T is const qualified. */ /** @{ */ diff --git a/libs/lua/LuaBridge/detail/Userdata.h b/libs/lua/LuaBridge/detail/Userdata.h index d87c1b0306..c7ee3bac3e 100644 --- a/libs/lua/LuaBridge/detail/Userdata.h +++ b/libs/lua/LuaBridge/detail/Userdata.h @@ -1,7 +1,8 @@ //------------------------------------------------------------------------------ /* https://github.com/vinniefalco/LuaBridge - + + Copyright 2016, Robin Gareus Copyright 2012, Vinnie Falco License: The MIT License (http://www.opensource.org/licenses/mit-license.php) @@ -68,7 +69,7 @@ protected: /** Get an untyped pointer to the contained class. */ - inline void* const getPointer () + inline void* getPointer () const { return m_p; } @@ -610,7 +611,7 @@ struct UserdataSharedHelper either be of the intrusive variety, or in the style of the RefCountedPtr type provided by LuaBridge (that uses a global hash table). */ -template +template struct StackHelper { static inline void push (lua_State* L, C const& c) @@ -636,7 +637,7 @@ struct StackHelper retrieved may result in undefined behavior if Lua garbage collected it. */ template -struct StackHelper +struct StackHelper { static inline void push (lua_State* L, T const& t) { @@ -649,6 +650,22 @@ struct StackHelper } }; +template +struct StackHelper +{ + static inline void push (lua_State* L, T const& t) + { + int v = static_cast (t); + lua_pushinteger (L, static_cast (v)); + } + + static inline T get (lua_State* L, int index) + { + int v = static_cast (luaL_checkinteger (L, index)); + return T (v); + } +}; + //============================================================================== /** @@ -661,13 +678,15 @@ public: static inline void push (lua_State* L, T const& t) { StackHelper ::value>::push (L, t); + TypeTraits::isContainer ::value, + TypeTraits::isEnum::value>::push (L, t); } static inline T get (lua_State* L, int index) { return StackHelper ::value>::get (L, index); + TypeTraits::isContainer ::value, + TypeTraits::isEnum::value>::get (L, index); } }; @@ -689,7 +708,7 @@ struct Stack UserdataPtr::push (L, p); } - static inline T* const get (lua_State* L, int index) + static inline T* get (lua_State* L, int index) { return Userdata::get (L, index, false); } @@ -704,7 +723,7 @@ struct Stack UserdataPtr::push (L, p); } - static inline T* const get (lua_State* L, int index) + static inline T* get (lua_State* L, int index) { return Userdata::get (L, index, false); } @@ -719,7 +738,7 @@ struct Stack UserdataPtr::push (L, p); } - static inline T const* const get (lua_State* L, int index) + static inline T const* get (lua_State* L, int index) { return Userdata::get (L, index, true); } @@ -734,7 +753,7 @@ struct Stack UserdataPtr::push (L, p); } - static inline T const* const get (lua_State* L, int index) + static inline T const* get (lua_State* L, int index) { return Userdata::get (L, index, true); } @@ -761,8 +780,8 @@ struct Stack template struct RefStackHelper { - typedef C return_type; - + typedef C return_type; + static inline void push (lua_State* L, C const& t) { UserdataSharedHelper struct RefStackHelper { - typedef T const& return_type; - - static inline void push (lua_State* L, T const& t) - { - UserdataPtr::push (L, &t); - } + typedef T const& return_type; + + static inline void push (lua_State* L, T const& t) + { + UserdataPtr::push (L, &t); + } static return_type get (lua_State* L, int index) { diff --git a/libs/lua/LuaBridge/detail/dump.h b/libs/lua/LuaBridge/detail/dump.h index 82f6a45ac1..b9b79ce19d 100644 --- a/libs/lua/LuaBridge/detail/dump.h +++ b/libs/lua/LuaBridge/detail/dump.h @@ -1,7 +1,7 @@ #include #include -std::string dumpLuaState(lua_State *L) { +static std::string dumpLuaState(lua_State *L) { std::stringstream ostr; int i; int top = lua_gettop(L); @@ -20,7 +20,7 @@ std::string dumpLuaState(lua_State *L) { ostr << " " << i << ": " << lua_tonumber(L, i) << "\n"; break; default: - ostr << " " << i << ": TYPE=" << lua_typename(L, t) << "\n"; + ostr << " " << i << ": TYPE=" << lua_typename(L, t) << ": " << lua_topointer(L, i)<< "\n"; break; } } -- cgit v1.2.3