From c442c6c62007f1d96f7e535a6def17dc8f5b0d17 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Mon, 29 Apr 2019 01:38:01 -0400 Subject: [PATCH] static indexing is a real thing now --- include/sol/types.hpp | 10 +- include/sol/usertype_storage.hpp | 39 ++++++-- single/include/sol/forward.hpp | 4 +- single/include/sol/sol.hpp | 53 +++++++--- .../source/usertypes.runtime.cpp | 99 ++++++++++++++++++- 5 files changed, 180 insertions(+), 25 deletions(-) diff --git a/include/sol/types.hpp b/include/sol/types.hpp index ec97127a..5c59f41b 100644 --- a/include/sol/types.hpp +++ b/include/sol/types.hpp @@ -795,12 +795,14 @@ namespace sol { call_construct, storage, gc_names, + static_index, + static_new_index, }; typedef meta_function meta_method; - inline const std::array& meta_function_names() { - static const std::array names = { { "new", + inline const std::array& meta_function_names() { + static const std::array names = { { "new", "__index", "__newindex", "__mode", @@ -837,7 +839,9 @@ namespace sol { "__typeinfo", "__sol.call_new", "__sol.storage", - "__sol.gc_names" } }; + "__sol.gc_names", + "__sol.static_index", + "__sol.static_new_index" } }; return names; } diff --git a/include/sol/usertype_storage.hpp b/include/sol/usertype_storage.hpp index 2dabd532..80f7dd09 100644 --- a/include/sol/usertype_storage.hpp +++ b/include/sol/usertype_storage.hpp @@ -36,7 +36,7 @@ namespace sol { namespace u_detail { template struct usertype_storage; - optional maybe_get_usertype_storage_base(lua_State* L, const char* gcmetakey); + optional maybe_get_usertype_storage_base(lua_State* L, int index); usertype_storage_base& get_usertype_storage_base(lua_State* L, const char* gcmetakey); template optional&> maybe_get_usertype_storage(lua_State* L); @@ -158,6 +158,8 @@ namespace sol { namespace u_detail { bool is_destruction = false; bool is_index = false; bool is_new_index = false; + bool is_static_index = false; + bool is_static_new_index = false; bool poison_indexing = false; bool is_unqualified_lua_CFunction = false; bool is_unqualified_lua_reference = false; @@ -207,7 +209,7 @@ namespace sol { namespace u_detail { t.pop(); return; } - if (is_index || is_new_index) { + if (is_index || is_new_index || is_static_index || is_static_new_index) { // do not serialize the new_index and index functions here directly // we control those... t.pop(); @@ -294,6 +296,7 @@ namespace sol { namespace u_detail { reference gc_names_table; reference named_metatable; new_index_call_storage base_index; + new_index_call_storage static_base_index; bool is_using_index; bool is_using_new_index; std::bitset<64> properties; @@ -310,6 +313,7 @@ namespace sol { namespace u_detail { , gc_names_table(make_reference(L, create)) , named_metatable(make_reference(L, create)) , base_index() + , static_base_index() , is_using_index(false) , is_using_new_index(false) , properties() { @@ -317,6 +321,10 @@ namespace sol { namespace u_detail { base_index.index = index_target_fail; base_index.new_index = new_index_target_fail; base_index.new_binding_data = nullptr; + static_base_index.binding_data = nullptr; + static_base_index.index = index_target_fail; + static_base_index.new_binding_data = this; + static_base_index.new_index = new_index_target_set; } template @@ -521,11 +529,10 @@ namespace sol { namespace u_detail { } else if constexpr (from_named_metatable) { if constexpr (is_new_index) { - self.set(L, reference(L, raw_index(2)), reference(L, raw_index(3))); - return 0; + return self.static_base_index.new_index(L, self.static_base_index.new_binding_data); } else { - return index_fail(L); + return self.static_base_index.index(L, self.static_base_index.binding_data); } } else { @@ -568,6 +575,12 @@ namespace sol { namespace u_detail { template void set(lua_State* L, Key&& key, Value&& value); + + static int new_index_target_set(lua_State* L, void* target) { + usertype_storage_base& self = *static_cast(target); + self.set(L, reference(L, raw_index(2)), reference(L, raw_index(3))); + return 0; + } }; template @@ -662,19 +675,23 @@ namespace sol { namespace u_detail { bool is_index = (s == to_string(meta_function::index)); bool is_new_index = (s == to_string(meta_function::new_index)); + bool is_static_index = (s == to_string(meta_function::static_index)); + bool is_static_new_index = (s == to_string(meta_function::static_new_index)); bool is_destruction = s == to_string(meta_function::garbage_collect); bool poison_indexing = (!is_using_index || !is_using_new_index) && (is_var_bind::value || is_index || is_new_index); void* derived_this = static_cast(static_cast*>(this)); index_call_storage ics; ics.binding_data = b.data(); - ics.index = is_index ? &Binding::template call_with_ : &Binding::template index_call_with_; + ics.index = is_index || is_static_index ? &Binding::template call_with_ : &Binding::template index_call_with_; ics.new_index - = is_new_index ? &Binding::template call_with_ : &Binding::template index_call_with_; + = is_new_index || is_static_new_index ? &Binding::template call_with_ : &Binding::template index_call_with_; string_for_each_metatable_func for_each_fx; for_each_fx.is_destruction = is_destruction; for_each_fx.is_index = is_index; for_each_fx.is_new_index = is_new_index; + for_each_fx.is_static_index = is_static_index; + for_each_fx.is_static_new_index = is_static_new_index; for_each_fx.poison_indexing = poison_indexing; for_each_fx.p_key = &s; for_each_fx.p_ics = &ics; @@ -706,6 +723,14 @@ namespace sol { namespace u_detail { this->base_index.new_index = ics.new_index; this->base_index.new_binding_data = ics.binding_data; } + if (is_static_index) { + this->static_base_index.index = ics.index; + this->static_base_index.binding_data = ics.binding_data; + } + if (is_static_new_index) { + this->static_base_index.new_index = ics.new_index; + this->static_base_index.new_binding_data = ics.binding_data; + } this->for_each_table(L, for_each_fx); this->add_entry(s, std::move(ics)); } diff --git a/single/include/sol/forward.hpp b/single/include/sol/forward.hpp index 81150abe..d4844925 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-28 20:45:14.775010 UTC -// This header was generated with sol v3.0.1-beta2 (revision 3426947) +// Generated 2019-04-29 05:20:05.556326 UTC +// This header was generated with sol v3.0.1-beta2 (revision 67231f7) // 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 5c22485b..caaaa25e 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-28 20:45:14.470847 UTC -// This header was generated with sol v3.0.1-beta2 (revision 3426947) +// Generated 2019-04-29 05:20:05.284047 UTC +// This header was generated with sol v3.0.1-beta2 (revision 67231f7) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -6948,12 +6948,14 @@ namespace sol { call_construct, storage, gc_names, + static_index, + static_new_index, }; typedef meta_function meta_method; - inline const std::array& meta_function_names() { - static const std::array names = { { "new", + inline const std::array& meta_function_names() { + static const std::array names = { { "new", "__index", "__newindex", "__mode", @@ -6990,7 +6992,9 @@ namespace sol { "__typeinfo", "__sol.call_new", "__sol.storage", - "__sol.gc_names" } }; + "__sol.gc_names", + "__sol.static_index", + "__sol.static_new_index" } }; return names; } @@ -20683,7 +20687,7 @@ namespace sol { namespace u_detail { template struct usertype_storage; - optional maybe_get_usertype_storage_base(lua_State* L, const char* gcmetakey); + optional maybe_get_usertype_storage_base(lua_State* L, int index); usertype_storage_base& get_usertype_storage_base(lua_State* L, const char* gcmetakey); template optional&> maybe_get_usertype_storage(lua_State* L); @@ -20805,6 +20809,8 @@ namespace sol { namespace u_detail { bool is_destruction = false; bool is_index = false; bool is_new_index = false; + bool is_static_index = false; + bool is_static_new_index = false; bool poison_indexing = false; bool is_unqualified_lua_CFunction = false; bool is_unqualified_lua_reference = false; @@ -20854,7 +20860,7 @@ namespace sol { namespace u_detail { t.pop(); return; } - if (is_index || is_new_index) { + if (is_index || is_new_index || is_static_index || is_static_new_index) { // do not serialize the new_index and index functions here directly // we control those... t.pop(); @@ -20941,6 +20947,7 @@ namespace sol { namespace u_detail { reference gc_names_table; reference named_metatable; new_index_call_storage base_index; + new_index_call_storage static_base_index; bool is_using_index; bool is_using_new_index; std::bitset<64> properties; @@ -20957,6 +20964,7 @@ namespace sol { namespace u_detail { , gc_names_table(make_reference(L, create)) , named_metatable(make_reference(L, create)) , base_index() + , static_base_index() , is_using_index(false) , is_using_new_index(false) , properties() { @@ -20964,6 +20972,10 @@ namespace sol { namespace u_detail { base_index.index = index_target_fail; base_index.new_index = new_index_target_fail; base_index.new_binding_data = nullptr; + static_base_index.binding_data = nullptr; + static_base_index.index = index_target_fail; + static_base_index.new_binding_data = this; + static_base_index.new_index = new_index_target_set; } template @@ -21168,11 +21180,10 @@ namespace sol { namespace u_detail { } else if constexpr (from_named_metatable) { if constexpr (is_new_index) { - self.set(L, reference(L, raw_index(2)), reference(L, raw_index(3))); - return 0; + return self.static_base_index.new_index(L, self.static_base_index.new_binding_data); } else { - return index_fail(L); + return self.static_base_index.index(L, self.static_base_index.binding_data); } } else { @@ -21215,6 +21226,12 @@ namespace sol { namespace u_detail { template void set(lua_State* L, Key&& key, Value&& value); + + static int new_index_target_set(lua_State* L, void* target) { + usertype_storage_base& self = *static_cast(target); + self.set(L, reference(L, raw_index(2)), reference(L, raw_index(3))); + return 0; + } }; template @@ -21309,19 +21326,23 @@ namespace sol { namespace u_detail { bool is_index = (s == to_string(meta_function::index)); bool is_new_index = (s == to_string(meta_function::new_index)); + bool is_static_index = (s == to_string(meta_function::static_index)); + bool is_static_new_index = (s == to_string(meta_function::static_new_index)); bool is_destruction = s == to_string(meta_function::garbage_collect); bool poison_indexing = (!is_using_index || !is_using_new_index) && (is_var_bind::value || is_index || is_new_index); void* derived_this = static_cast(static_cast*>(this)); index_call_storage ics; ics.binding_data = b.data(); - ics.index = is_index ? &Binding::template call_with_ : &Binding::template index_call_with_; + ics.index = is_index || is_static_index ? &Binding::template call_with_ : &Binding::template index_call_with_; ics.new_index - = is_new_index ? &Binding::template call_with_ : &Binding::template index_call_with_; + = is_new_index || is_static_new_index ? &Binding::template call_with_ : &Binding::template index_call_with_; string_for_each_metatable_func for_each_fx; for_each_fx.is_destruction = is_destruction; for_each_fx.is_index = is_index; for_each_fx.is_new_index = is_new_index; + for_each_fx.is_static_index = is_static_index; + for_each_fx.is_static_new_index = is_static_new_index; for_each_fx.poison_indexing = poison_indexing; for_each_fx.p_key = &s; for_each_fx.p_ics = &ics; @@ -21353,6 +21374,14 @@ namespace sol { namespace u_detail { this->base_index.new_index = ics.new_index; this->base_index.new_binding_data = ics.binding_data; } + if (is_static_index) { + this->static_base_index.index = ics.index; + this->static_base_index.binding_data = ics.binding_data; + } + if (is_static_new_index) { + this->static_base_index.new_index = ics.new_index; + this->static_base_index.new_binding_data = ics.binding_data; + } this->for_each_table(L, for_each_fx); this->add_entry(s, std::move(ics)); } diff --git a/tests/runtime_tests/source/usertypes.runtime.cpp b/tests/runtime_tests/source/usertypes.runtime.cpp index 41c77a52..3e0d6b3c 100644 --- a/tests/runtime_tests/source/usertypes.runtime.cpp +++ b/tests/runtime_tests/source/usertypes.runtime.cpp @@ -31,6 +31,44 @@ #include #include #include +#include + +struct static_special_property_object { + static int named_set_calls; + static int named_get_calls; + + 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)); + } + + static void named_get_property_lua(sol::this_state L) { + ++named_get_calls; + luaL_error(L, "absolutely not"); + } + + static void named_set_property_lua(sol::this_state L) { + ++named_set_calls; + luaL_error(L, "absolutely not"); + } +}; + +int static_special_property_object::named_get_calls = 0; +int static_special_property_object::named_set_calls = 0; struct special_property_object { struct obj_hash { @@ -435,7 +473,6 @@ TEST_CASE("usertype/object and class extensible", "make sure that a class which 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; }; }; @@ -468,3 +505,63 @@ TEST_CASE("usertype/object and class extensible", "make sure that a class which sol::script_pass_on_error); REQUIRE(result1.has_value()); } + +TEST_CASE("usertypes/static new index and static index", "ensure static index and static new index provide the proper interface") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("static_special_property_object", + sol::meta_function::index, + &static_special_property_object::get_property_lua, + sol::meta_function::new_index, + &static_special_property_object::set_property_lua, + sol::meta_function::static_index, + &static_special_property_object::named_get_property_lua, + sol::meta_function::static_new_index, + &static_special_property_object::named_set_property_lua); + + lua["add_object_func"] = [](sol::this_state L, static_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 = static_special_property_object.new() + s2 = static_special_property_object.new() + add_object_func(s) + value2 = s:specific_function() + assert(value2 == 23) + )", + sol::script_pass_on_error); + REQUIRE_FALSE(result0.has_value()); + int value2 = lua["value2"]; + REQUIRE(value2 == 23); + + sol::optional result1 = lua.safe_script(R"( + function static_special_property_object:additional_function () + return 24 + end + value = s:additional_function() + assert(value == 24) + )", + sol::script_pass_on_error); + REQUIRE(result1.has_value()); + bool is_value_valid = lua["value"].valid(); + REQUIRE_FALSE(is_value_valid); + + sol::optional result2 = lua.safe_script(R"( + value3 = s2:specific_function() + assert(value3 == 23) + )", + sol::script_pass_on_error); + REQUIRE(result2.has_value()); + + sol::optional result3 = lua.safe_script(R"( + assert(static_special_property_object.non_existent == nil) + )", + sol::script_pass_on_error); + REQUIRE(result3.has_value()); + + REQUIRE(static_special_property_object::named_get_calls == 1); + REQUIRE(static_special_property_object::named_set_calls == 1); +}