aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-03-27 10:37:05 +0100
committerBenoit Germain <benoit.germain@ubisoft.com>2024-03-27 10:37:05 +0100
commit9e3ca50cfafa0d7dc3e15f3b6a635aef6a938b80 (patch)
tree0b8dcb8cf1d90fedca7234e8a0179a09514a12bc /src
parentf214d35df5f09e7026dafd8553e83cc6ea21cbde (diff)
downloadlanes-9e3ca50cfafa0d7dc3e15f3b6a635aef6a938b80.tar.gz
lanes-9e3ca50cfafa0d7dc3e15f3b6a635aef6a938b80.tar.bz2
lanes-9e3ca50cfafa0d7dc3e15f3b6a635aef6a938b80.zip
C++ migration: new helper templates lua_tolightuserdata and lua_tofulluserdata
Diffstat (limited to 'src')
-rw-r--r--src/deep.cpp38
-rw-r--r--src/deep.h11
-rw-r--r--src/keeper.cpp19
-rw-r--r--src/lanes.cpp10
-rw-r--r--src/lanes_private.h2
-rw-r--r--src/linda.cpp2
-rw-r--r--src/macros_and_utils.h20
-rw-r--r--src/state.cpp2
-rw-r--r--src/universe.cpp20
9 files changed, 74 insertions, 50 deletions
diff --git a/src/deep.cpp b/src/deep.cpp
index f091d4d..e62ca6d 100644
--- a/src/deep.cpp
+++ b/src/deep.cpp
@@ -108,12 +108,12 @@ static void get_deep_lookup( lua_State* L)
108* Return the registered ID function for 'index' (deep userdata proxy), 108* Return the registered ID function for 'index' (deep userdata proxy),
109* or nullptr if 'index' is not a deep userdata proxy. 109* or nullptr if 'index' is not a deep userdata proxy.
110*/ 110*/
111static inline luaG_IdFunction* get_idfunc( lua_State* L, int index, LookupMode mode_) 111static inline luaG_IdFunction get_idfunc( lua_State* L, int index, LookupMode mode_)
112{ 112{
113 // when looking inside a keeper, we are 100% sure the object is a deep userdata 113 // when looking inside a keeper, we are 100% sure the object is a deep userdata
114 if( mode_ == eLM_FromKeeper) 114 if( mode_ == eLM_FromKeeper)
115 { 115 {
116 DeepPrelude** const proxy{ lua_touserdata<DeepPrelude*>(L, index) }; 116 DeepPrelude** const proxy{ lua_tofulluserdata<DeepPrelude*>(L, index) };
117 // we can (and must) cast and fetch the internally stored idfunc 117 // we can (and must) cast and fetch the internally stored idfunc
118 return (*proxy)->idfunc; 118 return (*proxy)->idfunc;
119 } 119 }
@@ -133,7 +133,7 @@ static inline luaG_IdFunction* get_idfunc( lua_State* L, int index, LookupMode m
133 // replace metatable with the idfunc pointer, if it is actually a deep userdata 133 // replace metatable with the idfunc pointer, if it is actually a deep userdata
134 get_deep_lookup( L); // deep ... idfunc|nil 134 get_deep_lookup( L); // deep ... idfunc|nil
135 135
136 luaG_IdFunction* const ret{ lua_touserdata<luaG_IdFunction>(L, -1) }; // nullptr if not a userdata 136 luaG_IdFunction const ret{ *lua_tolightuserdata<luaG_IdFunction>(L, -1) }; // nullptr if not a userdata
137 lua_pop( L, 1); 137 lua_pop( L, 1);
138 STACK_CHECK( L, 0); 138 STACK_CHECK( L, 0);
139 return ret; 139 return ret;
@@ -161,7 +161,7 @@ void free_deep_prelude( lua_State* L, DeepPrelude* prelude_)
161 */ 161 */
162static int deep_userdata_gc( lua_State* L) 162static int deep_userdata_gc( lua_State* L)
163{ 163{
164 DeepPrelude** const proxy{ lua_touserdata<DeepPrelude*>(L, 1) }; 164 DeepPrelude** const proxy{ lua_tofulluserdata<DeepPrelude*>(L, 1) };
165 DeepPrelude* p = *proxy; 165 DeepPrelude* p = *proxy;
166 166
167 // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded 167 // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded
@@ -203,8 +203,6 @@ static int deep_userdata_gc( lua_State* L)
203 */ 203 */
204char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_) 204char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_)
205{ 205{
206 DeepPrelude** proxy;
207
208 // Check if a proxy already exists 206 // Check if a proxy already exists
209 push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC 207 push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC
210 lua_pushlightuserdata( L, prelude); // DPC deep 208 lua_pushlightuserdata( L, prelude); // DPC deep
@@ -223,7 +221,7 @@ char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, Lookup
223 STACK_CHECK_START_REL(L, 0); 221 STACK_CHECK_START_REL(L, 0);
224 222
225 // a new full userdata, fitted with the specified number of uservalue slots (always 1 for Lua < 5.4) 223 // a new full userdata, fitted with the specified number of uservalue slots (always 1 for Lua < 5.4)
226 proxy = (DeepPrelude**) lua_newuserdatauv( L, sizeof(DeepPrelude*), nuv_); // DPC proxy 224 DeepPrelude** proxy = (DeepPrelude**) lua_newuserdatauv(L, sizeof(DeepPrelude*), nuv_); // DPC proxy
227 ASSERT_L( proxy); 225 ASSERT_L( proxy);
228 *proxy = prelude; 226 *proxy = prelude;
229 prelude->m_refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data 227 prelude->m_refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data
@@ -333,9 +331,9 @@ char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, Lookup
333 } 331 }
334 } 332 }
335 } 333 }
336 STACK_CHECK( L, 2); // DPC proxy metatable 334 STACK_CHECK(L, 2); // DPC proxy metatable
337 ASSERT_L( lua_isuserdata( L, -2)); 335 ASSERT_L(lua_type(L, -2) == LUA_TUSERDATA);
338 ASSERT_L( lua_istable( L, -1)); 336 ASSERT_L(lua_istable( L, -1));
339 lua_setmetatable( L, -2); // DPC proxy 337 lua_setmetatable( L, -2); // DPC proxy
340 338
341 // If we're here, we obviously had to create a new proxy, so cache it. 339 // If we're here, we obviously had to create a new proxy, so cache it.
@@ -343,8 +341,8 @@ char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, Lookup
343 lua_pushvalue( L, -2); // DPC proxy deep proxy 341 lua_pushvalue( L, -2); // DPC proxy deep proxy
344 lua_rawset( L, -4); // DPC proxy 342 lua_rawset( L, -4); // DPC proxy
345 lua_remove( L, -2); // proxy 343 lua_remove( L, -2); // proxy
346 ASSERT_L( lua_isuserdata( L, -1)); 344 ASSERT_L(lua_type(L, -1) == LUA_TUSERDATA);
347 STACK_CHECK( L, 0); 345 STACK_CHECK(L, 0);
348 return nullptr; 346 return nullptr;
349} 347}
350 348
@@ -370,7 +368,7 @@ char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, Lookup
370* 368*
371* Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' 369* Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()'
372*/ 370*/
373int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_) 371int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc, int nuv_)
374{ 372{
375 STACK_GROW( L, 1); 373 STACK_GROW( L, 1);
376 STACK_CHECK_START_REL(L, 0); 374 STACK_CHECK_START_REL(L, 0);
@@ -416,7 +414,7 @@ int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_)
416* Reference count is not changed, and access to the deep userdata is not 414* Reference count is not changed, and access to the deep userdata is not
417* serialized. It is the module's responsibility to prevent conflicting usage. 415* serialized. It is the module's responsibility to prevent conflicting usage.
418*/ 416*/
419void* luaG_todeep( lua_State* L, luaG_IdFunction* idfunc, int index) 417DeepPrelude* luaG_todeep(lua_State* L, luaG_IdFunction idfunc, int index)
420{ 418{
421 STACK_CHECK_START_REL(L, 0); 419 STACK_CHECK_START_REL(L, 0);
422 // ensure it is actually a deep userdata 420 // ensure it is actually a deep userdata
@@ -426,7 +424,7 @@ void* luaG_todeep( lua_State* L, luaG_IdFunction* idfunc, int index)
426 } 424 }
427 STACK_CHECK(L, 0); 425 STACK_CHECK(L, 0);
428 426
429 DeepPrelude** const proxy{ lua_touserdata<DeepPrelude*>(L, index) }; 427 DeepPrelude** const proxy{ lua_tofulluserdata<DeepPrelude*>(L, index) };
430 428
431 return *proxy; 429 return *proxy;
432} 430}
@@ -441,10 +439,7 @@ void* luaG_todeep( lua_State* L, luaG_IdFunction* idfunc, int index)
441 */ 439 */
442bool copydeep(Universe* U, lua_State* L2, int L2_cache_i, lua_State* L, int i, LookupMode mode_, char const* upName_) 440bool copydeep(Universe* U, lua_State* L2, int L2_cache_i, lua_State* L, int i, LookupMode mode_, char const* upName_)
443{ 441{
444 char const* errmsg; 442 luaG_IdFunction const idfunc { get_idfunc(L, i, mode_) };
445 luaG_IdFunction* idfunc = get_idfunc( L, i, mode_);
446 int nuv = 0;
447
448 if (idfunc == nullptr) 443 if (idfunc == nullptr)
449 { 444 {
450 return false; // not a deep userdata 445 return false; // not a deep userdata
@@ -454,7 +449,8 @@ bool copydeep(Universe* U, lua_State* L2, int L2_cache_i, lua_State* L, int i, L
454 STACK_CHECK_START_REL(L2, 0); 449 STACK_CHECK_START_REL(L2, 0);
455 450
456 // extract all uservalues of the source 451 // extract all uservalues of the source
457 while( lua_getiuservalue( L, i, nuv + 1) != LUA_TNONE) // ... u [uv]* nil 452 int nuv = 0;
453 while (lua_getiuservalue(L, i, nuv + 1) != LUA_TNONE) // ... u [uv]* nil
458 { 454 {
459 ++ nuv; 455 ++ nuv;
460 } 456 }
@@ -462,7 +458,7 @@ bool copydeep(Universe* U, lua_State* L2, int L2_cache_i, lua_State* L, int i, L
462 lua_pop( L, 1); // ... u [uv]* 458 lua_pop( L, 1); // ... u [uv]*
463 STACK_CHECK( L, nuv); 459 STACK_CHECK( L, nuv);
464 460
465 errmsg = push_deep_proxy(L2, *lua_touserdata<DeepPrelude*>(L, i), nuv, mode_); // u 461 char const* errmsg{ push_deep_proxy(L2, *lua_tofulluserdata<DeepPrelude*>(L, i), nuv, mode_) }; // u
466 462
467 // transfer all uservalues of the source in the destination 463 // transfer all uservalues of the source in the destination
468 { 464 {
diff --git a/src/deep.h b/src/deep.h
index 878fa63..2983427 100644
--- a/src/deep.h
+++ b/src/deep.h
@@ -36,19 +36,20 @@ enum DeepOp
36 eDO_module, 36 eDO_module,
37}; 37};
38 38
39using luaG_IdFunction = void*( lua_State* L, DeepOp op_); 39using luaG_IdFunction = void*(*)( lua_State* L, DeepOp op_);
40 40
41// ################################################################################################ 41// ################################################################################################
42 42
43// xxh64 of string "DEEP_VERSION_3" generated at https://www.pelock.com/products/hash-calculator 43// xxh64 of string "DEEP_VERSION_3" generated at https://www.pelock.com/products/hash-calculator
44static constexpr UniqueKey DEEP_VERSION{ 0xB2CC0FD9C0AE9674ull }; 44static constexpr UniqueKey DEEP_VERSION{ 0xB2CC0FD9C0AE9674ull };
45 45
46// should be used as header for full userdata 46// should be used as header for deep userdata
47// a deep userdata is a full userdata that stores a single pointer to the actual DeepPrelude-derived object
47struct DeepPrelude 48struct DeepPrelude
48{ 49{
49 UniqueKey const magic{ DEEP_VERSION }; 50 UniqueKey const magic{ DEEP_VERSION };
50 // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc 51 // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc
51 luaG_IdFunction* idfunc { nullptr }; 52 luaG_IdFunction idfunc { nullptr };
52 // data is destroyed when refcount is 0 53 // data is destroyed when refcount is 0
53 std::atomic<int> m_refcount{ 0 }; 54 std::atomic<int> m_refcount{ 0 };
54}; 55};
@@ -56,5 +57,5 @@ struct DeepPrelude
56char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_); 57char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_);
57void free_deep_prelude( lua_State* L, DeepPrelude* prelude_); 58void free_deep_prelude( lua_State* L, DeepPrelude* prelude_);
58 59
59LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_); 60LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc, int nuv_);
60LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction* idfunc, int index); 61LANES_API DeepPrelude* luaG_todeep(lua_State* L, luaG_IdFunction idfunc, int index);
diff --git a/src/keeper.cpp b/src/keeper.cpp
index 35b5ea8..e0a9fdc 100644
--- a/src/keeper.cpp
+++ b/src/keeper.cpp
@@ -64,6 +64,11 @@ class keeper_fifo
64 // always embedded somewhere else or "in-place constructed" as a full userdata 64 // always embedded somewhere else or "in-place constructed" as a full userdata
65 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception 65 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
66 static void operator delete(void* p_, lua_State* L){ ASSERT_L(!"should never be called") }; 66 static void operator delete(void* p_, lua_State* L){ ASSERT_L(!"should never be called") };
67
68 static keeper_fifo* getPtr(lua_State* L, int idx_)
69 {
70 return lua_tofulluserdata<keeper_fifo>(L, idx_);
71 }
67}; 72};
68 73
69static constexpr int CONTENTS_TABLE{ 1 }; 74static constexpr int CONTENTS_TABLE{ 1 };
@@ -73,7 +78,7 @@ static constexpr int CONTENTS_TABLE{ 1 };
73// replaces the fifo ud by its uservalue on the stack 78// replaces the fifo ud by its uservalue on the stack
74static keeper_fifo* prepare_fifo_access(lua_State* L, int idx_) 79static keeper_fifo* prepare_fifo_access(lua_State* L, int idx_)
75{ 80{
76 keeper_fifo* const fifo{ lua_touserdata<keeper_fifo>(L, idx_) }; 81 keeper_fifo* const fifo{ keeper_fifo::getPtr(L, idx_) };
77 if (fifo != nullptr) 82 if (fifo != nullptr)
78 { 83 {
79 idx_ = lua_absindex(L, idx_); 84 idx_ = lua_absindex(L, idx_);
@@ -284,8 +289,8 @@ int keepercall_send(lua_State* L)
284 lua_rawset(L, -4); // ud key ... fifos fifo 289 lua_rawset(L, -4); // ud key ... fifos fifo
285 } 290 }
286 lua_remove(L, -2); // ud key ... fifo 291 lua_remove(L, -2); // ud key ... fifo
287 keeper_fifo* fifo{ lua_touserdata<keeper_fifo>(L, -1) }; 292 keeper_fifo* fifo{ keeper_fifo::getPtr(L, -1) };
288 if( fifo->limit >= 0 && fifo->count + n > fifo->limit) 293 if (fifo->limit >= 0 && fifo->count + n > fifo->limit)
289 { 294 {
290 lua_settop(L, 0); // 295 lua_settop(L, 0); //
291 lua_pushboolean(L, 0); // false 296 lua_pushboolean(L, 0); // false
@@ -382,12 +387,12 @@ int keepercall_limit(lua_State* L)
382 lua_pop(L, 1); // fifos key 387 lua_pop(L, 1); // fifos key
383 lua_pushvalue(L, -1); // fifos key key 388 lua_pushvalue(L, -1); // fifos key key
384 lua_rawget(L, -3); // fifos key fifo|nil 389 lua_rawget(L, -3); // fifos key fifo|nil
385 keeper_fifo* fifo{ lua_touserdata<keeper_fifo>(L, -1) }; 390 keeper_fifo* fifo{ keeper_fifo::getPtr(L, -1) };
386 if (fifo == nullptr) 391 if (fifo == nullptr)
387 { // fifos key nil 392 { // fifos key nil
388 lua_pop(L, 1); // fifos key 393 lua_pop(L, 1); // fifos key
389 fifo_new(L); // fifos key fifo 394 fifo_new(L); // fifos key fifo
390 fifo = lua_touserdata<keeper_fifo>(L, -1); 395 fifo = keeper_fifo::getPtr(L, -1);
391 lua_rawset(L, -3); // fifos 396 lua_rawset(L, -3); // fifos
392 } 397 }
393 // remove any clutter on the stack 398 // remove any clutter on the stack
@@ -426,7 +431,7 @@ int keepercall_set(lua_State* L)
426 lua_pushvalue(L, -1); // fifos key key 431 lua_pushvalue(L, -1); // fifos key key
427 lua_rawget(L, 1); // fifos key fifo|nil 432 lua_rawget(L, 1); // fifos key fifo|nil
428 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! 433 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
429 keeper_fifo* const fifo{ lua_touserdata<keeper_fifo>(L, -1) }; 434 keeper_fifo* const fifo{ keeper_fifo::getPtr(L, -1) };
430 if (fifo != nullptr) // might be nullptr if we set a nonexistent key to nil 435 if (fifo != nullptr) // might be nullptr if we set a nonexistent key to nil
431 { // fifos key fifo 436 { // fifos key fifo
432 if (fifo->limit < 0) // fifo limit value is the default (unlimited): we can totally remove it 437 if (fifo->limit < 0) // fifo limit value is the default (unlimited): we can totally remove it
@@ -452,7 +457,7 @@ int keepercall_set(lua_State* L)
452 int const count{ lua_gettop(L) - 2 }; // number of items we want to store 457 int const count{ lua_gettop(L) - 2 }; // number of items we want to store
453 lua_pushvalue(L, 2); // fifos key [val [, ...]] key 458 lua_pushvalue(L, 2); // fifos key [val [, ...]] key
454 lua_rawget(L, 1); // fifos key [val [, ...]] fifo|nil 459 lua_rawget(L, 1); // fifos key [val [, ...]] fifo|nil
455 keeper_fifo* fifo{ lua_touserdata<keeper_fifo>(L, -1) }; 460 keeper_fifo* fifo{ keeper_fifo::getPtr(L, -1) };
456 if( fifo == nullptr) // can be nullptr if we store a value at a new key 461 if( fifo == nullptr) // can be nullptr if we store a value at a new key
457 { // fifos key [val [, ...]] nil 462 { // fifos key [val [, ...]] nil
458 // no need to wake writers in that case, because a writer can't wait on an inexistent key 463 // no need to wake writers in that case, because a writer can't wait on an inexistent key
diff --git a/src/lanes.cpp b/src/lanes.cpp
index 6b3542b..df509ee 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -442,7 +442,7 @@ static bool selfdestruct_remove( Lane* s)
442*/ 442*/
443static int selfdestruct_gc( lua_State* L) 443static int selfdestruct_gc( lua_State* L)
444{ 444{
445 Universe* const U{ lua_touserdata<Universe>(L, 1) }; 445 Universe* const U{ lua_tofulluserdata<Universe>(L, 1) };
446 446
447 while( U->selfdestruct_first != SELFDESTRUCT_END) // true at most once! 447 while( U->selfdestruct_first != SELFDESTRUCT_END) // true at most once!
448 { 448 {
@@ -574,7 +574,7 @@ static int selfdestruct_gc( lua_State* L)
574 { 574 {
575 int const prev_ref_count{ U->timer_deep->m_refcount.fetch_sub(1, std::memory_order_relaxed) }; 575 int const prev_ref_count{ U->timer_deep->m_refcount.fetch_sub(1, std::memory_order_relaxed) };
576 ASSERT_L(prev_ref_count == 1); // this should be the last reference 576 ASSERT_L(prev_ref_count == 1); // this should be the last reference
577 free_deep_prelude( L, (DeepPrelude*) U->timer_deep); 577 free_deep_prelude(L, U->timer_deep);
578 U->timer_deep = nullptr; 578 U->timer_deep = nullptr;
579 } 579 }
580 580
@@ -781,7 +781,7 @@ LUAG_FUNC( set_debug_threadname)
781 // fnv164 of string "debug_threadname" generated at https://www.pelock.com/products/hash-calculator 781 // fnv164 of string "debug_threadname" generated at https://www.pelock.com/products/hash-calculator
782 constexpr UniqueKey hidden_regkey{ 0x79C0669AAAE04440ull }; 782 constexpr UniqueKey hidden_regkey{ 0x79C0669AAAE04440ull };
783 // C s_lane structure is a light userdata upvalue 783 // C s_lane structure is a light userdata upvalue
784 Lane* const s{ lua_touserdata<Lane>(L, lua_upvalueindex(1)) }; 784 Lane* const s{ lua_tolightuserdata<Lane>(L, lua_upvalueindex(1)) };
785 luaL_checktype( L, -1, LUA_TSTRING); // "name" 785 luaL_checktype( L, -1, LUA_TSTRING); // "name"
786 lua_settop( L, 1); 786 lua_settop( L, 1);
787 STACK_CHECK_START_ABS( L, 1); 787 STACK_CHECK_START_ABS( L, 1);
@@ -1887,7 +1887,7 @@ LUAG_FUNC( configure)
1887 STACK_CHECK( L, 2); 1887 STACK_CHECK( L, 2);
1888 1888
1889 // Proxy userdata contents is only a 'DeepPrelude*' pointer 1889 // Proxy userdata contents is only a 'DeepPrelude*' pointer
1890 U->timer_deep = *lua_touserdata<DeepPrelude*>(L, -1); 1890 U->timer_deep = *lua_tofulluserdata<DeepPrelude*>(L, -1);
1891 // increment refcount so that this linda remains alive as long as the universe exists. 1891 // increment refcount so that this linda remains alive as long as the universe exists.
1892 U->timer_deep->m_refcount.fetch_add(1, std::memory_order_relaxed); 1892 U->timer_deep->m_refcount.fetch_add(1, std::memory_order_relaxed);
1893 lua_pop( L, 1); // settings 1893 lua_pop( L, 1); // settings
@@ -1916,7 +1916,7 @@ LUAG_FUNC( configure)
1916 1916
1917 { 1917 {
1918 char const* errmsg; 1918 char const* errmsg;
1919 errmsg = push_deep_proxy(L, (DeepPrelude*) U->timer_deep, 0, eLM_LaneBody); // settings M timer_deep 1919 errmsg = push_deep_proxy(L, U->timer_deep, 0, eLM_LaneBody); // settings M timer_deep
1920 if( errmsg != nullptr) 1920 if( errmsg != nullptr)
1921 { 1921 {
1922 return luaL_error( L, errmsg); 1922 return luaL_error( L, errmsg);
diff --git a/src/lanes_private.h b/src/lanes_private.h
index 839a51f..5d6d25c 100644
--- a/src/lanes_private.h
+++ b/src/lanes_private.h
@@ -83,7 +83,7 @@ static inline Lane* get_lane_from_registry( lua_State* L)
83 STACK_GROW( L, 1); 83 STACK_GROW( L, 1);
84 STACK_CHECK_START_REL(L, 0); 84 STACK_CHECK_START_REL(L, 0);
85 CANCEL_TEST_KEY.query_registry(L); 85 CANCEL_TEST_KEY.query_registry(L);
86 Lane* const s{ lua_touserdata<Lane>(L, -1) }; // lightuserdata (true 's_lane' pointer) / nil 86 Lane* const s{ lua_tolightuserdata<Lane>(L, -1) }; // lightuserdata (true 's_lane' pointer) / nil
87 lua_pop( L, 1); 87 lua_pop( L, 1);
88 STACK_CHECK( L, 0); 88 STACK_CHECK( L, 0);
89 return s; 89 return s;
diff --git a/src/linda.cpp b/src/linda.cpp
index 7e346d8..b28a126 100644
--- a/src/linda.cpp
+++ b/src/linda.cpp
@@ -808,7 +808,7 @@ static void* linda_id( lua_State* L, DeepOp op_)
808 808
809 case eDO_delete: 809 case eDO_delete:
810 { 810 {
811 struct s_Linda* const linda{ lua_touserdata<struct s_Linda>(L, 1) }; 811 struct s_Linda* const linda{ lua_tolightuserdata<struct s_Linda>(L, 1) };
812 ASSERT_L( linda); 812 ASSERT_L( linda);
813 813
814 // Clean associated structures in the keeper state. 814 // Clean associated structures in the keeper state.
diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h
index 370cbed..23fa0e9 100644
--- a/src/macros_and_utils.h
+++ b/src/macros_and_utils.h
@@ -11,6 +11,7 @@ extern "C" {
11#endif // __cplusplus 11#endif // __cplusplus
12 12
13#include <cassert> 13#include <cassert>
14#include <type_traits>
14 15
15#define USE_DEBUG_SPEW() 0 16#define USE_DEBUG_SPEW() 0
16#if USE_DEBUG_SPEW() 17#if USE_DEBUG_SPEW()
@@ -125,9 +126,24 @@ inline void STACK_GROW(lua_State* L, int n_)
125 126
126#define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L) 127#define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L)
127 128
128// a small helper to extract a userdata pointer from the stack 129// a small helper to extract a full userdata pointer from the stack in a safe way
129template<typename T> 130template<typename T>
130T* lua_touserdata(lua_State* L, int index_) 131T* lua_tofulluserdata(lua_State* L, int index_)
131{ 132{
133 ASSERT_L(lua_isnil(L, index_) || lua_type(L, index_) == LUA_TUSERDATA);
132 return static_cast<T*>(lua_touserdata(L, index_)); 134 return static_cast<T*>(lua_touserdata(L, index_));
133} 135}
136
137template<typename T>
138auto lua_tolightuserdata(lua_State* L, int index_)
139{
140 ASSERT_L(lua_isnil(L, index_) || lua_islightuserdata(L, index_));
141 if constexpr (std::is_pointer_v<T>)
142 {
143 return static_cast<T>(lua_touserdata(L, index_));
144 }
145 else
146 {
147 return static_cast<T*>(lua_touserdata(L, index_));
148 }
149}
diff --git a/src/state.cpp b/src/state.cpp
index b46a145..817d5b4 100644
--- a/src/state.cpp
+++ b/src/state.cpp
@@ -259,7 +259,7 @@ lua_State* create_state( Universe* U, lua_State* from_)
259 lua_pushcclosure( from_, U->provide_allocator, 0); 259 lua_pushcclosure( from_, U->provide_allocator, 0);
260 lua_call( from_, 0, 1); 260 lua_call( from_, 0, 1);
261 { 261 {
262 AllocatorDefinition* const def{ lua_touserdata<AllocatorDefinition>(from_, -1) }; 262 AllocatorDefinition* const def{ lua_tofulluserdata<AllocatorDefinition>(from_, -1) };
263 L = lua_newstate( def->m_allocF, def->m_allocUD); 263 L = lua_newstate( def->m_allocF, def->m_allocUD);
264 } 264 }
265 lua_pop( from_, 1); 265 lua_pop( from_, 1);
diff --git a/src/universe.cpp b/src/universe.cpp
index 095f000..3792da6 100644
--- a/src/universe.cpp
+++ b/src/universe.cpp
@@ -36,17 +36,22 @@ THE SOFTWARE.
36#include "macros_and_utils.h" 36#include "macros_and_utils.h"
37#include "uniquekey.h" 37#include "uniquekey.h"
38 38
39// crc64/we of string "UNIVERSE_REGKEY" generated at http://www.nitrxgen.net/hashgen/ 39// xxh64 of string "UNIVERSE_FULL_REGKEY" generated at http://www.nitrxgen.net/hashgen/
40static constexpr UniqueKey UNIVERSE_REGKEY{ 0x9f877b2cf078f17full }; 40static constexpr UniqueKey UNIVERSE_FULL_REGKEY{ 0x99CA130C09EDC074ull };
41// xxh64 of string "UNIVERSE_LIGHT_REGKEY" generated at http://www.nitrxgen.net/hashgen/
42static constexpr UniqueKey UNIVERSE_LIGHT_REGKEY{ 0x3663C07C742CEB81ull };
41 43
42// ################################################################################################ 44// ################################################################################################
43 45
46// only called from the master state
44Universe* universe_create(lua_State* L) 47Universe* universe_create(lua_State* L)
45{ 48{
46 Universe* const U = static_cast<Universe*>(lua_newuserdatauv(L, sizeof(Universe), 0)); // universe 49 ASSERT_L(universe_get(L) == nullptr);
50 Universe* const U = static_cast<Universe*>(lua_newuserdatauv(L, sizeof(Universe), 0)); // universe
47 U->Universe::Universe(); 51 U->Universe::Universe();
48 STACK_CHECK_START_REL(L, 1); 52 STACK_CHECK_START_REL(L, 1);
49 UNIVERSE_REGKEY.set_registry(L, [](lua_State* L) { lua_pushvalue(L, -2); }); // universe 53 UNIVERSE_FULL_REGKEY.set_registry(L, [](lua_State* L) { lua_pushvalue(L, -2); });
54 UNIVERSE_LIGHT_REGKEY.set_registry(L, [U](lua_State* L) { lua_pushlightuserdata( L, U); });
50 STACK_CHECK(L, 1); 55 STACK_CHECK(L, 1);
51 return U; 56 return U;
52} 57}
@@ -55,8 +60,9 @@ Universe* universe_create(lua_State* L)
55 60
56void universe_store(lua_State* L, Universe* U) 61void universe_store(lua_State* L, Universe* U)
57{ 62{
63 ASSERT_L(universe_get(L) == nullptr);
58 STACK_CHECK_START_REL(L, 0); 64 STACK_CHECK_START_REL(L, 0);
59 UNIVERSE_REGKEY.set_registry(L, [U](lua_State* L) { U ? lua_pushlightuserdata( L, U) : lua_pushnil( L); }); 65 UNIVERSE_LIGHT_REGKEY.set_registry(L, [U](lua_State* L) { U ? lua_pushlightuserdata( L, U) : lua_pushnil( L); });
60 STACK_CHECK( L, 0); 66 STACK_CHECK( L, 0);
61} 67}
62 68
@@ -66,8 +72,8 @@ Universe* universe_get(lua_State* L)
66{ 72{
67 STACK_GROW(L, 2); 73 STACK_GROW(L, 2);
68 STACK_CHECK_START_REL(L, 0); 74 STACK_CHECK_START_REL(L, 0);
69 UNIVERSE_REGKEY.query_registry(L); 75 UNIVERSE_LIGHT_REGKEY.query_registry(L);
70 Universe* const universe{ lua_touserdata<Universe>(L, -1) }; // nullptr if nil 76 Universe* const universe{ lua_tolightuserdata<Universe>(L, -1) }; // nullptr if nil
71 lua_pop(L, 1); 77 lua_pop(L, 1);
72 STACK_CHECK(L, 0); 78 STACK_CHECK(L, 0);
73 return universe; 79 return universe;