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