Pārlūkot izejas kodu

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 gadi atpakaļ
vecāks
revīzija
551ea377b5

+ 3 - 3
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)
 	{

+ 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_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)
@@ -53,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<Document>::push(L,ret,false);
         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());
         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;
 }
 
-
 RegType<ContextDocumentsProxy> ContextDocumentsProxyMethods[] =
 {
     { 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);
 int ContextDocumentsProxy__index(lua_State* L);
 int ContextDocumentsProxy__pairs(lua_State* L);
-int ContextDocumentsProxy__ipairs(lua_State* L);
 
 extern RegType<ContextDocumentsProxy> ContextDocumentsProxyMethods[];
 extern luaL_Reg ContextDocumentsProxyGetters[];

+ 2 - 32
Source/Lua/ElementAttributesProxy.cpp

@@ -29,6 +29,7 @@
 #include "ElementAttributesProxy.h"
 #include <RmlUi/Lua/Utilities.h>
 #include <RmlUi/Core/Variant.h>
+#include "Pairs.h"
 
 namespace Rml {
 namespace Lua {
@@ -38,8 +39,6 @@ template<> void ExtraInit<ElementAttributesProxy>(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<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)
 {
     ElementAttributesProxy* obj = LuaType<ElementAttributesProxy>::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<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);
 int ElementAttributesProxy__index(lua_State* L);
 int ElementAttributesProxy__pairs(lua_State* L);
-int ElementAttributesProxy__ipairs(lua_State* L);
 
 extern RegType<ElementAttributesProxy> ElementAttributesProxyMethods[];
 extern luaL_Reg ElementAttributesProxyGetters[];

+ 3 - 29
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<ElementChildNodesProxy>(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)
@@ -51,7 +50,7 @@ int ElementChildNodesProxy__index(lua_State* L)
         ElementChildNodesProxy* obj = LuaType<ElementChildNodesProxy>::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<Element>::push(L,child,false);
         return 1;
     }
@@ -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<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[] = 

+ 0 - 1
Source/Lua/ElementChildNodesProxy.h

@@ -42,7 +42,6 @@ struct ElementChildNodesProxy { Element* owner;  };
 template<> void ExtraInit<ElementChildNodesProxy>(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<ElementChildNodesProxy> ElementChildNodesProxyMethods[];
 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_setfield(L,metatable_index,"__pairs");
-
-    lua_pushcfunction(L,ElementStyleProxy__ipairs);
-    lua_setfield(L,metatable_index,"__ipairs");
 }
 
 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;
         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[] = 

+ 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__newindex(lua_State* L);
 int ElementStyleProxy__pairs(lua_State* L);
-int ElementStyleProxy__ipairs(lua_State* L);
 
 extern RegType<ElementStyleProxy> ElementStyleProxyMethods[];
 extern luaL_Reg ElementStyleProxyGetters[];

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

@@ -28,6 +28,7 @@
  
 #include "SelectOptionsProxy.h"
 #include <RmlUi/Core/Element.h>
+#include "../Pairs.h"
 
 
 namespace Rml {
@@ -43,7 +44,7 @@ int SelectOptionsProxy__index(lua_State* L)
         SelectOptionsProxy* proxy = LuaType<SelectOptionsProxy>::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<Element>::push(L,opt->GetElement(),false);
@@ -56,44 +57,10 @@ int SelectOptionsProxy__index(lua_State* 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[] =
@@ -118,8 +85,6 @@ template<> void ExtraInit<SelectOptionsProxy>(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)

+ 0 - 1
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<SelectOptionsProxy> SelectOptionsProxyMethods[];
 extern luaL_Reg SelectOptionsProxyGetters[];

+ 2 - 32
Source/Lua/EventParametersProxy.cpp

@@ -30,6 +30,7 @@
 #include <RmlUi/Lua/Utilities.h>
 #include <RmlUi/Core/Variant.h>
 #include <RmlUi/Core/Dictionary.h>
+#include "Pairs.h"
 
 
 namespace Rml {
@@ -41,8 +42,6 @@ template<> void ExtraInit<EventParametersProxy>(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<EventParametersProxy>::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<EventParametersProxy>::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<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);
 int EventParametersProxy__index(lua_State* L);
 int EventParametersProxy__pairs(lua_State* L);
-int EventParametersProxy__ipairs(lua_State* L);
 
 extern RegType<EventParametersProxy> EventParametersProxyMethods[];
 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
 */
 
-//__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");
 

+ 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 <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Core.h>
-
+#include "Pairs.h"
 
 namespace Rml {
 namespace Lua {
@@ -40,8 +40,6 @@ template<> void ExtraInit<RmlUiContextsProxy>(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)
@@ -60,7 +58,7 @@ int RmlUiContextsProxy__index(lua_State* L)
         else
         {
             int key = (int)luaL_checkinteger(L,2);
-            LuaType<Context>::push(L,GetContext(key));
+            LuaType<Context>::push(L,GetContext(key-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)
 {
-    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[] =
 {

+ 0 - 1
Source/Lua/RmlUiContextsProxy.h

@@ -41,7 +41,6 @@ struct RmlUiContextsProxy { void* nothing;  };
 template<> void ExtraInit<RmlUiContextsProxy>(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<RmlUiContextsProxy> RmlUiContextsProxyMethods[];
 extern luaL_Reg RmlUiContextsProxyGetters[];