diff options
author | Robin Gareus <robin@gareus.org> | 2016-02-21 19:25:42 +0100 |
---|---|---|
committer | Robin Gareus <robin@gareus.org> | 2016-02-22 22:06:47 +0100 |
commit | 12a58015a3810ed9df4661cee88be2563ea3db4e (patch) | |
tree | 13ff54b946696364f9f7ea9484522f2174908aca /libs/lua/LuaBridge | |
parent | 5b40e073e9c973479c3d286a007c57e1e0fa3d0f (diff) |
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
Diffstat (limited to 'libs/lua/LuaBridge')
-rw-r--r-- | libs/lua/LuaBridge/LuaBridge.h | 16 | ||||
-rw-r--r-- | libs/lua/LuaBridge/detail/CFunctions.h | 569 | ||||
-rw-r--r-- | libs/lua/LuaBridge/detail/LuaRef.h | 1 | ||||
-rw-r--r-- | libs/lua/LuaBridge/detail/Namespace.h | 440 | ||||
-rw-r--r-- | libs/lua/LuaBridge/detail/Stack.h | 65 | ||||
-rw-r--r-- | libs/lua/LuaBridge/detail/TypeTraits.h | 10 | ||||
-rw-r--r-- | libs/lua/LuaBridge/detail/Userdata.h | 55 | ||||
-rw-r--r-- | 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 <robin@gareus.org> Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> Copyright 2007, Nathan Reed @@ -39,6 +40,17 @@ #include <string> #include <typeinfo> +#include <bitset> +#include <list> +#include <map> +#include <set> +#include <vector> + +#include <inttypes.h> +#include <boost/ref.hpp> +#include <boost/type_traits.hpp> +#include <boost/shared_ptr.hpp> + #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 <robin@gareus.org> Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> License: The MIT License (http://www.opensource.org/licenses/mit-license.php) @@ -290,6 +291,95 @@ struct CFunc } }; + template <class MemFnPtr, class T, + class ReturnType = typename FuncTraits <MemFnPtr>::ReturnType> + struct CallMemberPtr + { + typedef typename FuncTraits <MemFnPtr>::Params Params; + + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + boost::shared_ptr<T>* const t = Userdata::get <boost::shared_ptr<T> > (L, 1, false); + T* const tt = t->get(); + if (!tt) { + return luaL_error (L, "shared_ptr is nil"); + } + MemFnPtr const& fnptr = *static_cast <MemFnPtr const*> (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + ArgList <Params, 2> args (L); + Stack <ReturnType>::push (L, FuncTraits <MemFnPtr>::call (tt, fnptr, args)); + return 1; + } + }; + + template <class T, class R> + struct CastMemberPtr + { + static int f (lua_State* L) + { + boost::shared_ptr<T> t = luabridge::Stack<boost::shared_ptr<T> >::get (L, 1); + Stack <boost::shared_ptr<R> >::push (L, boost::dynamic_pointer_cast<R> (t)); + return 1; + } + }; + + template <class T> + struct PtrNullCheck + { + static int f (lua_State* L) + { + boost::shared_ptr<T> t = luabridge::Stack<boost::shared_ptr<T> >::get (L, 1); + Stack <bool>::push (L, t == 0); + return 1; + } + }; + + template <class T> + struct WPtrNullCheck + { + static int f (lua_State* L) + { + bool rv = true; + boost::weak_ptr<T> tw = luabridge::Stack<boost::weak_ptr<T> >::get (L, 1); + boost::shared_ptr<T> const t = tw.lock(); + if (t) { + T* const tt = t.get(); + rv = (tt == 0); + } + Stack <bool>::push (L, rv); + return 1; + } + }; + + template <class MemFnPtr, class T, + class ReturnType = typename FuncTraits <MemFnPtr>::ReturnType> + struct CallMemberWPtr + { + typedef typename FuncTraits <MemFnPtr>::Params Params; + + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + boost::weak_ptr<T>* const tw = Userdata::get <boost::weak_ptr<T> > (L, 1, false); + boost::shared_ptr<T> 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 <MemFnPtr const*> (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + ArgList <Params, 2> args (L); + Stack <ReturnType>::push (L, FuncTraits <MemFnPtr>::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 <class MemFnPtr, class T> + struct CallMemberPtr <MemFnPtr, T, void> + { + typedef typename FuncTraits <MemFnPtr>::Params Params; + + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + boost::shared_ptr<T>* const t = Userdata::get <boost::shared_ptr<T> > (L, 1, false); + T* const tt = t->get(); + MemFnPtr const& fnptr = *static_cast <MemFnPtr const*> (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + ArgList <Params, 2> args (L); + FuncTraits <MemFnPtr>::call (tt, fnptr, args); + return 0; + } + }; + + template <class MemFnPtr, class T> + struct CallMemberWPtr <MemFnPtr, T, void> + { + typedef typename FuncTraits <MemFnPtr>::Params Params; + + static int f (lua_State* L) + { + assert (isfulluserdata (L, lua_upvalueindex (1))); + boost::weak_ptr<T>* const tw = Userdata::get <boost::weak_ptr<T> > (L, 1, false); + boost::shared_ptr<T> 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 <MemFnPtr const*> (lua_touserdata (L, lua_upvalueindex (1))); + assert (fnptr != 0); + ArgList <Params, 2> args (L); + FuncTraits <MemFnPtr>::call (tt, fnptr, args); + return 0; + } + }; + + + //-------------------------------------------------------------------------- /** lua_CFunction to call a class member lua_CFunction. @@ -396,6 +531,30 @@ struct CFunc } }; + template <class MemFnPtr> + struct CallMemberPtrFunctionHelper + { + typedef typename FuncTraits <MemFnPtr>::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 <MemFnPtr, T>::f, 1); + rawsetfield (L, -3, name); // class table + } + }; + + template <class MemFnPtr> + struct CallMemberWPtrFunctionHelper + { + typedef typename FuncTraits <MemFnPtr>::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 <MemFnPtr, T>::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. @@ -425,6 +589,20 @@ struct CFunc } //-------------------------------------------------------------------------- + + /** + lua_CFunction to get a constant (enum) + */ + template <typename U> + static int getConst (lua_State* L) + { + U *v = static_cast <U *> (lua_touserdata (L, lua_upvalueindex (1))); + assert (v); + Stack <U>::push (L, *v); + return 1; + } + + //-------------------------------------------------------------------------- /** lua_CFunction to set a class data member. @@ -439,4 +617,393 @@ struct CFunc c->**mp = Stack <T>::get (L, 2); return 0; } + + //-------------------------------------------------------------------------- + + // metatable callback for "array[index]" + template <typename T> + static int array_index (lua_State* L) { + T** parray = (T**) luaL_checkudata (L, 1, typeid(T).name()); + int const index = luabridge::Stack<int>::get (L, 2); + luabridge::Stack<T>::push (L, (*parray)[index-1]); + return 1; + } + + // metatable callback for "array[index] = value" + template <typename T> + static int array_newindex (lua_State* L) { + T** parray = (T**) luaL_checkudata (L, 1, typeid(T).name()); + int const index = luabridge::Stack<int>::get (L, 2); + T const value = luabridge::Stack<T>::get (L, 3); + (*parray)[index-1] = value; + return 0; + } + + template <typename T> + static int getArray (lua_State* L) { + T *v = luabridge::Stack<T*>::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 <typename T> + static int getTable (lua_State* L) { + T *v = luabridge::Stack<T*>::get (L, 1); + const int cnt = luabridge::Stack<int>::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 <typename T> + static int setTable (lua_State* L) { + T *v = luabridge::Stack<T*>::get (L, 1); + LuaRef t (LuaRef::fromStack(L, 2)); + const int cnt = luabridge::Stack<int>::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 <class T, class C> + 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<T>::get (L, -2); + t->push_back (value); + lua_pop (L, 2); + } + lua_pop (L, 1); + lua_pop (L, 2); + Stack<C>::push (L, *t); + return 1; + } + + template <class T, class C> + static int tableToList (lua_State *L) + { + C * const t = Userdata::get<C> (L, 1, false); + return tableToListHelper<T, C> (L, t); + } + + template <class T, class C> + static int ptrTableToList (lua_State *L) + { + boost::shared_ptr<C> const* const t = Userdata::get<boost::shared_ptr<C> > (L, 1, true); + if (!t) { return luaL_error (L, "cannot derefencee shared_ptr"); } + return tableToListHelper<T, C> (L, t->get()); + } + + //-------------------------------------------------------------------------- + template <class T, class C> + static int listIterIter (lua_State *L) { + typedef typename C::const_iterator IterType; + IterType * const end = static_cast <IterType * const> (lua_touserdata (L, lua_upvalueindex (2))); + IterType * const iter = static_cast <IterType * const> (lua_touserdata (L, lua_upvalueindex (1))); + assert (end); + assert (iter); + if ((*iter) == (*end)) { + return 0; + } + Stack <T>::push (L, **iter); + ++(*iter); + return 1; + } + + // generate an iterator + template <class T, class C> + 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<T, C>, 2); + return 1; + } + + template <class T, class C> + static int listIter (lua_State *L) + { + C * const t = Userdata::get <C> (L, 1, false); + return listIterHelper<T, C> (L, t); + } + + template <class T, class C> + static int ptrListIter (lua_State *L) + { + boost::shared_ptr<C> const* const t = Userdata::get <boost::shared_ptr<C> >(L, 1, true); + if (!t) { return luaL_error (L, "cannot derefencee shared_ptr"); } + return listIterHelper<T, C> (L, t->get()); + } + + //-------------------------------------------------------------------------- + // generate table from std::list + template <class T, class C> + 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<T>::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 <class T, class C> + static int listToTable (lua_State *L) + { + C const* const t = Userdata::get <C> (L, 1, true); + return listToTableHelper<T, C> (L, t); + } + + template <class T, class C> + static int ptrListToTable (lua_State *L) + { + boost::shared_ptr<C> const* const t = Userdata::get <boost::shared_ptr<C> > (L, 1, true); + if (!t) { return luaL_error (L, "cannot derefencee shared_ptr"); } + return listToTableHelper<T, C> (L, t->get()); + } + + //-------------------------------------------------------------------------- + // generate std::map from table + + template <class K, class V> + static int tableToMap (lua_State *L) + { + typedef std::map<K, V> C; + C * const t = Userdata::get <C> (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<K>::get (L, -1); + V const value = Stack<V>::get (L, -2); + t->insert (std::pair<K,V> (key, value)); + //(*t)[key] = value; + lua_pop (L, 2); + } + lua_pop (L, 1); + lua_pop (L, 2); + Stack<C>::push (L, *t); + return 1; + } + + // iterate over a std::map + template <class K, class V> + static int mapIterIter (lua_State *L) + { + typedef std::map<K, V> C; + typedef typename C::const_iterator IterType; + IterType * const end = static_cast <IterType * const> (lua_touserdata (L, lua_upvalueindex (2))); + IterType * const iter = static_cast <IterType * const> (lua_touserdata (L, lua_upvalueindex (1))); + assert (end); + assert (iter); + if ((*iter) == (*end)) { + return 0; + } + Stack <K>::push (L, (*iter)->first); + Stack <V>::push (L, (*iter)->second); + ++(*iter); + return 2; + } + + // generate iterator + template <class K, class V> + static int mapIter (lua_State *L) + { + typedef std::map<K, V> C; + C * const t = Userdata::get <C> (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<K, V>, 2); + return 1; + } + + // generate table from std::map + template <class K, class V> + static int mapToTable (lua_State *L) + { + typedef std::map<K, V> C; + C const* const t = Userdata::get <C> (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 <class T> + static int tableToSet (lua_State *L) + { + typedef std::set<T> C; + C * const t = Userdata::get <C> (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<T>::get (L, -1); + bool const v = Stack<bool>::get (L, -2); + if (v) { + t->insert (member); + } + lua_pop (L, 2); + } + lua_pop (L, 1); + lua_pop (L, 2); + Stack<C>::push (L, *t); + return 1; + } + + // iterate over a std::set, explicit "true" value. + // compare to http://www.lua.org/pil/11.5.html + template <class T> + static int setIterIter (lua_State *L) + { + typedef std::set<T> C; + typedef typename C::const_iterator IterType; + IterType * const end = static_cast <IterType * const> (lua_touserdata (L, lua_upvalueindex (2))); + IterType * const iter = static_cast <IterType * const> (lua_touserdata (L, lua_upvalueindex (1))); + assert (end); + assert (iter); + if ((*iter) == (*end)) { + return 0; + } + Stack <T>::push (L, **iter); + Stack <bool>::push (L, true); + ++(*iter); + return 2; + } + + // generate iterator + template <class T> + static int setIter (lua_State *L) + { + typedef std::set<T> C; + C * const t = Userdata::get <C> (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<T>, 2); + return 1; + } + + // generate table from std::set + template <class T> + static int setToTable (lua_State *L) + { + typedef std::set<T> C; + C const* const t = Userdata::get <C> (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 <unsigned int T> + static int tableToBitSet (lua_State *L) + { + typedef std::bitset<T> C; + C * const t = Userdata::get <C> (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<unsigned int>::get (L, -1); + bool const v = Stack<bool>::get (L, -2); + if (member < T && v) { + t->set (member); + } + lua_pop (L, 2); + } + lua_pop (L, 1); + lua_pop (L, 2); + Stack<C>::push (L, *t); + return 1; + } + + // generate table from std::bitset + template <unsigned int T> + static int bitSetToTable (lua_State *L) + { + typedef std::bitset<T> C; + C const* const t = Userdata::get <C> (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 <robin@gareus.org> Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> Copyright 2007, Nathan Reed @@ -482,6 +483,8 @@ private: } else { + lua_pop (L, 1); + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::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 MemFn> + Class <T>& addPtrFunction (char const* name, MemFn mf) + { + CFunc::CallMemberPtrFunctionHelper <MemFn>::add (L, name, mf); + return *this; + } + + template <class MemFn> + Class <T>& addWPtrFunction (char const* name, MemFn mf) + { + CFunc::CallMemberWPtrFunctionHelper <MemFn>::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 <T>& 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 <typename U> + Class <T>& 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 <U>, 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 <T>& addVoidConstructor () + { + return addConstructor <void (*) ()> (); + } + + }; + + /** C Array to/from table */ + template <typename T> + 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 <T>::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<T>, 0); + lua_setfield(L, -2, "__index"); + lua_pushcclosure (L, CFunc::array_newindex<T>, 0); + lua_setfield(L, -2, "__newindex"); + lua_pop (L, 1); + + createConstTable (name); + lua_pushcfunction (L, &CFunc::gcMetaMethod <T>); + rawsetfield (L, -2, "__gc"); + + createClassTable (name); + lua_pushcfunction (L, &CFunc::gcMetaMethod <T>); + rawsetfield (L, -2, "__gc"); + + createStaticTable (name); + + // Map T back to its tables. + lua_pushvalue (L, -1); + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getStaticKey ()); + lua_pushvalue (L, -2); + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ()); + lua_pushvalue (L, -3); + lua_rawsetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getConstKey ()); + + assert (lua_istable (L, -1)); + lua_pushcclosure (L, &CFunc::getArray <T>, 0); + rawsetfield (L, -3, "array"); // class table + + lua_pushcclosure (L, &CFunc::getTable <T>, 0); + rawsetfield (L, -3, "get_table"); // class table + + lua_pushcclosure (L, &CFunc::setTable <T>, 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 T> + 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 <class MemFn> + WSPtrClass <T>& addFunction (char const* name, MemFn mf) + { + set_weak_class (); + CFunc::CallMemberWPtrFunctionHelper <MemFn>::add (L, name, mf); + + set_shared_class (); + CFunc::CallMemberPtrFunctionHelper <MemFn>::add (L, name, mf); + return *this; + } + + template <class MemFn> + WSPtrClass <T>& addConstructor () + { + set_weak_class (); + lua_pushcclosure (L, + &weak.ctorPlacementProxy <typename FuncTraits <MemFn>::Params, boost::weak_ptr<T> >, 0); + rawsetfield(L, -2, "__call"); + + set_shared_class (); + lua_pushcclosure (L, + &shared.ctorPlacementProxy <typename FuncTraits <MemFn>::Params, boost::shared_ptr<T> >, 0); + rawsetfield(L, -2, "__call"); + return *this; + } + + WSPtrClass <T>& addVoidConstructor () + { + return addConstructor <void (*) ()> (); + } + + WSPtrClass <T>& 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 <class U> + WSPtrClass <T>& addCast (char const* name) + { + // TODO weak ptr + set_shared_class (); + assert (lua_istable (L, -1)); + lua_pushcclosure (L, &CFunc::CastMemberPtr <T, U>::f, 0); + rawsetfield (L, -3, name); // class table + return *this; + } + + WSPtrClass <T>& addNullCheck () + { + set_weak_class (); + assert (lua_istable (L, -1)); + lua_pushcclosure (L, &CFunc::WPtrNullCheck <T>::f, 0); + rawsetfield (L, -3, "isnil"); // class table + + set_shared_class (); + assert (lua_istable (L, -1)); + lua_pushcclosure (L, &CFunc::PtrNullCheck <T>::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 <boost::weak_ptr<T> >::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 <boost::shared_ptr<T> >::getStaticKey ()); + rawgetfield (L, -1, "__class"); + rawgetfield (L, -1, "__const"); + lua_insert (L, -3); + lua_insert (L, -2); + } + Class<boost::weak_ptr<T> > weak; + Class<boost::shared_ptr<T> > shared; }; + private: //---------------------------------------------------------------------------- /** @@ -1032,6 +1291,25 @@ public: return *this; } + template <typename U> + 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 <U>, 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 <typename T> + Namespace registerArray (char const* name) + { + return Array <T> (name, this).endArray(); + } + + //---------------------------------------------------------------------------- /** Add or replace a lua_CFunction. @@ -1108,6 +1399,143 @@ public: return Class <T> (name, this); } + /** weak & shared pointer class */ + template <class T> + WSPtrClass <T> beginWSPtrClass (char const* name) + { + return WSPtrClass <T> (name, this) + .addNullCheck(); + } + + //---------------------------------------------------------------------------- + + template <class K, class V> + Class<std::map<K, V> > beginStdMap (char const* name) + { + typedef std::map<K, V> LT; + typedef std::pair<const K, V> T; + + return beginClass<LT> (name) + .addVoidConstructor () + .addFunction ("empty", <::empty) + .addFunction ("size", <::size) + .addFunction ("clear", (void (LT::*)())<::clear) + .addFunction ("count", (void (LT::*)())<::count) + .addExtCFunction ("add", &CFunc::tableToMap<K, V>) + .addExtCFunction ("iter", &CFunc::mapIter<K, V>) + .addExtCFunction ("table", &CFunc::mapToTable<K, V>); + } + + template <class T> + Class<std::set<T> > beginStdSet (char const* name) + { + typedef std::set<T> LT; + return beginClass<LT> (name) + .addVoidConstructor () + .addFunction ("clear", (void (LT::*)())<::clear) + .addFunction ("empty", <::empty) + .addFunction ("size", <::size) + .addExtCFunction ("add", &CFunc::tableToSet<T>) + .addExtCFunction ("iter", &CFunc::setIter<T>) + .addExtCFunction ("table", &CFunc::setToTable<T>); + } + + template <unsigned int T> + Class<std::bitset<T> > beginStdBitSet (char const* name) + { + typedef std::bitset<T> BS; + return beginClass<BS> (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<T>) + .addExtCFunction ("table", &CFunc::bitSetToTable<T>); + } + + template <class T> + Class<std::list<T> > beginConstStdList (char const* name) + { + typedef std::list<T> LT; + return beginClass<LT> (name) + .addVoidConstructor () + .addFunction ("empty", <::empty) + .addFunction ("size", <::size) + .addFunction ("reverse", <::reverse) + .addExtCFunction ("iter", &CFunc::listIter<T, LT>) + .addExtCFunction ("table", &CFunc::listToTable<T, LT>); + } + + template <class T> + Class<std::list<T> > beginStdList (char const* name) + { + typedef std::list<T> LT; + return beginConstStdList<T> (name) + .addFunction ("unique", (void (LT::*)())<::unique) + .addFunction ("push_back", (void (LT::*)(const T&))<::push_back) + .addExtCFunction ("add", &CFunc::tableToList<T, LT>); + } + + template <class T> + Class<std::vector<T> > beginStdVector (char const* name) + { + typedef std::vector<T> LT; + typedef typename std::vector<T>::reference T_REF; + typedef typename std::vector<T>::size_type T_SIZE; + + return beginClass<LT> (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<T, LT>) + .addExtCFunction ("iter", &CFunc::listIter<T, LT>) + .addExtCFunction ("table", &CFunc::listToTable<T, LT>); + } + + //---------------------------------------------------------------------------- + + template <class T> + Class<boost::shared_ptr<std::list<T> > > beginPtrStdList (char const* name) + { + typedef std::list<T> LT; + + return beginClass<boost::shared_ptr<LT> > (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<T, LT>) + .addExtCFunction ("iter", &CFunc::ptrListIter<T, LT>) + .addExtCFunction ("table", &CFunc::ptrListToTable<T, LT>); + } + + template <class T> + Class<boost::shared_ptr<std::vector<T> > > beginPtrStdVector (char const* name) + { + typedef std::vector<T> LT; + typedef typename std::vector<T>::reference T_REF; + typedef typename std::vector<T>::size_type T_SIZE; + + return beginClass<boost::shared_ptr<LT> > (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<T, LT>) + .addExtCFunction ("iter", &CFunc::ptrListIter<T, LT>) + .addExtCFunction ("table", &CFunc::ptrListToTable<T, LT>); + } + //---------------------------------------------------------------------------- /** Derive a new class for registrations. @@ -1120,6 +1548,16 @@ public: { return Class <T> (name, this, ClassInfo <U>::getStaticKey ()); } + + template <class T, class U> + WSPtrClass <T> deriveWSPtrClass (char const* name) + { + return WSPtrClass <T> (name, this, + ClassInfo <boost::shared_ptr<U> >::getStaticKey (), + ClassInfo <boost::weak_ptr<U> >::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 <robin@gareus.org> Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> Copyright 2007, Nathan Reed @@ -283,6 +284,70 @@ struct Stack <unsigned long const&> //------------------------------------------------------------------------------ /** + Stack specialization for `long long`. +*/ +template <> +struct Stack <long long> +{ + static inline void push (lua_State* L, long long value) + { + lua_pushinteger (L, static_cast <lua_Integer> (value)); + } + + static inline long long get (lua_State* L, int index) + { + return static_cast <long long> (luaL_checkinteger (L, index)); + } +}; + +template <> +struct Stack <long long const&> +{ + static inline void push (lua_State* L, long long value) + { + lua_pushnumber (L, static_cast <lua_Number> (value)); + } + + static inline long long get (lua_State* L, int index) + { + return static_cast <long long> (luaL_checknumber (L, index)); + } +}; + +//------------------------------------------------------------------------------ +/** + Stack specialization for `unsigned long long`. +*/ +template <> +struct Stack <unsigned long long> +{ + static inline void push (lua_State* L, unsigned long long value) + { + lua_pushinteger (L, static_cast <lua_Integer> (value)); + } + + static inline unsigned long long get (lua_State* L, int index) + { + return static_cast <unsigned long long> (luaL_checkinteger (L, index)); + } +}; + +template <> +struct Stack <unsigned long long const&> +{ + static inline void push (lua_State* L, unsigned long long value) + { + lua_pushnumber (L, static_cast <lua_Number> (value)); + } + + static inline unsigned long long get (lua_State* L, int index) + { + return static_cast <unsigned long long> (luaL_checknumber (L, index)); + } +}; + +//------------------------------------------------------------------------------ +/** Stack specialization for `float`. */ template <> 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 <ContainerTraits <T> >(0)) == sizeof (yes); }; + /** Determine if T is an enum */ + template <typename T> + class isEnum + { + public: + //static const bool value = std::is_enum<T>::value; // C++11 + static const bool value = boost::is_enum<T>::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 <robin@gareus.org> Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com> 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 <C, true> either be of the intrusive variety, or in the style of the RefCountedPtr type provided by LuaBridge (that uses a global hash table). */ -template <class C, bool byContainer> +template <class C, bool byContainer, bool isEnum> 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 <class T> -struct StackHelper <T, false> +struct StackHelper <T, false, false> { static inline void push (lua_State* L, T const& t) { @@ -649,6 +650,22 @@ struct StackHelper <T, false> } }; +template <class T> +struct StackHelper <T, false, true> +{ + static inline void push (lua_State* L, T const& t) + { + int v = static_cast <int> (t); + lua_pushinteger (L, static_cast <lua_Integer> (v)); + } + + static inline T get (lua_State* L, int index) + { + int v = static_cast <int> (luaL_checkinteger (L, index)); + return T (v); + } +}; + //============================================================================== /** @@ -661,13 +678,15 @@ public: static inline void push (lua_State* L, T const& t) { StackHelper <T, - TypeTraits::isContainer <T>::value>::push (L, t); + TypeTraits::isContainer <T>::value, + TypeTraits::isEnum<T>::value>::push (L, t); } static inline T get (lua_State* L, int index) { return StackHelper <T, - TypeTraits::isContainer <T>::value>::get (L, index); + TypeTraits::isContainer <T>::value, + TypeTraits::isEnum<T>::value>::get (L, index); } }; @@ -689,7 +708,7 @@ struct Stack <T*> 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 <T> (L, index, false); } @@ -704,7 +723,7 @@ struct Stack <T* const> 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 <T> (L, index, false); } @@ -719,7 +738,7 @@ struct Stack <T const*> 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 <T> (L, index, true); } @@ -734,7 +753,7 @@ struct Stack <T const* const> 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 <T> (L, index, true); } @@ -761,8 +780,8 @@ struct Stack <T&> template <class C, bool byContainer> struct RefStackHelper { - typedef C return_type; - + typedef C return_type; + static inline void push (lua_State* L, C const& t) { UserdataSharedHelper <C, @@ -781,12 +800,12 @@ struct RefStackHelper template <class T> struct RefStackHelper <T, false> { - 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 <sstream> #include <string> -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; } } |