stack_reference.hpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. // sol2
  2. // The MIT License (MIT)
  3. // Copyright (c) 2013-2022 Rapptz, ThePhD and contributors
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy of
  5. // this software and associated documentation files (the "Software"), to deal in
  6. // the Software without restriction, including without limitation the rights to
  7. // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  8. // the Software, and to permit persons to whom the Software is furnished to do so,
  9. // subject to the following conditions:
  10. // The above copyright notice and this permission notice shall be included in all
  11. // copies or substantial portions of the Software.
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  14. // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  15. // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  16. // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  17. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. #ifndef SOL_STACK_REFERENCE_HPP
  19. #define SOL_STACK_REFERENCE_HPP
  20. #include <sol/types.hpp>
  21. namespace sol {
  22. namespace detail {
  23. inline bool xmovable(lua_State* leftL, lua_State* rightL) {
  24. if (rightL == nullptr || leftL == nullptr || leftL == rightL) {
  25. return false;
  26. }
  27. const void* leftregistry = lua_topointer(leftL, LUA_REGISTRYINDEX);
  28. const void* rightregistry = lua_topointer(rightL, LUA_REGISTRYINDEX);
  29. return leftregistry == rightregistry;
  30. }
  31. } // namespace detail
  32. class stateless_stack_reference {
  33. private:
  34. friend class stack_reference;
  35. int m_index = 0;
  36. int registry_index() const noexcept {
  37. return LUA_NOREF;
  38. }
  39. public:
  40. stateless_stack_reference() noexcept = default;
  41. stateless_stack_reference(lua_nil_t) noexcept : stateless_stack_reference() {};
  42. stateless_stack_reference(lua_State* L_, int index_) noexcept : stateless_stack_reference(absolute_index(L_, index_)) {
  43. }
  44. stateless_stack_reference(lua_State*, absolute_index index_) noexcept : stateless_stack_reference(index_) {
  45. }
  46. stateless_stack_reference(lua_State*, raw_index index_) noexcept : stateless_stack_reference(index_) {
  47. }
  48. stateless_stack_reference(absolute_index index_) noexcept : m_index(index_) {
  49. }
  50. stateless_stack_reference(raw_index index_) noexcept : m_index(index_) {
  51. }
  52. stateless_stack_reference(lua_State*, ref_index) noexcept = delete;
  53. stateless_stack_reference(ref_index) noexcept = delete;
  54. stateless_stack_reference(const reference&) noexcept = delete;
  55. stateless_stack_reference(const stateless_stack_reference&) noexcept = default;
  56. stateless_stack_reference(stateless_stack_reference&& o) noexcept = default;
  57. stateless_stack_reference& operator=(stateless_stack_reference&&) noexcept = default;
  58. stateless_stack_reference& operator=(const stateless_stack_reference&) noexcept = default;
  59. int push(lua_State* L_) const noexcept {
  60. #if SOL_IS_ON(SOL_SAFE_STACK_CHECK)
  61. luaL_checkstack(L_, 1, "not enough Lua stack space to push a single reference value");
  62. #endif // make sure stack doesn't overflow
  63. lua_pushvalue(L_, m_index);
  64. return 1;
  65. }
  66. void pop(lua_State* L_, int pop_count = 1) const noexcept {
  67. lua_pop(L_, pop_count);
  68. }
  69. int stack_index() const noexcept {
  70. return m_index;
  71. }
  72. const void* pointer(lua_State* L_) const noexcept {
  73. const void* pointer_id = lua_topointer(L_, stack_index());
  74. return pointer_id;
  75. }
  76. type get_type(lua_State* L_) const noexcept {
  77. int untyped_value = lua_type(L_, stack_index());
  78. return static_cast<type>(untyped_value);
  79. }
  80. bool valid(lua_State* L) const noexcept {
  81. type t = get_type(L);
  82. return t != type::lua_nil && t != type::none;
  83. }
  84. void reset(lua_State*) noexcept {
  85. m_index = 0;
  86. }
  87. void reset(lua_State* L_, int index_) noexcept {
  88. m_index = absolute_index(L_, index_);
  89. }
  90. void abandon(lua_State* = nullptr) noexcept {
  91. m_index = 0;
  92. }
  93. stateless_stack_reference copy(lua_State* L_) const noexcept {
  94. return stateless_stack_reference(L_, raw_index(m_index));
  95. }
  96. void copy_assign(lua_State*, const stateless_stack_reference& right) noexcept {
  97. m_index = right.m_index;
  98. }
  99. bool equals(lua_State* L_, const stateless_stack_reference& r) const noexcept {
  100. return lua_compare(L_, this->stack_index(), r.stack_index(), LUA_OPEQ) == 1;
  101. }
  102. bool equals(lua_State* L_, lua_nil_t) const noexcept {
  103. return valid(L_);
  104. }
  105. };
  106. class stack_reference : public stateless_stack_reference {
  107. private:
  108. lua_State* luastate = nullptr;
  109. public:
  110. stack_reference() noexcept = default;
  111. stack_reference(lua_nil_t) noexcept : stack_reference() {};
  112. stack_reference(lua_State* L, lua_nil_t) noexcept : stateless_stack_reference(L, 0), luastate(L) {
  113. }
  114. stack_reference(lua_State* L, int i) noexcept : stateless_stack_reference(L, i), luastate(L) {
  115. }
  116. stack_reference(lua_State* L, absolute_index i) noexcept : stateless_stack_reference(L, i), luastate(L) {
  117. }
  118. stack_reference(lua_State* L, raw_index i) noexcept : stateless_stack_reference(L, i), luastate(L) {
  119. }
  120. stack_reference(lua_State* L, ref_index i) noexcept = delete;
  121. stack_reference(lua_State* L, const reference& r) noexcept = delete;
  122. stack_reference(lua_State* L, const stack_reference& r) noexcept : luastate(L) {
  123. if (!r.valid()) {
  124. m_index = 0;
  125. return;
  126. }
  127. int i = r.stack_index();
  128. if (detail::xmovable(lua_state(), r.lua_state())) {
  129. #if SOL_IS_ON(SOL_SAFE_STACK_CHECK)
  130. luaL_checkstack(L, 1, "not enough Lua stack space to push a single reference value");
  131. #endif // make sure stack doesn't overflow
  132. lua_pushvalue(r.lua_state(), r.stack_index());
  133. lua_xmove(r.lua_state(), luastate, 1);
  134. i = absolute_index(luastate, -1);
  135. }
  136. m_index = i;
  137. }
  138. stack_reference(stack_reference&& o) noexcept = default;
  139. stack_reference& operator=(stack_reference&&) noexcept = default;
  140. stack_reference(const stack_reference&) noexcept = default;
  141. stack_reference& operator=(const stack_reference&) noexcept = default;
  142. int push() const noexcept {
  143. return push(lua_state());
  144. }
  145. int push(lua_State* L_) const noexcept {
  146. return stateless_stack_reference::push(L_);
  147. }
  148. void pop() const noexcept {
  149. pop(lua_state());
  150. }
  151. void pop(lua_State* L_, int pop_count_ = 1) const noexcept {
  152. stateless_stack_reference::pop(L_, pop_count_);
  153. }
  154. const void* pointer() const noexcept {
  155. return stateless_stack_reference::pointer(lua_state());
  156. }
  157. type get_type() const noexcept {
  158. return stateless_stack_reference::get_type(lua_state());
  159. }
  160. lua_State* lua_state() const noexcept {
  161. return luastate;
  162. }
  163. bool valid() const noexcept {
  164. return stateless_stack_reference::valid(lua_state());
  165. }
  166. void abandon() {
  167. stateless_stack_reference::abandon(lua_state());
  168. }
  169. };
  170. inline bool operator==(const stack_reference& l, const stack_reference& r) {
  171. return lua_compare(l.lua_state(), l.stack_index(), r.stack_index(), LUA_OPEQ) == 1;
  172. }
  173. inline bool operator!=(const stack_reference& l, const stack_reference& r) {
  174. return !operator==(l, r);
  175. }
  176. inline bool operator==(const stack_reference& lhs, const lua_nil_t&) {
  177. return !lhs.valid();
  178. }
  179. inline bool operator==(const lua_nil_t&, const stack_reference& rhs) {
  180. return !rhs.valid();
  181. }
  182. inline bool operator!=(const stack_reference& lhs, const lua_nil_t&) {
  183. return lhs.valid();
  184. }
  185. inline bool operator!=(const lua_nil_t&, const stack_reference& rhs) {
  186. return rhs.valid();
  187. }
  188. inline bool operator==(const stateless_stack_reference& l, const stateless_stack_reference& r) {
  189. return l.stack_index() == r.stack_index();
  190. }
  191. inline bool operator!=(const stateless_stack_reference& l, const stateless_stack_reference& r) {
  192. return l.stack_index() != r.stack_index();
  193. }
  194. struct stateless_stack_reference_equals {
  195. using is_transparent = std::true_type;
  196. stateless_stack_reference_equals(lua_State* L_) noexcept : m_L(L_) {
  197. }
  198. lua_State* lua_state() const noexcept {
  199. return m_L;
  200. }
  201. bool operator()(const stateless_stack_reference& lhs, const stateless_stack_reference& rhs) const {
  202. return lhs.equals(lua_state(), rhs);
  203. }
  204. bool operator()(lua_nil_t lhs, const stateless_stack_reference& rhs) const {
  205. return rhs.equals(lua_state(), lhs);
  206. }
  207. bool operator()(const stateless_stack_reference& lhs, lua_nil_t rhs) const {
  208. return lhs.equals(lua_state(), rhs);
  209. }
  210. private:
  211. lua_State* m_L;
  212. };
  213. struct stack_reference_equals {
  214. using is_transparent = std::true_type;
  215. bool operator()(const lua_nil_t& lhs, const stack_reference& rhs) const {
  216. return lhs == rhs;
  217. }
  218. bool operator()(const stack_reference& lhs, const lua_nil_t& rhs) const {
  219. return lhs == rhs;
  220. }
  221. bool operator()(const stack_reference& lhs, const stack_reference& rhs) const {
  222. return lhs == rhs;
  223. }
  224. };
  225. struct stateless_stack_reference_hash {
  226. using argument_type = stateless_stack_reference;
  227. using result_type = std::size_t;
  228. using is_transparent = std::true_type;
  229. stateless_stack_reference_hash(lua_State* L_) noexcept : m_L(L_) {
  230. }
  231. lua_State* lua_state() const noexcept {
  232. return m_L;
  233. }
  234. result_type operator()(const argument_type& lhs) const noexcept {
  235. std::hash<const void*> h;
  236. return h(lhs.pointer(lua_state()));
  237. }
  238. private:
  239. lua_State* m_L;
  240. };
  241. struct stack_reference_hash {
  242. using argument_type = stack_reference;
  243. using result_type = std::size_t;
  244. using is_transparent = std::true_type;
  245. result_type operator()(const argument_type& lhs) const noexcept {
  246. std::hash<const void*> h;
  247. return h(lhs.pointer());
  248. }
  249. };
  250. } // namespace sol
  251. #endif // SOL_STACK_REFERENCE_HPP