From 27f09fbb35bea41a5d624ff591593e266a30acf9 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Sat, 30 Jan 2016 04:21:33 -0500 Subject: [PATCH] variadic set - introduction of `state_view` type to allow for all of the benefits of `state` without destructing lua instance. --- sol/proxy.hpp | 4 +- sol/reference.hpp | 9 ++ sol/stack.hpp | 23 ++++ sol/state.hpp | 251 ++-------------------------------------- sol/state_view.hpp | 280 +++++++++++++++++++++++++++++++++++++++++++++ sol/table_core.hpp | 94 +++++++++------ 6 files changed, 381 insertions(+), 280 deletions(-) create mode 100644 sol/state_view.hpp diff --git a/sol/proxy.hpp b/sol/proxy.hpp index 3dbe5939..c233900b 100644 --- a/sol/proxy.hpp +++ b/sol/proxy.hpp @@ -30,13 +30,13 @@ namespace sol { template struct proxy { private: - Table& tbl; + Table tbl; If>, Key&, Unqualified> key; public: template - proxy(Table& table, T&& key) : tbl(table), key(std::forward(key)) {} + proxy(Table table, T&& key) : tbl(table), key(std::forward(key)) {} template proxy& set(T&& item) { diff --git a/sol/reference.hpp b/sol/reference.hpp index 9c10f553..5748c746 100644 --- a/sol/reference.hpp +++ b/sol/reference.hpp @@ -25,6 +25,15 @@ #include "types.hpp" namespace sol { +namespace detail { +template +struct push_pop { + T t; + push_pop (T x) : t(x) { t.push(); } + ~push_pop() { t.pop(); } +}; +} // detail + class reference { private: lua_State* L = nullptr; // non-owning diff --git a/sol/stack.hpp b/sol/stack.hpp index 2a8f231d..35afc608 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -133,6 +133,29 @@ true; false; #endif +inline void lua_getglobali(lua_State* L, lua_Integer n) { +#if SOL_LUA_VERSION >= 503 + lua_geti(L, LUA_RIDX_GLOBALS, n); +#else + lua_pushglobaltable(L); + lua_pushinteger(L, n); + lua_gettable(L, -2); + lua_remove(L, -2); // remove the global table, leave final value on the stack +#endif +} + +inline void lua_setglobali(lua_State* L, lua_Integer n) { +#if SOL_LUA_VERSION >= 503 + lua_seti(L, LUA_RIDX_GLOBALS, n); +#else + lua_pushglobaltable(L); + lua_pushinteger(L, n); + lua_pushvalue(L, -3) + lua_settable(L, -3); + lua_pop(L, 2); // remove table, and the copy of the value +#endif +} + template inline int push_confirmed_userdata(lua_State* L, Key&& metatablekey, Args&&... args) { T* pdatum = static_cast(lua_newuserdata(L, sizeof(T))); diff --git a/sol/state.hpp b/sol/state.hpp index 394afe77..ba2d33b1 100644 --- a/sol/state.hpp +++ b/sol/state.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 @@ -22,256 +22,19 @@ #ifndef SOL_STATE_HPP #define SOL_STATE_HPP -#include "error.hpp" -#include "table.hpp" -#include +#include "state_view.hpp" namespace sol { -namespace detail { -inline int atpanic(lua_State* L) { - const char* message = lua_tostring(L, -1); - std::string err = message ? message : "An unexpected error occurred and forced the lua state to call atpanic"; - throw error(err); -} -} // detail - -enum class lib : char { - base, - package, - coroutine, - string, - os, - math, - table, - debug, - bit32, - io, - count -}; - -class state { +class state : private std::unique_ptr, public state_view { private: - std::unique_ptr L; - table reg; - global_table globals; + typedef std::unique_ptr unique_base; public: + using state_view::get; state(lua_CFunction panic = detail::atpanic): - L(luaL_newstate(), lua_close), - reg(L.get(), LUA_REGISTRYINDEX), - globals(detail::global_overload, reg) { + unique_base(luaL_newstate(), lua_close), + state_view(unique_base::get()) { set_panic(panic); } - - lua_State* lua_state() const { - return L.get(); - } - - template - void open_libraries(Args&&... args) { - static_assert(are_same::value, "all types must be libraries"); - if(sizeof...(args) == 0) { - luaL_openlibs(L.get()); - return; - } - - lib libraries[1 + sizeof...(args)] = { lib::count, std::forward(args)... }; - - for(auto&& library : libraries) { - switch(library) { -#if SOL_LUA_VERSION <= 501 && defined(SOL_LUAJIT) - case lib::coroutine: -#endif // luajit opens coroutine base stuff - case lib::base: - luaL_requiref(L.get(), "base", luaopen_base, 1); - lua_pop(L.get(), 1); - break; - case lib::package: - luaL_requiref(L.get(), "package", luaopen_package, 1); - lua_pop(L.get(), 1); - break; -#if SOL_LUA_VERSION > 501 - case lib::coroutine: - luaL_requiref(L.get(), "coroutine", luaopen_coroutine, 1); - lua_pop(L.get(), 1); - break; -#endif // Lua 5.2+ only - case lib::string: - luaL_requiref(L.get(), "string", luaopen_string, 1); - lua_pop(L.get(), 1); - break; - case lib::table: - luaL_requiref(L.get(), "table", luaopen_table, 1); - lua_pop(L.get(), 1); - break; - case lib::math: - luaL_requiref(L.get(), "math", luaopen_math, 1); - lua_pop(L.get(), 1); - break; - case lib::bit32: -#if SOL_LUA_VERSION > 510 - luaL_requiref(L.get(), "bit32", luaopen_bit32, 1); - lua_pop(L.get(), 1); -#else -#endif // Lua 5.2+ only - break; - case lib::io: - luaL_requiref(L.get(), "io", luaopen_io, 1); - lua_pop(L.get(), 1); - break; - case lib::os: - luaL_requiref(L.get(), "os", luaopen_os, 1); - lua_pop(L.get(), 1); - break; - case lib::debug: - luaL_requiref(L.get(), "debug", luaopen_debug, 1); - lua_pop(L.get(), 1); - break; - case lib::count: - break; - } - } - } - - void script(const std::string& code) { - if(luaL_dostring(L.get(), code.c_str())) { - lua_error(L.get()); - } - } - - void open_file(const std::string& filename) { - if(luaL_dofile(L.get(), filename.c_str())) { - lua_error(L.get()); - } - } - - template - auto get(Keys&&... keys) const - -> decltype(globals.get(std::forward(keys)...)) { - return globals.get(std::forward(keys)...); - } - - template - state& set(T&& key, U&& value) { - globals.set(std::forward(key), std::forward(value)); - return *this; - } - - template - SOL_DEPRECATED table& set_userdata(usertype& user) { - return set_usertype(user); - } - - template - SOL_DEPRECATED table& set_userdata(Key&& key, usertype& user) { - return set_usertype(std::forward(key), user); - } - - template - SOL_DEPRECATED state& new_userdata(const std::string& name, Args&&... args) { - return new_usertype(name, std::forward(args)...); - } - - template - SOL_DEPRECATED state& new_userdata(const std::string& name, constructors ctor, Args&&... args) { - return new_usertype(name, std::move(ctor), std::forward(args)...); - } - - template - state& set_usertype(usertype& user) { - return set_usertype(usertype_traits::name, user); - } - - template - state& set_usertype(Key&& key, usertype& user) { - globals.set_usertype(std::forward(key), user); - return *this; - } - - template - state& new_usertype(const std::string& name, Args&&... args) { - constructors> ctor{}; - return new_usertype(name, ctor, std::forward(args)...); - } - - template - state& 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) { - globals.for_each(std::forward(fx)); - } - - template - table create_table(T&& key, int narr = 0, int nrec = 0) { - lua_createtable(L.get(), narr, nrec); - table result(L.get()); - lua_pop(L.get(), 1); - globals.set(std::forward(key), result); - return result; - } - - table create_table(int narr = 0, int nrec = 0) { - lua_createtable(L.get(), narr, nrec); - table result(L.get()); - lua_pop(L.get(), 1); - return result; - } - - global_table global() const { - return globals; - } - - table registry() const { - return reg; - } - - void set_panic(lua_CFunction panic){ - lua_atpanic(L.get(), panic); - } - - template - proxy operator[](T&& key) { - return globals[std::forward(key)]; - } - - template - proxy operator[](T&& key) const { - return globals[std::forward(key)]; - } - - template - state& set_function(Key&& key, R fun_ptr(Args...)){ - globals.set_function(std::forward(key), fun_ptr); - return *this; - } - - template - state& set_function(Key&& key, Sig* fun_ptr){ - globals.set_function(std::forward(key), fun_ptr); - return *this; - } - - template - state& set_function(Key&& key, R (C::*mem_ptr)(Args...), T&& obj) { - globals.set_function(std::forward(key), mem_ptr, std::forward(obj)); - return *this; - } - - template - state& set_function(Key&& key, Sig C::* mem_ptr, T&& obj) { - globals.set_function(std::forward(key), mem_ptr, std::forward(obj)); - return *this; - } - - template - state& set_function(Key&& key, Fx&& fx) { - globals.set_function(std::forward(key), std::forward(fx)); - return *this; - } }; } // sol diff --git a/sol/state_view.hpp b/sol/state_view.hpp new file mode 100644 index 00000000..beaa0c30 --- /dev/null +++ b/sol/state_view.hpp @@ -0,0 +1,280 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2016 Rapptz 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_STATE_VIEW_HPP +#define SOL_STATE_VIEW_HPP + +#include "error.hpp" +#include "table.hpp" +#include + +namespace sol { +namespace detail { +inline int atpanic(lua_State* L) { + const char* message = lua_tostring(L, -1); + std::string err = message ? message : "An unexpected error occurred and forced the lua state to call atpanic"; + throw error(err); +} +} // detail + +enum class lib : char { + base, + package, + coroutine, + string, + os, + math, + table, + debug, + bit32, + io, + count +}; + +class state_view { +private: + lua_State* L; + table reg; + global_table globals; +public: + state_view(lua_State* L): + L(L), + reg(L, LUA_REGISTRYINDEX), + globals(detail::global_overload, reg) { + + } + + lua_State* lua_state() const { + return L; + } + + template + void open_libraries(Args&&... args) { + static_assert(are_same::value, "all types must be libraries"); + if(sizeof...(args) == 0) { + luaL_openlibs(L); + return; + } + + lib libraries[1 + sizeof...(args)] = { lib::count, std::forward(args)... }; + + for(auto&& library : libraries) { + switch(library) { +#if SOL_LUA_VERSION <= 501 && defined(SOL_LUAJIT) + case lib::coroutine: +#endif // luajit opens coroutine base stuff + case lib::base: + luaL_requiref(L, "base", luaopen_base, 1); + lua_pop(L, 1); + break; + case lib::package: + luaL_requiref(L, "package", luaopen_package, 1); + lua_pop(L, 1); + break; +#if SOL_LUA_VERSION > 501 + case lib::coroutine: + luaL_requiref(L, "coroutine", luaopen_coroutine, 1); + lua_pop(L, 1); + break; +#endif // Lua 5.2+ only + case lib::string: + luaL_requiref(L, "string", luaopen_string, 1); + lua_pop(L, 1); + break; + case lib::table: + luaL_requiref(L, "table", luaopen_table, 1); + lua_pop(L, 1); + break; + case lib::math: + luaL_requiref(L, "math", luaopen_math, 1); + lua_pop(L, 1); + break; + case lib::bit32: +#if SOL_LUA_VERSION > 510 + luaL_requiref(L, "bit32", luaopen_bit32, 1); + lua_pop(L, 1); +#else +#endif // Lua 5.2+ only + break; + case lib::io: + luaL_requiref(L, "io", luaopen_io, 1); + lua_pop(L, 1); + break; + case lib::os: + luaL_requiref(L, "os", luaopen_os, 1); + lua_pop(L, 1); + break; + case lib::debug: + luaL_requiref(L, "debug", luaopen_debug, 1); + lua_pop(L, 1); + break; + case lib::count: + break; + } + } + } + + void script(const std::string& code) { + if(luaL_dostring(L, code.c_str())) { + lua_error(L); + } + } + + void open_file(const std::string& filename) { + if(luaL_dofile(L, filename.c_str())) { + lua_error(L); + } + } + + template + auto get(Keys&&... keys) const + -> decltype(globals.get(std::forward(keys)...)) { + return globals.get(std::forward(keys)...); + } + + template + state_view& set(T&& key, U&& value) { + globals.set(std::forward(key), std::forward(value)); + return *this; + } + + template + SOL_DEPRECATED table& set_userdata(usertype& user) { + return set_usertype(user); + } + + template + SOL_DEPRECATED table& set_userdata(Key&& key, usertype& user) { + return set_usertype(std::forward(key), user); + } + + template + SOL_DEPRECATED state_view& new_userdata(const std::string& name, Args&&... args) { + return new_usertype(name, std::forward(args)...); + } + + template + SOL_DEPRECATED state_view& new_userdata(const std::string& name, constructors ctor, Args&&... args) { + return new_usertype(name, std::move(ctor), std::forward(args)...); + } + + template + state_view& set_usertype(usertype& user) { + return set_usertype(usertype_traits::name, user); + } + + template + state_view& set_usertype(Key&& key, usertype& user) { + globals.set_usertype(std::forward(key), user); + return *this; + } + + template + state_view& new_usertype(const std::string& name, Args&&... args) { + constructors> ctor{}; + return new_usertype(name, ctor, std::forward(args)...); + } + + template + state_view& 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) { + globals.for_each(std::forward(fx)); + } + + template + table create_table(T&& key, int narr = 0, int nrec = 0) { + lua_createtable(L, narr, nrec); + table result(L); + lua_pop(L, 1); + globals.set(std::forward(key), result); + return result; + } + + template + table create_table(int narr = 0, int nrec = sizeof...(Tn), Tn&&... argn) { + lua_createtable(L, narr, nrec); + table result(L); + result.set(std::forward(argn)...); + lua_pop(L, 1); + return result; + } + + global_table global() const { + return globals; + } + + table registry() const { + return reg; + } + + void set_panic(lua_CFunction panic){ + lua_atpanic(L, panic); + } + + template + proxy operator[](T&& key) { + return globals[std::forward(key)]; + } + + template + proxy operator[](T&& key) const { + return globals[std::forward(key)]; + } + + template + state_view& set_function(Key&& key, R fun_ptr(Args...)){ + globals.set_function(std::forward(key), fun_ptr); + return *this; + } + + template + state_view& set_function(Key&& key, Sig* fun_ptr){ + globals.set_function(std::forward(key), fun_ptr); + return *this; + } + + template + state_view& set_function(Key&& key, R (C::*mem_ptr)(Args...), T&& obj) { + globals.set_function(std::forward(key), mem_ptr, std::forward(obj)); + return *this; + } + + template + state_view& set_function(Key&& key, Sig C::* mem_ptr, T&& obj) { + globals.set_function(std::forward(key), mem_ptr, std::forward(obj)); + return *this; + } + + template + state_view& set_function(Key&& key, Fx&& fx) { + globals.set_function(std::forward(key), std::forward(fx)); + return *this; + } +}; +} // sol + +#endif // SOL_STATE_VIEW_HPP diff --git a/sol/table_core.hpp b/sol/table_core.hpp index d68b9052..78e6cb40 100644 --- a/sol/table_core.hpp +++ b/sol/table_core.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Danny Y., Rapptz +// Copyright (c) 2013-2015 Rapptz 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 @@ -29,27 +29,31 @@ namespace sol { namespace detail { - struct global_overload_tag { } const global_overload; +struct global_overload_tag { } const global_overload; } // detail template class table_core : public reference { friend class state; - template>>, Bool> = 0> - stack::get_return single_get( Key&& key ) const { - lua_getglobal( lua_state( ), &key[ 0 ] ); - stack::get_return result = stack::pop( lua_state( ) ); - return result; + friend class state_view; + + template>>, Bool> = 0> + decltype(auto) single_get( Key&& key ) const { + lua_getglobal(lua_state( ), &key[0]); + return stack::pop(lua_state()); } - template>>, Bool> = 0> - stack::get_return single_get( Key&& key ) const { - push( ); + template>, Bool> = 0> + decltype(auto) single_get(Key&& key) const { + stack::detail::lua_getglobali(lua_state(), &key[0]); + return stack::pop(lua_state()); + } + + template>, Bool> = 0> + decltype(auto) single_get( Key&& key ) const { stack::push( lua_state( ), std::forward( key ) ); lua_gettable( lua_state( ), -2 ); - stack::get_return result = stack::pop( lua_state( ) ); - pop( ); - return result; + return stack::pop( lua_state( ) ); } template @@ -58,10 +62,35 @@ class table_core : public reference { } template - stack::get_return tuple_get( types, indices, Keys&& keys ) const { + decltype(auto) tuple_get( types, indices, Keys&& keys ) const { return single_get( std::get( keys ) ); } + template>, Bool> = 0> + void single_set( Key&& key, U&& value ) { + stack::push( lua_state( ), std::forward( value ) ); + stack::detail::lua_setglobali( lua_state( ), std::forward(key) ); + } + + template>>, Bool> = 0> + void single_set( Key&& key, Value&& value ) { + stack::push( lua_state( ), std::forward( value ) ); + lua_setglobal( lua_state( ), &key[0] ); + } + + template>, Bool> = 0> + void single_set(Key&& key, Value&& value) { + stack::push(lua_state(), std::forward(key)); + stack::push(lua_state(), std::forward(value)); + lua_settable(lua_state(), -3); + } + + template + void tuple_set( indices, Pairs&& pairs ) { + using swallow = int[]; + swallow{ 0, ( single_set(std::get(pairs), std::get(pairs)) , 0)..., 0 }; + } + #if SOL_LUA_VERSION < 502 table_core( detail::global_overload_tag, const table_core& reg ) noexcept : reference( reg.lua_state(), LUA_GLOBALSINDEX ) { } #else @@ -75,24 +104,16 @@ public: } template - stack::get_return get( Keys&&... keys ) const { - return tuple_get( types( ), build_indices( ), std::tie( keys... ) ); + decltype(auto) get( Keys&&... keys ) const { + auto pp = detail::push_pop(*this); + return tuple_get( types( ), build_indices( ), std::forward_as_tuple(std::forward(keys)...)); } - template - table_core& set( T&& key, U&& value ) { - if ( top_level ) { - stack::push( lua_state( ), std::forward( value ) ); - lua_setglobal( lua_state( ), &key[0] ); - } - else { - push( ); - stack::push( lua_state( ), std::forward( key ) ); - stack::push( lua_state( ), std::forward( value ) ); - lua_settable( lua_state( ), -3 ); - pop( ); - } - return *this; + template + table_core& set( Tn&&... argn ) { + auto pp = detail::push_pop(*this); + tuple_set(build_indices(), std::forward_as_tuple(std::forward(argn)...)); + return *this; } template @@ -148,13 +169,18 @@ public: } template - proxy operator[]( T&& key ) { - return proxy( *this, std::forward( key ) ); + proxy operator[]( T&& key ) & { + return proxy( *this, std::forward( key ) ); } template - proxy operator[]( T&& key ) const { - return proxy( *this, std::forward( key ) ); + proxy operator[]( T&& key ) const & { + return proxy( *this, std::forward( key ) ); + } + + template + proxy operator[]( T&& key ) && { + return proxy( *this, std::forward( key ) ); } void pop( int n = 1 ) const noexcept {