From 3426947340e7c0d6cf225095dfb008be77416a03 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Sun, 28 Apr 2019 09:40:51 -0400 Subject: [PATCH] the god-tier commit-without-running-tests... --- include/sol/error.hpp | 27 +- include/sol/protected_function.hpp | 1 + include/sol/proxy.hpp | 71 +++-- include/sol/proxy_base.hpp | 6 + include/sol/table.hpp | 8 +- include/sol/table_core.hpp | 6 + include/sol/usertype.hpp | 18 +- include/sol/usertype_proxy.hpp | 136 +++++++- include/sol/usertype_storage.hpp | 17 +- single/include/sol/forward.hpp | 4 +- single/include/sol/sol.hpp | 293 ++++++++++++++---- .../source/usertypes.runtime.cpp | 65 ++++ 12 files changed, 548 insertions(+), 104 deletions(-) diff --git a/include/sol/error.hpp b/include/sol/error.hpp index 98bed503..5f2c7502 100644 --- a/include/sol/error.hpp +++ b/include/sol/error.hpp @@ -33,23 +33,20 @@ namespace sol { namespace detail { struct direct_error_tag {}; - const auto direct_error = direct_error_tag {}; + const auto direct_error = direct_error_tag{}; struct error_result { int results; const char* format_string; std::array args_strings; - error_result() - : results(0), format_string(nullptr) { + error_result() : results(0), format_string(nullptr) { } - error_result(int results) - : results(results), format_string(nullptr) { + error_result(int results) : results(results), format_string(nullptr) { } - error_result(const char* fmt, const char* msg) - : results(0), format_string(fmt) { + error_result(const char* fmt, const char* msg) : results(0), format_string(fmt) { args_strings[0] = msg; } }; @@ -65,20 +62,16 @@ namespace sol { class error : public std::runtime_error { private: // Because VC++ is upsetting, most of the time! - std::string w; + std::string what_reason; public: - error(const std::string& str) - : error(detail::direct_error, "lua: error: " + str) { + error(const std::string& str) : error(detail::direct_error, "lua: error: " + str) { } - error(std::string&& str) - : error(detail::direct_error, "lua: error: " + std::move(str)) { + error(std::string&& str) : error(detail::direct_error, "lua: error: " + std::move(str)) { } - error(detail::direct_error_tag, const std::string& str) - : std::runtime_error(""), w(str) { + error(detail::direct_error_tag, const std::string& str) : std::runtime_error(""), what_reason(str) { } - error(detail::direct_error_tag, std::string&& str) - : std::runtime_error(""), w(std::move(str)) { + error(detail::direct_error_tag, std::string&& str) : std::runtime_error(""), what_reason(std::move(str)) { } error(const error& e) = default; @@ -87,7 +80,7 @@ namespace sol { error& operator=(error&& e) = default; virtual const char* what() const noexcept override { - return w.c_str(); + return what_reason.c_str(); } }; diff --git a/include/sol/protected_function.hpp b/include/sol/protected_function.hpp index a93f9e5e..6fff6106 100644 --- a/include/sol/protected_function.hpp +++ b/include/sol/protected_function.hpp @@ -32,6 +32,7 @@ #include "protected_handler.hpp" #include "bytecode.hpp" #include "dump_handler.hpp" + #include #include diff --git a/include/sol/proxy.hpp b/include/sol/proxy.hpp index de109e6d..75603c40 100644 --- a/include/sol/proxy.hpp +++ b/include/sol/proxy.hpp @@ -31,31 +31,31 @@ namespace sol { - namespace detail { - template - using proxy_key_t = meta::conditional_t, std::tuple>, - T, - std::tuple>, std::remove_reference_t&, meta::unqualified_t - >> - >; - } - template struct proxy : public proxy_base> { private: using key_type = detail::proxy_key_t; template - decltype(auto) tuple_get(std::index_sequence) const { + decltype(auto) tuple_get(std::index_sequence) const & { return tbl.template traverse_get(std::get(key)...); } + template + decltype(auto) tuple_get(std::index_sequence) && { + return tbl.template traverse_get(std::get(std::move(key))...); + } + template - void tuple_set(std::index_sequence, T&& value) { + void tuple_set(std::index_sequence, T&& value) & { tbl.traverse_set(std::get(key)..., std::forward(value)); } + template + void tuple_set(std::index_sequence, T&& value) && { + tbl.traverse_set(std::get(std::move(key))..., std::forward(value)); + } + auto setup_table(std::true_type) { auto p = stack::probe_get_field, global_table>>(lua_state(), key, tbl.stack_index()); lua_pop(lua_state(), p.levels); @@ -79,19 +79,31 @@ namespace sol { } template - proxy& set(T&& item) { + proxy& set(T&& item) & { tuple_set(std::make_index_sequence>>(), std::forward(item)); return *this; } + template + proxy&& set(T&& item) && { + tuple_set(std::make_index_sequence>>(), std::forward(item)); + return std::move(*this); + } + template - proxy& set_function(Args&&... args) { + proxy& set_function(Args&&... args) & { tbl.set_function(key, std::forward(args)...); return *this; } + template + proxy&& set_function(Args&&... args) && { + tbl.set_function(std::move(key), std::forward(args)...); + return std::move(*this); + } + template - proxy& operator=(T&& other) { + proxy& operator=(T&& other) & { using Tu = meta::unwrap_unqualified_t; if constexpr (!is_lua_reference_or_proxy_v && meta::is_callable_v) { return set_function(std::forward(other)); @@ -102,13 +114,36 @@ namespace sol { } template - proxy& operator=(std::initializer_list other) { + proxy&& operator=(T&& other) && { + using Tu = meta::unwrap_unqualified_t; + if constexpr (!is_lua_reference_or_proxy_v && meta::is_callable_v) { + return std::move(*this).set_function(std::forward(other)); + } + else { + return std::move(*this).set(std::forward(other)); + } + } + + template + proxy& operator=(std::initializer_list other) & { return set(std::move(other)); } template - decltype(auto) get() const { - return tuple_get(std::make_index_sequence>::value>()); + proxy&& operator=(std::initializer_list other) && { + return std::move(*this).set(std::move(other)); + } + + template + decltype(auto) get() const & { + using idx_seq = std::make_index_sequence>>; + return tuple_get(idx_seq()); + } + + template + decltype(auto) get() && { + using idx_seq = std::make_index_sequence>>; + return std::move(*this).template tuple_get(idx_seq()); } template diff --git a/include/sol/proxy_base.hpp b/include/sol/proxy_base.hpp index ec022340..9f7bd4ec 100644 --- a/include/sol/proxy_base.hpp +++ b/include/sol/proxy_base.hpp @@ -31,6 +31,12 @@ namespace sol { struct proxy_base_tag {}; + namespace detail { + template + using proxy_key_t = meta::conditional_t, std::tuple>, T, + std::tuple>, std::remove_reference_t&, meta::unqualified_t>>>; + } + template struct proxy_base : proxy_base_tag { operator std::string() const { diff --git a/include/sol/table.hpp b/include/sol/table.hpp index 062aa6e2..d27b81c7 100644 --- a/include/sol/table.hpp +++ b/include/sol/table.hpp @@ -70,10 +70,14 @@ namespace sol { template template void basic_metatable::set(Key&& key, Value&& value) { - optional maybe_uts = u_detail::maybe_get_usertype_storage_base(this->lua_state()); + this->push(); + lua_State* L = this->lua_state(); + int target = lua_gettop(L); + optional maybe_uts = u_detail::maybe_get_usertype_storage_base(L, target); + lua_pop(L, 1); if (maybe_uts) { u_detail::usertype_storage_base& uts = *maybe_uts; - uts.set(std::forward(key), std::forward(value)); + uts.set(L, std::forward(key), std::forward(value)); } else { base_t::set(std::forward(key), std::forward(value)); diff --git a/include/sol/table_core.hpp b/include/sol/table_core.hpp index 74309d50..916beed5 100644 --- a/include/sol/table_core.hpp +++ b/include/sol/table_core.hpp @@ -68,6 +68,10 @@ namespace sol { friend class state; friend class state_view; + template + friend class basic_usertype; + template + friend class basic_metatable; template decltype(auto) tuple_get(int table_index, Keys&&... keys) const { @@ -116,6 +120,8 @@ namespace sol { auto pp = stack::push_pop(*this); int table_index = pp.index_of(*this); lua_State* L = base_t::lua_state(); + (void)table_index; + (void)L; void(detail::swallow{ (stack::set_field(L, std::get(std::forward(pairs)), std::get(std::forward(pairs)), diff --git a/include/sol/usertype.hpp b/include/sol/usertype.hpp index 40e8c615..1ab9f77a 100644 --- a/include/sol/usertype.hpp +++ b/include/sol/usertype.hpp @@ -36,6 +36,7 @@ namespace sol { class basic_usertype : private basic_metatable { private: using base_t = basic_metatable; + using table_base_t = basic_table; template friend class basic_metatable; @@ -44,18 +45,23 @@ namespace sol { friend class basic_table_core; template - void tuple_set(std::index_sequence, std::tuple&& args) { + void tuple_set(std::index_sequence indices, std::tuple&& args) { using args_tuple = std::tuple&&; - optional&> maybe_uts = u_detail::maybe_get_usertype_storage(this->lua_state()); + lua_State* L = this->lua_state(); + optional&> maybe_uts = u_detail::maybe_get_usertype_storage(L); if constexpr (sizeof...(I) > 0) { if (maybe_uts) { u_detail::usertype_storage& uts = *maybe_uts; (void)detail::swallow{ 0, - (uts.set(this->lua_state(), std::get(std::forward(args)), std::get(std::forward(args))), + (uts.set(L, std::get(std::forward(args)), std::get(std::forward(args))), 0)... }; } + else { + table_base_t::template tuple_set(indices, std::move(args)); + } } else { + (void)indices; (void)args; } } @@ -67,6 +73,9 @@ namespace sol { using base_t::push; using base_t::lua_state; using base_t::get; + using base_t::set_function; + using base_t::traverse_set; + using base_t::traverse_get; using base_t::unregister; template @@ -76,6 +85,9 @@ namespace sol { u_detail::usertype_storage& uts = *maybe_uts; uts.set(this->lua_state(), std::forward(key), std::forward(value)); } + else { + base_t::set(std::forward(key), std::forward(value)); + } } template diff --git a/include/sol/usertype_proxy.hpp b/include/sol/usertype_proxy.hpp index bb93c176..2262337b 100644 --- a/include/sol/usertype_proxy.hpp +++ b/include/sol/usertype_proxy.hpp @@ -32,9 +32,42 @@ namespace sol { template struct usertype_proxy : public proxy_base> { + private: + using key_type = detail::proxy_key_t; + + template + decltype(auto) tuple_get(std::index_sequence) const & { + return tbl.template traverse_get(std::get(key)...); + } + + template + decltype(auto) tuple_get(std::index_sequence) && { + return tbl.template traverse_get(std::get(std::move(key))...); + } + + template + void tuple_set(std::index_sequence, T&& value) & { + if constexpr (sizeof...(I) > 1) { + tbl.traverse_set(std::get(key)..., std::forward(value)); + } + else { + tbl.set(std::get(key)..., std::forward(value)); + } + } + + template + void tuple_set(std::index_sequence, T&& value) && { + if constexpr (sizeof...(I) > 1) { + tbl.traverse_set(std::get(std::move(key))..., std::forward(value)); + } + else { + tbl.set(std::get(std::move(key))..., std::forward(value)); + } + } + public: Table tbl; - Key key; + key_type key; template usertype_proxy(Table table, T&& k) @@ -42,21 +75,110 @@ namespace sol { } template - usertype_proxy& set(T&& value) { - tbl.set(key, std::forward(value)); + usertype_proxy& set(T&& item) & { + using idx_seq = std::make_index_sequence>>; + tuple_set(idx_seq(), std::forward(item)); return *this; } - template - usertype_proxy& operator=(U&& other) { - return set(std::forward(other)); + template + usertype_proxy&& set(T&& item) && { + using idx_seq = std::make_index_sequence>>; + std::move(*this).tuple_set(idx_seq(), std::forward(item)); + return std::move(*this); } template - usertype_proxy& operator=(std::initializer_list other) { + usertype_proxy& operator=(T&& other) & { + return set(std::forward(other)); + } + + template + usertype_proxy&& operator=(T&& other) && { + return std::move(*this).set(std::forward(other)); + } + + template + usertype_proxy& operator=(std::initializer_list other) & { return set(std::move(other)); } + template + usertype_proxy&& operator=(std::initializer_list other) && { + return std::move(*this).set(std::move(other)); + } + + template + decltype(auto) get() const& { + using idx_seq = std::make_index_sequence>>; + return tuple_get(idx_seq()); + } + + template + decltype(auto) get() && { + using idx_seq = std::make_index_sequence>>; + return std::move(*this).template tuple_get(idx_seq()); + } + + template + decltype(auto) operator[](K&& k) const& { + auto keys = meta::tuplefy(key, std::forward(k)); + return usertype_proxy(tbl, std::move(keys)); + } + + template + decltype(auto) operator[](K&& k) & { + auto keys = meta::tuplefy(key, std::forward(k)); + return usertype_proxy(tbl, std::move(keys)); + } + + template + decltype(auto) operator[](K&& k) && { + auto keys = meta::tuplefy(std::move(key), std::forward(k)); + return usertype_proxy(tbl, std::move(keys)); + } + + template + decltype(auto) call(Args&&... args) { +#if !defined(__clang__) && defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 191200000 + // MSVC is ass sometimes + return get().call(std::forward(args)...); +#else + return get().template call(std::forward(args)...); +#endif + } + + template + decltype(auto) operator()(Args&&... args) { + return call<>(std::forward(args)...); + } + + bool valid() const { + auto pp = stack::push_pop(tbl); + auto p = stack::probe_get_field, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); + lua_pop(lua_state(), p.levels); + return p; + } + + int push() const noexcept { + return push(this->lua_state()); + } + + int push(lua_State* L) const noexcept { + return get().push(L); + } + + type get_type() const { + type t = type::none; + auto pp = stack::push_pop(tbl); + auto p = stack::probe_get_field, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); + if (p) { + t = type_of(lua_state(), -1); + } + lua_pop(lua_state(), p.levels); + return t; + } + lua_State* lua_state() const { return tbl.lua_state(); } diff --git a/include/sol/usertype_storage.hpp b/include/sol/usertype_storage.hpp index 0bb1b83a..2dabd532 100644 --- a/include/sol/usertype_storage.hpp +++ b/include/sol/usertype_storage.hpp @@ -774,17 +774,27 @@ namespace sol { namespace u_detail { return target_umt; } - inline optional maybe_get_usertype_storage_base(lua_State* L, const char* gcmetakey) { - stack::get_field(L, gcmetakey); + inline optional maybe_get_usertype_storage_base(lua_State* L, int index) { stack::record tracking; + if (!stack::check>(L, index)) { + return nullopt; + } usertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get>(L, -1, tracking); return target_umt; } + inline optional maybe_get_usertype_storage_base(lua_State* L, const char* gcmetakey) { + stack::get_field(L, gcmetakey); + auto maybe_storage = maybe_get_usertype_storage_base(L, lua_gettop(L)); + lua_pop(L, 1); + return maybe_storage; + } + inline usertype_storage_base& get_usertype_storage_base(lua_State* L, const char* gcmetakey) { stack::get_field(L, gcmetakey); stack::record tracking; usertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get>(L, -1, tracking); + lua_pop(L, 1); return target_umt; } @@ -792,7 +802,8 @@ namespace sol { namespace u_detail { inline optional&> maybe_get_usertype_storage(lua_State* L) { const char* gcmetakey = &usertype_traits::gc_table()[0]; stack::get_field(L, gcmetakey); - if (!stack::check>>(L)) { + int target = lua_gettop(L); + if (!stack::check>>(L, target)) { return nullopt; } usertype_storage& target_umt = stack::pop>>(L); diff --git a/single/include/sol/forward.hpp b/single/include/sol/forward.hpp index ccfeadcc..6beeb18a 100644 --- a/single/include/sol/forward.hpp +++ b/single/include/sol/forward.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2019-04-23 14:29:43.918566 UTC -// This header was generated with sol v3.0.1-beta2 (revision 468ac36) +// Generated 2019-04-28 13:40:08.826493 UTC +// This header was generated with sol v3.0.1-beta2 (revision 2d47085) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP diff --git a/single/include/sol/sol.hpp b/single/include/sol/sol.hpp index b50f195a..182d04ad 100644 --- a/single/include/sol/sol.hpp +++ b/single/include/sol/sol.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2019-04-23 14:29:43.637794 UTC -// This header was generated with sol v3.0.1-beta2 (revision 468ac36) +// Generated 2019-04-28 13:40:08.534101 UTC +// This header was generated with sol v3.0.1-beta2 (revision 2d47085) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -3491,23 +3491,20 @@ namespace sol { namespace sol { namespace detail { struct direct_error_tag {}; - const auto direct_error = direct_error_tag {}; + const auto direct_error = direct_error_tag{}; struct error_result { int results; const char* format_string; std::array args_strings; - error_result() - : results(0), format_string(nullptr) { + error_result() : results(0), format_string(nullptr) { } - error_result(int results) - : results(results), format_string(nullptr) { + error_result(int results) : results(results), format_string(nullptr) { } - error_result(const char* fmt, const char* msg) - : results(0), format_string(fmt) { + error_result(const char* fmt, const char* msg) : results(0), format_string(fmt) { args_strings[0] = msg; } }; @@ -3523,20 +3520,16 @@ namespace sol { class error : public std::runtime_error { private: // Because VC++ is upsetting, most of the time! - std::string w; + std::string what_reason; public: - error(const std::string& str) - : error(detail::direct_error, "lua: error: " + str) { + error(const std::string& str) : error(detail::direct_error, "lua: error: " + str) { } - error(std::string&& str) - : error(detail::direct_error, "lua: error: " + std::move(str)) { + error(std::string&& str) : error(detail::direct_error, "lua: error: " + std::move(str)) { } - error(detail::direct_error_tag, const std::string& str) - : std::runtime_error(""), w(str) { + error(detail::direct_error_tag, const std::string& str) : std::runtime_error(""), what_reason(str) { } - error(detail::direct_error_tag, std::string&& str) - : std::runtime_error(""), w(std::move(str)) { + error(detail::direct_error_tag, std::string&& str) : std::runtime_error(""), what_reason(std::move(str)) { } error(const error& e) = default; @@ -3545,7 +3538,7 @@ namespace sol { error& operator=(error&& e) = default; virtual const char* what() const noexcept override { - return w.c_str(); + return what_reason.c_str(); } }; @@ -14654,6 +14647,12 @@ namespace sol { namespace sol { struct proxy_base_tag {}; + namespace detail { + template + using proxy_key_t = meta::conditional_t, std::tuple>, T, + std::tuple>, std::remove_reference_t&, meta::unqualified_t>>>; + } + template struct proxy_base : proxy_base_tag { operator std::string() const { @@ -21344,17 +21343,27 @@ namespace sol { namespace u_detail { return target_umt; } - inline optional maybe_get_usertype_storage_base(lua_State* L, const char* gcmetakey) { - stack::get_field(L, gcmetakey); + inline optional maybe_get_usertype_storage_base(lua_State* L, int index) { stack::record tracking; + if (!stack::check>(L, index)) { + return nullopt; + } usertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get>(L, -1, tracking); return target_umt; } + inline optional maybe_get_usertype_storage_base(lua_State* L, const char* gcmetakey) { + stack::get_field(L, gcmetakey); + auto maybe_storage = maybe_get_usertype_storage_base(L, lua_gettop(L)); + lua_pop(L, 1); + return maybe_storage; + } + inline usertype_storage_base& get_usertype_storage_base(lua_State* L, const char* gcmetakey) { stack::get_field(L, gcmetakey); stack::record tracking; usertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get>(L, -1, tracking); + lua_pop(L, 1); return target_umt; } @@ -21362,7 +21371,8 @@ namespace sol { namespace u_detail { inline optional&> maybe_get_usertype_storage(lua_State* L) { const char* gcmetakey = &usertype_traits::gc_table()[0]; stack::get_field(L, gcmetakey); - if (!stack::check>>(L)) { + int target = lua_gettop(L); + if (!stack::check>>(L, target)) { return nullopt; } usertype_storage& target_umt = stack::pop>>(L); @@ -21634,9 +21644,42 @@ namespace sol { namespace u_detail { namespace sol { template struct usertype_proxy : public proxy_base> { + private: + using key_type = detail::proxy_key_t; + + template + decltype(auto) tuple_get(std::index_sequence) const & { + return tbl.template traverse_get(std::get(key)...); + } + + template + decltype(auto) tuple_get(std::index_sequence) && { + return tbl.template traverse_get(std::get(std::move(key))...); + } + + template + void tuple_set(std::index_sequence, T&& value) & { + if constexpr (sizeof...(I) > 1) { + tbl.traverse_set(std::get(key)..., std::forward(value)); + } + else { + tbl.set(std::get(key)..., std::forward(value)); + } + } + + template + void tuple_set(std::index_sequence, T&& value) && { + if constexpr (sizeof...(I) > 1) { + tbl.traverse_set(std::get(std::move(key))..., std::forward(value)); + } + else { + tbl.set(std::get(std::move(key))..., std::forward(value)); + } + } + public: Table tbl; - Key key; + key_type key; template usertype_proxy(Table table, T&& k) @@ -21644,21 +21687,110 @@ namespace sol { } template - usertype_proxy& set(T&& value) { - tbl.set(key, std::forward(value)); + usertype_proxy& set(T&& item) & { + using idx_seq = std::make_index_sequence>>; + tuple_set(idx_seq(), std::forward(item)); return *this; } - template - usertype_proxy& operator=(U&& other) { - return set(std::forward(other)); + template + usertype_proxy&& set(T&& item) && { + using idx_seq = std::make_index_sequence>>; + std::move(*this).tuple_set(idx_seq(), std::forward(item)); + return std::move(*this); } template - usertype_proxy& operator=(std::initializer_list other) { + usertype_proxy& operator=(T&& other) & { + return set(std::forward(other)); + } + + template + usertype_proxy&& operator=(T&& other) && { + return std::move(*this).set(std::forward(other)); + } + + template + usertype_proxy& operator=(std::initializer_list other) & { return set(std::move(other)); } + template + usertype_proxy&& operator=(std::initializer_list other) && { + return std::move(*this).set(std::move(other)); + } + + template + decltype(auto) get() const& { + using idx_seq = std::make_index_sequence>>; + return tuple_get(idx_seq()); + } + + template + decltype(auto) get() && { + using idx_seq = std::make_index_sequence>>; + return std::move(*this).template tuple_get(idx_seq()); + } + + template + decltype(auto) operator[](K&& k) const& { + auto keys = meta::tuplefy(key, std::forward(k)); + return usertype_proxy(tbl, std::move(keys)); + } + + template + decltype(auto) operator[](K&& k) & { + auto keys = meta::tuplefy(key, std::forward(k)); + return usertype_proxy(tbl, std::move(keys)); + } + + template + decltype(auto) operator[](K&& k) && { + auto keys = meta::tuplefy(std::move(key), std::forward(k)); + return usertype_proxy(tbl, std::move(keys)); + } + + template + decltype(auto) call(Args&&... args) { +#if !defined(__clang__) && defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 191200000 + // MSVC is ass sometimes + return get().call(std::forward(args)...); +#else + return get().template call(std::forward(args)...); +#endif + } + + template + decltype(auto) operator()(Args&&... args) { + return call<>(std::forward(args)...); + } + + bool valid() const { + auto pp = stack::push_pop(tbl); + auto p = stack::probe_get_field, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); + lua_pop(lua_state(), p.levels); + return p; + } + + int push() const noexcept { + return push(this->lua_state()); + } + + int push(lua_State* L) const noexcept { + return get().push(L); + } + + type get_type() const { + type t = type::none; + auto pp = stack::push_pop(tbl); + auto p = stack::probe_get_field, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); + if (p) { + t = type_of(lua_state(), -1); + } + lua_pop(lua_state(), p.levels); + return t; + } + lua_State* lua_state() const { return tbl.lua_state(); } @@ -21675,31 +21807,31 @@ namespace sol { namespace sol { - namespace detail { - template - using proxy_key_t = meta::conditional_t, std::tuple>, - T, - std::tuple>, std::remove_reference_t&, meta::unqualified_t - >> - >; - } - template struct proxy : public proxy_base> { private: using key_type = detail::proxy_key_t; template - decltype(auto) tuple_get(std::index_sequence) const { + decltype(auto) tuple_get(std::index_sequence) const & { return tbl.template traverse_get(std::get(key)...); } + template + decltype(auto) tuple_get(std::index_sequence) && { + return tbl.template traverse_get(std::get(std::move(key))...); + } + template - void tuple_set(std::index_sequence, T&& value) { + void tuple_set(std::index_sequence, T&& value) & { tbl.traverse_set(std::get(key)..., std::forward(value)); } + template + void tuple_set(std::index_sequence, T&& value) && { + tbl.traverse_set(std::get(std::move(key))..., std::forward(value)); + } + auto setup_table(std::true_type) { auto p = stack::probe_get_field, global_table>>(lua_state(), key, tbl.stack_index()); lua_pop(lua_state(), p.levels); @@ -21723,19 +21855,31 @@ namespace sol { } template - proxy& set(T&& item) { + proxy& set(T&& item) & { tuple_set(std::make_index_sequence>>(), std::forward(item)); return *this; } + template + proxy&& set(T&& item) && { + tuple_set(std::make_index_sequence>>(), std::forward(item)); + return std::move(*this); + } + template - proxy& set_function(Args&&... args) { + proxy& set_function(Args&&... args) & { tbl.set_function(key, std::forward(args)...); return *this; } + template + proxy&& set_function(Args&&... args) && { + tbl.set_function(std::move(key), std::forward(args)...); + return std::move(*this); + } + template - proxy& operator=(T&& other) { + proxy& operator=(T&& other) & { using Tu = meta::unwrap_unqualified_t; if constexpr (!is_lua_reference_or_proxy_v && meta::is_callable_v) { return set_function(std::forward(other)); @@ -21746,13 +21890,36 @@ namespace sol { } template - proxy& operator=(std::initializer_list other) { + proxy&& operator=(T&& other) && { + using Tu = meta::unwrap_unqualified_t; + if constexpr (!is_lua_reference_or_proxy_v && meta::is_callable_v) { + return std::move(*this).set_function(std::forward(other)); + } + else { + return std::move(*this).set(std::forward(other)); + } + } + + template + proxy& operator=(std::initializer_list other) & { return set(std::move(other)); } template - decltype(auto) get() const { - return tuple_get(std::make_index_sequence>::value>()); + proxy&& operator=(std::initializer_list other) && { + return std::move(*this).set(std::move(other)); + } + + template + decltype(auto) get() const & { + using idx_seq = std::make_index_sequence>>; + return tuple_get(idx_seq()); + } + + template + decltype(auto) get() && { + using idx_seq = std::make_index_sequence>>; + return std::move(*this).template tuple_get(idx_seq()); } template @@ -22060,6 +22227,10 @@ namespace sol { friend class state; friend class state_view; + template + friend class basic_usertype; + template + friend class basic_metatable; template decltype(auto) tuple_get(int table_index, Keys&&... keys) const { @@ -22108,6 +22279,8 @@ namespace sol { auto pp = stack::push_pop(*this); int table_index = pp.index_of(*this); lua_State* L = base_t::lua_state(); + (void)table_index; + (void)L; void(detail::swallow{ (stack::set_field(L, std::get(std::forward(pairs)), std::get(std::forward(pairs)), @@ -22746,6 +22919,7 @@ namespace sol { class basic_usertype : private basic_metatable { private: using base_t = basic_metatable; + using table_base_t = basic_table; template friend class basic_metatable; @@ -22754,18 +22928,23 @@ namespace sol { friend class basic_table_core; template - void tuple_set(std::index_sequence, std::tuple&& args) { + void tuple_set(std::index_sequence indices, std::tuple&& args) { using args_tuple = std::tuple&&; - optional&> maybe_uts = u_detail::maybe_get_usertype_storage(this->lua_state()); + lua_State* L = this->lua_state(); + optional&> maybe_uts = u_detail::maybe_get_usertype_storage(L); if constexpr (sizeof...(I) > 0) { if (maybe_uts) { u_detail::usertype_storage& uts = *maybe_uts; (void)detail::swallow{ 0, - (uts.set(this->lua_state(), std::get(std::forward(args)), std::get(std::forward(args))), + (uts.set(L, std::get(std::forward(args)), std::get(std::forward(args))), 0)... }; } + else { + table_base_t::template tuple_set(indices, std::move(args)); + } } else { + (void)indices; (void)args; } } @@ -22777,6 +22956,9 @@ namespace sol { using base_t::push; using base_t::lua_state; using base_t::get; + using base_t::set_function; + using base_t::traverse_set; + using base_t::traverse_get; using base_t::unregister; template @@ -22786,6 +22968,9 @@ namespace sol { u_detail::usertype_storage& uts = *maybe_uts; uts.set(this->lua_state(), std::forward(key), std::forward(value)); } + else { + base_t::set(std::forward(key), std::forward(value)); + } } template @@ -22917,10 +23102,14 @@ namespace sol { template template void basic_metatable::set(Key&& key, Value&& value) { - optional maybe_uts = u_detail::maybe_get_usertype_storage_base(this->lua_state()); + this->push(); + lua_State* L = this->lua_state(); + int target = lua_gettop(L); + optional maybe_uts = u_detail::maybe_get_usertype_storage_base(L, target); + lua_pop(L, 1); if (maybe_uts) { u_detail::usertype_storage_base& uts = *maybe_uts; - uts.set(std::forward(key), std::forward(value)); + uts.set(L, std::forward(key), std::forward(value)); } else { base_t::set(std::forward(key), std::forward(value)); diff --git a/tests/runtime_tests/source/usertypes.runtime.cpp b/tests/runtime_tests/source/usertypes.runtime.cpp index edb53435..41c77a52 100644 --- a/tests/runtime_tests/source/usertypes.runtime.cpp +++ b/tests/runtime_tests/source/usertypes.runtime.cpp @@ -30,6 +30,28 @@ #include #include #include +#include + +struct special_property_object { + struct obj_hash { + std::size_t operator()(const sol::object& obj) const noexcept { + return std::hash()(obj.pointer()); + } + }; + + std::unordered_map props; + + sol::object get_property_lua(sol::stack_object key) const { + if (auto it = props.find(key); it != props.cend()) { + return it->second; + } + return sol::lua_nil; + } + + void set_property_lua(sol::stack_object key, sol::stack_object value) { + props.insert_or_assign(key, sol::object(value)); + } +}; struct new_index_test_object { bool new_indexed = false; @@ -403,3 +425,46 @@ TEST_CASE("usertype/new_index and index", "a custom new_index and index only kic REQUIRE(a.borf_new_indexed); REQUIRE(a.new_indexed); } + +TEST_CASE("usertype/object and class extensible", "make sure that a class which override new_index and friends can still work properly") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("special_property_object", sol::meta_function::new_index, &special_property_object::set_property_lua, sol::meta_function::index, &special_property_object::get_property_lua); + + lua["add_class_func"] = [](sol::this_state L, special_property_object&) { + sol::stack_userdata self = sol::stack::get(L, 1); + sol::usertype mt = self[sol::metatable_key]; + std::string s = mt["__name"]; + mt["additional_function"] = []() { return 24; }; + }; + + lua["add_object_func"] = [](sol::this_state L, special_property_object&) { + sol::stack_userdata self = sol::stack::get(L, 1); + self["specific_function"] = []() { return 23; }; + }; + + sol::optional result0 = lua.safe_script(R"( + s = special_property_object.new() + s2 = special_property_object.new() + add_class_func(s) + add_object_func(s) + value = s:additional_function() + assert(value == 24) + value2 = s:specific_function() + assert(value2 == 23) + )", + sol::script_pass_on_error); + REQUIRE_FALSE(result0.has_value()); + int value = lua["value"]; + REQUIRE(value == 24); + int value2 = lua["value2"]; + REQUIRE(value2 == 23); + + sol::optional result1 = lua.safe_script(R"( + value3 = s2:specific_function() + assert(value3 == 23) + )", + sol::script_pass_on_error); + REQUIRE(result1.has_value()); +}