// 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 table_core : public reference { friend class state; friend class state_view; template using is_global = meta::And, meta::is_c_str...>; template void for_each(std::true_type, Fx&& fx) const { auto pp = stack::push_pop( *this ); stack::push( lua_state( ), nil ); while ( lua_next( this->lua_state( ), -2 ) ) { sol::object key( lua_state( ), -2 ); sol::object value( lua_state( ), -1 ); std::pair keyvalue(key, value); fx( keyvalue ); lua_pop( lua_state( ), 1 ); } } template void for_each(std::false_type, Fx&& fx) const { auto pp = stack::push_pop( *this ); stack::push( lua_state( ), nil ); while ( lua_next( this->lua_state( ), -2 ) ) { sol::object key( lua_state( ), -2 ); sol::object value( lua_state( ), -1 ); fx( key, value ); lua_pop( 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, sol::optional>(), detail::forward_get<0>(keys)), traverse_get_optional(meta::is_specialization_of, sol::optional>(), detail::forward_get<1>(keys)), traverse_get_optional(meta::is_specialization_of, sol::optional>(), detail::forward_get(keys))... ); } template decltype(auto) tuple_get( types, std::index_sequence, Keys&& keys ) const { return traverse_get_optional( meta::is_specialization_of, sol::optional>(), 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(lua_state(), detail::forward_get(pairs), detail::forward_get(pairs) ), 0)... }); } template decltype(auto) traverse_get_deep( Key&& key ) const { stack::get_field( lua_state( ), std::forward( key ) ); return stack::get( lua_state( ) ); } template decltype(auto) traverse_get_deep( Key&& key, Keys&&... keys ) const { stack::get_field( lua_state( ), std::forward( key ) ); return traverse_get_deep(std::forward(keys)...); } template decltype(auto) traverse_get_deep_optional( int& popcount, Key&& key ) const { auto p = stack::probe_get_field(lua_state(), std::forward(key), -1); popcount += p.levels; if (!p.success) return T(nullopt); return stack::get( lua_state( ) ); } template decltype(auto) traverse_get_deep_optional( int& popcount, Key&& key, Keys&&... keys ) const { auto p = I > 0 ? stack::probe_get_field(lua_state(), std::forward(key), - 1) : stack::probe_get_field( lua_state( ), std::forward( key ) ); 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(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(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( lua_state( ), std::forward( key ), std::forward(value) ); } template void traverse_set_deep( Key&& key, Keys&&... keys ) const { stack::get_field( lua_state( ), std::forward( key ) ); traverse_set_deep(std::forward(keys)...); } table_core(lua_State* L, detail::global_tag t) noexcept : reference(L, t) { } public: table_core( ) noexcept : reference( ) { } table_core( const table_core& global ) noexcept : reference( global ) { } table_core( lua_State* L, int index = -1 ) : reference( L, index ) { type_assert( L, index, type::table ); } table_iterator begin () const { return table_iterator(*this); } table_iterator end() const { return table_iterator(); } table_iterator cbegin() const { return begin(); } table_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::index_sequence_for( ), 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, sol::optional>(), std::forward(keys)...); } template table_core& traverse_set( Keys&&... keys ) { auto pp = stack::push_pop::value>(*this); traverse_set_deep(std::forward(keys)...); lua_pop(lua_state(), static_cast(sizeof...(Keys)-2)); return *this; } template table_core& set( Args&&... args ) { tuple_set(std::make_index_sequence(), std::forward_as_tuple(std::forward(args)...)); return *this; } template table_core& set_usertype( usertype& user ) { return set_usertype(usertype_traits::name, user); } template table_core& set_usertype( Key&& key, usertype& user ) { return set(std::forward(key), user); } template table_core& new_usertype(const std::string& name, Args&&... args) { usertype utype(std::forward(args)...); set_usertype(name, utype); return *this; } template table_core& new_usertype(const std::string& name, Args&&... args) { constructors> ctor{}; return new_usertype(name, ctor, std::forward(args)...); } template 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_callable )> is_paired; for_each(is_paired(), std::forward(fx)); } size_t size( ) const { auto pp = stack::push_pop( *this ); return lua_rawlen(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 table_core& set_function( Key&& key, Args&&... args ) { set_fx( types( ), std::forward( key ), std::forward( args )... ); return *this; } template 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, overload_set>> = 0> void set_fx( types<>, Key&& key, Fx&& fx ) { set(std::forward(key), std::forward(fx)); } template, overload_set>> = 0> 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_if_2_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(lua_state(), narr, nrec); } template table create(int narr, int nrec, Key&& key, Value&& value, Args&&... args) { return create(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(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(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(lua_state(), std::forward(args)...); } template table create_named(Name&& name, Args&&... args) { static const int narr = static_cast(meta::count_if_2_pack::value); return create(lua_state(), narr, sizeof...(Args) / 2 - narr, std::forward(args)...); } }; } // sol #endif // SOL_TABLE_CORE_HPP