Browse Source

Lua: Use standard pairs/ipairs implementation, use 1-based array indexing (#137)

* Use standard pairs/ipairs implementation

* Remove some warning

* Fixes lua5.2 compile

* Remove exception handle

* Change Lua's array object from base-0 to base-1

* GetContext ignores illegal index access.
actboy168 5 years ago
parent
commit
551ea377b5

+ 3 - 3
Source/Core/Core.cpp

@@ -285,9 +285,9 @@ Context* GetContext(int index)
 {
 {
 	ContextMap::iterator i = contexts.begin();
 	ContextMap::iterator i = contexts.begin();
 	int count = 0;
 	int count = 0;
-
-	if (index >= GetNumContexts())
-		index = GetNumContexts() - 1;
+	
+	if (index < 0 || index >= GetNumContexts())
+		return nullptr;
 
 
 	while (count < index)
 	while (count < index)
 	{
 	{

+ 47 - 59
Source/Lua/ContextDocumentsProxy.cpp

@@ -38,8 +38,6 @@ template<> void ExtraInit<ContextDocumentsProxy>(lua_State* L, int metatable_ind
     lua_setfield(L,metatable_index,"__index");
     lua_setfield(L,metatable_index,"__index");
     lua_pushcfunction(L,ContextDocumentsProxy__pairs);
     lua_pushcfunction(L,ContextDocumentsProxy__pairs);
     lua_setfield(L,metatable_index,"__pairs");
     lua_setfield(L,metatable_index,"__pairs");
-    lua_pushcfunction(L,ContextDocumentsProxy__ipairs);
-    lua_setfield(L,metatable_index,"__ipairs");
 }
 }
 
 
 int ContextDocumentsProxy__index(lua_State* L)
 int ContextDocumentsProxy__index(lua_State* L)
@@ -53,7 +51,7 @@ int ContextDocumentsProxy__index(lua_State* L)
         if(type == LUA_TSTRING)
         if(type == LUA_TSTRING)
             ret = proxy->owner->GetDocument(luaL_checkstring(L,2));
             ret = proxy->owner->GetDocument(luaL_checkstring(L,2));
         else
         else
-            ret = proxy->owner->GetDocument((int)luaL_checkinteger(L,2));
+            ret = proxy->owner->GetDocument((int)luaL_checkinteger(L,2)-1);
         LuaType<Document>::push(L,ret,false);
         LuaType<Document>::push(L,ret,false);
         return 1;
         return 1;
     }
     }
@@ -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<ContextDocumentsProxy>::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<ContextDocumentsProxy>::check(L,1);
+        ContextDocumentsProxyPairs* self = static_cast<ContextDocumentsProxyPairs*>(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());
         lua_pushstring(L,doc->GetId().c_str());
         LuaType<Document>::push(L,doc);
         LuaType<Document>::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<ContextDocumentsProxyPairs*>(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<ContextDocumentsProxy>::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<Document>::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;
     return 2;
 }
 }
 
 
-
 RegType<ContextDocumentsProxy> ContextDocumentsProxyMethods[] =
 RegType<ContextDocumentsProxy> ContextDocumentsProxyMethods[] =
 {
 {
     { nullptr, nullptr },
     { nullptr, nullptr },

+ 0 - 1
Source/Lua/ContextDocumentsProxy.h

@@ -41,7 +41,6 @@ struct ContextDocumentsProxy { Context* owner;  };
 template<> void ExtraInit<ContextDocumentsProxy>(lua_State* L, int metatable_index);
 template<> void ExtraInit<ContextDocumentsProxy>(lua_State* L, int metatable_index);
 int ContextDocumentsProxy__index(lua_State* L);
 int ContextDocumentsProxy__index(lua_State* L);
 int ContextDocumentsProxy__pairs(lua_State* L);
 int ContextDocumentsProxy__pairs(lua_State* L);
-int ContextDocumentsProxy__ipairs(lua_State* L);
 
 
 extern RegType<ContextDocumentsProxy> ContextDocumentsProxyMethods[];
 extern RegType<ContextDocumentsProxy> ContextDocumentsProxyMethods[];
 extern luaL_Reg ContextDocumentsProxyGetters[];
 extern luaL_Reg ContextDocumentsProxyGetters[];

+ 2 - 32
Source/Lua/ElementAttributesProxy.cpp

@@ -29,6 +29,7 @@
 #include "ElementAttributesProxy.h"
 #include "ElementAttributesProxy.h"
 #include <RmlUi/Lua/Utilities.h>
 #include <RmlUi/Lua/Utilities.h>
 #include <RmlUi/Core/Variant.h>
 #include <RmlUi/Core/Variant.h>
+#include "Pairs.h"
 
 
 namespace Rml {
 namespace Rml {
 namespace Lua {
 namespace Lua {
@@ -38,8 +39,6 @@ template<> void ExtraInit<ElementAttributesProxy>(lua_State* L, int metatable_in
     lua_setfield(L,metatable_index,"__index");
     lua_setfield(L,metatable_index,"__index");
     lua_pushcfunction(L,ElementAttributesProxy__pairs);
     lua_pushcfunction(L,ElementAttributesProxy__pairs);
     lua_setfield(L,metatable_index,"__pairs");
     lua_setfield(L,metatable_index,"__pairs");
-    lua_pushcfunction(L,ElementAttributesProxy__ipairs);
-    lua_setfield(L,metatable_index,"__ipairs");
 }
 }
 
 
 int ElementAttributesProxy__index(lua_State* L)
 int ElementAttributesProxy__index(lua_State* L)
@@ -59,40 +58,11 @@ int ElementAttributesProxy__index(lua_State* L)
         return LuaType<ElementAttributesProxy>::index(L);
         return LuaType<ElementAttributesProxy>::index(L);
 }
 }
 
 
-//[1] is the object, [2] is the key that was used previously, [3] is the userdata
 int ElementAttributesProxy__pairs(lua_State* L)
 int ElementAttributesProxy__pairs(lua_State* L)
 {
 {
     ElementAttributesProxy* obj = LuaType<ElementAttributesProxy>::check(L,1);
     ElementAttributesProxy* obj = LuaType<ElementAttributesProxy>::check(L,1);
     RMLUI_CHECK_OBJ(obj);
     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<ElementAttributesProxy> ElementAttributesProxyMethods[] =
 RegType<ElementAttributesProxy> ElementAttributesProxyMethods[] =

+ 0 - 1
Source/Lua/ElementAttributesProxy.h

@@ -41,7 +41,6 @@ struct ElementAttributesProxy { Element* owner;  };
 template<> void ExtraInit<ElementAttributesProxy>(lua_State* L, int metatable_index);
 template<> void ExtraInit<ElementAttributesProxy>(lua_State* L, int metatable_index);
 int ElementAttributesProxy__index(lua_State* L);
 int ElementAttributesProxy__index(lua_State* L);
 int ElementAttributesProxy__pairs(lua_State* L);
 int ElementAttributesProxy__pairs(lua_State* L);
-int ElementAttributesProxy__ipairs(lua_State* L);
 
 
 extern RegType<ElementAttributesProxy> ElementAttributesProxyMethods[];
 extern RegType<ElementAttributesProxy> ElementAttributesProxyMethods[];
 extern luaL_Reg ElementAttributesProxyGetters[];
 extern luaL_Reg ElementAttributesProxyGetters[];

+ 3 - 29
Source/Lua/ElementChildNodesProxy.cpp

@@ -28,6 +28,7 @@
  
  
 #include "ElementChildNodesProxy.h"
 #include "ElementChildNodesProxy.h"
 #include "Element.h"
 #include "Element.h"
+#include "Pairs.h"
 
 
 namespace Rml {
 namespace Rml {
 namespace Lua {
 namespace Lua {
@@ -38,8 +39,6 @@ template<> void ExtraInit<ElementChildNodesProxy>(lua_State* L, int metatable_in
     lua_setfield(L,metatable_index,"__index");
     lua_setfield(L,metatable_index,"__index");
     lua_pushcfunction(L,ElementChildNodesProxy__pairs);
     lua_pushcfunction(L,ElementChildNodesProxy__pairs);
     lua_setfield(L,metatable_index,"__pairs");
     lua_setfield(L,metatable_index,"__pairs");
-    lua_pushcfunction(L,ElementChildNodesProxy__ipairs);
-    lua_setfield(L,metatable_index,"__ipairs");
 }
 }
 
 
 int ElementChildNodesProxy__index(lua_State* L)
 int ElementChildNodesProxy__index(lua_State* L)
@@ -51,7 +50,7 @@ int ElementChildNodesProxy__index(lua_State* L)
         ElementChildNodesProxy* obj = LuaType<ElementChildNodesProxy>::check(L,1);
         ElementChildNodesProxy* obj = LuaType<ElementChildNodesProxy>::check(L,1);
         RMLUI_CHECK_OBJ(obj);
         RMLUI_CHECK_OBJ(obj);
         int key = (int)luaL_checkinteger(L,2);
         int key = (int)luaL_checkinteger(L,2);
-        Element* child = obj->owner->GetChild(key);
+        Element* child = obj->owner->GetChild(key-1);
         LuaType<Element>::push(L,child,false);
         LuaType<Element>::push(L,child,false);
         return 1;
         return 1;
     }
     }
@@ -61,32 +60,7 @@ int ElementChildNodesProxy__index(lua_State* L)
 
 
 int ElementChildNodesProxy__pairs(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<ElementChildNodesProxy>::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<Element>::push(L,obj->owner->GetChild(*pindex)); //value
-        (*pindex) += 1;
-    }
-    else
-    {
-        lua_pushnil(L);
-        lua_pushnil(L);
-    }
-    return 2;
+    return MakeIntPairs(L);
 }
 }
 
 
 RegType<ElementChildNodesProxy> ElementChildNodesProxyMethods[] = 
 RegType<ElementChildNodesProxy> ElementChildNodesProxyMethods[] = 

+ 0 - 1
Source/Lua/ElementChildNodesProxy.h

@@ -42,7 +42,6 @@ struct ElementChildNodesProxy { Element* owner;  };
 template<> void ExtraInit<ElementChildNodesProxy>(lua_State* L, int metatable_index);
 template<> void ExtraInit<ElementChildNodesProxy>(lua_State* L, int metatable_index);
 int ElementChildNodesProxy__index(lua_State* L);
 int ElementChildNodesProxy__index(lua_State* L);
 int ElementChildNodesProxy__pairs(lua_State* L);
 int ElementChildNodesProxy__pairs(lua_State* L);
-int ElementChildNodesProxy__ipairs(lua_State* L);
 
 
 extern RegType<ElementChildNodesProxy> ElementChildNodesProxyMethods[];
 extern RegType<ElementChildNodesProxy> ElementChildNodesProxyMethods[];
 extern luaL_Reg ElementChildNodesProxyGetters[];
 extern luaL_Reg ElementChildNodesProxyGetters[];

+ 43 - 34
Source/Lua/ElementStyleProxy.cpp

@@ -46,9 +46,6 @@ template<> void ExtraInit<ElementStyleProxy>(lua_State* L, int metatable_index)
 
 
     lua_pushcfunction(L,ElementStyleProxy__pairs);
     lua_pushcfunction(L,ElementStyleProxy__pairs);
     lua_setfield(L,metatable_index,"__pairs");
     lua_setfield(L,metatable_index,"__pairs");
-
-    lua_pushcfunction(L,ElementStyleProxy__ipairs);
-    lua_setfield(L,metatable_index,"__ipairs");
 }
 }
 
 
 int ElementStyleProxy__index(lua_State* L)
 int ElementStyleProxy__index(lua_State* L)
@@ -101,46 +98,58 @@ 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<ElementStyleProxy>::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();
+        ElementStyleProxyPairs* self = static_cast<ElementStyleProxyPairs*>(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;
 		String val;
         property.definition->GetValue(val, property);
         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<ElementStyleProxyPairs*>(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);
-    return 2;
+    ElementStyleProxy* obj = LuaType<ElementStyleProxy>::check(L,1);
+    RMLUI_CHECK_OBJ(obj);
+    ElementStyleProxyPairs::constructor(L, obj);
+    return 1;
 }
 }
 
 
 RegType<ElementStyleProxy> ElementStyleProxyMethods[] = 
 RegType<ElementStyleProxy> ElementStyleProxyMethods[] = 

+ 0 - 1
Source/Lua/ElementStyleProxy.h

@@ -42,7 +42,6 @@ template<> void ExtraInit<ElementStyleProxy>(lua_State* L, int metatable_index);
 int ElementStyleProxy__index(lua_State* L);
 int ElementStyleProxy__index(lua_State* L);
 int ElementStyleProxy__newindex(lua_State* L);
 int ElementStyleProxy__newindex(lua_State* L);
 int ElementStyleProxy__pairs(lua_State* L);
 int ElementStyleProxy__pairs(lua_State* L);
-int ElementStyleProxy__ipairs(lua_State* L);
 
 
 extern RegType<ElementStyleProxy> ElementStyleProxyMethods[];
 extern RegType<ElementStyleProxy> ElementStyleProxyMethods[];
 extern luaL_Reg ElementStyleProxyGetters[];
 extern luaL_Reg ElementStyleProxyGetters[];

+ 4 - 39
Source/Lua/Elements/SelectOptionsProxy.cpp

@@ -28,6 +28,7 @@
  
  
 #include "SelectOptionsProxy.h"
 #include "SelectOptionsProxy.h"
 #include <RmlUi/Core/Element.h>
 #include <RmlUi/Core/Element.h>
+#include "../Pairs.h"
 
 
 
 
 namespace Rml {
 namespace Rml {
@@ -43,7 +44,7 @@ int SelectOptionsProxy__index(lua_State* L)
         SelectOptionsProxy* proxy = LuaType<SelectOptionsProxy>::check(L,1);
         SelectOptionsProxy* proxy = LuaType<SelectOptionsProxy>::check(L,1);
         RMLUI_CHECK_OBJ(proxy);
         RMLUI_CHECK_OBJ(proxy);
         int index = (int)luaL_checkinteger(L,2);
         int index = (int)luaL_checkinteger(L,2);
-        SelectOption* opt = proxy->owner->GetOption(index);
+        SelectOption* opt = proxy->owner->GetOption(index-1);
         RMLUI_CHECK_OBJ(opt);
         RMLUI_CHECK_OBJ(opt);
         lua_newtable(L);
         lua_newtable(L);
         LuaType<Element>::push(L,opt->GetElement(),false);
         LuaType<Element>::push(L,opt->GetElement(),false);
@@ -56,44 +57,10 @@ int SelectOptionsProxy__index(lua_State* L)
         return LuaType<SelectOptionsProxy>::index(L);
         return LuaType<SelectOptionsProxy>::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<SelectOptionsProxy>::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<Element>::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<SelectOptionsProxy> SelectOptionsProxyMethods[] =
 RegType<SelectOptionsProxy> SelectOptionsProxyMethods[] =
@@ -118,8 +85,6 @@ template<> void ExtraInit<SelectOptionsProxy>(lua_State* L, int metatable_index)
     lua_setfield(L,metatable_index,"__index");
     lua_setfield(L,metatable_index,"__index");
     lua_pushcfunction(L,SelectOptionsProxy__pairs);
     lua_pushcfunction(L,SelectOptionsProxy__pairs);
     lua_setfield(L,metatable_index,"__pairs");
     lua_setfield(L,metatable_index,"__pairs");
-    lua_pushcfunction(L,SelectOptionsProxy__ipairs);
-    lua_setfield(L,metatable_index,"__ipairs");
 }
 }
 
 
 RMLUI_LUATYPE_DEFINE(SelectOptionsProxy)
 RMLUI_LUATYPE_DEFINE(SelectOptionsProxy)

+ 0 - 1
Source/Lua/Elements/SelectOptionsProxy.h

@@ -40,7 +40,6 @@ struct SelectOptionsProxy { ElementFormControlSelect* owner;  };
 
 
 int SelectOptionsProxy__index(lua_State* L);
 int SelectOptionsProxy__index(lua_State* L);
 int SelectOptionsProxy__pairs(lua_State* L);
 int SelectOptionsProxy__pairs(lua_State* L);
-int SelectOptionsProxy__ipairs(lua_State* L);
 
 
 extern RegType<SelectOptionsProxy> SelectOptionsProxyMethods[];
 extern RegType<SelectOptionsProxy> SelectOptionsProxyMethods[];
 extern luaL_Reg SelectOptionsProxyGetters[];
 extern luaL_Reg SelectOptionsProxyGetters[];

+ 2 - 32
Source/Lua/EventParametersProxy.cpp

@@ -30,6 +30,7 @@
 #include <RmlUi/Lua/Utilities.h>
 #include <RmlUi/Lua/Utilities.h>
 #include <RmlUi/Core/Variant.h>
 #include <RmlUi/Core/Variant.h>
 #include <RmlUi/Core/Dictionary.h>
 #include <RmlUi/Core/Dictionary.h>
+#include "Pairs.h"
 
 
 
 
 namespace Rml {
 namespace Rml {
@@ -41,8 +42,6 @@ template<> void ExtraInit<EventParametersProxy>(lua_State* L, int metatable_inde
     lua_setfield(L,metatable_index,"__index");
     lua_setfield(L,metatable_index,"__index");
     lua_pushcfunction(L,EventParametersProxy__pairs);
     lua_pushcfunction(L,EventParametersProxy__pairs);
     lua_setfield(L,metatable_index,"__pairs");
     lua_setfield(L,metatable_index,"__pairs");
-    lua_pushcfunction(L,EventParametersProxy__ipairs);
-    lua_setfield(L,metatable_index,"__ipairs");
 }
 }
 
 
 int EventParametersProxy__index(lua_State* L)
 int EventParametersProxy__index(lua_State* L)
@@ -63,40 +62,11 @@ int EventParametersProxy__index(lua_State* L)
         return LuaType<EventParametersProxy>::index(L);
         return LuaType<EventParametersProxy>::index(L);
 }
 }
 
 
-
-//[1] is the object, [2] is the last used key, [3] is the userdata
 int EventParametersProxy__pairs(lua_State* L)
 int EventParametersProxy__pairs(lua_State* L)
 {
 {
     EventParametersProxy* obj = LuaType<EventParametersProxy>::check(L,1);
     EventParametersProxy* obj = LuaType<EventParametersProxy>::check(L,1);
     RMLUI_CHECK_OBJ(obj);
     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<EventParametersProxy> EventParametersProxyMethods[] =
 RegType<EventParametersProxy> EventParametersProxyMethods[] =

+ 0 - 1
Source/Lua/EventParametersProxy.h

@@ -41,7 +41,6 @@ struct EventParametersProxy { Event* owner;  };
 template<> void ExtraInit<EventParametersProxy>(lua_State* L, int metatable_index);
 template<> void ExtraInit<EventParametersProxy>(lua_State* L, int metatable_index);
 int EventParametersProxy__index(lua_State* L);
 int EventParametersProxy__index(lua_State* L);
 int EventParametersProxy__pairs(lua_State* L);
 int EventParametersProxy__pairs(lua_State* L);
-int EventParametersProxy__ipairs(lua_State* L);
 
 
 extern RegType<EventParametersProxy> EventParametersProxyMethods[];
 extern RegType<EventParametersProxy> EventParametersProxyMethods[];
 extern luaL_Reg EventParametersProxyGetters[];
 extern luaL_Reg EventParametersProxyGetters[];

+ 0 - 85
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
 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
 //Based off of the luaB_print function from Lua's lbaselib.c
 int LuaPrint(lua_State* L)
 int LuaPrint(lua_State* L)
 {
 {
@@ -148,14 +71,6 @@ void OverrideLuaGlobalFunctions(lua_State* L)
 {
 {
     lua_getglobal(L,"_G");
     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_pushcfunction(L,LuaPrint);
     lua_setfield(L,-2,"print");
     lua_setfield(L,-2,"print");
 
 

+ 132 - 0
Source/Lua/Pairs.h

@@ -0,0 +1,132 @@
+/*
+ * 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 <RmlUi/Lua/IncludeLua.h>
+#include <RmlUi/Lua/Utilities.h>
+#include <utility>
+
+namespace Rml {
+namespace Lua {
+    
+template <class T>
+int PairsConvertTolua(lua_State* L, const T& v);
+
+template <class F, class S>
+int PairsConvertTolua(lua_State* L, const std::pair<F, S>& v) {
+    int nresult = 0;
+    nresult += PairsConvertTolua(L, v.first);
+    nresult += PairsConvertTolua(L, v.second);
+    return nresult;
+}
+
+template <>
+inline int PairsConvertTolua<String>(lua_State* L, const String& s) {
+    lua_pushlstring(L, s.c_str(), s.size());
+    return 1;
+}
+
+template <>
+inline int PairsConvertTolua<Variant>(lua_State* L, const Variant& v) {
+    PushVariant(L, &v);
+    return 1;
+}
+
+template <typename T>
+struct PairsHelper {
+    static int next(lua_State* L) {
+        PairsHelper* self = static_cast<PairsHelper*>(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<PairsHelper*>(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<T>));
+        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<T>(first, last);
+        return 1;
+    }
+    PairsHelper(const T& first, const T& last)
+        : m_first(first)
+        , m_last(last)
+    { }
+    T m_first;
+    T m_last;
+};
+
+template <class Iterator>
+int MakePairs(lua_State* L, const Iterator& first, const Iterator& last) {
+    return PairsHelper<Iterator>::constructor(L, first, last);
+}
+
+template <class Container>
+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);
+#if LUA_VERSION_NUM >= 503
+    return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
+#else
+    lua_pushinteger(L, i);
+    lua_gettable(L, 1);
+    return (lua_isnil(L, -1)) ? 1 : 2;
+#endif
+}
+
+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

+ 3 - 51
Source/Lua/RmlUiContextsProxy.cpp

@@ -29,7 +29,7 @@
 #include "RmlUiContextsProxy.h"
 #include "RmlUiContextsProxy.h"
 #include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Core.h>
 #include <RmlUi/Core/Core.h>
-
+#include "Pairs.h"
 
 
 namespace Rml {
 namespace Rml {
 namespace Lua {
 namespace Lua {
@@ -40,8 +40,6 @@ template<> void ExtraInit<RmlUiContextsProxy>(lua_State* L, int metatable_index)
     lua_setfield(L,metatable_index,"__index");
     lua_setfield(L,metatable_index,"__index");
     lua_pushcfunction(L,RmlUiContextsProxy__pairs);
     lua_pushcfunction(L,RmlUiContextsProxy__pairs);
     lua_setfield(L,metatable_index,"__pairs");
     lua_setfield(L,metatable_index,"__pairs");
-    lua_pushcfunction(L,RmlUiContextsProxy__ipairs);
-    lua_setfield(L,metatable_index,"__ipairs");
 }
 }
 
 
 int RmlUiContextsProxy__index(lua_State* L)
 int RmlUiContextsProxy__index(lua_State* L)
@@ -60,7 +58,7 @@ int RmlUiContextsProxy__index(lua_State* L)
         else
         else
         {
         {
             int key = (int)luaL_checkinteger(L,2);
             int key = (int)luaL_checkinteger(L,2);
-            LuaType<Context>::push(L,GetContext(key));
+            LuaType<Context>::push(L,GetContext(key-1));
         }
         }
         return 1;
         return 1;
     }
     }
@@ -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)
 int RmlUiContextsProxy__pairs(lua_State* L)
 {
 {
-    RmlUiContextsProxy* obj = LuaType<RmlUiContextsProxy>::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<Context>::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<RmlUiContextsProxy>::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<Context>::push(L,value);
-    }
-    return 2;
-}
 
 
 RegType<RmlUiContextsProxy> RmlUiContextsProxyMethods[] =
 RegType<RmlUiContextsProxy> RmlUiContextsProxyMethods[] =
 {
 {

+ 0 - 1
Source/Lua/RmlUiContextsProxy.h

@@ -41,7 +41,6 @@ struct RmlUiContextsProxy { void* nothing;  };
 template<> void ExtraInit<RmlUiContextsProxy>(lua_State* L, int metatable_index);
 template<> void ExtraInit<RmlUiContextsProxy>(lua_State* L, int metatable_index);
 int RmlUiContextsProxy__index(lua_State* L);
 int RmlUiContextsProxy__index(lua_State* L);
 int RmlUiContextsProxy__pairs(lua_State* L);
 int RmlUiContextsProxy__pairs(lua_State* L);
-int RmlUiContextsProxy__ipairs(lua_State* L);
 
 
 extern RegType<RmlUiContextsProxy> RmlUiContextsProxyMethods[];
 extern RegType<RmlUiContextsProxy> RmlUiContextsProxyMethods[];
 extern luaL_Reg RmlUiContextsProxyGetters[];
 extern luaL_Reg RmlUiContextsProxyGetters[];