// The MIT License (MIT) // Copyright (c) 2013-2016 Rapptz, ThePhD and contributors // 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_GET_HPP #define SOL_STACK_GET_HPP #include "stack_core.hpp" #include "usertype_traits.hpp" #include "inheritance.hpp" #include "overload.hpp" #include "error.hpp" #include #include #include #ifdef SOL_CODECVT_SUPPORT #include #include #endif namespace sol { namespace stack { template struct getter { static T& get(lua_State* L, int index, record& tracking) { return getter{}.get(L, index, tracking); } }; template struct getter::value>> { static T get(lua_State* L, int index, record& tracking) { tracking.use(1); return static_cast(lua_tonumber(L, index)); } }; template struct getter, std::is_signed>::value>> { static T get(lua_State* L, int index, record& tracking) { tracking.use(1); return static_cast(lua_tointeger(L, index)); } }; template struct getter, std::is_unsigned>::value>> { static T get(lua_State* L, int index, record& tracking) { tracking.use(1); return static_cast(lua_tointeger(L, index)); } }; template struct getter::value>> { static T get(lua_State* L, int index, record& tracking) { tracking.use(1); return static_cast(lua_tointegerx(L, index, nullptr)); } }; template struct getter, std::enable_if_t>::value>> { static T get(lua_State* L, int index, record& tracking) { typedef typename T::value_type V; tracking.use(1); index = lua_absindex(L, index); T arr; get_field(L, static_cast(-1), index); int isnum; std::size_t sizehint = static_cast(lua_tointegerx(L, -1, &isnum)); if (isnum != 0) { detail::reserve(arr, sizehint); } lua_pop(L, 1); #if SOL_LUA_VERSION >= 503 // This method is HIGHLY performant over regular table iteration thanks to the Lua API changes in 5.3 for (lua_Integer i = 0; ; i += lua_size::value, lua_pop(L, lua_size::value)) { for (int vi = 0; vi < lua_size::value; ++vi) { type t = static_cast(lua_geti(L, index, i + vi)); if (t == type::nil) { if (i == 0) { continue; } else { lua_pop(L, (vi + 1)); return arr; } } } arr.push_back(stack::get(L, -lua_size::value)); } #else // Zzzz slower but necessary thanks to the lower version API and missing functions qq for (lua_Integer i = 0; ; i += lua_size::value, lua_pop(L, lua_size::value)) { for (int vi = 0; vi < lua_size::value; ++vi) { lua_pushinteger(L, i); lua_gettable(L, index); type t = type_of(L, -1); if (t == type::nil) { if (i == 0) { continue; } else { lua_pop(L, (vi + 1)); return arr; } } } arr.push_back(stack::get(L, -1)); } #endif return arr; } }; template struct getter, std::enable_if_t>::value>> { static T get(lua_State* L, int index, record& tracking) { typedef typename T::value_type P; typedef typename P::first_type K; typedef typename P::second_type V; tracking.use(1); T associative; index = lua_absindex(L, index); lua_pushnil(L); while (lua_next(L, index) != 0) { decltype(auto) key = stack::check_get(L, -2); if (!key) { lua_pop(L, 1); continue; } associative.emplace(std::forward(*key), stack::get(L, -1)); lua_pop(L, 1); } return associative; } }; template struct getter::value || std::is_base_of::value>> { static T get(lua_State* L, int index, record& tracking) { tracking.use(1); return T(L, index); } }; template<> struct getter { static userdata_value get(lua_State* L, int index, record& tracking) { tracking.use(1); return userdata_value(lua_touserdata(L, index)); } }; template<> struct getter { static lightuserdata_value get(lua_State* L, int index, record& tracking) { tracking.use(1); return lightuserdata_value(lua_touserdata(L, index)); } }; template struct getter> { static light get(lua_State* L, int index, record& tracking) { tracking.use(1); return light(static_cast(lua_touserdata(L, index))); } }; template struct getter> { static T& get(lua_State* L, int index, record& tracking) { tracking.use(1); return *static_cast(lua_touserdata(L, index)); } }; template struct getter> { static T* get(lua_State* L, int index, record& tracking) { tracking.use(1); return static_cast(lua_touserdata(L, index)); } }; template<> struct getter { static type get(lua_State *L, int index, record& tracking) { tracking.use(1); return static_cast(lua_type(L, index)); } }; template<> struct getter { static bool get(lua_State* L, int index, record& tracking) { tracking.use(1); return lua_toboolean(L, index) != 0; } }; template<> struct getter { static std::string get(lua_State* L, int index, record& tracking) { tracking.use(1); std::size_t len; auto str = lua_tolstring(L, index, &len); return std::string( str, len ); } }; template <> struct getter { string_detail::string_shim get(lua_State* L, int index, record& tracking) { tracking.use(1); size_t len; const char* p = lua_tolstring(L, index, &len); return string_detail::string_shim(p, len); } }; template<> struct getter { static const char* get(lua_State* L, int index, record& tracking) { tracking.use(1); return lua_tostring(L, index); } }; template<> struct getter { static char get(lua_State* L, int index, record& tracking) { tracking.use(1); size_t len; auto str = lua_tolstring(L, index, &len); return len > 0 ? str[0] : '\0'; } }; #ifdef SOL_CODECVT_SUPPORT template<> struct getter { static std::wstring get(lua_State* L, int index, record& tracking) { tracking.use(1); size_t len; auto str = lua_tolstring(L, index, &len); if (len < 1) return std::wstring(); if (sizeof(wchar_t) == 2) { std::wstring_convert> convert; std::wstring r = convert.from_bytes(str, str + len); #ifdef __MINGW32__ // Fuck you, MinGW, and fuck you libstdc++ for introducing this absolutely asinine bug // https://sourceforge.net/p/mingw-w64/bugs/538/ // http://chat.stackoverflow.com/transcript/message/32271369#32271369 for (auto& c : r) { uint8_t* b = reinterpret_cast(&c); std::swap(b[0], b[1]); } #endif return r; } std::wstring_convert> convert; std::wstring r = convert.from_bytes(str, str + len); return r; } }; template<> struct getter { static std::u16string get(lua_State* L, int index, record& tracking) { tracking.use(1); size_t len; auto str = lua_tolstring(L, index, &len); if (len < 1) return std::u16string(); #ifdef _MSC_VER std::wstring_convert, int16_t> convert; auto intd = convert.from_bytes(str, str + len); std::u16string r(intd.size(), '\0'); std::memcpy(&r[0], intd.data(), intd.size() * sizeof(char16_t)); #else std::wstring_convert, char16_t> convert; std::u16string r = convert.from_bytes(str, str + len); #endif // VC++ is a shit return r; } }; template<> struct getter { static std::u32string get(lua_State* L, int index, record& tracking) { tracking.use(1); size_t len; auto str = lua_tolstring(L, index, &len); if (len < 1) return std::u32string(); #ifdef _MSC_VER std::wstring_convert, int32_t> convert; auto intd = convert.from_bytes(str, str + len); std::u32string r(intd.size(), '\0'); std::memcpy(&r[0], intd.data(), r.size() * sizeof(char32_t)); #else std::wstring_convert, char32_t> convert; std::u32string r = convert.from_bytes(str, str + len); #endif // VC++ is a shit return r; } }; template<> struct getter { static wchar_t get(lua_State* L, int index, record& tracking) { auto str = getter{}.get(L, index, tracking); return str.size() > 0 ? str[0] : '\0'; } }; template<> struct getter { static char get(lua_State* L, int index, record& tracking) { auto str = getter{}.get(L, index, tracking); return str.size() > 0 ? str[0] : '\0'; } }; template<> struct getter { static char32_t get(lua_State* L, int index, record& tracking) { auto str = getter{}.get(L, index, tracking); return str.size() > 0 ? str[0] : '\0'; } }; #endif // codecvt header support template<> struct getter { static meta_function get(lua_State *L, int index, record& tracking) { tracking.use(1); const char* name = getter{}.get(L, index, tracking); for (std::size_t i = 0; i < meta_function_names.size(); ++i) if (meta_function_names[i] == name) return static_cast(i); return meta_function::construct; } }; template<> struct getter { static nil_t get(lua_State*, int, record& tracking) { tracking.use(1); return nil; } }; template<> struct getter { static std::nullptr_t get(lua_State*, int, record& tracking) { tracking.use(1); return nullptr; } }; template<> struct getter { static nullopt_t get(lua_State*, int, record& tracking) { tracking.use(1); return nullopt; } }; template<> struct getter { static this_state get(lua_State* L, int, record& tracking) { tracking.use(0); return this_state{ L }; } }; template<> struct getter { static lua_CFunction get(lua_State* L, int index, record& tracking) { tracking.use(1); return lua_tocfunction(L, index); } }; template<> struct getter { static c_closure get(lua_State* L, int index, record& tracking) { tracking.use(1); return c_closure(lua_tocfunction(L, index), -1); } }; template<> struct getter { static error get(lua_State* L, int index, record& tracking) { tracking.use(1); size_t sz = 0; const char* err = lua_tolstring(L, index, &sz); if (err == nullptr) { return error(detail::direct_error, ""); } return error(detail::direct_error, std::string(err, sz)); } }; template<> struct getter { static void* get(lua_State* L, int index, record& tracking) { tracking.use(1); return lua_touserdata(L, index); } }; template struct getter { static T* get_no_nil(lua_State* L, int index, record& tracking) { tracking.use(1); void** pudata = static_cast(lua_touserdata(L, index)); void* udata = *pudata; return get_no_nil_from(L, udata, index, tracking); } static T* get_no_nil_from(lua_State* L, void* udata, int index, record&) { if (detail::has_derived::value && luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) { void* basecastdata = lua_touserdata(L, -1); detail::inheritance_cast_function ic = (detail::inheritance_cast_function)basecastdata; // use the casting function to properly adjust the pointer for the desired T udata = ic(udata, detail::id_for::value); lua_pop(L, 1); } T* obj = static_cast(udata); return obj; } static T* get(lua_State* L, int index, record& tracking) { type t = type_of(L, index); if (t == type::nil) { tracking.use(1); return nullptr; } return get_no_nil(L, index, tracking); } }; template struct getter> { static T* get(lua_State* L, int index, record& tracking) { return getter::get_no_nil(L, index, tracking); } }; template struct getter { static T& get(lua_State* L, int index, record& tracking) { return *getter::get_no_nil(L, index, tracking); } }; template struct getter::value>> { typedef typename unique_usertype_traits::type P; typedef typename unique_usertype_traits::actual_type Real; static Real& get(lua_State* L, int index, record& tracking) { tracking.use(1); P** pref = static_cast(lua_touserdata(L, index)); detail::special_destruct_func* fx = static_cast(static_cast(pref + 1)); Real* mem = static_cast(static_cast(fx + 1)); return *mem; } }; template struct getter> { static T& get(lua_State* L, int index, record& tracking) { return getter{}.get(L, index, tracking); } }; template struct getter> { typedef std::tuple(nullptr, 0))...> R; template static R apply(std::index_sequence<>, lua_State*, int, record&, TArgs&&... args) { // Fuck you too, VC++ return R{std::forward(args)...}; } template static R apply(std::index_sequence, lua_State* L, int index, record& tracking, TArgs&&... args) { // Fuck you too, VC++ typedef std::tuple_element_t> T; return apply(std::index_sequence(), L, index, tracking, std::forward(args)..., stack::get(L, index + tracking.used, tracking)); } static R get(lua_State* L, int index, record& tracking) { return apply(std::make_index_sequence(), L, index, tracking); } }; template struct getter> { static decltype(auto) get(lua_State* L, int index, record& tracking) { return std::pair(L, index)), decltype(stack::get(L, index))>{stack::get(L, index, tracking), stack::get(L, index + tracking.used, tracking)}; } }; } // stack } // sol #endif // SOL_STACK_GET_HPP