From b58bd5a12e511d9d6059c04b2fe86036b9f218df Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 9 Feb 2018 19:03:10 -0800 Subject: [PATCH] Cleanup and compressing methods/metamethods into the same thing. --- limmutable.c | 53 +++++++++++++++++++--------------------------------- test.lua | 20 ++++++++++++++++++-- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/limmutable.c b/limmutable.c index e6e4c4c..8125c60 100644 --- a/limmutable.c +++ b/limmutable.c @@ -100,15 +100,11 @@ static int Lcreate_instance(lua_State *L) // Stack: [inst, buckets] lua_createtable(L, 1, 0); // Stack: [inst, buckets, bucket] - // TODO: share bucket metatables - lua_createtable(L, 0, 1); - // Stack: [inst, buckets, bucket, bucket_mt] - lua_pushstring(L, "k"); - lua_setfield(L, -2, "__mode"); + lua_pushlightuserdata(L, (void*)Lcreate_instance); + lua_gettable(L, LUA_REGISTRYINDEX); // Stack: [inst, buckets, bucket, {'__mode'='k'}] lua_setmetatable(L, -2); // Stack: [inst, buckets, bucket] - lua_pushvalue(L, -1); // Stack: [inst, buckets, bucket, bucket] lua_rawseti(L, -3, hash); @@ -376,6 +372,7 @@ static const luaL_Reg R[] = { { "__len", Llen}, { "__index", Lindex}, + { "__tostring", Ltostring}, { "__ipairs", Lipairs}, { "__pairs", Lpairs}, { "from_table", Lfrom_table}, @@ -384,21 +381,24 @@ static const luaL_Reg R[] = static int Lmake_class(lua_State *L) { - // args: fields, [methods, [metamethods]] + // args: fields, [methods/metamethods] int n_args = lua_gettop(L); // CLS = {} lua_newtable(L); // Stack: [CLS] - lua_pushcfunction(L, Ltostring); - lua_setfield(L, -2, "__tostring"); + // Populate CLS.__len, CLS.__index, CLS.__pairs, etc. + luaL_register(L,NULL,R); - // If metamethods were passed in, copy them over - if (n_args > 2) { + // If methods were passed in, copy them over, overwriting defaults if desired + if (n_args >= 2) { + // Stack: [CLS] lua_pushnil(L); // Stack: [CLS, nil] - while (lua_next(L, 3) != 0) { + while (lua_next(L, 2) != 0) { + // Stack: [CLS, method_name, method_value] lua_pushvalue(L, -2); + // Stack: [CLS, method_name, method_value, method_name] lua_pushvalue(L, -2); // Stack: [CLS, method_name, method_value, method_name, method_value] lua_settable(L, -5); @@ -406,9 +406,10 @@ static int Lmake_class(lua_State *L) lua_pop(L, 1); // Stack: [CLS, method_name] } + // Stack: [CLS] } - // CLS.buckets = {} + // Stack: [CLS] lua_newtable(L); // Stack: [CLS, CLS.buckets] lua_setfield(L, -2, "__instances"); @@ -435,27 +436,6 @@ static int Lmake_class(lua_State *L) lua_setfield(L, -2, "__indices"); // Stack: [CLS] - // If methods were passed in, copy them over - if (n_args > 1) { - // Stack: [ - lua_pushnil(L); - // Stack: [CLS, nil] - while (lua_next(L, 2) != 0) { - // Stack: [CLS, method_name, method_value] - lua_pushvalue(L, -2); - lua_pushvalue(L, -2); - // Stack: [CLS, method_name, method_value, method_name, method_value] - lua_settable(L, -5); - // Stack: [CLS, method_name, method_value] - lua_pop(L, 1); - // Stack: [CLS, method_name] - } - } - // Stack: [CLS] - - // Populate __len, __eq, __index, new, etc. - luaL_register(L,NULL,R); - // setmetatable(CLS, {__new=CLS.new}) lua_createtable(L, 0, 1); lua_pushcfunction(L, Lcreate_instance); @@ -468,6 +448,11 @@ static int Lmake_class(lua_State *L) LUALIB_API int luaopen_immutable(lua_State *L) { + lua_pushlightuserdata(L, (void*)Lcreate_instance); + lua_createtable(L, 0, 1); + lua_pushstring(L, "k"); + lua_setfield(L, -2, "__mode"); + lua_settable(L, LUA_REGISTRYINDEX); lua_pushcfunction(L, Lmake_class); return 1; } diff --git a/test.lua b/test.lua index e58a98c..10a8711 100644 --- a/test.lua +++ b/test.lua @@ -47,7 +47,6 @@ test("Creating class", function() len2=function(self) return self.x*self.x + self.y*self.y end, - }, { __add=function(self, other) local cls = getmetatable(self) return cls(self.x+other.x, self.y+other.y) @@ -110,12 +109,29 @@ end) collectgarbage() collectgarbage() +test("Testing garbage collection", function() + local collected = false + local GCSnooper = immutable({}, { + __gc=function(self) + collected = true + end, + }) + local g = GCSnooper() + collectgarbage() + collectgarbage() + assert(not collected) + g = nil + collectgarbage() + collectgarbage() + assert(collected) +end) + + test("Testing similar class", function() local FooVec = immutable({"x","y"}, { len2=function(self) return self.x*self.x + self.y*self.y end, - }, { __add=function(self, other) local cls = getmetatable(self) return cls(self.x+other.x, self.y+other.y)