sol2/sol/stack.hpp
PrincessNyanara 77901bb654 massive rework of stack
get turned into getter<T>, matches pusher<T> and uses same semantics as std::allocator and other things used throughout the codebase
-----
userdata has its traits defined outside in new file of userdata to prevent errors when trying to use those typetraits in places before userdata.hpp gets included
userdata was changed to support returning itself via pointers or references.
rework of stack changes semantics based on T&, T*, and T&& (the last one tries to create a new userdata and move in data)
solves problems maybe presented in https://github.com/Rapptz/sol/issues/25

-----
container.hpp is attempt at solving original problem before going on wild tangent with userdata, stack, and get
is going to attempt to use userdata to allow transporation of containers losslessly, perhaps without copying need
-----
found out trying to return a std::function does not work -- not sure what do exactly?
perhaps should push c closure as last thing, but right now it is tied to a key value (code comes from table.hpp and set_function)
will just have to think over how stack arranges itself and learn what to do
2014-06-09 06:28:55 -04:00

421 lines
14 KiB
C++

// The MIT License (MIT)
// Copyright (c) 2013 Danny Y., Rapptz
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_HPP
#define SOL_STACK_HPP
#include "error.hpp"
#include "reference.hpp"
#include "tuple.hpp"
#include "traits.hpp"
#include "userdata_traits.hpp"
#include <utility>
#include <array>
#include <cstring>
#include <functional>
namespace sol {
namespace detail {
template<typename T>
T* get_ptr(T& val) {
return std::addressof(val);
}
template<typename T>
T* get_ptr(T* val) {
return val;
}
} // detail
namespace stack {
namespace detail {
template<typename T, typename Key>
inline void push_userdata(lua_State* L, T&& userdata, Key&& metatablekey) {
T* pdatum = static_cast<T*>(lua_newuserdata(L, sizeof(T)));
T& datum = *pdatum;
datum = std::forward<T>(userdata);
luaL_getmetatable(L, std::addressof(metatablekey[0]));
lua_setmetatable(L, -2);
}
} // detail
template <typename T, typename X = void>
struct getter;
template <typename T, typename X = void>
struct pusher;
template <typename T, typename>
struct getter {
template<typename U = T, EnableIf<std::is_floating_point<U>> = 0>
static U get(lua_State* L, int index = -1) {
return lua_tonumber(L, index);
}
template<typename U = T, EnableIf<std::is_integral<U>, std::is_signed<U>> = 0>
static U get(lua_State* L, int index = -1) {
return lua_tounsigned(L, index);
}
template<typename U = T, EnableIf<std::is_integral<U>, std::is_unsigned<U>> = 0>
static U get(lua_State* L, int index = -1) {
return static_cast<T>(lua_tointeger(L, index));
}
template<typename U = T, EnableIf<std::is_base_of<reference, U>> = 0>
static U get(lua_State* L, int index = -1) {
return T(L, index);
}
template<typename U = T, EnableIf<Not<std::is_base_of<reference, U>>, Not<std::is_integral<U>>, Not<std::is_floating_point<U>>> = 0>
static U& get(lua_State* L, int index = -1) {
void* udata = lua_touserdata(L, index);
T* obj = static_cast<T*>(udata);
return *obj;
}
};
template <typename T>
struct getter<T*> {
static T* get(lua_State* L, int index = -1) {
void* udata = lua_touserdata(L, index);
T** obj = static_cast<T**>(udata);
return *obj;
}
};
template <>
struct getter<type> {
type get(lua_State *L, int index){
return static_cast<type>(lua_type(L, index));
}
};
template <>
struct getter<bool> {
static bool get(lua_State* L, int index) {
return lua_toboolean(L, index) != 0;
}
};
template <>
struct getter<std::string> {
static std::string get(lua_State* L, int index = -1) {
std::string::size_type len;
auto str = lua_tolstring(L, index, &len);
return{ str, len };
}
};
template <>
struct getter<const char*> {
const char* get(lua_State* L, int index = -1) {
return lua_tostring(L, index);
}
};
template <>
struct getter<nil_t> {
nil_t get(lua_State* L, int index = -1) {
if (lua_isnil(L, index) == 0)
throw sol::error("not nil");
return nil_t{ };
}
};
template <>
struct getter<userdata_t> {
userdata_t get(lua_State* L, int index = -1) {
return{ lua_touserdata(L, index) };
}
};
template <>
struct getter<lightuserdata_t> {
lightuserdata_t get(lua_State* L, int index = 1) {
return{ lua_touserdata(L, lua_upvalueindex(index)) };
}
};
template <>
struct getter<void*> {
void* get(lua_State* L, int index = 1) {
return lua_touserdata(L, index);
}
};
template<typename T, typename>
struct pusher {
template<typename U = T, EnableIf<std::is_floating_point<U>> = 0>
static void push(lua_State* L, const T& value) {
lua_pushnumber(L, value);
}
template<typename U = T, EnableIf<std::is_integral<U>, std::is_signed<U>> = 0>
static void push(lua_State* L, const T& value) {
lua_pushinteger(L, value);
}
template<typename U = T, EnableIf<std::is_integral<U>, std::is_unsigned<U>> = 0>
static void push(lua_State* L, const T& value) {
lua_pushunsigned(L, value);
}
template<typename U = T, EnableIf<std::is_base_of<reference, U>> = 0>
static void push(lua_State*, T& ref) {
ref.push();
}
template<typename U = T, EnableIf<Not<std::is_base_of<reference, U>>, Not<std::is_integral<U>>, Not<std::is_floating_point<U>>> = 0>
static void push(lua_State* L, T& t) {
pusher<T*>{}.push(L, std::addressof(t));
}
template<typename U = T, EnableIf<Not<std::is_base_of<reference, U>>, Not<std::is_integral<U>>, Not<std::is_floating_point<U>>> = 0>
static void push(lua_State* L, T&& t) {
detail::push_userdata(L, std::move(t), userdata_traits<T*>::metatable);
}
};
template<typename T>
struct pusher<T*> {
static void push(lua_State* L, T* obj) {
detail::push_userdata(L, obj, userdata_traits<T*>::metatable);
}
};
template<>
struct pusher<bool> {
static void push(lua_State* L, const bool& b) {
lua_pushboolean(L, b);
}
};
template<>
struct pusher<nil_t> {
static void push(lua_State* L, const nil_t&) {
lua_pushnil(L);
}
};
template<>
struct pusher<lua_CFunction> {
static void push(lua_State* L, lua_CFunction func) {
lua_pushcfunction(L, func);
}
};
template<>
struct pusher<void*> {
static void push(lua_State* L, void* userdata) {
lua_pushlightuserdata(L, userdata);
}
};
template<>
struct pusher<lightuserdata_t> {
static void push(lua_State* L, lightuserdata_t userdata) {
lua_pushlightuserdata(L, userdata);
}
};
template<>
struct pusher<const char*> {
static void push(lua_State* L, const char* str) {
lua_pushlstring(L, str, std::char_traits<char>::length(str));
}
};
template<size_t N>
struct pusher<char[N]> {
static void push(lua_State* L, const char (&str)[N]) {
lua_pushlstring(L, str, N - 1);
}
};
template<>
struct pusher<std::string> {
static void push(lua_State* L, const std::string& str) {
lua_pushlstring(L, str.c_str(), str.size());
}
};
inline void push(lua_State*) {
}
template<typename T, typename... Args>
inline void push(lua_State* L, T&& t, Args&&... args) {
using swallow = char[];
pusher<Unqualified<T>>{}.push(L, std::forward<T>(t));
void(swallow{'\0', (pusher<Unqualified<T>>{}.push(L, std::forward<Args>(args)), '\0')... });
}
template<typename T, typename U = Unqualified<T>>
inline auto get(lua_State* L, int index = -1) -> decltype(getter<U>{}.get(L, index)) {
return getter<U>{}.get(L, index);
}
template<typename T>
auto pop(lua_State* L) -> decltype(get<T>(L)) {
typedef decltype(get<T>(L)) ret_t;
ret_t r = get<T>(L);
lua_pop(L, 1);
return r;
}
namespace detail {
template<typename T>
inline int push_as_upvalues(lua_State* L, T& item) {
typedef typename std::decay<T>::type TValue;
const static std::size_t itemsize = sizeof(TValue);
const static std::size_t voidsize = sizeof(void*);
const static std::size_t voidsizem1 = voidsize - 1;
const static std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize;
typedef std::array<void*, data_t_count> data_t;
data_t data{{}};
std::memcpy(std::addressof(data[0]), std::addressof(item), itemsize);
for (auto&& v : data) {
push(L, v);
}
return data_t_count;
}
template<typename T>
inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 1) {
const static std::size_t data_t_count = (sizeof(T)+(sizeof(void*)-1)) / sizeof(void*);
typedef std::array<void*, data_t_count> data_t;
data_t voiddata{ {} };
for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) {
voiddata[ i ] = get<lightuserdata_t>(L, index++);
}
return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);
}
template<typename T, std::size_t... I>
inline void push_tuple(lua_State* L, indices<I...>, T&& tuplen) {
using swallow = char[1 + sizeof...(I)];
swallow {'\0', (sol::stack::push(L, std::get<I>(tuplen)), '\0')... };
}
template<typename F, typename... Vs, typename... Args>
inline auto ltr_get(lua_State*, int, F&& f, types<Args...>, types<>, Vs&&... vs) -> decltype(f(std::forward<Vs>(vs)...)) {
return f(std::forward<Vs>(vs)...);
}
template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args>
inline auto ltr_get(lua_State* L, int index, F&& f, types<Args...> t, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) {
return ltr_get(L, index + 1, std::forward<F>(f), t, types<Tail...>(), std::forward<Vs>(vs)..., stack::get<Head>(L, index));
}
template<typename F, typename... Vs, typename... Args>
inline auto ltr_pop(lua_State*, F&& f, types<Args...>, types<>, Vs&&... vs) -> decltype(f(std::forward<Vs>(vs)...)) {
return f(std::forward<Vs>(vs)...);
}
template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args>
inline auto ltr_pop(lua_State* L, F&& f, types<Args...> t, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) {
return ltr_pop(L, std::forward<F>(f), t, types<Tail...>(), std::forward<Vs>(vs)..., stack::pop<Head>(L));
}
template<typename F, typename... Vs, typename... Args>
inline auto rtl_pop(lua_State*, F&& f, types<Args...>, types<>, Vs&&... vs) -> decltype(f(std::forward<Vs>(vs)...)) {
return f(std::forward<Vs>(vs)...);
}
template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args>
inline auto rtl_pop(lua_State* L, F&& f, types<Args...> t, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) {
return rtl_pop(L, std::forward<F>(f), t, types<Tail...>(), stack::pop<Head>(L), std::forward<Vs>(vs)...);
}
} // detail
template<typename... Args>
struct pusher<std::tuple<Args...>> {
static void push(lua_State* L, const std::tuple<Args...>& tuplen) {
detail::push_tuple(L, build_indices<sizeof...(Args)>(), tuplen);
}
static void push(lua_State* L, std::tuple<Args...>&& tuplen) {
detail::push_tuple(L, build_indices<sizeof...(Args)>(), std::move(tuplen));
}
};
template<typename T>
inline void push_reverse(lua_State* L, T&& item) {
push(L, std::forward<T>(item));
}
template<typename... Args>
inline void push_reverse(lua_State* L, const std::tuple<Args...>& tuplen) {
detail::push_tuple(L, build_reverse_indices<sizeof...(Args)>(), tuplen);
}
template<typename... Args>
inline void push_reverse(lua_State* L, std::tuple<Args...>&& tuplen) {
detail::push_tuple(L, build_reverse_indices<sizeof...(Args)>(), std::move(tuplen));
}
template<typename... Args, typename TFx>
inline auto get_call(lua_State* L, int index, TFx&& fx, types<Args...> t) -> decltype(detail::ltr_get(L, index, std::forward<TFx>(fx), t, t)) {
return detail::ltr_get(L, index, std::forward<TFx>(fx), t, t);
}
template<typename... Args, typename TFx>
inline auto get_call(lua_State* L, TFx&& fx, types<Args...> t) -> decltype(get_call(L, 1, std::forward<TFx>(fx), t)) {
return get_call(L, 1, std::forward<TFx>(fx), t);
}
template<typename... Args, typename TFx>
inline auto pop_call(lua_State* L, TFx&& fx, types<Args...> t) -> decltype(detail::ltr_pop(L, std::forward<TFx>(fx), t, t)) {
return detail::ltr_pop(L, std::forward<TFx>(fx), t, t);
}
template<typename... Args, typename TFx>
inline auto pop_reverse_call(lua_State* L, TFx&& fx, types<Args...> t) -> decltype(detail::rtl_pop(L, std::forward<TFx>(fx), t, reversed<Args...>())) {
return detail::rtl_pop(L, std::forward<TFx>(fx), t, reversed<Args...>());
}
inline call_syntax get_call_syntax(lua_State* L, const std::string& meta) {
if (get<type>(L, 1) == type::table) {
if (luaL_newmetatable(L, meta.c_str()) == 0) {
lua_settop(L, -2);
return call_syntax::colon;
}
}
return call_syntax::dot;
}
inline std::string dump_types(lua_State* L) {
std::string visual;
std::size_t size = lua_gettop(L) + 1;
for (std::size_t i = 1; i < size; ++i) {
if (i != 1)
visual += " | ";
visual += type_name(L, stack::get<type>(L, i));
}
return visual;
}
template <typename T>
struct get_return {
typedef decltype(get<T>(nullptr)) type;
};
} // stack
} // sol
#endif // SOL_STACK_HPP