From 0338b7d18f18c0dd1a55f0233606f438d441b449 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Thu, 11 Aug 2016 09:16:23 -0400 Subject: [PATCH] Baby you construct me in all the right ways, let's spend our lifetimes together in this wonderful scope.~ Closes #168 --- docs/source/api/object.rst | 6 ++++- sol/object.hpp | 51 +++++++++++++++++++++++--------------- sol/optional.hpp | 44 ++++++++++++++++++++++---------- sol/stack_core.hpp | 2 +- sol/stack_get.hpp | 2 +- sol/stack_push.hpp | 12 ++++++++- test_strings.cpp | 11 ++++++++ 7 files changed, 91 insertions(+), 37 deletions(-) diff --git a/docs/source/api/object.rst b/docs/source/api/object.rst index 0f02ebec..a7b98c30 100644 --- a/docs/source/api/object.rst +++ b/docs/source/api/object.rst @@ -20,8 +20,12 @@ members template object(T&&); object(lua_State* L, int index = -1); + template + object(lua_State* L, in_place_t, T&& arg, Args&&... args); + template + object(lua_State* L, in_place_type_t, Args&&... args); -There are 2 kinds of constructors here. One allows construction of a object from other reference types such as :doc:`table` and :doc:`stack_reference`. The other creates an object which references the specific element at the given index in the specified ``lua_State*``. +There are 4 kinds of constructors here. One allows construction of a object from other reference types such as :doc:`sol::table
` and :doc:`sol::stack_reference`. The secon creates an object which references the specific element at the given index in the specified ``lua_State*``. The more advanced ``in_place...`` constructors create a single object by pushing the specified type ``T`` onto the stack and then setting it as the object. It gets popped from the stack afterwards (unless this is an instance of ``sol::stack_object``, in which case it is left on the stack). .. code-block:: cpp :caption: function: type conversion diff --git a/sol/object.hpp b/sol/object.hpp index c9bd70ac..c8d7dbc6 100644 --- a/sol/object.hpp +++ b/sol/object.hpp @@ -28,6 +28,27 @@ #include "variadic_args.hpp" namespace sol { + + template ::value, typename T> + R make_reference(lua_State* L, T&& value) { + int backpedal = stack::push(L, std::forward(value)); + R r = stack::get(L, -backpedal); + if (should_pop) { + lua_pop(L, backpedal); + } + return r; + } + + template ::value, typename... Args> + R make_reference(lua_State* L, Args&&... args) { + int backpedal = stack::push(L, std::forward(args)...); + R r = stack::get(L, -backpedal); + if (should_pop) { + lua_pop(L, backpedal); + } + return r; + } + template class basic_object : public base_t { private: @@ -52,6 +73,12 @@ namespace sol { auto pp = stack::push_pop(*this); return stack::check(base_t::lua_state(), -1, no_panic); } + template + basic_object(std::integral_constant, lua_State* L, int index = -1) noexcept : base_t(L, index) { + if (invert_and_pop) { + lua_pop(L, -index); + } + } public: basic_object() noexcept = default; @@ -65,6 +92,10 @@ namespace sol { basic_object(const stack_reference& r) noexcept : basic_object(r.lua_state(), r.stack_index()) {} basic_object(stack_reference&& r) noexcept : basic_object(r.lua_state(), r.stack_index()) {} basic_object(lua_State* L, int index = -1) noexcept : base_t(L, index) {} + template + basic_object(lua_State* L, in_place_type_t, Args&&... args) noexcept : basic_object(std::integral_constant::value>(), L, -stack::push(L, std::forward(args)...)) {} + template + basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept : basic_object(L, in_place, std::forward(arg), std::forward(args)...) {} template decltype(auto) as() const { @@ -79,26 +110,6 @@ namespace sol { } }; - template ::value, typename T> - R make_reference(lua_State* L, T&& value) { - int backpedal = stack::push(L, std::forward(value)); - R r = stack::get(L, -backpedal); - if (should_pop) { - lua_pop(L, backpedal); - } - return r; - } - - template ::value, typename... Args> - object make_reference(lua_State* L, Args&&... args) { - int backpedal = stack::push(L, std::forward(args)...); - object r = stack::get(L, -backpedal); - if (should_pop) { - lua_pop(L, backpedal); - } - return r; - } - template object make_object(lua_State* L, T&& value) { return make_reference(L, std::forward(value)); diff --git a/sol/optional.hpp b/sol/optional.hpp index 812ae9fc..74b3bae3 100644 --- a/sol/optional.hpp +++ b/sol/optional.hpp @@ -22,28 +22,46 @@ #ifndef SOL_OPTIONAL_HPP #define SOL_OPTIONAL_HPP -#if __cplusplus > 201402L -#include -#elif defined(SOL_USE_BOOST) +#if defined(SOL_USE_BOOST) #include #else #include "../Optional/optional.hpp" -#endif // C++ 14 +#endif // Boost vs. Better optional namespace sol { -#if __cplusplus > 201402L - template - using optional = sol::optional; - using nullopt_t = std::nullopt_t; - constexpr nullopt_t nullopt = std::nullopt; -#elif defined(SOL_USE_BOOST) +#if defined(SOL_USE_BOOST) template using optional = boost::optional; using nullopt_t = boost::none_t; const nullopt_t nullopt = boost::none; -#else -#endif // C++ 14 -} + + namespace detail { + struct in_place_of {}; + } // detail + + struct in_place_tag { struct init {}; constexpr in_place_tag(init) {} in_place_tag() = delete; }; + constexpr inline in_place_tag in_place(detail::in_place_of) { return in_place_tag(in_place_tag::init()); } + using in_place_t = in_place_tag(&)(detail::in_place_of); +#endif // Boost vs. Better optional + + namespace detail { + template + struct in_place_of_i {}; + template + struct in_place_of_t {}; + } + + template + constexpr inline in_place_tag in_place(detail::in_place_of_t) { return in_place_tag(in_place_tag::init()); } + template + constexpr inline in_place_tag in_place(detail::in_place_of_i) { return in_place_tag(in_place_tag::init()); } + + template + using in_place_type_t = in_place_tag(&)(detail::in_place_of_t); + template + using in_place_index_t = in_place_tag(&)(detail::in_place_of_i); + +} // sol #endif // SOL_OPTIONAL_HPP diff --git a/sol/stack_core.hpp b/sol/stack_core.hpp index b980a197..8a8606ad 100644 --- a/sol/stack_core.hpp +++ b/sol/stack_core.hpp @@ -135,7 +135,7 @@ namespace sol { } // overload allows to use a pusher of a specific type, but pass in any kind of args - template + template::value>> inline int push(lua_State* L, Arg&& arg, Args&&... args) { return pusher>{}.push(L, std::forward(arg), std::forward(args)...); } diff --git a/sol/stack_get.hpp b/sol/stack_get.hpp index dc2f9dd1..60c8773c 100644 --- a/sol/stack_get.hpp +++ b/sol/stack_get.hpp @@ -143,7 +143,7 @@ namespace sol { tracking.use(1); std::size_t len; auto str = lua_tolstring(L, index, &len); - return{ str, len }; + return std::string( str, len ); } }; diff --git a/sol/stack_push.hpp b/sol/stack_push.hpp index 7d5753c3..ab253c0b 100644 --- a/sol/stack_push.hpp +++ b/sol/stack_push.hpp @@ -358,13 +358,18 @@ namespace sol { lua_pushlstring(L, str, N - 1); return 1; } + + static int push(lua_State* L, const char(&str)[N], std::size_t sz) { + lua_pushlstring(L, str, sz); + return 1; + } }; template <> struct pusher { static int push(lua_State* L, char c) { const char str[2] = { c, '\0' }; - return stack::push(L, str); + return stack::push(L, str, 1); } }; @@ -374,6 +379,11 @@ namespace sol { lua_pushlstring(L, str.c_str(), str.size()); return 1; } + + static int push(lua_State* L, const std::string& str, std::size_t sz) { + lua_pushlstring(L, str.c_str(), sz); + return 1; + } }; template<> diff --git a/test_strings.cpp b/test_strings.cpp index 114c572c..1e2cfe46 100644 --- a/test_strings.cpp +++ b/test_strings.cpp @@ -92,3 +92,14 @@ TEST_CASE("detail/demangling", "test some basic demangling cases") { REQUIRE(nsteststr == "ns_test"); REQUIRE(nsateststr == "ns_anon_test"); } + +TEST_CASE("object/string-pushers", "test some basic string pushers with in_place constructor") { + sol::state lua; + + sol::object ocs(lua, sol::in_place, "bark\0bark", 9); + sol::object os(lua, sol::in_place, std::string("bark\0bark", 9), 8); + bool test1 = os.as() == std::string("bark\0bar", 8); + bool test2 = ocs.as() == std::string("bark\0bark", 9); + REQUIRE(test1); + REQUIRE(test2); +}