table_core.hpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  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_TABLE_CORE_HPP
  19. #define SOL_TABLE_CORE_HPP
  20. #include <sol/table_proxy.hpp>
  21. #include <sol/stack.hpp>
  22. #include <sol/function_types.hpp>
  23. #include <sol/table_iterator.hpp>
  24. #include <sol/pairs_iterator.hpp>
  25. #include <sol/types.hpp>
  26. #include <sol/object.hpp>
  27. #include <sol/usertype.hpp>
  28. #include <sol/optional.hpp>
  29. namespace sol {
  30. namespace detail {
  31. template <std::size_t n>
  32. struct clean {
  33. lua_State* L;
  34. clean(lua_State* luastate) : L(luastate) {
  35. }
  36. ~clean() {
  37. lua_pop(L, static_cast<int>(n));
  38. }
  39. };
  40. struct ref_clean {
  41. lua_State* L;
  42. int& pop_count;
  43. ref_clean(lua_State* L_, int& pop_count_) noexcept : L(L_), pop_count(pop_count_) {
  44. }
  45. ~ref_clean() {
  46. lua_pop(L, static_cast<int>(pop_count));
  47. }
  48. };
  49. inline int fail_on_newindex(lua_State* L_) {
  50. return luaL_error(L_, "sol: cannot modify the elements of an enumeration table");
  51. }
  52. } // namespace detail
  53. template <bool top_level, typename ref_t>
  54. class basic_table_core : public basic_object<ref_t> {
  55. private:
  56. using base_t = basic_object<ref_t>;
  57. friend class state;
  58. friend class state_view;
  59. template <typename, typename>
  60. friend class basic_usertype;
  61. template <typename>
  62. friend class basic_metatable;
  63. template <typename T>
  64. using is_get_direct_tableless = meta::boolean<stack::stack_detail::is_get_direct_tableless_v<T, top_level, false>>;
  65. template <typename T>
  66. using is_raw_get_direct_tableless = std::false_type;
  67. template <typename T>
  68. using is_set_direct_tableless = meta::boolean<stack::stack_detail::is_set_direct_tableless_v<T, top_level, false>>;
  69. template <typename T>
  70. using is_raw_set_direct_tableless = std::false_type;
  71. template <bool raw, typename... Ret, typename... Keys>
  72. decltype(auto) tuple_get(int table_index, Keys&&... keys) const {
  73. if constexpr (sizeof...(Ret) < 2) {
  74. return traverse_get_single_maybe_tuple<raw, Ret...>(table_index, std::forward<Keys>(keys)...);
  75. }
  76. else {
  77. using multi_ret = decltype(stack::pop<std::tuple<Ret...>>(nullptr));
  78. return multi_ret(traverse_get_single_maybe_tuple<raw, Ret>(table_index, std::forward<Keys>(keys))...);
  79. }
  80. }
  81. template <bool raw, typename Ret, size_t... I, typename Key>
  82. decltype(auto) traverse_get_single_tuple(int table_index, std::index_sequence<I...>, Key&& key) const {
  83. return traverse_get_single<raw, Ret>(table_index, std::get<I>(std::forward<Key>(key))...);
  84. }
  85. template <bool raw, typename Ret, typename Key>
  86. decltype(auto) traverse_get_single_maybe_tuple(int table_index, Key&& key) const {
  87. if constexpr (meta::is_tuple_v<meta::unqualified_t<Key>>) {
  88. return traverse_get_single_tuple<raw, Ret>(
  89. table_index, std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<Key>>>(), std::forward<Key>(key));
  90. }
  91. else {
  92. return traverse_get_single<raw, Ret>(table_index, std::forward<Key>(key));
  93. }
  94. }
  95. template <bool raw, typename Ret, typename... Keys>
  96. decltype(auto) traverse_get_single(int table_index, Keys&&... keys) const {
  97. constexpr static bool global = (meta::count_for_to_pack_v < 1, is_get_direct_tableless, meta::unqualified_t<Keys>... >> 0);
  98. if constexpr (meta::is_optional_v<meta::unqualified_t<Ret>>) {
  99. int popcount = 0;
  100. detail::ref_clean c(base_t::lua_state(), popcount);
  101. return traverse_get_deep_optional<global, raw, detail::insert_mode::none, Ret>(popcount, table_index, std::forward<Keys>(keys)...);
  102. }
  103. else {
  104. detail::clean<sizeof...(Keys) - meta::count_for_pack_v<detail::is_insert_mode, meta::unqualified_t<Keys>...>> c(base_t::lua_state());
  105. return traverse_get_deep<global, raw, detail::insert_mode::none, Ret>(table_index, std::forward<Keys>(keys)...);
  106. }
  107. }
  108. template <bool raw, typename Pairs, std::size_t... I>
  109. void tuple_set(std::index_sequence<I...>, Pairs&& pairs) {
  110. constexpr static bool global = (meta::count_even_for_pack_v < is_set_direct_tableless,
  111. meta::unqualified_t<decltype(std::get<I * 2>(std::forward<Pairs>(pairs)))>... >> 0);
  112. auto pp = stack::push_pop<global>(*this);
  113. int table_index = pp.index_of(*this);
  114. lua_State* L = base_t::lua_state();
  115. (void)table_index;
  116. (void)L;
  117. void(detail::swallow { (stack::set_field<(top_level), raw>(
  118. L, std::get<I * 2>(std::forward<Pairs>(pairs)), std::get<I * 2 + 1>(std::forward<Pairs>(pairs)), table_index),
  119. 0)... });
  120. }
  121. template <bool global, bool raw, detail::insert_mode mode, typename T, typename Key, typename... Keys>
  122. decltype(auto) traverse_get_deep(int table_index, Key&& key, Keys&&... keys) const {
  123. if constexpr (std::is_same_v<meta::unqualified_t<Key>, create_if_nil_t>) {
  124. (void)key;
  125. return traverse_get_deep<false, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::create_if_nil), T>(
  126. table_index, std::forward<Keys>(keys)...);
  127. }
  128. else {
  129. lua_State* L = base_t::lua_state();
  130. stack::get_field<global, raw>(L, std::forward<Key>(key), table_index);
  131. if constexpr (sizeof...(Keys) > 0) {
  132. if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {
  133. type t = type_of(L, -1);
  134. if (t == type::lua_nil || t == type::none) {
  135. lua_pop(L, 1);
  136. stack::push(L, new_table(0, 0));
  137. }
  138. }
  139. return traverse_get_deep<false, raw, mode, T>(lua_gettop(L), std::forward<Keys>(keys)...);
  140. }
  141. else {
  142. if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {
  143. type t = type_of(L, -1);
  144. if ((t == type::lua_nil || t == type::none) && (is_table_like_v<T>)) {
  145. lua_pop(L, 1);
  146. stack::push(L, new_table(0, 0));
  147. }
  148. }
  149. return stack::get<T>(L);
  150. }
  151. }
  152. }
  153. template <bool global, bool raw, detail::insert_mode mode, typename T, typename Key, typename... Keys>
  154. decltype(auto) traverse_get_deep_optional(int& popcount, int table_index, Key&& key, Keys&&... keys) const {
  155. if constexpr (std::is_same_v<meta::unqualified_t<Key>, create_if_nil_t>) {
  156. constexpr detail::insert_mode new_mode = static_cast<detail::insert_mode>(mode | detail::insert_mode::create_if_nil);
  157. (void)key;
  158. return traverse_get_deep_optional<global, raw, new_mode, T>(popcount, table_index, std::forward<Keys>(keys)...);
  159. }
  160. else if constexpr (std::is_same_v<meta::unqualified_t<Key>, update_if_empty_t>) {
  161. constexpr detail::insert_mode new_mode = static_cast<detail::insert_mode>(mode | detail::insert_mode::update_if_empty);
  162. (void)key;
  163. return traverse_get_deep_optional<global, raw, new_mode, T>(popcount, table_index, std::forward<Keys>(keys)...);
  164. }
  165. else if constexpr (std::is_same_v<meta::unqualified_t<Key>, override_value_t>) {
  166. constexpr detail::insert_mode new_mode = static_cast<detail::insert_mode>(mode | detail::insert_mode::override_value);
  167. (void)key;
  168. return traverse_get_deep_optional<global, raw, new_mode, T>(popcount, table_index, std::forward<Keys>(keys)...);
  169. }
  170. else {
  171. if constexpr (sizeof...(Keys) > 0) {
  172. lua_State* L = base_t::lua_state();
  173. auto p = stack::probe_get_field<global, raw>(L, std::forward<Key>(key), table_index);
  174. popcount += p.levels;
  175. if (!p.success) {
  176. if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {
  177. lua_pop(L, 1);
  178. constexpr bool is_seq = meta::count_for_to_pack_v < 1, std::is_integral, Keys... >> 0;
  179. stack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq)));
  180. stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index);
  181. }
  182. else {
  183. return T(nullopt);
  184. }
  185. }
  186. return traverse_get_deep_optional<false, raw, mode, T>(popcount, lua_gettop(L), std::forward<Keys>(keys)...);
  187. }
  188. else {
  189. using R = decltype(stack::get<T>(nullptr));
  190. using value_type = typename meta::unqualified_t<R>::value_type;
  191. lua_State* L = base_t::lua_state();
  192. auto p = stack::probe_get_field<global, raw, value_type>(L, key, table_index);
  193. popcount += p.levels;
  194. if (!p.success) {
  195. if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {
  196. lua_pop(L, 1);
  197. stack::push(L, new_table(0, 0));
  198. stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index);
  199. if (stack::check<value_type>(L, lua_gettop(L), &no_panic)) {
  200. return stack::get<T>(L);
  201. }
  202. }
  203. return R(nullopt);
  204. }
  205. return stack::get<T>(L);
  206. }
  207. }
  208. }
  209. template <bool global, bool raw, detail::insert_mode mode, typename Key, typename... Keys>
  210. void traverse_set_deep(int table_index, Key&& key, Keys&&... keys) const {
  211. using KeyU = meta::unqualified_t<Key>;
  212. if constexpr (std::is_same_v<KeyU, update_if_empty_t>) {
  213. (void)key;
  214. traverse_set_deep<global, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::update_if_empty)>(
  215. table_index, std::forward<Keys>(keys)...);
  216. }
  217. else if constexpr (std::is_same_v<KeyU, create_if_nil_t>) {
  218. (void)key;
  219. traverse_set_deep<global, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::create_if_nil)>(
  220. table_index, std::forward<Keys>(keys)...);
  221. }
  222. else if constexpr (std::is_same_v<KeyU, override_value_t>) {
  223. (void)key;
  224. traverse_set_deep<global, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::override_value)>(
  225. table_index, std::forward<Keys>(keys)...);
  226. }
  227. else {
  228. lua_State* L = base_t::lua_state();
  229. if constexpr (sizeof...(Keys) == 1) {
  230. if constexpr ((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty) {
  231. auto p = stack::probe_get_field<global, raw>(L, key, table_index);
  232. lua_pop(L, p.levels);
  233. if (!p.success) {
  234. stack::set_field<global, raw>(L, std::forward<Key>(key), std::forward<Keys>(keys)..., table_index);
  235. }
  236. }
  237. else {
  238. stack::set_field<global, raw>(L, std::forward<Key>(key), std::forward<Keys>(keys)..., table_index);
  239. }
  240. }
  241. else {
  242. if constexpr (mode != detail::insert_mode::none) {
  243. stack::get_field<global, raw>(L, key, table_index);
  244. type vt = type_of(L, -1);
  245. if constexpr ((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty
  246. || (mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {
  247. if (vt == type::lua_nil || vt == type::none) {
  248. constexpr bool is_seq = meta::count_for_to_pack_v < 1, std::is_integral, Keys... >> 0;
  249. lua_pop(L, 1);
  250. stack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq)));
  251. stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index);
  252. }
  253. }
  254. else {
  255. if (vt != type::table) {
  256. constexpr bool is_seq = meta::count_for_to_pack_v < 1, std::is_integral, Keys... >> 0;
  257. lua_pop(L, 1);
  258. stack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq)));
  259. stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index);
  260. }
  261. }
  262. }
  263. else {
  264. stack::get_field<global, raw>(L, std::forward<Key>(key), table_index);
  265. }
  266. traverse_set_deep<false, raw, mode>(lua_gettop(L), std::forward<Keys>(keys)...);
  267. }
  268. }
  269. }
  270. protected:
  271. basic_table_core(detail::no_safety_tag, lua_nil_t n) : base_t(n) {
  272. }
  273. basic_table_core(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) {
  274. }
  275. basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) {
  276. }
  277. template <typename T,
  278. meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<ref_t, stack_reference>>,
  279. meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
  280. basic_table_core(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward<T>(r)) {
  281. }
  282. template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
  283. basic_table_core(detail::no_safety_tag, lua_State* L, T&& r) noexcept : base_t(L, std::forward<T>(r)) {
  284. }
  285. public:
  286. using iterator = basic_table_iterator<ref_t>;
  287. using const_iterator = iterator;
  288. using base_t::lua_state;
  289. basic_table_core() noexcept = default;
  290. basic_table_core(const basic_table_core&) = default;
  291. basic_table_core(basic_table_core&&) = default;
  292. basic_table_core& operator=(const basic_table_core&) = default;
  293. basic_table_core& operator=(basic_table_core&&) = default;
  294. basic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) {
  295. }
  296. basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {
  297. }
  298. template <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
  299. basic_table_core(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) {
  300. #if SOL_IS_ON(SOL_SAFE_REFERENCES)
  301. auto pp = stack::push_pop(*this);
  302. int table_index = pp.index_of(*this);
  303. constructor_handler handler {};
  304. stack::check<basic_table_core>(lua_state(), table_index, handler);
  305. #endif // Safety
  306. }
  307. basic_table_core(lua_State* L, const new_table& nt) : base_t(L, -stack::push(L, nt)) {
  308. if (!is_stack_based<meta::unqualified_t<ref_t>>::value) {
  309. lua_pop(L, 1);
  310. }
  311. }
  312. basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) {
  313. #if SOL_IS_ON(SOL_SAFE_REFERENCES)
  314. constructor_handler handler {};
  315. stack::check<basic_table_core>(L, index, handler);
  316. #endif // Safety
  317. }
  318. basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) {
  319. #if SOL_IS_ON(SOL_SAFE_REFERENCES)
  320. auto pp = stack::push_pop(*this);
  321. int table_index = pp.index_of(*this);
  322. constructor_handler handler {};
  323. stack::check<basic_table_core>(lua_state(), table_index, handler);
  324. #endif // Safety
  325. }
  326. template <typename T,
  327. meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<ref_t, stack_reference>>,
  328. meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
  329. basic_table_core(T&& r) noexcept : basic_table_core(detail::no_safety, std::forward<T>(r)) {
  330. #if SOL_IS_ON(SOL_SAFE_REFERENCES)
  331. if (!is_table<meta::unqualified_t<T>>::value) {
  332. auto pp = stack::push_pop(*this);
  333. int table_index = pp.index_of(*this);
  334. constructor_handler handler {};
  335. stack::check<basic_table_core>(lua_state(), table_index, handler);
  336. }
  337. #endif // Safety
  338. }
  339. basic_table_core(lua_nil_t r) noexcept : basic_table_core(detail::no_safety, r) {
  340. }
  341. basic_table_core(lua_State* L, global_tag_t t) noexcept : base_t(L, t) {
  342. }
  343. iterator begin() const {
  344. if (this->get_type() == type::table) {
  345. return iterator(*this);
  346. }
  347. return iterator();
  348. }
  349. iterator end() const {
  350. return iterator();
  351. }
  352. const_iterator cbegin() const {
  353. return begin();
  354. }
  355. const_iterator cend() const {
  356. return end();
  357. }
  358. basic_pairs_range<basic_table_core> pairs() noexcept {
  359. return basic_pairs_range<basic_table_core>(*this);
  360. }
  361. basic_pairs_range<const basic_table_core> pairs() const noexcept {
  362. return basic_pairs_range<const basic_table_core>(*this);
  363. }
  364. void clear() {
  365. auto pp = stack::push_pop<false>(*this);
  366. int table_index = pp.index_of(*this);
  367. stack::clear(lua_state(), table_index);
  368. }
  369. template <typename... Ret, typename... Keys>
  370. decltype(auto) get(Keys&&... keys) const {
  371. static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match");
  372. constexpr static bool global = meta::all<meta::boolean<top_level>, is_get_direct_tableless<meta::unqualified_t<Keys>>...>::value;
  373. auto pp = stack::push_pop<global>(*this);
  374. int table_index = pp.index_of(*this);
  375. return tuple_get<false, Ret...>(table_index, std::forward<Keys>(keys)...);
  376. }
  377. template <typename T, typename Key>
  378. decltype(auto) get_or(Key&& key, T&& otherwise) const {
  379. typedef decltype(get<T>("")) U;
  380. optional<U> option = get<optional<U>>(std::forward<Key>(key));
  381. if (option) {
  382. return static_cast<U>(option.value());
  383. }
  384. return static_cast<U>(std::forward<T>(otherwise));
  385. }
  386. template <typename T, typename Key, typename D>
  387. decltype(auto) get_or(Key&& key, D&& otherwise) const {
  388. optional<T> option = get<optional<T>>(std::forward<Key>(key));
  389. if (option) {
  390. return static_cast<T>(option.value());
  391. }
  392. return static_cast<T>(std::forward<D>(otherwise));
  393. }
  394. template <typename T, typename... Keys>
  395. decltype(auto) traverse_get(Keys&&... keys) const {
  396. static_assert(sizeof...(Keys) > 0, "must pass at least 1 key to get");
  397. constexpr static bool global = (meta::count_for_to_pack_v < 1, is_get_direct_tableless, meta::unqualified_t<Keys>... >> 0);
  398. auto pp = stack::push_pop<global>(*this);
  399. int table_index = pp.index_of(*this);
  400. return traverse_get_single<false, T>(table_index, std::forward<Keys>(keys)...);
  401. }
  402. template <typename... Keys>
  403. basic_table_core& traverse_set(Keys&&... keys) {
  404. static_assert(sizeof...(Keys) > 1, "must pass at least 1 key and 1 value to set");
  405. constexpr static bool global
  406. = (meta::count_when_for_to_pack_v < detail::is_not_insert_mode, 1, is_set_direct_tableless, meta::unqualified_t<Keys>... >> 0);
  407. auto pp = stack::push_pop<global>(*this);
  408. int table_index = pp.index_of(*this);
  409. lua_State* L = base_t::lua_state();
  410. auto pn = stack::pop_n(L, static_cast<int>(sizeof...(Keys) - 2 - meta::count_for_pack_v<detail::is_insert_mode, meta::unqualified_t<Keys>...>));
  411. traverse_set_deep<top_level, false, detail::insert_mode::none>(table_index, std::forward<Keys>(keys)...);
  412. return *this;
  413. }
  414. template <typename... Args>
  415. basic_table_core& set(Args&&... args) {
  416. if constexpr (sizeof...(Args) == 2) {
  417. traverse_set(std::forward<Args>(args)...);
  418. }
  419. else {
  420. tuple_set<false>(std::make_index_sequence<sizeof...(Args) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...));
  421. }
  422. return *this;
  423. }
  424. template <typename... Ret, typename... Keys>
  425. decltype(auto) raw_get(Keys&&... keys) const {
  426. static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match");
  427. constexpr static bool global = (meta::count_for_to_pack_v < 1, is_raw_get_direct_tableless, meta::unqualified_t<Keys>... >> 0);
  428. auto pp = stack::push_pop<global>(*this);
  429. int table_index = pp.index_of(*this);
  430. return tuple_get<true, Ret...>(table_index, std::forward<Keys>(keys)...);
  431. }
  432. template <typename T, typename Key>
  433. decltype(auto) raw_get_or(Key&& key, T&& otherwise) const {
  434. typedef decltype(raw_get<T>("")) U;
  435. optional<U> option = raw_get<optional<U>>(std::forward<Key>(key));
  436. if (option) {
  437. return static_cast<U>(option.value());
  438. }
  439. return static_cast<U>(std::forward<T>(otherwise));
  440. }
  441. template <typename T, typename Key, typename D>
  442. decltype(auto) raw_get_or(Key&& key, D&& otherwise) const {
  443. optional<T> option = raw_get<optional<T>>(std::forward<Key>(key));
  444. if (option) {
  445. return static_cast<T>(option.value());
  446. }
  447. return static_cast<T>(std::forward<D>(otherwise));
  448. }
  449. template <typename T, typename... Keys>
  450. decltype(auto) traverse_raw_get(Keys&&... keys) const {
  451. constexpr static bool global = (meta::count_for_to_pack_v < 1, is_raw_get_direct_tableless, meta::unqualified_t<Keys>... >> 0);
  452. auto pp = stack::push_pop<global>(*this);
  453. int table_index = pp.index_of(*this);
  454. return traverse_get_single<true, T>(table_index, std::forward<Keys>(keys)...);
  455. }
  456. template <typename... Keys>
  457. basic_table_core& traverse_raw_set(Keys&&... keys) {
  458. constexpr static bool global = (meta::count_for_to_pack_v < 1, is_raw_set_direct_tableless, meta::unqualified_t<Keys>... >> 0);
  459. auto pp = stack::push_pop<global>(*this);
  460. lua_State* L = base_t::lua_state();
  461. auto pn = stack::pop_n(L, static_cast<int>(sizeof...(Keys) - 2 - meta::count_for_pack_v<detail::is_insert_mode, meta::unqualified_t<Keys>...>));
  462. traverse_set_deep<top_level, true, false>(std::forward<Keys>(keys)...);
  463. return *this;
  464. }
  465. template <typename... Args>
  466. basic_table_core& raw_set(Args&&... args) {
  467. tuple_set<true>(std::make_index_sequence<sizeof...(Args) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...));
  468. return *this;
  469. }
  470. template <typename Class, typename Key>
  471. usertype<Class> new_usertype(Key&& key);
  472. template <typename Class, typename Key, automagic_flags enrollment_flags>
  473. usertype<Class> new_usertype(Key&& key, constant_automagic_enrollments<enrollment_flags> enrollment);
  474. template <typename Class, typename Key>
  475. usertype<Class> new_usertype(Key&& key, automagic_enrollments enrollment);
  476. template <typename Class, typename Key, typename Arg, typename... Args,
  477. typename = std::enable_if_t<!std::is_base_of_v<automagic_enrollments, meta::unqualified_t<Arg>>>>
  478. usertype<Class> new_usertype(Key&& key, Arg&& arg, Args&&... args);
  479. template <bool read_only = true, typename... Args>
  480. table new_enum(const string_view& name, Args&&... args) {
  481. table target = create_with(std::forward<Args>(args)...);
  482. if constexpr (read_only) {
  483. // Need to create a special iterator to handle this
  484. table x
  485. = create_with(meta_function::new_index, detail::fail_on_newindex, meta_function::index, target, meta_function::pairs, stack::stack_detail::readonly_pairs);
  486. table shim = create_named(name, metatable_key, x);
  487. return shim;
  488. }
  489. else {
  490. set(name, target);
  491. return target;
  492. }
  493. }
  494. template <typename T, bool read_only = true>
  495. table new_enum(const string_view& name, std::initializer_list<std::pair<string_view, T>> items) {
  496. table target = create(static_cast<int>(items.size()), static_cast<int>(0));
  497. for (const auto& kvp : items) {
  498. target.set(kvp.first, kvp.second);
  499. }
  500. if constexpr (read_only) {
  501. table x = create_with(meta_function::new_index, detail::fail_on_newindex, meta_function::index, target);
  502. table shim = create_named(name, metatable_key, x);
  503. return shim;
  504. }
  505. else {
  506. set(name, target);
  507. return target;
  508. }
  509. }
  510. template <typename Key = object, typename Value = object, typename Fx>
  511. void for_each(Fx&& fx) const {
  512. lua_State* L = base_t::lua_state();
  513. if constexpr (std::is_invocable_v<Fx, Key, Value>) {
  514. auto pp = stack::push_pop(*this);
  515. int table_index = pp.index_of(*this);
  516. stack::push(L, lua_nil);
  517. while (lua_next(L, table_index)) {
  518. Key key(L, -2);
  519. Value value(L, -1);
  520. auto pn = stack::pop_n(L, 1);
  521. fx(key, value);
  522. }
  523. }
  524. else {
  525. auto pp = stack::push_pop(*this);
  526. int table_index = pp.index_of(*this);
  527. stack::push(L, lua_nil);
  528. while (lua_next(L, table_index)) {
  529. Key key(L, -2);
  530. Value value(L, -1);
  531. auto pn = stack::pop_n(L, 1);
  532. std::pair<Key&, Value&> keyvalue(key, value);
  533. fx(keyvalue);
  534. }
  535. }
  536. }
  537. size_t size() const {
  538. auto pp = stack::push_pop(*this);
  539. int table_index = pp.index_of(*this);
  540. lua_State* L = base_t::lua_state();
  541. lua_len(L, table_index);
  542. return stack::pop<size_t>(L);
  543. }
  544. bool empty() const {
  545. return cbegin() == cend();
  546. }
  547. template <typename T>
  548. auto operator[](T&& key) & {
  549. return table_proxy<basic_table_core&, detail::proxy_key_t<T>>(*this, std::forward<T>(key));
  550. }
  551. template <typename T>
  552. auto operator[](T&& key) const& {
  553. return table_proxy<const basic_table_core&, detail::proxy_key_t<T>>(*this, std::forward<T>(key));
  554. }
  555. template <typename T>
  556. auto operator[](T&& key) && {
  557. return table_proxy<basic_table_core, detail::proxy_key_t<T>>(std::move(*this), std::forward<T>(key));
  558. }
  559. template <typename Sig, typename Key, typename... Args>
  560. basic_table_core& set_function(Key&& key, Args&&... args) {
  561. set_fx(types<Sig>(), std::forward<Key>(key), std::forward<Args>(args)...);
  562. return *this;
  563. }
  564. template <typename Key, typename... Args>
  565. basic_table_core& set_function(Key&& key, Args&&... args) {
  566. set_fx(types<>(), std::forward<Key>(key), std::forward<Args>(args)...);
  567. return *this;
  568. }
  569. template <typename... Args>
  570. basic_table_core& add(Args&&... args) {
  571. auto pp = stack::push_pop(*this);
  572. int table_index = pp.index_of(*this);
  573. lua_State* L = base_t::lua_state();
  574. (void)detail::swallow { 0, (stack::stack_detail::raw_table_set(L, std::forward<Args>(args), table_index), 0)... };
  575. return *this;
  576. }
  577. private:
  578. template <typename R, typename... Args, typename Fx, typename Key, typename = std::invoke_result_t<Fx, Args...>>
  579. void set_fx(types<R(Args...)>, Key&& key, Fx&& fx) {
  580. set_resolved_function<R(Args...)>(std::forward<Key>(key), std::forward<Fx>(fx));
  581. }
  582. template <typename Fx, typename Key, meta::enable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler>
  583. void set_fx(types<>, Key&& key, Fx&& fx) {
  584. set(std::forward<Key>(key), std::forward<Fx>(fx));
  585. }
  586. template <typename Fx, typename Key, typename... Args,
  587. meta::disable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler>
  588. void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) {
  589. set(std::forward<Key>(key), as_function_reference(std::forward<Fx>(fx), std::forward<Args>(args)...));
  590. }
  591. template <typename... Sig, typename... Args, typename Key>
  592. void set_resolved_function(Key&& key, Args&&... args) {
  593. set(std::forward<Key>(key), as_function_reference<function_sig<Sig...>>(std::forward<Args>(args)...));
  594. }
  595. public:
  596. static inline table create(lua_State* L, int narr = 0, int nrec = 0) {
  597. lua_createtable(L, narr, nrec);
  598. table result(L);
  599. lua_pop(L, 1);
  600. return result;
  601. }
  602. template <typename Key, typename Value, typename... Args>
  603. static inline table create(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) {
  604. lua_createtable(L, narr, nrec);
  605. table result(L);
  606. result.set(std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
  607. lua_pop(L, 1);
  608. return result;
  609. }
  610. template <typename... Args>
  611. static inline table create_with(lua_State* L, Args&&... args) {
  612. static_assert(sizeof...(Args) % 2 == 0, "You must have an even number of arguments for a key, value ... list.");
  613. constexpr int narr = static_cast<int>(meta::count_odd_for_pack_v<std::is_integral, Args...>);
  614. return create(L, narr, static_cast<int>((sizeof...(Args) / 2) - narr), std::forward<Args>(args)...);
  615. }
  616. table create(int narr = 0, int nrec = 0) {
  617. return create(base_t::lua_state(), narr, nrec);
  618. }
  619. template <typename Key, typename Value, typename... Args>
  620. table create(int narr, int nrec, Key&& key, Value&& value, Args&&... args) {
  621. return create(base_t::lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
  622. }
  623. template <typename Name>
  624. table create(Name&& name, int narr = 0, int nrec = 0) {
  625. table x = create(base_t::lua_state(), narr, nrec);
  626. this->set(std::forward<Name>(name), x);
  627. return x;
  628. }
  629. template <typename Name, typename Key, typename Value, typename... Args>
  630. table create(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) {
  631. table x = create(base_t::lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
  632. this->set(std::forward<Name>(name), x);
  633. return x;
  634. }
  635. template <typename... Args>
  636. table create_with(Args&&... args) {
  637. return create_with(base_t::lua_state(), std::forward<Args>(args)...);
  638. }
  639. template <typename Name, typename... Args>
  640. table create_named(Name&& name, Args&&... args) {
  641. static const int narr = static_cast<int>(meta::count_even_for_pack_v<std::is_integral, Args...>);
  642. return create(std::forward<Name>(name), narr, (sizeof...(Args) / 2) - narr, std::forward<Args>(args)...);
  643. }
  644. };
  645. } // namespace sol
  646. #endif // SOL_TABLE_CORE_HPP