Baby you construct me in all the right ways, let's spend our lifetimes together in this wonderful scope.~

Closes #168
This commit is contained in:
ThePhD 2016-08-11 09:16:23 -04:00
parent 7280668de7
commit 0338b7d18f
7 changed files with 91 additions and 37 deletions

View File

@ -20,8 +20,12 @@ members
template <typename T> template <typename T>
object(T&&); object(T&&);
object(lua_State* L, int index = -1); object(lua_State* L, int index = -1);
template <typename T, typename... Args>
object(lua_State* L, in_place_t, T&& arg, Args&&... args);
template <typename T, typename... Args>
object(lua_State* L, in_place_type_t<T>, Args&&... args);
There are 2 kinds of constructors here. One allows construction of a object from other reference types such as :doc:`table<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<table>` and :doc:`sol::stack_reference<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 .. code-block:: cpp
:caption: function: type conversion :caption: function: type conversion

View File

@ -28,6 +28,27 @@
#include "variadic_args.hpp" #include "variadic_args.hpp"
namespace sol { namespace sol {
template <typename R = reference, bool should_pop = !std::is_base_of<stack_reference, R>::value, typename T>
R make_reference(lua_State* L, T&& value) {
int backpedal = stack::push(L, std::forward<T>(value));
R r = stack::get<R>(L, -backpedal);
if (should_pop) {
lua_pop(L, backpedal);
}
return r;
}
template <typename T, typename R = reference, bool should_pop = !std::is_base_of<stack_reference, R>::value, typename... Args>
R make_reference(lua_State* L, Args&&... args) {
int backpedal = stack::push<T>(L, std::forward<Args>(args)...);
R r = stack::get<R>(L, -backpedal);
if (should_pop) {
lua_pop(L, backpedal);
}
return r;
}
template <typename base_t> template <typename base_t>
class basic_object : public base_t { class basic_object : public base_t {
private: private:
@ -52,6 +73,12 @@ namespace sol {
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
return stack::check<T>(base_t::lua_state(), -1, no_panic); return stack::check<T>(base_t::lua_state(), -1, no_panic);
} }
template <bool invert_and_pop = false>
basic_object(std::integral_constant<bool, invert_and_pop>, lua_State* L, int index = -1) noexcept : base_t(L, index) {
if (invert_and_pop) {
lua_pop(L, -index);
}
}
public: public:
basic_object() noexcept = default; 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(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(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) {} basic_object(lua_State* L, int index = -1) noexcept : base_t(L, index) {}
template <typename T, typename... Args>
basic_object(lua_State* L, in_place_type_t<T>, Args&&... args) noexcept : basic_object(std::integral_constant<bool, !std::is_base_of<stack_reference, base_t>::value>(), L, -stack::push<T>(L, std::forward<Args>(args)...)) {}
template <typename T, typename... Args>
basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept : basic_object(L, in_place<T>, std::forward<T>(arg), std::forward<Args>(args)...) {}
template<typename T> template<typename T>
decltype(auto) as() const { decltype(auto) as() const {
@ -79,26 +110,6 @@ namespace sol {
} }
}; };
template <typename R = reference, bool should_pop = !std::is_base_of<stack_reference, R>::value, typename T>
R make_reference(lua_State* L, T&& value) {
int backpedal = stack::push(L, std::forward<T>(value));
R r = stack::get<R>(L, -backpedal);
if (should_pop) {
lua_pop(L, backpedal);
}
return r;
}
template <typename T, typename R = reference, bool should_pop = !std::is_base_of<stack_reference, R>::value, typename... Args>
object make_reference(lua_State* L, Args&&... args) {
int backpedal = stack::push<T>(L, std::forward<Args>(args)...);
object r = stack::get<sol::object>(L, -backpedal);
if (should_pop) {
lua_pop(L, backpedal);
}
return r;
}
template <typename T> template <typename T>
object make_object(lua_State* L, T&& value) { object make_object(lua_State* L, T&& value) {
return make_reference<object, true>(L, std::forward<T>(value)); return make_reference<object, true>(L, std::forward<T>(value));

View File

@ -22,28 +22,46 @@
#ifndef SOL_OPTIONAL_HPP #ifndef SOL_OPTIONAL_HPP
#define SOL_OPTIONAL_HPP #define SOL_OPTIONAL_HPP
#if __cplusplus > 201402L #if defined(SOL_USE_BOOST)
#include <optional>
#elif defined(SOL_USE_BOOST)
#include <boost/optional.hpp> #include <boost/optional.hpp>
#else #else
#include "../Optional/optional.hpp" #include "../Optional/optional.hpp"
#endif // C++ 14 #endif // Boost vs. Better optional
namespace sol { namespace sol {
#if __cplusplus > 201402L #if defined(SOL_USE_BOOST)
template <typename T>
using optional = sol::optional<T>;
using nullopt_t = std::nullopt_t;
constexpr nullopt_t nullopt = std::nullopt;
#elif defined(SOL_USE_BOOST)
template <typename T> template <typename T>
using optional = boost::optional<T>; using optional = boost::optional<T>;
using nullopt_t = boost::none_t; using nullopt_t = boost::none_t;
const nullopt_t nullopt = boost::none; 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 <std::size_t I>
struct in_place_of_i {};
template <typename T>
struct in_place_of_t {};
}
template <typename T>
constexpr inline in_place_tag in_place(detail::in_place_of_t<T>) { return in_place_tag(in_place_tag::init()); }
template <std::size_t I>
constexpr inline in_place_tag in_place(detail::in_place_of_i<I>) { return in_place_tag(in_place_tag::init()); }
template <typename T>
using in_place_type_t = in_place_tag(&)(detail::in_place_of_t<T>);
template <std::size_t I>
using in_place_index_t = in_place_tag(&)(detail::in_place_of_i<I>);
} // sol
#endif // SOL_OPTIONAL_HPP #endif // SOL_OPTIONAL_HPP

View File

@ -135,7 +135,7 @@ namespace sol {
} }
// overload allows to use a pusher of a specific type, but pass in any kind of args // overload allows to use a pusher of a specific type, but pass in any kind of args
template<typename T, typename Arg, typename... Args> template<typename T, typename Arg, typename... Args, typename = std::enable_if_t<!std::is_same<T, Arg>::value>>
inline int push(lua_State* L, Arg&& arg, Args&&... args) { inline int push(lua_State* L, Arg&& arg, Args&&... args) {
return pusher<meta::unqualified_t<T>>{}.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...); return pusher<meta::unqualified_t<T>>{}.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
} }

View File

@ -143,7 +143,7 @@ namespace sol {
tracking.use(1); tracking.use(1);
std::size_t len; std::size_t len;
auto str = lua_tolstring(L, index, &len); auto str = lua_tolstring(L, index, &len);
return{ str, len }; return std::string( str, len );
} }
}; };

View File

@ -358,13 +358,18 @@ namespace sol {
lua_pushlstring(L, str, N - 1); lua_pushlstring(L, str, N - 1);
return 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 <> template <>
struct pusher<char> { struct pusher<char> {
static int push(lua_State* L, char c) { static int push(lua_State* L, char c) {
const char str[2] = { c, '\0' }; 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()); lua_pushlstring(L, str.c_str(), str.size());
return 1; 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<> template<>

View File

@ -92,3 +92,14 @@ TEST_CASE("detail/demangling", "test some basic demangling cases") {
REQUIRE(nsteststr == "ns_test"); REQUIRE(nsteststr == "ns_test");
REQUIRE(nsateststr == "ns_anon_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>, std::string("bark\0bark", 9), 8);
bool test1 = os.as<std::string>() == std::string("bark\0bar", 8);
bool test2 = ocs.as<std::string>() == std::string("bark\0bark", 9);
REQUIRE(test1);
REQUIRE(test2);
}