diff --git a/.travis.yml b/.travis.yml index 0d25d078..dd28fa7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -74,6 +74,29 @@ matrix: - ninja-build - libluajit-5.1-dev + # gcc-5:i386 + - os: linux + env: COMPILER=g++-5 LUA_VERSION=luajit51:i386 + compiler: gcc + install: + - sudo dpkg --add-architecture i386 + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-5 + - g++-5 + - ninja-build + - libluajit-5.1-dev + - libluajit-5.1-dev:i386 + - libc6:i386 + - libncurses5:i386 + - libstdc++6:i386 + - gcc-5-multilib + - g++-5-multilib + - linux-libc-dev:i386 + # clang - os: linux env: diff --git a/bootstrap.py b/bootstrap.py index 5f29ebdd..2ff7a8cf 100755 --- a/bootstrap.py +++ b/bootstrap.py @@ -91,6 +91,12 @@ if 'linux' in sys.platform: # Using normal lua lua_lib = lua_version[:-1] + '.' + lua_version[-1] lua_incl = lua_lib + elif re.match(r'luajit5[1-3]:i386', lua_version): + # luajit:i386 + lua_incl = 'luajit-2.0' + lua_lib = lua_version[:-7] + '-' + lua_version[-7] + '.' + lua_version[-6] + cxxflags.append('-m32') + include.extend(['/usr/include/luajit-2.0/', '/usr/local/include/luajit-2.0/']) elif re.match(r'luajit5[1-3]', lua_version): # luajit lua_incl = 'luajit-2.0' # I don't get this.. diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index 596b0f76..0481063a 100644 --- a/single/sol/sol.hpp +++ b/single/sol/sol.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2017-08-11 14:35:51.568053 UTC -// This header was generated with sol v2.18.0 (revision 4f7f1af) +// Generated 2017-08-11 12:59:23.551177 UTC +// This header was generated with sol v2.18.0 (revision 5e109c2) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -5798,6 +5798,7 @@ namespace sol { // end of sol/inheritance.hpp +#include #ifdef SOL_CXX17_FEATURES #endif // C++17 @@ -5854,7 +5855,14 @@ namespace sol { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); - bool success = lua_isinteger(L, index) == 1; +#if SOL_LUA_VERSION >= 503 + if (lua_isinteger(L, index) != 0) { + return true; + } +#endif + int isnum = 0; + const lua_Number v = lua_tonumberx(L, index, &isnum); + const bool success = isnum != 0 && static_cast(std::llround(v)) == v; if (!success) { // expected type, actual type handler(L, index, type::number, type_of(L, index)); @@ -6347,18 +6355,15 @@ namespace sol { }; template - struct getter, std::is_signed>::value>> { + struct getter::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)); +#if SOL_LUA_VERSION >= 503 + if (lua_isinteger(L, index) != 0) { + return static_cast(lua_tointeger(L, index)); + } +#endif + return static_cast(std::llround(lua_tonumber(L, index))); } }; @@ -7107,16 +7112,25 @@ namespace sol { struct check_getter::value && lua_type_of::value == type::number>> { template static optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - int isnum = 0; - lua_Integer value = lua_tointegerx(L, index, &isnum); - if (isnum == 0) { - type t = type_of(L, index); - tracking.use(static_cast(t != type::none)); - handler(L, index, type::number, t); - return nullopt; +#if SOL_LUA_VERSION >= 503 + if (lua_isinteger(L, index) != 0) { + tracking.use(1); + return static_cast(lua_tointeger(L, index)); } - tracking.use(1); - return static_cast(value); +#endif + int isnum = 0; + const lua_Number value = lua_tonumberx(L, index, &isnum); + if (isnum != 0) { + const auto integer_value = std::llround(value); + if (static_cast(integer_value) == value) { + tracking.use(1); + return static_cast(integer_value); + } + } + const type t = type_of(L, index); + tracking.use(static_cast(t != type::none)); + handler(L, index, type::number, t); + return nullopt; } }; @@ -7317,6 +7331,8 @@ namespace sol { // end of sol/raii.hpp +#include +#include #ifdef SOL_CODECVT_SUPPORT #endif #ifdef SOL_CXX17_FEATURES @@ -7477,17 +7493,34 @@ namespace sol { }; template - struct pusher, std::is_signed>::value>> { + struct pusher::value>> { static int push(lua_State* L, const T& value) { - lua_pushinteger(L, static_cast(value)); - return 1; - } - }; - - template - struct pusher, std::is_unsigned>::value>> { - static int push(lua_State* L, const T& value) { - lua_pushinteger(L, static_cast(value)); +#if SOL_LUA_VERSION >= 503 + static auto integer_value_fits = [](T const& value) { + if (sizeof(T) < sizeof(lua_Integer) || std::is_signed::value && sizeof(T) == sizeof(lua_Integer)) { + return true; + } + auto u_min = static_cast(std::numeric_limits::min()); + auto u_max = static_cast(std::numeric_limits::max()); + auto t_min = static_cast(std::numeric_limits::min()); + auto t_max = static_cast(std::numeric_limits::max()); + return (u_min <= t_min || value >= static_cast(u_min)) && (u_max >= t_max || value <= static_cast(u_max)); + }; + if (integer_value_fits(value)) { + lua_pushinteger(L, static_cast(value)); + return 1; + } +#endif +#if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION) + if (static_cast(std::llround(static_cast(value))) != value) { +#ifndef SOL_NO_EXCEPTIONS + throw sol::error("The integer will be misrepresented in lua."); +#else + assert(false && "The integer will be misrepresented in lua."); +#endif + } +#endif + lua_pushnumber(L, static_cast(value)); return 1; } }; @@ -11854,8 +11887,6 @@ namespace sol { // end of sol/stack_proxy.hpp -#include - namespace sol { template struct va_iterator : std::iterator, std::ptrdiff_t, std::conditional_t, std::conditional_t> { @@ -13716,7 +13747,6 @@ namespace sol { #include #include -#include namespace sol { namespace usertype_detail { diff --git a/sol/stack_check.hpp b/sol/stack_check.hpp index 532e085c..676eb2e2 100644 --- a/sol/stack_check.hpp +++ b/sol/stack_check.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef SOL_CXX17_FEATURES #include #endif // C++17 @@ -85,7 +86,14 @@ namespace sol { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); - bool success = lua_isinteger(L, index) == 1; +#if SOL_LUA_VERSION >= 503 + if (lua_isinteger(L, index) != 0) { + return true; + } +#endif + int isnum = 0; + const lua_Number v = lua_tonumberx(L, index, &isnum); + const bool success = isnum != 0 && static_cast(std::llround(v)) == v; if (!success) { // expected type, actual type handler(L, index, type::number, type_of(L, index)); diff --git a/sol/stack_check_get.hpp b/sol/stack_check_get.hpp index a3f01923..d4e61e08 100644 --- a/sol/stack_check_get.hpp +++ b/sol/stack_check_get.hpp @@ -27,6 +27,7 @@ #include "stack_check.hpp" #include "optional.hpp" #include +#include namespace sol { namespace stack { @@ -56,16 +57,25 @@ namespace sol { struct check_getter::value && lua_type_of::value == type::number>> { template static optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - int isnum = 0; - lua_Integer value = lua_tointegerx(L, index, &isnum); - if (isnum == 0) { - type t = type_of(L, index); - tracking.use(static_cast(t != type::none)); - handler(L, index, type::number, t); - return nullopt; +#if SOL_LUA_VERSION >= 503 + if (lua_isinteger(L, index) != 0) { + tracking.use(1); + return static_cast(lua_tointeger(L, index)); } - tracking.use(1); - return static_cast(value); +#endif + int isnum = 0; + const lua_Number value = lua_tonumberx(L, index, &isnum); + if (isnum != 0) { + const auto integer_value = std::llround(value); + if (static_cast(integer_value) == value) { + tracking.use(1); + return static_cast(integer_value); + } + } + const type t = type_of(L, index); + tracking.use(static_cast(t != type::none)); + handler(L, index, type::number, t); + return nullopt; } }; diff --git a/sol/stack_get.hpp b/sol/stack_get.hpp index 0f29e06b..682afd5e 100644 --- a/sol/stack_get.hpp +++ b/sol/stack_get.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef SOL_CODECVT_SUPPORT #include #include @@ -59,18 +60,15 @@ namespace sol { }; template - struct getter, std::is_signed>::value>> { + struct getter::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)); +#if SOL_LUA_VERSION >= 503 + if (lua_isinteger(L, index) != 0) { + return static_cast(lua_tointeger(L, index)); + } +#endif + return static_cast(std::llround(lua_tonumber(L, index))); } }; diff --git a/sol/stack_push.hpp b/sol/stack_push.hpp index 6169dcaf..bf216afa 100644 --- a/sol/stack_push.hpp +++ b/sol/stack_push.hpp @@ -28,6 +28,8 @@ #include "usertype_traits.hpp" #include #include +#include +#include #ifdef SOL_CODECVT_SUPPORT #include #include @@ -192,17 +194,34 @@ namespace sol { }; template - struct pusher, std::is_signed>::value>> { + struct pusher::value>> { static int push(lua_State* L, const T& value) { - lua_pushinteger(L, static_cast(value)); - return 1; - } - }; - - template - struct pusher, std::is_unsigned>::value>> { - static int push(lua_State* L, const T& value) { - lua_pushinteger(L, static_cast(value)); +#if SOL_LUA_VERSION >= 503 + static auto integer_value_fits = [](T const& value) { + if (sizeof(T) < sizeof(lua_Integer) || std::is_signed::value && sizeof(T) == sizeof(lua_Integer)) { + return true; + } + auto u_min = static_cast(std::numeric_limits::min()); + auto u_max = static_cast(std::numeric_limits::max()); + auto t_min = static_cast(std::numeric_limits::min()); + auto t_max = static_cast(std::numeric_limits::max()); + return (u_min <= t_min || value >= static_cast(u_min)) && (u_max >= t_max || value <= static_cast(u_max)); + }; + if (integer_value_fits(value)) { + lua_pushinteger(L, static_cast(value)); + return 1; + } +#endif +#if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION) + if (static_cast(std::llround(static_cast(value))) != value) { +#ifndef SOL_NO_EXCEPTIONS + throw sol::error("The integer will be misrepresented in lua."); +#else + assert(false && "The integer will be misrepresented in lua."); +#endif + } +#endif + lua_pushnumber(L, static_cast(value)); return 1; } }; diff --git a/test_large_integer.cpp b/test_large_integer.cpp new file mode 100644 index 00000000..1605e330 --- /dev/null +++ b/test_large_integer.cpp @@ -0,0 +1,117 @@ +#define SOL_CHECK_ARGUMENTS +#include + +#include +#include +#include + +TEST_CASE("large_integer/bool", "pass bool integral value to and from lua") { + sol::state lua; + lua.open_libraries(); + lua.set_function("f", [&](bool num) { + REQUIRE(num == true); + return num; + }); + lua.script("x = f(true)"); + lua.script("assert(x == true)"); + sol::object x = lua["x"]; + REQUIRE(x.is()); + REQUIRE(x.as() == true); + REQUIRE_FALSE(x.is()); + REQUIRE_THROWS([&lua]() { + lua.script("f(1)"); + }()); +} + +TEST_CASE("large_integers/unsigned32", "pass large unsigned 32bit values to and from lua") { + using T = std::uint32_t; + sol::state lua; + lua.open_libraries(); + lua.set_function("f", [&](T num) -> T { + REQUIRE(num == 0xFFFFFFFF); + return num; + }); + lua.script("x = f(0xFFFFFFFF)"); + lua.script("assert(x == 0xFFFFFFFF)"); + sol::object x = lua["x"]; + REQUIRE(x.is()); + REQUIRE(x.as() == 0xFFFFFFFF); +} + +TEST_CASE("large_integer/unsigned53", "pass large unsigned 53bit value to and from lua") { + using T = std::uint64_t; + sol::state lua; + lua.open_libraries(); + lua.set_function("f", [&](T num) -> T { + REQUIRE(num == 0x1FFFFFFFFFFFFFull); + return num; + }); + lua.script("x = f(0x1FFFFFFFFFFFFF)"); + lua.script("assert(x == 0x1FFFFFFFFFFFFF)"); + sol::object x = lua["x"]; + REQUIRE(x.is()); + REQUIRE(x.as() == 0x1FFFFFFFFFFFFFull); +} + +TEST_CASE("large_integer/unsigned64", "pass too large unsigned 64bit value to lua") { + using T = std::int64_t; + sol::state lua; + lua.open_libraries(); + lua.set_function("f", [&](T num) -> T { + return num; + }); + REQUIRE_THROWS([&lua]() { + lua["f"](0xFFFFFFFFFFFFFFFFull); + }()); +} + +TEST_CASE("large_integer/double", "pass negative and large positive values as signed and unsigned from and to lua") { + sol::state lua; + lua.open_libraries(); + lua.set_function("s32", [&](std::int32_t num) { + return num; + }); + lua.set_function("s64", [&](std::int64_t num) { + return num; + }); + lua.set_function("u32", [&](std::uint32_t num) { + return num; + }); + lua.set_function("u64", [&](std::uint64_t num) { + return num; + }); + //signed 32bit + REQUIRE_NOTHROW([&lua]() { + lua.script("x = s32(-1)"); + lua.script("assert(x == -1)"); + lua.script("x = s32(0xFFFFFFFF)"); + lua.script("assert(x == -1)"); + sol::object x = lua["x"]; + REQUIRE(x.is()); + REQUIRE(x.as() == -1); + REQUIRE(x.is()); + REQUIRE(x.as() == 0xFFFFFFFF); + }()); + //unsigned 32bit + REQUIRE_NOTHROW([&lua]() { + lua.script("x = u32(0xFFFFFFFF)"); + lua.script("assert(x == 0xFFFFFFFF)"); + lua.script("x = u32(-1)"); + lua.script("assert(x == 0xFFFFFFFF)"); + sol::object x = lua["x"]; + REQUIRE(x.is()); + REQUIRE(x.as() == -1); + REQUIRE(x.is()); + REQUIRE(x.as() == 0xFFFFFFFF); + }()); + //signed 64bit + REQUIRE_NOTHROW([&lua]() { + lua.script("x = s64(-1)"); + lua.script("assert(x == -1)"); + sol::object x = lua["x"]; + REQUIRE(x.is()); + REQUIRE(x.as() == -1); + REQUIRE(x.is()); + REQUIRE(x.as() == 0xFFFFFFFFFFFFFFFFull); + }()); +}