diff --git a/docs/source/api/proxy.rst b/docs/source/api/proxy.rst index c31edcb6..03f01369 100644 --- a/docs/source/api/proxy.rst +++ b/docs/source/api/proxy.rst @@ -78,6 +78,17 @@ Gets the value associated with the keys and converts it to the type ``T``. Gets the value associated with the keys and converts it to the type ``T``. If it is not of the proper type, it will return a ``sol::nullopt`` instead. +.. code-block:: c++ + :caption: function: [overloaded] optionally get or create a value + :name: regular-get-or-create + + template + decltype(auto) get_or_create(); + template + decltype(auto) get_or_create( Otherwise&& other ); + +Gets the value associated with the keys if it exists. If it does not, it will set it with the value and return the result. + ``operator[]`` proxy-only members --------------------------------- diff --git a/examples/tutorials/quick_n_dirty/namespacing.cpp b/examples/tutorials/quick_n_dirty/namespacing.cpp index e00cee8c..e556e867 100644 --- a/examples/tutorials/quick_n_dirty/namespacing.cpp +++ b/examples/tutorials/quick_n_dirty/namespacing.cpp @@ -24,7 +24,14 @@ int main() { // "bark" namespacing in Lua // namespacing is just putting things in a table - sol::table bark = lua.create_named_table("bark"); + // forces creation if it does not exist + auto bark = lua["bark"].get_or_create(); + // equivalent-ish: + //sol::table bark = lua["bark"].force(); // forces table creation + // equivalent, and more flexible: + //sol::table bark = lua["bark"].get_or_create(sol::new_table()); + // equivalent, but less efficient/ugly: + //sol::table bark = lua["bark"] = lua.get_or("bark", lua.create_table()); bark.new_usertype("my_class", "f", &my_class::f, "g", &my_class::g); // the usual diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index 1aa57816..cb4f8a22 100644 --- a/single/sol/sol.hpp +++ b/single/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 2018-11-09 18:52:51.075276 UTC -// This header was generated with sol v2.20.4 (revision 1f90b04) +// Generated 2018-11-10 14:40:45.361811 UTC +// This header was generated with sol v2.20.5 (revision a7048ae) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -8247,12 +8247,12 @@ namespace stack { } #endif // Do not allow strings to be numbers int isnum = 0; - const lua_Number v = lua_tonumberx(L, index, &isnum); - const bool success = isnum != 0 #if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) - && static_cast(llround(v)) == v + const lua_Number v = lua_tonumberx(L, index, &isnum); + const bool success = isnum != 0 && static_cast(llround(v)) == v; +#else + const bool success = isnum != 0; #endif // Safe numerics and number precision checking - ; if (!success) { // expected type, actual type #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS @@ -14542,7 +14542,7 @@ namespace sol { template static void set_fx(lua_State* L, Args&&... args) { - lua_CFunction freefunc = function_detail::call, 2, is_yielding>; + lua_CFunction freefunc = detail::static_trampoline, 2, is_yielding>>; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -15512,6 +15512,19 @@ namespace sol { return static_cast(std::forward(otherwise)); } + template + decltype(auto) get_or_create() { + return get_or_create(new_table()); + } + + template + decltype(auto) get_or_create(Otherwise&& other) { + if (!this->valid()) { + this->set(std::forward(other)); + } + return get(); + } + template decltype(auto) operator[](K&& k) const { auto keys = meta::tuplefy(key, std::forward(k)); @@ -15562,6 +15575,13 @@ namespace sol { lua_State* lua_state() const { return tbl.lua_state(); } + + proxy& force() { + if (this->valid()) { + this->set(new_table()); + } + return *this; + } }; template @@ -18280,6 +18300,9 @@ namespace sol { #include namespace sol { + + struct usertype_metatable_core; + namespace usertype_detail { const int metatable_index = 2; const int metatable_core_index = 3; @@ -18291,7 +18314,7 @@ namespace sol { const int newindex_function_index = 4; typedef void (*base_walk)(lua_State*, bool&, int&, string_view&); - typedef int (*member_search)(lua_State*, void*, int); + typedef int (*member_search)(lua_State*, void*, usertype_metatable_core&, int); struct call_information { member_search index; @@ -18443,8 +18466,7 @@ namespace sol { return isnum != 0 && magic == toplevel_magic; } - inline int runtime_object_call(lua_State* L, void*, int runtimetarget) { - usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); + inline int runtime_object_call(lua_State* L, void*, usertype_metatable_core& umc, int runtimetarget) { std::vector& runtime = umc.runtime; object& runtimeobj = runtime[runtimetarget]; return stack::push(L, runtimeobj); @@ -18476,7 +18498,7 @@ namespace sol { } } - int runtime_new_index(lua_State* L, void*, int runtimetarget); + int runtime_new_index(lua_State* L, void*, usertype_metatable_core&, int runtimetarget); template inline int metatable_new_index(lua_State* L) { @@ -18575,8 +18597,7 @@ namespace sol { return indexing_fail(L); } - inline int runtime_new_index(lua_State* L, void*, int runtimetarget) { - usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); + inline int runtime_new_index(lua_State* L, void*, usertype_metatable_core& umc, int runtimetarget) { std::vector& runtime = umc.runtime; object& runtimeobj = runtime[runtimetarget]; runtimeobj = object(L, 3); @@ -18781,7 +18802,7 @@ namespace sol { usertype_metatable& operator=(usertype_metatable&&) = default; template - static int real_find_call(lua_State* L, void* um, int) { + static int real_find_call(lua_State* L, void* um, usertype_metatable_core&, int) { auto& f = *static_cast(um); if (is_variable_binding(f.functions))>::value) { return real_call_with(L, f); @@ -18827,7 +18848,7 @@ namespace sol { } } if (member != nullptr) { - return (member)(L, static_cast(&f), runtime_target); + return (member)(L, static_cast(&f), static_cast(f), runtime_target); } string_view accessor = stack::get(L, keyidx); int ret = 0; diff --git a/single/sol/sol_forward.hpp b/single/sol/sol_forward.hpp index 371c3873..6b6080bb 100644 --- a/single/sol/sol_forward.hpp +++ b/single/sol/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 2018-11-09 18:52:51.285820 UTC -// This header was generated with sol v2.20.4 (revision 1f90b04) +// Generated 2018-11-10 14:40:45.917037 UTC +// This header was generated with sol v2.20.5 (revision a7048ae) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP diff --git a/sol/function_types.hpp b/sol/function_types.hpp index d0c49e16..ad2b4bda 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -220,7 +220,7 @@ namespace sol { template static void set_fx(lua_State* L, Args&&... args) { - lua_CFunction freefunc = function_detail::call, 2, is_yielding>; + lua_CFunction freefunc = detail::static_trampoline, 2, is_yielding>>; int upvalues = 0; upvalues += stack::push(L, nullptr); diff --git a/sol/proxy.hpp b/sol/proxy.hpp index 6b68cd81..99f0f0c6 100644 --- a/sol/proxy.hpp +++ b/sol/proxy.hpp @@ -1,4 +1,4 @@ -// sol2 +// sol2 // The MIT License (MIT) @@ -118,6 +118,20 @@ namespace sol { return static_cast(std::forward(otherwise)); } + + template + decltype(auto) get_or_create() { + return get_or_create(new_table()); + } + + template + decltype(auto) get_or_create(Otherwise&& other) { + if (!this->valid()) { + this->set(std::forward(other)); + } + return get(); + } + template decltype(auto) operator[](K&& k) const { auto keys = meta::tuplefy(key, std::forward(k)); @@ -168,6 +182,13 @@ namespace sol { lua_State* lua_state() const { return tbl.lua_state(); } + + proxy& force() { + if (this->valid()) { + this->set(new_table()); + } + return *this; + } }; template diff --git a/sol/stack_check_unqualified.hpp b/sol/stack_check_unqualified.hpp index b05f73ce..e63a70e2 100644 --- a/sol/stack_check_unqualified.hpp +++ b/sol/stack_check_unqualified.hpp @@ -140,12 +140,12 @@ namespace stack { } #endif // Do not allow strings to be numbers int isnum = 0; - const lua_Number v = lua_tonumberx(L, index, &isnum); - const bool success = isnum != 0 #if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) - && static_cast(llround(v)) == v + const lua_Number v = lua_tonumberx(L, index, &isnum); + const bool success = isnum != 0 && static_cast(llround(v)) == v; +#else + const bool success = isnum != 0; #endif // Safe numerics and number precision checking - ; if (!success) { // expected type, actual type #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS diff --git a/sol/usertype_metatable.hpp b/sol/usertype_metatable.hpp index a091f4f3..cc511cee 100644 --- a/sol/usertype_metatable.hpp +++ b/sol/usertype_metatable.hpp @@ -43,6 +43,9 @@ #include namespace sol { + + struct usertype_metatable_core; + namespace usertype_detail { const int metatable_index = 2; const int metatable_core_index = 3; @@ -54,7 +57,7 @@ namespace sol { const int newindex_function_index = 4; typedef void (*base_walk)(lua_State*, bool&, int&, string_view&); - typedef int (*member_search)(lua_State*, void*, int); + typedef int (*member_search)(lua_State*, void*, usertype_metatable_core&, int); struct call_information { member_search index; @@ -206,8 +209,7 @@ namespace sol { return isnum != 0 && magic == toplevel_magic; } - inline int runtime_object_call(lua_State* L, void*, int runtimetarget) { - usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); + inline int runtime_object_call(lua_State* L, void*, usertype_metatable_core& umc, int runtimetarget) { std::vector& runtime = umc.runtime; object& runtimeobj = runtime[runtimetarget]; return stack::push(L, runtimeobj); @@ -239,7 +241,7 @@ namespace sol { } } - int runtime_new_index(lua_State* L, void*, int runtimetarget); + int runtime_new_index(lua_State* L, void*, usertype_metatable_core&, int runtimetarget); template inline int metatable_new_index(lua_State* L) { @@ -338,8 +340,7 @@ namespace sol { return indexing_fail(L); } - inline int runtime_new_index(lua_State* L, void*, int runtimetarget) { - usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); + inline int runtime_new_index(lua_State* L, void*, usertype_metatable_core& umc, int runtimetarget) { std::vector& runtime = umc.runtime; object& runtimeobj = runtime[runtimetarget]; runtimeobj = object(L, 3); @@ -544,7 +545,7 @@ namespace sol { usertype_metatable& operator=(usertype_metatable&&) = default; template - static int real_find_call(lua_State* L, void* um, int) { + static int real_find_call(lua_State* L, void* um, usertype_metatable_core&, int) { auto& f = *static_cast(um); if (is_variable_binding(f.functions))>::value) { return real_call_with(L, f); @@ -590,7 +591,7 @@ namespace sol { } } if (member != nullptr) { - return (member)(L, static_cast(&f), runtime_target); + return (member)(L, static_cast(&f), static_cast(f), runtime_target); } string_view accessor = stack::get(L, keyidx); int ret = 0; diff --git a/tests/test_usertypes.cpp b/tests/test_usertypes.cpp index a39387e9..d647d6b6 100644 --- a/tests/test_usertypes.cpp +++ b/tests/test_usertypes.cpp @@ -310,7 +310,7 @@ struct alignas(16) weird_aligned_wrapper { } void operator()(SelfType& self, sol::object param) const { lambda(self, param.as()); - } + } std::function lambda; }; @@ -1627,6 +1627,16 @@ TEST_CASE("usertype/runtime-extensibility", "Check if usertypes are runtime exte }; int val = 0; + class base_a { + public: + int x; + }; + + class derived_b : public base_a { + }; + + + SECTION("just functions") { sol::state lua; lua.open_libraries(sol::lib::base); @@ -1722,6 +1732,24 @@ end val = lua["val"]; REQUIRE(val == 3); } + SECTION("with bases") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("A", + "x", &base_a::x //no crash without this + ); + + lua.new_usertype("B", + sol::base_classes, sol::bases()); + + auto pfr0 = lua.safe_script("function A:c() print('A') return 1 end", sol::script_pass_on_error); + REQUIRE(pfr0.valid()); + auto pfr1 = lua.safe_script("function B:c() print('B') return 2 end", sol::script_pass_on_error); + REQUIRE(pfr1.valid()); + auto pfr2 = lua.safe_script("local obja = A.new() local objb = B.new() assert(obja:c() == 1) assert(objb:c() == 2)", sol::script_pass_on_error); + REQUIRE(pfr2.valid()); + } } TEST_CASE("usertype/runtime-replacement", "ensure that functions can be properly replaced at runtime for non-indexed things") {