aboutsummaryrefslogtreecommitdiff
path: root/src/keeper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/keeper.cpp')
-rw-r--r--src/keeper.cpp53
1 files changed, 32 insertions, 21 deletions
diff --git a/src/keeper.cpp b/src/keeper.cpp
index 3054f86..ae09b37 100644
--- a/src/keeper.cpp
+++ b/src/keeper.cpp
@@ -68,7 +68,7 @@ class KeyUD
68 public: 68 public:
69 int first{ 1 }; 69 int first{ 1 };
70 int count{ 0 }; 70 int count{ 0 };
71 int limit{ -1 }; 71 LindaLimit limit{ -1 };
72 72
73 // a fifo full userdata has one uservalue, the table that holds the actual fifo contents 73 // a fifo full userdata has one uservalue, the table that holds the actual fifo contents
74 [[nodiscard]] static void* operator new([[maybe_unused]] size_t size_, KeeperState L_) noexcept { return luaG_newuserdatauv<KeyUD>(L_, 1); } 74 [[nodiscard]] static void* operator new([[maybe_unused]] size_t size_, KeeperState L_) noexcept { return luaG_newuserdatauv<KeyUD>(L_, 1); }
@@ -76,19 +76,19 @@ class KeyUD
76 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception 76 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
77 static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] KeeperState L_) { LUA_ASSERT(L_, !"should never be called"); } 77 static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] KeeperState L_) { LUA_ASSERT(L_, !"should never be called"); }
78 78
79 [[nodiscard]] bool changeLimit(int limit_); 79 [[nodiscard]] bool changeLimit(LindaLimit limit_);
80 [[nodiscard]] static KeyUD* Create(KeeperState K_); 80 [[nodiscard]] static KeyUD* Create(KeeperState K_);
81 [[nodiscard]] static KeyUD* GetPtr(KeeperState K_, int idx_); 81 [[nodiscard]] static KeyUD* GetPtr(KeeperState K_, int idx_);
82 void peek(KeeperState K_, int count_) const; // keepercall_get 82 void peek(KeeperState K_, int count_) const; // keepercall_get
83 [[nodiscard]] int pop(KeeperState K_, int minCount_, int maxCount_); // keepercall_receive[_batched] 83 [[nodiscard]] int pop(KeeperState K_, int minCount_, int maxCount_); // keepercall_receive[_batched]
84 void prepareAccess(KeeperState K_, int idx_) const; 84 void prepareAccess(KeeperState K_, int idx_) const;
85 [[nodiscard]] bool push(KeeperState K_, int count_); // keepercall_send 85 [[nodiscard]] bool push(KeeperState K_, int count_, bool enforceLimit_); // keepercall_send and keepercall_set
86 [[nodiscard]] bool reset(KeeperState K_); 86 [[nodiscard]] bool reset(KeeperState K_);
87}; 87};
88 88
89// ################################################################################################# 89// #################################################################################################
90 90
91bool KeyUD::changeLimit(int const limit_) 91bool KeyUD::changeLimit(LindaLimit const limit_)
92{ 92{
93 bool const _newSlackAvailable{ 93 bool const _newSlackAvailable{
94 ((limit >= 0) && (count >= limit)) // then: the key was full if limited and count exceeded the previous limit 94 ((limit >= 0) && (count >= limit)) // then: the key was full if limited and count exceeded the previous limit
@@ -209,11 +209,11 @@ void KeyUD::prepareAccess(KeeperState const K_, int const idx_) const
209 209
210// in: expect this val... on top of the stack 210// in: expect this val... on top of the stack
211// out: nothing, removes all pushed values from the stack 211// out: nothing, removes all pushed values from the stack
212bool KeyUD::push(KeeperState const K_, int const count_) 212bool KeyUD::push(KeeperState const K_, int const count_, bool const enforceLimit_)
213{ 213{
214 int const _fifoIdx{ luaG_absindex(K_, -1 - count_) }; 214 int const _fifoIdx{ luaG_absindex(K_, -1 - count_) };
215 LUA_ASSERT(K_, KeyUD::GetPtr(K_, _fifoIdx) == this); // K_: this val... 215 LUA_ASSERT(K_, KeyUD::GetPtr(K_, _fifoIdx) == this); // K_: this val...
216 if (limit >= 0 && count + count_ > limit) { // not enough room 216 if (enforceLimit_ && (limit >= 0) && (count + count_ > limit)) { // not enough room
217 return false; 217 return false;
218 } 218 }
219 219
@@ -239,7 +239,8 @@ bool KeyUD::reset(KeeperState const K_)
239 STACK_CHECK_START_REL(K_, 0); 239 STACK_CHECK_START_REL(K_, 0);
240 bool const _wasFull{ (limit > 0) && (count >= limit) }; 240 bool const _wasFull{ (limit > 0) && (count >= limit) };
241 // empty the KeyUD: replace uservalue with a virgin table, reset counters, but leave limit unchanged! 241 // empty the KeyUD: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
242 lua_newtable(K_); // K_: KeysDB key val... KeyUD {} 242 // if we have an actual limit, use it to preconfigure the table
243 lua_createtable(K_, (limit <= 0) ? 0 : limit, 0); // K_: KeysDB key val... KeyUD {}
243 lua_setiuservalue(K_, -2, kContentsTableIndex); // K_: KeysDB key val... KeyUD 244 lua_setiuservalue(K_, -2, kContentsTableIndex); // K_: KeysDB key val... KeyUD
244 first = 1; 245 first = 1;
245 count = 0; 246 count = 0;
@@ -397,23 +398,34 @@ int keepercall_get(lua_State* const L_)
397int keepercall_limit(lua_State* const L_) 398int keepercall_limit(lua_State* const L_)
398{ 399{
399 KeeperState const _K{ L_ }; 400 KeeperState const _K{ L_ };
400 int const _limit{ static_cast<int>(luaL_optinteger(_K, 3, -1)) }; // -1 if we read nil because the argument is absent 401 // no limit to set, means we read and return the current limit instead
402 bool const _reading{ lua_gettop(_K) == 2 };
403 LindaLimit const _limit{ static_cast<LindaLimit::type>(luaL_optinteger(_K, 3, -1)) }; // -1 if we read nil because the argument is absent
401 lua_settop(_K, 2); // _K: linda key 404 lua_settop(_K, 2); // _K: linda key
402 PushKeysDB(_K, 1); // _K: linda key KeysDB 405 PushKeysDB(_K, 1); // _K: linda key KeysDB
403 lua_replace(_K, 1); // _K: KeysDB key 406 lua_replace(_K, 1); // _K: KeysDB key
404 lua_pushvalue(_K, -1); // _K: KeysDB key key 407 lua_pushvalue(_K, -1); // _K: KeysDB key key
405 lua_rawget(_K, -3); // _K: KeysDB key KeyUD|nil 408 lua_rawget(_K, -3); // _K: KeysDB key KeyUD|nil
406 KeyUD* _key{ KeyUD::GetPtr(_K, -1) }; 409 KeyUD* _key{ KeyUD::GetPtr(_K, -1) };
407 if (_key == nullptr) { // _K: KeysDB key nil 410 if (_reading) {
408 lua_pop(_K, 1); // _K: KeysDB key 411 if (_key && _key->limit >= 0) {
409 _key = KeyUD::Create(_K); // _K: KeysDB key KeyUD 412 lua_pushinteger(_K, _key->limit); // _K: KeysDB key KeyUD limit
410 lua_rawset(_K, -3); // _K: KeysDB 413 } else { // if the key doesn't exist, it is unlimited by default
414 luaG_pushstring(_K, "unlimited"); // _K: KeysDB key KeyUD "unlimited"
415 }
416 // return a single value: the limit of the key
417 } else {
418 if (_key == nullptr) { // _K: KeysDB key nil
419 lua_pop(_K, 1); // _K: KeysDB key
420 _key = KeyUD::Create(_K); // _K: KeysDB key KeyUD
421 lua_rawset(_K, -3); // _K: KeysDB
422 }
423 // remove any clutter on the stack
424 lua_settop(_K, 0); // _K:
425 // return true if we decide that blocked threads waiting to write on that key should be awakened
426 // this is the case if we detect the key was full but it is no longer the case
427 lua_pushboolean(_K, _key->changeLimit(_limit) ? 1 : 0); // _K: bool
411 } 428 }
412 // remove any clutter on the stack
413 lua_settop(_K, 0); // _K:
414 // return true if we decide that blocked threads waiting to write on that key should be awakened
415 // this is the case if we detect the key was full but it is no longer the case
416 lua_pushboolean(_K, _key->changeLimit(_limit) ? 1 : 0); // _K: bool
417 return 1; 429 return 1;
418} 430}
419 431
@@ -502,7 +514,7 @@ int keepercall_send(lua_State* const L_)
502 lua_pop(_K, 1); // _K: linda KeyUD val... 514 lua_pop(_K, 1); // _K: linda KeyUD val...
503 STACK_CHECK(_K, 0); 515 STACK_CHECK(_K, 0);
504 KeyUD* const _key{ KeyUD::GetPtr(_K, 2) }; 516 KeyUD* const _key{ KeyUD::GetPtr(_K, 2) };
505 if (_key && _key->push(_K, _n)) { // not enough room? 517 if (_key && _key->push(_K, _n, true)) { // not enough room?
506 lua_settop(_K, 0); // _K: 518 lua_settop(_K, 0); // _K:
507 lua_pushboolean(_K, 1); // _K: true 519 lua_pushboolean(_K, 1); // _K: true
508 } else { 520 } else {
@@ -527,8 +539,7 @@ int keepercall_set(lua_State* const L_)
527 PushKeysDB(_K, 1); // _K: linda key val... KeysDB 539 PushKeysDB(_K, 1); // _K: linda key val... KeysDB
528 lua_replace(_K, 1); // _K: KeysDB key val... 540 lua_replace(_K, 1); // _K: KeysDB key val...
529 541
530 // make sure we have a value on the stack 542 if (lua_gettop(_K) == 2) { // no value to set // _K: KeysDB key
531 if (lua_gettop(_K) == 2) { // _K: KeysDB key
532 lua_pushvalue(_K, -1); // _K: KeysDB key key 543 lua_pushvalue(_K, -1); // _K: KeysDB key key
533 lua_rawget(_K, 1); // _K: KeysDB key KeyUD|nil 544 lua_rawget(_K, 1); // _K: KeysDB key KeyUD|nil
534 // empty the KeyUD for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! 545 // empty the KeyUD for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
@@ -563,7 +574,7 @@ int keepercall_set(lua_State* const L_)
563 } 574 }
564 // replace the key with the KeyUD in the stack 575 // replace the key with the KeyUD in the stack
565 lua_replace(_K, -2 - _count); // _K: KeysDB KeyUD val... 576 lua_replace(_K, -2 - _count); // _K: KeysDB KeyUD val...
566 [[maybe_unused]] bool const _pushed{ _key->push(_K, _count) }; // _K: KeysDB 577 [[maybe_unused]] bool const _pushed{ _key->push(_K, _count, false) }; // _K: KeysDB
567 } 578 }
568 // stack isn't the same here depending on what we did before, but that's not a problem 579 // stack isn't the same here depending on what we did before, but that's not a problem
569 lua_pushboolean(_K, _should_wake_writers ? 1 : 0); // _K: ... bool 580 lua_pushboolean(_K, _should_wake_writers ? 1 : 0); // _K: ... bool