aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2025-09-29 17:11:58 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2025-09-29 17:11:58 +0200
commitf011dcafb0f583c89ed9971238fd83ddcbdb5438 (patch)
treee118ea27af987540fccb2cb1563cc8d9508b255c
parent4e109a0c12d245b155bf03cb561c01b242666395 (diff)
downloadlanes-f011dcafb0f583c89ed9971238fd83ddcbdb5438.tar.gz
lanes-f011dcafb0f583c89ed9971238fd83ddcbdb5438.tar.bz2
lanes-f011dcafb0f583c89ed9971238fd83ddcbdb5438.zip
Lift restriction on tables as table keys
As demonstrated by the unit tests, there is no problem with using a table as a table key
-rw-r--r--CHANGES4
-rw-r--r--docs/index.html14
-rw-r--r--src/intercopycontext.cpp4
-rw-r--r--unit_tests/UnitTests.vcxproj1
-rw-r--r--unit_tests/UnitTests.vcxproj.filters3
-rw-r--r--unit_tests/linda_tests.cpp1
-rw-r--r--unit_tests/scripts/linda/send_receive_tables.lua41
7 files changed, 54 insertions, 14 deletions
diff --git a/CHANGES b/CHANGES
index 17a79f7..5ebf0cd 100644
--- a/CHANGES
+++ b/CHANGES
@@ -57,9 +57,11 @@ CHANGE 2: BGe 05-Jun-25
57 - linda:wake() can wake up threads waiting for a Linda without doing any I/O on it. 57 - linda:wake() can wake up threads waiting for a Linda without doing any I/O on it.
58 - linda.status reads the cancel status of the Linda. 58 - linda.status reads the cancel status of the Linda.
59 - new function linda:collectgarbage() to force collection of all stale data in the associated keeper. 59 - new function linda:collectgarbage() to force collection of all stale data in the associated keeper.
60 - Deep userdata are an acceptable key to send data into (for example, another linda). 60 - Deep userdata are an acceptable slot to send data into (for example, another linda).
61 - Tables can be used as table keys in transferred data.
61 - Full userdata conversion: 62 - Full userdata conversion:
62 - __lanesconvert added. 63 - __lanesconvert added.
64 - global configuration convert_fallback and convert_max_attempts added.
63 - __lanesignore removed. Use __lanesconvert instead. 65 - __lanesignore removed. Use __lanesconvert instead.
64 66
65CHANGE 1: BGe 9-Apr-24 67CHANGE 1: BGe 9-Apr-24
diff --git a/docs/index.html b/docs/index.html
index eba39bb..452dcfa 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1936,13 +1936,12 @@
1936</p> 1936</p>
1937 1937
1938<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> 1938<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre>
1939 int luaopen_module(lua_State *L ) 1939 int luaopen_module(lua_State* L)
1940 { 1940 {
1941 static char been_here; /* 0 by ANSI C */ 1941 static char been_here; /* 0 by ANSI C */
1942 1942
1943 // Calls to 'require' serialized by Lanes; this is safe. 1943 // Calls to 'require' serialized by Lanes; this is safe.
1944 if (!been_here) 1944 if (!been_here) {
1945 {
1946 been_here= 1; 1945 been_here= 1;
1947 ... one time initializations ... 1946 ... one time initializations ...
1948 } 1947 }
@@ -1959,8 +1958,7 @@
1959<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> 1958<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre>
1960static int clonable_lanesclone(lua_State* L) 1959static int clonable_lanesclone(lua_State* L)
1961{ 1960{
1962 switch(lua_gettop(L)) 1961 switch(lua_gettop(L)) {
1963 {
1964 case 3: 1962 case 3:
1965 { 1963 {
1966 struct s_MyClonableUserdata* self = lua_touserdata(L, 1); 1964 struct s_MyClonableUserdata* self = lua_touserdata(L, 1);
@@ -1988,16 +1986,14 @@ int luaopen_deep_userdata_example(lua_State* L)
1988 luaL_newlib(L, deep_module); 1986 luaL_newlib(L, deep_module);
1989 1987
1990 // preregister the metatables for the types we can instanciate so that Lanes can know about them 1988 // preregister the metatables for the types we can instanciate so that Lanes can know about them
1991 if (luaL_newmetatable(L, "clonable")) 1989 if (luaL_newmetatable(L, "clonable")) {
1992 {
1993 luaL_setfuncs(L, clonable_mt, 0); 1990 luaL_setfuncs(L, clonable_mt, 0);
1994 lua_pushvalue(L, -1); 1991 lua_pushvalue(L, -1);
1995 lua_setfield(L, -2, "__index"); 1992 lua_setfield(L, -2, "__index");
1996 } 1993 }
1997 lua_setfield(L, -2, "__clonableMT"); // actual name is not important 1994 lua_setfield(L, -2, "__clonableMT"); // actual name is not important
1998 1995
1999 if (luaL_newmetatable(L, "deep")) 1996 if (luaL_newmetatable(L, "deep")) {
2000 {
2001 luaL_setfuncs(L, deep_mt, 0); 1997 luaL_setfuncs(L, deep_mt, 0);
2002 lua_pushvalue(L, -1); 1998 lua_pushvalue(L, -1);
2003 lua_setfield(L, -2, "__index"); 1999 lua_setfield(L, -2, "__index");
diff --git a/src/intercopycontext.cpp b/src/intercopycontext.cpp
index a8b3374..7fb2706 100644
--- a/src/intercopycontext.cpp
+++ b/src/intercopycontext.cpp
@@ -1106,10 +1106,6 @@ void InterCopyContext::interCopyString() const
1106[[nodiscard]] 1106[[nodiscard]]
1107InterCopyOneResult InterCopyContext::interCopyTable() const 1107InterCopyOneResult InterCopyContext::interCopyTable() const
1108{ 1108{
1109 if (vt == VT::KEY) {
1110 return InterCopyOneResult::NotCopied;
1111 }
1112
1113 STACK_CHECK_START_REL(L1, 0); 1109 STACK_CHECK_START_REL(L1, 0);
1114 STACK_CHECK_START_REL(L2, 0); 1110 STACK_CHECK_START_REL(L2, 0);
1115 DEBUGSPEW_CODE(DebugSpew(nullptr) << "TABLE " << name << std::endl); 1111 DEBUGSPEW_CODE(DebugSpew(nullptr) << "TABLE " << name << std::endl);
diff --git a/unit_tests/UnitTests.vcxproj b/unit_tests/UnitTests.vcxproj
index d5edef9..300eb9b 100644
--- a/unit_tests/UnitTests.vcxproj
+++ b/unit_tests/UnitTests.vcxproj
@@ -1160,6 +1160,7 @@
1160 <None Include="scripts\lane\body_is_a_c_function.lua" /> 1160 <None Include="scripts\lane\body_is_a_c_function.lua" />
1161 <None Include="scripts\lane\tasking_cancelling_with_hook.lua" /> 1161 <None Include="scripts\lane\tasking_cancelling_with_hook.lua" />
1162 <None Include="scripts\linda\send_receive_func_and_string.lua" /> 1162 <None Include="scripts\linda\send_receive_func_and_string.lua" />
1163 <None Include="scripts\linda\send_receive_tables.lua" />
1163 <None Include="scripts\linda\wake_period.lua" /> 1164 <None Include="scripts\linda\wake_period.lua" />
1164 <None Include="scripts\misc\deeptest.lua" /> 1165 <None Include="scripts\misc\deeptest.lua" />
1165 <None Include="scripts\_utils54.lua" /> 1166 <None Include="scripts\_utils54.lua" />
diff --git a/unit_tests/UnitTests.vcxproj.filters b/unit_tests/UnitTests.vcxproj.filters
index 5d2dad8..57d8918 100644
--- a/unit_tests/UnitTests.vcxproj.filters
+++ b/unit_tests/UnitTests.vcxproj.filters
@@ -156,5 +156,8 @@
156 <None Include="scripts\misc\deeptest.lua"> 156 <None Include="scripts\misc\deeptest.lua">
157 <Filter>Scripts\misc</Filter> 157 <Filter>Scripts\misc</Filter>
158 </None> 158 </None>
159 <None Include="scripts\linda\send_receive_tables.lua">
160 <Filter>Scripts\linda</Filter>
161 </None>
159 </ItemGroup> 162 </ItemGroup>
160</Project> \ No newline at end of file 163</Project> \ No newline at end of file
diff --git a/unit_tests/linda_tests.cpp b/unit_tests/linda_tests.cpp
index 90630a7..dfba393 100644
--- a/unit_tests/linda_tests.cpp
+++ b/unit_tests/linda_tests.cpp
@@ -398,6 +398,7 @@ TEST_CASE("scripted_tests." #DIR "." #FILE) \
398MAKE_TEST_CASE(linda, multiple_keepers) 398MAKE_TEST_CASE(linda, multiple_keepers)
399MAKE_TEST_CASE(linda, send_receive) 399MAKE_TEST_CASE(linda, send_receive)
400MAKE_TEST_CASE(linda, send_receive_func_and_string) 400MAKE_TEST_CASE(linda, send_receive_func_and_string)
401MAKE_TEST_CASE(linda, send_receive_tables)
401MAKE_TEST_CASE(linda, send_registered_userdata) 402MAKE_TEST_CASE(linda, send_registered_userdata)
402MAKE_TEST_CASE(linda, wake_period) 403MAKE_TEST_CASE(linda, wake_period)
403 404
diff --git a/unit_tests/scripts/linda/send_receive_tables.lua b/unit_tests/scripts/linda/send_receive_tables.lua
new file mode 100644
index 0000000..08b1f16
--- /dev/null
+++ b/unit_tests/scripts/linda/send_receive_tables.lua
@@ -0,0 +1,41 @@
1local lanes = require "lanes"
2
3-- a newly created linda doesn't contain anything
4local l = lanes.linda()
5
6-- send a table with subtables, both as keys and values, making sure the structure is preserved
7
8local t1 = {["name"] = "t1"}
9local t2 = {["name"] = "t2"}
10
11local t3 = {
12 ["name"] = "t3",
13 ["t1"] = t1,
14 [t1] = t2, -- table t1 as key, table t2 as value
15 ["t2"] = t2,
16 [t2] = t1 -- table t2 as key, table t1 as value
17}
18
19-- add recursivity for good measure
20t3["t3"] = t3
21t3[t3] = t3
22t1["t3"] = t3
23t2["t3"] = t3
24
25l:send("data", t3)
26local k, t = l:receive("data")
27assert(k == "data" and type(t) == "table" and t.name == "t3")
28-- when keys are strings
29assert(t["t3"] == t)
30assert(type(t["t1"]) == "table")
31assert(t["t1"].name == "t1")
32assert(type(t["t2"]) == "table")
33assert(t["t2"].name == "t2")
34assert(t["t1"].t3 == t)
35assert(t["t2"].t3 == t)
36-- when keys are tables
37assert(t[t.t1] == t.t2)
38assert(t[t.t1]["t3"] == t)
39assert(t[t.t2] == t.t1)
40assert(t[t.t2]["t3"] == t)
41assert(t[t.t3] == t.t3)