aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-10-24 11:30:18 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2024-10-24 11:30:18 +0200
commiteba98e4e1adcf3ce11e5934e2dce54f29aef1e0a (patch)
treed51d51eb2d48208df1cfdf6eb0bd40a928d6243c
parent8745a54f88f31cd51dc86c96039ebe0b3e98f5ea (diff)
downloadlanes-eba98e4e1adcf3ce11e5934e2dce54f29aef1e0a.tar.gz
lanes-eba98e4e1adcf3ce11e5934e2dce54f29aef1e0a.tar.bz2
lanes-eba98e4e1adcf3ce11e5934e2dce54f29aef1e0a.zip
Make Unique even stronger
-rw-r--r--deep_test/deep_test.cpp2
-rw-r--r--src/allocator.h6
-rw-r--r--src/compat.cpp2
-rw-r--r--src/compat.h6
-rw-r--r--src/intercopycontext.cpp10
-rw-r--r--src/intercopycontext.h2
-rw-r--r--src/keeper.cpp16
-rw-r--r--src/keeper.h2
-rw-r--r--src/lanes.cpp14
-rw-r--r--src/linda.cpp8
-rw-r--r--src/lindafactory.cpp2
-rw-r--r--src/stackindex.hpp4
-rw-r--r--src/unique.hpp9
-rw-r--r--src/universe.h2
14 files changed, 49 insertions, 36 deletions
diff --git a/deep_test/deep_test.cpp b/deep_test/deep_test.cpp
index a6c6296..974709f 100644
--- a/deep_test/deep_test.cpp
+++ b/deep_test/deep_test.cpp
@@ -229,7 +229,7 @@ static luaL_Reg const clonable_mt[] = {
229 229
230int luaD_new_clonable(lua_State* L) 230int luaD_new_clonable(lua_State* L)
231{ 231{
232 int const _nuv{ static_cast<int>(luaL_optinteger(L, 1, 1)) }; 232 UserValueCount const _nuv{ static_cast<int>(luaL_optinteger(L, 1, 1)) };
233 lua_newuserdatauv(L, sizeof(MyClonableUserdata), _nuv); 233 lua_newuserdatauv(L, sizeof(MyClonableUserdata), _nuv);
234 luaG_setmetatable(L, "clonable"); 234 luaG_setmetatable(L, "clonable");
235 return 1; 235 return 1;
diff --git a/src/allocator.h b/src/allocator.h
index 0505251..e0ff9d6 100644
--- a/src/allocator.h
+++ b/src/allocator.h
@@ -16,11 +16,11 @@ namespace lanes {
16 lua_Alloc allocF{ nullptr }; 16 lua_Alloc allocF{ nullptr };
17 void* allocUD{ nullptr }; 17 void* allocUD{ nullptr };
18 18
19 [[nodiscard]] static void* operator new(size_t size_) noexcept = delete; // can't create one outside of a Lua state 19 [[nodiscard]] static void* operator new(size_t const size_) noexcept = delete; // can't create one outside of a Lua state
20 [[nodiscard]] static void* operator new(size_t size_, lua_State* L_) noexcept { return lua_newuserdatauv(L_, size_, 0); } 20 [[nodiscard]] static void* operator new(size_t const size_, lua_State* const L_) noexcept { return lua_newuserdatauv(L_, size_, UserValueCount{ 0 }); }
21 // always embedded somewhere else or "in-place constructed" as a full userdata 21 // always embedded somewhere else or "in-place constructed" as a full userdata
22 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception 22 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
23 static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] lua_State* L_) {} 23 static void operator delete([[maybe_unused]] void* const p_, [[maybe_unused]] lua_State* const L_) {}
24 24
25 AllocatorDefinition(uintptr_t const version_, lua_Alloc const allocF_, void* const allocUD_) noexcept 25 AllocatorDefinition(uintptr_t const version_, lua_Alloc const allocF_, void* const allocUD_) noexcept
26 : version{ version_ } 26 : version{ version_ }
diff --git a/src/compat.cpp b/src/compat.cpp
index 1be910f..b661b28 100644
--- a/src/compat.cpp
+++ b/src/compat.cpp
@@ -83,7 +83,7 @@ void luaL_requiref(lua_State* L_, const char* modname_, lua_CFunction openf_, in
83// ################################################################################################# 83// #################################################################################################
84// ################################################################################################# 84// #################################################################################################
85 85
86void* lua_newuserdatauv(lua_State* const L_, size_t const sz_, [[maybe_unused]] int const nuvalue_) 86void* lua_newuserdatauv(lua_State* const L_, size_t const sz_, [[maybe_unused]] UserValueCount const nuvalue_)
87{ 87{
88 LUA_ASSERT(L_, nuvalue_ <= 1); 88 LUA_ASSERT(L_, nuvalue_ <= 1);
89 return lua_newuserdata(L_, sz_); 89 return lua_newuserdata(L_, sz_);
diff --git a/src/compat.h b/src/compat.h
index af014b1..0b6b12b 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -80,7 +80,7 @@ inline int luaL_optint(lua_State* L_, int n_, lua_Integer d_)
80 80
81#if LUA_VERSION_NUM < 504 81#if LUA_VERSION_NUM < 504
82 82
83void* lua_newuserdatauv(lua_State* L_, size_t sz_, int nuvalue_); 83void* lua_newuserdatauv(lua_State* L_, size_t sz_, UserValueCount nuvalue_);
84int lua_getiuservalue(lua_State* L_, StackIndex idx_, int n_); 84int lua_getiuservalue(lua_State* L_, StackIndex idx_, int n_);
85int lua_setiuservalue(lua_State* L_, StackIndex idx_, int n_); 85int lua_setiuservalue(lua_State* L_, StackIndex idx_, int n_);
86 86
@@ -138,7 +138,7 @@ inline LuaType luaG_type(lua_State* const L_, StackIndex const idx_)
138// use this in place of lua_absindex to save a function call 138// use this in place of lua_absindex to save a function call
139inline StackIndex luaG_absindex(lua_State* const L_, StackIndex const idx_) 139inline StackIndex luaG_absindex(lua_State* const L_, StackIndex const idx_)
140{ 140{
141 return StackIndex{ (idx_ >= 0 || idx_ <= kIdxRegistry) ? idx_ : lua_gettop(L_) + idx_ + 1 }; 141 return StackIndex{ (idx_ >= 0 || idx_ <= kIdxRegistry) ? idx_ : StackIndex{ lua_gettop(L_) + idx_ + 1 } };
142} 142}
143 143
144// ################################################################################################# 144// #################################################################################################
@@ -295,7 +295,7 @@ static inline void luaG_newlib(lua_State* const L_, luaL_Reg const (&funcs_)[N])
295// ################################################################################################# 295// #################################################################################################
296 296
297template <typename T> 297template <typename T>
298[[nodiscard]] T* luaG_newuserdatauv(lua_State* L_, int nuvalue_) 298[[nodiscard]] T* luaG_newuserdatauv(lua_State* L_, UserValueCount nuvalue_)
299{ 299{
300 return static_cast<T*>(lua_newuserdatauv(L_, sizeof(T), nuvalue_)); 300 return static_cast<T*>(lua_newuserdatauv(L_, sizeof(T), nuvalue_));
301} 301}
diff --git a/src/intercopycontext.cpp b/src/intercopycontext.cpp
index f54c152..5f3ce7d 100644
--- a/src/intercopycontext.cpp
+++ b/src/intercopycontext.cpp
@@ -738,7 +738,7 @@ LuaType InterCopyContext::processConversion() const
738 lua_getupvalue(L2, -1, 2); // L2: ... userdata_clone_sentinel u 738 lua_getupvalue(L2, -1, 2); // L2: ... userdata_clone_sentinel u
739 } 739 }
740 // assign uservalues 740 // assign uservalues
741 int _uvi{ _nuv }; 741 UserValueIndex _uvi{ _nuv.value() };
742 while (_uvi > 0) { 742 while (_uvi > 0) {
743 _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop) }; 743 _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop) };
744 if (_c.interCopyOne() != InterCopyResult::Success) { // L2: ... u uv 744 if (_c.interCopyOne() != InterCopyResult::Success) { // L2: ... u uv
@@ -796,7 +796,7 @@ LuaType InterCopyContext::processConversion() const
796 InterCopyContext _c{ U, L2, L1, L2_cache_i, {}, VT::NORMAL, mode, name }; 796 InterCopyContext _c{ U, L2, L1, L2_cache_i, {}, VT::NORMAL, mode, name };
797 StackIndex const _clone_i{ lua_gettop(L2) }; 797 StackIndex const _clone_i{ lua_gettop(L2) };
798 STACK_GROW(L2, _nuv); 798 STACK_GROW(L2, _nuv);
799 int _uvi{ _nuv }; 799 UserValueIndex _uvi{ _nuv.value() };
800 while (_uvi) { 800 while (_uvi) {
801 _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop) }; 801 _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop) };
802 if (_c.interCopyOne() != InterCopyResult::Success) { // L1: ... deep ... [uv]* L2: deep uv 802 if (_c.interCopyOne() != InterCopyResult::Success) { // L1: ... deep ... [uv]* L2: deep uv
@@ -880,7 +880,7 @@ LuaType InterCopyContext::processConversion() const
880 lua_setmetatable(L2, -2); // L2: ... mt u 880 lua_setmetatable(L2, -2); // L2: ... mt u
881 // transfer and assign uservalues 881 // transfer and assign uservalues
882 InterCopyContext _c{ *this }; 882 InterCopyContext _c{ *this };
883 int _uvi{ _nuv }; 883 UserValueIndex _uvi{ _nuv.value() };
884 while (_uvi > 0) { 884 while (_uvi > 0) {
885 _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop) }; 885 _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop) };
886 if (_c.interCopyOne() != InterCopyResult::Success) { // L2: ... mt u uv 886 if (_c.interCopyOne() != InterCopyResult::Success) { // L2: ... mt u uv
@@ -1276,7 +1276,7 @@ namespace {
1276 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U }); 1276 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U });
1277 1277
1278 StackIndex const _top_L1{ lua_gettop(L1) }; 1278 StackIndex const _top_L1{ lua_gettop(L1) };
1279 int const _available{ (L1_i != 0) ? (_top_L1 - L1_i + 1) : _top_L1 }; 1279 int const _available{ (L1_i != 0) ? (_top_L1 - L1_i + 1) : _top_L1.value() };
1280 if (n_ > _available) { 1280 if (n_ > _available) {
1281 // requesting to copy more than is available? 1281 // requesting to copy more than is available?
1282 DEBUGSPEW_CODE(DebugSpew(U) << "nothing to copy" << std::endl); 1282 DEBUGSPEW_CODE(DebugSpew(U) << "nothing to copy" << std::endl);
@@ -1298,7 +1298,7 @@ namespace {
1298 InterCopyResult _copyok{ InterCopyResult::Success }; 1298 InterCopyResult _copyok{ InterCopyResult::Success };
1299 STACK_CHECK_START_REL(L1, 0); 1299 STACK_CHECK_START_REL(L1, 0);
1300 // if L1_i is specified, start here, else take the _n items off the top of the stack 1300 // if L1_i is specified, start here, else take the _n items off the top of the stack
1301 for (StackIndex _i{ L1_i != 0 ? L1_i : (_top_L1 - n_ + 1) }, _j{ 1 }; _j <= n_; ++_i, ++_j) { 1301 for (StackIndex _i{ (L1_i != 0) ? L1_i.value() : (_top_L1 - n_ + 1) }, _j{ 1 }; _j <= n_; ++_i, ++_j) {
1302 char _tmpBuf[16]; 1302 char _tmpBuf[16];
1303 if (U->verboseErrors) { 1303 if (U->verboseErrors) {
1304 sprintf(_tmpBuf, "arg_%d", _j.operator int()); 1304 sprintf(_tmpBuf, "arg_%d", _j.operator int());
diff --git a/src/intercopycontext.h b/src/intercopycontext.h
index a9be267..3a5db36 100644
--- a/src/intercopycontext.h
+++ b/src/intercopycontext.h
@@ -41,7 +41,7 @@ class InterCopyContext
41 [[nodiscard]] std::string_view findLookupName() const; 41 [[nodiscard]] std::string_view findLookupName() const;
42 // when mode == LookupMode::FromKeeper, L1 is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error 42 // when mode == LookupMode::FromKeeper, L1 is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error
43 // whon mode != LookupMode::FromKeeper, L1 is not a keeper state, therefore L1 is the state where we want to raise the error 43 // whon mode != LookupMode::FromKeeper, L1 is not a keeper state, therefore L1 is the state where we want to raise the error
44 lua_State* getErrL() const { return (mode == LookupMode::FromKeeper) ? L2 : L1; } 44 lua_State* getErrL() const { return (mode == LookupMode::FromKeeper) ? L2.value() : L1.value(); }
45 [[nodiscard]] LuaType processConversion() const; 45 [[nodiscard]] LuaType processConversion() const;
46 46
47 // for use in copyCachedFunction 47 // for use in copyCachedFunction
diff --git a/src/keeper.cpp b/src/keeper.cpp
index bea91a7..7deb2b3 100644
--- a/src/keeper.cpp
+++ b/src/keeper.cpp
@@ -75,7 +75,7 @@ class KeyUD
75 LindaLimit limit{ -1 }; 75 LindaLimit limit{ -1 };
76 76
77 // a fifo full userdata has one uservalue, the table that holds the actual fifo contents 77 // a fifo full userdata has one uservalue, the table that holds the actual fifo contents
78 [[nodiscard]] static void* operator new([[maybe_unused]] size_t size_, KeeperState L_) noexcept { return luaG_newuserdatauv<KeyUD>(L_, 1); } 78 [[nodiscard]] static void* operator new([[maybe_unused]] size_t size_, KeeperState L_) noexcept { return luaG_newuserdatauv<KeyUD>(L_, UserValueCount{ 1 }); }
79 // always embedded somewhere else or "in-place constructed" as a full userdata 79 // always embedded somewhere else or "in-place constructed" as a full userdata
80 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception 80 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
81 static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] KeeperState L_) { LUA_ASSERT(L_, !"should never be called"); } 81 static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] KeeperState L_) { LUA_ASSERT(L_, !"should never be called"); }
@@ -275,7 +275,7 @@ bool KeyUD::reset(KeeperState const K_)
275 bool const _wasFull{ (limit > 0) && (count >= limit) }; 275 bool const _wasFull{ (limit > 0) && (count >= limit) };
276 // empty the KeyUD: replace uservalue with a virgin table, reset counters, but leave limit unchanged! 276 // empty the KeyUD: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
277 // if we have an actual limit, use it to preconfigure the table 277 // if we have an actual limit, use it to preconfigure the table
278 lua_createtable(K_, (limit <= 0) ? 0 : limit, 0); // K_: KeysDB key val... KeyUD {} 278 lua_createtable(K_, (limit <= 0) ? 0 : limit.value(), 0); // K_: KeysDB key val... KeyUD {}
279 lua_setiuservalue(K_, StackIndex{ -2 }, kContentsTableIndex); // K_: KeysDB key val... KeyUD 279 lua_setiuservalue(K_, StackIndex{ -2 }, kContentsTableIndex); // K_: KeysDB key val... KeyUD
280 first = 1; 280 first = 1;
281 count = 0; 281 count = 0;
@@ -646,7 +646,7 @@ KeeperCallResult keeper_call(KeeperState const K_, keeper_api_t const func_, lua
646 lua_pushlightuserdata(K_, linda_); // L: ... args... K_: func_ linda 646 lua_pushlightuserdata(K_, linda_); // L: ... args... K_: func_ linda
647 if ( 647 if (
648 (_args == 0) || 648 (_args == 0) ||
649 (InterCopyContext{ linda_->U, DestState{ K_ }, SourceState{ L_ }, {}, {}, {}, LookupMode::ToKeeper, {} }.interCopy(_args) == InterCopyResult::Success) 649 (InterCopyContext{ linda_->U, DestState{ K_.value() }, SourceState{ L_ }, {}, {}, {}, LookupMode::ToKeeper, {} }.interCopy(_args) == InterCopyResult::Success)
650 ) { // L: ... args... K_: func_ linda args... 650 ) { // L: ... args... K_: func_ linda args...
651 lua_call(K_, 1 + _args, LUA_MULTRET); // L: ... args... K_: result... 651 lua_call(K_, 1 + _args, LUA_MULTRET); // L: ... args... K_: result...
652 int const _retvals{ lua_gettop(K_) - _top_K }; 652 int const _retvals{ lua_gettop(K_) - _top_K };
@@ -656,7 +656,7 @@ KeeperCallResult keeper_call(KeeperState const K_, keeper_api_t const func_, lua
656 // when attempting to grab the mutex again (WINVER <= 0x400 does this, but locks just fine, I don't know about pthread) 656 // when attempting to grab the mutex again (WINVER <= 0x400 does this, but locks just fine, I don't know about pthread)
657 if ( 657 if (
658 (_retvals == 0) || 658 (_retvals == 0) ||
659 (InterCopyContext{ linda_->U, DestState{ L_ }, SourceState{ K_ }, {}, {}, {}, LookupMode::FromKeeper, {} }.interMove(_retvals) == InterCopyResult::Success) 659 (InterCopyContext{ linda_->U, DestState{ L_ }, SourceState{ K_.value() }, {}, {}, {}, LookupMode::FromKeeper, {} }.interMove(_retvals) == InterCopyResult::Success)
660 ) { // L: ... args... result... K_: result... 660 ) { // L: ... args... result... K_: result...
661 _result.emplace(_retvals); 661 _result.emplace(_retvals);
662 } 662 }
@@ -721,7 +721,7 @@ void Keeper::operator delete[](void* p_, Universe* U_)
721int Keeper::PushLindaStorage(Linda& linda_, DestState const L_) 721int Keeper::PushLindaStorage(Linda& linda_, DestState const L_)
722{ 722{
723 Keeper* const _keeper{ linda_.whichKeeper() }; 723 Keeper* const _keeper{ linda_.whichKeeper() };
724 KeeperState const _K{ _keeper ? _keeper->K : KeeperState{ nullptr } }; 724 KeeperState const _K{ _keeper ? _keeper->K : KeeperState{ static_cast<lua_State*>(nullptr) } };
725 if (_K == nullptr) { 725 if (_K == nullptr) {
726 return 0; 726 return 0;
727 } 727 }
@@ -740,7 +740,7 @@ int Keeper::PushLindaStorage(Linda& linda_, DestState const L_)
740 STACK_GROW(L_, 5); 740 STACK_GROW(L_, 5);
741 STACK_CHECK_START_REL(L_, 0); 741 STACK_CHECK_START_REL(L_, 0);
742 lua_newtable(L_); // _K: KeysDB L_: out 742 lua_newtable(L_); // _K: KeysDB L_: out
743 InterCopyContext _c{ linda_.U, L_, SourceState{ _K }, {}, {}, {}, LookupMode::FromKeeper, {} }; 743 InterCopyContext _c{ linda_.U, L_, SourceState{ _K.value() }, {}, {}, {}, LookupMode::FromKeeper, {} };
744 lua_pushnil(_K); // _K: KeysDB nil L_: out 744 lua_pushnil(_K); // _K: KeysDB nil L_: out
745 while (lua_next(_K, -2)) { // _K: KeysDB key KeyUD L_: out 745 while (lua_next(_K, -2)) { // _K: KeysDB key KeyUD L_: out
746 KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; 746 KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) };
@@ -810,7 +810,7 @@ void Keepers::close()
810 } 810 }
811 811
812 auto _closeOneKeeper = [](Keeper& keeper_) { 812 auto _closeOneKeeper = [](Keeper& keeper_) {
813 lua_State* const _K{ std::exchange(keeper_.K, KeeperState{ nullptr }) }; 813 lua_State* const _K{ std::exchange(keeper_.K, KeeperState{ static_cast<lua_State*>(nullptr) }) };
814 if (_K) { 814 if (_K) {
815 lua_close(_K); 815 lua_close(_K);
816 } 816 }
@@ -928,7 +928,7 @@ void Keepers::initialize(Universe& U_, lua_State* L_, size_t const nbKeepers_, i
928 // copy package.path and package.cpath from the source state 928 // copy package.path and package.cpath from the source state
929 if (luaG_getmodule(L, LUA_LOADLIBNAME) != LuaType::NIL) { // L_: settings package _K: 929 if (luaG_getmodule(L, LUA_LOADLIBNAME) != LuaType::NIL) { // L_: settings package _K:
930 // when copying with mode LookupMode::ToKeeper, error message is pushed at the top of the stack, not raised immediately 930 // when copying with mode LookupMode::ToKeeper, error message is pushed at the top of the stack, not raised immediately
931 InterCopyContext _c{ U, DestState{ _K }, SourceState{ L }, {}, SourceIndex{ luaG_absindex(L, kIdxTop) }, {}, LookupMode::ToKeeper, {} }; 931 InterCopyContext _c{ U, DestState{ _K.value() }, SourceState{ L }, {}, SourceIndex{ luaG_absindex(L, kIdxTop) }, {}, LookupMode::ToKeeper, {} };
932 if (_c.interCopyPackage() != InterCopyResult::Success) { // L_: settings ... error_msg _K: 932 if (_c.interCopyPackage() != InterCopyResult::Success) { // L_: settings ... error_msg _K:
933 // if something went wrong, the error message is at the top of the stack 933 // if something went wrong, the error message is at the top of the stack
934 lua_remove(L, -2); // L_: settings error_msg 934 lua_remove(L, -2); // L_: settings error_msg
diff --git a/src/keeper.h b/src/keeper.h
index 74bdbf2..7e3e1fa 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -16,7 +16,7 @@ DECLARE_UNIQUE_TYPE(KeeperIndex, int);
16struct Keeper 16struct Keeper
17{ 17{
18 std::mutex mutex; 18 std::mutex mutex;
19 KeeperState K{ nullptr }; 19 KeeperState K{ static_cast<lua_State*>(nullptr) };
20 20
21 [[nodiscard]] static void* operator new[](size_t size_, Universe* U_) noexcept; 21 [[nodiscard]] static void* operator new[](size_t size_, Universe* U_) noexcept;
22 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception 22 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
diff --git a/src/lanes.cpp b/src/lanes.cpp
index 572d8f9..e545ca0 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -329,7 +329,7 @@ LUAG_FUNC(lane_new)
329 DEBUGSPEW_CODE(DebugSpew(lane->U) << "lane_new: preparing lane userdata" << std::endl); 329 DEBUGSPEW_CODE(DebugSpew(lane->U) << "lane_new: preparing lane userdata" << std::endl);
330 STACK_CHECK_START_REL(L, 0); 330 STACK_CHECK_START_REL(L, 0);
331 // a Lane full userdata needs a single uservalue 331 // a Lane full userdata needs a single uservalue
332 Lane** const _ud{ luaG_newuserdatauv<Lane*>(L, 1) }; // L: ... lane 332 Lane** const _ud{ luaG_newuserdatauv<Lane*>(L, UserValueCount{ 1 }) }; // L: ... lane
333 *_ud = lane; // don't forget to store the pointer in the userdata! 333 *_ud = lane; // don't forget to store the pointer in the userdata!
334 334
335 // Set metatable for the userdata 335 // Set metatable for the userdata
@@ -342,7 +342,7 @@ LUAG_FUNC(lane_new)
342 lua_newtable(L); // L: ... lane {uv} 342 lua_newtable(L); // L: ... lane {uv}
343 343
344 // Store the gc_cb callback in the uservalue 344 // Store the gc_cb callback in the uservalue
345 StackIndex const _gc_cb_idx{ lua_isnoneornil(L, kGcCbIdx) ? 0 : kGcCbIdx }; 345 StackIndex const _gc_cb_idx{ lua_isnoneornil(L, kGcCbIdx) ? kIdxNone : kGcCbIdx };
346 if (_gc_cb_idx > 0) { 346 if (_gc_cb_idx > 0) {
347 kLaneGC.pushKey(L); // L: ... lane {uv} k 347 kLaneGC.pushKey(L); // L: ... lane {uv} k
348 lua_pushvalue(L, _gc_cb_idx); // L: ... lane {uv} k gc_cb 348 lua_pushvalue(L, _gc_cb_idx); // L: ... lane {uv} k gc_cb
@@ -354,7 +354,7 @@ LUAG_FUNC(lane_new)
354 354
355 lua_State* const _L2{ lane->L }; 355 lua_State* const _L2{ lane->L };
356 STACK_CHECK_START_REL(_L2, 0); 356 STACK_CHECK_START_REL(_L2, 0);
357 StackIndex const _name_idx{ lua_isnoneornil(L, kNameIdx) ? 0 : kNameIdx }; 357 StackIndex const _name_idx{ lua_isnoneornil(L, kNameIdx) ? kIdxNone : kNameIdx };
358 std::string_view const _debugName{ (_name_idx > 0) ? luaG_tostring(L, _name_idx) : std::string_view{} }; 358 std::string_view const _debugName{ (_name_idx > 0) ? luaG_tostring(L, _name_idx) : std::string_view{} };
359 if (!_debugName.empty()) 359 if (!_debugName.empty())
360 { 360 {
@@ -393,7 +393,7 @@ LUAG_FUNC(lane_new)
393 // On some platforms, -3 is equivalent to -2 and +3 to +2 393 // On some platforms, -3 is equivalent to -2 and +3 to +2
394 int const _priority{ 394 int const _priority{
395 std::invoke([L = L_]() { 395 std::invoke([L = L_]() {
396 int const _prio_idx{ lua_isnoneornil(L, kPrioIdx) ? 0 : kPrioIdx }; 396 StackIndex const _prio_idx{ lua_isnoneornil(L, kPrioIdx) ? kIdxNone : kPrioIdx };
397 if (_prio_idx == 0) { 397 if (_prio_idx == 0) {
398 return kThreadPrioDefault; 398 return kThreadPrioDefault;
399 } 399 }
@@ -412,7 +412,7 @@ LUAG_FUNC(lane_new)
412 STACK_CHECK_START_REL(L_, 0); 412 STACK_CHECK_START_REL(L_, 0);
413 413
414 // package 414 // package
415 StackIndex const _package_idx{ lua_isnoneornil(L_, kPackIdx) ? 0 : kPackIdx }; 415 StackIndex const _package_idx{ lua_isnoneornil(L_, kPackIdx) ? kIdxNone : kPackIdx };
416 if (_package_idx != 0) { 416 if (_package_idx != 0) {
417 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: update 'package'" << std::endl); 417 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: update 'package'" << std::endl);
418 // when copying with mode LookupMode::LaneBody, should raise an error in case of problem, not leave it one the stack 418 // when copying with mode LookupMode::LaneBody, should raise an error in case of problem, not leave it one the stack
@@ -424,7 +424,7 @@ LUAG_FUNC(lane_new)
424 STACK_CHECK(_L2, 0); 424 STACK_CHECK(_L2, 0);
425 425
426 // modules to require in the target lane *before* the function is transfered! 426 // modules to require in the target lane *before* the function is transfered!
427 StackIndex const _required_idx{ lua_isnoneornil(L_, kRequIdx) ? 0 : kRequIdx }; 427 StackIndex const _required_idx{ lua_isnoneornil(L_, kRequIdx) ? kIdxNone : kRequIdx };
428 if (_required_idx != 0) { 428 if (_required_idx != 0) {
429 int _nbRequired{ 1 }; 429 int _nbRequired{ 1 };
430 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: process 'required' list" << std::endl); 430 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: process 'required' list" << std::endl);
@@ -473,7 +473,7 @@ LUAG_FUNC(lane_new)
473 // Appending the specified globals to the global environment 473 // Appending the specified globals to the global environment
474 // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed... 474 // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed...
475 // 475 //
476 StackIndex const _globals_idx{ lua_isnoneornil(L_, kGlobIdx) ? 0 : kGlobIdx }; 476 StackIndex const _globals_idx{ lua_isnoneornil(L_, kGlobIdx) ? kIdxNone : kGlobIdx };
477 if (_globals_idx != 0) { 477 if (_globals_idx != 0) {
478 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: transfer globals" << std::endl); 478 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: transfer globals" << std::endl);
479 if (!lua_istable(L_, _globals_idx)) { 479 if (!lua_istable(L_, _globals_idx)) {
diff --git a/src/linda.cpp b/src/linda.cpp
index 6655ae4..15e7a2c 100644
--- a/src/linda.cpp
+++ b/src/linda.cpp
@@ -196,7 +196,7 @@ int Linda::ProtectedCall(lua_State* const L_, lua_CFunction const f_)
196 196
197 // acquire the keeper 197 // acquire the keeper
198 Keeper* const _keeper{ _linda->acquireKeeper() }; 198 Keeper* const _keeper{ _linda->acquireKeeper() };
199 KeeperState const _K{ _keeper ? _keeper->K : KeeperState{ nullptr } }; 199 KeeperState const _K{ _keeper ? _keeper->K : KeeperState{ static_cast<lua_State*>(nullptr) } };
200 if (_K == nullptr) 200 if (_K == nullptr)
201 return 0; 201 return 0;
202 202
@@ -469,7 +469,7 @@ LUAG_FUNC(linda_limit)
469 luaL_argcheck(L_, _nargs == 2 || _nargs == 3, 2, "wrong number of arguments"); 469 luaL_argcheck(L_, _nargs == 2 || _nargs == 3, 2, "wrong number of arguments");
470 // make sure we got a numeric limit, or "unlimited", (or nothing) 470 // make sure we got a numeric limit, or "unlimited", (or nothing)
471 bool const _unlimited{ luaG_tostring(L_, StackIndex{ 3 }) == "unlimited" }; 471 bool const _unlimited{ luaG_tostring(L_, StackIndex{ 3 }) == "unlimited" };
472 LindaLimit const _val{ _unlimited ? std::numeric_limits<LindaLimit::type>::max() : LindaLimit{ static_cast<LindaLimit::type>(luaL_optinteger(L_, 3, 0)) } }; 472 LindaLimit const _val{ _unlimited ? std::numeric_limits<LindaLimit::type>::max() : static_cast<LindaLimit::type>(luaL_optinteger(L_, 3, 0)) };
473 if (_val < 0) { 473 if (_val < 0) {
474 raise_luaL_argerror(L_, StackIndex{ 3 }, "limit must be >= 0"); 474 raise_luaL_argerror(L_, StackIndex{ 3 }, "limit must be >= 0");
475 } 475 }
@@ -575,7 +575,7 @@ LUAG_FUNC(linda_receive)
575 575
576 Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) }; 576 Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) };
577 Keeper* const _keeper{ _linda->whichKeeper() }; 577 Keeper* const _keeper{ _linda->whichKeeper() };
578 KeeperState const _K{ _keeper ? _keeper->K : KeeperState{ nullptr } }; 578 KeeperState const _K{ _keeper ? _keeper->K : KeeperState{ static_cast<lua_State*>(nullptr) } };
579 if (_K == nullptr) 579 if (_K == nullptr)
580 return 0; 580 return 0;
581 581
@@ -714,7 +714,7 @@ LUAG_FUNC(linda_send)
714 { 714 {
715 Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) }; 715 Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) };
716 Keeper* const _keeper{ _linda->whichKeeper() }; 716 Keeper* const _keeper{ _linda->whichKeeper() };
717 KeeperState const _K{ _keeper ? _keeper->K : KeeperState{ nullptr } }; 717 KeeperState const _K{ _keeper ? _keeper->K : KeeperState{ static_cast<lua_State*>(nullptr) } };
718 if (_K == nullptr) 718 if (_K == nullptr)
719 return 0; 719 return 0;
720 720
diff --git a/src/lindafactory.cpp b/src/lindafactory.cpp
index e5903fb..cb801dd 100644
--- a/src/lindafactory.cpp
+++ b/src/lindafactory.cpp
@@ -80,7 +80,7 @@ void LindaFactory::deleteDeepObjectInternal(lua_State* L_, DeepPrelude* o_) cons
80 Keeper* const _keeper{ _need_acquire_release ? _linda->acquireKeeper() : _myKeeper }; 80 Keeper* const _keeper{ _need_acquire_release ? _linda->acquireKeeper() : _myKeeper };
81 LUA_ASSERT(L_, _keeper == _myKeeper); // should always be the same 81 LUA_ASSERT(L_, _keeper == _myKeeper); // should always be the same
82 // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex... 82 // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex...
83 [[maybe_unused]] KeeperCallResult const result{ keeper_call(_keeper->K, KEEPER_API(destruct), L_, _linda, StackIndex{ 0 }) }; 83 [[maybe_unused]] KeeperCallResult const result{ keeper_call(_keeper->K, KEEPER_API(destruct), L_, _linda, kIdxNone) };
84 LUA_ASSERT(L_, result.has_value() && result.value() == 0); 84 LUA_ASSERT(L_, result.has_value() && result.value() == 0);
85 if (_need_acquire_release) { 85 if (_need_acquire_release) {
86 _linda->releaseKeeper(_keeper); 86 _linda->releaseKeeper(_keeper);
diff --git a/src/stackindex.hpp b/src/stackindex.hpp
index 1c2ce8c..c414ce2 100644
--- a/src/stackindex.hpp
+++ b/src/stackindex.hpp
@@ -5,6 +5,9 @@
5DECLARE_UNIQUE_TYPE(StackIndex, int); 5DECLARE_UNIQUE_TYPE(StackIndex, int);
6static_assert(std::is_trivial_v<StackIndex>); 6static_assert(std::is_trivial_v<StackIndex>);
7 7
8DECLARE_UNIQUE_TYPE(UserValueIndex, int);
9static_assert(std::is_trivial_v<UserValueIndex>);
10
8DECLARE_UNIQUE_TYPE(UserValueCount, int); 11DECLARE_UNIQUE_TYPE(UserValueCount, int);
9static_assert(std::is_trivial_v<UserValueCount>); 12static_assert(std::is_trivial_v<UserValueCount>);
10 13
@@ -14,4 +17,5 @@ static_assert(std::is_trivial_v<UserValueCount>);
14// ################################################################################################# 17// #################################################################################################
15 18
16static constexpr StackIndex kIdxRegistry{ LUA_REGISTRYINDEX }; 19static constexpr StackIndex kIdxRegistry{ LUA_REGISTRYINDEX };
20static constexpr StackIndex kIdxNone{ 0 };
17static constexpr StackIndex kIdxTop{ -1 }; 21static constexpr StackIndex kIdxTop{ -1 };
diff --git a/src/unique.hpp b/src/unique.hpp
index 98a9d48..27ea71e 100644
--- a/src/unique.hpp
+++ b/src/unique.hpp
@@ -10,6 +10,7 @@ class Unique
10 T val; // no default initialization so that std::is_trivial_v<Unique<T>> == true 10 T val; // no default initialization so that std::is_trivial_v<Unique<T>> == true
11 11
12 public: 12 public:
13 using self = Unique<T, TAG, specialization>;
13 using type = T; 14 using type = T;
14 15
15 ~Unique() = default; 16 ~Unique() = default;
@@ -25,12 +26,20 @@ class Unique
25 constexpr Unique& operator=(Unique const&) = default; 26 constexpr Unique& operator=(Unique const&) = default;
26 constexpr Unique& operator=(Unique&&) = default; 27 constexpr Unique& operator=(Unique&&) = default;
27 28
29 // Forbid construction with any other class, especially with types that convert naturally to UnderlyingType.
30 // For instance, this prevents construction with a float when UnderlyingType is an integer type.
31 // Conversion will have to be explicit and the developer will be aware of it.
32 // However we want to keep the same-type copy constructors (including with an inherited class), hence the enable_if stuff.
33 template <typename AnyOtherClass, std::enable_if_t<!std::is_base_of_v<self, std::decay_t<AnyOtherClass>>, bool> = true>
34 Unique(AnyOtherClass&&) = delete;
35
28 // can't implicitly affect from base type 36 // can't implicitly affect from base type
29 Unique& operator=(T const&) = delete; 37 Unique& operator=(T const&) = delete;
30 constexpr Unique& operator=(T&&) = delete; 38 constexpr Unique& operator=(T&&) = delete;
31 39
32 // cast 40 // cast
33 constexpr operator T() const noexcept { return val; } 41 constexpr operator T() const noexcept { return val; }
42 constexpr T value() const noexcept { return val; }
34 43
35 // pre-increment 44 // pre-increment
36 auto& operator++() noexcept 45 auto& operator++() noexcept
diff --git a/src/universe.h b/src/universe.h
index dc8940f..75e2198 100644
--- a/src/universe.h
+++ b/src/universe.h
@@ -119,7 +119,7 @@ class Universe
119 std::atomic<int> selfdestructingCount{ 0 }; 119 std::atomic<int> selfdestructingCount{ 0 };
120 120
121 public: 121 public:
122 [[nodiscard]] static void* operator new([[maybe_unused]] size_t size_, lua_State* L_) noexcept { return luaG_newuserdatauv<Universe>(L_, 0); }; 122 [[nodiscard]] static void* operator new([[maybe_unused]] size_t size_, lua_State* L_) noexcept { return luaG_newuserdatauv<Universe>(L_, UserValueCount{ 0 }); };
123 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception 123 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
124 static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] lua_State* L_) {} // nothing to do, as nothing is allocated independently 124 static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] lua_State* L_) {} // nothing to do, as nothing is allocated independently
125 125