We do have a cheap char type now, but figuring out that codecvt is super busted makes me sad

Safety macros are now in place. Usertype ones turned on by default
Closes #93
Closes #94
This commit is contained in:
ThePhD 2016-05-18 21:29:17 -04:00
parent 85b4ad54ab
commit 96f231a183
9 changed files with 363 additions and 3 deletions

View File

@ -44,10 +44,15 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#ifdef _DEBUG #ifdef _DEBUG
#ifndef NDEBUG
#ifndef SOL_CHECK_ARGUMENTS #ifndef SOL_CHECK_ARGUMENTS
// Do not define by default: let user turn it on // Do not define by default: let user turn it on
//#define SOL_CHECK_ARGUMENTS //#define SOL_CHECK_ARGUMENTS
#endif // Check Arguments #endif // Check Arguments
#ifndef SOL_SAFE_USERTYPE
#define SOL_SAFE_USERTYPE
#endif // Safe Usertypes
#endif // NDEBUG
#endif // Debug #endif // Debug
#ifndef _CPPUNWIND #ifndef _CPPUNWIND
@ -69,7 +74,11 @@
#ifndef SOL_CHECK_ARGUMENTS #ifndef SOL_CHECK_ARGUMENTS
// Do not define by default: let user choose // Do not define by default: let user choose
//#define SOL_CHECK_ARGUMENTS //#define SOL_CHECK_ARGUMENTS
// But do check userdata by default:
#endif // Check Arguments #endif // Check Arguments
#ifndef SOL_SAFE_USERTYPE
#define SOL_SAFE_USERTYPE
#endif // Safe Usertypes
#endif // g++ optimizer flag #endif // g++ optimizer flag
#endif // Not Debug #endif // Not Debug
@ -87,4 +96,10 @@
#endif // vc++ || clang++/g++ #endif // vc++ || clang++/g++
#ifndef SOL_SAFE_USERTYPE
#ifdef SOL_CHECK_ARGUMENTS
#define SOL_SAFE_USERTYPE
#endif // Turn on Safety for all
#endif // Safe Usertypes
#endif // SOL_VERSION_HPP #endif // SOL_VERSION_HPP

View File

@ -119,7 +119,12 @@ struct usertype_overloaded_function : base_function {
template <typename Fx, std::size_t I, typename... R, typename... Args, meta::DisableIf<meta::Bool<Fx::is_free>> = 0> template <typename Fx, std::size_t I, typename... R, typename... Args, meta::DisableIf<meta::Bool<Fx::is_free>> = 0>
int call(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) { int call(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
auto& func = std::get<I>(overloads); auto& func = std::get<I>(overloads);
func.item = detail::ptr(stack::get<T>(L, 1)); func.item = stack::get<meta::Unwrapped<T>*>(L, 1);
#ifdef SOL_SAFE_USERTYPE
if (func.item == nullptr) {
return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions)");
}
#endif // Safety
return stack::call_into_lua<0, false>(r, a, L, start, func); return stack::call_into_lua<0, false>(r, a, L, start, func);
} }

View File

@ -60,7 +60,12 @@ struct usertype_function : public usertype_function_core<Tp, Function> {
usertype_function(Args&&... args): base_t(std::forward<Args>(args)...) {} usertype_function(Args&&... args): base_t(std::forward<Args>(args)...) {}
int prelude(lua_State* L) { int prelude(lua_State* L) {
this->fx.item = detail::ptr(stack::get<T>(L, 1)); this->fx.item = stack::get<meta::Unwrapped<T>*>(L, 1);
#ifdef SOL_SAFE_USERTYPE
if (this->fx.item == nullptr) {
return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions)");
}
#endif // Safety
return static_cast<base_t&>(*this)(meta::tuple_types<return_type>(), args_type(), index_value<2>(), L); return static_cast<base_t&>(*this)(meta::tuple_types<return_type>(), args_type(), index_value<2>(), L);
} }
@ -122,6 +127,11 @@ struct usertype_variable_function : public usertype_function_core<Tp, Function>
int prelude(lua_State* L) { int prelude(lua_State* L) {
int argcount = lua_gettop(L); int argcount = lua_gettop(L);
this->fx.item = stack::get<T*>(L, 1); this->fx.item = stack::get<T*>(L, 1);
#ifdef SOL_SAFE_USERTYPE
if (this->fx.item == nullptr) {
return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions)");
}
#endif // Safety
switch(argcount) { switch(argcount) {
case 2: case 2:
return get_variable(can_read(), L); return get_variable(can_read(), L);

View File

@ -51,7 +51,7 @@ struct check_getter<optional<T>> {
}; };
template <typename T> template <typename T>
struct check_getter<T, std::enable_if_t<std::is_integral<T>::value && !std::is_same<T, bool>::value>> { struct check_getter<T, std::enable_if_t<std::is_integral<T>::value && !lua_type_of<T>::value == type::number>> {
template <typename Handler> template <typename Handler>
static optional<T> get( lua_State* L, int index, Handler&& handler) { static optional<T> get( lua_State* L, int index, Handler&& handler) {
int isnum = 0; int isnum = 0;

View File

@ -30,6 +30,7 @@
#include <memory> #include <memory>
#include <functional> #include <functional>
#include <utility> #include <utility>
#include <codecvt>
namespace sol { namespace sol {
namespace stack { namespace stack {
@ -113,6 +114,88 @@ struct getter<const char*> {
} }
}; };
template<>
struct getter<char> {
static char get(lua_State* L, int index = -1) {
size_t len;
auto str = lua_tolstring(L, index, &len);
return len > 0 ? str[0] : '\0';
}
};
template<>
struct getter<std::wstring> {
static std::wstring get(lua_State* L, int index = -1) {
size_t len;
auto str = lua_tolstring(L, index, &len);
typedef std::codecvt_utf8<wchar_t> convert;
std::wstring_convert<convert, wchar_t> conv;
return conv.from_bytes(str, str + len);
}
};
template<>
struct getter<std::u16string> {
static std::u16string get(lua_State* L, int index = -1) {
size_t len;
auto str = lua_tolstring(L, index, &len);
#ifdef _MSC_VER // https://connect.microsoft.com/VisualStudio/feedback/details/1348277/link-error-when-using-std-codecvt-utf8-utf16-char16-t
typedef uint16_t T;
typedef std::codecvt_utf8<T> convert;
std::wstring_convert<convert, T> conv;
std::basic_string<T> shitty = conv.from_bytes(str, str + len);
return std::u16string(shitty.cbegin(), shitty.cend()); // fuck you VC++
#else
typedef std::codecvt_utf8<char16_t> convert;
std::wstring_convert<convert, char16_t> conv;
return conv.from_bytes(str, str + len);
#endif // VC++
}
};
template<>
struct getter<std::u32string> {
static std::u32string get(lua_State* L, int index = -1) {
size_t len;
auto str = lua_tolstring(L, index, &len);
#ifdef _MSC_VER // https://connect.microsoft.com/VisualStudio/feedback/details/1348277/link-error-when-using-std-codecvt-utf8-utf16-char16-t
typedef int32_t T;
typedef std::codecvt_utf8<T> convert;
std::wstring_convert<convert, T> conv;
std::basic_string<T> shitty = conv.from_bytes(str, str + len);
return std::u32string(shitty.cbegin(), shitty.cend()); // fuck you VC++
#else
typedef std::codecvt_utf8<char32_t> convert;
std::wstring_convert<convert, char32_t> conv;
return conv.from_bytes(str, str + len);
#endif // VC++
}
};
template<>
struct getter<wchar_t> {
static wchar_t get(lua_State* L, int index = -1) {
auto str = getter<std::wstring>{}.get(L, index);
return str.size() > 0 ? str[0] : '\0';
}
};
template<>
struct getter<char16_t> {
static char get(lua_State* L, int index = -1) {
auto str = getter<std::u16string>{}.get(L, index);
return str.size() > 0 ? str[0] : '\0';
}
};
template<>
struct getter<char32_t> {
static char32_t get(lua_State* L, int index = -1) {
auto str = getter<std::u32string>{}.get(L, index);
return str.size() > 0 ? str[0] : '\0';
}
};
template<> template<>
struct getter<nil_t> { struct getter<nil_t> {
static nil_t get(lua_State*, int = -1) { static nil_t get(lua_State*, int = -1) {

View File

@ -26,6 +26,7 @@
#include "raii.hpp" #include "raii.hpp"
#include "optional.hpp" #include "optional.hpp"
#include <memory> #include <memory>
#include <codecvt>
namespace sol { namespace sol {
namespace stack { namespace stack {
@ -252,6 +253,55 @@ struct pusher<const char*> {
} }
}; };
template<>
struct pusher<const wchar_t*> {
static int push(lua_State* L, const wchar_t* wstr) {
return push(L, wstr, wstr + std::char_traits<wchar_t>::length(wstr));
}
static int push(lua_State* L, const wchar_t* wstrb, const wchar_t* wstre) {
typedef std::codecvt_utf8<wchar_t> convert;
std::wstring_convert<convert, wchar_t> conv;
std::string str = conv.to_bytes( wstrb, wstre );
return stack::push(L, str);
}
};
template<>
struct pusher<const char16_t*> {
static int push(lua_State* L, const char16_t* u16str) {
return push(L, u16str, u16str + std::char_traits<char16_t>::length(u16str));
}
static int push(lua_State* L, const char16_t* u16strb, const char16_t* u16stre) {
#ifdef _MSC_VER // https://connect.microsoft.com/VisualStudio/feedback/details/1348277/link-error-when-using-std-codecvt-utf8-utf16-char16-t
typedef uint16_t T;
#else
typedef char16_t T;
#endif // VC++
typedef std::codecvt_utf8<T> convert;
std::wstring_convert<convert, T> conv;
std::string str = conv.to_bytes( reinterpret_cast<const T*>(u16strb), reinterpret_cast<const T*>(u16stre) );
return stack::push(L, str);
}
};
template<>
struct pusher<const char32_t*> {
static int push(lua_State* L, const char32_t* u32str) {
return push(L, u32str, u32str + std::char_traits<char32_t>::length(u32str));
}
static int push(lua_State* L, const char32_t* u32strb, const char32_t* u32stre) {
#ifdef _MSC_VER // https://connect.microsoft.com/VisualStudio/feedback/details/1348277/link-error-when-using-std-codecvt-utf8-utf16-char16-t
typedef uint32_t T;
#else
typedef char32_t T;
#endif // VC++
typedef std::codecvt_utf8<T> convert;
std::wstring_convert<convert, T> conv;
std::string str = conv.to_bytes( reinterpret_cast<const T*>(u32strb), reinterpret_cast<const T*>(u32stre) );
return stack::push(L, str);
}
};
template<size_t N> template<size_t N>
struct pusher<char[N]> { struct pusher<char[N]> {
static int push(lua_State* L, const char (&str)[N]) { static int push(lua_State* L, const char (&str)[N]) {
@ -260,6 +310,59 @@ struct pusher<char[N]> {
} }
}; };
template<size_t N>
struct pusher<wchar_t[N]> {
static int push(lua_State* L, const wchar_t (&str)[N]) {
return stack::push<const wchar_t*>(L, str, str + N - 1);
}
};
template<size_t N>
struct pusher<char16_t[N]> {
static int push(lua_State* L, const char16_t (&str)[N]) {
return stack::push<const char16_t*>(L, str, str + N - 1);
}
};
template<size_t N>
struct pusher<char32_t[N]> {
static int push(lua_State* L, const char32_t (&str)[N]) {
return stack::push<const char32_t*>(L, str, str + N - 1);
}
};
template <>
struct pusher<char> {
static int push(lua_State* L, char c) {
const char str[2] = { c, '\0'};
return stack::push(L, str);
}
};
template <>
struct pusher<wchar_t> {
static int push(lua_State* L, wchar_t c) {
const wchar_t str[2] = { c, '\0'};
return stack::push(L, str);
}
};
template <>
struct pusher<char16_t> {
static int push(lua_State* L, char16_t c) {
const char16_t str[2] = { c, '\0'};
return stack::push(L, str);
}
};
template <>
struct pusher<char32_t> {
static int push(lua_State* L, char32_t c) {
const char32_t str[2] = { c, '\0'};
return stack::push(L, str);
}
};
template<> template<>
struct pusher<std::string> { struct pusher<std::string> {
static int push(lua_State* L, const std::string& str) { static int push(lua_State* L, const std::string& str) {
@ -268,6 +371,27 @@ struct pusher<std::string> {
} }
}; };
template<>
struct pusher<std::wstring> {
static int push(lua_State* L, const std::wstring& wstr) {
return stack::push(L, wstr.data(), wstr.data() + wstr.size());
}
};
template<>
struct pusher<std::u16string> {
static int push(lua_State* L, const std::u16string& u16str) {
return stack::push(L, u16str.data(), u16str.data() + u16str.size());
}
};
template<>
struct pusher<std::u32string> {
static int push(lua_State* L, const std::u32string& u32str) {
return stack::push(L, u32str.data(), u32str.data() + u32str.size());
}
};
template<typename... Args> template<typename... Args>
struct pusher<std::tuple<Args...>> { struct pusher<std::tuple<Args...>> {
template <std::size_t... I, typename T> template <std::size_t... I, typename T>

View File

@ -379,12 +379,48 @@ struct lua_type_of : std::integral_constant<type, type::userdata> {};
template <> template <>
struct lua_type_of<std::string> : std::integral_constant<type, type::string> {}; struct lua_type_of<std::string> : std::integral_constant<type, type::string> {};
template <>
struct lua_type_of<std::wstring> : std::integral_constant<type, type::string> {};
template <>
struct lua_type_of<std::u16string> : std::integral_constant<type, type::string> {};
template <>
struct lua_type_of<std::u32string> : std::integral_constant<type, type::string> {};
template <std::size_t N> template <std::size_t N>
struct lua_type_of<char[N]> : std::integral_constant<type, type::string> {}; struct lua_type_of<char[N]> : std::integral_constant<type, type::string> {};
template <std::size_t N>
struct lua_type_of<wchar_t[N]> : std::integral_constant<type, type::string> {};
template <std::size_t N>
struct lua_type_of<char16_t[N]> : std::integral_constant<type, type::string> {};
template <std::size_t N>
struct lua_type_of<char32_t[N]> : std::integral_constant<type, type::string> {};
template <>
struct lua_type_of<char> : std::integral_constant<type, type::string> {};
template <>
struct lua_type_of<wchar_t> : std::integral_constant<type, type::string> {};
template <>
struct lua_type_of<char16_t> : std::integral_constant<type, type::string> {};
template <>
struct lua_type_of<char32_t> : std::integral_constant<type, type::string> {};
template <> template <>
struct lua_type_of<const char*> : std::integral_constant<type, type::string> {}; struct lua_type_of<const char*> : std::integral_constant<type, type::string> {};
template <>
struct lua_type_of<const char16_t*> : std::integral_constant<type, type::string> {};
template <>
struct lua_type_of<const char32_t*> : std::integral_constant<type, type::string> {};
template <> template <>
struct lua_type_of<bool> : std::integral_constant<type, type::boolean> {}; struct lua_type_of<bool> : std::integral_constant<type, type::boolean> {};

71
test_strings.cpp Normal file
View File

@ -0,0 +1,71 @@
#define SOL_CHECK_ARGUMENTS
#include <catch.hpp>
#include <sol.hpp>
// There isn't a single library roundtripping with codecvt works on. We'll do the nitty-gritty of it later...
#if 0
TEST_CASE("stack/strings", "test that strings can be roundtripped") {
sol::state lua;
static const char utf8str[] = "\xF0\x9F\x8D\x8C\x20\xE6\x99\xA5\x20\x46\x6F\x6F\x20\xC2\xA9\x20\x62\x61\x72\x20\xF0\x9D\x8C\x86\x20\x62\x61\x7A\x20\xE2\x98\x83\x20\x71\x75\x78";
static const char16_t utf16str[] = { 0xD83C, 0xDF4C, 0x20, 0x6665, 0x20, 0x46, 0x6F, 0x6F, 0x20, 0xA9, 0x20, 0x62, 0x61, 0x72, 0x20, 0xD834, 0xDF06, 0x20, 0x62, 0x61, 0x7A, 0x20, 0x2603, 0x20, 0x71, 0x75, 0x78, 0x00 };
static const char32_t utf32str[] = { 0x1F34C, 0x0020, 0x6665, 0x0020, 0x0046, 0x006F, 0x006F, 0x0020, 0x00A9, 0x0020, 0x0062, 0x0061, 0x0072, 0x0020, 0x1D306, 0x0020, 0x0062, 0x0061, 0x007A, 0x0020, 0x2603, 0x0020, 0x0071, 0x0075, 0x0078, 0x00 };
static const wchar_t widestr[] = L"Fuck these shitty compilers";
lua["utf8"] = utf8str;
lua["utf16"] = utf16str;
lua["utf32"] = utf32str;
lua["wide"] = widestr;
std::string utf8_to_utf8 = lua["utf8"];
std::string utf16_to_utf8 = lua["utf16"];
std::string utf32_to_utf8 = lua["utf32"];
std::string wide_to_utf8 = lua["wide"];
std::wstring utf8_to_wide = lua["utf8"];
std::wstring utf16_to_wide = lua["utf16"];
std::wstring utf32_to_wide = lua["utf32"];
std::wstring wide_to_wide = lua["wide"];
std::u16string utf8_to_utf16 = lua["utf8"];
std::u16string utf16_to_utf16 = lua["utf16"];
std::u16string utf32_to_utf16 = lua["utf32"];
std::u16string wide_to_utf16 = lua["wide"];
std::u32string utf8_to_utf32 = lua["utf8"];
std::u32string utf16_to_utf32 = lua["utf16"];
std::u32string utf32_to_utf32 = lua["utf32"];
std::u32string wide_to_utf32 = lua["wide"];
REQUIRE(utf8_to_utf8 == utf8str);
REQUIRE(utf16_to_utf8 == utf8str);
REQUIRE(utf32_to_utf8 == utf8str);
REQUIRE(wide_to_utf8 == utf8str);
REQUIRE(utf8_to_utf16 == utf16str);
REQUIRE(utf16_to_utf16 == utf16str);
REQUIRE(utf32_to_utf16 == utf16str);
REQUIRE(wide_to_utf16 == utf16str);
REQUIRE(utf8_to_utf32 == utf32str);
REQUIRE(utf16_to_utf32 == utf32str);
REQUIRE(utf32_to_utf32 == utf32str);
REQUIRE(wide_to_utf32 == utf32str);
REQUIRE(utf8_to_wide == widestr);
REQUIRE(utf16_to_wide == widestr);
REQUIRE(utf32_to_wide == widestr);
REQUIRE(wide_to_wide == widestr);
char32_t utf8_to_char32 = lua["utf8"];
char32_t utf16_to_char32 = lua["utf16"];
char32_t utf32_to_char32 = lua["utf32"];
char32_t wide_to_char32 = lua["wide"];
REQUIRE(utf8_to_char32 == utf32str[0]);
REQUIRE(utf16_to_char32 == utf32str[0]);
REQUIRE(utf32_to_char32 == utf32str[0]);
REQUIRE(wide_to_char32 == utf32str[0]);
}
#endif // Shit C++

View File

@ -1186,3 +1186,19 @@ TEST_CASE("object/conversions", "make sure all basic reference types can be made
REQUIRE(os.get_type() == sol::type::string); REQUIRE(os.get_type() == sol::type::string);
REQUIRE(omn.get_type() == sol::type::nil); REQUIRE(omn.get_type() == sol::type::nil);
} }
TEST_CASE("usertype/safety", "crash with an exception -- not a segfault -- on bad userdata calls") {
class Test {
public:
void sayHello() { std::cout << "Hey\n"; }
};
sol::state lua;
lua.new_usertype<Test>("Test", "sayHello", &Test::sayHello);
static const std::string code = R"(
local t = Test.new()
t:sayHello() --Works fine
t.sayHello() --Uh oh.
)";
REQUIRE_THROWS(lua.script(code));
}