diff options
| author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-04-15 09:44:45 +0200 |
|---|---|---|
| committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-04-15 09:44:45 +0200 |
| commit | 111790701a45e074de2e8e5d8d4831ac285e22b0 (patch) | |
| tree | 3f9233015e61f605e22e9fd0d4c8642a8e7000cd /src | |
| parent | 69d40c81d8343a1af7e0fe61fbf20a4cf5880c25 (diff) | |
| download | lanes-111790701a45e074de2e8e5d8d4831ac285e22b0.tar.gz lanes-111790701a45e074de2e8e5d8d4831ac285e22b0.tar.bz2 lanes-111790701a45e074de2e8e5d8d4831ac285e22b0.zip | |
C++ migration: keeper_call returns a std::optional
Diffstat (limited to 'src')
| -rw-r--r-- | src/cancel.h | 2 | ||||
| -rw-r--r-- | src/keeper.cpp | 28 | ||||
| -rw-r--r-- | src/keeper.h | 6 | ||||
| -rw-r--r-- | src/linda.cpp | 147 | ||||
| -rw-r--r-- | src/macros_and_utils.h | 44 | ||||
| -rw-r--r-- | src/uniquekey.h | 5 |
6 files changed, 141 insertions, 91 deletions
diff --git a/src/cancel.h b/src/cancel.h index 060edb3..10a9804 100644 --- a/src/cancel.h +++ b/src/cancel.h | |||
| @@ -47,7 +47,7 @@ enum class CancelOp | |||
| 47 | }; | 47 | }; |
| 48 | 48 | ||
| 49 | // crc64/we of string "CANCEL_ERROR" generated at http://www.nitrxgen.net/hashgen/ | 49 | // crc64/we of string "CANCEL_ERROR" generated at http://www.nitrxgen.net/hashgen/ |
| 50 | static constexpr UniqueKey CANCEL_ERROR{ 0xe97d41626cc97577ull }; // 'raise_cancel_error' sentinel | 50 | static constexpr UniqueKey CANCEL_ERROR{ 0xe97d41626cc97577ull, "lanes.cancel_error" }; // 'raise_cancel_error' sentinel |
| 51 | 51 | ||
| 52 | [[nodiscard]] CancelOp which_cancel_op(char const* op_string_); | 52 | [[nodiscard]] CancelOp which_cancel_op(char const* op_string_); |
| 53 | [[nodiscard]] CancelResult thread_cancel(Lane* lane_, CancelOp op_, int hook_count_, lua_Duration secs_, bool wake_lindas_); | 53 | [[nodiscard]] CancelResult thread_cancel(Lane* lane_, CancelOp op_, int hook_count_, lua_Duration secs_, bool wake_lindas_); |
diff --git a/src/keeper.cpp b/src/keeper.cpp index f56c50c..61321e1 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp | |||
| @@ -418,7 +418,7 @@ int keepercall_limit(lua_State* L) | |||
| 418 | // ################################################################################################## | 418 | // ################################################################################################## |
| 419 | 419 | ||
| 420 | // in: linda_ud key [[val] ...] | 420 | // in: linda_ud key [[val] ...] |
| 421 | //out: true or nil | 421 | //out: true if the linda was full but it's no longer the case, else nothing |
| 422 | int keepercall_set(lua_State* L) | 422 | int keepercall_set(lua_State* L) |
| 423 | { | 423 | { |
| 424 | bool should_wake_writers{ false }; | 424 | bool should_wake_writers{ false }; |
| @@ -826,35 +826,35 @@ void keeper_toggle_nil_sentinels(lua_State* L, int val_i_, LookupMode const mode | |||
| 826 | * 'linda': deep Linda pointer (used only as a unique table key, first parameter) | 826 | * 'linda': deep Linda pointer (used only as a unique table key, first parameter) |
| 827 | * 'starting_index': first of the rest of parameters (none if 0) | 827 | * 'starting_index': first of the rest of parameters (none if 0) |
| 828 | * | 828 | * |
| 829 | * Returns: number of return values (pushed to 'L') or -1 in case of error | 829 | * Returns: number of return values (pushed to 'L'), unset in case of error |
| 830 | */ | 830 | */ |
| 831 | int keeper_call(Universe* U, lua_State* K, keeper_api_t func_, lua_State* L, void* linda, int starting_index) | 831 | KeeperCallResult keeper_call(Universe* U, lua_State* K, keeper_api_t func_, lua_State* L, void* linda, int starting_index) |
| 832 | { | 832 | { |
| 833 | KeeperCallResult result; | ||
| 833 | int const args{ starting_index ? (lua_gettop(L) - starting_index + 1) : 0 }; | 834 | int const args{ starting_index ? (lua_gettop(L) - starting_index + 1) : 0 }; |
| 834 | int const Ktos{ lua_gettop(K) }; | 835 | int const top_K{ lua_gettop(K) }; |
| 835 | int retvals = -1; | ||
| 836 | 836 | ||
| 837 | STACK_GROW(K, 2); | 837 | STACK_GROW(K, 2); |
| 838 | 838 | ||
| 839 | PUSH_KEEPER_FUNC(K, func_); | 839 | PUSH_KEEPER_FUNC(K, func_); // func_ |
| 840 | 840 | ||
| 841 | lua_pushlightuserdata(K, linda); | 841 | lua_pushlightuserdata(K, linda); // func_ linda |
| 842 | 842 | ||
| 843 | if ((args == 0) || luaG_inter_copy(U, Source{ L }, Dest{ K }, args, LookupMode::ToKeeper) == InterCopyResult::Success) // L->K | 843 | if ((args == 0) || luaG_inter_copy(U, Source{ L }, Dest{ K }, args, LookupMode::ToKeeper) == InterCopyResult::Success) // func_ linda args... |
| 844 | { | 844 | { |
| 845 | lua_call(K, 1 + args, LUA_MULTRET); | 845 | lua_call(K, 1 + args, LUA_MULTRET); // result... |
| 846 | retvals = lua_gettop(K) - Ktos; | 846 | int const retvals{ lua_gettop(K) - top_K }; |
| 847 | // note that this can raise a luaL_error while the keeper state (and its mutex) is acquired | 847 | // note that this can raise a luaL_error while the keeper state (and its mutex) is acquired |
| 848 | // this may interrupt a lane, causing the destruction of the underlying OS thread | 848 | // this may interrupt a lane, causing the destruction of the underlying OS thread |
| 849 | // after this, another lane making use of this keeper can get an error code from the mutex-locking function | 849 | // after this, another lane making use of this keeper can get an error code from the mutex-locking function |
| 850 | // when attempting to grab the mutex again (WINVER <= 0x400 does this, but locks just fine, I don't know about pthread) | 850 | // when attempting to grab the mutex again (WINVER <= 0x400 does this, but locks just fine, I don't know about pthread) |
| 851 | if ((retvals > 0) && luaG_inter_move(U, Source{ K }, Dest{ L }, retvals, LookupMode::FromKeeper) != InterCopyResult::Success) // K->L | 851 | if ((retvals == 0) || (luaG_inter_move(U, Source{ K }, Dest{ L }, retvals, LookupMode::FromKeeper) == InterCopyResult::Success)) // K->L |
| 852 | { | 852 | { |
| 853 | retvals = -1; | 853 | result.emplace(retvals); |
| 854 | } | 854 | } |
| 855 | } | 855 | } |
| 856 | // whatever happens, restore the stack to where it was at the origin | 856 | // whatever happens, restore the stack to where it was at the origin |
| 857 | lua_settop(K, Ktos); | 857 | lua_settop(K, top_K); |
| 858 | 858 | ||
| 859 | // don't do this for this particular function, as it is only called during Linda destruction, and we don't want to raise an error, ever | 859 | // don't do this for this particular function, as it is only called during Linda destruction, and we don't want to raise an error, ever |
| 860 | if (func_ != KEEPER_API(clear)) [[unlikely]] | 860 | if (func_ != KEEPER_API(clear)) [[unlikely]] |
| @@ -880,5 +880,5 @@ int keeper_call(Universe* U, lua_State* K, keeper_api_t func_, lua_State* L, voi | |||
| 880 | } | 880 | } |
| 881 | } | 881 | } |
| 882 | 882 | ||
| 883 | return retvals; | 883 | return result; |
| 884 | } | 884 | } |
diff --git a/src/keeper.h b/src/keeper.h index 627c7ea..7ec8b15 100644 --- a/src/keeper.h +++ b/src/keeper.h | |||
| @@ -11,6 +11,7 @@ extern "C" { | |||
| 11 | #include "threading.h" | 11 | #include "threading.h" |
| 12 | #include "uniquekey.h" | 12 | #include "uniquekey.h" |
| 13 | 13 | ||
| 14 | #include <optional> | ||
| 14 | #include <mutex> | 15 | #include <mutex> |
| 15 | 16 | ||
| 16 | // forwards | 17 | // forwards |
| @@ -33,7 +34,7 @@ struct Keepers | |||
| 33 | 34 | ||
| 34 | static constexpr uintptr_t KEEPER_MAGIC_SHIFT{ 3 }; | 35 | static constexpr uintptr_t KEEPER_MAGIC_SHIFT{ 3 }; |
| 35 | // crc64/we of string "NIL_SENTINEL" generated at http://www.nitrxgen.net/hashgen/ | 36 | // crc64/we of string "NIL_SENTINEL" generated at http://www.nitrxgen.net/hashgen/ |
| 36 | static constexpr UniqueKey NIL_SENTINEL{ 0x7eaafa003a1d11a1ull }; | 37 | static constexpr UniqueKey NIL_SENTINEL{ 0x7eaafa003a1d11a1ull, "internal nil sentinel" }; |
| 37 | 38 | ||
| 38 | void init_keepers(Universe* U, lua_State* L); | 39 | void init_keepers(Universe* U, lua_State* L); |
| 39 | void close_keepers(Universe* U); | 40 | void close_keepers(Universe* U); |
| @@ -57,4 +58,5 @@ using keeper_api_t = lua_CFunction; | |||
| 57 | [[nodiscard]] int keepercall_set(lua_State* L); | 58 | [[nodiscard]] int keepercall_set(lua_State* L); |
| 58 | [[nodiscard]] int keepercall_count(lua_State* L); | 59 | [[nodiscard]] int keepercall_count(lua_State* L); |
| 59 | 60 | ||
| 60 | [[nodiscard]] int keeper_call(Universe* U, lua_State* K, keeper_api_t _func, lua_State* L, void* linda, int starting_index); | 61 | using KeeperCallResult = Unique<std::optional<int>>; |
| 62 | [[nodiscard]] KeeperCallResult keeper_call(Universe* U, lua_State* K, keeper_api_t _func, lua_State* L, void* linda, int starting_index); | ||
diff --git a/src/linda.cpp b/src/linda.cpp index e749f52..dbd6b21 100644 --- a/src/linda.cpp +++ b/src/linda.cpp | |||
| @@ -39,8 +39,12 @@ THE SOFTWARE. | |||
| 39 | #include "universe.h" | 39 | #include "universe.h" |
| 40 | 40 | ||
| 41 | #include <array> | 41 | #include <array> |
| 42 | #include <functional> | ||
| 42 | #include <variant> | 43 | #include <variant> |
| 43 | 44 | ||
| 45 | // xxh64 of string "CANCEL_ERROR" generated at https://www.pelock.com/products/hash-calculator | ||
| 46 | static constexpr UniqueKey BATCH_SENTINEL{ 0x2DDFEE0968C62AA7ull, "linda.batched" }; | ||
| 47 | |||
| 44 | /* | 48 | /* |
| 45 | * Actual data is kept within a keeper state, which is hashed by the 'Linda' | 49 | * Actual data is kept within a keeper state, which is hashed by the 'Linda' |
| 46 | * pointer (which is same to all userdatas pointing to it). | 50 | * pointer (which is same to all userdatas pointing to it). |
| @@ -140,14 +144,14 @@ class Linda : public DeepPrelude // Deep userdata MUST start with this header | |||
| 140 | [[nodiscard]] static void* linda_id(lua_State*, DeepOp); | 144 | [[nodiscard]] static void* linda_id(lua_State*, DeepOp); |
| 141 | 145 | ||
| 142 | template<bool OPT> | 146 | template<bool OPT> |
| 143 | [[nodiscard]] static inline Linda* lua_toLinda(lua_State* L, int idx_) | 147 | [[nodiscard]] static inline Linda* ToLinda(lua_State* L, int idx_) |
| 144 | { | 148 | { |
| 145 | Linda* const linda{ static_cast<Linda*>(luaG_todeep(L, linda_id, idx_)) }; | 149 | Linda* const linda{ static_cast<Linda*>(luaG_todeep(L, linda_id, idx_)) }; |
| 146 | if (!OPT) | 150 | if constexpr (!OPT) |
| 147 | { | 151 | { |
| 148 | luaL_argcheck(L, linda != nullptr, idx_, "expecting a linda object"); | 152 | luaL_argcheck(L, linda != nullptr, idx_, "expecting a linda object"); |
| 153 | ASSERT_L(linda->U == universe_get(L)); | ||
| 149 | } | 154 | } |
| 150 | ASSERT_L(linda->U == universe_get(L)); | ||
| 151 | return linda; | 155 | return linda; |
| 152 | } | 156 | } |
| 153 | 157 | ||
| @@ -157,10 +161,28 @@ static void check_key_types(lua_State* L, int start_, int end_) | |||
| 157 | { | 161 | { |
| 158 | for (int i{ start_ }; i <= end_; ++i) | 162 | for (int i{ start_ }; i <= end_; ++i) |
| 159 | { | 163 | { |
| 160 | int const t{ lua_type(L, i) }; | 164 | LuaType const t{ lua_type_as_enum(L, i) }; |
| 161 | if (t == LUA_TBOOLEAN || t == LUA_TNUMBER || t == LUA_TSTRING || t == LUA_TLIGHTUSERDATA) | 165 | switch (t) |
| 162 | { | 166 | { |
| 167 | case LuaType::BOOLEAN: | ||
| 168 | case LuaType::NUMBER: | ||
| 169 | case LuaType::STRING: | ||
| 163 | continue; | 170 | continue; |
| 171 | |||
| 172 | case LuaType::LIGHTUSERDATA: | ||
| 173 | { | ||
| 174 | // NIL_SENTINEL isn't publicly exposed, but it doesn't hurt to check | ||
| 175 | static constexpr std::array<std::reference_wrapper<UniqueKey const>, 3> to_check{ BATCH_SENTINEL, CANCEL_ERROR, NIL_SENTINEL }; | ||
| 176 | for (UniqueKey const& key : to_check) | ||
| 177 | { | ||
| 178 | if (key.equals(L, i)) | ||
| 179 | { | ||
| 180 | luaL_error(L, "argument #%d: can't use %s as a key", i, key.m_debugName); // doesn't return | ||
| 181 | break; | ||
| 182 | } | ||
| 183 | } | ||
| 184 | } | ||
| 185 | break; | ||
| 164 | } | 186 | } |
| 165 | luaL_error(L, "argument #%d: invalid key type (not a boolean, string, number or light userdata)", i); // doesn't return | 187 | luaL_error(L, "argument #%d: invalid key type (not a boolean, string, number or light userdata)", i); // doesn't return |
| 166 | } | 188 | } |
| @@ -170,7 +192,7 @@ static void check_key_types(lua_State* L, int start_, int end_) | |||
| 170 | 192 | ||
| 171 | LUAG_FUNC(linda_protected_call) | 193 | LUAG_FUNC(linda_protected_call) |
| 172 | { | 194 | { |
| 173 | Linda* const linda{ lua_toLinda<false>(L, 1) }; | 195 | Linda* const linda{ ToLinda<false>(L, 1) }; |
| 174 | 196 | ||
| 175 | // acquire the keeper | 197 | // acquire the keeper |
| 176 | Keeper* const K{ keeper_acquire(linda->U->keepers, linda->hashSeed()) }; | 198 | Keeper* const K{ keeper_acquire(linda->U->keepers, linda->hashSeed()) }; |
| @@ -209,7 +231,7 @@ LUAG_FUNC(linda_protected_call) | |||
| 209 | */ | 231 | */ |
| 210 | LUAG_FUNC(linda_send) | 232 | LUAG_FUNC(linda_send) |
| 211 | { | 233 | { |
| 212 | Linda* const linda{ lua_toLinda<false>(L, 1) }; | 234 | Linda* const linda{ ToLinda<false>(L, 1) }; |
| 213 | std::chrono::time_point<std::chrono::steady_clock> until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; | 235 | std::chrono::time_point<std::chrono::steady_clock> until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; |
| 214 | int key_i{ 2 }; // index of first key, if timeout not there | 236 | int key_i{ 2 }; // index of first key, if timeout not there |
| 215 | 237 | ||
| @@ -257,7 +279,7 @@ LUAG_FUNC(linda_send) | |||
| 257 | keeper_toggle_nil_sentinels(L, key_i + 1, LookupMode::ToKeeper); | 279 | keeper_toggle_nil_sentinels(L, key_i + 1, LookupMode::ToKeeper); |
| 258 | bool ret{ false }; | 280 | bool ret{ false }; |
| 259 | CancelRequest cancel{ CancelRequest::None }; | 281 | CancelRequest cancel{ CancelRequest::None }; |
| 260 | int pushed{ 0 }; | 282 | KeeperCallResult pushed; |
| 261 | { | 283 | { |
| 262 | Lane* const lane{ LANE_POINTER_REGKEY.readLightUserDataValue<Lane>(L) }; | 284 | Lane* const lane{ LANE_POINTER_REGKEY.readLightUserDataValue<Lane>(L) }; |
| 263 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; | 285 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; |
| @@ -276,17 +298,17 @@ LUAG_FUNC(linda_send) | |||
| 276 | // if user wants to cancel, or looped because of a timeout, the call returns without sending anything | 298 | // if user wants to cancel, or looped because of a timeout, the call returns without sending anything |
| 277 | if (!try_again || cancel != CancelRequest::None) | 299 | if (!try_again || cancel != CancelRequest::None) |
| 278 | { | 300 | { |
| 279 | pushed = 0; | 301 | pushed.emplace(0); |
| 280 | break; | 302 | break; |
| 281 | } | 303 | } |
| 282 | 304 | ||
| 283 | STACK_CHECK(KL, 0); | 305 | STACK_CHECK(KL, 0); |
| 284 | pushed = keeper_call(linda->U, KL, KEEPER_API(send), L, linda, key_i); | 306 | pushed = keeper_call(linda->U, KL, KEEPER_API(send), L, linda, key_i); |
| 285 | if (pushed < 0) | 307 | if (!pushed.has_value()) |
| 286 | { | 308 | { |
| 287 | break; | 309 | break; |
| 288 | } | 310 | } |
| 289 | ASSERT_L(pushed == 1); | 311 | ASSERT_L(pushed.value() == 1); |
| 290 | 312 | ||
| 291 | ret = lua_toboolean(L, -1) ? true : false; | 313 | ret = lua_toboolean(L, -1) ? true : false; |
| 292 | lua_pop(L, 1); | 314 | lua_pop(L, 1); |
| @@ -331,9 +353,9 @@ LUAG_FUNC(linda_send) | |||
| 331 | STACK_CHECK(KL, 0); | 353 | STACK_CHECK(KL, 0); |
| 332 | } | 354 | } |
| 333 | 355 | ||
| 334 | if (pushed < 0) | 356 | if (!pushed.has_value()) |
| 335 | { | 357 | { |
| 336 | return luaL_error(L, "tried to copy unsupported types"); | 358 | luaL_error(L, "tried to copy unsupported types"); // doesn't return |
| 337 | } | 359 | } |
| 338 | 360 | ||
| 339 | switch (cancel) | 361 | switch (cancel) |
| @@ -366,11 +388,9 @@ LUAG_FUNC(linda_send) | |||
| 366 | * returns the actual consumed values, or nil if there weren't enough values to consume | 388 | * returns the actual consumed values, or nil if there weren't enough values to consume |
| 367 | * | 389 | * |
| 368 | */ | 390 | */ |
| 369 | // xxh64 of string "CANCEL_ERROR" generated at https://www.pelock.com/products/hash-calculator | ||
| 370 | static constexpr UniqueKey BATCH_SENTINEL{ 0x2DDFEE0968C62AA7ull }; | ||
| 371 | LUAG_FUNC(linda_receive) | 391 | LUAG_FUNC(linda_receive) |
| 372 | { | 392 | { |
| 373 | Linda* const linda{ lua_toLinda<false>(L, 1) }; | 393 | Linda* const linda{ ToLinda<false>(L, 1) }; |
| 374 | std::chrono::time_point<std::chrono::steady_clock> until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; | 394 | std::chrono::time_point<std::chrono::steady_clock> until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; |
| 375 | int key_i{ 2 }; // index of first key, if timeout not there | 395 | int key_i{ 2 }; // index of first key, if timeout not there |
| 376 | 396 | ||
| @@ -430,7 +450,7 @@ LUAG_FUNC(linda_receive) | |||
| 430 | return 0; | 450 | return 0; |
| 431 | 451 | ||
| 432 | CancelRequest cancel{ CancelRequest::None }; | 452 | CancelRequest cancel{ CancelRequest::None }; |
| 433 | int pushed{ 0 }; | 453 | KeeperCallResult pushed; |
| 434 | STACK_CHECK_START_REL(KL, 0); | 454 | STACK_CHECK_START_REL(KL, 0); |
| 435 | for (bool try_again{ true };;) | 455 | for (bool try_again{ true };;) |
| 436 | { | 456 | { |
| @@ -442,21 +462,21 @@ LUAG_FUNC(linda_receive) | |||
| 442 | // if user wants to cancel, or looped because of a timeout, the call returns without sending anything | 462 | // if user wants to cancel, or looped because of a timeout, the call returns without sending anything |
| 443 | if (!try_again || cancel != CancelRequest::None) | 463 | if (!try_again || cancel != CancelRequest::None) |
| 444 | { | 464 | { |
| 445 | pushed = 0; | 465 | pushed.emplace(0); |
| 446 | break; | 466 | break; |
| 447 | } | 467 | } |
| 448 | 468 | ||
| 449 | // all arguments of receive() but the first are passed to the keeper's receive function | 469 | // all arguments of receive() but the first are passed to the keeper's receive function |
| 450 | pushed = keeper_call(linda->U, KL, selected_keeper_receive, L, linda, key_i); | 470 | pushed = keeper_call(linda->U, KL, selected_keeper_receive, L, linda, key_i); |
| 451 | if (pushed < 0) | 471 | if (!pushed.has_value()) |
| 452 | { | 472 | { |
| 453 | break; | 473 | break; |
| 454 | } | 474 | } |
| 455 | if (pushed > 0) | 475 | if (pushed.value() > 0) |
| 456 | { | 476 | { |
| 457 | ASSERT_L(pushed >= expected_pushed_min && pushed <= expected_pushed_max); | 477 | ASSERT_L(pushed.value() >= expected_pushed_min && pushed.value() <= expected_pushed_max); |
| 458 | // replace sentinels with real nils | 478 | // replace sentinels with real nils |
| 459 | keeper_toggle_nil_sentinels(L, lua_gettop(L) - pushed, LookupMode::FromKeeper); | 479 | keeper_toggle_nil_sentinels(L, lua_gettop(L) - pushed.value(), LookupMode::FromKeeper); |
| 460 | // To be done from within the 'K' locking area | 480 | // To be done from within the 'K' locking area |
| 461 | // | 481 | // |
| 462 | linda->m_read_happened.notify_all(); | 482 | linda->m_read_happened.notify_all(); |
| @@ -494,7 +514,7 @@ LUAG_FUNC(linda_receive) | |||
| 494 | } | 514 | } |
| 495 | STACK_CHECK(KL, 0); | 515 | STACK_CHECK(KL, 0); |
| 496 | 516 | ||
| 497 | if (pushed < 0) | 517 | if (!pushed.has_value()) |
| 498 | { | 518 | { |
| 499 | return luaL_error(L, "tried to copy unsupported types"); | 519 | return luaL_error(L, "tried to copy unsupported types"); |
| 500 | } | 520 | } |
| @@ -511,7 +531,7 @@ LUAG_FUNC(linda_receive) | |||
| 511 | raise_cancel_error(L); // raises an error and doesn't return | 531 | raise_cancel_error(L); // raises an error and doesn't return |
| 512 | 532 | ||
| 513 | default: | 533 | default: |
| 514 | return pushed; | 534 | return pushed.value(); |
| 515 | } | 535 | } |
| 516 | } | 536 | } |
| 517 | 537 | ||
| @@ -527,13 +547,13 @@ LUAG_FUNC(linda_receive) | |||
| 527 | */ | 547 | */ |
| 528 | LUAG_FUNC(linda_set) | 548 | LUAG_FUNC(linda_set) |
| 529 | { | 549 | { |
| 530 | Linda* const linda{ lua_toLinda<false>(L, 1) }; | 550 | Linda* const linda{ ToLinda<false>(L, 1) }; |
| 531 | bool const has_value{ lua_gettop(L) > 2 }; | 551 | bool const has_value{ lua_gettop(L) > 2 }; |
| 532 | // make sure the key is of a valid type (throws an error if not the case) | 552 | // make sure the key is of a valid type (throws an error if not the case) |
| 533 | check_key_types(L, 2, 2); | 553 | check_key_types(L, 2, 2); |
| 534 | 554 | ||
| 535 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; | 555 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; |
| 536 | int pushed{ 0 }; | 556 | KeeperCallResult pushed; |
| 537 | if (linda->simulate_cancel == CancelRequest::None) | 557 | if (linda->simulate_cancel == CancelRequest::None) |
| 538 | { | 558 | { |
| 539 | if (has_value) | 559 | if (has_value) |
| @@ -542,16 +562,16 @@ LUAG_FUNC(linda_set) | |||
| 542 | keeper_toggle_nil_sentinels(L, 3, LookupMode::ToKeeper); | 562 | keeper_toggle_nil_sentinels(L, 3, LookupMode::ToKeeper); |
| 543 | } | 563 | } |
| 544 | pushed = keeper_call(linda->U, K->L, KEEPER_API(set), L, linda, 2); | 564 | pushed = keeper_call(linda->U, K->L, KEEPER_API(set), L, linda, 2); |
| 545 | if (pushed >= 0) // no error? | 565 | if (pushed.has_value()) // no error? |
| 546 | { | 566 | { |
| 547 | ASSERT_L(pushed == 0 || pushed == 1); | 567 | ASSERT_L(pushed.value() == 0 || pushed.value() == 1); |
| 548 | 568 | ||
| 549 | if (has_value) | 569 | if (has_value) |
| 550 | { | 570 | { |
| 551 | // we put some data in the slot, tell readers that they should wake | 571 | // we put some data in the slot, tell readers that they should wake |
| 552 | linda->m_write_happened.notify_all(); // To be done from within the 'K' locking area | 572 | linda->m_write_happened.notify_all(); // To be done from within the 'K' locking area |
| 553 | } | 573 | } |
| 554 | if (pushed == 1) | 574 | if (pushed.value() == 1) |
| 555 | { | 575 | { |
| 556 | // the key was full, but it is no longer the case, tell writers they should wake | 576 | // the key was full, but it is no longer the case, tell writers they should wake |
| 557 | ASSERT_L(lua_type(L, -1) == LUA_TBOOLEAN && lua_toboolean(L, -1) == 1); | 577 | ASSERT_L(lua_type(L, -1) == LUA_TBOOLEAN && lua_toboolean(L, -1) == 1); |
| @@ -563,11 +583,11 @@ LUAG_FUNC(linda_set) | |||
| 563 | { | 583 | { |
| 564 | // do nothing and return lanes.cancel_error | 584 | // do nothing and return lanes.cancel_error |
| 565 | CANCEL_ERROR.pushKey(L); | 585 | CANCEL_ERROR.pushKey(L); |
| 566 | pushed = 1; | 586 | pushed.emplace(1); |
| 567 | } | 587 | } |
| 568 | 588 | ||
| 569 | // must trigger any error after keeper state has been released | 589 | // must trigger any error after keeper state has been released |
| 570 | return (pushed < 0) ? luaL_error(L, "tried to copy unsupported types") : pushed; | 590 | return OptionalValue(pushed, L, "tried to copy unsupported types"); |
| 571 | } | 591 | } |
| 572 | 592 | ||
| 573 | // ################################################################################################# | 593 | // ################################################################################################# |
| @@ -579,17 +599,13 @@ LUAG_FUNC(linda_set) | |||
| 579 | */ | 599 | */ |
| 580 | LUAG_FUNC(linda_count) | 600 | LUAG_FUNC(linda_count) |
| 581 | { | 601 | { |
| 582 | Linda* const linda{ lua_toLinda<false>(L, 1) }; | 602 | Linda* const linda{ ToLinda<false>(L, 1) }; |
| 583 | // make sure the keys are of a valid type | 603 | // make sure the keys are of a valid type |
| 584 | check_key_types(L, 2, lua_gettop(L)); | 604 | check_key_types(L, 2, lua_gettop(L)); |
| 585 | 605 | ||
| 586 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; | 606 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; |
| 587 | int const pushed{ keeper_call(linda->U, K->L, KEEPER_API(count), L, linda, 2) }; | 607 | KeeperCallResult const pushed{ keeper_call(linda->U, K->L, KEEPER_API(count), L, linda, 2) }; |
| 588 | if (pushed < 0) | 608 | return OptionalValue(pushed, L, "tried to count an invalid key"); |
| 589 | { | ||
| 590 | return luaL_error(L, "tried to count an invalid key"); | ||
| 591 | } | ||
| 592 | return pushed; | ||
| 593 | } | 609 | } |
| 594 | 610 | ||
| 595 | // ################################################################################################# | 611 | // ################################################################################################# |
| @@ -601,36 +617,31 @@ LUAG_FUNC(linda_count) | |||
| 601 | */ | 617 | */ |
| 602 | LUAG_FUNC(linda_get) | 618 | LUAG_FUNC(linda_get) |
| 603 | { | 619 | { |
| 604 | Linda* const linda{ lua_toLinda<false>(L, 1) }; | 620 | Linda* const linda{ ToLinda<false>(L, 1) }; |
| 605 | lua_Integer const count{ luaL_optinteger(L, 3, 1) }; | 621 | lua_Integer const count{ luaL_optinteger(L, 3, 1) }; |
| 606 | luaL_argcheck(L, count >= 1, 3, "count should be >= 1"); | 622 | luaL_argcheck(L, count >= 1, 3, "count should be >= 1"); |
| 607 | luaL_argcheck(L, lua_gettop(L) <= 3, 4, "too many arguments"); | 623 | luaL_argcheck(L, lua_gettop(L) <= 3, 4, "too many arguments"); |
| 608 | // make sure the key is of a valid type (throws an error if not the case) | 624 | // make sure the key is of a valid type (throws an error if not the case) |
| 609 | check_key_types(L, 2, 2); | 625 | check_key_types(L, 2, 2); |
| 610 | 626 | ||
| 611 | int pushed{ 0 }; | 627 | KeeperCallResult pushed; |
| 612 | if (linda->simulate_cancel == CancelRequest::None) | 628 | if (linda->simulate_cancel == CancelRequest::None) |
| 613 | { | 629 | { |
| 614 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; | 630 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; |
| 615 | pushed = keeper_call(linda->U, K->L, KEEPER_API(get), L, linda, 2); | 631 | pushed = keeper_call(linda->U, K->L, KEEPER_API(get), L, linda, 2); |
| 616 | if (pushed > 0) | 632 | if (pushed.value_or(0) > 0) |
| 617 | { | 633 | { |
| 618 | keeper_toggle_nil_sentinels(L, lua_gettop(L) - pushed, LookupMode::FromKeeper); | 634 | keeper_toggle_nil_sentinels(L, lua_gettop(L) - pushed.value(), LookupMode::FromKeeper); |
| 619 | } | 635 | } |
| 620 | } | 636 | } |
| 621 | else // linda is cancelled | 637 | else // linda is cancelled |
| 622 | { | 638 | { |
| 623 | // do nothing and return lanes.cancel_error | 639 | // do nothing and return lanes.cancel_error |
| 624 | CANCEL_ERROR.pushKey(L); | 640 | CANCEL_ERROR.pushKey(L); |
| 625 | pushed = 1; | 641 | pushed.emplace(1); |
| 626 | } | 642 | } |
| 627 | // an error can be raised if we attempt to read an unregistered function | 643 | // an error can be raised if we attempt to read an unregistered function |
| 628 | if (pushed < 0) | 644 | return OptionalValue(pushed, L, "tried to copy unsupported types"); |
| 629 | { | ||
| 630 | return luaL_error(L, "tried to copy unsupported types"); | ||
| 631 | } | ||
| 632 | |||
| 633 | return pushed; | ||
| 634 | } | 645 | } |
| 635 | 646 | ||
| 636 | // ################################################################################################# | 647 | // ################################################################################################# |
| @@ -641,9 +652,9 @@ LUAG_FUNC(linda_get) | |||
| 641 | * Set limit to 1 Linda keys. | 652 | * Set limit to 1 Linda keys. |
| 642 | * Optionally wake threads waiting to write on the linda, in case the limit enables them to do so | 653 | * Optionally wake threads waiting to write on the linda, in case the limit enables them to do so |
| 643 | */ | 654 | */ |
| 644 | LUAG_FUNC( linda_limit) | 655 | LUAG_FUNC(linda_limit) |
| 645 | { | 656 | { |
| 646 | Linda* const linda{ lua_toLinda<false>(L, 1) }; | 657 | Linda* const linda{ ToLinda<false>(L, 1) }; |
| 647 | // make sure we got 3 arguments: the linda, a key and a limit | 658 | // make sure we got 3 arguments: the linda, a key and a limit |
| 648 | luaL_argcheck( L, lua_gettop( L) == 3, 2, "wrong number of arguments"); | 659 | luaL_argcheck( L, lua_gettop( L) == 3, 2, "wrong number of arguments"); |
| 649 | // make sure we got a numeric limit | 660 | // make sure we got a numeric limit |
| @@ -651,13 +662,13 @@ LUAG_FUNC( linda_limit) | |||
| 651 | // make sure the key is of a valid type | 662 | // make sure the key is of a valid type |
| 652 | check_key_types( L, 2, 2); | 663 | check_key_types( L, 2, 2); |
| 653 | 664 | ||
| 654 | int pushed{ 0 }; | 665 | KeeperCallResult pushed; |
| 655 | if (linda->simulate_cancel == CancelRequest::None) | 666 | if (linda->simulate_cancel == CancelRequest::None) |
| 656 | { | 667 | { |
| 657 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; | 668 | Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; |
| 658 | pushed = keeper_call(linda->U, K->L, KEEPER_API(limit), L, linda, 2); | 669 | pushed = keeper_call(linda->U, K->L, KEEPER_API(limit), L, linda, 2); |
| 659 | ASSERT_L( pushed == 0 || pushed == 1); // no error, optional boolean value saying if we should wake blocked writer threads | 670 | ASSERT_L( pushed.has_value() && (pushed.value() == 0 || pushed.value() == 1)); // no error, optional boolean value saying if we should wake blocked writer threads |
| 660 | if( pushed == 1) | 671 | if (pushed.value() == 1) |
| 661 | { | 672 | { |
| 662 | ASSERT_L( lua_type( L, -1) == LUA_TBOOLEAN && lua_toboolean( L, -1) == 1); | 673 | ASSERT_L( lua_type( L, -1) == LUA_TBOOLEAN && lua_toboolean( L, -1) == 1); |
| 663 | linda->m_read_happened.notify_all(); // To be done from within the 'K' locking area | 674 | linda->m_read_happened.notify_all(); // To be done from within the 'K' locking area |
| @@ -667,10 +678,10 @@ LUAG_FUNC( linda_limit) | |||
| 667 | { | 678 | { |
| 668 | // do nothing and return lanes.cancel_error | 679 | // do nothing and return lanes.cancel_error |
| 669 | CANCEL_ERROR.pushKey(L); | 680 | CANCEL_ERROR.pushKey(L); |
| 670 | pushed = 1; | 681 | pushed.emplace(1); |
| 671 | } | 682 | } |
| 672 | // propagate pushed boolean if any | 683 | // propagate pushed boolean if any |
| 673 | return pushed; | 684 | return pushed.value(); |
| 674 | } | 685 | } |
| 675 | 686 | ||
| 676 | // ################################################################################################# | 687 | // ################################################################################################# |
| @@ -682,7 +693,7 @@ LUAG_FUNC( linda_limit) | |||
| 682 | */ | 693 | */ |
| 683 | LUAG_FUNC(linda_cancel) | 694 | LUAG_FUNC(linda_cancel) |
| 684 | { | 695 | { |
| 685 | Linda* const linda{ lua_toLinda<false>(L, 1) }; | 696 | Linda* const linda{ ToLinda<false>(L, 1) }; |
| 686 | char const* who = luaL_optstring(L, 2, "both"); | 697 | char const* who = luaL_optstring(L, 2, "both"); |
| 687 | // make sure we got 3 arguments: the linda, a key and a limit | 698 | // make sure we got 3 arguments: the linda, a key and a limit |
| 688 | luaL_argcheck(L, lua_gettop(L) <= 2, 2, "wrong number of arguments"); | 699 | luaL_argcheck(L, lua_gettop(L) <= 2, 2, "wrong number of arguments"); |
| @@ -726,7 +737,7 @@ LUAG_FUNC(linda_cancel) | |||
| 726 | */ | 737 | */ |
| 727 | LUAG_FUNC(linda_deep) | 738 | LUAG_FUNC(linda_deep) |
| 728 | { | 739 | { |
| 729 | Linda* const linda{ lua_toLinda<false>(L, 1) }; | 740 | Linda* const linda{ ToLinda<false>(L, 1) }; |
| 730 | lua_pushlightuserdata(L, linda); // just the address | 741 | lua_pushlightuserdata(L, linda); // just the address |
| 731 | return 1; | 742 | return 1; |
| 732 | } | 743 | } |
| @@ -742,9 +753,9 @@ LUAG_FUNC(linda_deep) | |||
| 742 | */ | 753 | */ |
| 743 | 754 | ||
| 744 | template <bool OPT> | 755 | template <bool OPT> |
| 745 | [[nodiscard]] static int linda_tostring(lua_State* L, int idx_) | 756 | [[nodiscard]] static int LindaToString(lua_State* L, int idx_) |
| 746 | { | 757 | { |
| 747 | Linda* const linda{ lua_toLinda<OPT>(L, idx_) }; | 758 | Linda* const linda{ ToLinda<OPT>(L, idx_) }; |
| 748 | if (linda != nullptr) | 759 | if (linda != nullptr) |
| 749 | { | 760 | { |
| 750 | char text[128]; | 761 | char text[128]; |
| @@ -761,7 +772,7 @@ template <bool OPT> | |||
| 761 | 772 | ||
| 762 | LUAG_FUNC(linda_tostring) | 773 | LUAG_FUNC(linda_tostring) |
| 763 | { | 774 | { |
| 764 | return linda_tostring<false>(L, 1); | 775 | return LindaToString<false>(L, 1); |
| 765 | } | 776 | } |
| 766 | 777 | ||
| 767 | // ################################################################################################# | 778 | // ################################################################################################# |
| @@ -777,12 +788,12 @@ LUAG_FUNC(linda_concat) | |||
| 777 | { // linda1? linda2? | 788 | { // linda1? linda2? |
| 778 | bool atLeastOneLinda{ false }; | 789 | bool atLeastOneLinda{ false }; |
| 779 | // Lua semantics enforce that one of the 2 arguments is a Linda, but not necessarily both. | 790 | // Lua semantics enforce that one of the 2 arguments is a Linda, but not necessarily both. |
| 780 | if (linda_tostring<true>(L, 1)) | 791 | if (LindaToString<true>(L, 1)) |
| 781 | { | 792 | { |
| 782 | atLeastOneLinda = true; | 793 | atLeastOneLinda = true; |
| 783 | lua_replace(L, 1); | 794 | lua_replace(L, 1); |
| 784 | } | 795 | } |
| 785 | if (linda_tostring<true>(L, 2)) | 796 | if (LindaToString<true>(L, 2)) |
| 786 | { | 797 | { |
| 787 | atLeastOneLinda = true; | 798 | atLeastOneLinda = true; |
| 788 | lua_replace(L, 2); | 799 | lua_replace(L, 2); |
| @@ -803,7 +814,7 @@ LUAG_FUNC(linda_concat) | |||
| 803 | */ | 814 | */ |
| 804 | LUAG_FUNC(linda_dump) | 815 | LUAG_FUNC(linda_dump) |
| 805 | { | 816 | { |
| 806 | Linda* const linda{ lua_toLinda<false>(L, 1) }; | 817 | Linda* const linda{ ToLinda<false>(L, 1) }; |
| 807 | return keeper_push_linda_storage(linda->U, Dest{ L }, linda, linda->hashSeed()); | 818 | return keeper_push_linda_storage(linda->U, Dest{ L }, linda, linda->hashSeed()); |
| 808 | } | 819 | } |
| 809 | 820 | ||
| @@ -815,12 +826,12 @@ LUAG_FUNC(linda_dump) | |||
| 815 | */ | 826 | */ |
| 816 | LUAG_FUNC(linda_towatch) | 827 | LUAG_FUNC(linda_towatch) |
| 817 | { | 828 | { |
| 818 | Linda* const linda{ lua_toLinda<false>(L, 1) }; | 829 | Linda* const linda{ ToLinda<false>(L, 1) }; |
| 819 | int pushed{ keeper_push_linda_storage(linda->U, Dest{ L }, linda, linda->hashSeed()) }; | 830 | int pushed{ keeper_push_linda_storage(linda->U, Dest{ L }, linda, linda->hashSeed()) }; |
| 820 | if (pushed == 0) | 831 | if (pushed == 0) |
| 821 | { | 832 | { |
| 822 | // if the linda is empty, don't return nil | 833 | // if the linda is empty, don't return nil |
| 823 | pushed = linda_tostring<false>(L, 1); | 834 | pushed = LindaToString<false>(L, 1); |
| 824 | } | 835 | } |
| 825 | return pushed; | 836 | return pushed; |
| 826 | } | 837 | } |
| @@ -907,7 +918,8 @@ LUAG_FUNC(linda_towatch) | |||
| 907 | // Clean associated structures in the keeper state. | 918 | // Clean associated structures in the keeper state. |
| 908 | Keeper* const K{ need_acquire_release ? keeper_acquire(linda->U->keepers, linda->hashSeed()) : myK }; | 919 | Keeper* const K{ need_acquire_release ? keeper_acquire(linda->U->keepers, linda->hashSeed()) : myK }; |
| 909 | // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex... | 920 | // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex... |
| 910 | std::ignore = keeper_call(linda->U, K->L, KEEPER_API(clear), L, linda, 0); | 921 | [[maybe_unused]] KeeperCallResult const result{ keeper_call(linda->U, K->L, KEEPER_API(clear), L, linda, 0) }; |
| 922 | ASSERT_L(result.has_value() && result.value() == 0); | ||
| 911 | if (need_acquire_release) | 923 | if (need_acquire_release) |
| 912 | { | 924 | { |
| 913 | keeper_release(K); | 925 | keeper_release(K); |
| @@ -943,6 +955,7 @@ LUAG_FUNC(linda_towatch) | |||
| 943 | // protected calls, to ensure associated keeper is always released even in case of error | 955 | // protected calls, to ensure associated keeper is always released even in case of error |
| 944 | // all function are the protected call wrapper, where the actual operation is provided as upvalue | 956 | // all function are the protected call wrapper, where the actual operation is provided as upvalue |
| 945 | // note that this kind of thing can break function lookup as we use the function pointer here and there | 957 | // note that this kind of thing can break function lookup as we use the function pointer here and there |
| 958 | // TODO: change that and use different functions! | ||
| 946 | 959 | ||
| 947 | lua_pushcfunction(L, LG_linda_send); | 960 | lua_pushcfunction(L, LG_linda_send); |
| 948 | lua_pushcclosure(L, LG_linda_protected_call, 1); | 961 | lua_pushcclosure(L, LG_linda_protected_call, 1); |
diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h index e8d5ab5..77bcfe2 100644 --- a/src/macros_and_utils.h +++ b/src/macros_and_utils.h | |||
| @@ -178,16 +178,48 @@ using lua_Duration = std::chrono::template duration<lua_Number>; | |||
| 178 | // ################################################################################################# | 178 | // ################################################################################################# |
| 179 | 179 | ||
| 180 | // A unique type generator | 180 | // A unique type generator |
| 181 | template <typename T, auto = []{}> | 181 | template <typename T, auto = [] {}, typename specialization = void> |
| 182 | struct Unique | 182 | class Unique |
| 183 | { | 183 | { |
| 184 | private: | ||
| 185 | |||
| 184 | T m_val; | 186 | T m_val; |
| 185 | constexpr Unique() = default; | 187 | |
| 186 | constexpr operator T() const { return m_val; } | 188 | public: |
| 187 | constexpr explicit Unique(T b_) : m_val{ b_ } {} | 189 | |
| 190 | Unique() = default; | ||
| 191 | operator T() const { return m_val; } | ||
| 192 | explicit Unique(T b_) : m_val{ b_ } {} | ||
| 193 | }; | ||
| 194 | |||
| 195 | template <typename T, auto lambda> | ||
| 196 | class Unique<T, lambda, std::enable_if_t<!std::is_scalar_v<T>>> : public T | ||
| 197 | { | ||
| 198 | public: | ||
| 199 | |||
| 200 | using T::T; | ||
| 201 | explicit Unique(T const& b_) : T{ b_ } {} | ||
| 188 | }; | 202 | }; |
| 189 | 203 | ||
| 190 | // ################################################################################################# | 204 | // ################################################################################################# |
| 191 | 205 | ||
| 192 | using Source = Unique<lua_State*>; | 206 | using Source = Unique<lua_State*>; |
| 193 | using Dest = Unique<lua_State*>; \ No newline at end of file | 207 | using Dest = Unique<lua_State*>; |
| 208 | |||
| 209 | // ################################################################################################# | ||
| 210 | |||
| 211 | // A helper to issue an error if the provided optional doesn't contain a value | ||
| 212 | // we can't use std::optional::value_or(luaL_error(...)), because the 'or' value is always evaluated | ||
| 213 | template <typename T> | ||
| 214 | concept IsOptional = requires(T x){ x.value_or(T{}); }; | ||
| 215 | |||
| 216 | template<typename T, typename ...Ts> | ||
| 217 | requires IsOptional<T> | ||
| 218 | typename T::value_type const& OptionalValue(T const& x_, Ts... args_) | ||
| 219 | { | ||
| 220 | if (!x_.has_value()) | ||
| 221 | { | ||
| 222 | luaL_error(std::forward<Ts>(args_)...); // doesn't return | ||
| 223 | } | ||
| 224 | return x_.value(); | ||
| 225 | } | ||
diff --git a/src/uniquekey.h b/src/uniquekey.h index a89ecd3..78c0765 100644 --- a/src/uniquekey.h +++ b/src/uniquekey.h | |||
| @@ -13,12 +13,15 @@ class UniqueKey | |||
| 13 | 13 | ||
| 14 | public: | 14 | public: |
| 15 | 15 | ||
| 16 | constexpr explicit UniqueKey(uint64_t val_) | 16 | char const* m_debugName{ nullptr }; |
| 17 | |||
| 18 | constexpr explicit UniqueKey(uint64_t val_, char const* debugName_ = nullptr) | ||
| 17 | #if LUAJIT_FLAVOR() == 64 // building against LuaJIT headers for 64 bits, light userdata is restricted to 47 significant bits, because LuaJIT uses the other bits for internal optimizations | 19 | #if LUAJIT_FLAVOR() == 64 // building against LuaJIT headers for 64 bits, light userdata is restricted to 47 significant bits, because LuaJIT uses the other bits for internal optimizations |
| 18 | : m_storage{ static_cast<uintptr_t>(val_ & 0x7fffffffffffull) } | 20 | : m_storage{ static_cast<uintptr_t>(val_ & 0x7fffffffffffull) } |
| 19 | #else // LUAJIT_FLAVOR() | 21 | #else // LUAJIT_FLAVOR() |
| 20 | : m_storage{ static_cast<uintptr_t>(val_) } | 22 | : m_storage{ static_cast<uintptr_t>(val_) } |
| 21 | #endif // LUAJIT_FLAVOR() | 23 | #endif // LUAJIT_FLAVOR() |
| 24 | , m_debugName{ debugName_ } | ||
| 22 | { | 25 | { |
| 23 | } | 26 | } |
| 24 | constexpr UniqueKey(UniqueKey const& rhs_) = default; | 27 | constexpr UniqueKey(UniqueKey const& rhs_) = default; |
