# HG changeset patch # User David Demelier # Date 1393602669 -3600 # Node ID d859ed8bc815288981a44c04efa216ccf8f3fcd0 # Parent b54c83ed71ca1d9da4b4642597af7d578fb46ccc Luae: add pushIterator diff -r b54c83ed71ca -r d859ed8bc815 C++/Luae.h --- a/C++/Luae.h Sun Feb 23 22:14:43 2014 +0100 +++ b/C++/Luae.h Fri Feb 28 16:51:09 2014 +0100 @@ -76,6 +76,24 @@ }; /** + * @struct Iterator + * @brief Wrap STL containers + */ + template + struct Iterator { + Type begin; + Type end; + Type current; + + Iterator(Type begin, Type end) + : begin(begin) + , end(end) + , current(begin) + { + } + }; + + /** * Preload a library, it will be added to package.preload so the * user can successfully call require "name". In order to work, you need * to open luaopen_package and luaopen_base first. @@ -101,6 +119,39 @@ } /** + * Load all Lua libraries. + * + * @param L the Lua state + */ + static inline void openlibs(lua_State *L) + { + luaL_openlibs(L); + } + + /** + * Set a global. + * + * @param L the Lua state + * @param name the name + */ + static inline void setglobal(lua_State *L, const std::string &name) + { + lua_setglobal(L, name.c_str()); + } + + /** + * Push a function with an optional number of upvalues. + * + * @param L the Lua state + * @param func the function + * @param nup the number of up values + */ + static inline void pushfunction(lua_State *L, lua_CFunction func, int nup = 0) + { + lua_pushcclosure(L, func, nup); + } + + /** * Move the top element at the given index. * * @param L the Lua state @@ -272,6 +323,57 @@ } /** + * Push an iterator function onto the stack. May be used by functions + * calls or directly with __pairs. + * + * The container must at least have: + * value_type, + * const_iterator + * + * The value of the container must also be pushable with Luae::Convert. + * + * @param L the Lua state + * @param container the container + * @return 1 + */ + template > + static int pushIterator(lua_State *L, const Container &container) + { + using ValueType = typename Container::value_type; + using IteratorType = typename Container::const_iterator; + + LUAE_STACK_CHECKBEGIN(L); + + auto it = new (L) Iterator(container.cbegin(), container.cend()); + + lua_createtable(L, 0, 0); + lua_pushcfunction(L, [] (lua_State *L) -> int { + toType *>(L, 1)->~Iterator(); + + return 0; + }); + lua_setfield(L, -2, "__gc"); + lua_setmetatable(L, -2); + + // Push the iterator function + lua_pushcclosure(L, [] (lua_State *L) -> int { + auto it = toType *>(L, lua_upvalueindex(1)); + + if (it->current == it->end) + return 0; + + Converter::push(L, *(it->current++)); + + return 1; + }, 1); + + LUAE_STACK_CHECKEND(L, -1); + + return 1; + } + + /** * Convert a new placement made object, without testing if its a real * object. * @@ -635,6 +737,30 @@ return *static_cast *>(lua_touserdata(L, index)); } + + /** + * Delete the shared pointer at the given index. This function does + * not check if the type is valid for performance reason. And because + * it's usually called in __gc, there is no reason to check. + * + * Also return 0 the __gc method can directly call + * return LuaeClass::deleteShared(...) + * + * @param L the Lua state + * @param index the index + * @return 0 for convenience + */ + template + static int deleteShared(lua_State *L, int index) + { + LUAE_STACK_CHECKBEGIN(L); + + Luae::toType *>(L, index)->~shared_ptr(); + + LUAE_STACK_CHECKEQUALS(L); + + return 0; + } }; /* }}} */ @@ -758,8 +884,12 @@ const std::string &meta, LuaeClass::Ptr o) { + LUAE_STACK_CHECKBEGIN(L); + LuaeClass::pushShared(L, o, meta); LuaeTable::setfield(L, (index < 0) ? --index : index, name); + + LUAE_STACK_CHECKEQUALS(L); } /** @@ -773,6 +903,8 @@ template static T require(lua_State *L, int idx, const std::string &name) { + LUAE_STACK_CHECKBEGIN(L); + lua_getfield(L, idx, name.c_str()); if (lua_type(L, -1) == LUA_TNIL) @@ -780,8 +912,11 @@ // NOT REACHED lua_pop(L, 1); + auto v = get(L, idx, name); - return get(L, idx, name); + LUAE_STACK_CHECKEQUALS(L); + + return v; } /**