aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-10-07 09:29:49 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2024-10-07 09:29:49 +0200
commite939e5e6a894a042d3301e47faa05264445f27f6 (patch)
treee913615e3fd0ed9e94d9494d6e266420dd7a771b
parentb064bedccebe511b96c9d99d689d6634f5873ec2 (diff)
downloadlanes-e939e5e6a894a042d3301e47faa05264445f27f6.tar.gz
lanes-e939e5e6a894a042d3301e47faa05264445f27f6.tar.bz2
lanes-e939e5e6a894a042d3301e47faa05264445f27f6.zip
Internal improvements: new strong types StackIndex and KeeperIndex
-rw-r--r--src/debug.h20
-rw-r--r--src/keeper.cpp2
-rw-r--r--src/keeper.h3
-rw-r--r--src/linda.cpp56
-rw-r--r--src/linda.h2
-rw-r--r--src/macros_and_utils.h34
-rw-r--r--src/unique.hpp44
-rw-r--r--src/universe.cpp2
8 files changed, 84 insertions, 79 deletions
diff --git a/src/debug.h b/src/debug.h
index e96632d..0f5c6bc 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -2,6 +2,7 @@
2 2
3#include "lanesconf.h" 3#include "lanesconf.h"
4#include "luaerrors.h" 4#include "luaerrors.h"
5#include "unique.hpp"
5 6
6// ################################################################################################# 7// #################################################################################################
7 8
@@ -18,7 +19,7 @@ inline SourceLocation Where(std::source_location const& where_ = std::source_loc
18 return std::make_tuple(_fileName, where_.line(), _func); 19 return std::make_tuple(_fileName, where_.line(), _func);
19} 20}
20 21
21inline void LUA_ASSERT_IMPL(lua_State* const L_, bool cond_, std::string_view const& txt_, SourceLocation const& where_ = Where()) 22inline void LUA_ASSERT_IMPL(lua_State* const L_, bool const cond_, std::string_view const& txt_, SourceLocation const& where_ = Where())
22{ 23{
23 if (!cond_) { 24 if (!cond_) {
24 raise_luaL_error(L_, "%s:%d: LUA_ASSERT '%s' IN %s", std::get<0>(where_).data(), std::get<1>(where_), txt_.data(), std::get<2>(where_).data()); 25 raise_luaL_error(L_, "%s:%d: LUA_ASSERT '%s' IN %s", std::get<0>(where_).data(), std::get<1>(where_), txt_.data(), std::get<2>(where_).data());
@@ -35,19 +36,8 @@ class StackChecker
35 int oldtop; 36 int oldtop;
36 37
37 public: 38 public:
38 struct Relative 39 using Relative = Unique<int>;
39 { 40 using Absolute = Unique<int>;
40 int const offset;
41
42 operator int() const { return offset; }
43 };
44
45 struct Absolute
46 {
47 int const offset;
48
49 operator int() const { return offset; }
50 };
51 41
52 StackChecker(lua_State* const L_, Relative const offset_, SourceLocation const& where_ = Where()) 42 StackChecker(lua_State* const L_, Relative const offset_, SourceLocation const& where_ = Where())
53 : L{ L_ } 43 : L{ L_ }
@@ -77,7 +67,7 @@ class StackChecker
77 } 67 }
78 68
79 // verify if the distance between the current top and the initial one is what we expect 69 // verify if the distance between the current top and the initial one is what we expect
80 void check(int expected_, SourceLocation const& where_ = Where()) 70 void check(int const expected_, SourceLocation const& where_ = Where())
81 { 71 {
82 if (expected_ != LUA_MULTRET) { 72 if (expected_ != LUA_MULTRET) {
83 int const _actual{ lua_gettop(L) - oldtop }; 73 int const _actual{ lua_gettop(L) - oldtop };
diff --git a/src/keeper.cpp b/src/keeper.cpp
index e2df380..58796b8 100644
--- a/src/keeper.cpp
+++ b/src/keeper.cpp
@@ -840,7 +840,7 @@ void Keepers::close()
840 840
841// ################################################################################################# 841// #################################################################################################
842 842
843[[nodiscard]] Keeper* Keepers::getKeeper(int idx_) 843[[nodiscard]] Keeper* Keepers::getKeeper(KeeperIndex const idx_)
844{ 844{
845 if (isClosing.test(std::memory_order_acquire)) { 845 if (isClosing.test(std::memory_order_acquire)) {
846 return nullptr; 846 return nullptr;
diff --git a/src/keeper.h b/src/keeper.h
index 05e3547..04bf834 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -9,6 +9,7 @@ class Universe;
9 9
10using KeeperState = Unique<lua_State*>; 10using KeeperState = Unique<lua_State*>;
11using LindaLimit = Unique<int>; 11using LindaLimit = Unique<int>;
12using KeeperIndex = Unique<int>;
12 13
13// ################################################################################################# 14// #################################################################################################
14 15
@@ -62,7 +63,7 @@ struct Keepers
62 63
63 Keepers() = default; 64 Keepers() = default;
64 void close(); 65 void close();
65 [[nodiscard]] Keeper* getKeeper(int idx_); 66 [[nodiscard]] Keeper* getKeeper(KeeperIndex idx_);
66 [[nodiscard]] int getNbKeepers() const; 67 [[nodiscard]] int getNbKeepers() const;
67 void initialize(Universe& U_, lua_State* L_, int nbKeepers_, int gc_threshold_); 68 void initialize(Universe& U_, lua_State* L_, int nbKeepers_, int gc_threshold_);
68}; 69};
diff --git a/src/linda.cpp b/src/linda.cpp
index eb39c0f..3f5fd33 100644
--- a/src/linda.cpp
+++ b/src/linda.cpp
@@ -44,10 +44,10 @@ namespace {
44 // ############################################################################################# 44 // #############################################################################################
45 45
46 46
47 static void CheckKeyTypes(lua_State* const L_, int const start_, int const end_) 47 static void CheckKeyTypes(lua_State* const L_, StackIndex const start_, StackIndex const end_)
48 { 48 {
49 STACK_CHECK_START_REL(L_, 0); 49 STACK_CHECK_START_REL(L_, 0);
50 for (int const _i : std::ranges::iota_view{ start_, end_ + 1 }) { 50 for (StackIndex const _i : std::ranges::iota_view{ start_, StackIndex{ end_ + 1 } }) {
51 LuaType const _t{ luaG_type(L_, _i) }; 51 LuaType const _t{ luaG_type(L_, _i) };
52 switch (_t) { 52 switch (_t) {
53 case LuaType::BOOLEAN: 53 case LuaType::BOOLEAN:
@@ -83,7 +83,7 @@ namespace {
83 // ############################################################################################# 83 // #############################################################################################
84 84
85 template <bool OPT> 85 template <bool OPT>
86 [[nodiscard]] static inline Linda* ToLinda(lua_State* const L_, int const idx_) 86 [[nodiscard]] static inline Linda* ToLinda(lua_State* const L_, StackIndex const idx_)
87 { 87 {
88 Linda* const _linda{ static_cast<Linda*>(LindaFactory::Instance.toDeep(L_, idx_)) }; 88 Linda* const _linda{ static_cast<Linda*>(LindaFactory::Instance.toDeep(L_, idx_)) };
89 if constexpr (!OPT) { 89 if constexpr (!OPT) {
@@ -104,7 +104,7 @@ namespace {
104 */ 104 */
105 105
106 template <bool OPT> 106 template <bool OPT>
107 [[nodiscard]] static int LindaToString(lua_State* const L_, int const idx_) 107 [[nodiscard]] static int LindaToString(lua_State* const L_, StackIndex const idx_)
108 { 108 {
109 Linda* const _linda{ ToLinda<OPT>(L_, idx_) }; 109 Linda* const _linda{ ToLinda<OPT>(L_, idx_) };
110 if (_linda != nullptr) { 110 if (_linda != nullptr) {
@@ -192,7 +192,7 @@ std::string_view Linda::getName() const
192// used to perform all linda operations that access keepers 192// used to perform all linda operations that access keepers
193int Linda::ProtectedCall(lua_State* const L_, lua_CFunction const f_) 193int Linda::ProtectedCall(lua_State* const L_, lua_CFunction const f_)
194{ 194{
195 Linda* const _linda{ ToLinda<false>(L_, 1) }; 195 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
196 196
197 // acquire the keeper 197 // acquire the keeper
198 Keeper* const _keeper{ _linda->acquireKeeper() }; 198 Keeper* const _keeper{ _linda->acquireKeeper() };
@@ -279,7 +279,7 @@ void Linda::setName(std::string_view const& name_)
279 */ 279 */
280LUAG_FUNC(linda_cancel) 280LUAG_FUNC(linda_cancel)
281{ 281{
282 Linda* const _linda{ ToLinda<false>(L_, 1) }; 282 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
283 std::string_view const _who{ luaG_optstring(L_, 2, "both") }; 283 std::string_view const _who{ luaG_optstring(L_, 2, "both") };
284 // make sure we got 2 arguments: the linda and the cancellation mode 284 // make sure we got 2 arguments: the linda and the cancellation mode
285 luaL_argcheck(L_, lua_gettop(L_) <= 2, 2, "wrong number of arguments"); 285 luaL_argcheck(L_, lua_gettop(L_) <= 2, 2, "wrong number of arguments");
@@ -306,7 +306,7 @@ LUAG_FUNC(linda_cancel)
306// linda:__close(err|nil) 306// linda:__close(err|nil)
307static LUAG_FUNC(linda_close) 307static LUAG_FUNC(linda_close)
308{ 308{
309 [[maybe_unused]] Linda* const _linda{ ToLinda<false>(L_, 1) }; // L_: linda err|nil 309 [[maybe_unused]] Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; // L_: linda err|nil
310 310
311 // do we have a uservalue? it contains a callback 311 // do we have a uservalue? it contains a callback
312 switch (lua_getiuservalue(L_, 1, 1)) { 312 switch (lua_getiuservalue(L_, 1, 1)) {
@@ -340,11 +340,11 @@ LUAG_FUNC(linda_concat)
340{ // L_: linda1? linda2? 340{ // L_: linda1? linda2?
341 bool _atLeastOneLinda{ false }; 341 bool _atLeastOneLinda{ false };
342 // Lua semantics enforce that one of the 2 arguments is a Linda, but not necessarily both. 342 // Lua semantics enforce that one of the 2 arguments is a Linda, but not necessarily both.
343 if (LindaToString<true>(L_, 1)) { 343 if (LindaToString<true>(L_, StackIndex{ 1 })) {
344 _atLeastOneLinda = true; 344 _atLeastOneLinda = true;
345 lua_replace(L_, 1); 345 lua_replace(L_, 1);
346 } 346 }
347 if (LindaToString<true>(L_, 2)) { 347 if (LindaToString<true>(L_, StackIndex{ 2 })) {
348 _atLeastOneLinda = true; 348 _atLeastOneLinda = true;
349 lua_replace(L_, 2); 349 lua_replace(L_, 2);
350 } 350 }
@@ -366,9 +366,9 @@ LUAG_FUNC(linda_count)
366{ 366{
367 static constexpr lua_CFunction _count{ 367 static constexpr lua_CFunction _count{
368 +[](lua_State* const L_) { 368 +[](lua_State* const L_) {
369 Linda* const _linda{ ToLinda<false>(L_, 1) }; 369 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
370 // make sure the keys are of a valid type 370 // make sure the keys are of a valid type
371 CheckKeyTypes(L_, 2, lua_gettop(L_)); 371 CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ lua_gettop(L_) });
372 372
373 Keeper* const _keeper{ _linda->whichKeeper() }; 373 Keeper* const _keeper{ _linda->whichKeeper() };
374 KeeperCallResult const _pushed{ keeper_call(_keeper->K, KEEPER_API(count), L_, _linda, 2) }; 374 KeeperCallResult const _pushed{ keeper_call(_keeper->K, KEEPER_API(count), L_, _linda, 2) };
@@ -392,7 +392,7 @@ LUAG_FUNC(linda_count)
392 */ 392 */
393LUAG_FUNC(linda_deep) 393LUAG_FUNC(linda_deep)
394{ 394{
395 Linda* const _linda{ ToLinda<false>(L_, 1) }; 395 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
396 lua_pushlightuserdata(L_, _linda->obfuscated<void*>()); // just the address 396 lua_pushlightuserdata(L_, _linda->obfuscated<void*>()); // just the address
397 return 1; 397 return 1;
398} 398}
@@ -407,7 +407,7 @@ LUAG_FUNC(linda_dump)
407{ 407{
408 static constexpr lua_CFunction _dump{ 408 static constexpr lua_CFunction _dump{
409 +[](lua_State* const L_) { 409 +[](lua_State* const L_) {
410 Linda* const _linda{ ToLinda<false>(L_, 1) }; 410 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
411 return Keeper::PushLindaStorage(*_linda, DestState{ L_ }); 411 return Keeper::PushLindaStorage(*_linda, DestState{ L_ });
412 } 412 }
413 }; 413 };
@@ -425,12 +425,12 @@ LUAG_FUNC(linda_get)
425{ 425{
426 static constexpr lua_CFunction _get{ 426 static constexpr lua_CFunction _get{
427 +[](lua_State* const L_) { 427 +[](lua_State* const L_) {
428 Linda* const _linda{ ToLinda<false>(L_, 1) }; 428 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
429 lua_Integer const _count{ luaL_optinteger(L_, 3, 1) }; 429 lua_Integer const _count{ luaL_optinteger(L_, 3, 1) };
430 luaL_argcheck(L_, _count >= 1, 3, "count should be >= 1"); 430 luaL_argcheck(L_, _count >= 1, 3, "count should be >= 1");
431 luaL_argcheck(L_, lua_gettop(L_) <= 3, 4, "too many arguments"); 431 luaL_argcheck(L_, lua_gettop(L_) <= 3, 4, "too many arguments");
432 // make sure the key is of a valid type (throws an error if not the case) 432 // make sure the key is of a valid type (throws an error if not the case)
433 CheckKeyTypes(L_, 2, 2); 433 CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ 2 });
434 434
435 KeeperCallResult _pushed; 435 KeeperCallResult _pushed;
436 if (_linda->cancelRequest == CancelRequest::None) { 436 if (_linda->cancelRequest == CancelRequest::None) {
@@ -463,7 +463,7 @@ LUAG_FUNC(linda_limit)
463{ 463{
464 static constexpr lua_CFunction _limit{ 464 static constexpr lua_CFunction _limit{
465 +[](lua_State* const L_) { 465 +[](lua_State* const L_) {
466 Linda* const _linda{ ToLinda<false>(L_, 1) }; 466 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
467 // make sure we got 2 or 3 arguments: the linda, a key and optionally a limit 467 // make sure we got 2 or 3 arguments: the linda, a key and optionally a limit
468 int const _nargs{ lua_gettop(L_) }; 468 int const _nargs{ lua_gettop(L_) };
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");
@@ -474,7 +474,7 @@ LUAG_FUNC(linda_limit)
474 raise_luaL_argerror(L_, 3, "limit must be >= 0"); 474 raise_luaL_argerror(L_, 3, "limit must be >= 0");
475 } 475 }
476 // make sure the key is of a valid type 476 // make sure the key is of a valid type
477 CheckKeyTypes(L_, 2, 2); 477 CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ 2 });
478 478
479 KeeperCallResult _pushed; 479 KeeperCallResult _pushed;
480 if (_linda->cancelRequest == CancelRequest::None) { 480 if (_linda->cancelRequest == CancelRequest::None) {
@@ -526,8 +526,8 @@ LUAG_FUNC(linda_receive)
526{ 526{
527 static constexpr lua_CFunction _receive{ 527 static constexpr lua_CFunction _receive{
528 +[](lua_State* const L_) { 528 +[](lua_State* const L_) {
529 Linda* const _linda{ ToLinda<false>(L_, 1) }; 529 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
530 int _key_i{ 2 }; // index of first key, if timeout not there 530 StackIndex _key_i{ 2 }; // index of first key, if timeout not there
531 531
532 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; 532 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
533 if (luaG_type(L_, 2) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion 533 if (luaG_type(L_, 2) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion
@@ -566,7 +566,7 @@ LUAG_FUNC(linda_receive)
566 } 566 }
567 } else { 567 } else {
568 // make sure the keys are of a valid type 568 // make sure the keys are of a valid type
569 CheckKeyTypes(L_, _key_i, lua_gettop(L_)); 569 CheckKeyTypes(L_, _key_i, StackIndex{ lua_gettop(L_) });
570 // receive a single value, checking multiple slots 570 // receive a single value, checking multiple slots
571 _selected_keeper_receive = KEEPER_API(receive); 571 _selected_keeper_receive = KEEPER_API(receive);
572 // we expect a single (value, key) pair of returned values 572 // we expect a single (value, key) pair of returned values
@@ -682,8 +682,8 @@ LUAG_FUNC(linda_send)
682{ 682{
683 static constexpr lua_CFunction _send{ 683 static constexpr lua_CFunction _send{
684 +[](lua_State* const L_) { 684 +[](lua_State* const L_) {
685 Linda* const _linda{ ToLinda<false>(L_, 1) }; 685 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
686 int _key_i{ 2 }; // index of first key, if timeout not there 686 StackIndex _key_i{ 2 }; // index of first key, if timeout not there
687 687
688 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; 688 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
689 if (luaG_type(L_, 2) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion 689 if (luaG_type(L_, 2) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion
@@ -820,10 +820,10 @@ LUAG_FUNC(linda_set)
820{ 820{
821 static constexpr lua_CFunction _set{ 821 static constexpr lua_CFunction _set{
822 +[](lua_State* const L_) { 822 +[](lua_State* const L_) {
823 Linda* const _linda{ ToLinda<false>(L_, 1) }; 823 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
824 bool const _has_data{ lua_gettop(L_) > 2 }; 824 bool const _has_data{ lua_gettop(L_) > 2 };
825 // make sure the key is of a valid type (throws an error if not the case) 825 // make sure the key is of a valid type (throws an error if not the case)
826 CheckKeyTypes(L_, 2, 2); 826 CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ 2 });
827 827
828 KeeperCallResult _pushed; 828 KeeperCallResult _pushed;
829 if (_linda->cancelRequest == CancelRequest::None) { 829 if (_linda->cancelRequest == CancelRequest::None) {
@@ -859,7 +859,7 @@ LUAG_FUNC(linda_set)
859 859
860LUAG_FUNC(linda_tostring) 860LUAG_FUNC(linda_tostring)
861{ 861{
862 return LindaToString<false>(L_, 1); 862 return LindaToString<false>(L_, StackIndex{ 1 });
863} 863}
864 864
865// ################################################################################################# 865// #################################################################################################
@@ -871,11 +871,11 @@ LUAG_FUNC(linda_tostring)
871 */ 871 */
872LUAG_FUNC(linda_towatch) 872LUAG_FUNC(linda_towatch)
873{ 873{
874 Linda* const _linda{ ToLinda<false>(L_, 1) }; 874 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
875 int _pushed{ Keeper::PushLindaStorage(*_linda, DestState{ L_ }) }; 875 int _pushed{ Keeper::PushLindaStorage(*_linda, DestState{ L_ }) };
876 if (_pushed == 0) { 876 if (_pushed == 0) {
877 // if the linda is empty, don't return nil 877 // if the linda is empty, don't return nil
878 _pushed = LindaToString<false>(L_, 1); 878 _pushed = LindaToString<false>(L_, StackIndex{ 1 });
879 } 879 }
880 return _pushed; 880 return _pushed;
881} 881}
@@ -989,7 +989,7 @@ LUAG_FUNC(linda)
989 } 989 }
990 // depending on whether we have a handler or not, the stack is not in the same state at this point 990 // depending on whether we have a handler or not, the stack is not in the same state at this point
991 // just make sure we have our Linda at the top 991 // just make sure we have our Linda at the top
992 LUA_ASSERT(L_, ToLinda<true>(L_, -1)); 992 LUA_ASSERT(L_, ToLinda<true>(L_, StackIndex{ -1 }));
993 return 1; 993 return 1;
994 } else { // no to-be-closed support 994 } else { // no to-be-closed support
995 // ensure we have name, group in that order on the stack 995 // ensure we have name, group in that order on the stack
diff --git a/src/linda.h b/src/linda.h
index 6901a86..4551443 100644
--- a/src/linda.h
+++ b/src/linda.h
@@ -52,7 +52,7 @@ class Linda
52 std::condition_variable readHappened{}; 52 std::condition_variable readHappened{};
53 std::condition_variable writeHappened{}; 53 std::condition_variable writeHappened{};
54 Universe* const U{ nullptr }; // the universe this linda belongs to 54 Universe* const U{ nullptr }; // the universe this linda belongs to
55 int const keeperIndex{ -1 }; // the keeper associated to this linda 55 KeeperIndex const keeperIndex{ -1 }; // the keeper associated to this linda
56 CancelRequest cancelRequest{ CancelRequest::None }; 56 CancelRequest cancelRequest{ CancelRequest::None };
57 57
58 public: 58 public:
diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h
index 1b1ced6..e73abef 100644
--- a/src/macros_and_utils.h
+++ b/src/macros_and_utils.h
@@ -2,6 +2,7 @@
2 2
3#include "debug.h" 3#include "debug.h"
4#include "luaerrors.h" 4#include "luaerrors.h"
5#include "unique.hpp"
5 6
6using namespace std::chrono_literals; 7using namespace std::chrono_literals;
7 8
@@ -24,40 +25,9 @@ using lua_Duration = std::chrono::template duration<lua_Number>;
24 25
25// ################################################################################################# 26// #################################################################################################
26 27
27// A unique type generator
28template <typename T, auto = [] {}, typename specialization = void>
29class Unique
30{
31 private:
32 T val;
33
34 public:
35 using type = T;
36 Unique() = default;
37 operator T() const { return val; }
38 explicit Unique(T b_)
39 : val{ b_ }
40 {
41 }
42};
43
44template <typename T, auto lambda>
45class Unique<T, lambda, std::enable_if_t<!std::is_scalar_v<T>>>
46: public T
47{
48 public:
49 using type = T;
50 using T::T;
51 explicit Unique(T const& b_)
52 : T{ b_ }
53 {
54 }
55};
56
57// #################################################################################################
58
59using SourceState = Unique<lua_State*>; 28using SourceState = Unique<lua_State*>;
60using DestState = Unique<lua_State*>; 29using DestState = Unique<lua_State*>;
30using StackIndex = Unique<int>;
61 31
62// ################################################################################################# 32// #################################################################################################
63 33
diff --git a/src/unique.hpp b/src/unique.hpp
new file mode 100644
index 0000000..aeb7a67
--- /dev/null
+++ b/src/unique.hpp
@@ -0,0 +1,44 @@
1#pragma once
2
3// #################################################################################################
4
5// A unique type generator
6template <typename T, auto = [] {}, typename specialization = void>
7class Unique
8{
9 private:
10 T val;
11
12 public:
13 using type = T;
14 Unique() = default;
15 operator T() const { return val; }
16 explicit Unique(T b_)
17 : val{ b_ }
18 {
19 }
20 // pre-imcrement
21 auto& operator++()
22 {
23 ++val;
24 return *this;
25 }
26 // post-increment
27 auto operator++(int)
28 {
29 return Unique<T>{ std::exchange(val, val + 1) };
30 }
31};
32
33template <typename T, auto lambda>
34class Unique<T, lambda, std::enable_if_t<!std::is_scalar_v<T>>>
35: public T
36{
37 public:
38 using type = T;
39 using T::T;
40 explicit Unique(T const& b_)
41 : T{ b_ }
42 {
43 }
44};
diff --git a/src/universe.cpp b/src/universe.cpp
index 04db10f..3800dbb 100644
--- a/src/universe.cpp
+++ b/src/universe.cpp
@@ -85,7 +85,7 @@ void Universe::callOnStateCreate(lua_State* const L_, lua_State* const from_, Lo
85 } 85 }
86 86
87 STACK_CHECK_START_REL(L_, 0); 87 STACK_CHECK_START_REL(L_, 0);
88 DEBUGSPEW_CODE(DebugSpew(U_) << "calling on_state_create()" << std::endl); 88 DEBUGSPEW_CODE(DebugSpew(this) << "calling on_state_create()" << std::endl);
89 if (std::holds_alternative<lua_CFunction>(onStateCreateFunc)) { 89 if (std::holds_alternative<lua_CFunction>(onStateCreateFunc)) {
90 90
91 // C function: recreate a closure in the new state, bypassing the lookup scheme 91 // C function: recreate a closure in the new state, bypassing the lookup scheme