From 5fcbc757f62cdc9698a8f783864141f40fdff34e Mon Sep 17 00:00:00 2001
From: Benoit Germain <benoit.germain@ubisoft.com>
Date: Thu, 6 Jun 2024 14:21:46 +0200
Subject: Augment deep_test with deep:invoke()

---
 deep_test/deep_test.args.json    |  2 +-
 deep_test/deep_test.cpp          | 14 ++++++++++++++
 deep_test/deep_test.vcxproj.user |  4 ++--
 deep_test/deeptest.lua           | 34 +++++++++++++++++++++++++++++-----
 4 files changed, 46 insertions(+), 8 deletions(-)

diff --git a/deep_test/deep_test.args.json b/deep_test/deep_test.args.json
index a540fc2..a94ccbb 100644
--- a/deep_test/deep_test.args.json
+++ b/deep_test/deep_test.args.json
@@ -8,7 +8,7 @@
       "Items": [
         {
           "Id": "10e30bb2-dc23-4882-b918-b5939c14e588",
-          "Command": "-i deeptest.lua"
+          "Command": "-e \"REPEAT=1000, SIZE=1000\" -i deeptest.lua"
         }
       ]
     }
diff --git a/deep_test/deep_test.cpp b/deep_test/deep_test.cpp
index da467f3..c330cbe 100644
--- a/deep_test/deep_test.cpp
+++ b/deep_test/deep_test.cpp
@@ -47,6 +47,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* c
 [[nodiscard]] static int deep_gc(lua_State* L)
 {
     MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) };
+    luaL_argcheck(L, 1, !_self->inUse.load(), "being collected while in use!");
     return 0;
 }
 
@@ -76,6 +77,18 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* c
 
 // #################################################################################################
 
+[[nodiscard]] static int deep_invoke(lua_State* L)
+{
+    MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) };
+    luaL_argcheck(L, 2, lua_gettop(L) >= 2, "need something to call");
+    _self->inUse.fetch_add(1, std::memory_order_seq_cst);
+    lua_call(L, lua_gettop(L) - 2, LUA_MULTRET);
+    _self->inUse.fetch_sub(1, std::memory_order_seq_cst);
+    return 1;
+}
+
+// #################################################################################################
+
 [[nodiscard]] static int deep_set(lua_State* const L_)
 {
     MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L_, 1)) };
@@ -105,6 +118,7 @@ static luaL_Reg const deep_mt[] = {
     { "__gc", deep_gc },
     { "__tostring", deep_tostring },
     { "getuv", deep_getuv },
+    { "invoke", deep_invoke },
     { "set", deep_set },
     { "setuv", deep_setuv },
     { nullptr, nullptr }
diff --git a/deep_test/deep_test.vcxproj.user b/deep_test/deep_test.vcxproj.user
index 257d4e9..ed75184 100644
--- a/deep_test/deep_test.vcxproj.user
+++ b/deep_test/deep_test.vcxproj.user
@@ -36,9 +36,9 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">
     <LocalDebuggerCommand>$(SolutionDir)..\framework\lua54.exe</LocalDebuggerCommand>
     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
-    <LocalDebuggerCommandArguments>deeptest.lua</LocalDebuggerCommandArguments>
+    <LocalDebuggerCommandArguments>-e "REPEAT=1000, SIZE=1000" -i deeptest.lua</LocalDebuggerCommandArguments>
     <LocalDebuggerWorkingDirectory>$(SolutionDir)Lanes\lanes\deep_test\</LocalDebuggerWorkingDirectory>
-    <RemoteDebuggerCommandArguments>deeptest.lua</RemoteDebuggerCommandArguments>
+    <RemoteDebuggerCommandArguments>-e "REPEAT=1000, SIZE=1000" -i deeptest.lua</RemoteDebuggerCommandArguments>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug MoonJIT|x64'">
     <LocalDebuggerCommand>$(SolutionDir)..\MoonJIT\bin\$(Platform)\moonjit.exe</LocalDebuggerCommand>
diff --git a/deep_test/deeptest.lua b/deep_test/deeptest.lua
index 89e6f0d..99cf1e4 100644
--- a/deep_test/deeptest.lua
+++ b/deep_test/deeptest.lua
@@ -4,8 +4,11 @@ local l = lanes.linda "my linda"
 -- we will transfer userdata created by this module, so we need to make Lanes aware of it
 local dt = lanes.require "deep_test"
 
-local test_deep = true
-local test_clonable = true
+-- set DEEP to any non-false value to run the Deep Userdata tests. "gc" selects a special test for debug purposes
+DEEP = DEEP or true
+-- set CLONABLE to any non-false value to run the Clonable Userdata tests
+CLONABLE = CLONABLE or true
+
 -- lua 5.1->5.2 support a single table uservalue
 -- lua 5.3->5.4 supports an arbitrary type uservalue
 local test_uvtype = (_VERSION == "Lua 5.4") and "function" or (_VERSION == "Lua 5.3") and "string" or "table"
@@ -86,13 +89,34 @@ local performTest = function( obj_)
 	printDeep( "from lane:", h[1], h[2])
 end
 
-if test_deep then
+if DEEP then
 	print "================================================================"
 	print "DEEP"
-	performTest( dt.new_deep(nupvals))
+	local d = dt.new_deep(nupvals)
+	if DEEP == "gc" then
+		local thrasher = function(repeat_, size_)
+			print "in thrasher"
+			-- result is a table of repeat_ tables, each containing size_ entries
+			local result = {}
+			for i = 1, repeat_ do
+				local batch_values = {}
+				for j = 1, size_ do
+					table.insert(batch_values, j)
+				end
+				table.insert(result, batch_values)
+			end
+			print "thrasher done"
+			return result
+		end
+		-- have the object call the function from inside one of its functions, to detect if it gets collected from there (while in use!)
+		local r = d:invoke(thrasher, REPEAT or 10, SIZE or 10)
+		print("invoke -> ", tostring(r))
+	else
+		performTest(d)
+	end
 end
 
-if test_clonable then
+if CLONABLE then
 	print "================================================================"
 	print "CLONABLE"
 	performTest( dt.new_clonable(nupvals))
-- 
cgit v1.2.3-55-g6feb