// The MIT License (MIT) // Copyright (c) 2013-2016 Rapptz, ThePhD and contributors // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #ifndef SOL_TABLE_CORE_HPP #define SOL_TABLE_CORE_HPP #include "proxy.hpp" #include "stack.hpp" #include "function_types.hpp" #include "usertype.hpp" #include "table_iterator.hpp" namespace sol { namespace detail { template struct clean { lua_State* L; clean(lua_State* L) : L(L) {} ~clean() { lua_pop(L, static_cast(n)); } }; struct ref_clean { lua_State* L; int& n; ref_clean(lua_State* L, int& n) : L(L), n(n) {} ~ref_clean() { lua_pop(L, static_cast(n)); } }; } template class basic_table_core : public base_t { friend class state; friend class state_view; template using is_global = meta::all, meta::is_c_str...>; template void for_each(std::true_type, Fx&& fx) const { auto pp = stack::push_pop( *this ); stack::push( base_t::lua_state( ), nil ); while ( lua_next( base_t::lua_state( ), -2 ) ) { sol::object key( base_t::lua_state( ), -2 ); sol::object value( base_t::lua_state( ), -1 ); std::pair keyvalue(key, value); fx( keyvalue ); lua_pop( base_t::lua_state( ), 1 ); } } template void for_each(std::false_type, Fx&& fx) const { auto pp = stack::push_pop( *this ); stack::push( base_t::lua_state( ), nil ); while ( lua_next( base_t::lua_state( ), -2 ) ) { sol::object key( base_t::lua_state( ), -2 ); sol::object value( base_t::lua_state( ), -1 ); fx( key, value ); lua_pop( base_t::lua_state( ), 1 ); } } template auto tuple_get( types, std::index_sequence<0, 1, I...>, Keys&& keys ) const -> decltype(stack::pop>(nullptr)){ typedef decltype(stack::pop>(nullptr)) Tup; return Tup( traverse_get_optional(meta::is_specialization_of>(), detail::forward_get<0>(keys)), traverse_get_optional(meta::is_specialization_of>(), detail::forward_get<1>(keys)), traverse_get_optional(meta::is_specialization_of>(), detail::forward_get(keys))... ); } template decltype(auto) tuple_get( types, std::index_sequence, Keys&& keys ) const { return traverse_get_optional( meta::is_specialization_of>(), detail::forward_get(keys) ); } template void tuple_set( std::index_sequence, Pairs&& pairs ) { auto pp = stack::push_pop(pairs))...>::value)>(*this); void(detail::swallow{ (stack::set_field(base_t::lua_state(), detail::forward_get(pairs), detail::forward_get(pairs), lua_gettop(base_t::lua_state()) ), 0)... }); } template decltype(auto) traverse_get_deep( Key&& key ) const { stack::get_field( base_t::lua_state( ), std::forward( key ) ); return stack::get( base_t::lua_state( ) ); } template decltype(auto) traverse_get_deep( Key&& key, Keys&&... keys ) const { stack::get_field( base_t::lua_state( ), std::forward( key ) ); return traverse_get_deep(std::forward(keys)...); } template decltype(auto) traverse_get_deep_optional( int& popcount, Key&& key ) const { typedef decltype(stack::get(base_t::lua_state())) R; auto p = stack::probe_get_field(base_t::lua_state(), std::forward(key), lua_gettop(base_t::lua_state())); popcount += p.levels; if (!p.success) return R(nullopt); return stack::get( base_t::lua_state( ) ); } template decltype(auto) traverse_get_deep_optional( int& popcount, Key&& key, Keys&&... keys ) const { auto p = I > 0 ? stack::probe_get_field(base_t::lua_state(), std::forward(key), -1) : stack::probe_get_field( base_t::lua_state( ), std::forward( key ), lua_gettop(base_t::lua_state())); popcount += p.levels; if (!p.success) return T(nullopt); return traverse_get_deep_optional(popcount, std::forward(keys)...); } template decltype(auto) traverse_get_optional( std::false_type, Keys&&... keys ) const { detail::clean c(base_t::lua_state()); return traverse_get_deep(std::forward(keys)...); } template decltype(auto) traverse_get_optional( std::true_type, Keys&&... keys ) const { int popcount = 0; detail::ref_clean c(base_t::lua_state(), popcount); return traverse_get_deep_optional(popcount, std::forward(keys)...); } template void traverse_set_deep( Key&& key, Value&& value ) const { stack::set_field( base_t::lua_state( ), std::forward( key ), std::forward(value) ); } template void traverse_set_deep( Key&& key, Keys&&... keys ) const { stack::get_field( base_t::lua_state( ), std::forward( key ) ); traverse_set_deep(std::forward(keys)...); } basic_table_core(lua_State* L, detail::global_tag t) noexcept : reference(L, t) { } public: typedef basic_table_iterator iterator; typedef iterator const_iterator; basic_table_core( ) noexcept : base_t( ) { } template , basic_table_core>>, std::is_base_of>> = meta::enabler> basic_table_core( T&& r ) noexcept : base_t( std::forward(r) ) { #ifdef SOL_CHECK_ARGUMENTS if (!is_table>::value) { auto pp = stack::push_pop(*this); stack::check(base_t::lua_state(), -1, type_panic); } #endif // Safety } basic_table_core(const basic_table_core&) = default; basic_table_core(basic_table_core&&) = default; basic_table_core& operator=(const basic_table_core&) = default; basic_table_core& operator=(basic_table_core&&) = default; basic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) {} basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {} basic_table_core( lua_State* L, int index = -1 ) : base_t( L, index ) { #ifdef SOL_CHECK_ARGUMENTS stack::check(L, index, type_panic); #endif // Safety } iterator begin () const { return iterator(*this); } iterator end() const { return iterator(); } const_iterator cbegin() const { return begin(); } const_iterator cend() const { return end(); } template decltype(auto) get( Keys&&... keys ) const { static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); auto pp = stack::push_pop::value>(*this); return tuple_get( types( ), std::make_index_sequence( ), std::forward_as_tuple(std::forward(keys)...)); } template decltype(auto) get_or(Key&& key, T&& otherwise) const { typedef decltype(get("")) U; sol::optional option = get>(std::forward(key)); if (option) { return static_cast(option.value()); } return static_cast(std::forward(otherwise)); } template decltype(auto) get_or(Key&& key, D&& otherwise) const { sol::optional option = get>(std::forward(key)); if (option) { return static_cast(option.value()); } return static_cast(std::forward(otherwise)); } template decltype(auto) traverse_get( Keys&&... keys ) const { auto pp = stack::push_pop::value>(*this); return traverse_get_optional(meta::is_specialization_of>(), std::forward(keys)...); } template basic_table_core& traverse_set( Keys&&... keys ) { auto pp = stack::push_pop::value>(*this); traverse_set_deep(std::forward(keys)...); lua_pop(base_t::lua_state(), static_cast(sizeof...(Keys)-2)); return *this; } template basic_table_core& set( Args&&... args ) { tuple_set(std::make_index_sequence(), std::forward_as_tuple(std::forward(args)...)); return *this; } template basic_table_core& set_usertype( usertype& user ) { return set_usertype(usertype_traits::name, user); } template basic_table_core& set_usertype( Key&& key, usertype& user ) { return set(std::forward(key), user); } template basic_table_core& new_usertype(const std::string& name, Args&&... args) { usertype utype(std::forward(args)...); set_usertype(name, utype); return *this; } template basic_table_core& new_usertype(const std::string& name, Args&&... args) { constructors> ctor{}; return new_usertype(name, ctor, std::forward(args)...); } template basic_table_core& new_usertype(const std::string& name, constructors ctor, Args&&... args) { usertype utype(ctor, std::forward(args)...); set_usertype(name, utype); return *this; } template void for_each( Fx&& fx ) const { typedef meta::is_invokable )> is_paired; for_each(is_paired(), std::forward(fx)); } size_t size( ) const { auto pp = stack::push_pop( *this ); return lua_rawlen(base_t::lua_state(), -1); } bool empty() const { return cbegin() == cend(); } template proxy operator[]( T&& key ) & { return proxy( *this, std::forward( key ) ); } template proxy operator[]( T&& key ) const & { return proxy( *this, std::forward( key ) ); } template proxy operator[]( T&& key ) && { return proxy( *this, std::forward( key ) ); } template basic_table_core& set_function( Key&& key, Args&&... args ) { set_fx( types( ), std::forward( key ), std::forward( args )... ); return *this; } template basic_table_core& set_function( Key&& key, Args&&... args ) { set_fx( types<>( ), std::forward( key ), std::forward( args )... ); return *this; } private: template> void set_fx( types, Key&& key, Fx&& fx ) { set_resolved_function( std::forward( key ), std::forward( fx ) ); } template>> = meta::enabler> void set_fx( types<>, Key&& key, Fx&& fx ) { set(std::forward(key), std::forward(fx)); } template>> = meta::enabler> void set_fx( types<>, Key&& key, Fx&& fx, Args&&... args ) { set(std::forward(key), function_args(std::forward(fx), std::forward(args)...)); } template void set_resolved_function( Key&& key, Args&&... args ) { set(std::forward(key), function_args>(std::forward(args)...)); } public: static inline table create(lua_State* L, int narr = 0, int nrec = 0) { lua_createtable(L, narr, nrec); table result(L); lua_pop(L, 1); return result; } template static inline table create(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { lua_createtable(L, narr, nrec); table result(L); result.set(std::forward(key), std::forward(value), std::forward(args)...); lua_pop(L, 1); return result; } template static inline table create_with(lua_State* L, Args&&... args) { static const int narr = static_cast(meta::count_2_for_pack::value); return create(L, narr, static_cast((sizeof...(Args) / 2) - narr), std::forward(args)...); } table create(int narr = 0, int nrec = 0) { return create(base_t::lua_state(), narr, nrec); } template table create(int narr, int nrec, Key&& key, Value&& value, Args&&... args) { return create(base_t::lua_state(), narr, nrec, std::forward(key), std::forward(value), std::forward(args)...); } template table create(Name&& name, int narr = 0, int nrec = 0) { table x = create(base_t::lua_state(), narr, nrec); this->set(std::forward(name), x); return x; } template table create(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { table x = create(base_t::lua_state(), narr, nrec, std::forward(key), std::forward(value), std::forward(args)...); this->set(std::forward(name), x); return x; } template table create_with(Args&&... args) { return create_with(base_t::lua_state(), std::forward(args)...); } template table create_named(Name&& name, Args&&... args) { static const int narr = static_cast(meta::count_2_for_pack::value); return create(std::forward(name), narr, sizeof...(Args) / 2 - narr, std::forward(args)...); } }; } // sol #endif // SOL_TABLE_CORE_HPP