table_proxy.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. // sol3
  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_TABLE_PROXY_HPP
  19. #define SOL_TABLE_PROXY_HPP
  20. #include <sol/traits.hpp>
  21. #include <sol/function.hpp>
  22. #include <sol/protected_function.hpp>
  23. #include <sol/proxy_base.hpp>
  24. namespace sol {
  25. template <typename Table, typename Key>
  26. struct table_proxy : public proxy_base<table_proxy<Table, Key>> {
  27. private:
  28. using key_type = detail::proxy_key_t<Key>;
  29. template <typename T, std::size_t... I>
  30. decltype(auto) tuple_get(std::index_sequence<I...>) const& {
  31. return tbl.template traverse_get<T>(std::get<I>(key)...);
  32. }
  33. template <typename T, std::size_t... I>
  34. decltype(auto) tuple_get(std::index_sequence<I...>) && {
  35. return tbl.template traverse_get<T>(std::get<I>(std::move(key))...);
  36. }
  37. template <std::size_t... I, typename T>
  38. void tuple_set(std::index_sequence<I...>, T&& value) & {
  39. tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value));
  40. }
  41. template <std::size_t... I, typename T>
  42. void tuple_set(std::index_sequence<I...>, T&& value) && {
  43. tbl.traverse_set(std::get<I>(std::move(key))..., std::forward<T>(value));
  44. }
  45. auto setup_table(std::true_type) {
  46. auto p = stack::probe_get_field<std::is_same_v<meta::unqualified_t<Table>, global_table>>(lua_state(), key, tbl.stack_index());
  47. lua_pop(lua_state(), p.levels);
  48. return p;
  49. }
  50. bool is_valid(std::false_type) {
  51. auto pp = stack::push_pop(tbl);
  52. auto p = stack::probe_get_field<std::is_same_v<meta::unqualified_t<Table>, global_table>>(lua_state(), key, lua_gettop(lua_state()));
  53. lua_pop(lua_state(), p.levels);
  54. return p;
  55. }
  56. public:
  57. Table tbl;
  58. key_type key;
  59. template <typename T>
  60. table_proxy(Table table, T&& k) : tbl(table), key(std::forward<T>(k)) {
  61. }
  62. table_proxy(const table_proxy&) = default;
  63. table_proxy(table_proxy&&) = default;
  64. table_proxy& operator=(const table_proxy& right) {
  65. return set(right);
  66. }
  67. table_proxy& operator=(table_proxy&& right) {
  68. return set(std::move(right));
  69. }
  70. template <typename T>
  71. table_proxy& set(T&& item) & {
  72. tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item));
  73. return *this;
  74. }
  75. template <typename T>
  76. table_proxy&& set(T&& item) && {
  77. std::move(*this).tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item));
  78. return std::move(*this);
  79. }
  80. template <typename... Args>
  81. table_proxy& set_function(Args&&... args) & {
  82. tbl.set_function(key, std::forward<Args>(args)...);
  83. return *this;
  84. }
  85. template <typename... Args>
  86. table_proxy&& set_function(Args&&... args) && {
  87. tbl.set_function(std::move(key), std::forward<Args>(args)...);
  88. return std::move(*this);
  89. }
  90. template <typename T, std::enable_if_t<!std::is_same_v<meta::unqualified_t<T>, table_proxy>>* = nullptr>
  91. table_proxy& operator=(T&& other) & {
  92. using Tu = meta::unwrap_unqualified_t<T>;
  93. if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_invocable_v<Tu>) {
  94. return set_function(std::forward<T>(other));
  95. }
  96. else {
  97. return set(std::forward<T>(other));
  98. }
  99. }
  100. template <typename T, std::enable_if_t<!std::is_same_v<meta::unqualified_t<T>, table_proxy>>* = nullptr>
  101. table_proxy&& operator=(T&& other) && {
  102. using Tu = meta::unwrap_unqualified_t<T>;
  103. if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_invocable_v<Tu> && !detail::is_msvc_callable_rigged_v<T>) {
  104. return std::move(*this).set_function(std::forward<T>(other));
  105. }
  106. else {
  107. return std::move(*this).set(std::forward<T>(other));
  108. }
  109. }
  110. template <typename T>
  111. table_proxy& operator=(std::initializer_list<T> other) & {
  112. return set(std::move(other));
  113. }
  114. template <typename T>
  115. table_proxy&& operator=(std::initializer_list<T> other) && {
  116. return std::move(*this).set(std::move(other));
  117. }
  118. template <typename T>
  119. bool is() const {
  120. typedef decltype(get<T>()) U;
  121. optional<U> option = this->get<optional<U>>();
  122. return option.has_value();
  123. }
  124. template <typename T>
  125. decltype(auto) get() const& {
  126. using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
  127. return tuple_get<T>(idx_seq());
  128. }
  129. template <typename T>
  130. decltype(auto) get() && {
  131. using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
  132. return std::move(*this).template tuple_get<T>(idx_seq());
  133. }
  134. template <typename T>
  135. decltype(auto) get_or(T&& otherwise) const {
  136. typedef decltype(get<T>()) U;
  137. optional<U> option = get<optional<U>>();
  138. if (option) {
  139. return static_cast<U>(option.value());
  140. }
  141. return static_cast<U>(std::forward<T>(otherwise));
  142. }
  143. template <typename T, typename D>
  144. decltype(auto) get_or(D&& otherwise) const {
  145. optional<T> option = get<optional<T>>();
  146. if (option) {
  147. return static_cast<T>(option.value());
  148. }
  149. return static_cast<T>(std::forward<D>(otherwise));
  150. }
  151. template <typename T>
  152. decltype(auto) get_or_create() {
  153. return get_or_create<T>(new_table());
  154. }
  155. template <typename T, typename Otherwise>
  156. decltype(auto) get_or_create(Otherwise&& other) {
  157. if (!this->valid()) {
  158. this->set(std::forward<Otherwise>(other));
  159. }
  160. return get<T>();
  161. }
  162. template <typename K>
  163. decltype(auto) operator[](K&& k) const& {
  164. auto keys = meta::tuplefy(key, std::forward<K>(k));
  165. return table_proxy<Table, decltype(keys)>(tbl, std::move(keys));
  166. }
  167. template <typename K>
  168. decltype(auto) operator[](K&& k) & {
  169. auto keys = meta::tuplefy(key, std::forward<K>(k));
  170. return table_proxy<Table, decltype(keys)>(tbl, std::move(keys));
  171. }
  172. template <typename K>
  173. decltype(auto) operator[](K&& k) && {
  174. auto keys = meta::tuplefy(std::move(key), std::forward<K>(k));
  175. return table_proxy<Table, decltype(keys)>(tbl, std::move(keys));
  176. }
  177. template <typename... Ret, typename... Args>
  178. decltype(auto) call(Args&&... args) {
  179. lua_State* L = this->lua_state();
  180. push(L);
  181. int idx = lua_gettop(L);
  182. stack_aligned_function func(L, idx);
  183. return func.call<Ret...>(std::forward<Args>(args)...);
  184. }
  185. template <typename... Args>
  186. decltype(auto) operator()(Args&&... args) {
  187. return call<>(std::forward<Args>(args)...);
  188. }
  189. bool valid() const {
  190. auto pp = stack::push_pop(tbl);
  191. auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state()));
  192. lua_pop(lua_state(), p.levels);
  193. return p;
  194. }
  195. int push() const noexcept {
  196. return push(this->lua_state());
  197. }
  198. int push(lua_State* L) const noexcept {
  199. if constexpr (std::is_same_v<meta::unqualified_t<Table>, global_table> || is_stack_table_v<meta::unqualified_t<Table>>) {
  200. auto pp = stack::push_pop<true>(tbl);
  201. int tableindex = pp.index_of(tbl);
  202. int top_index = lua_gettop(L);
  203. stack::get_field<true>(lua_state(), key, tableindex);
  204. lua_replace(L, top_index + 1);
  205. lua_settop(L, top_index + 1);
  206. }
  207. else {
  208. auto pp = stack::push_pop<false>(tbl);
  209. int tableindex = pp.index_of(tbl);
  210. int aftertableindex = lua_gettop(L);
  211. stack::get_field<false>(lua_state(), key, tableindex);
  212. lua_replace(L, tableindex);
  213. lua_settop(L, aftertableindex + 1);
  214. }
  215. return 1;
  216. }
  217. type get_type() const {
  218. type t = type::none;
  219. auto pp = stack::push_pop(tbl);
  220. auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state()));
  221. if (p) {
  222. t = type_of(lua_state(), -1);
  223. }
  224. lua_pop(lua_state(), p.levels);
  225. return t;
  226. }
  227. lua_State* lua_state() const {
  228. return tbl.lua_state();
  229. }
  230. table_proxy& force() {
  231. if (!this->valid()) {
  232. this->set(new_table());
  233. }
  234. return *this;
  235. }
  236. };
  237. template <typename Table, typename Key, typename T>
  238. inline bool operator==(T&& left, const table_proxy<Table, Key>& right) {
  239. using G = decltype(stack::get<T>(nullptr, 0));
  240. return right.template get<optional<G>>() == left;
  241. }
  242. template <typename Table, typename Key, typename T>
  243. inline bool operator==(const table_proxy<Table, Key>& right, T&& left) {
  244. using G = decltype(stack::get<T>(nullptr, 0));
  245. return right.template get<optional<G>>() == left;
  246. }
  247. template <typename Table, typename Key, typename T>
  248. inline bool operator!=(T&& left, const table_proxy<Table, Key>& right) {
  249. using G = decltype(stack::get<T>(nullptr, 0));
  250. return right.template get<optional<G>>() != left;
  251. }
  252. template <typename Table, typename Key, typename T>
  253. inline bool operator!=(const table_proxy<Table, Key>& right, T&& left) {
  254. using G = decltype(stack::get<T>(nullptr, 0));
  255. return right.template get<optional<G>>() != left;
  256. }
  257. template <typename Table, typename Key>
  258. inline bool operator==(lua_nil_t, const table_proxy<Table, Key>& right) {
  259. return !right.valid();
  260. }
  261. template <typename Table, typename Key>
  262. inline bool operator==(const table_proxy<Table, Key>& right, lua_nil_t) {
  263. return !right.valid();
  264. }
  265. template <typename Table, typename Key>
  266. inline bool operator!=(lua_nil_t, const table_proxy<Table, Key>& right) {
  267. return right.valid();
  268. }
  269. template <typename Table, typename Key>
  270. inline bool operator!=(const table_proxy<Table, Key>& right, lua_nil_t) {
  271. return right.valid();
  272. }
  273. template <bool b>
  274. template <typename Super>
  275. basic_reference<b>& basic_reference<b>::operator=(proxy_base<Super>&& r) {
  276. basic_reference<b> v = r;
  277. this->operator=(std::move(v));
  278. return *this;
  279. }
  280. template <bool b>
  281. template <typename Super>
  282. basic_reference<b>& basic_reference<b>::operator=(const proxy_base<Super>& r) {
  283. basic_reference<b> v = r;
  284. this->operator=(std::move(v));
  285. return *this;
  286. }
  287. namespace stack {
  288. template <typename Table, typename Key>
  289. struct unqualified_pusher<table_proxy<Table, Key>> {
  290. static int push(lua_State* L, const table_proxy<Table, Key>& p) {
  291. return p.push(L);
  292. }
  293. };
  294. } // namespace stack
  295. } // namespace sol
  296. #endif // SOL_TABLE_PROXY_HPP