diff options
Diffstat (limited to 'src/linda.cpp')
-rw-r--r-- | src/linda.cpp | 389 |
1 files changed, 150 insertions, 239 deletions
diff --git a/src/linda.cpp b/src/linda.cpp index f88158a..82f5f98 100644 --- a/src/linda.cpp +++ b/src/linda.cpp | |||
@@ -2,7 +2,7 @@ | |||
2 | * LINDA.CPP Copyright (c) 2018-2024, Benoit Germain | 2 | * LINDA.CPP Copyright (c) 2018-2024, Benoit Germain |
3 | * | 3 | * |
4 | * Linda deep userdata. | 4 | * Linda deep userdata. |
5 | */ | 5 | */ |
6 | 6 | ||
7 | /* | 7 | /* |
8 | =============================================================================== | 8 | =============================================================================== |
@@ -62,8 +62,7 @@ Linda::Linda(Universe* U_, LindaGroup group_, char const* name_, size_t len_) | |||
62 | 62 | ||
63 | Linda::~Linda() | 63 | Linda::~Linda() |
64 | { | 64 | { |
65 | if (std::holds_alternative<AllocatedName>(m_name)) | 65 | if (std::holds_alternative<AllocatedName>(m_name)) { |
66 | { | ||
67 | AllocatedName& name = std::get<AllocatedName>(m_name); | 66 | AllocatedName& name = std::get<AllocatedName>(m_name); |
68 | U->internal_allocator.free(name.name, name.len); | 67 | U->internal_allocator.free(name.name, name.len); |
69 | } | 68 | } |
@@ -74,19 +73,15 @@ Linda::~Linda() | |||
74 | void Linda::setName(char const* name_, size_t len_) | 73 | void Linda::setName(char const* name_, size_t len_) |
75 | { | 74 | { |
76 | // keep default | 75 | // keep default |
77 | if (!name_ || len_ == 0) | 76 | if (!name_ || len_ == 0) { |
78 | { | ||
79 | return; | 77 | return; |
80 | } | 78 | } |
81 | ++len_; // don't forget terminating 0 | 79 | ++len_; // don't forget terminating 0 |
82 | if (len_ < kEmbeddedNameLength) | 80 | if (len_ < kEmbeddedNameLength) { |
83 | { | ||
84 | m_name.emplace<EmbeddedName>(); | 81 | m_name.emplace<EmbeddedName>(); |
85 | char* const name{ std::get<EmbeddedName>(m_name).data() }; | 82 | char* const name{ std::get<EmbeddedName>(m_name).data() }; |
86 | memcpy(name, name_, len_); | 83 | memcpy(name, name_, len_); |
87 | } | 84 | } else { |
88 | else | ||
89 | { | ||
90 | AllocatedName& name = std::get<AllocatedName>(m_name); | 85 | AllocatedName& name = std::get<AllocatedName>(m_name); |
91 | name.name = static_cast<char*>(U->internal_allocator.alloc(len_)); | 86 | name.name = static_cast<char*>(U->internal_allocator.alloc(len_)); |
92 | name.len = len_; | 87 | name.len = len_; |
@@ -98,13 +93,11 @@ void Linda::setName(char const* name_, size_t len_) | |||
98 | 93 | ||
99 | char const* Linda::getName() const | 94 | char const* Linda::getName() const |
100 | { | 95 | { |
101 | if (std::holds_alternative<AllocatedName>(m_name)) | 96 | if (std::holds_alternative<AllocatedName>(m_name)) { |
102 | { | ||
103 | AllocatedName const& name = std::get<AllocatedName>(m_name); | 97 | AllocatedName const& name = std::get<AllocatedName>(m_name); |
104 | return name.name; | 98 | return name.name; |
105 | } | 99 | } |
106 | if (std::holds_alternative<EmbeddedName>(m_name)) | 100 | if (std::holds_alternative<EmbeddedName>(m_name)) { |
107 | { | ||
108 | char const* const name{ std::get<EmbeddedName>(m_name).data() }; | 101 | char const* const name{ std::get<EmbeddedName>(m_name).data() }; |
109 | return name; | 102 | return name; |
110 | } | 103 | } |
@@ -117,8 +110,7 @@ template <bool OPT> | |||
117 | [[nodiscard]] static inline Linda* ToLinda(lua_State* L_, int idx_) | 110 | [[nodiscard]] static inline Linda* ToLinda(lua_State* L_, int idx_) |
118 | { | 111 | { |
119 | Linda* const linda{ static_cast<Linda*>(LindaFactory::Instance.toDeep(L_, idx_)) }; | 112 | Linda* const linda{ static_cast<Linda*>(LindaFactory::Instance.toDeep(L_, idx_)) }; |
120 | if constexpr (!OPT) | 113 | if constexpr (!OPT) { |
121 | { | ||
122 | luaL_argcheck(L_, linda != nullptr, idx_, "expecting a linda object"); // doesn't return if linda is nullptr | 114 | luaL_argcheck(L_, linda != nullptr, idx_, "expecting a linda object"); // doesn't return if linda is nullptr |
123 | LUA_ASSERT(L_, linda->U == universe_get(L_)); | 115 | LUA_ASSERT(L_, linda->U == universe_get(L_)); |
124 | } | 116 | } |
@@ -129,26 +121,20 @@ template <bool OPT> | |||
129 | 121 | ||
130 | static void check_key_types(lua_State* L_, int start_, int end_) | 122 | static void check_key_types(lua_State* L_, int start_, int end_) |
131 | { | 123 | { |
132 | for (int i{ start_ }; i <= end_; ++i) | 124 | for (int i{ start_ }; i <= end_; ++i) { |
133 | { | ||
134 | LuaType const t{ lua_type_as_enum(L_, i) }; | 125 | LuaType const t{ lua_type_as_enum(L_, i) }; |
135 | switch (t) | 126 | switch (t) { |
136 | { | 127 | case LuaType::BOOLEAN: |
137 | case LuaType::BOOLEAN: | 128 | case LuaType::NUMBER: |
138 | case LuaType::NUMBER: | 129 | case LuaType::STRING: |
139 | case LuaType::STRING: | ||
140 | continue; | 130 | continue; |
141 | 131 | ||
142 | case LuaType::LIGHTUSERDATA: | 132 | case LuaType::LIGHTUSERDATA: |
143 | { | 133 | static constexpr std::array<std::reference_wrapper<UniqueKey const>, 3> kKeysToCheck{ kLindaBatched, kCancelError, kNilSentinel }; |
144 | static constexpr std::array<std::reference_wrapper<UniqueKey const>, 3> kKeysToCheck{ kLindaBatched, kCancelError, kNilSentinel }; | 134 | for (UniqueKey const& key : kKeysToCheck) { |
145 | for (UniqueKey const& key : kKeysToCheck) | 135 | if (key.equals(L_, i)) { |
146 | { | 136 | raise_luaL_error(L_, "argument #%d: can't use %s as a key", i, key.m_debugName); |
147 | if (key.equals(L_, i)) | 137 | break; |
148 | { | ||
149 | raise_luaL_error(L_, "argument #%d: can't use %s as a key", i, key.m_debugName); | ||
150 | break; | ||
151 | } | ||
152 | } | 138 | } |
153 | } | 139 | } |
154 | break; | 140 | break; |
@@ -184,8 +170,7 @@ int Linda::ProtectedCall(lua_State* L_, lua_CFunction f_) | |||
184 | linda->releaseKeeper(K); | 170 | linda->releaseKeeper(K); |
185 | 171 | ||
186 | // if there was an error, forward it | 172 | // if there was an error, forward it |
187 | if (rc != LUA_OK) | 173 | if (rc != LUA_OK) { |
188 | { | ||
189 | raise_lua_error(L_); | 174 | raise_lua_error(L_); |
190 | } | 175 | } |
191 | // return whatever the actual operation provided | 176 | // return whatever the actual operation provided |
@@ -195,39 +180,33 @@ int Linda::ProtectedCall(lua_State* L_, lua_CFunction f_) | |||
195 | // ################################################################################################# | 180 | // ################################################################################################# |
196 | 181 | ||
197 | /* | 182 | /* |
198 | * bool= linda_send( linda_ud, [timeout_secs=-1,] [linda.null,] key_num|str|bool|lightuserdata, ... ) | 183 | * bool= linda_send( linda_ud, [timeout_secs=-1,] [linda.null,] key_num|str|bool|lightuserdata, ... ) |
199 | * | 184 | * |
200 | * Send one or more values to a Linda. If there is a limit, all values must fit. | 185 | * Send one or more values to a Linda. If there is a limit, all values must fit. |
201 | * | 186 | * |
202 | * Returns: 'true' if the value was queued | 187 | * Returns: 'true' if the value was queued |
203 | * 'false' for timeout (only happens when the queue size is limited) | 188 | * 'false' for timeout (only happens when the queue size is limited) |
204 | * nil, kCancelError if cancelled | 189 | * nil, kCancelError if cancelled |
205 | */ | 190 | */ |
206 | LUAG_FUNC(linda_send) | 191 | LUAG_FUNC(linda_send) |
207 | { | 192 | { |
208 | auto send = [](lua_State* L_) | 193 | auto send = [](lua_State* L_) { |
209 | { | ||
210 | Linda* const linda{ ToLinda<false>(L_, 1) }; | 194 | Linda* const linda{ ToLinda<false>(L_, 1) }; |
211 | std::chrono::time_point<std::chrono::steady_clock> until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; | 195 | std::chrono::time_point<std::chrono::steady_clock> until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; |
212 | int key_i{ 2 }; // index of first key, if timeout not there | 196 | int key_i{ 2 }; // index of first key, if timeout not there |
213 | 197 | ||
214 | if (lua_type(L_, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion | 198 | if (lua_type(L_, 2) == LUA_TNUMBER) { // we don't want to use lua_isnumber() because of autocoercion |
215 | { | ||
216 | lua_Duration const duration{ lua_tonumber(L_, 2) }; | 199 | lua_Duration const duration{ lua_tonumber(L_, 2) }; |
217 | if (duration.count() >= 0.0) | 200 | if (duration.count() >= 0.0) { |
218 | { | ||
219 | until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration); | 201 | until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration); |
220 | } | 202 | } |
221 | ++key_i; | 203 | ++key_i; |
222 | } | 204 | } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key |
223 | else if (lua_isnil(L_, 2)) // alternate explicit "infinite timeout" by passing nil before the key | ||
224 | { | ||
225 | ++key_i; | 205 | ++key_i; |
226 | } | 206 | } |
227 | 207 | ||
228 | bool const as_nil_sentinel{ kNilSentinel.equals(L_, key_i) }; // if not nullptr, send() will silently send a single nil if nothing is provided | 208 | bool const as_nil_sentinel{ kNilSentinel.equals(L_, key_i) }; // if not nullptr, send() will silently send a single nil if nothing is provided |
229 | if (as_nil_sentinel) | 209 | if (as_nil_sentinel) { |
230 | { | ||
231 | // the real key to send data to is after the kNilSentinel marker | 210 | // the real key to send data to is after the kNilSentinel marker |
232 | ++key_i; | 211 | ++key_i; |
233 | } | 212 | } |
@@ -238,15 +217,11 @@ LUAG_FUNC(linda_send) | |||
238 | STACK_GROW(L_, 1); | 217 | STACK_GROW(L_, 1); |
239 | 218 | ||
240 | // make sure there is something to send | 219 | // make sure there is something to send |
241 | if (lua_gettop(L_) == key_i) | 220 | if (lua_gettop(L_) == key_i) { |
242 | { | 221 | if (as_nil_sentinel) { |
243 | if (as_nil_sentinel) | ||
244 | { | ||
245 | // send a single nil if nothing is provided | 222 | // send a single nil if nothing is provided |
246 | kNilSentinel.pushKey(L_); | 223 | kNilSentinel.pushKey(L_); |
247 | } | 224 | } else { |
248 | else | ||
249 | { | ||
250 | raise_luaL_error(L_, "no data to send"); | 225 | raise_luaL_error(L_, "no data to send"); |
251 | } | 226 | } |
252 | } | 227 | } |
@@ -264,24 +239,20 @@ LUAG_FUNC(linda_send) | |||
264 | return 0; | 239 | return 0; |
265 | 240 | ||
266 | STACK_CHECK_START_REL(KL, 0); | 241 | STACK_CHECK_START_REL(KL, 0); |
267 | for (bool try_again{ true };;) | 242 | for (bool try_again{ true };;) { |
268 | { | 243 | if (lane != nullptr) { |
269 | if (lane != nullptr) | ||
270 | { | ||
271 | cancel = lane->cancel_request; | 244 | cancel = lane->cancel_request; |
272 | } | 245 | } |
273 | cancel = (cancel != CancelRequest::None) ? cancel : linda->simulate_cancel; | 246 | cancel = (cancel != CancelRequest::None) ? cancel : linda->simulate_cancel; |
274 | // if user wants to cancel, or looped because of a timeout, the call returns without sending anything | 247 | // if user wants to cancel, or looped because of a timeout, the call returns without sending anything |
275 | if (!try_again || cancel != CancelRequest::None) | 248 | if (!try_again || cancel != CancelRequest::None) { |
276 | { | ||
277 | pushed.emplace(0); | 249 | pushed.emplace(0); |
278 | break; | 250 | break; |
279 | } | 251 | } |
280 | 252 | ||
281 | STACK_CHECK(KL, 0); | 253 | STACK_CHECK(KL, 0); |
282 | pushed = keeper_call(linda->U, KL, KEEPER_API(send), L_, linda, key_i); | 254 | pushed = keeper_call(linda->U, KL, KEEPER_API(send), L_, linda, key_i); |
283 | if (!pushed.has_value()) | 255 | if (!pushed.has_value()) { |
284 | { | ||
285 | break; | 256 | break; |
286 | } | 257 | } |
287 | LUA_ASSERT(L_, pushed.value() == 1); | 258 | LUA_ASSERT(L_, pushed.value() == 1); |
@@ -289,26 +260,23 @@ LUAG_FUNC(linda_send) | |||
289 | ret = lua_toboolean(L_, -1) ? true : false; | 260 | ret = lua_toboolean(L_, -1) ? true : false; |
290 | lua_pop(L_, 1); | 261 | lua_pop(L_, 1); |
291 | 262 | ||
292 | if (ret) | 263 | if (ret) { |
293 | { | ||
294 | // Wake up ALL waiting threads | 264 | // Wake up ALL waiting threads |
295 | linda->m_write_happened.notify_all(); | 265 | linda->m_write_happened.notify_all(); |
296 | break; | 266 | break; |
297 | } | 267 | } |
298 | 268 | ||
299 | // instant timout to bypass the wait syscall | 269 | // instant timout to bypass the wait syscall |
300 | if (std::chrono::steady_clock::now() >= until) | 270 | if (std::chrono::steady_clock::now() >= until) { |
301 | { | ||
302 | break; /* no wait; instant timeout */ | 271 | break; /* no wait; instant timeout */ |
303 | } | 272 | } |
304 | 273 | ||
305 | // storage limit hit, wait until timeout or signalled that we should try again | 274 | // storage limit hit, wait until timeout or signalled that we should try again |
306 | { | 275 | { |
307 | Lane::Status prev_status{ Lane::Error }; // prevent 'might be used uninitialized' warnings | 276 | Lane::Status prev_status{ Lane::Error }; // prevent 'might be used uninitialized' warnings |
308 | if (lane != nullptr) | 277 | if (lane != nullptr) { |
309 | { | ||
310 | // change status of lane to "waiting" | 278 | // change status of lane to "waiting" |
311 | prev_status = lane->m_status; // Running, most likely | 279 | prev_status = lane->m_status; // Running, most likely |
312 | LUA_ASSERT(L_, prev_status == Lane::Running); // but check, just in case | 280 | LUA_ASSERT(L_, prev_status == Lane::Running); // but check, just in case |
313 | lane->m_status = Lane::Waiting; | 281 | lane->m_status = Lane::Waiting; |
314 | LUA_ASSERT(L_, lane->m_waiting_on == nullptr); | 282 | LUA_ASSERT(L_, lane->m_waiting_on == nullptr); |
@@ -317,10 +285,9 @@ LUAG_FUNC(linda_send) | |||
317 | // could not send because no room: wait until some data was read before trying again, or until timeout is reached | 285 | // could not send because no room: wait until some data was read before trying again, or until timeout is reached |
318 | std::unique_lock<std::mutex> keeper_lock{ K->m_mutex, std::adopt_lock }; | 286 | std::unique_lock<std::mutex> keeper_lock{ K->m_mutex, std::adopt_lock }; |
319 | std::cv_status const status{ linda->m_read_happened.wait_until(keeper_lock, until) }; | 287 | std::cv_status const status{ linda->m_read_happened.wait_until(keeper_lock, until) }; |
320 | keeper_lock.release(); // we don't want to release the lock! | 288 | keeper_lock.release(); // we don't want to release the lock! |
321 | try_again = (status == std::cv_status::no_timeout); // detect spurious wakeups | 289 | try_again = (status == std::cv_status::no_timeout); // detect spurious wakeups |
322 | if (lane != nullptr) | 290 | if (lane != nullptr) { |
323 | { | ||
324 | lane->m_waiting_on = nullptr; | 291 | lane->m_waiting_on = nullptr; |
325 | lane->m_status = prev_status; | 292 | lane->m_status = prev_status; |
326 | } | 293 | } |
@@ -329,23 +296,21 @@ LUAG_FUNC(linda_send) | |||
329 | STACK_CHECK(KL, 0); | 296 | STACK_CHECK(KL, 0); |
330 | } | 297 | } |
331 | 298 | ||
332 | if (!pushed.has_value()) | 299 | if (!pushed.has_value()) { |
333 | { | ||
334 | raise_luaL_error(L_, "tried to copy unsupported types"); | 300 | raise_luaL_error(L_, "tried to copy unsupported types"); |
335 | } | 301 | } |
336 | 302 | ||
337 | switch (cancel) | 303 | switch (cancel) { |
338 | { | 304 | case CancelRequest::Soft: |
339 | case CancelRequest::Soft: | ||
340 | // if user wants to soft-cancel, the call returns lanes.cancel_error | 305 | // if user wants to soft-cancel, the call returns lanes.cancel_error |
341 | kCancelError.pushKey(L_); | 306 | kCancelError.pushKey(L_); |
342 | return 1; | 307 | return 1; |
343 | 308 | ||
344 | case CancelRequest::Hard: | 309 | case CancelRequest::Hard: |
345 | // raise an error interrupting execution only in case of hard cancel | 310 | // raise an error interrupting execution only in case of hard cancel |
346 | raise_cancel_error(L_); // raises an error and doesn't return | 311 | raise_cancel_error(L_); // raises an error and doesn't return |
347 | 312 | ||
348 | default: | 313 | default: |
349 | lua_pushboolean(L_, ret); // true (success) or false (timeout) | 314 | lua_pushboolean(L_, ret); // true (success) or false (timeout) |
350 | return 1; | 315 | return 1; |
351 | } | 316 | } |
@@ -368,23 +333,18 @@ LUAG_FUNC(linda_send) | |||
368 | */ | 333 | */ |
369 | LUAG_FUNC(linda_receive) | 334 | LUAG_FUNC(linda_receive) |
370 | { | 335 | { |
371 | auto receive = [](lua_State* L_) | 336 | auto receive = [](lua_State* L_) { |
372 | { | ||
373 | Linda* const linda{ ToLinda<false>(L_, 1) }; | 337 | 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() }; | 338 | 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 | 339 | int key_i{ 2 }; // index of first key, if timeout not there |
376 | 340 | ||
377 | if (lua_type(L_, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion | 341 | if (lua_type(L_, 2) == LUA_TNUMBER) { // we don't want to use lua_isnumber() because of autocoercion |
378 | { | ||
379 | lua_Duration const duration{ lua_tonumber(L_, 2) }; | 342 | lua_Duration const duration{ lua_tonumber(L_, 2) }; |
380 | if (duration.count() >= 0.0) | 343 | if (duration.count() >= 0.0) { |
381 | { | ||
382 | until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration); | 344 | until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration); |
383 | } | 345 | } |
384 | ++key_i; | 346 | ++key_i; |
385 | } | 347 | } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key |
386 | else if (lua_isnil(L_, 2)) // alternate explicit "infinite timeout" by passing nil before the key | ||
387 | { | ||
388 | ++key_i; | 348 | ++key_i; |
389 | } | 349 | } |
390 | 350 | ||
@@ -394,8 +354,7 @@ LUAG_FUNC(linda_receive) | |||
394 | kLindaBatched.pushKey(L_); | 354 | kLindaBatched.pushKey(L_); |
395 | int const is_batched{ lua501_equal(L_, key_i, -1) }; | 355 | int const is_batched{ lua501_equal(L_, key_i, -1) }; |
396 | lua_pop(L_, 1); | 356 | lua_pop(L_, 1); |
397 | if (is_batched) | 357 | if (is_batched) { |
398 | { | ||
399 | // no need to pass linda.batched in the keeper state | 358 | // no need to pass linda.batched in the keeper state |
400 | ++key_i; | 359 | ++key_i; |
401 | // make sure the keys are of a valid type | 360 | // make sure the keys are of a valid type |
@@ -408,13 +367,10 @@ LUAG_FUNC(linda_receive) | |||
408 | // don't forget to count the key in addition to the values | 367 | // don't forget to count the key in addition to the values |
409 | ++expected_pushed_min; | 368 | ++expected_pushed_min; |
410 | ++expected_pushed_max; | 369 | ++expected_pushed_max; |
411 | if (expected_pushed_min > expected_pushed_max) | 370 | if (expected_pushed_min > expected_pushed_max) { |
412 | { | ||
413 | raise_luaL_error(L_, "batched min/max error"); | 371 | raise_luaL_error(L_, "batched min/max error"); |
414 | } | 372 | } |
415 | } | 373 | } else { |
416 | else | ||
417 | { | ||
418 | // make sure the keys are of a valid type | 374 | // make sure the keys are of a valid type |
419 | check_key_types(L_, key_i, lua_gettop(L_)); | 375 | check_key_types(L_, key_i, lua_gettop(L_)); |
420 | // receive a single value, checking multiple slots | 376 | // receive a single value, checking multiple slots |
@@ -432,28 +388,23 @@ LUAG_FUNC(linda_receive) | |||
432 | CancelRequest cancel{ CancelRequest::None }; | 388 | CancelRequest cancel{ CancelRequest::None }; |
433 | KeeperCallResult pushed; | 389 | KeeperCallResult pushed; |
434 | STACK_CHECK_START_REL(KL, 0); | 390 | STACK_CHECK_START_REL(KL, 0); |
435 | for (bool try_again{ true };;) | 391 | for (bool try_again{ true };;) { |
436 | { | 392 | if (lane != nullptr) { |
437 | if (lane != nullptr) | ||
438 | { | ||
439 | cancel = lane->cancel_request; | 393 | cancel = lane->cancel_request; |
440 | } | 394 | } |
441 | cancel = (cancel != CancelRequest::None) ? cancel : linda->simulate_cancel; | 395 | cancel = (cancel != CancelRequest::None) ? cancel : linda->simulate_cancel; |
442 | // if user wants to cancel, or looped because of a timeout, the call returns without sending anything | 396 | // if user wants to cancel, or looped because of a timeout, the call returns without sending anything |
443 | if (!try_again || cancel != CancelRequest::None) | 397 | if (!try_again || cancel != CancelRequest::None) { |
444 | { | ||
445 | pushed.emplace(0); | 398 | pushed.emplace(0); |
446 | break; | 399 | break; |
447 | } | 400 | } |
448 | 401 | ||
449 | // all arguments of receive() but the first are passed to the keeper's receive function | 402 | // 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); | 403 | pushed = keeper_call(linda->U, KL, selected_keeper_receive, L_, linda, key_i); |
451 | if (!pushed.has_value()) | 404 | if (!pushed.has_value()) { |
452 | { | ||
453 | break; | 405 | break; |
454 | } | 406 | } |
455 | if (pushed.value() > 0) | 407 | if (pushed.value() > 0) { |
456 | { | ||
457 | LUA_ASSERT(L_, pushed.value() >= expected_pushed_min && pushed.value() <= expected_pushed_max); | 408 | LUA_ASSERT(L_, pushed.value() >= expected_pushed_min && pushed.value() <= expected_pushed_max); |
458 | // replace sentinels with real nils | 409 | // replace sentinels with real nils |
459 | keeper_toggle_nil_sentinels(L_, lua_gettop(L_) - pushed.value(), LookupMode::FromKeeper); | 410 | keeper_toggle_nil_sentinels(L_, lua_gettop(L_) - pushed.value(), LookupMode::FromKeeper); |
@@ -463,18 +414,16 @@ LUAG_FUNC(linda_receive) | |||
463 | break; | 414 | break; |
464 | } | 415 | } |
465 | 416 | ||
466 | if (std::chrono::steady_clock::now() >= until) | 417 | if (std::chrono::steady_clock::now() >= until) { |
467 | { | ||
468 | break; /* instant timeout */ | 418 | break; /* instant timeout */ |
469 | } | 419 | } |
470 | 420 | ||
471 | // nothing received, wait until timeout or signalled that we should try again | 421 | // nothing received, wait until timeout or signalled that we should try again |
472 | { | 422 | { |
473 | Lane::Status prev_status{ Lane::Error }; // prevent 'might be used uninitialized' warnings | 423 | Lane::Status prev_status{ Lane::Error }; // prevent 'might be used uninitialized' warnings |
474 | if (lane != nullptr) | 424 | if (lane != nullptr) { |
475 | { | ||
476 | // change status of lane to "waiting" | 425 | // change status of lane to "waiting" |
477 | prev_status = lane->m_status; // Running, most likely | 426 | prev_status = lane->m_status; // Running, most likely |
478 | LUA_ASSERT(L_, prev_status == Lane::Running); // but check, just in case | 427 | LUA_ASSERT(L_, prev_status == Lane::Running); // but check, just in case |
479 | lane->m_status = Lane::Waiting; | 428 | lane->m_status = Lane::Waiting; |
480 | LUA_ASSERT(L_, lane->m_waiting_on == nullptr); | 429 | LUA_ASSERT(L_, lane->m_waiting_on == nullptr); |
@@ -483,10 +432,9 @@ LUAG_FUNC(linda_receive) | |||
483 | // not enough data to read: wakeup when data was sent, or when timeout is reached | 432 | // not enough data to read: wakeup when data was sent, or when timeout is reached |
484 | std::unique_lock<std::mutex> keeper_lock{ K->m_mutex, std::adopt_lock }; | 433 | 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) }; | 434 | 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! | 435 | keeper_lock.release(); // we don't want to release the lock! |
487 | try_again = (status == std::cv_status::no_timeout); // detect spurious wakeups | 436 | try_again = (status == std::cv_status::no_timeout); // detect spurious wakeups |
488 | if (lane != nullptr) | 437 | if (lane != nullptr) { |
489 | { | ||
490 | lane->m_waiting_on = nullptr; | 438 | lane->m_waiting_on = nullptr; |
491 | lane->m_status = prev_status; | 439 | lane->m_status = prev_status; |
492 | } | 440 | } |
@@ -494,23 +442,21 @@ LUAG_FUNC(linda_receive) | |||
494 | } | 442 | } |
495 | STACK_CHECK(KL, 0); | 443 | STACK_CHECK(KL, 0); |
496 | 444 | ||
497 | if (!pushed.has_value()) | 445 | if (!pushed.has_value()) { |
498 | { | ||
499 | raise_luaL_error(L_, "tried to copy unsupported types"); | 446 | raise_luaL_error(L_, "tried to copy unsupported types"); |
500 | } | 447 | } |
501 | 448 | ||
502 | switch (cancel) | 449 | switch (cancel) { |
503 | { | 450 | case CancelRequest::Soft: |
504 | case CancelRequest::Soft: | ||
505 | // if user wants to soft-cancel, the call returns kCancelError | 451 | // if user wants to soft-cancel, the call returns kCancelError |
506 | kCancelError.pushKey(L_); | 452 | kCancelError.pushKey(L_); |
507 | return 1; | 453 | return 1; |
508 | 454 | ||
509 | case CancelRequest::Hard: | 455 | case CancelRequest::Hard: |
510 | // raise an error interrupting execution only in case of hard cancel | 456 | // raise an error interrupting execution only in case of hard cancel |
511 | raise_cancel_error(L_); // raises an error and doesn't return | 457 | raise_cancel_error(L_); // raises an error and doesn't return |
512 | 458 | ||
513 | default: | 459 | default: |
514 | return pushed.value(); | 460 | return pushed.value(); |
515 | } | 461 | } |
516 | }; | 462 | }; |
@@ -520,17 +466,16 @@ LUAG_FUNC(linda_receive) | |||
520 | // ################################################################################################# | 466 | // ################################################################################################# |
521 | 467 | ||
522 | /* | 468 | /* |
523 | * [true|lanes.cancel_error] = linda_set( linda_ud, key_num|str|bool|lightuserdata [, value [, ...]]) | 469 | * [true|lanes.cancel_error] = linda_set( linda_ud, key_num|str|bool|lightuserdata [, value [, ...]]) |
524 | * | 470 | * |
525 | * Set one or more value to Linda. | 471 | * Set one or more value to Linda. |
526 | * TODO: what do we do if we set to non-nil and limit is 0? | 472 | * TODO: what do we do if we set to non-nil and limit is 0? |
527 | * | 473 | * |
528 | * Existing slot value is replaced, and possible queued entries removed. | 474 | * Existing slot value is replaced, and possible queued entries removed. |
529 | */ | 475 | */ |
530 | LUAG_FUNC(linda_set) | 476 | LUAG_FUNC(linda_set) |
531 | { | 477 | { |
532 | auto set = [](lua_State* L_) | 478 | auto set = [](lua_State* L_) { |
533 | { | ||
534 | Linda* const linda{ ToLinda<false>(L_, 1) }; | 479 | Linda* const linda{ ToLinda<false>(L_, 1) }; |
535 | bool const has_value{ lua_gettop(L_) > 2 }; | 480 | bool const has_value{ lua_gettop(L_) > 2 }; |
536 | // make sure the key is of a valid type (throws an error if not the case) | 481 | // make sure the key is of a valid type (throws an error if not the case) |
@@ -538,33 +483,26 @@ LUAG_FUNC(linda_set) | |||
538 | 483 | ||
539 | Keeper* const K{ linda->whichKeeper() }; | 484 | Keeper* const K{ linda->whichKeeper() }; |
540 | KeeperCallResult pushed; | 485 | KeeperCallResult pushed; |
541 | if (linda->simulate_cancel == CancelRequest::None) | 486 | if (linda->simulate_cancel == CancelRequest::None) { |
542 | { | 487 | if (has_value) { |
543 | if (has_value) | ||
544 | { | ||
545 | // convert nils to some special non-nil sentinel in sent values | 488 | // convert nils to some special non-nil sentinel in sent values |
546 | keeper_toggle_nil_sentinels(L_, 3, LookupMode::ToKeeper); | 489 | keeper_toggle_nil_sentinels(L_, 3, LookupMode::ToKeeper); |
547 | } | 490 | } |
548 | pushed = keeper_call(linda->U, K->L, KEEPER_API(set), L_, linda, 2); | 491 | pushed = keeper_call(linda->U, K->L, KEEPER_API(set), L_, linda, 2); |
549 | if (pushed.has_value()) // no error? | 492 | if (pushed.has_value()) { // no error? |
550 | { | ||
551 | LUA_ASSERT(L_, pushed.value() == 0 || pushed.value() == 1); | 493 | LUA_ASSERT(L_, pushed.value() == 0 || pushed.value() == 1); |
552 | 494 | ||
553 | if (has_value) | 495 | if (has_value) { |
554 | { | ||
555 | // we put some data in the slot, tell readers that they should wake | 496 | // we put some data in the slot, tell readers that they should wake |
556 | linda->m_write_happened.notify_all(); // To be done from within the 'K' locking area | 497 | linda->m_write_happened.notify_all(); // To be done from within the 'K' locking area |
557 | } | 498 | } |
558 | if (pushed.value() == 1) | 499 | if (pushed.value() == 1) { |
559 | { | ||
560 | // the key was full, but it is no longer the case, tell writers they should wake | 500 | // the key was full, but it is no longer the case, tell writers they should wake |
561 | LUA_ASSERT(L_, lua_type(L_, -1) == LUA_TBOOLEAN && lua_toboolean(L_, -1) == 1); | 501 | LUA_ASSERT(L_, lua_type(L_, -1) == LUA_TBOOLEAN && lua_toboolean(L_, -1) == 1); |
562 | linda->m_read_happened.notify_all(); // To be done from within the 'K' locking area | 502 | linda->m_read_happened.notify_all(); // To be done from within the 'K' locking area |
563 | } | 503 | } |
564 | } | 504 | } |
565 | } | 505 | } else { // linda is cancelled |
566 | else // linda is cancelled | ||
567 | { | ||
568 | // do nothing and return lanes.cancel_error | 506 | // do nothing and return lanes.cancel_error |
569 | kCancelError.pushKey(L_); | 507 | kCancelError.pushKey(L_); |
570 | pushed.emplace(1); | 508 | pushed.emplace(1); |
@@ -585,8 +523,7 @@ LUAG_FUNC(linda_set) | |||
585 | */ | 523 | */ |
586 | LUAG_FUNC(linda_count) | 524 | LUAG_FUNC(linda_count) |
587 | { | 525 | { |
588 | auto count = [](lua_State* L_) | 526 | auto count = [](lua_State* L_) { |
589 | { | ||
590 | Linda* const linda{ ToLinda<false>(L_, 1) }; | 527 | Linda* const linda{ ToLinda<false>(L_, 1) }; |
591 | // make sure the keys are of a valid type | 528 | // make sure the keys are of a valid type |
592 | check_key_types(L_, 2, lua_gettop(L_)); | 529 | check_key_types(L_, 2, lua_gettop(L_)); |
@@ -601,14 +538,13 @@ LUAG_FUNC(linda_count) | |||
601 | // ################################################################################################# | 538 | // ################################################################################################# |
602 | 539 | ||
603 | /* | 540 | /* |
604 | * [val [, ...]] = linda_get( linda_ud, key_num|str|bool|lightuserdata [, count = 1]) | 541 | * [val [, ...]] = linda_get( linda_ud, key_num|str|bool|lightuserdata [, count = 1]) |
605 | * | 542 | * |
606 | * Get one or more values from Linda. | 543 | * Get one or more values from Linda. |
607 | */ | 544 | */ |
608 | LUAG_FUNC(linda_get) | 545 | LUAG_FUNC(linda_get) |
609 | { | 546 | { |
610 | auto get = [](lua_State* L_) | 547 | auto get = [](lua_State* L_) { |
611 | { | ||
612 | Linda* const linda{ ToLinda<false>(L_, 1) }; | 548 | Linda* const linda{ ToLinda<false>(L_, 1) }; |
613 | lua_Integer const count{ luaL_optinteger(L_, 3, 1) }; | 549 | lua_Integer const count{ luaL_optinteger(L_, 3, 1) }; |
614 | luaL_argcheck(L_, count >= 1, 3, "count should be >= 1"); | 550 | luaL_argcheck(L_, count >= 1, 3, "count should be >= 1"); |
@@ -617,17 +553,13 @@ LUAG_FUNC(linda_get) | |||
617 | check_key_types(L_, 2, 2); | 553 | check_key_types(L_, 2, 2); |
618 | 554 | ||
619 | KeeperCallResult pushed; | 555 | KeeperCallResult pushed; |
620 | if (linda->simulate_cancel == CancelRequest::None) | 556 | if (linda->simulate_cancel == CancelRequest::None) { |
621 | { | ||
622 | Keeper* const K{ linda->whichKeeper() }; | 557 | Keeper* const K{ linda->whichKeeper() }; |
623 | pushed = keeper_call(linda->U, K->L, KEEPER_API(get), L_, linda, 2); | 558 | pushed = keeper_call(linda->U, K->L, KEEPER_API(get), L_, linda, 2); |
624 | if (pushed.value_or(0) > 0) | 559 | if (pushed.value_or(0) > 0) { |
625 | { | ||
626 | keeper_toggle_nil_sentinels(L_, lua_gettop(L_) - pushed.value(), LookupMode::FromKeeper); | 560 | keeper_toggle_nil_sentinels(L_, lua_gettop(L_) - pushed.value(), LookupMode::FromKeeper); |
627 | } | 561 | } |
628 | } | 562 | } else { // linda is cancelled |
629 | else // linda is cancelled | ||
630 | { | ||
631 | // do nothing and return lanes.cancel_error | 563 | // do nothing and return lanes.cancel_error |
632 | kCancelError.pushKey(L_); | 564 | kCancelError.pushKey(L_); |
633 | pushed.emplace(1); | 565 | pushed.emplace(1); |
@@ -641,37 +573,32 @@ LUAG_FUNC(linda_get) | |||
641 | // ################################################################################################# | 573 | // ################################################################################################# |
642 | 574 | ||
643 | /* | 575 | /* |
644 | * [true] = linda_limit( linda_ud, key_num|str|bool|lightuserdata, int) | 576 | * [true] = linda_limit( linda_ud, key_num|str|bool|lightuserdata, int) |
645 | * | 577 | * |
646 | * Set limit to 1 Linda keys. | 578 | * Set limit to 1 Linda keys. |
647 | * Optionally wake threads waiting to write on the linda, in case the limit enables them to do so | 579 | * Optionally wake threads waiting to write on the linda, in case the limit enables them to do so |
648 | */ | 580 | */ |
649 | LUAG_FUNC(linda_limit) | 581 | LUAG_FUNC(linda_limit) |
650 | { | 582 | { |
651 | auto limit = [](lua_State* L_) | 583 | auto limit = [](lua_State* L_) { |
652 | { | ||
653 | Linda* const linda{ ToLinda<false>(L_, 1) }; | 584 | Linda* const linda{ ToLinda<false>(L_, 1) }; |
654 | // make sure we got 3 arguments: the linda, a key and a limit | 585 | // make sure we got 3 arguments: the linda, a key and a limit |
655 | luaL_argcheck( L_, lua_gettop( L_) == 3, 2, "wrong number of arguments"); | 586 | luaL_argcheck(L_, lua_gettop(L_) == 3, 2, "wrong number of arguments"); |
656 | // make sure we got a numeric limit | 587 | // make sure we got a numeric limit |
657 | luaL_checknumber( L_, 3); | 588 | luaL_checknumber(L_, 3); |
658 | // make sure the key is of a valid type | 589 | // make sure the key is of a valid type |
659 | check_key_types( L_, 2, 2); | 590 | check_key_types(L_, 2, 2); |
660 | 591 | ||
661 | KeeperCallResult pushed; | 592 | KeeperCallResult pushed; |
662 | if (linda->simulate_cancel == CancelRequest::None) | 593 | if (linda->simulate_cancel == CancelRequest::None) { |
663 | { | ||
664 | Keeper* const K{ linda->whichKeeper() }; | 594 | Keeper* const K{ linda->whichKeeper() }; |
665 | pushed = keeper_call(linda->U, K->L, KEEPER_API(limit), L_, linda, 2); | 595 | pushed = keeper_call(linda->U, K->L, KEEPER_API(limit), L_, linda, 2); |
666 | LUA_ASSERT(L_, pushed.has_value() && (pushed.value() == 0 || pushed.value() == 1)); // no error, optional boolean value saying if we should wake blocked writer threads | 596 | LUA_ASSERT(L_, pushed.has_value() && (pushed.value() == 0 || pushed.value() == 1)); // no error, optional boolean value saying if we should wake blocked writer threads |
667 | if (pushed.value() == 1) | 597 | if (pushed.value() == 1) { |
668 | { | 598 | LUA_ASSERT(L_, lua_type(L_, -1) == LUA_TBOOLEAN && lua_toboolean(L_, -1) == 1); |
669 | LUA_ASSERT(L_, lua_type( L_, -1) == LUA_TBOOLEAN && lua_toboolean( L_, -1) == 1); | ||
670 | linda->m_read_happened.notify_all(); // To be done from within the 'K' locking area | 599 | linda->m_read_happened.notify_all(); // To be done from within the 'K' locking area |
671 | } | 600 | } |
672 | } | 601 | } else { // linda is cancelled |
673 | else // linda is cancelled | ||
674 | { | ||
675 | // do nothing and return lanes.cancel_error | 602 | // do nothing and return lanes.cancel_error |
676 | kCancelError.pushKey(L_); | 603 | kCancelError.pushKey(L_); |
677 | pushed.emplace(1); | 604 | pushed.emplace(1); |
@@ -685,10 +612,10 @@ LUAG_FUNC(linda_limit) | |||
685 | // ################################################################################################# | 612 | // ################################################################################################# |
686 | 613 | ||
687 | /* | 614 | /* |
688 | * (void) = linda_cancel( linda_ud, "read"|"write"|"both"|"none") | 615 | * (void) = linda_cancel( linda_ud, "read"|"write"|"both"|"none") |
689 | * | 616 | * |
690 | * Signal linda so that waiting threads wake up as if their own lane was cancelled | 617 | * Signal linda so that waiting threads wake up as if their own lane was cancelled |
691 | */ | 618 | */ |
692 | LUAG_FUNC(linda_cancel) | 619 | LUAG_FUNC(linda_cancel) |
693 | { | 620 | { |
694 | Linda* const linda{ ToLinda<false>(L_, 1) }; | 621 | Linda* const linda{ ToLinda<false>(L_, 1) }; |
@@ -697,25 +624,16 @@ LUAG_FUNC(linda_cancel) | |||
697 | luaL_argcheck(L_, lua_gettop(L_) <= 2, 2, "wrong number of arguments"); | 624 | luaL_argcheck(L_, lua_gettop(L_) <= 2, 2, "wrong number of arguments"); |
698 | 625 | ||
699 | linda->simulate_cancel = CancelRequest::Soft; | 626 | linda->simulate_cancel = CancelRequest::Soft; |
700 | if (strcmp(who, "both") == 0) // tell everyone writers to wake up | 627 | if (strcmp(who, "both") == 0) { // tell everyone writers to wake up |
701 | { | ||
702 | linda->m_write_happened.notify_all(); | 628 | linda->m_write_happened.notify_all(); |
703 | linda->m_read_happened.notify_all(); | 629 | linda->m_read_happened.notify_all(); |
704 | } | 630 | } else if (strcmp(who, "none") == 0) { // reset flag |
705 | else if (strcmp(who, "none") == 0) // reset flag | ||
706 | { | ||
707 | linda->simulate_cancel = CancelRequest::None; | 631 | linda->simulate_cancel = CancelRequest::None; |
708 | } | 632 | } else if (strcmp(who, "read") == 0) { // tell blocked readers to wake up |
709 | else if (strcmp(who, "read") == 0) // tell blocked readers to wake up | ||
710 | { | ||
711 | linda->m_write_happened.notify_all(); | 633 | linda->m_write_happened.notify_all(); |
712 | } | 634 | } else if (strcmp(who, "write") == 0) { // tell blocked writers to wake up |
713 | else if (strcmp(who, "write") == 0) // tell blocked writers to wake up | ||
714 | { | ||
715 | linda->m_read_happened.notify_all(); | 635 | linda->m_read_happened.notify_all(); |
716 | } | 636 | } else { |
717 | else | ||
718 | { | ||
719 | raise_luaL_error(L_, "unknown wake hint '%s'", who); | 637 | raise_luaL_error(L_, "unknown wake hint '%s'", who); |
720 | } | 638 | } |
721 | return 0; | 639 | return 0; |
@@ -724,15 +642,15 @@ LUAG_FUNC(linda_cancel) | |||
724 | // ################################################################################################# | 642 | // ################################################################################################# |
725 | 643 | ||
726 | /* | 644 | /* |
727 | * lightuserdata= linda_deep( linda_ud ) | 645 | * lightuserdata= linda_deep( linda_ud ) |
728 | * | 646 | * |
729 | * Return the 'deep' userdata pointer, identifying the Linda. | 647 | * Return the 'deep' userdata pointer, identifying the Linda. |
730 | * | 648 | * |
731 | * This is needed for using Lindas as key indices (timer system needs it); | 649 | * This is needed for using Lindas as key indices (timer system needs it); |
732 | * separately created proxies of the same underlying deep object will have | 650 | * separately created proxies of the same underlying deep object will have |
733 | * different userdata and won't be known to be essentially the same deep one | 651 | * different userdata and won't be known to be essentially the same deep one |
734 | * without this. | 652 | * without this. |
735 | */ | 653 | */ |
736 | LUAG_FUNC(linda_deep) | 654 | LUAG_FUNC(linda_deep) |
737 | { | 655 | { |
738 | Linda* const linda{ ToLinda<false>(L_, 1) }; | 656 | Linda* const linda{ ToLinda<false>(L_, 1) }; |
@@ -743,19 +661,18 @@ LUAG_FUNC(linda_deep) | |||
743 | // ################################################################################################# | 661 | // ################################################################################################# |
744 | 662 | ||
745 | /* | 663 | /* |
746 | * string = linda:__tostring( linda_ud) | 664 | * string = linda:__tostring( linda_ud) |
747 | * | 665 | * |
748 | * Return the stringification of a linda | 666 | * Return the stringification of a linda |
749 | * | 667 | * |
750 | * Useful for concatenation or debugging purposes | 668 | * Useful for concatenation or debugging purposes |
751 | */ | 669 | */ |
752 | 670 | ||
753 | template <bool OPT> | 671 | template <bool OPT> |
754 | [[nodiscard]] static int LindaToString(lua_State* L_, int idx_) | 672 | [[nodiscard]] static int LindaToString(lua_State* L_, int idx_) |
755 | { | 673 | { |
756 | Linda* const linda{ ToLinda<OPT>(L_, idx_) }; | 674 | Linda* const linda{ ToLinda<OPT>(L_, idx_) }; |
757 | if (linda != nullptr) | 675 | if (linda != nullptr) { |
758 | { | ||
759 | char text[128]; | 676 | char text[128]; |
760 | int len; | 677 | int len; |
761 | if (linda->getName()) | 678 | if (linda->getName()) |
@@ -768,6 +685,8 @@ template <bool OPT> | |||
768 | return 0; | 685 | return 0; |
769 | } | 686 | } |
770 | 687 | ||
688 | // ################################################################################################# | ||
689 | |||
771 | LUAG_FUNC(linda_tostring) | 690 | LUAG_FUNC(linda_tostring) |
772 | { | 691 | { |
773 | return LindaToString<false>(L_, 1); | 692 | return LindaToString<false>(L_, 1); |
@@ -776,28 +695,25 @@ LUAG_FUNC(linda_tostring) | |||
776 | // ################################################################################################# | 695 | // ################################################################################################# |
777 | 696 | ||
778 | /* | 697 | /* |
779 | * string = linda:__concat( a, b) | 698 | * string = linda:__concat( a, b) |
780 | * | 699 | * |
781 | * Return the concatenation of a pair of items, one of them being a linda | 700 | * Return the concatenation of a pair of items, one of them being a linda |
782 | * | 701 | * |
783 | * Useful for concatenation or debugging purposes | 702 | * Useful for concatenation or debugging purposes |
784 | */ | 703 | */ |
785 | LUAG_FUNC(linda_concat) | 704 | LUAG_FUNC(linda_concat) |
786 | { // linda1? linda2? | 705 | { // L_: linda1? linda2? |
787 | bool atLeastOneLinda{ false }; | 706 | bool atLeastOneLinda{ false }; |
788 | // Lua semantics enforce that one of the 2 arguments is a Linda, but not necessarily both. | 707 | // Lua semantics enforce that one of the 2 arguments is a Linda, but not necessarily both. |
789 | if (LindaToString<true>(L_, 1)) | 708 | if (LindaToString<true>(L_, 1)) { |
790 | { | ||
791 | atLeastOneLinda = true; | 709 | atLeastOneLinda = true; |
792 | lua_replace(L_, 1); | 710 | lua_replace(L_, 1); |
793 | } | 711 | } |
794 | if (LindaToString<true>(L_, 2)) | 712 | if (LindaToString<true>(L_, 2)) { |
795 | { | ||
796 | atLeastOneLinda = true; | 713 | atLeastOneLinda = true; |
797 | lua_replace(L_, 2); | 714 | lua_replace(L_, 2); |
798 | } | 715 | } |
799 | if (!atLeastOneLinda) // should not be possible | 716 | if (!atLeastOneLinda) { // should not be possible |
800 | { | ||
801 | raise_luaL_error(L_, "internal error: linda_concat called on non-Linda"); | 717 | raise_luaL_error(L_, "internal error: linda_concat called on non-Linda"); |
802 | } | 718 | } |
803 | lua_concat(L_, 2); | 719 | lua_concat(L_, 2); |
@@ -812,8 +728,7 @@ LUAG_FUNC(linda_concat) | |||
812 | */ | 728 | */ |
813 | LUAG_FUNC(linda_dump) | 729 | LUAG_FUNC(linda_dump) |
814 | { | 730 | { |
815 | auto dump = [](lua_State* L_) | 731 | auto dump = [](lua_State* L_) { |
816 | { | ||
817 | Linda* const linda{ ToLinda<false>(L_, 1) }; | 732 | Linda* const linda{ ToLinda<false>(L_, 1) }; |
818 | return keeper_push_linda_storage(*linda, DestState{ L_ }); | 733 | return keeper_push_linda_storage(*linda, DestState{ L_ }); |
819 | }; | 734 | }; |
@@ -830,8 +745,7 @@ LUAG_FUNC(linda_towatch) | |||
830 | { | 745 | { |
831 | Linda* const linda{ ToLinda<false>(L_, 1) }; | 746 | Linda* const linda{ ToLinda<false>(L_, 1) }; |
832 | int pushed{ keeper_push_linda_storage(*linda, DestState{ L_ }) }; | 747 | int pushed{ keeper_push_linda_storage(*linda, DestState{ L_ }) }; |
833 | if (pushed == 0) | 748 | if (pushed == 0) { |
834 | { | ||
835 | // if the linda is empty, don't return nil | 749 | // if the linda is empty, don't return nil |
836 | pushed = LindaToString<false>(L_, 1); | 750 | pushed = LindaToString<false>(L_, 1); |
837 | } | 751 | } |
@@ -872,13 +786,10 @@ LUAG_FUNC(linda) | |||
872 | { | 786 | { |
873 | int const top{ lua_gettop(L_) }; | 787 | int const top{ lua_gettop(L_) }; |
874 | luaL_argcheck(L_, top <= 2, top, "too many arguments"); | 788 | luaL_argcheck(L_, top <= 2, top, "too many arguments"); |
875 | if (top == 1) | 789 | if (top == 1) { |
876 | { | ||
877 | LuaType const t{ lua_type_as_enum(L_, 1) }; | 790 | LuaType const t{ lua_type_as_enum(L_, 1) }; |
878 | luaL_argcheck(L_, t == LuaType::STRING || t == LuaType::NUMBER, 1, "wrong parameter (should be a string or a number)"); | 791 | luaL_argcheck(L_, t == LuaType::STRING || t == LuaType::NUMBER, 1, "wrong parameter (should be a string or a number)"); |
879 | } | 792 | } else if (top == 2) { |
880 | else if (top == 2) | ||
881 | { | ||
882 | luaL_checktype(L_, 1, LUA_TSTRING); | 793 | luaL_checktype(L_, 1, LUA_TSTRING); |
883 | luaL_checktype(L_, 2, LUA_TNUMBER); | 794 | luaL_checktype(L_, 2, LUA_TNUMBER); |
884 | } | 795 | } |