aboutsummaryrefslogtreecommitdiff
path: root/src/linda.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/linda.cpp')
-rw-r--r--src/linda.cpp153
1 files changed, 86 insertions, 67 deletions
diff --git a/src/linda.cpp b/src/linda.cpp
index 37a74b0..e749f52 100644
--- a/src/linda.cpp
+++ b/src/linda.cpp
@@ -61,8 +61,8 @@ class Linda : public DeepPrelude // Deep userdata MUST start with this header
61 61
62 public: 62 public:
63 63
64 SIGNAL_T read_happened; 64 std::condition_variable m_read_happened;
65 SIGNAL_T write_happened; 65 std::condition_variable m_write_happened;
66 Universe* const U; // the universe this linda belongs to 66 Universe* const U; // the universe this linda belongs to
67 uintptr_t const group; // a group to control keeper allocation between lindas 67 uintptr_t const group; // a group to control keeper allocation between lindas
68 CancelRequest simulate_cancel{ CancelRequest::None }; 68 CancelRequest simulate_cancel{ CancelRequest::None };
@@ -70,7 +70,7 @@ class Linda : public DeepPrelude // Deep userdata MUST start with this header
70 public: 70 public:
71 71
72 // a fifo full userdata has one uservalue, the table that holds the actual fifo contents 72 // a fifo full userdata has one uservalue, the table that holds the actual fifo contents
73 static void* operator new(size_t size_, Universe* U_) noexcept { return U_->internal_allocator.alloc(size_); } 73 [[nodiscard]] static void* operator new(size_t size_, Universe* U_) noexcept { return U_->internal_allocator.alloc(size_); }
74 // always embedded somewhere else or "in-place constructed" as a full userdata 74 // always embedded somewhere else or "in-place constructed" as a full userdata
75 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception 75 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
76 static void operator delete(void* p_, Universe* U_) { U_->internal_allocator.free(p_, sizeof(Linda)); } 76 static void operator delete(void* p_, Universe* U_) { U_->internal_allocator.free(p_, sizeof(Linda)); }
@@ -81,17 +81,11 @@ class Linda : public DeepPrelude // Deep userdata MUST start with this header
81 : U{ U_ } 81 : U{ U_ }
82 , group{ group_ << KEEPER_MAGIC_SHIFT } 82 , group{ group_ << KEEPER_MAGIC_SHIFT }
83 { 83 {
84 SIGNAL_INIT(&read_happened);
85 SIGNAL_INIT(&write_happened);
86
87 setName(name_, len_); 84 setName(name_, len_);
88 } 85 }
89 86
90 ~Linda() 87 ~Linda()
91 { 88 {
92 // There aren't any lanes waiting on these lindas, since all proxies have been gc'ed. Right?
93 SIGNAL_FREE(&read_happened);
94 SIGNAL_FREE(&write_happened);
95 if (std::holds_alternative<AllocatedName>(m_name)) 89 if (std::holds_alternative<AllocatedName>(m_name))
96 { 90 {
97 AllocatedName& name = std::get<AllocatedName>(m_name); 91 AllocatedName& name = std::get<AllocatedName>(m_name);
@@ -143,10 +137,10 @@ class Linda : public DeepPrelude // Deep userdata MUST start with this header
143 return nullptr; 137 return nullptr;
144 } 138 }
145}; 139};
146static void* linda_id( lua_State*, DeepOp); 140[[nodiscard]] static void* linda_id(lua_State*, DeepOp);
147 141
148template<bool OPT> 142template<bool OPT>
149static inline Linda* lua_toLinda(lua_State* L, int idx_) 143[[nodiscard]] static inline Linda* lua_toLinda(lua_State* L, int idx_)
150{ 144{
151 Linda* const linda{ static_cast<Linda*>(luaG_todeep(L, linda_id, idx_)) }; 145 Linda* const linda{ static_cast<Linda*>(luaG_todeep(L, linda_id, idx_)) };
152 if (!OPT) 146 if (!OPT)
@@ -168,7 +162,7 @@ static void check_key_types(lua_State* L, int start_, int end_)
168 { 162 {
169 continue; 163 continue;
170 } 164 }
171 std::ignore = luaL_error(L, "argument #%d: invalid key type (not a boolean, string, number or light userdata)", i); 165 luaL_error(L, "argument #%d: invalid key type (not a boolean, string, number or light userdata)", i); // doesn't return
172 } 166 }
173} 167}
174 168
@@ -216,15 +210,19 @@ LUAG_FUNC(linda_protected_call)
216LUAG_FUNC(linda_send) 210LUAG_FUNC(linda_send)
217{ 211{
218 Linda* const linda{ lua_toLinda<false>(L, 1) }; 212 Linda* const linda{ lua_toLinda<false>(L, 1) };
219 time_d timeout{ -1.0 }; 213 std::chrono::time_point<std::chrono::steady_clock> until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
220 int key_i{ 2 }; // index of first key, if timeout not there 214 int key_i{ 2 }; // index of first key, if timeout not there
221 215
222 if (lua_type(L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion 216 if (lua_type(L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion
223 { 217 {
224 timeout = SIGNAL_TIMEOUT_PREPARE(lua_tonumber(L, 2)); 218 lua_Duration const duration{ lua_tonumber(L, 2) };
219 if (duration.count() >= 0.0)
220 {
221 until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration);
222 }
225 ++key_i; 223 ++key_i;
226 } 224 }
227 else if (lua_isnil(L, 2)) // alternate explicit "no timeout" by passing nil before the key 225 else if (lua_isnil(L, 2)) // alternate explicit "infinite timeout" by passing nil before the key
228 { 226 {
229 ++key_i; 227 ++key_i;
230 } 228 }
@@ -266,6 +264,7 @@ LUAG_FUNC(linda_send)
266 lua_State* const KL{ K ? K->L : nullptr }; 264 lua_State* const KL{ K ? K->L : nullptr };
267 if (KL == nullptr) 265 if (KL == nullptr)
268 return 0; 266 return 0;
267
269 STACK_CHECK_START_REL(KL, 0); 268 STACK_CHECK_START_REL(KL, 0);
270 for (bool try_again{ true };;) 269 for (bool try_again{ true };;)
271 { 270 {
@@ -295,34 +294,37 @@ LUAG_FUNC(linda_send)
295 if (ret) 294 if (ret)
296 { 295 {
297 // Wake up ALL waiting threads 296 // Wake up ALL waiting threads
298 SIGNAL_ALL(&linda->write_happened); 297 linda->m_write_happened.notify_all();
299 break; 298 break;
300 } 299 }
301 300
302 // instant timout to bypass the wait syscall 301 // instant timout to bypass the wait syscall
303 if (timeout == 0.0) 302 if (std::chrono::steady_clock::now() >= until)
304 { 303 {
305 break; /* no wait; instant timeout */ 304 break; /* no wait; instant timeout */
306 } 305 }
307 306
308 // storage limit hit, wait until timeout or signalled that we should try again 307 // storage limit hit, wait until timeout or signalled that we should try again
309 { 308 {
310 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings 309 Lane::Status prev_status{ Lane::Error }; // prevent 'might be used uninitialized' warnings
311 if (lane != nullptr) 310 if (lane != nullptr)
312 { 311 {
313 // change status of lane to "waiting" 312 // change status of lane to "waiting"
314 prev_status = lane->status; // RUNNING, most likely 313 prev_status = lane->m_status; // Running, most likely
315 ASSERT_L(prev_status == RUNNING); // but check, just in case 314 ASSERT_L(prev_status == Lane::Running); // but check, just in case
316 lane->status = WAITING; 315 lane->m_status = Lane::Waiting;
317 ASSERT_L(lane->waiting_on == nullptr); 316 ASSERT_L(lane->m_waiting_on == nullptr);
318 lane->waiting_on = &linda->read_happened; 317 lane->m_waiting_on = &linda->m_read_happened;
319 } 318 }
320 // could not send because no room: wait until some data was read before trying again, or until timeout is reached 319 // could not send because no room: wait until some data was read before trying again, or until timeout is reached
321 try_again = SIGNAL_WAIT(&linda->read_happened, &K->keeper_cs, timeout); 320 std::unique_lock<std::mutex> keeper_lock{ K->m_mutex, std::adopt_lock };
321 std::cv_status const status{ linda->m_read_happened.wait_until(keeper_lock, until) };
322 keeper_lock.release(); // we don't want to release the lock!
323 try_again = (status == std::cv_status::no_timeout); // detect spurious wakeups
322 if (lane != nullptr) 324 if (lane != nullptr)
323 { 325 {
324 lane->waiting_on = nullptr; 326 lane->m_waiting_on = nullptr;
325 lane->status = prev_status; 327 lane->m_status = prev_status;
326 } 328 }
327 } 329 }
328 } 330 }
@@ -369,21 +371,24 @@ static constexpr UniqueKey BATCH_SENTINEL{ 0x2DDFEE0968C62AA7ull };
369LUAG_FUNC(linda_receive) 371LUAG_FUNC(linda_receive)
370{ 372{
371 Linda* const linda{ lua_toLinda<false>(L, 1) }; 373 Linda* const linda{ lua_toLinda<false>(L, 1) };
372 374 std::chrono::time_point<std::chrono::steady_clock> until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
373 time_d timeout{ -1.0 }; 375 int key_i{ 2 }; // index of first key, if timeout not there
374 int key_i{ 2 };
375 376
376 if (lua_type(L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion 377 if (lua_type(L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion
377 { 378 {
378 timeout = SIGNAL_TIMEOUT_PREPARE(lua_tonumber(L, 2)); 379 lua_Duration const duration{ lua_tonumber(L, 2) };
380 if (duration.count() >= 0.0)
381 {
382 until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration);
383 }
379 ++key_i; 384 ++key_i;
380 } 385 }
381 else if (lua_isnil(L, 2)) // alternate explicit "no timeout" by passing nil before the key 386 else if (lua_isnil(L, 2)) // alternate explicit "infinite timeout" by passing nil before the key
382 { 387 {
383 ++key_i; 388 ++key_i;
384 } 389 }
385 390
386 keeper_api_t keeper_receive; 391 keeper_api_t selected_keeper_receive{ nullptr };
387 int expected_pushed_min{ 0 }, expected_pushed_max{ 0 }; 392 int expected_pushed_min{ 0 }, expected_pushed_max{ 0 };
388 // are we in batched mode? 393 // are we in batched mode?
389 BATCH_SENTINEL.pushKey(L); 394 BATCH_SENTINEL.pushKey(L);
@@ -396,7 +401,7 @@ LUAG_FUNC(linda_receive)
396 // make sure the keys are of a valid type 401 // make sure the keys are of a valid type
397 check_key_types(L, key_i, key_i); 402 check_key_types(L, key_i, key_i);
398 // receive multiple values from a single slot 403 // receive multiple values from a single slot
399 keeper_receive = KEEPER_API(receive_batched); 404 selected_keeper_receive = KEEPER_API(receive_batched);
400 // we expect a user-defined amount of return value 405 // we expect a user-defined amount of return value
401 expected_pushed_min = (int) luaL_checkinteger(L, key_i + 1); 406 expected_pushed_min = (int) luaL_checkinteger(L, key_i + 1);
402 expected_pushed_max = (int) luaL_optinteger(L, key_i + 2, expected_pushed_min); 407 expected_pushed_max = (int) luaL_optinteger(L, key_i + 2, expected_pushed_min);
@@ -413,17 +418,20 @@ LUAG_FUNC(linda_receive)
413 // make sure the keys are of a valid type 418 // make sure the keys are of a valid type
414 check_key_types(L, key_i, lua_gettop(L)); 419 check_key_types(L, key_i, lua_gettop(L));
415 // receive a single value, checking multiple slots 420 // receive a single value, checking multiple slots
416 keeper_receive = KEEPER_API(receive); 421 selected_keeper_receive = KEEPER_API(receive);
417 // we expect a single (value, key) pair of returned values 422 // we expect a single (value, key) pair of returned values
418 expected_pushed_min = expected_pushed_max = 2; 423 expected_pushed_min = expected_pushed_max = 2;
419 } 424 }
420 425
421 Lane* const lane{ LANE_POINTER_REGKEY.readLightUserDataValue<Lane>(L) }; 426 Lane* const lane{ LANE_POINTER_REGKEY.readLightUserDataValue<Lane>(L) };
422 Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) }; 427 Keeper* const K{ which_keeper(linda->U->keepers, linda->hashSeed()) };
423 if (K == nullptr) 428 lua_State* const KL{ K ? K->L : nullptr };
429 if (KL == nullptr)
424 return 0; 430 return 0;
431
425 CancelRequest cancel{ CancelRequest::None }; 432 CancelRequest cancel{ CancelRequest::None };
426 int pushed{ 0 }; 433 int pushed{ 0 };
434 STACK_CHECK_START_REL(KL, 0);
427 for (bool try_again{ true };;) 435 for (bool try_again{ true };;)
428 { 436 {
429 if (lane != nullptr) 437 if (lane != nullptr)
@@ -439,7 +447,7 @@ LUAG_FUNC(linda_receive)
439 } 447 }
440 448
441 // all arguments of receive() but the first are passed to the keeper's receive function 449 // all arguments of receive() but the first are passed to the keeper's receive function
442 pushed = keeper_call(linda->U, K->L, keeper_receive, L, linda, key_i); 450 pushed = keeper_call(linda->U, KL, selected_keeper_receive, L, linda, key_i);
443 if (pushed < 0) 451 if (pushed < 0)
444 { 452 {
445 break; 453 break;
@@ -451,36 +459,40 @@ LUAG_FUNC(linda_receive)
451 keeper_toggle_nil_sentinels(L, lua_gettop(L) - pushed, LookupMode::FromKeeper); 459 keeper_toggle_nil_sentinels(L, lua_gettop(L) - pushed, LookupMode::FromKeeper);
452 // To be done from within the 'K' locking area 460 // To be done from within the 'K' locking area
453 // 461 //
454 SIGNAL_ALL(&linda->read_happened); 462 linda->m_read_happened.notify_all();
455 break; 463 break;
456 } 464 }
457 465
458 if (timeout == 0.0) 466 if (std::chrono::steady_clock::now() >= until)
459 { 467 {
460 break; /* instant timeout */ 468 break; /* instant timeout */
461 } 469 }
462 470
463 // nothing received, wait until timeout or signalled that we should try again 471 // nothing received, wait until timeout or signalled that we should try again
464 { 472 {
465 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings 473 Lane::Status prev_status{ Lane::Error }; // prevent 'might be used uninitialized' warnings
466 if (lane != nullptr) 474 if (lane != nullptr)
467 { 475 {
468 // change status of lane to "waiting" 476 // change status of lane to "waiting"
469 prev_status = lane->status; // RUNNING, most likely 477 prev_status = lane->m_status; // Running, most likely
470 ASSERT_L(prev_status == RUNNING); // but check, just in case 478 ASSERT_L(prev_status == Lane::Running); // but check, just in case
471 lane->status = WAITING; 479 lane->m_status = Lane::Waiting;
472 ASSERT_L(lane->waiting_on == nullptr); 480 ASSERT_L(lane->m_waiting_on == nullptr);
473 lane->waiting_on = &linda->write_happened; 481 lane->m_waiting_on = &linda->m_write_happened;
474 } 482 }
475 // not enough data to read: wakeup when data was sent, or when timeout is reached 483 // not enough data to read: wakeup when data was sent, or when timeout is reached
476 try_again = SIGNAL_WAIT(&linda->write_happened, &K->keeper_cs, timeout); 484 std::unique_lock<std::mutex> keeper_lock{ K->m_mutex, std::adopt_lock };
485 std::cv_status const status{ linda->m_write_happened.wait_until(keeper_lock, until) };
486 keeper_lock.release(); // we don't want to release the lock!
487 try_again = (status == std::cv_status::no_timeout); // detect spurious wakeups
477 if (lane != nullptr) 488 if (lane != nullptr)
478 { 489 {
479 lane->waiting_on = nullptr; 490 lane->m_waiting_on = nullptr;
480 lane->status = prev_status; 491 lane->m_status = prev_status;
481 } 492 }
482 } 493 }
483 } 494 }
495 STACK_CHECK(KL, 0);
484 496
485 if (pushed < 0) 497 if (pushed < 0)
486 { 498 {
@@ -537,13 +549,13 @@ LUAG_FUNC(linda_set)
537 if (has_value) 549 if (has_value)
538 { 550 {
539 // we put some data in the slot, tell readers that they should wake 551 // we put some data in the slot, tell readers that they should wake
540 SIGNAL_ALL(&linda->write_happened); // To be done from within the 'K' locking area 552 linda->m_write_happened.notify_all(); // To be done from within the 'K' locking area
541 } 553 }
542 if (pushed == 1) 554 if (pushed == 1)
543 { 555 {
544 // the key was full, but it is no longer the case, tell writers they should wake 556 // the key was full, but it is no longer the case, tell writers they should wake
545 ASSERT_L(lua_type(L, -1) == LUA_TBOOLEAN && lua_toboolean(L, -1) == 1); 557 ASSERT_L(lua_type(L, -1) == LUA_TBOOLEAN && lua_toboolean(L, -1) == 1);
546 SIGNAL_ALL(&linda->read_happened); // To be done from within the 'K' locking area 558 linda->m_read_happened.notify_all(); // To be done from within the 'K' locking area
547 } 559 }
548 } 560 }
549 } 561 }
@@ -648,7 +660,7 @@ LUAG_FUNC( linda_limit)
648 if( pushed == 1) 660 if( pushed == 1)
649 { 661 {
650 ASSERT_L( lua_type( L, -1) == LUA_TBOOLEAN && lua_toboolean( L, -1) == 1); 662 ASSERT_L( lua_type( L, -1) == LUA_TBOOLEAN && lua_toboolean( L, -1) == 1);
651 SIGNAL_ALL( &linda->read_happened); // To be done from within the 'K' locking area 663 linda->m_read_happened.notify_all(); // To be done from within the 'K' locking area
652 } 664 }
653 } 665 }
654 else // linda is cancelled 666 else // linda is cancelled
@@ -678,8 +690,8 @@ LUAG_FUNC(linda_cancel)
678 linda->simulate_cancel = CancelRequest::Soft; 690 linda->simulate_cancel = CancelRequest::Soft;
679 if (strcmp(who, "both") == 0) // tell everyone writers to wake up 691 if (strcmp(who, "both") == 0) // tell everyone writers to wake up
680 { 692 {
681 SIGNAL_ALL(&linda->write_happened); 693 linda->m_write_happened.notify_all();
682 SIGNAL_ALL(&linda->read_happened); 694 linda->m_read_happened.notify_all();
683 } 695 }
684 else if (strcmp(who, "none") == 0) // reset flag 696 else if (strcmp(who, "none") == 0) // reset flag
685 { 697 {
@@ -687,11 +699,11 @@ LUAG_FUNC(linda_cancel)
687 } 699 }
688 else if (strcmp(who, "read") == 0) // tell blocked readers to wake up 700 else if (strcmp(who, "read") == 0) // tell blocked readers to wake up
689 { 701 {
690 SIGNAL_ALL(&linda->write_happened); 702 linda->m_write_happened.notify_all();
691 } 703 }
692 else if (strcmp(who, "write") == 0) // tell blocked writers to wake up 704 else if (strcmp(who, "write") == 0) // tell blocked writers to wake up
693 { 705 {
694 SIGNAL_ALL(&linda->read_happened); 706 linda->m_read_happened.notify_all();
695 } 707 }
696 else 708 else
697 { 709 {
@@ -730,7 +742,7 @@ LUAG_FUNC(linda_deep)
730*/ 742*/
731 743
732template <bool OPT> 744template <bool OPT>
733static int linda_tostring(lua_State* L, int idx_) 745[[nodiscard]] static int linda_tostring(lua_State* L, int idx_)
734{ 746{
735 Linda* const linda{ lua_toLinda<OPT>(L, idx_) }; 747 Linda* const linda{ lua_toLinda<OPT>(L, idx_) };
736 if (linda != nullptr) 748 if (linda != nullptr)
@@ -792,7 +804,7 @@ LUAG_FUNC(linda_concat)
792LUAG_FUNC(linda_dump) 804LUAG_FUNC(linda_dump)
793{ 805{
794 Linda* const linda{ lua_toLinda<false>(L, 1) }; 806 Linda* const linda{ lua_toLinda<false>(L, 1) };
795 return keeper_push_linda_storage(linda->U, L, linda, linda->hashSeed()); 807 return keeper_push_linda_storage(linda->U, Dest{ L }, linda, linda->hashSeed());
796} 808}
797 809
798// ################################################################################################# 810// #################################################################################################
@@ -804,7 +816,7 @@ LUAG_FUNC(linda_dump)
804LUAG_FUNC(linda_towatch) 816LUAG_FUNC(linda_towatch)
805{ 817{
806 Linda* const linda{ lua_toLinda<false>(L, 1) }; 818 Linda* const linda{ lua_toLinda<false>(L, 1) };
807 int pushed{ keeper_push_linda_storage(linda->U, L, linda, linda->hashSeed()) }; 819 int pushed{ keeper_push_linda_storage(linda->U, Dest{ L }, linda, linda->hashSeed()) };
808 if (pushed == 0) 820 if (pushed == 0)
809 { 821 {
810 // if the linda is empty, don't return nil 822 // if the linda is empty, don't return nil
@@ -839,7 +851,7 @@ LUAG_FUNC(linda_towatch)
839* For any other strings, the ID function must not react at all. This allows 851* For any other strings, the ID function must not react at all. This allows
840* future extensions of the system. 852* future extensions of the system.
841*/ 853*/
842static void* linda_id( lua_State* L, DeepOp op_) 854[[nodiscard]] static void* linda_id(lua_State* L, DeepOp op_)
843{ 855{
844 switch( op_) 856 switch( op_)
845 { 857 {
@@ -885,15 +897,22 @@ static void* linda_id( lua_State* L, DeepOp op_)
885 { 897 {
886 Linda* const linda{ lua_tolightuserdata<Linda>(L, 1) }; 898 Linda* const linda{ lua_tolightuserdata<Linda>(L, 1) };
887 ASSERT_L(linda); 899 ASSERT_L(linda);
888 900 Keeper* const myK{ which_keeper(linda->U->keepers, linda->hashSeed()) };
889 // Clean associated structures in the keeper state. 901 // if collected after the universe, keepers are already destroyed, and there is nothing to clear
890 Keeper* const K{ keeper_acquire(linda->U->keepers, linda->hashSeed()) }; 902 if (myK)
891 if (K && K->L) // can be nullptr if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup)
892 { 903 {
904 // if collected from my own keeper, we can't acquire/release it
905 // because we are already inside a protected area, and trying to do so would deadlock!
906 bool const need_acquire_release{ myK->L != L };
907 // Clean associated structures in the keeper state.
908 Keeper* const K{ need_acquire_release ? keeper_acquire(linda->U->keepers, linda->hashSeed()) : myK };
893 // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex... 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...
894 keeper_call(linda->U, K->L, KEEPER_API(clear), L, linda, 0); 910 std::ignore = keeper_call(linda->U, K->L, KEEPER_API(clear), L, linda, 0);
911 if (need_acquire_release)
912 {
913 keeper_release(K);
914 }
895 } 915 }
896 keeper_release(K);
897 916
898 delete linda; // operator delete overload ensures things go as expected 917 delete linda; // operator delete overload ensures things go as expected
899 return nullptr; 918 return nullptr;
@@ -990,11 +1009,11 @@ static void* linda_id( lua_State* L, DeepOp op_)
990 */ 1009 */
991LUAG_FUNC(linda) 1010LUAG_FUNC(linda)
992{ 1011{
993 int const top = lua_gettop(L); 1012 int const top{ lua_gettop(L) };
994 luaL_argcheck(L, top <= 2, top, "too many arguments"); 1013 luaL_argcheck(L, top <= 2, top, "too many arguments");
995 if (top == 1) 1014 if (top == 1)
996 { 1015 {
997 int const t = lua_type(L, 1); 1016 int const t{ lua_type(L, 1) };
998 luaL_argcheck(L, t == LUA_TSTRING || t == LUA_TNUMBER, 1, "wrong parameter (should be a string or a number)"); 1017 luaL_argcheck(L, t == LUA_TSTRING || t == LUA_TNUMBER, 1, "wrong parameter (should be a string or a number)");
999 } 1018 }
1000 else if (top == 2) 1019 else if (top == 2)
@@ -1002,5 +1021,5 @@ LUAG_FUNC(linda)
1002 luaL_checktype(L, 1, LUA_TSTRING); 1021 luaL_checktype(L, 1, LUA_TSTRING);
1003 luaL_checktype(L, 2, LUA_TNUMBER); 1022 luaL_checktype(L, 2, LUA_TNUMBER);
1004 } 1023 }
1005 return luaG_newdeepuserdata(L, linda_id, 0); 1024 return luaG_newdeepuserdata(Dest{ L }, linda_id, 0);
1006} 1025}