diff options
Diffstat (limited to 'libs/lua/LuaBridge/detail/CFunctions.h')
-rw-r--r-- | libs/lua/LuaBridge/detail/CFunctions.h | 569 |
1 files changed, 568 insertions, 1 deletions
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: */ |