From 4f7403d892384d5d21f0e322e196563b5a1207ad Mon Sep 17 00:00:00 2001 From: actboy168 Date: Tue, 20 Oct 2020 16:09:42 +0800 Subject: [PATCH 1/6] Use standard pairs/ipairs implementation --- Source/Lua/ContextDocumentsProxy.cpp | 104 ++++++++-------- Source/Lua/ContextDocumentsProxy.h | 1 - Source/Lua/ElementAttributesProxy.cpp | 34 +----- Source/Lua/ElementAttributesProxy.h | 1 - Source/Lua/ElementChildNodesProxy.cpp | 30 +---- Source/Lua/ElementChildNodesProxy.h | 1 - Source/Lua/ElementStyleProxy.cpp | 77 ++++++------ Source/Lua/ElementStyleProxy.h | 1 - Source/Lua/Elements/SelectOptionsProxy.cpp | 41 +------ Source/Lua/Elements/SelectOptionsProxy.h | 1 - Source/Lua/EventParametersProxy.cpp | 34 +----- Source/Lua/EventParametersProxy.h | 1 - Source/Lua/GlobalLuaFunctions.cpp | 85 ------------- Source/Lua/Pairs.h | 131 +++++++++++++++++++++ Source/Lua/RmlUiContextsProxy.cpp | 52 +------- Source/Lua/RmlUiContextsProxy.h | 1 - 16 files changed, 232 insertions(+), 363 deletions(-) create mode 100644 Source/Lua/Pairs.h diff --git a/Source/Lua/ContextDocumentsProxy.cpp b/Source/Lua/ContextDocumentsProxy.cpp index 9ca84f919..21c51a638 100644 --- a/Source/Lua/ContextDocumentsProxy.cpp +++ b/Source/Lua/ContextDocumentsProxy.cpp @@ -38,8 +38,6 @@ template<> void ExtraInit(lua_State* L, int metatable_ind lua_setfield(L,metatable_index,"__index"); lua_pushcfunction(L,ContextDocumentsProxy__pairs); lua_setfield(L,metatable_index,"__pairs"); - lua_pushcfunction(L,ContextDocumentsProxy__ipairs); - lua_setfield(L,metatable_index,"__ipairs"); } int ContextDocumentsProxy__index(lua_State* L) @@ -62,75 +60,65 @@ int ContextDocumentsProxy__index(lua_State* L) } -//[1] is the object, [2] is the last used key, [3] is the userdata -int ContextDocumentsProxy__pairs(lua_State* L) +struct ContextDocumentsProxyPairs { - Document* doc = nullptr; - ContextDocumentsProxy* obj = LuaType::check(L,1); - RMLUI_CHECK_OBJ(obj); - int* pindex = (int*)lua_touserdata(L,3); - if((*pindex) == -1) - *pindex = 0; - - int num_docs = obj->owner->GetNumDocuments(); - //because there can be missing indexes, make sure to continue until there - //is actually a document at the index - while((*pindex) < num_docs) - { - doc = obj->owner->GetDocument((*pindex)++); - if(doc != nullptr) - break; - } - - //If we found a document - if(doc != nullptr) + static int next(lua_State* L) { + ContextDocumentsProxy* obj = LuaType::check(L,1); + ContextDocumentsProxyPairs* self = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + Document* doc = nullptr; + int num_docs = obj->owner->GetNumDocuments(); + //because there can be missing indexes, make sure to continue until there + //is actually a document at the index + while (self->m_cur < num_docs) + { + doc = obj->owner->GetDocument(self->m_cur++); + if (doc != nullptr) + break; + } + if (doc == nullptr) + { + return 0; + } lua_pushstring(L,doc->GetId().c_str()); LuaType::push(L,doc); + return 2; } - else //if we were at the end and didn't find a document + static int destroy(lua_State* L) { - lua_pushnil(L); - lua_pushnil(L); + static_cast(lua_touserdata(L, 1))->~ContextDocumentsProxyPairs(); + return 0; } - return 2; -} - -//same as __pairs, but putting an integer key instead of a string key -int ContextDocumentsProxy__ipairs(lua_State* L) -{ - Document* doc = nullptr; - ContextDocumentsProxy* obj = LuaType::check(L,1); - RMLUI_CHECK_OBJ(obj); - int* pindex = (int*)lua_touserdata(L,3); - if((*pindex) == -1) - *pindex = 0; - - int num_docs = obj->owner->GetNumDocuments(); - //because there can be missing indexes, make sure to continue until there - //is actually a document at the index - while((*pindex) < num_docs) + static int constructor(lua_State* L) { - doc = obj->owner->GetDocument((*pindex)++); - if(doc != nullptr) - break; + void* storage = lua_newuserdata(L, sizeof(ContextDocumentsProxyPairs)); + if (luaL_newmetatable(L, "RmlUi::Lua::ContextDocumentsProxyPairs")) + { + static luaL_Reg mt[] = + { + {"__gc", destroy}, + {NULL, NULL}, + }; + luaL_setfuncs(L, mt, 0); + } + lua_setmetatable(L, -2); + lua_pushcclosure(L, next, 1); + new (storage) ContextDocumentsProxyPairs(); + return 1; } + ContextDocumentsProxyPairs() + : m_cur(0) + { } + int m_cur; +}; - //we found a document - if(doc != nullptr) - { - lua_pushinteger(L,(*pindex)-1); - LuaType::push(L,doc); - } - else //we got to the end and didn't find another document - { - lua_pushnil(L); - lua_pushnil(L); - } +int ContextDocumentsProxy__pairs(lua_State* L) +{ + ContextDocumentsProxyPairs::constructor(L); + lua_pushvalue(L, 1); return 2; } - RegType ContextDocumentsProxyMethods[] = { { nullptr, nullptr }, diff --git a/Source/Lua/ContextDocumentsProxy.h b/Source/Lua/ContextDocumentsProxy.h index c5f23962e..ed3517955 100644 --- a/Source/Lua/ContextDocumentsProxy.h +++ b/Source/Lua/ContextDocumentsProxy.h @@ -41,7 +41,6 @@ struct ContextDocumentsProxy { Context* owner; }; template<> void ExtraInit(lua_State* L, int metatable_index); int ContextDocumentsProxy__index(lua_State* L); int ContextDocumentsProxy__pairs(lua_State* L); -int ContextDocumentsProxy__ipairs(lua_State* L); extern RegType ContextDocumentsProxyMethods[]; extern luaL_Reg ContextDocumentsProxyGetters[]; diff --git a/Source/Lua/ElementAttributesProxy.cpp b/Source/Lua/ElementAttributesProxy.cpp index c2da5a0e3..a771d36f6 100644 --- a/Source/Lua/ElementAttributesProxy.cpp +++ b/Source/Lua/ElementAttributesProxy.cpp @@ -29,6 +29,7 @@ #include "ElementAttributesProxy.h" #include #include +#include "Pairs.h" namespace Rml { namespace Lua { @@ -38,8 +39,6 @@ template<> void ExtraInit(lua_State* L, int metatable_in lua_setfield(L,metatable_index,"__index"); lua_pushcfunction(L,ElementAttributesProxy__pairs); lua_setfield(L,metatable_index,"__pairs"); - lua_pushcfunction(L,ElementAttributesProxy__ipairs); - lua_setfield(L,metatable_index,"__ipairs"); } int ElementAttributesProxy__index(lua_State* L) @@ -59,40 +58,11 @@ int ElementAttributesProxy__index(lua_State* L) return LuaType::index(L); } -//[1] is the object, [2] is the key that was used previously, [3] is the userdata int ElementAttributesProxy__pairs(lua_State* L) { ElementAttributesProxy* obj = LuaType::check(L,1); RMLUI_CHECK_OBJ(obj); - int& pindex = *(int*)lua_touserdata(L,3); - if ((pindex) == -1) - pindex = 0; - const ElementAttributes& attributes = obj->owner->GetAttributes(); - - if(pindex >= 0 && pindex < (int)attributes.size()) - { - auto it = attributes.begin(); - for (int i = 0; i < pindex; ++i) - ++it; - const String& key = it->first; - const Variant* value = &it->second; - lua_pushstring(L,key.c_str()); - PushVariant(L,value); - } - else - { - lua_pushnil(L); - lua_pushnil(L); - } - return 2; -} - -//Doesn't index by integer, so don't return anything -int ElementAttributesProxy__ipairs(lua_State* L) -{ - lua_pushnil(L); - lua_pushnil(L); - return 2; + return MakePairs(L, obj->owner->GetAttributes()); } RegType ElementAttributesProxyMethods[] = diff --git a/Source/Lua/ElementAttributesProxy.h b/Source/Lua/ElementAttributesProxy.h index dd577695b..f1fbb171b 100644 --- a/Source/Lua/ElementAttributesProxy.h +++ b/Source/Lua/ElementAttributesProxy.h @@ -41,7 +41,6 @@ struct ElementAttributesProxy { Element* owner; }; template<> void ExtraInit(lua_State* L, int metatable_index); int ElementAttributesProxy__index(lua_State* L); int ElementAttributesProxy__pairs(lua_State* L); -int ElementAttributesProxy__ipairs(lua_State* L); extern RegType ElementAttributesProxyMethods[]; extern luaL_Reg ElementAttributesProxyGetters[]; diff --git a/Source/Lua/ElementChildNodesProxy.cpp b/Source/Lua/ElementChildNodesProxy.cpp index 9d20a396e..c5363a266 100644 --- a/Source/Lua/ElementChildNodesProxy.cpp +++ b/Source/Lua/ElementChildNodesProxy.cpp @@ -28,6 +28,7 @@ #include "ElementChildNodesProxy.h" #include "Element.h" +#include "Pairs.h" namespace Rml { namespace Lua { @@ -38,8 +39,6 @@ template<> void ExtraInit(lua_State* L, int metatable_in lua_setfield(L,metatable_index,"__index"); lua_pushcfunction(L,ElementChildNodesProxy__pairs); lua_setfield(L,metatable_index,"__pairs"); - lua_pushcfunction(L,ElementChildNodesProxy__ipairs); - lua_setfield(L,metatable_index,"__ipairs"); } int ElementChildNodesProxy__index(lua_State* L) @@ -61,32 +60,7 @@ int ElementChildNodesProxy__index(lua_State* L) int ElementChildNodesProxy__pairs(lua_State* L) { - //because it is only indexed by integer, just go through ipairs - return ElementChildNodesProxy__ipairs(L); -} - - -//[1] is the object, [2] is the key that was just used, [3] is the userdata -int ElementChildNodesProxy__ipairs(lua_State* L) -{ - ElementChildNodesProxy* obj = LuaType::check(L,1); - RMLUI_CHECK_OBJ(obj); - int* pindex = (int*)lua_touserdata(L,3); - if((*pindex) == -1) //initial value - (*pindex) = 0; - int num_children = obj->owner->GetNumChildren(); - if((*pindex) < num_children) - { - lua_pushinteger(L,*pindex); //key - LuaType::push(L,obj->owner->GetChild(*pindex)); //value - (*pindex) += 1; - } - else - { - lua_pushnil(L); - lua_pushnil(L); - } - return 2; + return MakeIntPairs(L); } RegType ElementChildNodesProxyMethods[] = diff --git a/Source/Lua/ElementChildNodesProxy.h b/Source/Lua/ElementChildNodesProxy.h index 70dbbadd5..794721871 100644 --- a/Source/Lua/ElementChildNodesProxy.h +++ b/Source/Lua/ElementChildNodesProxy.h @@ -42,7 +42,6 @@ struct ElementChildNodesProxy { Element* owner; }; template<> void ExtraInit(lua_State* L, int metatable_index); int ElementChildNodesProxy__index(lua_State* L); int ElementChildNodesProxy__pairs(lua_State* L); -int ElementChildNodesProxy__ipairs(lua_State* L); extern RegType ElementChildNodesProxyMethods[]; extern luaL_Reg ElementChildNodesProxyGetters[]; diff --git a/Source/Lua/ElementStyleProxy.cpp b/Source/Lua/ElementStyleProxy.cpp index 9f53d93cf..5805a9d06 100644 --- a/Source/Lua/ElementStyleProxy.cpp +++ b/Source/Lua/ElementStyleProxy.cpp @@ -46,9 +46,6 @@ template<> void ExtraInit(lua_State* L, int metatable_index) lua_pushcfunction(L,ElementStyleProxy__pairs); lua_setfield(L,metatable_index,"__pairs"); - - lua_pushcfunction(L,ElementStyleProxy__ipairs); - lua_setfield(L,metatable_index,"__ipairs"); } int ElementStyleProxy__index(lua_State* L) @@ -101,45 +98,59 @@ int ElementStyleProxy__newindex(lua_State* L) } -//[1] is the object, [2] is the last used key, [3] is the userdata -int ElementStyleProxy__pairs(lua_State* L) +struct ElementStyleProxyPairs { - ElementStyleProxy* obj = LuaType::check(L,1); - RMLUI_CHECK_OBJ(obj); - int* pindex = (int*)lua_touserdata(L,3); - if ((*pindex) == -1) - *pindex = 0; - - int i = 0; - auto it = obj->owner->IterateLocalProperties(); - while (i < (*pindex) && !it.AtEnd()) - { - ++it; - ++i; - } - - if(!it.AtEnd()) + static int next(lua_State* L) { - const String& key = it.GetName(); - const Property& property = it.GetProperty(); + ElementStyleProxy* obj = LuaType::check(L,1); + ElementStyleProxyPairs* self = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + if (self->m_view.AtEnd()) + { + return 0; + } + const String& key = self->m_view.GetName(); + const Property& property = self->m_view.GetProperty(); String val; property.definition->GetValue(val, property); - lua_pushstring(L,key.c_str()); - lua_pushstring(L,val.c_str()); + lua_pushlstring(L, key.c_str(), key.size()); + lua_pushlstring(L, val.c_str(), val.size()); + ++self->m_view; + return 2; } - else + static int destroy(lua_State* L) { - lua_pushnil(L); - lua_pushnil(L); + static_cast(lua_touserdata(L, 1))->~ElementStyleProxyPairs(); + return 0; } - return 2; -} + static int constructor(lua_State* L, ElementStyleProxy* obj) + { + void* storage = lua_newuserdata(L, sizeof(ElementStyleProxyPairs)); + if (luaL_newmetatable(L, "RmlUi::Lua::ElementStyleProxyPairs")) + { + static luaL_Reg mt[] = + { + {"__gc", destroy}, + {NULL, NULL}, + }; + luaL_setfuncs(L, mt, 0); + } + lua_setmetatable(L, -2); + lua_pushcclosure(L, next, 1); + new (storage) ElementStyleProxyPairs(obj); + return 1; + } + ElementStyleProxyPairs(ElementStyleProxy* obj) + : m_view(obj->owner->IterateLocalProperties()) + { } + PropertiesIteratorView m_view; +}; -//only indexed by string -int ElementStyleProxy__ipairs(lua_State* L) +int ElementStyleProxy__pairs(lua_State* L) { - lua_pushnil(L); - lua_pushnil(L); + ElementStyleProxy* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + ElementStyleProxyPairs::constructor(L, obj); + lua_pushvalue(L, 1); return 2; } diff --git a/Source/Lua/ElementStyleProxy.h b/Source/Lua/ElementStyleProxy.h index 66e585b94..30d30ab3b 100644 --- a/Source/Lua/ElementStyleProxy.h +++ b/Source/Lua/ElementStyleProxy.h @@ -42,7 +42,6 @@ template<> void ExtraInit(lua_State* L, int metatable_index); int ElementStyleProxy__index(lua_State* L); int ElementStyleProxy__newindex(lua_State* L); int ElementStyleProxy__pairs(lua_State* L); -int ElementStyleProxy__ipairs(lua_State* L); extern RegType ElementStyleProxyMethods[]; extern luaL_Reg ElementStyleProxyGetters[]; diff --git a/Source/Lua/Elements/SelectOptionsProxy.cpp b/Source/Lua/Elements/SelectOptionsProxy.cpp index df84937fe..61f7a581c 100644 --- a/Source/Lua/Elements/SelectOptionsProxy.cpp +++ b/Source/Lua/Elements/SelectOptionsProxy.cpp @@ -28,6 +28,7 @@ #include "SelectOptionsProxy.h" #include +#include "../Pairs.h" namespace Rml { @@ -56,44 +57,10 @@ int SelectOptionsProxy__index(lua_State* L) return LuaType::index(L); } -//since there are no string keys, just use __ipairs -int SelectOptionsProxy__pairs(lua_State* L) -{ - return SelectOptionsProxy__ipairs(L); -} -//[1] is the object, [2] is the previous key, [3] is the userdata -int SelectOptionsProxy__ipairs(lua_State* L) +int SelectOptionsProxy__pairs(lua_State* L) { - SelectOptionsProxy* proxy = LuaType::check(L,1); - RMLUI_CHECK_OBJ(proxy); - int* pindex = (int*)lua_touserdata(L,3); - if((*pindex) == -1) - *pindex = 0; - SelectOption* opt = nullptr; - while((*pindex) < proxy->owner->GetNumOptions()) - { - opt = proxy->owner->GetOption((*pindex)++); - if(opt != nullptr) - break; - } - //we got to the end without finding an option - if(opt == nullptr) - { - lua_pushnil(L); - lua_pushnil(L); - } - else //we found an option - { - lua_pushinteger(L,(*pindex)-1); //key - lua_newtable(L); //value - //fill the value - LuaType::push(L,opt->GetElement()); - lua_setfield(L,-2,"element"); - lua_pushstring(L,opt->GetValue().c_str()); - lua_setfield(L,-2,"value"); - } - return 2; + return MakeIntPairs(L); } RegType SelectOptionsProxyMethods[] = @@ -118,8 +85,6 @@ template<> void ExtraInit(lua_State* L, int metatable_index) lua_setfield(L,metatable_index,"__index"); lua_pushcfunction(L,SelectOptionsProxy__pairs); lua_setfield(L,metatable_index,"__pairs"); - lua_pushcfunction(L,SelectOptionsProxy__ipairs); - lua_setfield(L,metatable_index,"__ipairs"); } RMLUI_LUATYPE_DEFINE(SelectOptionsProxy) diff --git a/Source/Lua/Elements/SelectOptionsProxy.h b/Source/Lua/Elements/SelectOptionsProxy.h index 4e7d3731b..2bdc32fd4 100644 --- a/Source/Lua/Elements/SelectOptionsProxy.h +++ b/Source/Lua/Elements/SelectOptionsProxy.h @@ -40,7 +40,6 @@ struct SelectOptionsProxy { ElementFormControlSelect* owner; }; int SelectOptionsProxy__index(lua_State* L); int SelectOptionsProxy__pairs(lua_State* L); -int SelectOptionsProxy__ipairs(lua_State* L); extern RegType SelectOptionsProxyMethods[]; extern luaL_Reg SelectOptionsProxyGetters[]; diff --git a/Source/Lua/EventParametersProxy.cpp b/Source/Lua/EventParametersProxy.cpp index 1a2ed10e5..0ee27e6fd 100644 --- a/Source/Lua/EventParametersProxy.cpp +++ b/Source/Lua/EventParametersProxy.cpp @@ -30,6 +30,7 @@ #include #include #include +#include "Pairs.h" namespace Rml { @@ -41,8 +42,6 @@ template<> void ExtraInit(lua_State* L, int metatable_inde lua_setfield(L,metatable_index,"__index"); lua_pushcfunction(L,EventParametersProxy__pairs); lua_setfield(L,metatable_index,"__pairs"); - lua_pushcfunction(L,EventParametersProxy__ipairs); - lua_setfield(L,metatable_index,"__ipairs"); } int EventParametersProxy__index(lua_State* L) @@ -63,40 +62,11 @@ int EventParametersProxy__index(lua_State* L) return LuaType::index(L); } - -//[1] is the object, [2] is the last used key, [3] is the userdata int EventParametersProxy__pairs(lua_State* L) { EventParametersProxy* obj = LuaType::check(L,1); RMLUI_CHECK_OBJ(obj); - int& pindex = *(int*)lua_touserdata(L,3); - if ((pindex) == -1) - pindex = 0; - const Dictionary& attributes = obj->owner->GetParameters(); - if(pindex >= 0 && pindex < (int)attributes.size()) - { - auto it = attributes.begin(); - for (int i = 0; i < pindex; ++i) - ++it; - const String& key = it->first; - const Variant* value = &it->second; - lua_pushstring(L,key.c_str()); - PushVariant(L,value); - } - else - { - lua_pushnil(L); - lua_pushnil(L); - } - return 2; -} - -//only index by string -int EventParametersProxy__ipairs(lua_State* L) -{ - lua_pushnil(L); - lua_pushnil(L); - return 2; + return MakePairs(L, obj->owner->GetParameters()); } RegType EventParametersProxyMethods[] = diff --git a/Source/Lua/EventParametersProxy.h b/Source/Lua/EventParametersProxy.h index 579b7d4d3..89e8cd2f9 100644 --- a/Source/Lua/EventParametersProxy.h +++ b/Source/Lua/EventParametersProxy.h @@ -41,7 +41,6 @@ struct EventParametersProxy { Event* owner; }; template<> void ExtraInit(lua_State* L, int metatable_index); int EventParametersProxy__index(lua_State* L); int EventParametersProxy__pairs(lua_State* L); -int EventParametersProxy__ipairs(lua_State* L); extern RegType EventParametersProxyMethods[]; extern luaL_Reg EventParametersProxyGetters[]; diff --git a/Source/Lua/GlobalLuaFunctions.cpp b/Source/Lua/GlobalLuaFunctions.cpp index 459c430a1..eb3caeb13 100644 --- a/Source/Lua/GlobalLuaFunctions.cpp +++ b/Source/Lua/GlobalLuaFunctions.cpp @@ -40,83 +40,6 @@ namespace Lua { Below here are global functions and their helper functions that help overwrite the Lua global functions */ -//__pairs should return two values. -//upvalue 1 is the __pairs function, upvalue 2 is the userdata created in rmlui_pairs -//[1] is the object implementing __pairs -//[2] is the key that was just read -int rmlui_pairsaux(lua_State* L) -{ - lua_pushvalue(L,lua_upvalueindex(1)); //push __pairs to top - lua_insert(L,1); //move __pairs to the bottom - lua_pushvalue(L,lua_upvalueindex(2)); //push userdata - //stack looks like [1] = __pairs, [2] = object, [3] = latest key, [4] = userdata - if(lua_pcall(L,lua_gettop(L)-1,LUA_MULTRET,0) != 0) - Report(L,"__pairs"); - return lua_gettop(L); -} - -//A version of paris that respects a __pairs metamethod. -//"next" function is upvalue 1 -int rmlui_pairs(lua_State* L) -{ - luaL_checkany(L,1); //[1] is the object given to us by pairs(object) - if(luaL_getmetafield(L,1,"__pairs")) - { - void* ud = lua_newuserdata(L,sizeof(void*)); //create a new block of memory to be used as upvalue 1 - (*(int*)(ud)) = -1; - lua_pushcclosure(L,rmlui_pairsaux,2); //uv 1 is __pairs, uv 2 is ud - } - else - lua_pushvalue(L,lua_upvalueindex(1)); //generator - lua_pushvalue(L,1); //state - lua_pushnil(L); //initial value - return 3; -} - -//copy + pasted from Lua's lbaselib.c -int ipairsaux (lua_State *L) { - lua_Integer i = luaL_checkinteger(L, 2); - luaL_checktype(L, 1, LUA_TTABLE); - i++; /* next value */ - lua_pushinteger(L, i); - lua_rawgeti(L, 1, i); - return (lua_isnil(L, -1)) ? 0 : 2; -} - -//__ipairs should return two values -//upvalue 1 is the __ipairs function, upvalue 2 is the userdata created in rmlui_ipairs -//[1] is the object implementing __ipairs, [2] is the key last used -int rmlui_ipairsaux(lua_State* L) -{ - lua_pushvalue(L,lua_upvalueindex(1)); //push __ipairs - lua_insert(L,1); //move __ipairs to the bottom - lua_pushvalue(L,lua_upvalueindex(2)); //push userdata - //stack looks like [1] = __ipairs, [2] = object, [3] = latest key, [4] = userdata - if(lua_pcall(L,lua_gettop(L)-1,LUA_MULTRET,0) != 0) - Report(L,"__ipairs"); - return lua_gettop(L); -} - - -//A version of paris that respects a __pairs metamethod. -//ipairsaux function is upvalue 1 -int rmlui_ipairs(lua_State* L) -{ - luaL_checkany(L,1); //[1] is the object given to us by ipairs(object) - if(luaL_getmetafield(L,1,"__ipairs")) - { - void* ud = lua_newuserdata(L,sizeof(void*)); //create a new block of memory to be used as upvalue 1 - (*(int*)(ud)) = -1; - lua_pushcclosure(L,rmlui_pairsaux,2); //uv 1 is __ipairs, uv 2 is ud - } - else - lua_pushvalue(L,lua_upvalueindex(1)); //generator - lua_pushvalue(L,1); //state - lua_pushnil(L); //initial value - return 3; -} - - //Based off of the luaB_print function from Lua's lbaselib.c int LuaPrint(lua_State* L) { @@ -148,14 +71,6 @@ void OverrideLuaGlobalFunctions(lua_State* L) { lua_getglobal(L,"_G"); - lua_getglobal(L,"next"); - lua_pushcclosure(L,rmlui_pairs,1); - lua_setfield(L,-2,"pairs"); - - lua_pushcfunction(L,ipairsaux); - lua_pushcclosure(L,rmlui_ipairs,1); - lua_setfield(L,-2,"ipairs"); - lua_pushcfunction(L,LuaPrint); lua_setfield(L,-2,"print"); diff --git a/Source/Lua/Pairs.h b/Source/Lua/Pairs.h new file mode 100644 index 000000000..1752695ba --- /dev/null +++ b/Source/Lua/Pairs.h @@ -0,0 +1,131 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_PAIRS_H +#define RMLUI_LUA_PAIRS_H + +#include +#include +#include + +namespace Rml { +namespace Lua { + +template +int PairsConvertTolua(lua_State* L, const T& v); + +template +int PairsConvertTolua(lua_State* L, const std::pair& v) { + int nresult = 0; + nresult += PairsConvertTolua(L, v.first); + nresult += PairsConvertTolua(L, v.second); + return nresult; +} + +template <> +inline int PairsConvertTolua(lua_State* L, const String& s) { + lua_pushlstring(L, s.c_str(), s.size()); + return 1; +} + +template <> +inline int PairsConvertTolua(lua_State* L, const Variant& v) { + PushVariant(L, &v); + return 1; +} + +template +struct PairsHelper { + static int next(lua_State* L) { + try { + PairsHelper* self = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + if (self->m_first == self->m_last) { + return 0; + } + int nreslut = PairsConvertTolua(L, *self->m_first); + ++(self->m_first); + return nreslut; + } catch (const std::exception& e) { + lua_pushstring(L, e.what()); + return lua_error(L); + } + } + static int destroy(lua_State* L) { + static_cast(lua_touserdata(L, 1))->~PairsHelper(); + return 0; + } + static int constructor(lua_State* L, const T& first, const T& last) { + void* storage = lua_newuserdata(L, sizeof(PairsHelper)); + if (luaL_newmetatable(L, "RmlUi::Lua::PairsHelper")) { + static luaL_Reg mt[] = { + {"__gc", destroy}, + {NULL, NULL}, + }; + luaL_setfuncs(L, mt, 0); + } + lua_setmetatable(L, -2); + lua_pushcclosure(L, next, 1); + new (storage) PairsHelper(first, last); + return 1; + } + PairsHelper(const T& first, const T& last) + : m_first(first) + , m_last(last) + { } + T m_first; + T m_last; +}; + +template +int MakePairs(lua_State* L, const Iterator& first, const Iterator& last) { + return PairsHelper::constructor(L, first, last); +} + +template +int MakePairs(lua_State* L, const Container& container) { + return MakePairs(L, std::begin(container), std::end(container)); +} + +inline int ipairsaux(lua_State* L) { + lua_Integer i = luaL_checkinteger(L, 2) + 1; + lua_pushinteger(L, i); + return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; +} + +inline int MakeIntPairs(lua_State* L) { + luaL_checkany(L, 1); + lua_pushcfunction(L, ipairsaux); + lua_pushvalue(L, 1); + lua_pushinteger(L, 0); + return 3; +} + +} // namespace Lua +} // namespace Rml + +#endif diff --git a/Source/Lua/RmlUiContextsProxy.cpp b/Source/Lua/RmlUiContextsProxy.cpp index 673199d58..2f6d79429 100644 --- a/Source/Lua/RmlUiContextsProxy.cpp +++ b/Source/Lua/RmlUiContextsProxy.cpp @@ -29,7 +29,7 @@ #include "RmlUiContextsProxy.h" #include #include - +#include "Pairs.h" namespace Rml { namespace Lua { @@ -40,8 +40,6 @@ template<> void ExtraInit(lua_State* L, int metatable_index) lua_setfield(L,metatable_index,"__index"); lua_pushcfunction(L,RmlUiContextsProxy__pairs); lua_setfield(L,metatable_index,"__pairs"); - lua_pushcfunction(L,RmlUiContextsProxy__ipairs); - lua_setfield(L,metatable_index,"__ipairs"); } int RmlUiContextsProxy__index(lua_State* L) @@ -69,57 +67,11 @@ int RmlUiContextsProxy__index(lua_State* L) } -//[1] is the object, [2] is the last used key, [3] is the userdata int RmlUiContextsProxy__pairs(lua_State* L) { - RmlUiContextsProxy* obj = LuaType::check(L,1); - RMLUI_CHECK_OBJ(obj); - int* pindex = (int*)lua_touserdata(L,3); - if((*pindex) == -1) - *pindex = 0; - Context* value = nullptr; - if((*pindex)++ < GetNumContexts()) - { - value = GetContext(*pindex); - } - if(value == nullptr) - { - lua_pushnil(L); - lua_pushnil(L); - } - else - { - lua_pushstring(L,value->GetName().c_str()); - LuaType::push(L,value); - } - return 2; + return MakeIntPairs(L); } -//[1] is the object, [2] is the last used key, [3] is the userdata -int RmlUiContextsProxy__ipairs(lua_State* L) -{ - RmlUiContextsProxy* obj = LuaType::check(L,1); - RMLUI_CHECK_OBJ(obj); - int* pindex = (int*)lua_touserdata(L,3); - if((*pindex) == -1) - *pindex = 0; - Context* value = nullptr; - if((*pindex)++ < GetNumContexts()) - { - value = GetContext(*pindex); - } - if(value == nullptr) - { - lua_pushnil(L); - lua_pushnil(L); - } - else - { - lua_pushinteger(L,(*pindex)-1); - LuaType::push(L,value); - } - return 2; -} RegType RmlUiContextsProxyMethods[] = { diff --git a/Source/Lua/RmlUiContextsProxy.h b/Source/Lua/RmlUiContextsProxy.h index 51f933a0f..7c0b09261 100644 --- a/Source/Lua/RmlUiContextsProxy.h +++ b/Source/Lua/RmlUiContextsProxy.h @@ -41,7 +41,6 @@ struct RmlUiContextsProxy { void* nothing; }; template<> void ExtraInit(lua_State* L, int metatable_index); int RmlUiContextsProxy__index(lua_State* L); int RmlUiContextsProxy__pairs(lua_State* L); -int RmlUiContextsProxy__ipairs(lua_State* L); extern RegType RmlUiContextsProxyMethods[]; extern luaL_Reg RmlUiContextsProxyGetters[]; From b02799643bdb190da7753723a0a0380591a539b8 Mon Sep 17 00:00:00 2001 From: actboy168 Date: Tue, 20 Oct 2020 16:47:37 +0800 Subject: [PATCH 2/6] Remove some warning --- Source/Lua/ElementStyleProxy.cpp | 4 +--- Source/Lua/Pairs.h | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Source/Lua/ElementStyleProxy.cpp b/Source/Lua/ElementStyleProxy.cpp index 5805a9d06..6812e782a 100644 --- a/Source/Lua/ElementStyleProxy.cpp +++ b/Source/Lua/ElementStyleProxy.cpp @@ -102,7 +102,6 @@ struct ElementStyleProxyPairs { static int next(lua_State* L) { - ElementStyleProxy* obj = LuaType::check(L,1); ElementStyleProxyPairs* self = static_cast(lua_touserdata(L, lua_upvalueindex(1))); if (self->m_view.AtEnd()) { @@ -150,8 +149,7 @@ int ElementStyleProxy__pairs(lua_State* L) ElementStyleProxy* obj = LuaType::check(L,1); RMLUI_CHECK_OBJ(obj); ElementStyleProxyPairs::constructor(L, obj); - lua_pushvalue(L, 1); - return 2; + return 1; } RegType ElementStyleProxyMethods[] = diff --git a/Source/Lua/Pairs.h b/Source/Lua/Pairs.h index 1752695ba..d127b0e65 100644 --- a/Source/Lua/Pairs.h +++ b/Source/Lua/Pairs.h @@ -114,7 +114,12 @@ int MakePairs(lua_State* L, const Container& container) { inline int ipairsaux(lua_State* L) { lua_Integer i = luaL_checkinteger(L, 2) + 1; lua_pushinteger(L, i); +#if LUA_VERSION_NUM >= 503 return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; +#else + lua_pushinteger(L, i); + return (lua_gettable(L, 1) == LUA_TNIL) ? 1 : 2; +#endif } inline int MakeIntPairs(lua_State* L) { From 3142d5cded2a00f5f472a2d86b05d65de8d6fdd4 Mon Sep 17 00:00:00 2001 From: actboy168 Date: Tue, 20 Oct 2020 17:05:35 +0800 Subject: [PATCH 3/6] Fixes lua5.2 compile --- Source/Lua/Pairs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Lua/Pairs.h b/Source/Lua/Pairs.h index d127b0e65..e754f854b 100644 --- a/Source/Lua/Pairs.h +++ b/Source/Lua/Pairs.h @@ -118,7 +118,8 @@ inline int ipairsaux(lua_State* L) { return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; #else lua_pushinteger(L, i); - return (lua_gettable(L, 1) == LUA_TNIL) ? 1 : 2; + lua_gettable(L, 1); + return (lua_isnil(L, -1)) ? 1 : 2; #endif } From 6d2e0ccea88d4037334a97d16755a74013cb3612 Mon Sep 17 00:00:00 2001 From: actboy168 Date: Tue, 20 Oct 2020 17:18:21 +0800 Subject: [PATCH 4/6] Remove exception handle --- Source/Lua/Pairs.h | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/Source/Lua/Pairs.h b/Source/Lua/Pairs.h index e754f854b..1d2b2bf7f 100644 --- a/Source/Lua/Pairs.h +++ b/Source/Lua/Pairs.h @@ -62,18 +62,13 @@ inline int PairsConvertTolua(lua_State* L, const Variant& v) { template struct PairsHelper { static int next(lua_State* L) { - try { - PairsHelper* self = static_cast(lua_touserdata(L, lua_upvalueindex(1))); - if (self->m_first == self->m_last) { - return 0; - } - int nreslut = PairsConvertTolua(L, *self->m_first); - ++(self->m_first); - return nreslut; - } catch (const std::exception& e) { - lua_pushstring(L, e.what()); - return lua_error(L); + PairsHelper* self = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + if (self->m_first == self->m_last) { + return 0; } + int nreslut = PairsConvertTolua(L, *self->m_first); + ++(self->m_first); + return nreslut; } static int destroy(lua_State* L) { static_cast(lua_touserdata(L, 1))->~PairsHelper(); From ae0ec6bdfc7b1a2bb3817fc77b92b7ea8e659145 Mon Sep 17 00:00:00 2001 From: actboy168 Date: Fri, 23 Oct 2020 16:39:47 +0800 Subject: [PATCH 5/6] Change Lua's array object from base-0 to base-1 --- Source/Lua/ContextDocumentsProxy.cpp | 2 +- Source/Lua/ElementChildNodesProxy.cpp | 2 +- Source/Lua/Elements/SelectOptionsProxy.cpp | 2 +- Source/Lua/RmlUiContextsProxy.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Lua/ContextDocumentsProxy.cpp b/Source/Lua/ContextDocumentsProxy.cpp index 21c51a638..ecc8da090 100644 --- a/Source/Lua/ContextDocumentsProxy.cpp +++ b/Source/Lua/ContextDocumentsProxy.cpp @@ -51,7 +51,7 @@ int ContextDocumentsProxy__index(lua_State* L) if(type == LUA_TSTRING) ret = proxy->owner->GetDocument(luaL_checkstring(L,2)); else - ret = proxy->owner->GetDocument((int)luaL_checkinteger(L,2)); + ret = proxy->owner->GetDocument((int)luaL_checkinteger(L,2)-1); LuaType::push(L,ret,false); return 1; } diff --git a/Source/Lua/ElementChildNodesProxy.cpp b/Source/Lua/ElementChildNodesProxy.cpp index c5363a266..105793b33 100644 --- a/Source/Lua/ElementChildNodesProxy.cpp +++ b/Source/Lua/ElementChildNodesProxy.cpp @@ -50,7 +50,7 @@ int ElementChildNodesProxy__index(lua_State* L) ElementChildNodesProxy* obj = LuaType::check(L,1); RMLUI_CHECK_OBJ(obj); int key = (int)luaL_checkinteger(L,2); - Element* child = obj->owner->GetChild(key); + Element* child = obj->owner->GetChild(key-1); LuaType::push(L,child,false); return 1; } diff --git a/Source/Lua/Elements/SelectOptionsProxy.cpp b/Source/Lua/Elements/SelectOptionsProxy.cpp index 61f7a581c..0e1d59183 100644 --- a/Source/Lua/Elements/SelectOptionsProxy.cpp +++ b/Source/Lua/Elements/SelectOptionsProxy.cpp @@ -44,7 +44,7 @@ int SelectOptionsProxy__index(lua_State* L) SelectOptionsProxy* proxy = LuaType::check(L,1); RMLUI_CHECK_OBJ(proxy); int index = (int)luaL_checkinteger(L,2); - SelectOption* opt = proxy->owner->GetOption(index); + SelectOption* opt = proxy->owner->GetOption(index-1); RMLUI_CHECK_OBJ(opt); lua_newtable(L); LuaType::push(L,opt->GetElement(),false); diff --git a/Source/Lua/RmlUiContextsProxy.cpp b/Source/Lua/RmlUiContextsProxy.cpp index 2f6d79429..159a0cde2 100644 --- a/Source/Lua/RmlUiContextsProxy.cpp +++ b/Source/Lua/RmlUiContextsProxy.cpp @@ -58,7 +58,7 @@ int RmlUiContextsProxy__index(lua_State* L) else { int key = (int)luaL_checkinteger(L,2); - LuaType::push(L,GetContext(key)); + LuaType::push(L,GetContext(key-1)); } return 1; } From 9e501763779e090ca0cec388d7583eb48b2c5b31 Mon Sep 17 00:00:00 2001 From: actboy168 Date: Fri, 23 Oct 2020 16:45:01 +0800 Subject: [PATCH 6/6] GetContext ignores illegal index access. --- Source/Core/Core.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core.cpp b/Source/Core/Core.cpp index 6a9b4a7c4..cc0cc2a77 100644 --- a/Source/Core/Core.cpp +++ b/Source/Core/Core.cpp @@ -285,9 +285,9 @@ Context* GetContext(int index) { ContextMap::iterator i = contexts.begin(); int count = 0; - - if (index >= GetNumContexts()) - index = GetNumContexts() - 1; + + if (index < 0 || index >= GetNumContexts()) + return nullptr; while (count < index) {