summaryrefslogtreecommitdiff
path: root/Lib/lua
diff options
context:
space:
mode:
authorArtem Serebriyskiy <v.for.vandal@gmail.com>2014-04-22 14:31:41 +0400
committerArtem Serebriyskiy <v.for.vandal@gmail.com>2014-04-22 14:31:41 +0400
commitd120c05fccd75c1393bed0a295c092cc2f8128e4 (patch)
treededcd82abf5e3e89e00b2de7e4fea823513e752c /Lib/lua
parentc7e2f92a2254d8e101d79a8b063ada254f759aba (diff)
downloadswig-d120c05fccd75c1393bed0a295c092cc2f8128e4.tar.gz
Optimize metamethods inheritance resolving
* a table of metamethods that should be inherited is now stored in SWIG registry table. It optimizes memory usage.
Diffstat (limited to 'Lib/lua')
-rw-r--r--Lib/lua/luarun.swg135
1 files changed, 97 insertions, 38 deletions
diff --git a/Lib/lua/luarun.swg b/Lib/lua/luarun.swg
index b9e2d409a..398c2c8c7 100644
--- a/Lib/lua/luarun.swg
+++ b/Lib/lua/luarun.swg
@@ -332,6 +332,11 @@ typedef struct {
lua_pushcfunction(L, f), \
lua_rawset(L,-3))
+#define SWIG_Lua_add_boolean(L,n,b) \
+ (lua_pushstring(L, n), \
+ lua_pushboolean(L, b), \
+ lua_rawset(L,-3))
+
/* special helper for allowing 'nil' for usertypes */
#define SWIG_isptrtype(L,I) (lua_isuserdata(L,I) || lua_isnil(L,I))
@@ -1016,7 +1021,52 @@ SWIGINTERN int SWIG_Lua_class_disown(lua_State *L)
return 0;
}
-/* gets the swig class registry (or creates it) */
+/* populate table at the top of the stack with metamethods that ought to be inherited */
+SWIGINTERN void SWIG_Lua_populate_inheritable_metamethods(lua_State *L)
+{
+ assert(lua_istable(L,-1)); // TODO: REMOVE
+ SWIG_Lua_add_boolean(L, "__add", 1);
+ SWIG_Lua_add_boolean(L, "__sub", 1);
+ SWIG_Lua_add_boolean(L, "__mul", 1);
+ SWIG_Lua_add_boolean(L, "__div", 1);
+ SWIG_Lua_add_boolean(L, "__mod", 1);
+ SWIG_Lua_add_boolean(L, "__pow", 1);
+ SWIG_Lua_add_boolean(L, "__unm", 1);
+ SWIG_Lua_add_boolean(L, "__len", 1 );
+ SWIG_Lua_add_boolean(L, "__concat", 1 );
+ SWIG_Lua_add_boolean(L, "__eq", 1);
+ SWIG_Lua_add_boolean(L, "__lt", 1);
+ SWIG_Lua_add_boolean(L, "__le", 1);
+ SWIG_Lua_add_boolean(L, "__call", 1);
+ SWIG_Lua_add_boolean(L, "__tostring", 1);
+ SWIG_Lua_add_boolean(L, "__gc", 0);
+}
+
+/* creates the swig registry */
+SWIGINTERN void SWIG_Lua_create_class_registry(lua_State *L)
+{
+ /* create main SWIG registry table */
+ lua_pushstring(L,"SWIG");
+ lua_newtable(L);
+ /* populate it with some predefined data */
+
+ /* .library table. Placeholder */
+ lua_pushstring(L,".library");
+ lua_newtable(L);
+ {
+ /* list of metamethods that class inherits from its bases */
+ lua_pushstring(L,"inheritable_metamethods");
+ lua_newtable(L);
+ /* populate with list of metamethods */
+ SWIG_Lua_populate_inheritable_metamethods(L);
+ lua_rawset(L,-3);
+ }
+ lua_rawset(L,-3);
+
+ lua_rawset(L,LUA_REGISTRYINDEX);
+}
+
+/* gets the swig registry (or creates it) */
SWIGINTERN void SWIG_Lua_get_class_registry(lua_State *L)
{
/* add this all into the swig registry: */
@@ -1025,13 +1075,26 @@ SWIGINTERN void SWIG_Lua_get_class_registry(lua_State *L)
if (!lua_istable(L,-1)) /* not there */
{ /* must be first time, so add it */
lua_pop(L,1); /* remove the result */
- lua_pushstring(L,"SWIG");
- lua_newtable(L);
- lua_rawset(L,LUA_REGISTRYINDEX);
+ SWIG_Lua_create_class_registry(L);
/* then get it */
lua_pushstring(L,"SWIG");
lua_rawget(L,LUA_REGISTRYINDEX);
}
+ assert(!lua_isnil(L,-1)); // TODO: REMOVE
+}
+
+SWIGINTERN void SWIG_Lua_get_inheritable_metamethods(lua_State *L)
+{
+ SWIG_Lua_get_class_registry(L);
+ lua_pushstring(L, ".library");
+ lua_rawget(L,-2);
+ assert( !lua_isnil(L,-1) );
+ lua_pushstring(L, "inheritable_metamethods");
+ lua_rawget(L,-2);
+
+ /* Remove class registry and library table */
+ lua_remove(L,-2);
+ lua_remove(L,-2);
}
/* Helper function to get the classes metatable from the register */
@@ -1323,20 +1386,18 @@ SWIGRUNTIME int SWIG_Lua_resolve_metamethod(lua_State *L)
* Returns 1 if successfully added, 0 if not added because no base class has it, -1
* if method is defined in the class metatable itself
*/
-SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *clss)
+SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *clss, const int metatable_index)
{
const int begin = lua_gettop(L); // TODO:REMOVE
- /* Class metatable must be one below the top of the stack */
- assert(lua_istable(L,-2));
- /* and metamethod name - on the top of the stack */
+ assert(lua_istable(L, metatable_index)); // TODO: REMOVE
+ /* metamethod name - on the top of the stack */
assert(lua_isstring(L,-1));
- const int metatable_index = lua_gettop(L) - 1;
const int key_index = lua_gettop(L);
/* Check whether method is already defined in metatable */
- lua_pushvalue(L,-1); /* copy of the key */
+ lua_pushvalue(L,key_index); /* copy of the key */
lua_gettable(L,metatable_index);
if( !lua_isnil(L,-1) ) {
lua_pop(L,1);
@@ -1355,6 +1416,7 @@ SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *
const swig_lua_class *base = clss->bases[i];
SWIG_Lua_get_class_metatable(L, base->fqname);
lua_pushvalue(L, key_index);
+ assert(lua_istable(L,-2)); // TODO: REMOVE
lua_rawget(L, -2);
if( !lua_isnil(L,-1) ) {
assert( lua_gettop(L) == begin + 2); // TODO: REMOVE
@@ -1383,50 +1445,47 @@ SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *
return success;
}
-#define SWIG_ADD_CLASS_METAMETHOD( name ) \
- lua_pushstring(L,name);\
- SWIG_Lua_add_class_user_metamethod(L,clss);\
- lua_pop(L,1);
-
SWIGINTERN void SWIG_Lua_add_class_user_metamethods(lua_State *L, swig_lua_class *clss)
{
const int begin = lua_gettop(L); // TODO:REMOVE
- /* TODO: This place desperately needs for optimization:
- * 1. Hardcoded names of all metamethods is bad idea
- * 2. We create a N lua strings for every class instead of creating those N strings
- * only once
- */
SWIG_Lua_get_class_metatable(L, clss->fqname);
const int metatable_index = lua_gettop(L);
- SWIG_ADD_CLASS_METAMETHOD( "__add" );
- SWIG_ADD_CLASS_METAMETHOD( "__sub" );
- SWIG_ADD_CLASS_METAMETHOD( "__mul" );
- SWIG_ADD_CLASS_METAMETHOD( "__div" );
- SWIG_ADD_CLASS_METAMETHOD( "__mod" );
- SWIG_ADD_CLASS_METAMETHOD( "__pow" );
- SWIG_ADD_CLASS_METAMETHOD( "__unm" );
- SWIG_ADD_CLASS_METAMETHOD( "__concat" );
- SWIG_ADD_CLASS_METAMETHOD( "__len" );
- SWIG_ADD_CLASS_METAMETHOD( "__eq" );
- SWIG_ADD_CLASS_METAMETHOD( "__lt" );
- SWIG_ADD_CLASS_METAMETHOD( "__le" );
- SWIG_ADD_CLASS_METAMETHOD( "__call" );
+ SWIG_Lua_get_inheritable_metamethods(L);
+ assert(lua_istable(L,-1));
+ const int metamethods_info_index = lua_gettop(L);
+ lua_pushnil(L); /* first key */
+ while(lua_next(L, metamethods_info_index) != 0 ) {
+ /* key at index -2, value at index -1 */
+ const int is_inheritable = lua_toboolean(L,-2);
+ lua_pop(L,1); /* remove value - we don't need it anymore */
+
+ if(is_inheritable) { /* if metamethod is inheritable */
+ SWIG_Lua_add_class_user_metamethod(L,clss,metatable_index);
+ }
+
+ assert(lua_gettop(L) == metamethods_info_index + 1 ); // TODO: REMOVE
+ }
+
+ lua_pop(L,1); /* remove inheritable metatmethods table */
/* Special handling for __tostring method */
lua_pushstring(L, "__tostring");
- const int tostring_result = SWIG_Lua_add_class_user_metamethod(L,clss);
- if (tostring_result == 0) {
+ lua_pushvalue(L,-1);
+ assert(lua_istable(L,metatable_index)); // TODO: REMOVE
+ lua_rawget(L,metatable_index);
+ const int tostring_undefined = lua_isnil(L,-1);
+ lua_pop(L,1);
+ if( tostring_undefined ) {
lua_pushcfunction(L, SWIG_Lua_class_tostring);
lua_rawset(L, metatable_index);
} else {
- lua_pop(L,1);
+ lua_pop(L,1); /* remove copy of the key */
}
-
/* Warning: __index and __newindex are SWIG-defined. For user-defined operator[]
* a __getitem/__setitem method should be defined
*/
- lua_pop(L,1);
+ lua_pop(L,1); /* pop class metatable */
assert(lua_gettop(L) == begin ); // TODO: REMOVE
}