1 // sol2 2 3 // The MIT License (MIT) 4 5 // Copyright (c) 2013-2018 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_TABLE_CORE_HPP 25 #define SOL_TABLE_CORE_HPP 26 27 #include "proxy.hpp" 28 #include "stack.hpp" 29 #include "function_types.hpp" 30 #include "usertype.hpp" 31 #include "table_iterator.hpp" 32 #include "types.hpp" 33 #include "object_base.hpp" 34 35 namespace sol { 36 namespace detail { 37 template <std::size_t n> 38 struct clean { 39 lua_State* L; cleansol::detail::clean40 clean(lua_State* luastate) 41 : L(luastate) { 42 } ~cleansol::detail::clean43 ~clean() { 44 lua_pop(L, static_cast<int>(n)); 45 } 46 }; 47 struct ref_clean { 48 lua_State* L; 49 int& n; ref_cleansol::detail::ref_clean50 ref_clean(lua_State* luastate, int& n) 51 : L(luastate), n(n) { 52 } ~ref_cleansol::detail::ref_clean53 ~ref_clean() { 54 lua_pop(L, static_cast<int>(n)); 55 } 56 }; fail_on_newindex(lua_State * L)57 inline int fail_on_newindex(lua_State* L) { 58 return luaL_error(L, "sol: cannot modify the elements of an enumeration table"); 59 } 60 } // namespace detail 61 62 const new_table create = new_table{}; 63 64 template <bool top_level, typename base_type> 65 class basic_table_core : public basic_object_base<base_type> { 66 typedef basic_object_base<base_type> base_t; 67 friend class state; 68 friend class state_view; 69 70 template <typename... Args> 71 using is_global = meta::all<meta::boolean<top_level>, meta::is_c_str<Args>...>; 72 73 template <typename Fx> for_each(std::true_type,Fx && fx) const74 void for_each(std::true_type, Fx&& fx) const { 75 auto pp = stack::push_pop(*this); 76 stack::push(base_t::lua_state(), lua_nil); 77 while (lua_next(base_t::lua_state(), -2)) { 78 object key(base_t::lua_state(), -2); 79 object value(base_t::lua_state(), -1); 80 std::pair<object&, object&> keyvalue(key, value); 81 auto pn = stack::pop_n(base_t::lua_state(), 1); 82 fx(keyvalue); 83 } 84 } 85 86 template <typename Fx> for_each(std::false_type,Fx && fx) const87 void for_each(std::false_type, Fx&& fx) const { 88 auto pp = stack::push_pop(*this); 89 stack::push(base_t::lua_state(), lua_nil); 90 while (lua_next(base_t::lua_state(), -2)) { 91 object key(base_t::lua_state(), -2); 92 object value(base_t::lua_state(), -1); 93 auto pn = stack::pop_n(base_t::lua_state(), 1); 94 fx(key, value); 95 } 96 } 97 98 template <bool raw, typename Ret0, typename Ret1, typename... Ret, std::size_t... I, typename Keys> tuple_get(types<Ret0,Ret1,Ret...>,std::index_sequence<0,1,I...>,Keys && keys) const99 auto tuple_get(types<Ret0, Ret1, Ret...>, std::index_sequence<0, 1, I...>, Keys&& keys) const 100 -> decltype(stack::pop<std::tuple<Ret0, Ret1, Ret...>>(nullptr)) { 101 typedef decltype(stack::pop<std::tuple<Ret0, Ret1, Ret...>>(nullptr)) Tup; 102 return Tup( 103 traverse_get_optional<top_level, raw, Ret0>(meta::is_optional<meta::unqualified_t<Ret0>>(), detail::forward_get<0>(keys)), 104 traverse_get_optional<top_level, raw, Ret1>(meta::is_optional<meta::unqualified_t<Ret1>>(), detail::forward_get<1>(keys)), 105 traverse_get_optional<top_level, raw, Ret>(meta::is_optional<meta::unqualified_t<Ret>>(), detail::forward_get<I>(keys))...); 106 } 107 108 template <bool raw, typename Ret, std::size_t I, typename Keys> tuple_get(types<Ret>,std::index_sequence<I>,Keys && keys) const109 decltype(auto) tuple_get(types<Ret>, std::index_sequence<I>, Keys&& keys) const { 110 return traverse_get_optional<top_level, raw, Ret>(meta::is_optional<meta::unqualified_t<Ret>>(), detail::forward_get<I>(keys)); 111 } 112 113 template <bool raw, typename Pairs, std::size_t... I> tuple_set(std::index_sequence<I...>,Pairs && pairs)114 void tuple_set(std::index_sequence<I...>, Pairs&& pairs) { 115 auto pp = stack::push_pop < top_level && (is_global<decltype(detail::forward_get<I * 2>(pairs))...>::value) > (*this); 116 void(detail::swallow{ (stack::set_field<top_level, raw>(base_t::lua_state(), 117 detail::forward_get<I * 2>(pairs), 118 detail::forward_get<I * 2 + 1>(pairs), 119 lua_gettop(base_t::lua_state())), 120 0)... }); 121 } 122 123 template <bool global, bool raw, typename T, typename Key> traverse_get_deep(Key && key) const124 decltype(auto) traverse_get_deep(Key&& key) const { 125 stack::get_field<global, raw>(base_t::lua_state(), std::forward<Key>(key)); 126 return stack::get<T>(base_t::lua_state()); 127 } 128 129 template <bool global, bool raw, typename T, typename Key, typename... Keys> traverse_get_deep(Key && key,Keys &&...keys) const130 decltype(auto) traverse_get_deep(Key&& key, Keys&&... keys) const { 131 stack::get_field<global, raw>(base_t::lua_state(), std::forward<Key>(key)); 132 return traverse_get_deep<false, raw, T>(std::forward<Keys>(keys)...); 133 } 134 135 template <bool global, bool raw, typename T, std::size_t I, typename Key> traverse_get_deep_optional(int & popcount,Key && key) const136 decltype(auto) traverse_get_deep_optional(int& popcount, Key&& key) const { 137 typedef decltype(stack::get<T>(base_t::lua_state())) R; 138 auto p = stack::probe_get_field<global, raw, T>(base_t::lua_state(), std::forward<Key>(key), lua_gettop(base_t::lua_state())); 139 popcount += p.levels; 140 if (!p.success) 141 return R(nullopt); 142 return stack::get<T>(base_t::lua_state()); 143 } 144 145 template <bool global, bool raw, typename T, std::size_t I, typename Key, typename... Keys> traverse_get_deep_optional(int & popcount,Key && key,Keys &&...keys) const146 decltype(auto) traverse_get_deep_optional(int& popcount, Key&& key, Keys&&... keys) const { 147 auto p = I > 0 ? stack::probe_get_field<global>(base_t::lua_state(), std::forward<Key>(key), -1) : stack::probe_get_field<global>(base_t::lua_state(), std::forward<Key>(key), lua_gettop(base_t::lua_state())); 148 popcount += p.levels; 149 if (!p.success) 150 return T(nullopt); 151 return traverse_get_deep_optional<false, raw, T, I + 1>(popcount, std::forward<Keys>(keys)...); 152 } 153 154 template <bool global, bool raw, typename T, typename... Keys> traverse_get_optional(std::false_type,Keys &&...keys) const155 decltype(auto) traverse_get_optional(std::false_type, Keys&&... keys) const { 156 detail::clean<sizeof...(Keys)> c(base_t::lua_state()); 157 return traverse_get_deep<global, raw, T>(std::forward<Keys>(keys)...); 158 } 159 160 template <bool global, bool raw, typename T, typename... Keys> traverse_get_optional(std::true_type,Keys &&...keys) const161 decltype(auto) traverse_get_optional(std::true_type, Keys&&... keys) const { 162 int popcount = 0; 163 detail::ref_clean c(base_t::lua_state(), popcount); 164 return traverse_get_deep_optional<global, raw, T, 0>(popcount, std::forward<Keys>(keys)...); 165 } 166 167 template <bool global, bool raw, typename Key, typename Value> traverse_set_deep(Key && key,Value && value) const168 void traverse_set_deep(Key&& key, Value&& value) const { 169 stack::set_field<global, raw>(base_t::lua_state(), std::forward<Key>(key), std::forward<Value>(value)); 170 } 171 172 template <bool global, bool raw, typename Key, typename... Keys> traverse_set_deep(Key && key,Keys &&...keys) const173 void traverse_set_deep(Key&& key, Keys&&... keys) const { 174 stack::get_field<global, raw>(base_t::lua_state(), std::forward<Key>(key)); 175 traverse_set_deep<false, raw>(std::forward<Keys>(keys)...); 176 } 177 basic_table_core(lua_State * L,detail::global_tag t)178 basic_table_core(lua_State* L, detail::global_tag t) noexcept 179 : base_t(L, t) { 180 } 181 182 protected: basic_table_core(detail::no_safety_tag,lua_nil_t n)183 basic_table_core(detail::no_safety_tag, lua_nil_t n) 184 : base_t(n) { 185 } basic_table_core(detail::no_safety_tag,lua_State * L,int index)186 basic_table_core(detail::no_safety_tag, lua_State* L, int index) 187 : base_t(L, index) { 188 } basic_table_core(detail::no_safety_tag,lua_State * L,ref_index index)189 basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) 190 : base_t(L, index) { 191 } 192 template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_table_core(detail::no_safety_tag,T && r)193 basic_table_core(detail::no_safety_tag, T&& r) noexcept 194 : base_t(std::forward<T>(r)) { 195 } 196 template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_table_core(detail::no_safety_tag,lua_State * L,T && r)197 basic_table_core(detail::no_safety_tag, lua_State*L, T&& r) noexcept 198 : base_t(L, std::forward<T>(r)) { 199 } 200 201 public: 202 typedef basic_table_iterator<base_type> iterator; 203 typedef iterator const_iterator; 204 205 using base_t::lua_state; 206 207 basic_table_core() noexcept = default; 208 basic_table_core(const basic_table_core&) = default; 209 basic_table_core(basic_table_core&&) = default; 210 basic_table_core& operator=(const basic_table_core&) = default; 211 basic_table_core& operator=(basic_table_core&&) = default; basic_table_core(const stack_reference & r)212 basic_table_core(const stack_reference& r) 213 : basic_table_core(r.lua_state(), r.stack_index()) { 214 } basic_table_core(stack_reference && r)215 basic_table_core(stack_reference&& r) 216 : basic_table_core(r.lua_state(), r.stack_index()) { 217 } 218 template <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_table_core(lua_State * L,T && r)219 basic_table_core(lua_State* L, T&& r) 220 : base_t(L, std::forward<T>(r)) { 221 #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES 222 auto pp = stack::push_pop(*this); 223 constructor_handler handler{}; 224 stack::check<basic_table_core>(lua_state(), -1, handler); 225 #endif // Safety 226 } basic_table_core(lua_State * L,const new_table & nt)227 basic_table_core(lua_State* L, const new_table& nt) 228 : base_t(L, -stack::push(L, nt)) { 229 if (!is_stack_based<meta::unqualified_t<base_type>>::value) { 230 lua_pop(L, 1); 231 } 232 } basic_table_core(lua_State * L,int index=-1)233 basic_table_core(lua_State* L, int index = -1) 234 : basic_table_core(detail::no_safety, L, index) { 235 #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES 236 constructor_handler handler{}; 237 stack::check<basic_table_core>(L, index, handler); 238 #endif // Safety 239 } basic_table_core(lua_State * L,ref_index index)240 basic_table_core(lua_State* L, ref_index index) 241 : basic_table_core(detail::no_safety, L, index) { 242 #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES 243 auto pp = stack::push_pop(*this); 244 constructor_handler handler{}; 245 stack::check<basic_table_core>(lua_state(), -1, handler); 246 #endif // Safety 247 } 248 template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_table_core(T && r)249 basic_table_core(T&& r) noexcept 250 : basic_table_core(detail::no_safety, std::forward<T>(r)) { 251 #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES 252 if (!is_table<meta::unqualified_t<T>>::value) { 253 auto pp = stack::push_pop(*this); 254 constructor_handler handler{}; 255 stack::check<basic_table_core>(base_t::lua_state(), -1, handler); 256 } 257 #endif // Safety 258 } basic_table_core(lua_nil_t r)259 basic_table_core(lua_nil_t r) noexcept 260 : basic_table_core(detail::no_safety, r) { 261 } 262 begin() const263 iterator begin() const { 264 return iterator(*this); 265 } 266 end() const267 iterator end() const { 268 return iterator(); 269 } 270 cbegin() const271 const_iterator cbegin() const { 272 return begin(); 273 } 274 cend() const275 const_iterator cend() const { 276 return end(); 277 } 278 279 template <typename... Ret, typename... Keys> get(Keys &&...keys) const280 decltype(auto) get(Keys&&... keys) const { 281 static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); 282 auto pp = stack::push_pop<is_global<Keys...>::value>(*this); 283 return tuple_get<false>(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), std::forward_as_tuple(std::forward<Keys>(keys)...)); 284 } 285 286 template <typename T, typename Key> get_or(Key && key,T && otherwise) const287 decltype(auto) get_or(Key&& key, T&& otherwise) const { 288 typedef decltype(get<T>("")) U; 289 optional<U> option = get<optional<U>>(std::forward<Key>(key)); 290 if (option) { 291 return static_cast<U>(option.value()); 292 } 293 return static_cast<U>(std::forward<T>(otherwise)); 294 } 295 296 template <typename T, typename Key, typename D> get_or(Key && key,D && otherwise) const297 decltype(auto) get_or(Key&& key, D&& otherwise) const { 298 optional<T> option = get<optional<T>>(std::forward<Key>(key)); 299 if (option) { 300 return static_cast<T>(option.value()); 301 } 302 return static_cast<T>(std::forward<D>(otherwise)); 303 } 304 305 template <typename T, typename... Keys> traverse_get(Keys &&...keys) const306 decltype(auto) traverse_get(Keys&&... keys) const { 307 auto pp = stack::push_pop<is_global<Keys...>::value>(*this); 308 return traverse_get_optional<top_level, false, T>(meta::is_optional<meta::unqualified_t<T>>(), std::forward<Keys>(keys)...); 309 } 310 311 template <typename... Keys> traverse_set(Keys &&...keys)312 basic_table_core& traverse_set(Keys&&... keys) { 313 auto pp = stack::push_pop<is_global<Keys...>::value>(*this); 314 auto pn = stack::pop_n(base_t::lua_state(), static_cast<int>(sizeof...(Keys) - 2)); 315 traverse_set_deep<top_level, false>(std::forward<Keys>(keys)...); 316 return *this; 317 } 318 319 template <typename... Args> set(Args &&...args)320 basic_table_core& set(Args&&... args) { 321 tuple_set<false>(std::make_index_sequence<sizeof...(Args) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...)); 322 return *this; 323 } 324 325 template <typename... Ret, typename... Keys> raw_get(Keys &&...keys) const326 decltype(auto) raw_get(Keys&&... keys) const { 327 static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); 328 auto pp = stack::push_pop<is_global<Keys...>::value>(*this); 329 return tuple_get<true>(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), std::forward_as_tuple(std::forward<Keys>(keys)...)); 330 } 331 332 template <typename T, typename Key> raw_get_or(Key && key,T && otherwise) const333 decltype(auto) raw_get_or(Key&& key, T&& otherwise) const { 334 typedef decltype(raw_get<T>("")) U; 335 optional<U> option = raw_get<optional<U>>(std::forward<Key>(key)); 336 if (option) { 337 return static_cast<U>(option.value()); 338 } 339 return static_cast<U>(std::forward<T>(otherwise)); 340 } 341 342 template <typename T, typename Key, typename D> raw_get_or(Key && key,D && otherwise) const343 decltype(auto) raw_get_or(Key&& key, D&& otherwise) const { 344 optional<T> option = raw_get<optional<T>>(std::forward<Key>(key)); 345 if (option) { 346 return static_cast<T>(option.value()); 347 } 348 return static_cast<T>(std::forward<D>(otherwise)); 349 } 350 351 template <typename T, typename... Keys> traverse_raw_get(Keys &&...keys) const352 decltype(auto) traverse_raw_get(Keys&&... keys) const { 353 auto pp = stack::push_pop<is_global<Keys...>::value>(*this); 354 return traverse_get_optional<top_level, true, T>(meta::is_optional<meta::unqualified_t<T>>(), std::forward<Keys>(keys)...); 355 } 356 357 template <typename... Keys> traverse_raw_set(Keys &&...keys)358 basic_table_core& traverse_raw_set(Keys&&... keys) { 359 auto pp = stack::push_pop<is_global<Keys...>::value>(*this); 360 auto pn = stack::pop_n(base_t::lua_state(), static_cast<int>(sizeof...(Keys) - 2)); 361 traverse_set_deep<top_level, true>(std::forward<Keys>(keys)...); 362 return *this; 363 } 364 365 template <typename... Args> raw_set(Args &&...args)366 basic_table_core& raw_set(Args&&... args) { 367 tuple_set<true>(std::make_index_sequence<sizeof...(Args) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...)); 368 return *this; 369 } 370 371 template <typename T> set_usertype(usertype<T> & user)372 basic_table_core& set_usertype(usertype<T>& user) { 373 return set_usertype(usertype_traits<T>::name(), user); 374 } 375 376 template <typename Key, typename T> set_usertype(Key && key,usertype<T> & user)377 basic_table_core& set_usertype(Key&& key, usertype<T>& user) { 378 return set(std::forward<Key>(key), user); 379 } 380 381 template <typename Class, typename... Args> new_usertype(const std::string & name,Args &&...args)382 basic_table_core& new_usertype(const std::string& name, Args&&... args) { 383 usertype<Class> utype(std::forward<Args>(args)...); 384 set_usertype(name, utype); 385 return *this; 386 } 387 388 template <typename Class, typename CTor0, typename... CTor, typename... Args> new_usertype(const std::string & name,Args &&...args)389 basic_table_core& new_usertype(const std::string& name, Args&&... args) { 390 constructors<types<CTor0, CTor...>> ctor{}; 391 return new_usertype<Class>(name, ctor, std::forward<Args>(args)...); 392 } 393 394 template <typename Class, typename... CArgs, typename... Args> new_usertype(const std::string & name,constructors<CArgs...> ctor,Args &&...args)395 basic_table_core& new_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) { 396 usertype<Class> utype(ctor, std::forward<Args>(args)...); 397 set_usertype(name, utype); 398 return *this; 399 } 400 401 template <typename Class, typename... Args> new_simple_usertype(const std::string & name,Args &&...args)402 basic_table_core& new_simple_usertype(const std::string& name, Args&&... args) { 403 simple_usertype<Class> utype(base_t::lua_state(), std::forward<Args>(args)...); 404 set_usertype(name, utype); 405 return *this; 406 } 407 408 template <typename Class, typename CTor0, typename... CTor, typename... Args> new_simple_usertype(const std::string & name,Args &&...args)409 basic_table_core& new_simple_usertype(const std::string& name, Args&&... args) { 410 constructors<types<CTor0, CTor...>> ctor{}; 411 return new_simple_usertype<Class>(name, ctor, std::forward<Args>(args)...); 412 } 413 414 template <typename Class, typename... CArgs, typename... Args> new_simple_usertype(const std::string & name,constructors<CArgs...> ctor,Args &&...args)415 basic_table_core& new_simple_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) { 416 simple_usertype<Class> utype(base_t::lua_state(), ctor, std::forward<Args>(args)...); 417 set_usertype(name, utype); 418 return *this; 419 } 420 421 template <typename Class, typename... Args> create_simple_usertype(Args &&...args)422 simple_usertype<Class> create_simple_usertype(Args&&... args) { 423 simple_usertype<Class> utype(base_t::lua_state(), std::forward<Args>(args)...); 424 return utype; 425 } 426 427 template <typename Class, typename CTor0, typename... CTor, typename... Args> create_simple_usertype(Args &&...args)428 simple_usertype<Class> create_simple_usertype(Args&&... args) { 429 constructors<types<CTor0, CTor...>> ctor{}; 430 return create_simple_usertype<Class>(ctor, std::forward<Args>(args)...); 431 } 432 433 template <typename Class, typename... CArgs, typename... Args> create_simple_usertype(constructors<CArgs...> ctor,Args &&...args)434 simple_usertype<Class> create_simple_usertype(constructors<CArgs...> ctor, Args&&... args) { 435 simple_usertype<Class> utype(base_t::lua_state(), ctor, std::forward<Args>(args)...); 436 return utype; 437 } 438 439 template <bool read_only = true, typename... Args> new_enum(const string_view & name,Args &&...args)440 table new_enum(const string_view& name, Args&&... args) { 441 table target = create_with(std::forward<Args>(args)...); 442 if (read_only) { 443 table x = create_with( 444 meta_function::new_index, detail::fail_on_newindex, 445 meta_function::index, target); 446 table shim = create_named(name, metatable_key, x); 447 return shim; 448 } 449 else { 450 set(name, target); 451 return target; 452 } 453 } 454 455 template <typename T, bool read_only = true> new_enum(const string_view & name,std::initializer_list<std::pair<string_view,T>> items)456 table new_enum(const string_view& name, std::initializer_list<std::pair<string_view, T>> items) { 457 table target = create(static_cast<int>(items.size()), static_cast<int>(0)); 458 for (const auto& kvp : items) { 459 target.set(kvp.first, kvp.second); 460 } 461 if (read_only) { 462 table x = create_with( 463 meta_function::new_index, detail::fail_on_newindex, 464 meta_function::index, target); 465 table shim = create_named(name, metatable_key, x); 466 return shim; 467 } 468 else { 469 set(name, target); 470 return target; 471 } 472 } 473 474 template <typename Fx> for_each(Fx && fx) const475 void for_each(Fx&& fx) const { 476 typedef meta::is_invokable<Fx(std::pair<object, object>)> is_paired; 477 for_each(is_paired(), std::forward<Fx>(fx)); 478 } 479 size() const480 size_t size() const { 481 auto pp = stack::push_pop(*this); 482 lua_len(base_t::lua_state(), -1); 483 return stack::pop<size_t>(base_t::lua_state()); 484 } 485 empty() const486 bool empty() const { 487 return cbegin() == cend(); 488 } 489 490 template <typename T> operator [](T && key)491 proxy<basic_table_core&, T> operator[](T&& key) & { 492 return proxy<basic_table_core&, T>(*this, std::forward<T>(key)); 493 } 494 495 template <typename T> operator [](T && key) const496 proxy<const basic_table_core&, T> operator[](T&& key) const& { 497 return proxy<const basic_table_core&, T>(*this, std::forward<T>(key)); 498 } 499 500 template <typename T> operator [](T && key)501 proxy<basic_table_core, T> operator[](T&& key) && { 502 return proxy<basic_table_core, T>(*this, std::forward<T>(key)); 503 } 504 505 template <typename Sig, typename Key, typename... Args> set_function(Key && key,Args &&...args)506 basic_table_core& set_function(Key&& key, Args&&... args) { 507 set_fx(types<Sig>(), std::forward<Key>(key), std::forward<Args>(args)...); 508 return *this; 509 } 510 511 template <typename Key, typename... Args> set_function(Key && key,Args &&...args)512 basic_table_core& set_function(Key&& key, Args&&... args) { 513 set_fx(types<>(), std::forward<Key>(key), std::forward<Args>(args)...); 514 return *this; 515 } 516 517 template <typename... Args> add(Args &&...args)518 basic_table_core& add(Args&&... args) { 519 auto pp = stack::push_pop(*this); 520 (void)detail::swallow{ 0, 521 (stack::set_ref(base_t::lua_state(), std::forward<Args>(args)), 0)... }; 522 return *this; 523 } 524 525 private: 526 template <typename R, typename... Args, typename Fx, typename Key, typename = std::result_of_t<Fx(Args...)>> set_fx(types<R (Args...)>,Key && key,Fx && fx)527 void set_fx(types<R(Args...)>, Key&& key, Fx&& fx) { 528 set_resolved_function<R(Args...)>(std::forward<Key>(key), std::forward<Fx>(fx)); 529 } 530 531 template <typename Fx, typename Key, meta::enable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler> set_fx(types<>,Key && key,Fx && fx)532 void set_fx(types<>, Key&& key, Fx&& fx) { 533 set(std::forward<Key>(key), std::forward<Fx>(fx)); 534 } 535 536 template <typename Fx, typename Key, typename... Args, meta::disable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler> set_fx(types<>,Key && key,Fx && fx,Args &&...args)537 void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) { 538 set(std::forward<Key>(key), as_function_reference(std::forward<Fx>(fx), std::forward<Args>(args)...)); 539 } 540 541 template <typename... Sig, typename... Args, typename Key> set_resolved_function(Key && key,Args &&...args)542 void set_resolved_function(Key&& key, Args&&... args) { 543 set(std::forward<Key>(key), as_function_reference<function_sig<Sig...>>(std::forward<Args>(args)...)); 544 } 545 546 public: create(lua_State * L,int narr=0,int nrec=0)547 static inline table create(lua_State* L, int narr = 0, int nrec = 0) { 548 lua_createtable(L, narr, nrec); 549 table result(L); 550 lua_pop(L, 1); 551 return result; 552 } 553 554 template <typename Key, typename Value, typename... Args> create(lua_State * L,int narr,int nrec,Key && key,Value && value,Args &&...args)555 static inline table create(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { 556 lua_createtable(L, narr, nrec); 557 table result(L); 558 result.set(std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); 559 lua_pop(L, 1); 560 return result; 561 } 562 563 template <typename... Args> create_with(lua_State * L,Args &&...args)564 static inline table create_with(lua_State* L, Args&&... args) { 565 static_assert(sizeof...(Args) % 2 == 0, "You must have an even number of arguments for a key, value ... list."); 566 static const int narr = static_cast<int>(meta::count_2_for_pack<std::is_integral, Args...>::value); 567 return create(L, narr, static_cast<int>((sizeof...(Args) / 2) - narr), std::forward<Args>(args)...); 568 } 569 create(int narr=0,int nrec=0)570 table create(int narr = 0, int nrec = 0) { 571 return create(base_t::lua_state(), narr, nrec); 572 } 573 574 template <typename Key, typename Value, typename... Args> create(int narr,int nrec,Key && key,Value && value,Args &&...args)575 table create(int narr, int nrec, Key&& key, Value&& value, Args&&... args) { 576 return create(base_t::lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); 577 } 578 579 template <typename Name> create(Name && name,int narr=0,int nrec=0)580 table create(Name&& name, int narr = 0, int nrec = 0) { 581 table x = create(base_t::lua_state(), narr, nrec); 582 this->set(std::forward<Name>(name), x); 583 return x; 584 } 585 586 template <typename Name, typename Key, typename Value, typename... Args> create(Name && name,int narr,int nrec,Key && key,Value && value,Args &&...args)587 table create(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { 588 table x = create(base_t::lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); 589 this->set(std::forward<Name>(name), x); 590 return x; 591 } 592 593 template <typename... Args> create_with(Args &&...args)594 table create_with(Args&&... args) { 595 return create_with(base_t::lua_state(), std::forward<Args>(args)...); 596 } 597 598 template <typename Name, typename... Args> create_named(Name && name,Args &&...args)599 table create_named(Name&& name, Args&&... args) { 600 static const int narr = static_cast<int>(meta::count_2_for_pack<std::is_integral, Args...>::value); 601 return create(std::forward<Name>(name), narr, (sizeof...(Args) / 2) - narr, std::forward<Args>(args)...); 602 } 603 }; 604 } // namespace sol 605 606 #endif // SOL_TABLE_CORE_HPP 607