1 // sol3 2 3 // The MIT License (MIT) 4 5 // Copyright (c) 2013-2021 Rapptz, ThePhD and contributors 6 7 // Permission is hereby granted, free of charge, to any person obtaining a copy of 8 // this software and associated documentation files (the "Software"), to deal in 9 // the Software without restriction, including without limitation the rights to 10 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 // the Software, and to permit persons to whom the Software is furnished to do so, 12 // subject to the following conditions: 13 14 // The above copyright notice and this permission notice shall be included in all 15 // copies or substantial portions of the Software. 16 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24 #ifndef SOL_REFERENCE_HPP 25 #define SOL_REFERENCE_HPP 26 27 #include <sol/types.hpp> 28 #include <sol/stack_reference.hpp> 29 30 #include <functional> 31 32 namespace sol { 33 namespace detail { __anon89e9424c0102null34 inline const char (&default_main_thread_name())[9] { 35 static const char name[9] = "sol.\xF0\x9F\x93\x8C"; 36 return name; 37 } 38 } // namespace detail 39 40 namespace stack { remove(lua_State * L_,int rawindex,int count)41 inline void remove(lua_State* L_, int rawindex, int count) { 42 if (count < 1) 43 return; 44 int top = lua_gettop(L_); 45 if (top < 1) { 46 return; 47 } 48 if (rawindex == -count || top == rawindex) { 49 // Slice them right off the top 50 lua_pop(L_, static_cast<int>(count)); 51 return; 52 } 53 54 // Remove each item one at a time using stack operations 55 // Probably slower, maybe, haven't benchmarked, 56 // but necessary 57 int index = lua_absindex(L_, rawindex); 58 if (index < 0) { 59 index = lua_gettop(L_) + (index + 1); 60 } 61 int last = index + count; 62 for (int i = index; i < last; ++i) { 63 lua_remove(L_, index); 64 } 65 } 66 67 struct push_popper_at { 68 lua_State* L; 69 int index; 70 int count; push_popper_atsol::stack::push_popper_at71 push_popper_at(lua_State* L_, int index_ = -1, int count_ = 1) : L(L_), index(index_), count(count_) { 72 } ~push_popper_atsol::stack::push_popper_at73 ~push_popper_at() { 74 remove(L, index, count); 75 } 76 }; 77 78 template <bool top_level> 79 struct push_popper_n { 80 lua_State* L; 81 int pop_count; push_popper_nsol::stack::push_popper_n82 push_popper_n(lua_State* L_, int pop_count_) : L(L_), pop_count(pop_count_) { 83 } 84 push_popper_n(const push_popper_n&) = delete; 85 push_popper_n(push_popper_n&&) = default; 86 push_popper_n& operator=(const push_popper_n&) = delete; 87 push_popper_n& operator=(push_popper_n&&) = default; ~push_popper_nsol::stack::push_popper_n88 ~push_popper_n() { 89 lua_pop(L, pop_count); 90 } 91 }; 92 93 template <> 94 struct push_popper_n<true> { push_popper_nsol::stack::push_popper_n95 push_popper_n(lua_State*, int) { 96 } 97 }; 98 99 template <bool, typename T, typename = void> 100 struct push_popper { 101 using Tu = meta::unqualified_t<T>; 102 T m_object; 103 int m_index; 104 push_poppersol::stack::push_popper105 push_popper(T object_) noexcept : m_object(object_), m_index(lua_absindex(m_object.lua_state(), -m_object.push())) { 106 } 107 index_ofsol::stack::push_popper108 int index_of(const Tu&) const noexcept { 109 return m_index; 110 } 111 ~push_poppersol::stack::push_popper112 ~push_popper() { 113 m_object.pop(); 114 } 115 }; 116 117 template <typename T, typename C> 118 struct push_popper<true, T, C> { 119 using Tu = meta::unqualified_t<T>; 120 push_poppersol::stack::push_popper121 push_popper(T) noexcept { 122 } 123 index_ofsol::stack::push_popper124 int index_of(const Tu&) const noexcept { 125 return -1; 126 } 127 ~push_poppersol::stack::push_popper128 ~push_popper() { 129 } 130 }; 131 132 template <typename T> 133 struct push_popper<false, T, std::enable_if_t<is_stack_based_v<meta::unqualified_t<T>>>> { 134 using Tu = meta::unqualified_t<T>; 135 push_poppersol::stack::push_popper136 push_popper(T) noexcept { 137 } 138 index_ofsol::stack::push_popper139 int index_of(const Tu& object_) const noexcept { 140 return object_.stack_index(); 141 } 142 ~push_poppersol::stack::push_popper143 ~push_popper() { 144 } 145 }; 146 147 template <bool, typename T, typename = void> 148 struct stateless_push_popper { 149 using Tu = meta::unqualified_t<T>; 150 lua_State* m_L; 151 T m_object; 152 int m_index; 153 stateless_push_poppersol::stack::stateless_push_popper154 stateless_push_popper(lua_State* L_, T object_) noexcept : m_L(L_), m_object(object_), m_index(lua_absindex(m_L, -m_object.push(m_L))) { 155 } 156 index_ofsol::stack::stateless_push_popper157 int index_of(const Tu&) const noexcept { 158 return m_index; 159 } 160 ~stateless_push_poppersol::stack::stateless_push_popper161 ~stateless_push_popper() { 162 m_object.pop(m_L); 163 } 164 }; 165 166 template <typename T, typename C> 167 struct stateless_push_popper<true, T, C> { 168 using Tu = meta::unqualified_t<T>; 169 stateless_push_poppersol::stack::stateless_push_popper170 stateless_push_popper(lua_State*, T) noexcept { 171 } 172 index_ofsol::stack::stateless_push_popper173 int index_of(lua_State*, const Tu&) const noexcept { 174 return -1; 175 } 176 ~stateless_push_poppersol::stack::stateless_push_popper177 ~stateless_push_popper() { 178 } 179 }; 180 181 template <typename T> 182 struct stateless_push_popper<false, T, std::enable_if_t<is_stack_based_v<meta::unqualified_t<T>>>> { 183 using Tu = meta::unqualified_t<T>; 184 lua_State* m_L; 185 stateless_push_poppersol::stack::stateless_push_popper186 stateless_push_popper(lua_State* L_, T) noexcept : m_L(L_) { 187 } 188 index_ofsol::stack::stateless_push_popper189 int index_of(const Tu& object_) const noexcept { 190 return object_.stack_index(); 191 } 192 ~stateless_push_poppersol::stack::stateless_push_popper193 ~stateless_push_popper() { 194 } 195 }; 196 197 template <bool top_level = false, typename T> push_pop(T && x)198 push_popper<top_level, T> push_pop(T&& x) { 199 return push_popper<top_level, T>(std::forward<T>(x)); 200 } 201 202 template <bool top_level = false, typename T> push_pop(lua_State * L_,T && object_)203 stateless_push_popper<top_level, T> push_pop(lua_State* L_, T&& object_) { 204 return stateless_push_popper<top_level, T>(L_, std::forward<T>(object_)); 205 } 206 207 template <typename T> push_pop_at(T && object_)208 push_popper_at push_pop_at(T&& object_) { 209 int push_count = object_.push(); 210 lua_State* L = object_.lua_state(); 211 return push_popper_at(L, lua_absindex(L, -push_count), push_count); 212 } 213 214 template <bool top_level = false> pop_n(lua_State * L_,int pop_count_)215 push_popper_n<top_level> pop_n(lua_State* L_, int pop_count_) { 216 return push_popper_n<top_level>(L_, pop_count_); 217 } 218 } // namespace stack 219 main_thread(lua_State * L_,lua_State * backup_if_unsupported_=nullptr)220 inline lua_State* main_thread(lua_State* L_, lua_State* backup_if_unsupported_ = nullptr) { 221 #if SOL_LUA_VESION_I_ < 502 222 if (L_ == nullptr) 223 return backup_if_unsupported_; 224 lua_getglobal(L_, detail::default_main_thread_name()); 225 auto pp = stack::pop_n(L_, 1); 226 if (type_of(L_, -1) == type::thread) { 227 return lua_tothread(L_, -1); 228 } 229 return backup_if_unsupported_; 230 #else 231 if (L_ == nullptr) 232 return backup_if_unsupported_; 233 lua_rawgeti(L_, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); 234 lua_State* Lmain = lua_tothread(L_, -1); 235 lua_pop(L_, 1); 236 return Lmain; 237 #endif // Lua 5.2+ has the main thread unqualified_getter 238 } 239 240 namespace detail { 241 struct no_safety_tag { 242 } inline constexpr no_safety {}; 243 244 template <bool b> pick_main_thread(lua_State * L_,lua_State * backup_if_unsupported=nullptr)245 inline lua_State* pick_main_thread(lua_State* L_, lua_State* backup_if_unsupported = nullptr) { 246 (void)L_; 247 (void)backup_if_unsupported; 248 if (b) { 249 return main_thread(L_, backup_if_unsupported); 250 } 251 return L_; 252 } 253 } // namespace detail 254 255 class stateless_reference { 256 private: 257 template <bool o_main_only> 258 friend class basic_reference; 259 260 int ref = LUA_NOREF; 261 copy_ref(lua_State * L_) const262 int copy_ref(lua_State* L_) const noexcept { 263 if (ref == LUA_NOREF) 264 return LUA_NOREF; 265 push(L_); 266 return luaL_ref(L_, LUA_REGISTRYINDEX); 267 } 268 copy_assign_ref(lua_State * L_,lua_State * rL,const stateless_reference & r)269 lua_State* copy_assign_ref(lua_State* L_, lua_State* rL, const stateless_reference& r) { 270 if (valid(L_)) { 271 deref(L_); 272 } 273 ref = r.copy_ref(L_); 274 return rL; 275 } 276 move_assign(lua_State * L_,lua_State * rL,stateless_reference && r)277 lua_State* move_assign(lua_State* L_, lua_State* rL, stateless_reference&& r) { 278 if (valid(L_)) { 279 deref(L_); 280 } 281 ref = r.ref; 282 r.ref = LUA_NOREF; 283 return rL; 284 } 285 286 protected: stack_index() const287 int stack_index() const noexcept { 288 return -1; 289 } 290 stateless_reference(lua_State * L_,global_tag_t)291 stateless_reference(lua_State* L_, global_tag_t) noexcept { 292 #if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) 293 luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); 294 #endif // make sure stack doesn't overflow 295 lua_pushglobaltable(L_); 296 ref = luaL_ref(L_, LUA_REGISTRYINDEX); 297 } 298 stateless_reference(int raw_ref_index)299 stateless_reference(int raw_ref_index) noexcept : ref(raw_ref_index) { 300 } 301 302 public: 303 stateless_reference() noexcept = default; stateless_reference(lua_nil_t)304 stateless_reference(lua_nil_t) noexcept : stateless_reference() { 305 } stateless_reference(const stack_reference & r)306 stateless_reference(const stack_reference& r) noexcept : stateless_reference(r.lua_state(), r.stack_index()) { 307 } stateless_reference(stack_reference && r)308 stateless_reference(stack_reference&& r) noexcept : stateless_reference(r.lua_state(), r.stack_index()) { 309 } stateless_reference(lua_State * L_,const stateless_reference & r)310 stateless_reference(lua_State* L_, const stateless_reference& r) noexcept { 311 if (r.ref == LUA_REFNIL) { 312 ref = LUA_REFNIL; 313 return; 314 } 315 if (r.ref == LUA_NOREF || L_ == nullptr) { 316 ref = LUA_NOREF; 317 return; 318 } 319 ref = r.copy_ref(L_); 320 } 321 stateless_reference(lua_State * L_,stateless_reference && r)322 stateless_reference(lua_State* L_, stateless_reference&& r) noexcept { 323 if (r.ref == LUA_REFNIL) { 324 ref = LUA_REFNIL; 325 return; 326 } 327 if (r.ref == LUA_NOREF || L_ == nullptr) { 328 ref = LUA_NOREF; 329 return; 330 } 331 ref = r.ref; 332 r.ref = LUA_NOREF; 333 } 334 stateless_reference(lua_State * L_,const stack_reference & r)335 stateless_reference(lua_State* L_, const stack_reference& r) noexcept { 336 if (L_ == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) { 337 ref = LUA_NOREF; 338 return; 339 } 340 if (r.get_type() == type::lua_nil) { 341 ref = LUA_REFNIL; 342 return; 343 } 344 if (L_ != r.lua_state() && !detail::xmovable(L_, r.lua_state())) { 345 return; 346 } 347 r.push(L_); 348 ref = luaL_ref(L_, LUA_REGISTRYINDEX); 349 } 350 stateless_reference(lua_State * L_,const stateless_stack_reference & r)351 stateless_reference(lua_State* L_, const stateless_stack_reference& r) noexcept : stateless_reference(L_, r.stack_index()) { 352 } 353 stateless_reference(lua_State * L_,int index=-1)354 stateless_reference(lua_State* L_, int index = -1) noexcept { 355 #if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) 356 luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); 357 #endif // make sure stack doesn't overflow 358 lua_pushvalue(L_, index); 359 ref = luaL_ref(L_, LUA_REGISTRYINDEX); 360 } stateless_reference(lua_State * L_,absolute_index index_)361 stateless_reference(lua_State* L_, absolute_index index_) noexcept : stateless_reference(L_, index_.index) { 362 } stateless_reference(lua_State * L_,ref_index index_)363 stateless_reference(lua_State* L_, ref_index index_) noexcept { 364 lua_rawgeti(L_, LUA_REGISTRYINDEX, index_.index); 365 ref = luaL_ref(L_, LUA_REGISTRYINDEX); 366 } stateless_reference(lua_State *,lua_nil_t)367 stateless_reference(lua_State*, lua_nil_t) noexcept { 368 } 369 370 ~stateless_reference() noexcept = default; 371 372 stateless_reference(const stateless_reference& o) noexcept = delete; 373 stateless_reference& operator=(const stateless_reference& r) noexcept = delete; 374 stateless_reference(stateless_reference && o)375 stateless_reference(stateless_reference&& o) noexcept : ref(o.ref) { 376 o.ref = LUA_NOREF; 377 } 378 operator =(stateless_reference && o)379 stateless_reference& operator=(stateless_reference&& o) noexcept { 380 ref = o.ref; 381 o.ref = LUA_NOREF; 382 return *this; 383 } 384 push(lua_State * L_) const385 int push(lua_State* L_) const noexcept { 386 #if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) 387 luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); 388 #endif // make sure stack doesn't overflow 389 lua_rawgeti(L_, LUA_REGISTRYINDEX, ref); 390 return 1; 391 } 392 pop(lua_State * L_,int n=1) const393 void pop(lua_State* L_, int n = 1) const noexcept { 394 lua_pop(L_, n); 395 } 396 registry_index() const397 int registry_index() const noexcept { 398 return ref; 399 } 400 reset(lua_State * L_)401 void reset(lua_State* L_) noexcept { 402 if (valid(L_)) { 403 deref(L_); 404 } 405 ref = LUA_NOREF; 406 } 407 reset(lua_State * L_,int index_)408 void reset(lua_State* L_, int index_) noexcept { 409 reset(L_); 410 #if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) 411 luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); 412 #endif // make sure stack doesn't overflow 413 lua_pushvalue(L_, index_); 414 ref = luaL_ref(L_, LUA_REGISTRYINDEX); 415 } 416 valid(lua_State *) const417 bool valid(lua_State*) const noexcept { 418 return !(ref == LUA_NOREF || ref == LUA_REFNIL); 419 } 420 pointer(lua_State * L_) const421 const void* pointer(lua_State* L_) const noexcept { 422 int si = push(L_); 423 const void* vp = lua_topointer(L_, -si); 424 lua_pop(L_, si); 425 return vp; 426 } 427 get_type(lua_State * L_) const428 type get_type(lua_State* L_) const noexcept { 429 int p = push(L_); 430 int result = lua_type(L_, -1); 431 pop(L_, p); 432 return static_cast<type>(result); 433 } 434 abandon(lua_State * =nullptr)435 void abandon(lua_State* = nullptr) { 436 ref = LUA_NOREF; 437 } 438 deref(lua_State * L_) const439 void deref(lua_State* L_) const noexcept { 440 luaL_unref(L_, LUA_REGISTRYINDEX, ref); 441 } 442 copy(lua_State * L_) const443 stateless_reference copy(lua_State* L_) const noexcept { 444 if (!valid(L_)) { 445 return {}; 446 } 447 return stateless_reference(copy_ref(L_)); 448 } 449 copy_assign(lua_State * L_,const stateless_reference & right)450 void copy_assign(lua_State* L_, const stateless_reference& right) noexcept { 451 if (valid(L_)) { 452 deref(L_); 453 } 454 if (!right.valid(L_)) { 455 return; 456 } 457 ref = right.copy_ref(L_); 458 } 459 equals(lua_State * L_,const stateless_reference & r) const460 bool equals(lua_State* L_, const stateless_reference& r) const noexcept { 461 auto ppl = stack::push_pop(L_, *this); 462 auto ppr = stack::push_pop(L_, r); 463 return lua_compare(L_, -1, -2, LUA_OPEQ) == 1; 464 } 465 equals(lua_State * L_,const stateless_stack_reference & r) const466 bool equals(lua_State* L_, const stateless_stack_reference& r) const noexcept { 467 auto ppl = stack::push_pop(L_, *this); 468 return lua_compare(L_, -1, r.stack_index(), LUA_OPEQ) == 1; 469 } 470 equals(lua_State * L_,lua_nil_t) const471 bool equals(lua_State* L_, lua_nil_t) const noexcept { 472 return valid(L_); 473 } 474 }; 475 476 template <bool main_only = false> 477 class basic_reference : public stateless_reference { 478 private: 479 template <bool o_main_only> 480 friend class basic_reference; 481 lua_State* luastate = nullptr; // non-owning 482 483 template <bool r_main_only> copy_assign_complex(const basic_reference<r_main_only> & r)484 void copy_assign_complex(const basic_reference<r_main_only>& r) { 485 if (valid()) { 486 deref(); 487 } 488 if (r.ref == LUA_REFNIL) { 489 luastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state()); 490 ref = LUA_REFNIL; 491 return; 492 } 493 if (r.ref == LUA_NOREF) { 494 luastate = r.luastate; 495 ref = LUA_NOREF; 496 return; 497 } 498 if (detail::xmovable(lua_state(), r.lua_state())) { 499 r.push(lua_state()); 500 ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); 501 return; 502 } 503 luastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state()); 504 ref = r.copy_ref(); 505 } 506 507 template <bool r_main_only> move_assign(basic_reference<r_main_only> && r)508 void move_assign(basic_reference<r_main_only>&& r) { 509 if (valid()) { 510 deref(); 511 } 512 if (r.ref == LUA_REFNIL) { 513 luastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state()); 514 ref = LUA_REFNIL; 515 return; 516 } 517 if (r.ref == LUA_NOREF) { 518 luastate = r.luastate; 519 ref = LUA_NOREF; 520 return; 521 } 522 if (detail::xmovable(lua_state(), r.lua_state())) { 523 r.push(lua_state()); 524 ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); 525 return; 526 } 527 528 luastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state()); 529 ref = r.ref; 530 r.ref = LUA_NOREF; 531 r.luastate = nullptr; 532 } 533 534 protected: basic_reference(lua_State * L_,global_tag_t)535 basic_reference(lua_State* L_, global_tag_t) noexcept : basic_reference(detail::pick_main_thread<main_only>(L_, L_), global_tag, global_tag) { 536 } 537 basic_reference(lua_State * L_,global_tag_t,global_tag_t)538 basic_reference(lua_State* L_, global_tag_t, global_tag_t) noexcept : stateless_reference(L_, global_tag), luastate(L_) { 539 } 540 basic_reference(lua_State * oL,const basic_reference<!main_only> & o)541 basic_reference(lua_State* oL, const basic_reference<!main_only>& o) noexcept : stateless_reference(oL, o), luastate(oL) { 542 } 543 deref() const544 void deref() const noexcept { 545 return stateless_reference::deref(lua_state()); 546 } 547 copy_ref() const548 int copy_ref() const noexcept { 549 return copy_ref(lua_state()); 550 } 551 copy_ref(lua_State * L_) const552 int copy_ref(lua_State* L_) const noexcept { 553 return stateless_reference::copy_ref(L_); 554 } 555 556 public: 557 basic_reference() noexcept = default; basic_reference(lua_nil_t)558 basic_reference(lua_nil_t) noexcept : basic_reference() { 559 } basic_reference(const stack_reference & r)560 basic_reference(const stack_reference& r) noexcept : basic_reference(r.lua_state(), r.stack_index()) { 561 } basic_reference(stack_reference && r)562 basic_reference(stack_reference&& r) noexcept : basic_reference(r.lua_state(), r.stack_index()) { 563 } 564 template <bool r_main_only> basic_reference(lua_State * L_,const basic_reference<r_main_only> & r)565 basic_reference(lua_State* L_, const basic_reference<r_main_only>& r) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { 566 if (r.ref == LUA_REFNIL) { 567 ref = LUA_REFNIL; 568 return; 569 } 570 if (r.ref == LUA_NOREF || lua_state() == nullptr) { 571 ref = LUA_NOREF; 572 return; 573 } 574 if (detail::xmovable(lua_state(), r.lua_state())) { 575 r.push(lua_state()); 576 ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); 577 return; 578 } 579 ref = r.copy_ref(); 580 } 581 582 template <bool r_main_only> basic_reference(lua_State * L_,basic_reference<r_main_only> && r)583 basic_reference(lua_State* L_, basic_reference<r_main_only>&& r) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { 584 if (r.ref == LUA_REFNIL) { 585 ref = LUA_REFNIL; 586 return; 587 } 588 if (r.ref == LUA_NOREF || lua_state() == nullptr) { 589 ref = LUA_NOREF; 590 return; 591 } 592 if (detail::xmovable(lua_state(), r.lua_state())) { 593 r.push(lua_state()); 594 ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); 595 return; 596 } 597 ref = r.ref; 598 r.ref = LUA_NOREF; 599 r.luastate = nullptr; 600 } 601 basic_reference(lua_State * L_,const stack_reference & r)602 basic_reference(lua_State* L_, const stack_reference& r) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { 603 if (lua_state() == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) { 604 ref = LUA_NOREF; 605 return; 606 } 607 if (r.get_type() == type::lua_nil) { 608 ref = LUA_REFNIL; 609 return; 610 } 611 if (lua_state() != r.lua_state() && !detail::xmovable(lua_state(), r.lua_state())) { 612 return; 613 } 614 r.push(lua_state()); 615 ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); 616 } basic_reference(lua_State * L_,int index=-1)617 basic_reference(lua_State* L_, int index = -1) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { 618 // use L_ to stick with that state's execution stack 619 #if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) 620 luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); 621 #endif // make sure stack doesn't overflow 622 lua_pushvalue(L_, index); 623 ref = luaL_ref(L_, LUA_REGISTRYINDEX); 624 } basic_reference(lua_State * L_,ref_index index)625 basic_reference(lua_State* L_, ref_index index) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { 626 lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, index.index); 627 ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); 628 } basic_reference(lua_State * L_,lua_nil_t)629 basic_reference(lua_State* L_, lua_nil_t) noexcept : luastate(detail::pick_main_thread<main_only>(L_, L_)) { 630 } 631 ~basic_reference()632 ~basic_reference() noexcept { 633 if (lua_state() == nullptr || ref == LUA_NOREF) 634 return; 635 deref(); 636 } 637 basic_reference(const basic_reference & o)638 basic_reference(const basic_reference& o) noexcept : stateless_reference(o.copy_ref()), luastate(o.lua_state()) { 639 } 640 basic_reference(basic_reference && o)641 basic_reference(basic_reference&& o) noexcept : stateless_reference(std::move(o)), luastate(o.lua_state()) { 642 o.luastate = nullptr; 643 } 644 basic_reference(const basic_reference<!main_only> & o)645 basic_reference(const basic_reference<!main_only>& o) noexcept 646 : basic_reference(detail::pick_main_thread<main_only>(o.lua_state(), o.lua_state()), o) { 647 } 648 basic_reference(basic_reference<!main_only> && o)649 basic_reference(basic_reference<!main_only>&& o) noexcept 650 : stateless_reference(std::move(o)), luastate(detail::pick_main_thread<main_only>(o.lua_state(), o.lua_state())) { 651 o.luastate = nullptr; 652 o.ref = LUA_NOREF; 653 } 654 operator =(basic_reference && r)655 basic_reference& operator=(basic_reference&& r) noexcept { 656 move_assign(std::move(r)); 657 return *this; 658 } 659 operator =(const basic_reference & r)660 basic_reference& operator=(const basic_reference& r) noexcept { 661 copy_assign_complex(r); 662 return *this; 663 } 664 operator =(basic_reference<!main_only> && r)665 basic_reference& operator=(basic_reference<!main_only>&& r) noexcept { 666 move_assign(std::move(r)); 667 return *this; 668 } 669 operator =(const basic_reference<!main_only> & r)670 basic_reference& operator=(const basic_reference<!main_only>& r) noexcept { 671 copy_assign_complex(r); 672 return *this; 673 } 674 operator =(const lua_nil_t &)675 basic_reference& operator=(const lua_nil_t&) noexcept { 676 reset(); 677 return *this; 678 } 679 680 template <typename Super> 681 basic_reference& operator=(proxy_base<Super>&& r); 682 683 template <typename Super> 684 basic_reference& operator=(const proxy_base<Super>& r); 685 push() const686 int push() const noexcept { 687 return push(lua_state()); 688 } 689 reset()690 void reset() noexcept { 691 stateless_reference::reset(luastate); 692 luastate = nullptr; 693 } 694 push(lua_State * L_) const695 int push(lua_State* L_) const noexcept { 696 #if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) 697 luaL_checkstack(L_, 1, "not enough Lua stack space to push this reference value"); 698 #endif // make sure stack doesn't overflow 699 if (lua_state() == nullptr) { 700 lua_pushnil(L_); 701 return 1; 702 } 703 lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, ref); 704 if (L_ != lua_state()) { 705 lua_xmove(lua_state(), L_, 1); 706 } 707 return 1; 708 } 709 pop() const710 void pop() const noexcept { 711 pop(lua_state()); 712 } 713 pop(lua_State * L_,int n=1) const714 void pop(lua_State* L_, int n = 1) const noexcept { 715 stateless_reference::pop(L_, n); 716 } 717 registry_index() const718 int registry_index() const noexcept { 719 return stateless_reference::registry_index(); 720 } 721 valid() const722 bool valid() const noexcept { 723 return stateless_reference::valid(lua_state()); 724 } 725 valid(lua_State * L_) const726 bool valid(lua_State* L_) const noexcept { 727 return stateless_reference::valid(L_); 728 } 729 pointer() const730 const void* pointer() const noexcept { 731 return stateless_reference::pointer(lua_state()); 732 } 733 operator bool() const734 explicit operator bool() const noexcept { 735 return valid(); 736 } 737 get_type() const738 type get_type() const noexcept { 739 return stateless_reference::get_type(lua_state()); 740 } 741 lua_state() const742 lua_State* lua_state() const noexcept { 743 return luastate; 744 } 745 }; 746 747 template <bool lb, bool rb> operator ==(const basic_reference<lb> & l,const basic_reference<rb> & r)748 inline bool operator==(const basic_reference<lb>& l, const basic_reference<rb>& r) noexcept { 749 auto ppl = stack::push_pop(l); 750 auto ppr = stack::push_pop(r); 751 return lua_compare(l.lua_state(), -1, -2, LUA_OPEQ) == 1; 752 } 753 754 template <bool lb, bool rb> operator !=(const basic_reference<lb> & l,const basic_reference<rb> & r)755 inline bool operator!=(const basic_reference<lb>& l, const basic_reference<rb>& r) noexcept { 756 return !operator==(l, r); 757 } 758 759 template <bool lb> operator ==(const basic_reference<lb> & l,const stack_reference & r)760 inline bool operator==(const basic_reference<lb>& l, const stack_reference& r) noexcept { 761 auto ppl = stack::push_pop(l); 762 return lua_compare(l.lua_state(), -1, r.stack_index(), LUA_OPEQ) == 1; 763 } 764 765 template <bool lb> operator !=(const basic_reference<lb> & l,const stack_reference & r)766 inline bool operator!=(const basic_reference<lb>& l, const stack_reference& r) noexcept { 767 return !operator==(l, r); 768 } 769 770 template <bool rb> operator ==(const stack_reference & l,const basic_reference<rb> & r)771 inline bool operator==(const stack_reference& l, const basic_reference<rb>& r) noexcept { 772 auto ppr = stack::push_pop(r); 773 return lua_compare(l.lua_state(), -1, r.stack_index(), LUA_OPEQ) == 1; 774 } 775 776 template <bool rb> operator !=(const stack_reference & l,const basic_reference<rb> & r)777 inline bool operator!=(const stack_reference& l, const basic_reference<rb>& r) noexcept { 778 return !operator==(l, r); 779 } 780 781 template <bool lb> operator ==(const basic_reference<lb> & lhs,const lua_nil_t &)782 inline bool operator==(const basic_reference<lb>& lhs, const lua_nil_t&) noexcept { 783 return !lhs.valid(); 784 } 785 786 template <bool rb> operator ==(const lua_nil_t &,const basic_reference<rb> & rhs)787 inline bool operator==(const lua_nil_t&, const basic_reference<rb>& rhs) noexcept { 788 return !rhs.valid(); 789 } 790 791 template <bool lb> operator !=(const basic_reference<lb> & lhs,const lua_nil_t &)792 inline bool operator!=(const basic_reference<lb>& lhs, const lua_nil_t&) noexcept { 793 return lhs.valid(); 794 } 795 796 template <bool rb> operator !=(const lua_nil_t &,const basic_reference<rb> & rhs)797 inline bool operator!=(const lua_nil_t&, const basic_reference<rb>& rhs) noexcept { 798 return rhs.valid(); 799 } 800 operator ==(const stateless_reference & l,const stateless_reference & r)801 inline bool operator==(const stateless_reference& l, const stateless_reference& r) noexcept { 802 return l.registry_index() == r.registry_index(); 803 } 804 operator !=(const stateless_reference & l,const stateless_reference & r)805 inline bool operator!=(const stateless_reference& l, const stateless_reference& r) noexcept { 806 return l.registry_index() != r.registry_index(); 807 } 808 operator ==(const stateless_reference & lhs,const lua_nil_t &)809 inline bool operator==(const stateless_reference& lhs, const lua_nil_t&) noexcept { 810 return lhs.registry_index() == LUA_REFNIL; 811 } 812 operator ==(const lua_nil_t &,const stateless_reference & rhs)813 inline bool operator==(const lua_nil_t&, const stateless_reference& rhs) noexcept { 814 return rhs.registry_index() == LUA_REFNIL; 815 } 816 operator !=(const stateless_reference & lhs,const lua_nil_t &)817 inline bool operator!=(const stateless_reference& lhs, const lua_nil_t&) noexcept { 818 return lhs.registry_index() != LUA_REFNIL; 819 } 820 operator !=(const lua_nil_t &,const stateless_reference & rhs)821 inline bool operator!=(const lua_nil_t&, const stateless_reference& rhs) noexcept { 822 return rhs.registry_index() != LUA_REFNIL; 823 } 824 825 struct stateless_reference_equals : public stateless_stack_reference_equals { 826 using is_transparent = std::true_type; 827 stateless_reference_equalssol::stateless_reference_equals828 stateless_reference_equals(lua_State* L_) noexcept : stateless_stack_reference_equals(L_) { 829 } 830 operator ()sol::stateless_reference_equals831 bool operator()(const lua_nil_t& lhs, const stateless_reference& rhs) const noexcept { 832 return rhs.equals(lua_state(), lhs); 833 } 834 operator ()sol::stateless_reference_equals835 bool operator()(const stateless_reference& lhs, const lua_nil_t& rhs) const noexcept { 836 return lhs.equals(lua_state(), rhs); 837 } 838 operator ()sol::stateless_reference_equals839 bool operator()(const stateless_reference& lhs, const stateless_reference& rhs) const noexcept { 840 return lhs.equals(lua_state(), rhs); 841 } 842 }; 843 844 struct reference_equals : public stack_reference_equals { 845 using is_transparent = std::true_type; 846 847 template <bool rb> operator ()sol::reference_equals848 bool operator()(const lua_nil_t& lhs, const basic_reference<rb>& rhs) const noexcept { 849 return lhs == rhs; 850 } 851 852 template <bool lb> operator ()sol::reference_equals853 bool operator()(const basic_reference<lb>& lhs, const lua_nil_t& rhs) const noexcept { 854 return lhs == rhs; 855 } 856 857 template <bool lb, bool rb> operator ()sol::reference_equals858 bool operator()(const basic_reference<lb>& lhs, const basic_reference<rb>& rhs) const noexcept { 859 return lhs == rhs; 860 } 861 862 template <bool lb> operator ()sol::reference_equals863 bool operator()(const basic_reference<lb>& lhs, const stack_reference& rhs) const noexcept { 864 return lhs == rhs; 865 } 866 867 template <bool rb> operator ()sol::reference_equals868 bool operator()(const stack_reference& lhs, const basic_reference<rb>& rhs) const noexcept { 869 return lhs == rhs; 870 } 871 }; 872 873 struct stateless_reference_hash : public stateless_stack_reference_hash { 874 using argument_type = stateless_reference; 875 using result_type = std::size_t; 876 using is_transparent = std::true_type; 877 stateless_reference_hashsol::stateless_reference_hash878 stateless_reference_hash(lua_State* L_) noexcept : stateless_stack_reference_hash(L_) { 879 } 880 operator ()sol::stateless_reference_hash881 result_type operator()(const stateless_reference& lhs) const noexcept { 882 std::hash<const void*> h; 883 return h(lhs.pointer(lua_state())); 884 } 885 }; 886 887 struct reference_hash : public stack_reference_hash { 888 using argument_type = reference; 889 using result_type = std::size_t; 890 using is_transparent = std::true_type; 891 892 template <bool lb> operator ()sol::reference_hash893 result_type operator()(const basic_reference<lb>& lhs) const noexcept { 894 std::hash<const void*> h; 895 return h(lhs.pointer()); 896 } 897 }; 898 } // namespace sol 899 900 #endif // SOL_REFERENCE_HPP 901