From a142eb1e1ee81919d10b55bb7fa2e33636098d85 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Wed, 7 Nov 2018 19:16:36 +0100 Subject: __lanesclone mechanism should actually work now --- CHANGES | 3 ++ deep_test/deep_test.c | 80 +++++++++++++++++++++++++++++++++------------ deep_test/deeptest.lua | 53 ++++++++++++++++++++---------- docs/index.html | 65 ++++++++++++++++++++++++++++++++---- src/lanes.c | 1 + src/tools.c | 89 +++++++++++++++++++++++++++++++++++++++++--------- 6 files changed, 230 insertions(+), 61 deletions(-) diff --git a/CHANGES b/CHANGES index be0e7d9..228038b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,8 @@ CHANGES: +CHANGE 132: BGe 7-Nov-18 + * __lanesclone mechanism should actually work now + CHANGE 131: BGe 7-Nov-18 * Fix potential crash at application shutdown when deep userdata were created before Lanes is required diff --git a/deep_test/deep_test.c b/deep_test/deep_test.c index 8f34fe5..4aac586 100644 --- a/deep_test/deep_test.c +++ b/deep_test/deep_test.c @@ -80,10 +80,7 @@ static void* deep_test_id( lua_State* L, enum eDeepOp op_) case eDO_metatable: { - lua_newtable( L); // mt - luaL_setfuncs( L, deep_mt, 0); // mt - lua_pushvalue( L, -1); // mt mt - lua_setfield( L, -2, "__index"); // mt + luaL_getmetatable( L, "deep"); // mt luaG_pushdeepversion( L); // mt version return NULL; } @@ -115,6 +112,16 @@ struct s_MyClonableUserdata // ################################################################################################ +static int clonable_set( lua_State* L) +{ + struct s_MyClonableUserdata* self = (struct s_MyClonableUserdata*) lua_touserdata( L, 1); + lua_Integer i = lua_tointeger( L, 2); + self->val = i; + return 0; +} + +// ################################################################################################ + static int clonable_tostring(lua_State* L) { struct s_MyClonableUserdata* self = (struct s_MyClonableUserdata*) lua_touserdata( L, 1); @@ -124,13 +131,34 @@ static int clonable_tostring(lua_State* L) // ################################################################################################ +static int clonable_gc( lua_State* L) +{ + struct s_MyClonableUserdata* self = (struct s_MyClonableUserdata*) lua_touserdata( L, 1); + return 0; +} + +// ################################################################################################ + static int clonable_lanesclone( lua_State* L) { - // no need to set the metatable, the Lane copying mechanism will take care of it - struct s_MyClonableUserdata* self = lua_touserdata( L, 1); - struct s_MyClonableUserdata* to = lua_newuserdata( L, sizeof( struct s_MyClonableUserdata)); - memcpy( to, self, sizeof(struct s_MyClonableUserdata)); - return 1; + switch( lua_gettop( L)) + { + case 0: + lua_pushinteger( L, sizeof( struct s_MyClonableUserdata)); + return 1; + + case 2: + { + struct s_MyClonableUserdata* self = lua_touserdata( L, 1); + struct s_MyClonableUserdata* from = lua_touserdata( L, 2); + *self = *from; + return 0; + } + + default: + (void) luaL_error( L, "Lanes called clonable_lanesclone with unexpected parameters"); + } + return 0; } // ################################################################################################ @@ -138,9 +166,9 @@ static int clonable_lanesclone( lua_State* L) static luaL_Reg const clonable_mt[] = { { "__tostring", clonable_tostring}, - //{ "__gc", deep_gc}, + { "__gc", clonable_gc}, { "__lanesclone", clonable_lanesclone}, - //{ "set", deep_set}, + { "set", clonable_set}, { NULL, NULL } }; @@ -149,15 +177,7 @@ static luaL_Reg const clonable_mt[] = int luaD_new_clonable( lua_State* L) { lua_newuserdata( L, sizeof( struct s_MyClonableUserdata)); - if( luaL_getmetatable( L, "clonable") == LUA_TNIL) // u mt? - { - lua_pop( L, 1); // u - lua_newtable( L); // u mt - luaL_setfuncs( L, clonable_mt, 0); - lua_pushvalue(L, -1); // u mt mt - lua_setfield(L, -2, "__index"); // u mt - } - lua_setmetatable( L, -2); // u + luaL_setmetatable( L, "clonable"); return 1; } @@ -175,6 +195,24 @@ static luaL_Reg const deep_module[] = extern int __declspec(dllexport) luaopen_deep_test(lua_State* L) { - luaL_newlib( L, deep_module); + luaL_newlib( L, deep_module); // M + + // preregister the metatables for the types we can instanciate so that Lanes can know about them + if( luaL_newmetatable( L, "clonable")) // M mt + { + luaL_setfuncs( L, clonable_mt, 0); + lua_pushvalue(L, -1); // M mt mt + lua_setfield(L, -2, "__index"); // M mt + } + lua_setfield(L, -2, "__clonableMT"); // M + + if( luaL_newmetatable( L, "deep")) // mt + { + luaL_setfuncs( L, deep_mt, 0); + lua_pushvalue(L, -1); // mt mt + lua_setfield(L, -2, "__index"); // mt + } + lua_setfield(L, -2, "__deepMT"); // M + return 1; } diff --git a/deep_test/deeptest.lua b/deep_test/deeptest.lua index 3b514dd..c0bbab4 100644 --- a/deep_test/deeptest.lua +++ b/deep_test/deeptest.lua @@ -1,22 +1,39 @@ --- create a deep-aware full userdata while Lanes isn't loaded -local dt = require "deep_test" -local deep = dt.new_deep() -deep:set(666) -print( deep) +local lanes = require("lanes").configure{ with_timers = false} +local l = lanes.linda "my linda" -local clonable = dt.new_clonable() +-- we will transfer userdata created by this module, so we need to make Lanes aware of it +local dt = lanes.require "deep_test" --- now load Lanes and see if that userdata is transferable ---[[ -local lanes = require("lanes").configure() -local l = lanes.linda "my linda" +local test_deep = true +local test_clonable = false + +local performTest = function( obj_) + obj_:set(666) + print( "immediate:", obj_) + + l:set( "key", obj_) + local out = l:get( "key") + print( "out of linda:", out) + + local g = lanes.gen( + "package" + , { + required = { "deep_test"} -- we will transfer userdata created by this module, so we need to make this lane aware of it + } + , function( obj_) + print( "in lane:", obj_) + return obj_ + end + ) + h = g( obj_) + local from_lane = h[1] + print( "from lane:", from_lane) +end -l:set( "key", deep) -local deep_out = l:get( "key") -print( deep_out) +if test_deep then + performTest( dt.new_deep()) +end -lanes.register() -l:set( "key", clonable) -local clonable_out = l:get( "key") -print( clonable_out) ---]] \ No newline at end of file +if test_clonable then + performTest( dt.new_clonable()) +end diff --git a/docs/index.html b/docs/index.html index aa12a36..9c76bef 100644 --- a/docs/index.html +++ b/docs/index.html @@ -70,7 +70,7 @@
- This document was revised on 4-Nov-18, and applies to version 3.13. + This document was revised on 7-Nov-18, and applies to version 3.13.
@@ -1516,15 +1516,68 @@ events to a common Linda, but... :).static int clonable_lanesclone( lua_State* L) { - // no need to set the metatable, the Lane copying mechanism will take care of it - struct s_MyClonableUserdata* self = lua_touserdata( L, 1); - struct s_MyClonableUserdata* to = lua_newuserdata( L, sizeof( struct s_MyClonableUserdata)); - memcpy( to, self, sizeof(struct s_MyClonableUserdata)); + switch( lua_gettop( L)) + { + case 0: + lua_pushinteger( L, sizeof( struct s_MyClonableUserdata)); + return 1; + + case 2: + { + struct s_MyClonableUserdata* self = lua_touserdata( L, 1); + struct s_MyClonableUserdata* from = lua_touserdata( L, 2); + *self = *from; + return 0; + } + + default: + (void) luaL_error( L, "Lanes called clonable_lanesclone with unexpected parameters"); + } + return 0; +} + |
+ Of course, more complex objects may require smarter cloning behavior than a simple memcpy. Also, the module initialisation code should make each metatable accessible from the module table itself as in: +
+int luaopen_deep_test(lua_State* L) +{ + luaL_newlib( L, deep_module); + + // preregister the metatables for the types we can instanciate so that Lanes can know about them + if( luaL_newmetatable( L, "clonable")) + { + luaL_setfuncs( L, clonable_mt, 0); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + } + lua_setfield(L, -2, "__clonableMT"); // actual name is not important + + if( luaL_newmetatable( L, "deep")) + { + luaL_setfuncs( L, deep_mt, 0); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + } + lua_setfield(L, -2, "__deepMT"); // actual name is not important + + return 1; +} + |
+ Then a new clonable userdata instance can just do like any non-Lanes aware userdata, as long as its metatable contains the aforementionned __lanesclone method. Note that the current implementation doesn't support uservalues on such userdata. +
+int luaD_new_clonable( lua_State* L) +{ + lua_newuserdata( L, sizeof( struct s_MyClonableUserdata)); + luaL_setmetatable( L, "clonable"); return 1; } |