From e8467334f67e394e182b6459565b58824b15ea32 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Fri, 22 Mar 2019 16:28:17 -0400 Subject: [PATCH] Completley overhaul tests Add unregister funcationality Make sure clearing is stack-size-safe. --- .gitignore | 3 + .travis.yml | 165 ++++--- Dockerfile | 14 +- appveyor.yml | 72 ++- examples/CMakeLists.txt | 12 +- examples/require_dll_example/CMakeLists.txt | 26 +- examples/source/docs/inheritance.cpp | 3 +- include/sol/bytecode.hpp | 24 +- include/sol/call.hpp | 6 +- include/sol/ebco.hpp | 28 +- include/sol/error_handler.hpp | 2 +- include/sol/forward_detail.hpp | 4 + include/sol/lua_value.hpp | 49 +- include/sol/metatable.hpp | 38 +- include/sol/stack_core.hpp | 52 ++- include/sol/stack_field.hpp | 4 +- include/sol/stack_get_unqualified.hpp | 48 +- include/sol/stack_push.hpp | 4 +- include/sol/table_core.hpp | 6 + include/sol/traits.hpp | 3 +- include/sol/unicode.hpp | 4 +- include/sol/usertype.hpp | 23 +- include/sol/usertype_core.hpp | 99 ++-- include/sol/usertype_storage.hpp | 66 ++- scripts/build.linux.sh | 39 +- scripts/preparation.linux.sh | 62 ++- scripts/push.linux.sh | 28 +- scripts/run.linux.sh | 94 ++-- scripts/run.osx.sh | 4 +- single/include/sol/forward.hpp | 4 +- single/include/sol/sol.hpp | 439 ++++++++++++------ tests/compile_tests/CMakeLists.txt | 14 +- tests/runtime_tests/CMakeLists.txt | 16 +- tests/runtime_tests/source/basic.cpp | 10 +- tests/runtime_tests/source/common_classes.hpp | 2 + tests/runtime_tests/source/containers.cpp | 1 + tests/runtime_tests/source/coroutines.cpp | 2 +- tests/runtime_tests/source/functions.cpp | 3 + tests/runtime_tests/source/lua_value.cpp | 103 +++- tests/runtime_tests/source/tables.clear.cpp | 74 +++ .../source/usertypes.unregister.cpp | 147 ++++++ 41 files changed, 1271 insertions(+), 526 deletions(-) create mode 100644 tests/runtime_tests/source/tables.clear.cpp create mode 100644 tests/runtime_tests/source/usertypes.unregister.cpp diff --git a/.gitignore b/.gitignore index 02482c5f..981bbece 100644 --- a/.gitignore +++ b/.gitignore @@ -100,6 +100,9 @@ docs/build/ *.sublime-project +# MacOS Garbage +.DS_Store + # Windows Crap desktop.ini *.db diff --git a/.travis.yml b/.travis.yml index 514bf984..ef7f2168 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,8 +35,16 @@ before_install: script: - export SOL2_DIR=${TRAVIS_BUILD_DIR} - sudo docker image pull thephd/sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} -- sudo docker run --rm --interactive --tty --name "sol2.test" -v "${SOL2_DIR}:/root/sol2" --env "CI=${CI}" --env "PLATFORM=${PLATFORM}" --env "LUA_VERSION=${LUA_VERSION}" --env "GCC_VERSION=${GCC_VERSION}" --env "LLVM_VERSION=${LLVM_VERSION}" thephd/sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} -- sudo docker rmi $(sudo docker image ls -q) +- sudo docker run --rm --interactive --tty --name "sol2.test" -v "${SOL2_DIR}:/root/sol2" --env "SOL2_CI=${SOL2_CI}" --env "SOL2_PLATFORM=${SOL2_PLATFORM}" --env "SOL2_LUA_VERSION=${SOL2_LUA_VERSION}" --env "SOL2_TEST_SINGLE=${SOL2_TEST_SINGLE}" --env "SOL2_TEST_INTEROP=${SOL2_TEST_INTEROP}" --env "GCC_VERSION=${GCC_VERSION}" --env "LLVM_VERSION=${LLVM_VERSION}" thephd/sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} + +after_success: +- wget https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh +- chmod +x send.sh +- ./send.sh success ${DISORD_WEBHOOK_URL} +after_failure: +- wget https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh +- chmod +x send.sh +- ./send.sh failure ${DISORD_WEBHOOK_URL} matrix: fast_finish: true @@ -44,91 +52,108 @@ matrix: - os: osx include: - # GCC 4.9.x, 5.x, 6.x, 7.x + # LLVM 5.0.x -> 8.0.x - env: - - LUA_VERSION=5.3.5 - GCC_VERSION=7 - PLATFORM=i686 - CI=true - - - env: - - LUA_VERSION=luajit-2.0.5 - GCC_VERSION=7 - PLATFORM=i686 - CI=true - - - env: - - LUA_VERSION=luajit-2.1.0-beta3 - GCC_VERSION=7 - PLATFORM=i686 - CI=true - - - env: - - LUA_VERSION=5.3.5 - GCC_VERSION=7 - PLATFORM=x64 - CI=true - - # LLVM 3.9.x -> 5.0.x - - env: - - LUA_VERSION=5.3.5 - LLVM_VERSION=3.9.1 - PLATFORM=x64 - CI=true - - - env: - - LUA_VERSION=5.3.5 - LLVM_VERSION=4.0.1 - PLATFORM=x64 - CI=true - - - env: - - LUA_VERSION=5.3.5 + - SOL2_LUA_VERSION=5.3.5 LLVM_VERSION=5.0.2 - PLATFORM=x64 - CI=true + SOL2_PLATFORM=x64 + SOL2_CI=true - env: - - LUA_VERSION=5.3.5 + - SOL2_LUA_VERSION=5.3.5 LLVM_VERSION=6.0.1 - PLATFORM=x64 - CI=true + SOL2_PLATFORM=x64 + SOL2_CI=true - env: - - LUA_VERSION=5.3.5 - LLVM_VERSION=7.0.0 - PLATFORM=x64 - CI=true + - LLVM_VERSION=7.0.1 + SOL2_LUA_VERSION=5.3.5 + SOL2_PLATFORM=x64 + SOL2_CI=true - # Lua Versions 5.2.4, 5.1.5, and LuaJIT (as well as x86) - env: - - LUA_VERSION=5.2.4 + - LLVM_VERSION=8.0.0 + SOL2_LUA_VERSION=5.3.5 + SOL2_PLATFORM=x64 + SOL2_CI=true + + # GCC 7.x, 8.x + - env: + - SOL2_LUA_VERSION=5.3.5 + GCC_VERSION=8 + SOL2_PLATFORM=i686 + SOL2_CI=true + + - env: + - SOL2_LUA_VERSION=5.3.5 GCC_VERSION=7 - PLATFORM=x64 - CI=true + SOL2_PLATFORM=x64 + SOL2_CI=true + + - env: + - SOL2_LUA_VERSION=5.3.5 + GCC_VERSION=8 + SOL2_PLATFORM=x64 + SOL2_CI=true + + # Lua Versions 5.2.4, 5.1.5, and LuaJIT + - env: + - SOL2_LUA_VERSION=5.1.5 + GCC_VERSION=8 + SOL2_PLATFORM=x64 + SOL2_CI=true - env: - - LUA_VERSION=5.1.5 - GCC_VERSION=7 - PLATFORM=x64 - CI=true + - SOL2_LUA_VERSION=5.2.4 + GCC_VERSION=8 + SOL2_PLATFORM=x64 + SOL2_CI=true - env: - - LUA_VERSION=luajit-2.0.4 - GCC_VERSION=7 - PLATFORM=x64 - CI=true + - SOL2_LUA_VERSION=luajit-2.0.4 + GCC_VERSION=8 + SOL2_PLATFORM=x64 + SOL2_CI=true - env: - - LUA_VERSION=luajit-2.0.5 - GCC_VERSION=7 - PLATFORM=x64 - CI=true + - SOL2_LUA_VERSION=luajit-2.0.5 + GCC_VERSION=8 + SOL2_PLATFORM=x64 + SOL2_CI=true + + - env: + - SOL2_LUA_VERSION=luajit-2.0.5 + GCC_VERSION=8 + SOL2_PLATFORM=i686 + SOL2_CI=true + + - env: + - SOL2_LUA_VERSION=luajit-2.1.0-beta3 + GCC_VERSION=8 + SOL2_PLATFORM=i686 + SOL2_CI=true + + # Test Single, Interop, Etc. + - env: + - LLVM_VERSION=7.0.0 + SOL2_LUA_VERSION=5.3.5 + SOL2_PLATFORM=x64 + SOL2_CI=true + SOL2_TEST_SINGLE=true + SOL2_TEST_INTEROP=true + + - env: + - SOL2_LUA_VERSION=5.3.5 + GCC_VERSION=8 + SOL2_PLATFORM=x64 + SOL2_CI=true + SOL2_TEST_SINGLE=true + SOL2_TEST_INTEROP=true - os: osx osx_image: xcode9.0 env: - - LUA_VERSION=lua-5.3.5 + - SOL2_LUA_VERSION=lua-5.3.5 LLVM_VERSION=5.0.2 before_install: - chmod +x ./scripts/run.osx.sh @@ -140,7 +165,7 @@ matrix: - os: osx osx_image: xcode9.1 env: - - LUA_VERSION=lua-5.3.5 + - SOL2_LUA_VERSION=lua-5.3.5 LLVM_VERSION=5.0.2 before_install: - chmod +x ./scripts/run.osx.sh @@ -152,7 +177,7 @@ matrix: - os: osx osx_image: xcode9.2 env: - - LUA_VERSION=lua-5.3.5 + - SOL2_LUA_VERSION=lua-5.3.5 LLVM_VERSION=5.0.2 before_install: - chmod +x ./scripts/run.osx.sh @@ -164,7 +189,7 @@ matrix: notifications: webhooks: urls: - - https://webhooks.gitter.im/e/b864d553270a069d26c8 + - https://skyhook.glitch.me/api/webhooks/427786348108185611/y2nTmghqltv1SKX2DclEMEKyZtRcwKFlwfZpB_mL1A0nZTVS5MSfumqDKq30-gvWgeL5/travis on_success: change on_failure: always on_start: always diff --git a/Dockerfile b/Dockerfile index e304171c..1d9925d3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,8 +20,8 @@ # 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. -# Start from the ubuntu:xenial image -FROM ubuntu:xenial +# Start from the ubuntu:bionic image +FROM ubuntu:bionic # owner LABEL author="ThePhD " LABEL maintainer="ThePhD " @@ -48,13 +48,17 @@ VOLUME /root/sol2 # # This is ordered like this so making multiple of these # # containers is more or less identical up to this point # Command line arguments, with default values -ARG CI=true +ARG SOL2_PLATFORM=x64 +ARG SOL2_LUA_VERSION=x64 +ARG SOL2_LUA_VERSION=5.3.5 +ARG SOL2_TEST_SINGLE=false +ARG SOL2_TEST_INTEROP=false +ARG SOL2_CI=true ARG GCC_VERSION ARG LLVM_VERSION -ARG PLATFORM=x64 # Potential environment variables -ENV CI=${CI} PLATFORM=${PLATFORM} GCC_VERSION=${GCC_VERSION} LLVM_VERSION=${LLVM_VERSION} SOL2_DIR=/root/sol2 +ENV SOL2_LUA_VERSION=${SOL2_LUA_VERSION} SOL2_TEST_SINGLE=${SOL2_TEST_SINGLE} SOL2_TEST_INTEROP=${SOL2_TEST_INTEROP} SOL2_CI=${SOL2_CI} SOL2_PLATFORM=${SOL2_PLATFORM} GCC_VERSION=${GCC_VERSION} LLVM_VERSION=${LLVM_VERSION} SOL2_DIR=/root/sol2 RUN ["/usr/bin/env", "zsh", "-e", "/root/sol2-scripts/preparation.linux.sh"] diff --git a/appveyor.yml b/appveyor.yml index 218ee651..7923b2b3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -45,16 +45,14 @@ platform: environment: matrix: # apparently, I can't quite make LLVM work right now... - #- LUA_VERSION: 5.3.4 - # LLVM_VERSION: 4.0.0 - LUA_VERSION: 5.3.5 - MINGW_VERSION: 7.2.0 + MINGW_VERSION: 7.3.0 - LUA_VERSION: 5.3.5 - MINGW_VERSION: 6.3.0 + MINGW_VERSION: 8.1.0 - LUA_VERSION: luajit-2.0.5 - MINGW_VERSION: 6.3.0 + MINGW_VERSION: 8.1.0 - LUA_VERSION: luajit-2.1.0-beta3 - MINGW_VERSION: 6.3.0 + MINGW_VERSION: 8.1.0 - LUA_VERSION: 5.3.5 - LUA_VERSION: 5.2.4 - LUA_VERSION: 5.1.5 @@ -65,32 +63,22 @@ matrix: allow_failures: # 32-bit builds are temperamental with exceptions - platform: x86 - # Visual Studio 2015 builds are allowed to fail, since I have no intention of dealing with bad old builds - - image: Visual Studio 2015 - # LLVM is experimental as all get-out - - LLVM_VERSION: 4.0.0 exclude: # Necessary: MinGW doesn't exist on VS 2017 images - # Also does not have MinGW x64 for 5.3.0 - image: Visual Studio 2017 - MINGW_VERSION: 6.3.0 - # LLVM exists in all images, and we only want the VS 2017 x64 versions - - image: Visual Studio 2015 - LLVM_VERSION: 4.0.0 - - platform: x86 - LLVM_VERSION: 4.0.0 - # Get rid of x86 builds + MINGW_VERSION: 7.3.0 + - image: Visual Studio 2017 + MINGW_VERSION: 8.1.0 + # There are no recent i686 compilers on the VS2015/2017 images + - MINGW_VERSION: 7.3.0 + platform: x86 + - MINGW_VERSION: 8.1.0 + platform: x86 + # Get rid of x86 builds for non-latest (no reason to redo that work) - platform: x86 LUA_VERSION: 5.2.4 - platform: x86 LUA_VERSION: 5.1.5 - - platform: x86 - MINGW_VERSION: 7.2.0 - # Get rid of redundant Visual Studio 2015 builds - - image: Visual Studio 2015 - LUA_VERSION: 5.1.5 - - image: Visual Studio 2015 - LUA_VERSION: 5.2.4 init: # # Ninja @@ -109,10 +97,8 @@ init: - set python_path=C:\Python36 - set mingw_path= - set llvm_path= -- if "%MINGW_VERSION%"=="5.3.0" (set mingw_path=C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin) -- if "%MINGW_VERSION%"=="6.3.0" (if "%PLATFORM%"=="x64" (set mingw_path=C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin) else ( set mingw_path=C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin)) -- if "%MINGW_VERSION%"=="7.2.0" (if "%PLATFORM%"=="x64" (set mingw_path=C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin) else ( set mingw_path=C:\mingw-w64\i686-7.2.0-posix-seh-rt_v5-rev1\mingw32\bin)) -- if "%LLVM_VERSION%"=="4.0.0" (set llvm_path=C:\Program Files\LLVM\bin) +- if "%MINGW_VERSION%"=="7.3.0" (if "%PLATFORM%"=="x64" (set mingw_path=C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev1\mingw64\bin) else ( set mingw_path=C:\mingw-w64\i686-7.3.0-posix-seh-rt_v5-rev1\mingw32\bin)) +- if "%MINGW_VERSION%"=="8.1.0" (if "%PLATFORM%"=="x64" (set mingw_path=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v5-rev1\mingw64\bin) else ( set mingw_path=C:\mingw-w64\i686-8.1.0-posix-seh-rt_v5-rev1\mingw32\bin)) - if "%PLATFORM%"=="x64" (set python_path=C:\Python36-x64) - set PATH=%python_path%;%PATH% - set PATH=%mingw_path%;%PATH% @@ -124,50 +110,44 @@ init: - set arch= - set parallelism= - set logger= -- set build_type= - set build_compiler= - set lua_build_type=OFF - set vcvars_script="C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 - if "%PLATFORM%"=="x64" (set arch= Win64) - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (set CMAKE_GENERATOR=Visual Studio 15 2017%arch%&&set parallelism=/maxcpucount&&set logger=/verbosity:quiet /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"&&set vcvars_script="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat") - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" (set CMAKE_GENERATOR=Visual Studio 14 2015%arch%&&set parallelism=/maxcpucount&&set logger=/verbosity:quiet /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll") -- if "%MINGW_VERSION%"=="5.3.0" (set CMAKE_GENERATOR=Ninja&&set parallelism= &&set logger= &&set build_type=-DCMAKE_BUILD_TYPE=Release&&set build_compiler=-DCMAKE_CXX_COMPILER=g++.exe -DCMAKE_C_COMPILER=gcc.exe) -- if "%MINGW_VERSION%"=="6.3.0" (set CMAKE_GENERATOR=Ninja&&set parallelism= &&set logger= &&set build_type=-DCMAKE_BUILD_TYPE=Release&&set build_compiler=-DCMAKE_CXX_COMPILER=g++.exe -DCMAKE_C_COMPILER=gcc.exe) -- if "%MINGW_VERSION%"=="7.2.0" (set CMAKE_GENERATOR=Ninja&&set parallelism= &&set logger= &&set build_type=-DCMAKE_BUILD_TYPE=Release&&set build_compiler=-DCMAKE_CXX_COMPILER=g++.exe -DCMAKE_C_COMPILER=gcc.exe) -- if "%LLVM_VERSION%"=="4.0.0" (set CMAKE_GENERATOR=Ninja&&set parallelism= &&set logger= &&set build_type=-DCMAKE_BUILD_TYPE=Release&&set build_compiler=-DCMAKE_CXX_COMPILER=clang-cl.exe -DCMAKE_C_COMPILER=clang-cl.exe) +- if "%MINGW_VERSION%"=="7.3.0" (set CMAKE_GENERATOR=Ninja&&set parallelism= &&set logger= &&set build_compiler=-DCMAKE_CXX_COMPILER=g++.exe -DCMAKE_C_COMPILER=gcc.exe) +- if "%MINGW_VERSION%"=="8.1.0" (set CMAKE_GENERATOR=Ninja&&set parallelism= &&set logger= &&set build_compiler=-DCMAKE_CXX_COMPILER=g++.exe -DCMAKE_C_COMPILER=gcc.exe) # # Last printouts # print out generator information - echo Appveyor Image is %APPVEYOR_BUILD_WORKER_IMAGE% (vcvars script is %vcvars_script%) -- echo cmake generator is %CMAKE_GENERATOR% using build_type=%build_type% and build_compiler=%build_compiler% with special flags logger=%logger% parallelism=%parallelism% +- echo cmake generator is %CMAKE_GENERATOR% using build_compiler=%build_compiler% with special flags logger=%logger% parallelism=%parallelism% # print out useful tool information - ninja --version - cmake --version -- if DEFINED LLVM_VERSION (clang-cl.exe -v) -- if DEFINED MINGW_VERSION (g++.exe --version) -# We need to use CMAKE_BUILD_TYPE=Release since there are no "configuration" -# toolsets for Ninja or Makefiles as far as cmake is concerned, so -# the --config / -C switches on builds do nothing...! before_build: -- if DEFINED LLVM_VERSION (call %vcvars_script% && cd C:\projects\sol2) - md build-sol2 +- md buid-sol2\Debug +- md buid-sol2\Release - cd build-sol2 -- cmake .. -G "%CMAKE_GENERATOR%" %build_type% %build_compiler% -DSOL2_LUA_VERSION="%LUA_VERSION%" -DSOL2_CI=ON -DSOL2_BUILD_LUA=ON -DBUILD_LUA_AS_DLL=%lua_build_type% -DSOL2_TESTS=ON -DSOL2_EXAMPLES=ON -DSOL2_GENERATE_SINGLE=ON -DSOL2_TESTS_EXAMPLES=ON -DSOL2_EXAMPLES_SINGLE_GENERATED=ON -DSOL2_TESTS_SINGLE_GENERATED=ON +- if not defined %MINGW_VERSION% (cmake .. -G "%CMAKE_GENERATOR%" %build_compiler% -DSOL2_LUA_VERSION="%LUA_VERSION%" -DSOL2_CI=ON -DSOL2_BUILD_LUA=ON -DBUILD_LUA_AS_DLL=%lua_build_type% -DSOL2_TESTS=ON -DSOL2_EXAMPLES=ON -DSOL2_GENERATE_SINGLE=ON -DSOL2_TESTS_EXAMPLES=ON -DSOL2_EXAMPLES_SINGLE_GENERATED=ON -DSOL2_TESTS_SINGLE_GENERATED=ON) +- if defined %MINGW_VERSION% (cmake ..\.. -G "%CMAKE_GENERATOR%" %build_compiler% -DSOL2_LUA_VERSION="%LUA_VERSION%" -DSOL2_CI=ON -DSOL2_BUILD_LUA=ON -DBUILD_LUA_AS_DLL=%lua_build_type% -DSOL2_TESTS=ON -DSOL2_EXAMPLES=ON -DSOL2_GENERATE_SINGLE=ON -DSOL2_TESTS_EXAMPLES=ON -DSOL2_EXAMPLES_SINGLE_GENERATED=ON -DSOL2_TESTS_SINGLE_GENERATED=ON) +- if defined %MINGW_VERSION% (cmake ..\.. -G "%CMAKE_GENERATOR%" %build_compiler% -DSOL2_LUA_VERSION="%LUA_VERSION%" -DSOL2_CI=ON -DSOL2_BUILD_LUA=ON -DBUILD_LUA_AS_DLL=%lua_build_type% -DSOL2_TESTS=ON -DSOL2_EXAMPLES=ON -DSOL2_GENERATE_SINGLE=ON -DSOL2_TESTS_EXAMPLES=ON -DSOL2_EXAMPLES_SINGLE_GENERATED=ON -DSOL2_TESTS_SINGLE_GENERATED=ON) # We do not build the debug versions because the compiler # generates too much debug info for MinGW to handle -# TODO: fix the damn compilation space and time already build_script: -- if NOT "%build_type%"=="-DCMAKE_BUILD_TYPE=Release" (cmake --build . --config Debug -- %parallelism% %logger%) +- cmake --build . --config Debug -- %parallelism% %logger% - cmake --build . --config Release -- %parallelism% %logger% test_script: -- if NOT "%build_type%"=="-DCMAKE_BUILD_TYPE=Release" (ctest -C Debug --output-on-failure) +- ctest -C Debug --output-on-failure - ctest -C Release --output-on-failure notifications: - provider: Webhook - url: https://webhooks.gitter.im/e/1af10e654a918bef7f1e + url: http://skyhook.glitch.me/api/webhooks/427786348108185611/y2nTmghqltv1SKX2DclEMEKyZtRcwKFlwfZpB_mL1A0nZTVS5MSfumqDKq30-gvWgeL5/appveyor method: POST on_build_success: true on_build_failure: true diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 7ca4c1a9..2ac93f1e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -86,9 +86,17 @@ function (MAKE_EXAMPLE example_source_file example_suffix target_sol) target_compile_options(${example_name} PRIVATE -std=c++1z -ftemplate-backtrace-limit=0 + -Wno-unknown-warning -Wno-unknown-warning-option -Wall -Wpedantic -Werror -pedantic -pedantic-errors - -Wno-noexcept-type - -Wno-unknown-warning -Wno-unknown-warning-option) + -Wno-noexcept-type) + + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # For another day, when C++ is not so crap + # and we have time to audit the entire lib + # for all uses of `detail::swallow`... + #target_compile_options(${example_name} + # PRIVATE -Wcomma) + endif() endif() target_link_libraries(${example_name} diff --git a/examples/require_dll_example/CMakeLists.txt b/examples/require_dll_example/CMakeLists.txt index 4c93a04f..39544d49 100644 --- a/examples/require_dll_example/CMakeLists.txt +++ b/examples/require_dll_example/CMakeLists.txt @@ -62,9 +62,19 @@ function(make_require_from_dll_example target_lib example_lib_name_suffix) else() target_compile_options(${example_lib_name} PRIVATE -std=c++1z + -Wno-unknown-warning -Wno-unknown-warning-option -Wall -Wextra -Wpedantic -pedantic -pedantic-errors - -Wno-noexcept-type - -Wno-unknown-warning -Wno-unknown-warning-option) + -Wno-noexcept-type) + + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # For another day, when C++ is not so crap + # and we have time to audit the entire lib + # for all uses of `detail::swallow`... + #target_compile_options(${test_target_name} + # PRIVATE -Wcomma) + endif() + + if (IS_X86) target_compile_options(${example_lib_name} BEFORE PRIVATE -m32) endif() @@ -93,9 +103,17 @@ function(make_require_from_dll_example target_lib example_lib_name_suffix) else() target_compile_options(${example_name} PRIVATE -std=c++1z + -Wno-unknown-warning -Wno-unknown-warning-option -Wall -Wextra -Wpedantic -pedantic -pedantic-errors - -Wno-noexcept-type - -Wno-unknown-warning -Wno-unknown-warning-option) + -Wno-noexcept-type) + + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # For another day, when C++ is not so crap + # and we have time to audit the entire lib + # for all uses of `detail::swallow`... + #target_compile_options(${test_target_name} + # PRIVATE -Wcomma) + endif() endif() if(CMAKE_DL_LIBS) diff --git a/examples/source/docs/inheritance.cpp b/examples/source/docs/inheritance.cpp index 81e1df48..e09a7ed2 100644 --- a/examples/source/docs/inheritance.cpp +++ b/examples/source/docs/inheritance.cpp @@ -3,7 +3,8 @@ struct A { int a = 10; - virtual int call() { return 0; } + virtual int call() { return 0; } + virtual ~A(){} }; struct B : A { int b = 11; diff --git a/include/sol/bytecode.hpp b/include/sol/bytecode.hpp index ecbbffde..cf85371a 100644 --- a/include/sol/bytecode.hpp +++ b/include/sol/bytecode.hpp @@ -38,18 +38,18 @@ namespace sol { using base_t = std::vector; public: - using base_t::allocator_type; - using base_t::const_iterator; - using base_t::const_pointer; - using base_t::const_reference; - using base_t::const_reverse_iterator; - using base_t::difference_type; - using base_t::iterator; - using base_t::pointer; - using base_t::reference; - using base_t::reverse_iterator; - using base_t::size_type; - using base_t::value_type; + using typename base_t::allocator_type; + using typename base_t::const_iterator; + using typename base_t::const_pointer; + using typename base_t::const_reference; + using typename base_t::const_reverse_iterator; + using typename base_t::difference_type; + using typename base_t::iterator; + using typename base_t::pointer; + using typename base_t::reference; + using typename base_t::reverse_iterator; + using typename base_t::size_type; + using typename base_t::value_type; using base_t::base_t; using base_t::operator=; diff --git a/include/sol/call.hpp b/include/sol/call.hpp index cca9da2c..a991abc0 100644 --- a/include/sol/call.hpp +++ b/include/sol/call.hpp @@ -314,7 +314,7 @@ namespace sol { construct_match(constructor_match(obj), L, argcount, 1 + static_cast(syntax)); userdataref.push(); - stack::stack_detail::undefined_metatable umf(L, &meta[0]); + stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on); umf(); return 1; @@ -633,7 +633,7 @@ namespace sol { construct_match(constructor_match(obj), L, argcount, boost + 1 + static_cast(syntax)); userdataref.push(); - stack::stack_detail::undefined_metatable umf(L, &meta[0]); + stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on); umf(); return 1; @@ -655,7 +655,7 @@ namespace sol { stack::call_into_lua(r, a, L, boost + start, func, detail::implicit_wrapper(obj)); userdataref.push(); - stack::stack_detail::undefined_metatable umf(L, &meta[0]); + stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on); umf(); return 1; diff --git a/include/sol/ebco.hpp b/include/sol/ebco.hpp index aba4cddc..cc8e544b 100644 --- a/include/sol/ebco.hpp +++ b/include/sol/ebco.hpp @@ -41,7 +41,7 @@ namespace sol { namespace detail { ebco(const T& v) : value_(v){}; ebco(T&& v) : value_(std::move(v)){}; ebco& operator=(const T& v) { - value = v; + value_ = v; return *this; } ebco& operator=(T&& v) { @@ -53,13 +53,17 @@ namespace sol { namespace detail { ebco> && !std::is_same_v>, T>>> ebco(Arg&& arg, Args&&... args) : T(std::forward(arg), std::forward(args)...){} - T& value() { + T& value() & { return value_; } - T const& value() const { + T const& value() const & { return value_; } + + T&& value() && { + return std::move(value_); + } }; template @@ -86,13 +90,17 @@ namespace sol { namespace detail { return *this; }; - T& value() { + T& value() & { return static_cast(*this); } - T const& value() const { + T const& value() const & { return static_cast(*this); } + + T&& value() && { + return std::move(static_cast(*this)); + } }; template @@ -128,10 +136,18 @@ namespace sol { namespace detail { ebco& operator=(const ebco&) = default; ebco& operator=(ebco&&) = default; ebco& operator=(T&& v) { - ref = v; + ref = std::move(v); return *this; } + T& value() & { + return ref; + } + + const T& value() const & { + return ref; + } + T&& value() && { return std::move(ref); } diff --git a/include/sol/error_handler.hpp b/include/sol/error_handler.hpp index 6ff1872b..5de5e662 100644 --- a/include/sol/error_handler.hpp +++ b/include/sol/error_handler.hpp @@ -67,7 +67,7 @@ namespace sol { const char* name = lua_tolstring(L, -1, &sz); std::string tn(name, static_cast(sz)); lua_pop(L, 2); - return std::move(tn); + return tn; } default: break; diff --git a/include/sol/forward_detail.hpp b/include/sol/forward_detail.hpp index b0de5e00..9d5099ea 100644 --- a/include/sol/forward_detail.hpp +++ b/include/sol/forward_detail.hpp @@ -46,7 +46,11 @@ namespace sol { namespace stack { namespace stack_detail { + using undefined_method_func = void (*)(stack_reference); + template + void set_undefined_methods_on(stack_reference); + struct undefined_metatable; } } // namespace stack::stack_detail diff --git a/include/sol/lua_value.hpp b/include/sol/lua_value.hpp index 3902e12e..17397302 100644 --- a/include/sol/lua_value.hpp +++ b/include/sol/lua_value.hpp @@ -29,16 +29,23 @@ #include "make_reference.hpp" namespace sol { - namespace detail { + struct lua_value { + public: + struct arr : detail::ebco> { + private: + using base_t = detail::ebco>; + public: + using base_t::base_t; + }; + + private: template - using is_reference_or_lua_value_init_list = meta::any, std::is_same>; + using is_reference_or_lua_value_init_list + = meta::any, std::is_same, std::is_same>; template using is_lua_value_single_constructible = meta::any, is_reference_or_lua_value_init_list>; - } - - struct lua_value { - private: + static lua_State*& thread_local_lua_state() { static thread_local lua_State* L = nullptr; return L; @@ -51,21 +58,39 @@ namespace sol { thread_local_lua_state() = L; } - template >> = meta::enabler> + template >> = meta::enabler> lua_value(lua_State* L_, T&& value) : lua_value(((set_lua_state(L_)), std::forward(value))) { } - template >> = meta::enabler> + template >> = meta::enabler> lua_value(T&& value) : ref_value(make_reference(thread_local_lua_state(), std::forward(value))) { } - lua_value(lua_State* L_, std::initializer_list il) : lua_value(((set_lua_state(L_)), std::move(il))) { + lua_value(lua_State* L_, std::initializer_list> il) + : lua_value([&L_, &il]() { + set_lua_state(L_); + return std::move(il); + }()) { } - lua_value(std::initializer_list il) : ref_value(make_reference(thread_local_lua_state(), std::move(il))) { + lua_value(std::initializer_list> il) : ref_value(make_reference(thread_local_lua_state(), std::move(il))) { } - lua_value(lua_State* L_, reference r) : lua_value(((thread_local_lua_state() = L_), std::move(r))) { + lua_value(lua_State* L_, arr il) + : lua_value([&L_, &il]() { + set_lua_state(L_); + return std::move(il); + }()) { + } + + lua_value(arr il) : ref_value(make_reference(thread_local_lua_state(), std::move(il.value()))) { + } + + lua_value(lua_State* L_, reference r) + : lua_value([&L_, &r]() { + set_lua_state(L_); + return std::move(r); + }()) { } lua_value(reference r) : ref_value(std::move(r)) { @@ -106,6 +131,8 @@ namespace sol { } }; + using array_value = typename lua_value::arr; + namespace stack { template <> struct unqualified_pusher { diff --git a/include/sol/metatable.hpp b/include/sol/metatable.hpp index 56c86275..6f0c7dc3 100644 --- a/include/sol/metatable.hpp +++ b/include/sol/metatable.hpp @@ -106,27 +106,28 @@ namespace sol { using ustorage_base = u_detail::usertype_storage_base; lua_State* L = this->lua_state(); - int x = lua_gettop(L); auto pp = stack::push_pop(*this); + int top = lua_gettop(L); + stack_reference mt(L, -1); stack::get_field(L, meta_function::gc_names, mt.stack_index()); if (type_of(L, -1) != type::table) { return; } + stack_reference gc_names_table(L, -1); stack::get_field(L, meta_function::storage, mt.stack_index()); if (type_of(L, -1) != type::lightuserdata) { return; } ustorage_base& base_storage = *static_cast(stack::get(L, -1)); - base_storage.clear(); - stack_reference gc_names_table(L, -1); - std::array registry_traits; - for (int i = 0; i < registry_traits.size(); ++i) { + std::array registry_traits; + for (std::size_t i = 0; i < registry_traits.size(); ++i) { u_detail::submetatable_type smt = static_cast(i); - stack::get_field(L, smt, gc_names_table.stack_index()); - registry_traits[i] = stack::get(L, -1); + stack::get_field(L, smt, gc_names_table.stack_index()); + registry_traits[i] = stack::get(L, -1); } + // get the registry stack_reference registry(L, raw_index(LUA_REGISTRYINDEX)); registry.push(); @@ -134,26 +135,31 @@ namespace sol { // in the registry (luaL_newmetatable does // [name] = new table // in registry upon creation) - for (int i = 0; i < registry_traits.size(); ++i) { + for (std::size_t i = 0; i < registry_traits.size(); ++i) { u_detail::submetatable_type smt = static_cast(i); + const string_view& gcmetakey = registry_traits[i]; if (smt == u_detail::submetatable_type::named) { - const char* gcmetakey = registry_traits[i]; - stack::set_field(L, gcmetakey, lua_nil); + // use .data() to make it treat it like a c string, + // which it is... + stack::set_field(L, gcmetakey.data(), lua_nil); } else { - stack::set_field(L, registry_traits[i], lua_nil, registry.stack_index()); + // do not change the values in the registry: they need to be present + // no matter what, for safety's sake + //stack::set_field(L, gcmetakey, lua_nil, registry.stack_index()); } } + // destroy all storage and tables + base_storage.clear(); + // 6 strings from gc_names table, // + 1 registry, // + 1 gc_names table // + 1 light userdata of storage - // 8 total - int y = lua_gettop(L); - lua_pop(L, 9); - int z = lua_gettop(L); - int a = x + y + z; + // + 1 registry + // 10 total, 4 left since popping off 6 gc_names tables + lua_settop(L, top); } }; diff --git a/include/sol/stack_core.hpp b/include/sol/stack_core.hpp index 6e3b9682..34370dc6 100644 --- a/include/sol/stack_core.hpp +++ b/include/sol/stack_core.hpp @@ -516,13 +516,13 @@ namespace sol { } template - void reserve(std::vector& arr, std::size_t hint) { - arr.reserve(hint); + void reserve(std::vector& vec, std::size_t hint) { + vec.reserve(hint); } template - void reserve(std::basic_string& arr, std::size_t hint) { - arr.reserve(hint); + void reserve(std::basic_string& str, std::size_t hint) { + str.reserve(hint); } inline bool property_always_true(meta_function) { @@ -798,6 +798,24 @@ namespace sol { return unqualified_interop_check(L, index, index_type, std::forward(handler), tracking); } } + + using undefined_method_func = void (*)(stack_reference); + + struct undefined_metatable { + lua_State* L; + const char* key; + undefined_method_func on_new_table; + + undefined_metatable(lua_State* l, const char* k, undefined_method_func umf) : L(l), key(k), on_new_table(umf) { + } + + void operator()() const { + if (luaL_newmetatable(L, key) == 1) { + on_new_table(stack_reference(L, -1)); + } + lua_setmetatable(L, -2); + } + }; } // namespace stack_detail inline bool maybe_indexable(lua_State* L, int index = -1) { @@ -831,6 +849,30 @@ namespace sol { lua_pop(L, stacksize); } + inline void clear(lua_State* L, int table_index) { + lua_pushnil(L); + while (lua_next(L, table_index) != 0) { + // remove value + lua_pop(L, 1); + // duplicate key to protect form rawset + lua_pushvalue(L, -1); + // push new value + lua_pushnil(L); + // table_index%[key] = nil + lua_rawset(L, table_index); + } + } + + inline void clear(reference& r) { + auto pp = push_pop(r); + int stack_index = pp.index_of(r); + clear(r.lua_state(), stack_index); + } + + inline void clear(stack_reference& r) { + clear(r.lua_state(), r.stack_index()); + } + template inline int push(lua_State* L, T&& t, Args&&... args) { using Tu = meta::unqualified_t; @@ -971,7 +1013,7 @@ namespace sol { } template - bool check_usertype(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { + bool check_usertype(lua_State* L, int index, type, Handler&& handler, record& tracking) { using Tu = meta::unqualified_t; using detail_t = meta::conditional_t, detail::as_pointer_tag, detail::as_value_tag>; return check(L, index, std::forward(handler), tracking); diff --git a/include/sol/stack_field.hpp b/include/sol/stack_field.hpp index f89764bd..0ecce6a8 100644 --- a/include/sol/stack_field.hpp +++ b/include/sol/stack_field.hpp @@ -143,7 +143,7 @@ namespace stack { template struct field_setter { - static constexpr int default_table_index = meta::conditional_t < meta::is_c_str_v || (std::is_integral_v && !std::is_same_v) + static constexpr int default_table_index = meta::conditional_t<(meta::is_c_str_v || meta::is_string_of_v) || (std::is_integral_v && !std::is_same_v) || (std::is_integral_v && !std::is_same_v) || (raw && std::is_void_v>), std::integral_constant, std::integral_constant> ::value; @@ -178,7 +178,7 @@ namespace stack { } } else { - if constexpr (meta::is_c_str_v) { + if constexpr (meta::is_c_str_v || meta::is_string_of_v) { if constexpr (global) { push(L, std::forward(value)); lua_setglobal(L, &key[0]); diff --git a/include/sol/stack_get_unqualified.hpp b/include/sol/stack_get_unqualified.hpp index d2765907..182c3037 100644 --- a/include/sol/stack_get_unqualified.hpp +++ b/include/sol/stack_get_unqualified.hpp @@ -232,32 +232,32 @@ namespace sol { namespace stack { using Tu = meta::unqualified_t; template - static void push_back_at_end(std::true_type, types, lua_State* L, T& arr, std::size_t) { - arr.push_back(stack::get(L, -lua_size::value)); + static void push_back_at_end(std::true_type, types, lua_State* L, T& cont, std::size_t) { + cont.push_back(stack::get(L, -lua_size::value)); } template - static void push_back_at_end(std::false_type, types t, lua_State* L, T& arr, std::size_t idx) { - insert_at_end(meta::has_insert(), t, L, arr, idx); + static void push_back_at_end(std::false_type, types t, lua_State* L, T& cont, std::size_t idx) { + insert_at_end(meta::has_insert(), t, L, cont, idx); } template - static void insert_at_end(std::true_type, types, lua_State* L, T& arr, std::size_t) { + static void insert_at_end(std::true_type, types, lua_State* L, T& cont, std::size_t) { using std::cend; - arr.insert(cend(arr), stack::get(L, -lua_size::value)); + cont.insert(cend(cont), stack::get(L, -lua_size::value)); } template - static void insert_at_end(std::false_type, types, lua_State* L, T& arr, std::size_t idx) { - arr[idx] = stack::get(L, -lua_size::value); + static void insert_at_end(std::false_type, types, lua_State* L, T& cont, std::size_t idx) { + cont[idx] = stack::get(L, -lua_size::value); } static bool max_size_check(std::false_type, T&, std::size_t) { return false; } - static bool max_size_check(std::true_type, T& arr, std::size_t idx) { - return idx >= arr.max_size(); + static bool max_size_check(std::true_type, T& cont, std::size_t idx) { + return idx >= cont.max_size(); } static T get(lua_State* L, int relindex, record& tracking) { @@ -279,7 +279,7 @@ namespace sol { namespace stack { // without hitting where the gotos have infested // so now I would get the error W4XXX unreachable - // me that the return arr at the end of this function + // me that the return cont at the end of this function // which is fair until other compilers complain // that there isn't a return and that based on // SOME MAGICAL FORCE @@ -308,14 +308,14 @@ namespace sol { namespace stack { // all in all: W4 is great!~ int index = lua_absindex(L, relindex); - T arr; + T cont; std::size_t idx = 0; #if SOL_LUA_VERSION >= 503 // This method is HIGHLY performant over regular table iteration // thanks to the Lua API changes in 5.3 // Questionable in 5.4 for (lua_Integer i = 0;; i += lua_size::value) { - if (max_size_check(meta::has_max_size(), arr, idx)) { + if (max_size_check(meta::has_max_size(), cont, idx)) { // see above comment goto done; } @@ -359,14 +359,14 @@ namespace sol { namespace stack { continue; } - push_back_at_end(meta::has_push_back(), t, L, arr, idx); + push_back_at_end(meta::has_push_back(), t, L, cont, idx); ++idx; lua_pop(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)) { - if (idx >= arr.max_size()) { + if (idx >= cont.max_size()) { // see above comment goto done; } @@ -390,12 +390,12 @@ namespace sol { namespace stack { } if (isnil) continue; - push_back_at_end(meta::has_push_back(), t, L, arr, idx); + push_back_at_end(meta::has_push_back(), t, L, cont, idx); ++idx; } #endif done: - return arr; + return cont; } static T get(std::true_type, lua_State* L, int index, record& tracking) { @@ -457,13 +457,13 @@ namespace sol { namespace stack { #endif // make sure stack doesn't overflow int index = lua_absindex(L, relindex); - C arr; - auto at = arr.cbefore_begin(); + C cont; + auto at = cont.cbefore_begin(); std::size_t idx = 0; #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)) { - if (idx >= arr.max_size()) { + if (idx >= cont.max_size()) { goto done; } bool isnil = false; @@ -480,13 +480,13 @@ namespace sol { namespace stack { } if (isnil) continue; - at = arr.insert_after(at, stack::get(L, -lua_size::value)); + at = cont.insert_after(at, stack::get(L, -lua_size::value)); ++idx; } #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)) { - if (idx >= arr.max_size()) { + if (idx >= cont.max_size()) { goto done; } bool isnil = false; @@ -505,12 +505,12 @@ namespace sol { namespace stack { } if (isnil) continue; - at = arr.insert_after(at, stack::get(L, -lua_size::value)); + at = cont.insert_after(at, stack::get(L, -lua_size::value)); ++idx; } #endif done: - return arr; + return cont; } template diff --git a/include/sol/stack_push.hpp b/include/sol/stack_push.hpp index b86f3e6a..ead491da 100644 --- a/include/sol/stack_push.hpp +++ b/include/sol/stack_push.hpp @@ -128,7 +128,7 @@ namespace sol { template static int push_keyed(lua_State* L, K&& k, Args&&... args) { - stack_detail::undefined_metatable fx(L, &k[0]); + stack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on); return push_fx(L, fx, std::forward(args)...); } @@ -167,7 +167,7 @@ namespace sol { template static int push_keyed(lua_State* L, K&& k, T* obj) { - stack_detail::undefined_metatable fx(L, &k[0]); + stack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on); return push_fx(L, fx, obj); } diff --git a/include/sol/table_core.hpp b/include/sol/table_core.hpp index 63e0f379..cd262428 100644 --- a/include/sol/table_core.hpp +++ b/include/sol/table_core.hpp @@ -300,6 +300,12 @@ namespace sol { return end(); } + void clear () { + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + stack::clear(lua_state(), table_index); + } + template decltype(auto) get(Keys&&... keys) const { static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); diff --git a/include/sol/traits.hpp b/include/sol/traits.hpp index b953f698..7db51e6a 100644 --- a/include/sol/traits.hpp +++ b/include/sol/traits.hpp @@ -630,8 +630,7 @@ namespace sol { struct is_pair> : std::true_type {}; template - using is_c_str = any>, const char*>, std::is_same>, char*>, - std::is_same, std::string>>; + using is_c_str = any, std::is_same, std::is_same, is_string_of, is_string_literal_array_of>; template constexpr inline bool is_c_str_v = is_c_str::value; diff --git a/include/sol/unicode.hpp b/include/sol/unicode.hpp index 109aa59f..de2d60c4 100644 --- a/include/sol/unicode.hpp +++ b/include/sol/unicode.hpp @@ -19,13 +19,13 @@ namespace sol { }; inline const string_view& to_string(error_code ec) { - static const string_view arr[4] = { + static const string_view storage[4] = { "ok", "invalid code points", "invalid code unit", "overlong sequence" }; - return arr[static_cast(ec)]; + return storage[static_cast(ec)]; } template diff --git a/include/sol/usertype.hpp b/include/sol/usertype.hpp index 82b85af4..40e8c615 100644 --- a/include/sol/usertype.hpp +++ b/include/sol/usertype.hpp @@ -37,20 +37,22 @@ namespace sol { private: using base_t = basic_metatable; - public: - using base_t::base_t; + template + friend class basic_metatable; - using base_t::pop; - using base_t::push; + template + friend class basic_table_core; template void tuple_set(std::index_sequence, std::tuple&& args) { using args_tuple = std::tuple&&; optional&> maybe_uts = u_detail::maybe_get_usertype_storage(this->lua_state()); - if constexpr(sizeof...(I) > 0) { + if constexpr (sizeof...(I) > 0) { if (maybe_uts) { u_detail::usertype_storage& uts = *maybe_uts; - detail::swallow{ 0, (uts.set(this->lua_state(), std::get(std::forward(args)), std::get(std::forward(args))), 0)... }; + (void)detail::swallow{ 0, + (uts.set(this->lua_state(), std::get(std::forward(args)), std::get(std::forward(args))), + 0)... }; } } else { @@ -58,6 +60,15 @@ namespace sol { } } + public: + using base_t::base_t; + + using base_t::pop; + using base_t::push; + using base_t::lua_state; + using base_t::get; + using base_t::unregister; + template void set(Key&& key, Value&& value) { optional&> maybe_uts = u_detail::maybe_get_usertype_storage(this->lua_state()); diff --git a/include/sol/usertype_core.hpp b/include/sol/usertype_core.hpp index ecbc327c..cebe6e76 100644 --- a/include/sol/usertype_core.hpp +++ b/include/sol/usertype_core.hpp @@ -140,26 +140,26 @@ namespace sol { lua_CFunction f = &comparsion_operator_wrap; ifx(meta_function::equal_to, f); } - if (fx(meta_function::pairs)) { - ifx(meta_function::pairs, &container_detail::u_c_launch>::pairs_call); + } + if (fx(meta_function::pairs)) { + ifx(meta_function::pairs, &container_detail::u_c_launch>::pairs_call); + } + if (fx(meta_function::length)) { + if constexpr (meta::has_size::value || meta::has_size::value) { + auto f = &default_size; + ifx(meta_function::length, f); } - if (fx(meta_function::length)) { - if constexpr (meta::has_size::value || meta::has_size::value) { - auto f = &default_size; - ifx(meta_function::length, f); - } + } + if (fx(meta_function::to_string)) { + if constexpr (is_to_stringable::value) { + auto f = &detail::static_trampoline<&default_to_string>; + ifx(meta_function::to_string, f); } - if (fx(meta_function::to_string)) { - if constexpr (is_to_stringable::value) { - auto f = &detail::static_trampoline<&default_to_string>; - ifx(meta_function::to_string, f); - } - } - if (fx(meta_function::call_function)) { - if constexpr (meta::has_deducible_signature::value) { - auto f = &c_call; - ifx(meta_function::call_function, f); - } + } + if (fx(meta_function::call_function)) { + if constexpr (meta::has_deducible_signature::value) { + auto f = &c_call; + ifx(meta_function::call_function, f); } } } @@ -167,43 +167,36 @@ namespace sol { } // namespace detail namespace stack { namespace stack_detail { - template - struct undefined_metatable { - typedef meta::all>, std::is_destructible> is_destructible; - typedef std::remove_pointer_t P; - lua_State* L; - const char* key; - - undefined_metatable(lua_State* l, const char* k) - : L(l), key(k) { + template + void set_undefined_methods_on(stack_reference t) { + using T = std::remove_pointer_t; + + lua_State* L = t.lua_state(); + + t.push(); + + detail::lua_reg_table l{}; + int index = 0; + detail::indexed_insert insert_fx(l, index); + detail::insert_default_registrations(insert_fx, detail::property_always_true); + if constexpr (!std::is_pointer_v) { + l[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), detail::make_destructor() }; } + luaL_setfuncs(L, l, 0); + + // __type table + lua_createtable(L, 0, 2); + const std::string& name = detail::demangle(); + lua_pushlstring(L, name.c_str(), name.size()); + lua_setfield(L, -2, "name"); + lua_CFunction is_func = &detail::is_check; + lua_pushcclosure(L, is_func, 0); + lua_setfield(L, -2, "is"); + lua_setfield(L, t.stack_index(), to_string(meta_function::type).c_str()); - void operator()() const { - if (luaL_newmetatable(L, key) == 1) { - detail::lua_reg_table l{}; - int index = 0; - detail::indexed_insert insert_fx(l, index); - detail::insert_default_registrations

(insert_fx, detail::property_always_true); - if constexpr (!std::is_pointer_v) { - l[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), detail::make_destructor

() }; - } - luaL_setfuncs(L, l, 0); - - // __type table - lua_createtable(L, 0, 2); - const std::string& name = detail::demangle(); - lua_pushlstring(L, name.c_str(), name.size()); - lua_setfield(L, -2, "name"); - lua_CFunction is_func = &detail::is_check; - lua_pushcclosure(L, is_func, 0); - lua_setfield(L, -2, "is"); - lua_setfield(L, -2, to_string(meta_function::type).c_str()); - } - lua_setmetatable(L, -2); - } - }; - } - } // namespace stack::stack_detail + t.pop(); + } + }} // namespace stack::stack_detail } // namespace sol #endif // SOL_USERTYPE_CORE_HPP diff --git a/include/sol/usertype_storage.hpp b/include/sol/usertype_storage.hpp index 9bdfd1c8..4a9e5bc5 100644 --- a/include/sol/usertype_storage.hpp +++ b/include/sol/usertype_storage.hpp @@ -389,12 +389,53 @@ namespace sol { namespace u_detail { } void clear() { + if (value_index_table.valid()) { + stack::clear(value_index_table); + } + if (reference_index_table.valid()) { + stack::clear(reference_index_table); + } + if (unique_index_table.valid()) { + stack::clear(unique_index_table); + } + if (const_reference_index_table.valid()) { + stack::clear(const_reference_index_table); + } + if (const_value_index_table.valid()) { + stack::clear(const_value_index_table); + } + if (named_index_table.valid()) { + stack::clear(named_index_table); + } + if (type_table.valid()) { + stack::clear(type_table); + } + if (gc_names_table.valid()) { + stack::clear(gc_names_table); + } + if (named_metatable.valid()) { + lua_State* L = named_metatable.lua_state(); + auto pp = stack::push_pop(named_metatable); + int named_metatable_index = pp.index_of(named_metatable); + if (lua_getmetatable(L, named_metatable_index) == 1) { + stack::clear(L, absolute_index(L, -1)); + } + stack::clear(named_metatable); + } + + value_index_table = lua_nil; + reference_index_table = lua_nil; + unique_index_table = lua_nil; + const_reference_index_table = lua_nil; + const_value_index_table = lua_nil; + named_index_table = lua_nil; + type_table = lua_nil; + gc_names_table = lua_nil; + named_metatable = lua_nil; + storage.clear(); string_keys.clear(); auxiliary_keys.clear(); - // TODO: also nuke individual lua tables, - // one by one, - // then replace unqualified_getter/setter } template @@ -433,7 +474,7 @@ namespace sol { namespace u_detail { } } } - else if (k_type != type::nil && k_type != type::none) { + else if (k_type != type::lua_nil && k_type != type::none) { reference* target = nullptr; { stack_reference k = stack::get(L, 2); @@ -461,7 +502,7 @@ namespace sol { namespace u_detail { int base_result; (void)keep_going; (void)base_result; - detail::swallow{ 1, (base_walk_index(L, self, keep_going, base_result), 1)... }; + (void)detail::swallow{ 1, (base_walk_index(L, self, keep_going, base_result), 1)... }; if constexpr (sizeof...(Bases) > 0) { if (!keep_going) { return base_result; @@ -498,7 +539,6 @@ namespace sol { namespace u_detail { this->is_using_index |= true; this->is_using_new_index |= true; - //detail::clear_entries(t); if (submetatable == submetatable_type::named) { stack::set_field(L, metatable_key, named_index_table, t.stack_index()); stack_reference stack_metametatable(L, -named_metatable.push()); @@ -567,6 +607,11 @@ namespace sol { namespace u_detail { inline void set(lua_State* L, Key&& key, Value&& value); }; + template + inline int destruct_usertype_storage (lua_State* L) { + return detail::user_alloc_destruct>(L); + } + template void usertype_storage_base::set(lua_State* L, Key&& key, Value&& value) { using ValueU = meta::unwrap_unqualified_t; @@ -706,7 +751,7 @@ namespace sol { namespace u_detail { int usertype_storage_metatabe_count = stack::push(L, new_table(0, 1)); stack_reference usertype_storage_metatable(L, -usertype_storage_metatabe_count); // set the destruction routine on the metatable - stack::set_field(L, meta_function::garbage_collect, detail::user_alloc_destruct>, usertype_storage_metatable.stack_index()); + stack::set_field(L, meta_function::garbage_collect, &destruct_usertype_storage, usertype_storage_metatable.stack_index()); // set the metatable on the usertype storage userdata stack::set_field(L, metatable_key, usertype_storage_metatable, usertype_storage_ref.stack_index()); usertype_storage_metatable.pop(); @@ -759,10 +804,12 @@ namespace sol { namespace u_detail { template inline void delete_usertype_storage(lua_State* L) { using u_traits = usertype_traits; +#if 0 using u_const_traits = usertype_traits; using u_unique_traits = usertype_traits>; using u_ref_traits = usertype_traits; using u_const_ref_traits = usertype_traits; +#endif using uts = usertype_storage; const char* gcmetakey = &u_traits::gc_table()[0]; @@ -771,9 +818,11 @@ namespace sol { namespace u_detail { lua_pop(L, 1); return; } - lua_pop(L, 1); + usertype_storage& target_umt = stack::pop>>(L); + target_umt.clear(); // get the registry +#if 0 stack_reference registry(L, raw_index(LUA_REGISTRYINDEX)); registry.push(); // eliminate all named entries for this usertype @@ -786,6 +835,7 @@ namespace sol { namespace u_detail { stack::set_field(L, &u_ref_traits::metatable()[0], lua_nil, registry.stack_index()); stack::set_field(L, &u_unique_traits::metatable()[0], lua_nil, registry.stack_index()); registry.pop(); +#endif // Registry Cleanout stack::set_field(L, gcmetakey, lua_nil); } diff --git a/scripts/build.linux.sh b/scripts/build.linux.sh index 13f44aac..808b9b7f 100644 --- a/scripts/build.linux.sh +++ b/scripts/build.linux.sh @@ -23,53 +23,60 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -CI=true declare -a gcc_versions gcc_versions=( - 4.9 - 5 - 6 - 7 +# 7 +# 8 ) declare -r gcc_versions declare -a llvm_versions llvm_versions=( - 3.6.2 - 3.7.1 - 3.8.1 3.9.1 - 4.0.1 - 5.0.1 + 4.0.0 +# 5.0.2 +# 6.0.1 +# 7.0.1 +# 8.0.0 ) declare -r llvm_versions +build_generic=false + if [ -z "${DOCKER_USERNAME}" ] then docker_username= else docker_username=${DOCKER_USERNAME}/ fi +if [ -z "${SOL2_CI}"] +then + SOL2_CI=true +fi echo "====== ======= ======= ======= ======" echo "====== Building All Docker Images ======" echo "====== ======= ======= ======= ======" +echo "For: ${DOCKER_USERNAME} from Dockerfile in ${SOL2_DIR}\n" for i in $gcc_versions; do GCC_VERSION=$i unset LLVM_VERSION echo "====== Building Docker Image: ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} =======" - docker build --tag ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} --build-arg GCC_VERSION=${GCC_VERSION} --build-arg LLVM_VERSION=${LLVM_VERSION} --build-arg CI=${CI} "${SOL2_DIR}" + docker build --tag ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} --build-arg GCC_VERSION=${GCC_VERSION} --build-arg LLVM_VERSION=${LLVM_VERSION} --build-arg SOL2_CI=${SOL2_CI} "${SOL2_DIR}" done for i in $llvm_versions; do LLVM_VERSION=$i unset GCC_VERSION echo "====== Building Docker Image: ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} =======" - docker build --tag ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} --build-arg GCC_VERSION=${GCC_VERSION} --build-arg LLVM_VERSION=${LLVM_VERSION} --build-arg CI=${CI} "${SOL2_DIR}" + docker build --tag ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} --build-arg GCC_VERSION=${GCC_VERSION} --build-arg LLVM_VERSION=${LLVM_VERSION} --build-arg SOL2_CI=${SOL2_CI} "${SOL2_DIR}" done -unset LLVM_VERSION -unset GCC_VERSION -echo "====== Building Docker Image: ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} =======" -docker build --tag ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} --build-arg GCC_VERSION=${GCC_VERSION} --build-arg LLVM_VERSION=${LLVM_VERSION} --build-arg CI=${CI} "${SOL2_DIR}" +if [ "${build_generic}" = true ] +then + unset LLVM_VERSION + unset GCC_VERSION + echo "====== Building Docker Image: ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} =======" + docker build --tag ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} --build-arg GCC_VERSION=${GCC_VERSION} --build-arg LLVM_VERSION=${LLVM_VERSION} --build-arg SOL2_CI=${SOL2_CI} "${SOL2_DIR}" +fi diff --git a/scripts/preparation.linux.sh b/scripts/preparation.linux.sh index f12d551c..9b94608f 100644 --- a/scripts/preparation.linux.sh +++ b/scripts/preparation.linux.sh @@ -32,7 +32,7 @@ build_dir="$(pwd)" echo "#\!/usr/bin/env zsh\n\n" > "sol2.compiler.vars" # # Initial and necessary installations -apt-get update && apt-get -y install ninja-build libreadline6 libreadline6-dev lib32readline6 lib32readline6-dev python3 wget curl libcurl3 cmake git +apt-get update && apt-get -y install lsb-release ninja-build libreadline7 libreadline-dev lib32readline7 lib32readline-dev python3 wget curl libcurl4 cmake git # # LLVM and GCC updates # Grab LLVM or GCC @@ -46,13 +46,17 @@ then minor=$version_nums[2] revision=$version_nums[3] download_llvm=true - download_version=16.04 + image_version=$(lsb_release -rs) + download_version=${image_version} apt_version=${major}.${minor} - #sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test - #sudo apt-get -y update - if [ ${major} -le 5 ] && [ ${major} -ge 4 ]; + if [ ${major} -le 6 ]; then - download_llvm=false + download_llvm=true + download_version=16.04 + elif [ ${major} -eq 4 ] + then + download_llvm=true + download_version=16.04 elif [ ${major} -eq 3 ] then download_llvm=false @@ -60,27 +64,43 @@ then then download_llvm=true download_version=14.04 + elif [ ${minor} -lt 10 ] + then + download_llvm=true + download_version=16.04 fi fi if [ ${download_llvm} = true ] then - export LLVM_ARCHIVE_PATH=${build_dir}/clang+llvm.tar.xz - export CLANG_PREFIX=${build_dir}/clang-${LLVM_VERSION} + export LLVM_ARCHIVE_PATH=${build_dir}/clang-llvm.tar.xz + export CLANG_PREFIX=${build_dir}/clang-llvm-${LLVM_VERSION} export PATH=$CLANG_PREFIX/bin:$PATH export LD_LIBRARY_PATH=$CLANG_PREFIX/lib:$LD_LIBRARY_PATH echo "export LLVM_ARCHIVE_PATH=${build_dir}/clang+llvm.tar.xz\nexport CLANG_PREFIX=${build_dir}/clang-$LLVM_VERSION\nexport PATH=$CLANG_PREFIX/bin:$PATH\nexport LD_LIBRARY_PATH=$CLANG_PREFIX/lib:$LD_LIBRARY_PATH\n" >> "sol2.compiler.vars" apt-get -y install xz-utils clang + #if [${major} -le 5] + #then + # wget http://llvm.org/releases/$LLVM_VERSION/clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-${download_version}.tar.xz -O ${LLVM_ARCHIVE_PATH} + # http://releases.llvm.org/$LLVM_VERSION/clang+llvm-$LLVM_VERSION-x86_64-linux-gnu-ubuntu-${download_version}.tar.xz + #else + # wget http://llvm.org/releases/$LLVM_VERSION/clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-${download_version}.tar.xz -O ${LLVM_ARCHIVE_PATH} + #fi wget http://llvm.org/releases/$LLVM_VERSION/clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-${download_version}.tar.xz -O ${LLVM_ARCHIVE_PATH} mkdir -p "${CLANG_PREFIX}" - tar xf "${LLVM_ARCHIE_PATH}" -C "${CLANG_PREFIX}" --strip-components 1 - # make sure a clang(++) of major/minor exists - # use || true to ignore potential failures - ln -s "clang-${major}.${minor}" "${CLANG_PREFIX}/bin/clang-${major}.${minor}" || true - ln -s "clang-${major}.${minor}" "${CLANG_PREFIX}/bin/clang++-${major}.${minor}" || true - rm -f "${LLVM_ARCHIVE_PATH}" - export CC=clang-${major}.${minor} - export CXX=clang++-${major}.${minor} + tar xf "${LLVM_ARCHIVE_PATH}" -C "${CLANG_PREFIX}" --strip-components 1 + if [ -f "${CLANG_PREFIX}/bin/clang" ] + then + export CC="${CLANG_PREFIX}/bin/clang" + else + export CC="${CLANG_PREFIX}/bin/clang-${major}" + fi + if [ -f "${CLANG_PREFIX}/bin/clang++-${major}" ] + then + export CXX="${CLANG_PREFIX}/bin/clang++-${major}" + else + export CXX="${CLANG_PREFIX}/bin/clang++" + fi else apt-get -y install clang-${apt_version} export CC=clang-${apt_version} @@ -89,11 +109,15 @@ then elif [ "${GCC_VERSION}" ] then # get and use GCC version that we desire - apt-get -y install software-properties-common python-software-properties + # python-software-properties is no longer needed in 18.04, it + # comes with software-properties-common + apt-get -y install software-properties-common add-apt-repository -y ppa:ubuntu-toolchain-r/test apt-get -y update apt-get -y dist-upgrade apt-get -y install gcc-${GCC_VERSION} g++-${GCC_VERSION} gcc-${GCC_VERSION}-multilib g++-${GCC_VERSION}-multilib + #update-alternatives --remove-all gcc + #update-alternatives --remove-all g++ update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 60 --slave /usr/bin/g++ g++ /usr/bin/g++-${GCC_VERSION} update-alternatives --config gcc export CC=gcc-${GCC_VERSION} @@ -112,8 +136,8 @@ apt-get -y autoclean echo "=== Compiler and tool variables ===" ninja --version cmake --version -$CC --version -$CXX --version +${CC} --version +${CXX} --version echo "export CC=$CC\nexport CXX=$CXX\n" >> "sol2.compiler.vars" diff --git a/scripts/push.linux.sh b/scripts/push.linux.sh index 552e5c51..316d9d3f 100644 --- a/scripts/push.linux.sh +++ b/scripts/push.linux.sh @@ -26,24 +26,22 @@ CI=true declare -a gcc_versions gcc_versions=( - 4.9 - 5 - 6 7 + 8 ) declare -r gcc_versions declare -a llvm_versions llvm_versions=( - 3.6.2 - 3.7.1 - 3.8.1 - 3.9.1 - 4.0.1 - 5.0.1 +# 5.0.2 +# 6.0.1 +# 7.0.1 +# 8.0.0 ) declare -r llvm_versions +push_generic=false + if [ -z "${DOCKER_USERNAME}" ] then docker_username= @@ -69,8 +67,10 @@ for i in $llvm_versions; do docker push ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} done -unset LLVM_VERSION -unset GCC_VERSION -echo "====== Pushing Docker Image: ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} =======" -docker push ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} - +if [ "${push_generic}" = true ] +then + unset LLVM_VERSION + unset GCC_VERSION + echo "====== Pushing Docker Image: ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} =======" + docker push ${docker_username}sol2:gcc-${GCC_VERSION}_llvm-${LLVM_VERSION} +fi diff --git a/scripts/run.linux.sh b/scripts/run.linux.sh index 5dae1d95..08c40b3f 100644 --- a/scripts/run.linux.sh +++ b/scripts/run.linux.sh @@ -24,10 +24,10 @@ # # This script runs the actual project -echo -en "travis_fold:start:build_preparation.1\r" +echo -e "travis_fold:start:build_preparation.1\r" if [ -z "${SOL2_DIR}" ] then - if [ ${CI} = true ] + if [ "${SOL2_CI}" = true ] then export SOL2_DIR=~/sol2 else @@ -35,9 +35,14 @@ echo -en "travis_fold:start:build_preparation.1\r" fi fi - if [ -z "${LUA_VERSION}" ] + if [ -z "${SOL2_LUA_VERSION}" ] then - export LUA_VERSION=5.3.4 + export SOL2_LUA_VERSION=5.3.5 + fi + + if [ -z "${SOL2_PLATFORM}" ] + then + export SOL2_PLATFORM=x64 fi mkdir -p build-sol2 @@ -50,47 +55,82 @@ echo -en "travis_fold:start:build_preparation.1\r" source ./sol2.compiler.vars fi - if [[ ${LUA_VERSION} =~ "5.3" ]] + if [ ! -z "${CC}" ] then - export INTEROP_DEFINES="-DINTEROP_EXAMPLES=ON -DTESTS_INTEROP_EXAMPLES=ON -DINTEROP_EXAMPLES_SINGLE=ON -DDYNAMIC_LOADING_EXAMPLES=ON -DDYNAMIC_LOADING_EXAMPLES_SINGLE=ON -DTESTS_DYNAMIC_LOADING_EXAMPLES=ON" + build_type_cc="-DCMAKE_CXX_COMPILER=${CC}" else - export INTEROP_DEFINES= + build_type_cc= + fi + + if [ ! -z "${CXX}" ] + then + build_type_cxx="-DCMAKE_CXX_COMPILER=${CXX}" + else + build_type_cxx= + fi + + SOL2_CMAKE_DEFINES=("-DSOL2_LUA_VERSION=${SOL2_LUA_VERSION}") + SOL2_CMAKE_DEFINES+=("-DSOL2_PLATFORM=${SOL2_PLATFORM}") + SOL2_CMAKE_DEFINES+=('-DSOL2_CI=ON') + SOL2_CMAKE_DEFINES+=('-DSOL2_BUILD_LUA=ON') + SOL2_CMAKE_DEFINES+=('-DBUILD_LUA_AS_DLL=OFF') + SOL2_CMAKE_DEFINES+=('-DSOL2_TESTS=ON') + SOL2_CMAKE_DEFINES+=('-DSOL2_EXAMPLES=ON') + SOL2_CMAKE_DEFINES+=('-DSOL2_TESTS_EXAMPLES=ON') + if [[ ! -z ${SOL2_TEST_SINGLE} ]] + then + SOL2_CMAKE_DEFINES+=('-DSOL2_GENERATE_SINGLE=ON') + SOL2_CMAKE_DEFINES+=('-DSOL2_EXAMPLES_SINGLE=ON') + SOL2_CMAKE_DEFINES+=('-DSOL2_EXAMPLES_SINGLE_GENERATED=ON') + SOL2_CMAKE_DEFINES+=('-DSOL2_TESTS_SINGLE=ON') + SOL2_CMAKE_DEFINES+=('-DSOL2_TESTS_SINGLE_GENERATED=ON') + fi + if [[ ! -z ${SOL2_TEST_INTEROP} ]] + then + SOL2_CMAKE_DEFINES+=('-DSOL2_INTEROP_EXAMPLES=ON') + SOL2_CMAKE_DEFINES+=('-DSOL2_TESTS_INTEROP_EXAMPLES=ON') + SOL2_CMAKE_DEFINES+=('-DSOL2_DYNAMIC_LOADING_EXAMPLES=ON') + SOL2_CMAKE_DEFINES+=('-DSOL2_TESTS_DYNAMIC_LOADING_EXAMPLES=ON') + if [[ ! -z ${SOL2_TEST_SINGLE} ]] + then + SOL2_CMAKE_DEFINES+=('-DSOL2_INTEROP_EXAMPLES_SINGLE=ON') + SOL2_CMAKE_DEFINES+=('-DSOL2_INTEROP_EXAMPLES_SINGLE_GENERATED=ON') + SOL2_CMAKE_DEFINES+=('-DSOL2_DYNAMIC_LOADING_EXAMPLES_SINGLE=ON') + SOL2_CMAKE_DEFINES+=('-DSOL2_DYNAMIC_LOADING_EXAMPLES_SINGLE_GENERATED=ON') + fi fi mkdir -p Debug Release - - export build_type_cc=-DCMAKE_C_COMPILER\=${CC} - export build_type_cxx=-DCMAKE_CXX_COMPILER\=${CXX} -echo -en "travis_fold:end:build_preparation.1\r" +echo -e "travis_fold:end:build_preparation.1\r" # show the tool and compiler versions we're using -echo -en "travis_fold:start:build_preparation.2\r" +echo -e "travis_fold:start:build_preparation.2\r" echo "=== Compiler and tool variables ===" ninja --version cmake --version - ${CC} --version - ${CXX} --version - echo build_type_cc : "${build_type_cc}" - echo build_type_cxx: "${build_type_cxx}" -echo -en "travis_fold:end:build_preparation.2\r" + echo sol2 source dir : "${SOL2_DIR}" + echo build_type_cc : "${build_type_cc}" + echo build_type_cxx : "${build_type_cxx}" + echo cmake defines : "${SOL2_CMAKE_DEFINES[@]}" +echo -e "travis_fold:end:build_preparation.2\r" -echo -en "travis_fold:start:build.debug\r" +echo -e "travis_fold:start:build.debug\r" cd Debug - cmake ${SOL2_DIR} -G Ninja -DCMAKE_BUILD_TYPE=Debug ${build_type_cc} ${build_type_cxx} -DSOL2_LUA_VERSION="${LUA_VERSION}" -DSOL2_CI=ON -DSOL2_PLATFORM=${PLATFORM} -DSOL2_BUILD_LUA=ON -DBUILD_LUA_AS_DLL=OFF -DSOL2_TESTS=ON -DSOL2_EXAMPLES=ON -DSOL2_GENERATE_SINGLE=ON -DSOL2_TESTS_EXAMPLES=ON -DSOL2_EXAMPLES_SINGLE_GENERATED=ON -DSOL2_TESTS_SINGLE_GENERATED=ON ${INTEROP_DEFINES} + cmake "${SOL2_DIR}" -G Ninja -DCMAKE_BUILD_TYPE=Debug ${build_type_cc} ${build_type_cxx} "${SOL2_CMAKE_DEFINES[@]}" cmake --build . --config Debug -echo -en "travis_fold:end:build.debug\r" -echo -en "travis_fold:start:test.debug\r" +echo -e "travis_fold:end:build.debug\r" +echo -e "travis_fold:start:test.debug\r" ctest --build-config Debug --output-on-failure cd .. -echo -en "travis_fold:end:test.debug\r" +echo -e "travis_fold:end:test.debug\r" -echo "travis_fold:start:build.release\r" +echo -e "travis_fold:start:build.release\r" cd Release - cmake ${SOL2_DIR} -G Ninja -DCMAKE_BUILD_TYPE=Release ${build_type_cc} ${build_type_cxx} -DSOL2_LUA_VERSION="${LUA_VERSION}" -DSOL2_CI=ON -DSOL2_PLATFORM=${PLATFORM} -DSOL2_BUILD_LUA=ON -DBUILD_LUA_AS_DLL=OFF -DSOL2_TESTS=ON -DSOL2_EXAMPLES=ON -DSOL2_GENERATE_SINGLE=ON -DSOL2_TESTS_EXAMPLES=ON -DSOL2_EXAMPLES_SINGLE_GENERATED=ON -DSOL2_TESTS_SINGLE_GENERATED=ON ${INTEROP_DEFINES} + cmake "${SOL2_DIR}" -G Ninja -DCMAKE_BUILD_TYPE=Release ${build_type_cc} ${build_type_cxx} "${SOL2_CMAKE_DEFINES[@]}" cmake --build . --config Release -echo -en "travis_fold:end:build.release\r" -echo -en "travis_fold:start:test.release\r" +echo -e "travis_fold:end:build.release\r" +echo -e "travis_fold:start:test.release\r" ctest --build-config Release --output-on-failure cd .. -echo -en "travis_fold:end:test.release\r" +echo -e "travis_fold:end:test.release\r" diff --git a/scripts/run.osx.sh b/scripts/run.osx.sh index a51ebde8..dbdd253f 100644 --- a/scripts/run.osx.sh +++ b/scripts/run.osx.sh @@ -32,13 +32,13 @@ ninja --version cmake --version cd Debug - cmake ${SOL2_DIR} -G Xcode -DCMAKE_BUILD_TYPE=Debug -DSOL2_LUA_VERSION="${LUA_VERSION}" -DSOL2_CI=ON -DSOL2_PLATFORM=${PLATFORM} -DSOL2_BUILD_LUA=ON -DBUILD_LUA_AS_DLL=OFF -DSOL2_TESTS=ON -DSOL2_EXAMPLES=ON -DSOL2_GENERATE_SINGLE=ON -DSOL2_TESTS_EXAMPLES=ON -DSOL2_EXAMPLES_SINGLE_GENERATED=ON -DSOL2_TESTS_SINGLE_GENERATED=ON + cmake ${SOL2_DIR} -G Xcode -DCMAKE_BUILD_TYPE=Debug -DSOL2_LUA_VERSION="${SOL2_LUA_VERSION}" -DSOL2_CI=ON -DSOL2_PLATFORM=${SOL2_PLATFORM} -DSOL2_BUILD_LUA=ON -DBUILD_LUA_AS_DLL=OFF -DSOL2_TESTS=ON -DSOL2_EXAMPLES=ON -DSOL2_GENERATE_SINGLE=ON -DSOL2_TESTS_EXAMPLES=ON -DSOL2_EXAMPLES_SINGLE_GENERATED=ON -DSOL2_TESTS_SINGLE_GENERATED=ON cmake --build . --config Debug ctest --build-config Debug --output-on-failure cd .. cd Release - cmake ${SOL2_DIR} -G Xcode -DCMAKE_BUILD_TYPE=Release -DSOL2_LUA_VERSION="${LUA_VERSION}" -DSOL2_CI=ON -DSOL2_PLATFORM=${PLATFORM} -DSOL2_BUILD_LUA=ON -DBUILD_LUA_AS_DLL=OFF -DSOL2_TESTS=ON -DSOL2_EXAMPLES=ON -DSOL2_GENERATE_SINGLE=ON -DSOL2_TESTS_EXAMPLES=ON -DSOL2_EXAMPLES_SINGLE=ON -DSOL2_TESTS_SINGLE_GENERATED=ON + cmake ${SOL2_DIR} -G Xcode -DCMAKE_BUILD_TYPE=Release -DSOL2_LUA_VERSION="${SOL2_LUA_VERSION}" -DSOL2_CI=ON -DSOL2_PLATFORM=${SOL2_PLATFORM} -DSOL2_BUILD_LUA=ON -DBUILD_LUA_AS_DLL=OFF -DSOL2_TESTS=ON -DSOL2_EXAMPLES=ON -DSOL2_GENERATE_SINGLE=ON -DSOL2_TESTS_EXAMPLES=ON -DSOL2_EXAMPLES_SINGLE=ON -DSOL2_TESTS_SINGLE_GENERATED=ON cmake --build . --config Release ctest --build-config Release --output-on-failure cd .. diff --git a/single/include/sol/forward.hpp b/single/include/sol/forward.hpp index 87caf27a..626232f6 100644 --- a/single/include/sol/forward.hpp +++ b/single/include/sol/forward.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 2019-03-18 11:44:35.615829 UTC -// This header was generated with sol v3.0.0-beta (revision b63d7af) +// Generated 2019-03-21 16:10:16.440886 UTC +// This header was generated with sol v3.0.0-beta (revision 04b36f1) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP diff --git a/single/include/sol/sol.hpp b/single/include/sol/sol.hpp index 67f73612..e835a900 100644 --- a/single/include/sol/sol.hpp +++ b/single/include/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 2019-03-18 11:44:35.317733 UTC -// This header was generated with sol v3.0.0-beta (revision b63d7af) +// Generated 2019-03-21 16:10:16.112045 UTC +// This header was generated with sol v3.0.0-beta (revision 04b36f1) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -2042,7 +2042,11 @@ namespace sol { namespace stack { namespace stack_detail { + using undefined_method_func = void (*)(stack_reference); + template + void set_undefined_methods_on(stack_reference); + struct undefined_metatable; } } // namespace stack::stack_detail @@ -3383,18 +3387,18 @@ namespace sol { using base_t = std::vector; public: - using base_t::allocator_type; - using base_t::const_iterator; - using base_t::const_pointer; - using base_t::const_reference; - using base_t::const_reverse_iterator; - using base_t::difference_type; - using base_t::iterator; - using base_t::pointer; - using base_t::reference; - using base_t::reverse_iterator; - using base_t::size_type; - using base_t::value_type; + using typename base_t::allocator_type; + using typename base_t::const_iterator; + using typename base_t::const_pointer; + using typename base_t::const_reference; + using typename base_t::const_reverse_iterator; + using typename base_t::difference_type; + using typename base_t::iterator; + using typename base_t::pointer; + using typename base_t::reference; + using typename base_t::reverse_iterator; + using typename base_t::size_type; + using typename base_t::value_type; using base_t::base_t; using base_t::operator=; @@ -6047,7 +6051,7 @@ namespace sol { namespace detail { ebco(const T& v) : value_(v){}; ebco(T&& v) : value_(std::move(v)){}; ebco& operator=(const T& v) { - value = v; + value_ = v; return *this; } ebco& operator=(T&& v) { @@ -6059,13 +6063,17 @@ namespace sol { namespace detail { ebco> && !std::is_same_v>, T>>> ebco(Arg&& arg, Args&&... args) : T(std::forward(arg), std::forward(args)...){} - T& value() { + T& value() & { return value_; } - T const& value() const { + T const& value() const & { return value_; } + + T&& value() && { + return std::move(value_); + } }; template @@ -6092,13 +6100,17 @@ namespace sol { namespace detail { return *this; }; - T& value() { + T& value() & { return static_cast(*this); } - T const& value() const { + T const& value() const & { return static_cast(*this); } + + T&& value() && { + return std::move(static_cast(*this)); + } }; template @@ -6134,10 +6146,18 @@ namespace sol { namespace detail { ebco& operator=(const ebco&) = default; ebco& operator=(ebco&&) = default; ebco& operator=(T&& v) { - ref = v; + ref = std::move(v); return *this; } + T& value() & { + return ref; + } + + const T& value() const & { + return ref; + } + T&& value() && { return std::move(ref); } @@ -8084,7 +8104,7 @@ namespace sol { const char* name = lua_tolstring(L, -1, &sz); std::string tn(name, static_cast(sz)); lua_pop(L, 2); - return std::move(tn); + return tn; } default: break; @@ -9497,13 +9517,13 @@ namespace sol { } template - void reserve(std::vector& arr, std::size_t hint) { - arr.reserve(hint); + void reserve(std::vector& vec, std::size_t hint) { + vec.reserve(hint); } template - void reserve(std::basic_string& arr, std::size_t hint) { - arr.reserve(hint); + void reserve(std::basic_string& str, std::size_t hint) { + str.reserve(hint); } inline bool property_always_true(meta_function) { @@ -9778,6 +9798,24 @@ namespace sol { return unqualified_interop_check(L, index, index_type, std::forward(handler), tracking); } } + + using undefined_method_func = void (*)(stack_reference); + + struct undefined_metatable { + lua_State* L; + const char* key; + undefined_method_func on_new_table; + + undefined_metatable(lua_State* l, const char* k, undefined_method_func umf) : L(l), key(k), on_new_table(umf) { + } + + void operator()() const { + if (luaL_newmetatable(L, key) == 1) { + on_new_table(stack_reference(L, -1)); + } + lua_setmetatable(L, -2); + } + }; } // namespace stack_detail inline bool maybe_indexable(lua_State* L, int index = -1) { @@ -9811,6 +9849,30 @@ namespace sol { lua_pop(L, stacksize); } + inline void clear(lua_State* L, int table_index) { + lua_pushnil(L); + while (lua_next(L, table_index) != 0) { + // remove value + lua_pop(L, 1); + // duplicate key to protect form rawset + lua_pushvalue(L, -1); + // push new value + lua_pushnil(L); + // table_index%[key] = nil + lua_rawset(L, table_index); + } + } + + inline void clear(reference& r) { + auto pp = push_pop(r); + int stack_index = pp.index_of(r); + clear(r.lua_state(), stack_index); + } + + inline void clear(stack_reference& r) { + clear(r.lua_state(), r.stack_index()); + } + template inline int push(lua_State* L, T&& t, Args&&... args) { using Tu = meta::unqualified_t; @@ -11052,13 +11114,13 @@ namespace sol { }; inline const string_view& to_string(error_code ec) { - static const string_view arr[4] = { + static const string_view storage[4] = { "ok", "invalid code points", "invalid code unit", "overlong sequence" }; - return arr[static_cast(ec)]; + return storage[static_cast(ec)]; } template @@ -11537,32 +11599,32 @@ namespace sol { namespace stack { using Tu = meta::unqualified_t; template - static void push_back_at_end(std::true_type, types, lua_State* L, T& arr, std::size_t) { - arr.push_back(stack::get(L, -lua_size::value)); + static void push_back_at_end(std::true_type, types, lua_State* L, T& cont, std::size_t) { + cont.push_back(stack::get(L, -lua_size::value)); } template - static void push_back_at_end(std::false_type, types t, lua_State* L, T& arr, std::size_t idx) { - insert_at_end(meta::has_insert(), t, L, arr, idx); + static void push_back_at_end(std::false_type, types t, lua_State* L, T& cont, std::size_t idx) { + insert_at_end(meta::has_insert(), t, L, cont, idx); } template - static void insert_at_end(std::true_type, types, lua_State* L, T& arr, std::size_t) { + static void insert_at_end(std::true_type, types, lua_State* L, T& cont, std::size_t) { using std::cend; - arr.insert(cend(arr), stack::get(L, -lua_size::value)); + cont.insert(cend(cont), stack::get(L, -lua_size::value)); } template - static void insert_at_end(std::false_type, types, lua_State* L, T& arr, std::size_t idx) { - arr[idx] = stack::get(L, -lua_size::value); + static void insert_at_end(std::false_type, types, lua_State* L, T& cont, std::size_t idx) { + cont[idx] = stack::get(L, -lua_size::value); } static bool max_size_check(std::false_type, T&, std::size_t) { return false; } - static bool max_size_check(std::true_type, T& arr, std::size_t idx) { - return idx >= arr.max_size(); + static bool max_size_check(std::true_type, T& cont, std::size_t idx) { + return idx >= cont.max_size(); } static T get(lua_State* L, int relindex, record& tracking) { @@ -11584,7 +11646,7 @@ namespace sol { namespace stack { // without hitting where the gotos have infested // so now I would get the error W4XXX unreachable - // me that the return arr at the end of this function + // me that the return cont at the end of this function // which is fair until other compilers complain // that there isn't a return and that based on // SOME MAGICAL FORCE @@ -11613,14 +11675,14 @@ namespace sol { namespace stack { // all in all: W4 is great!~ int index = lua_absindex(L, relindex); - T arr; + T cont; std::size_t idx = 0; #if SOL_LUA_VERSION >= 503 // This method is HIGHLY performant over regular table iteration // thanks to the Lua API changes in 5.3 // Questionable in 5.4 for (lua_Integer i = 0;; i += lua_size::value) { - if (max_size_check(meta::has_max_size(), arr, idx)) { + if (max_size_check(meta::has_max_size(), cont, idx)) { // see above comment goto done; } @@ -11664,14 +11726,14 @@ namespace sol { namespace stack { continue; } - push_back_at_end(meta::has_push_back(), t, L, arr, idx); + push_back_at_end(meta::has_push_back(), t, L, cont, idx); ++idx; lua_pop(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)) { - if (idx >= arr.max_size()) { + if (idx >= cont.max_size()) { // see above comment goto done; } @@ -11695,12 +11757,12 @@ namespace sol { namespace stack { } if (isnil) continue; - push_back_at_end(meta::has_push_back(), t, L, arr, idx); + push_back_at_end(meta::has_push_back(), t, L, cont, idx); ++idx; } #endif done: - return arr; + return cont; } static T get(std::true_type, lua_State* L, int index, record& tracking) { @@ -11762,13 +11824,13 @@ namespace sol { namespace stack { #endif // make sure stack doesn't overflow int index = lua_absindex(L, relindex); - C arr; - auto at = arr.cbefore_begin(); + C cont; + auto at = cont.cbefore_begin(); std::size_t idx = 0; #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)) { - if (idx >= arr.max_size()) { + if (idx >= cont.max_size()) { goto done; } bool isnil = false; @@ -11785,13 +11847,13 @@ namespace sol { namespace stack { } if (isnil) continue; - at = arr.insert_after(at, stack::get(L, -lua_size::value)); + at = cont.insert_after(at, stack::get(L, -lua_size::value)); ++idx; } #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)) { - if (idx >= arr.max_size()) { + if (idx >= cont.max_size()) { goto done; } bool isnil = false; @@ -11810,12 +11872,12 @@ namespace sol { namespace stack { } if (isnil) continue; - at = arr.insert_after(at, stack::get(L, -lua_size::value)); + at = cont.insert_after(at, stack::get(L, -lua_size::value)); ++idx; } #endif done: - return arr; + return cont; } template @@ -12648,7 +12710,7 @@ namespace sol { template static int push_keyed(lua_State* L, K&& k, Args&&... args) { - stack_detail::undefined_metatable fx(L, &k[0]); + stack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on); return push_fx(L, fx, std::forward(args)...); } @@ -12687,7 +12749,7 @@ namespace sol { template static int push_keyed(lua_State* L, K&& k, T* obj) { - stack_detail::undefined_metatable fx(L, &k[0]); + stack_detail::undefined_metatable fx(L, &k[0], &stack::stack_detail::set_undefined_methods_on); return push_fx(L, fx, obj); } @@ -15911,7 +15973,7 @@ namespace sol { construct_match(constructor_match(obj), L, argcount, 1 + static_cast(syntax)); userdataref.push(); - stack::stack_detail::undefined_metatable umf(L, &meta[0]); + stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on); umf(); return 1; @@ -16230,7 +16292,7 @@ namespace sol { construct_match(constructor_match(obj), L, argcount, boost + 1 + static_cast(syntax)); userdataref.push(); - stack::stack_detail::undefined_metatable umf(L, &meta[0]); + stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on); umf(); return 1; @@ -16252,7 +16314,7 @@ namespace sol { stack::call_into_lua(r, a, L, boost + start, func, detail::implicit_wrapper(obj)); userdataref.push(); - stack::stack_detail::undefined_metatable umf(L, &meta[0]); + stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on); umf(); return 1; @@ -20390,26 +20452,26 @@ namespace sol { lua_CFunction f = &comparsion_operator_wrap; ifx(meta_function::equal_to, f); } - if (fx(meta_function::pairs)) { - ifx(meta_function::pairs, &container_detail::u_c_launch>::pairs_call); + } + if (fx(meta_function::pairs)) { + ifx(meta_function::pairs, &container_detail::u_c_launch>::pairs_call); + } + if (fx(meta_function::length)) { + if constexpr (meta::has_size::value || meta::has_size::value) { + auto f = &default_size; + ifx(meta_function::length, f); } - if (fx(meta_function::length)) { - if constexpr (meta::has_size::value || meta::has_size::value) { - auto f = &default_size; - ifx(meta_function::length, f); - } + } + if (fx(meta_function::to_string)) { + if constexpr (is_to_stringable::value) { + auto f = &detail::static_trampoline<&default_to_string>; + ifx(meta_function::to_string, f); } - if (fx(meta_function::to_string)) { - if constexpr (is_to_stringable::value) { - auto f = &detail::static_trampoline<&default_to_string>; - ifx(meta_function::to_string, f); - } - } - if (fx(meta_function::call_function)) { - if constexpr (meta::has_deducible_signature::value) { - auto f = &c_call; - ifx(meta_function::call_function, f); - } + } + if (fx(meta_function::call_function)) { + if constexpr (meta::has_deducible_signature::value) { + auto f = &c_call; + ifx(meta_function::call_function, f); } } } @@ -20417,43 +20479,36 @@ namespace sol { } // namespace detail namespace stack { namespace stack_detail { - template - struct undefined_metatable { - typedef meta::all>, std::is_destructible> is_destructible; - typedef std::remove_pointer_t P; - lua_State* L; - const char* key; - - undefined_metatable(lua_State* l, const char* k) - : L(l), key(k) { + template + void set_undefined_methods_on(stack_reference t) { + using T = std::remove_pointer_t; + + lua_State* L = t.lua_state(); + + t.push(); + + detail::lua_reg_table l{}; + int index = 0; + detail::indexed_insert insert_fx(l, index); + detail::insert_default_registrations(insert_fx, detail::property_always_true); + if constexpr (!std::is_pointer_v) { + l[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), detail::make_destructor() }; } + luaL_setfuncs(L, l, 0); + + // __type table + lua_createtable(L, 0, 2); + const std::string& name = detail::demangle(); + lua_pushlstring(L, name.c_str(), name.size()); + lua_setfield(L, -2, "name"); + lua_CFunction is_func = &detail::is_check; + lua_pushcclosure(L, is_func, 0); + lua_setfield(L, -2, "is"); + lua_setfield(L, t.stack_index(), to_string(meta_function::type).c_str()); - void operator()() const { - if (luaL_newmetatable(L, key) == 1) { - detail::lua_reg_table l{}; - int index = 0; - detail::indexed_insert insert_fx(l, index); - detail::insert_default_registrations

(insert_fx, detail::property_always_true); - if constexpr (!std::is_pointer_v) { - l[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), detail::make_destructor

() }; - } - luaL_setfuncs(L, l, 0); - - // __type table - lua_createtable(L, 0, 2); - const std::string& name = detail::demangle(); - lua_pushlstring(L, name.c_str(), name.size()); - lua_setfield(L, -2, "name"); - lua_CFunction is_func = &detail::is_check; - lua_pushcclosure(L, is_func, 0); - lua_setfield(L, -2, "is"); - lua_setfield(L, -2, to_string(meta_function::type).c_str()); - } - lua_setmetatable(L, -2); - } - }; - } - } // namespace stack::stack_detail + t.pop(); + } + }} // namespace stack::stack_detail } // namespace sol // end of sol/usertype_core.hpp @@ -20819,12 +20874,47 @@ namespace sol { namespace u_detail { } void clear() { + if (value_index_table.valid()) { + stack::clear(value_index_table); + } + if (reference_index_table.valid()) { + stack::clear(reference_index_table); + } + if (unique_index_table.valid()) { + stack::clear(unique_index_table); + } + if (const_reference_index_table.valid()) { + stack::clear(const_reference_index_table); + } + if (const_value_index_table.valid()) { + stack::clear(const_value_index_table); + } + if (named_index_table.valid()) { + stack::clear(named_index_table); + } + if (type_table.valid()) { + stack::clear(type_table); + } + if (gc_names_table.valid()) { + stack::clear(gc_names_table); + } + if (named_metatable.valid()) { + stack::clear(named_metatable); + } + + value_index_table = lua_nil; + reference_index_table = lua_nil; + unique_index_table = lua_nil; + const_reference_index_table = lua_nil; + const_value_index_table = lua_nil; + named_index_table = lua_nil; + type_table = lua_nil; + gc_names_table = lua_nil; + named_metatable = lua_nil; + storage.clear(); string_keys.clear(); auxiliary_keys.clear(); - // TODO: also nuke individual lua tables, - // one by one, - // then replace unqualified_getter/setter } template @@ -20863,7 +20953,7 @@ namespace sol { namespace u_detail { } } } - else if (k_type != type::nil && k_type != type::none) { + else if (k_type != type::lua_nil && k_type != type::none) { reference* target = nullptr; { stack_reference k = stack::get(L, 2); @@ -20928,7 +21018,6 @@ namespace sol { namespace u_detail { this->is_using_index |= true; this->is_using_new_index |= true; - //detail::clear_entries(t); if (submetatable == submetatable_type::named) { stack::set_field(L, metatable_key, named_index_table, t.stack_index()); stack_reference stack_metametatable(L, -named_metatable.push()); @@ -20997,6 +21086,11 @@ namespace sol { namespace u_detail { inline void set(lua_State* L, Key&& key, Value&& value); }; + template + inline int destruct_usertype_storage (lua_State* L) { + return detail::user_alloc_destruct>(L); + } + template void usertype_storage_base::set(lua_State* L, Key&& key, Value&& value) { using ValueU = meta::unwrap_unqualified_t; @@ -21136,7 +21230,7 @@ namespace sol { namespace u_detail { int usertype_storage_metatabe_count = stack::push(L, new_table(0, 1)); stack_reference usertype_storage_metatable(L, -usertype_storage_metatabe_count); // set the destruction routine on the metatable - stack::set_field(L, meta_function::garbage_collect, detail::user_alloc_destruct>, usertype_storage_metatable.stack_index()); + stack::set_field(L, meta_function::garbage_collect, &destruct_usertype_storage, usertype_storage_metatable.stack_index()); // set the metatable on the usertype storage userdata stack::set_field(L, metatable_key, usertype_storage_metatable, usertype_storage_ref.stack_index()); usertype_storage_metatable.pop(); @@ -21189,10 +21283,12 @@ namespace sol { namespace u_detail { template inline void delete_usertype_storage(lua_State* L) { using u_traits = usertype_traits; +#if 0 using u_const_traits = usertype_traits; using u_unique_traits = usertype_traits>; using u_ref_traits = usertype_traits; using u_const_ref_traits = usertype_traits; +#endif using uts = usertype_storage; const char* gcmetakey = &u_traits::gc_table()[0]; @@ -21201,9 +21297,11 @@ namespace sol { namespace u_detail { lua_pop(L, 1); return; } - lua_pop(L, 1); + usertype_storage& target_umt = stack::pop>>(L); + target_umt.clear(); // get the registry +#if 0 stack_reference registry(L, raw_index(LUA_REGISTRYINDEX)); registry.push(); // eliminate all named entries for this usertype @@ -21216,6 +21314,7 @@ namespace sol { namespace u_detail { stack::set_field(L, &u_ref_traits::metatable()[0], lua_nil, registry.stack_index()); stack::set_field(L, &u_unique_traits::metatable()[0], lua_nil, registry.stack_index()); registry.pop(); +#endif // Registry Cleanout stack::set_field(L, gcmetakey, lua_nil); } @@ -22096,6 +22195,12 @@ namespace sol { return end(); } + void clear () { + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + stack::clear(lua_state(), table_index); + } + template decltype(auto) get(Keys&&... keys) const { static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); @@ -22483,7 +22588,8 @@ namespace sol { using ustorage_base = u_detail::usertype_storage_base; lua_State* L = this->lua_state(); - int x = lua_gettop(L); + + int top = lua_gettop(L); auto pp = stack::push_pop(*this); stack_reference mt(L, -1); @@ -22491,19 +22597,19 @@ namespace sol { if (type_of(L, -1) != type::table) { return; } + stack_reference gc_names_table(L, -1); stack::get_field(L, meta_function::storage, mt.stack_index()); if (type_of(L, -1) != type::lightuserdata) { return; } ustorage_base& base_storage = *static_cast(stack::get(L, -1)); - base_storage.clear(); - stack_reference gc_names_table(L, -1); - std::array registry_traits; + std::array registry_traits; for (int i = 0; i < registry_traits.size(); ++i) { u_detail::submetatable_type smt = static_cast(i); - stack::get_field(L, smt, gc_names_table.stack_index()); - registry_traits[i] = stack::get(L, -1); + stack::get_field(L, smt, gc_names_table.stack_index()); + registry_traits[i] = stack::get(L, -1); } + // get the registry stack_reference registry(L, raw_index(LUA_REGISTRYINDEX)); registry.push(); @@ -22513,24 +22619,27 @@ namespace sol { // in registry upon creation) for (int i = 0; i < registry_traits.size(); ++i) { u_detail::submetatable_type smt = static_cast(i); + const string_view& gcmetakey = registry_traits[i]; if (smt == u_detail::submetatable_type::named) { - const char* gcmetakey = registry_traits[i]; stack::set_field(L, gcmetakey, lua_nil); } else { - stack::set_field(L, registry_traits[i], lua_nil, registry.stack_index()); + // do not change the values in the registry: they need to be present + // no matter what, for safety's sake + //stack::set_field(L, gcmetakey, lua_nil, registry.stack_index()); } } + // destroy all storage and tables + base_storage.clear(); + // 6 strings from gc_names table, // + 1 registry, // + 1 gc_names table // + 1 light userdata of storage - // 8 total - int y = lua_gettop(L); - lua_pop(L, 9); - int z = lua_gettop(L); - int a = x + y + z; + // + 1 registry + // 10 total, 4 left since popping off 6 gc_names tables + lua_settop(L, top); } }; @@ -22545,20 +22654,22 @@ namespace sol { private: using base_t = basic_metatable; - public: - using base_t::base_t; + template + friend class basic_metatable; - using base_t::pop; - using base_t::push; + template + friend class basic_table_core; template void tuple_set(std::index_sequence, std::tuple&& args) { using args_tuple = std::tuple&&; optional&> maybe_uts = u_detail::maybe_get_usertype_storage(this->lua_state()); - if constexpr(sizeof...(I) > 0) { + if constexpr (sizeof...(I) > 0) { if (maybe_uts) { u_detail::usertype_storage& uts = *maybe_uts; - detail::swallow{ 0, (uts.set(this->lua_state(), std::get(std::forward(args)), std::get(std::forward(args))), 0)... }; + detail::swallow{ 0, + (uts.set(this->lua_state(), std::get(std::forward(args)), std::get(std::forward(args))), + 0)... }; } } else { @@ -22566,6 +22677,15 @@ namespace sol { } } + public: + using base_t::base_t; + + using base_t::pop; + using base_t::push; + using base_t::lua_state; + using base_t::get; + using base_t::unregister; + template void set(Key&& key, Value&& value) { optional&> maybe_uts = u_detail::maybe_get_usertype_storage(this->lua_state()); @@ -23064,16 +23184,23 @@ namespace sol { // beginning of sol/lua_value.hpp namespace sol { - namespace detail { + struct lua_value { + public: + struct arr : detail::ebco> { + private: + using base_t = detail::ebco>; + public: + using base_t::base_t; + }; + + private: template - using is_reference_or_lua_value_init_list = meta::any, std::is_same>; + using is_reference_or_lua_value_init_list + = meta::any, std::is_same, std::is_same>; template using is_lua_value_single_constructible = meta::any, is_reference_or_lua_value_init_list>; - } - - struct lua_value { - private: + static lua_State*& thread_local_lua_state() { static thread_local lua_State* L = nullptr; return L; @@ -23086,21 +23213,39 @@ namespace sol { thread_local_lua_state() = L; } - template >> = meta::enabler> + template >> = meta::enabler> lua_value(lua_State* L_, T&& value) : lua_value(((set_lua_state(L_)), std::forward(value))) { } - template >> = meta::enabler> + template >> = meta::enabler> lua_value(T&& value) : ref_value(make_reference(thread_local_lua_state(), std::forward(value))) { } - lua_value(lua_State* L_, std::initializer_list il) : lua_value(((set_lua_state(L_)), std::move(il))) { + lua_value(lua_State* L_, std::initializer_list> il) + : lua_value([&L_, &il]() { + set_lua_state(L_); + return std::move(il); + }()) { } - lua_value(std::initializer_list il) : ref_value(make_reference(thread_local_lua_state(), std::move(il))) { + lua_value(std::initializer_list> il) : ref_value(make_reference(thread_local_lua_state(), std::move(il))) { } - lua_value(lua_State* L_, reference r) : lua_value(((thread_local_lua_state() = L_), std::move(r))) { + lua_value(lua_State* L_, arr il) + : lua_value([&L_, &il]() { + set_lua_state(L_); + return std::move(il); + }()) { + } + + lua_value(arr il) : ref_value(make_reference(thread_local_lua_state(), std::move(il.value()))) { + } + + lua_value(lua_State* L_, reference r) + : lua_value([&L_, &r]() { + set_lua_state(L_); + return std::move(r); + }()) { } lua_value(reference r) : ref_value(std::move(r)) { @@ -23141,6 +23286,8 @@ namespace sol { } }; + using array_value = typename lua_value::arr; + namespace stack { template <> struct unqualified_pusher { diff --git a/tests/compile_tests/CMakeLists.txt b/tests/compile_tests/CMakeLists.txt index f19773af..a973cd9a 100644 --- a/tests/compile_tests/CMakeLists.txt +++ b/tests/compile_tests/CMakeLists.txt @@ -49,10 +49,18 @@ function(CREATE_TEST test_target_name test_name target_sol) _CRT_SECURE_NO_WARNINGS _CRT_SECURE_NO_DEPRECATE) else() target_compile_options(${test_target_name} - PRIVATE -std=c++1z + PRIVATE -std=c++1z + -Wno-unknown-warning -Wno-unknown-warning-option -Wall -Wextra -Wpedantic -pedantic -pedantic-errors - -Wno-noexcept-type - -Wno-unknown-warning -Wno-unknown-warning-option) + -Wno-noexcept-type) + + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # For another day, when C++ is not so crap + # and we have time to audit the entire lib + # for all uses of `detail::swallow`... + #target_compile_options(${test_target_name} + # PRIVATE -Wcomma) + endif() endif() if (MSVC) diff --git a/tests/runtime_tests/CMakeLists.txt b/tests/runtime_tests/CMakeLists.txt index b8178c1c..a9979930 100644 --- a/tests/runtime_tests/CMakeLists.txt +++ b/tests/runtime_tests/CMakeLists.txt @@ -47,10 +47,18 @@ function(CREATE_TEST test_target_name test_name target_sol) endif() else() target_compile_options(${test_target_name} - PRIVATE -std=c++1z - -Wall -Wpedantic -Werror -pedantic -pedantic-errors - -Wno-noexcept-type -pthread - -Wno-unknown-warning -Wno-unknown-warning-option) + PRIVATE -std=c++1z -pthread + -Wno-unknown-warning -Wno-unknown-warning-option + -Wall -Wpedantic -Werror -pedantic -pedantic-errors + -Wno-noexcept-type) + + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # For another day, when C++ is not so crap + # and we have time to audit the entire lib + # for all uses of `detail::swallow`... + #target_compile_options(${test_target_name} + # PRIVATE -Wcomma) + endif() if (IS_X86) if(MINGW) diff --git a/tests/runtime_tests/source/basic.cpp b/tests/runtime_tests/source/basic.cpp index 6f121244..25383f2f 100644 --- a/tests/runtime_tests/source/basic.cpp +++ b/tests/runtime_tests/source/basic.cpp @@ -704,11 +704,11 @@ TEST_CASE("object/base_of_things", "make sure that object is the base of things lua["ud"] = base1{}; lua["f1"] = [](sol::stack_object o) -> sol::stack_object { return o; }; - lua["f2"] = [](sol::stack_table o) -> sol::stack_object { return o; }; - lua["f3"] = [](sol::stack_thread o) -> sol::stack_object { return o; }; - lua["f4"] = [](sol::stack_unsafe_function o) -> sol::stack_object { return o; }; - lua["f5"] = [](sol::stack_protected_function o) -> sol::stack_object { return o; }; - lua["f6"] = [](sol::stack_userdata o) -> sol::stack_object { return o; }; + lua["f2"] = [](sol::stack_table o) -> sol::stack_object { return std::move(o); }; + lua["f3"] = [](sol::stack_thread o) -> sol::stack_object { return std::move(o); }; + lua["f4"] = [](sol::stack_unsafe_function o) -> sol::stack_object { return std::move(o); }; + lua["f5"] = [](sol::stack_protected_function o) -> sol::stack_object { return std::move(o); }; + lua["f6"] = [](sol::stack_userdata o) -> sol::stack_object { return std::move(o); }; auto result1 = lua.safe_script("f1(2)", sol::script_pass_on_error); REQUIRE(result1.valid()); auto result2 = lua.safe_script("f2({})", sol::script_pass_on_error); diff --git a/tests/runtime_tests/source/common_classes.hpp b/tests/runtime_tests/source/common_classes.hpp index d1993df9..1d024509 100644 --- a/tests/runtime_tests/source/common_classes.hpp +++ b/tests/runtime_tests/source/common_classes.hpp @@ -131,6 +131,8 @@ public: class abstract_A { public: virtual void a() = 0; + virtual ~abstract_A() { + } }; class abstract_B : public abstract_A { diff --git a/tests/runtime_tests/source/containers.cpp b/tests/runtime_tests/source/containers.cpp index c45e86b3..10db59fd 100644 --- a/tests/runtime_tests/source/containers.cpp +++ b/tests/runtime_tests/source/containers.cpp @@ -487,6 +487,7 @@ TEST_CASE("containers/pairs", "test how well pairs work with the underlying syst TEST_CASE("containers/pointer types", "check that containers with unique usertypes and pointers or something") { struct base_t { virtual int get() const = 0; + virtual ~base_t(){} }; struct derived_1_t : base_t { diff --git a/tests/runtime_tests/source/coroutines.cpp b/tests/runtime_tests/source/coroutines.cpp index d10f2a20..697f5498 100644 --- a/tests/runtime_tests/source/coroutines.cpp +++ b/tests/runtime_tests/source/coroutines.cpp @@ -480,7 +480,7 @@ end // Resume from lua via thread and coroutine sol::thread runner_thread = lua["loop_th"]; sol::state_view runner_thread_state = runner_thread.state(); - auto test_resume = [&runner_thread, &runner_thread_state]() { + auto test_resume = [&runner_thread_state]() { sol::coroutine cr = runner_thread_state["loop"]; sol::stack::push(runner_thread_state, 50); sol::stack::push(runner_thread_state, 25); diff --git a/tests/runtime_tests/source/functions.cpp b/tests/runtime_tests/source/functions.cpp index 37a2b991..9e24bbae 100644 --- a/tests/runtime_tests/source/functions.cpp +++ b/tests/runtime_tests/source/functions.cpp @@ -534,6 +534,9 @@ TEST_CASE("functions/all kinds", "Register all kinds of functions, make sure the static std::tuple x_bark(int num_value, test_1* a) { return std::tuple(num_value * 2, a->a); } + + virtual ~test_1() { + } }; struct test_2 { diff --git a/tests/runtime_tests/source/lua_value.cpp b/tests/runtime_tests/source/lua_value.cpp index ae84487e..5e3126f0 100644 --- a/tests/runtime_tests/source/lua_value.cpp +++ b/tests/runtime_tests/source/lua_value.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES @@ -81,8 +82,8 @@ TEST_CASE("lua_value/nested", "make nested values can be put in lua_value proper sol::state lua; - sol::lua_value lv_mixed_table(lua, { 1, int_entry(2), 3, int_entry(4), 5 }); - sol::lua_value lv_mixed_nested_table(lua, { 1, int_entry(2), 3, int_entry(4), { 5, 6, int_entry(7), "8" } }); + sol::lua_value lv_mixed_table(lua, sol::array_value{ 1, int_entry(2), 3, int_entry(4), 5 }); + sol::lua_value lv_mixed_nested_table(lua, sol::array_value{ 1, int_entry(2), 3, int_entry(4), sol::array_value{ 5, 6, int_entry(7), "8" } }); REQUIRE(lv_mixed_table.is()); REQUIRE(lv_mixed_nested_table.is()); @@ -96,13 +97,13 @@ TEST_CASE("lua_value/nested", "make nested values can be put in lua_value proper SECTION("type check (object)") { sol::object obj_mixed_table(lv_mixed_table.value()); sol::object obj_mixed_nested_table(lv_mixed_nested_table.value()); - + REQUIRE(obj_mixed_table.is()); REQUIRE(obj_mixed_nested_table.is()); - + std::vector> mixed_table_value = obj_mixed_table.as>>(); std::vector mixed_nested_table_value = obj_mixed_nested_table.as>(); - + REQUIRE(mixed_table_truth == mixed_table_value); REQUIRE(mixed_nested_table_truth == mixed_nested_table_value); } @@ -118,7 +119,79 @@ TEST_CASE("lua_value/nested", "make nested values can be put in lua_value proper std::vector> mixed_table_value = obj_mixed_table.as>>(); std::vector mixed_nested_table_value = obj_mixed_nested_table.as>(); - + + REQUIRE(mixed_table_truth == mixed_table_value); + REQUIRE(mixed_nested_table_truth == mixed_nested_table_value); + } + SECTION("pushing/popping (object)") { + lua["obj_mixed_table"] = lv_mixed_table; + lua["obj_mixed_nested_table"] = lv_mixed_nested_table; + + sol::object obj_mixed_table = lua["obj_mixed_table"]; + sol::object obj_mixed_nested_table = lua["obj_mixed_nested_table"]; + + REQUIRE(obj_mixed_table.is()); + REQUIRE(obj_mixed_nested_table.is()); + + std::vector> mixed_table_value = obj_mixed_table.as>>(); + std::vector mixed_nested_table_value = obj_mixed_nested_table.as>(); + + REQUIRE(mixed_table_truth == mixed_table_value); + REQUIRE(mixed_nested_table_truth == mixed_nested_table_value); + } +#else + REQUIRE(true); +#endif // C++17 +} + +TEST_CASE("lua_value/nested key value", "make nested values (key value) can be put in lua_value properly") { +#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT + using mixed_table_entry = std::variant; + using nested_entry = std::variant>; + + const std::vector> mixed_table_truth = { 1, int_entry(2), 3, int_entry(4), 5 }; + const std::vector mixed_nested_table_truth = { 1, int_entry(2), 3, int_entry(4), std::vector{ 5, 6, int_entry(7), "8" } }; + + sol::state lua; + + sol::lua_value lv_mixed_table(lua, sol::array_value{ 1, int_entry(2), 3, int_entry(4), 5 }); + sol::lua_value lv_mixed_nested_table(lua, sol::array_value{ 1, int_entry(2), 3, int_entry(4), sol::array_value{ 5, 6, int_entry(7), "8" } }); + + REQUIRE(lv_mixed_table.is()); + REQUIRE(lv_mixed_nested_table.is()); + + std::vector> mixed_table_value_lv = lv_mixed_table.as>>(); + std::vector mixed_nested_table_value_lv = lv_mixed_nested_table.as>(); + + REQUIRE(mixed_table_truth == mixed_table_value_lv); + REQUIRE(mixed_nested_table_truth == mixed_nested_table_value_lv); + + SECTION("type check (object)") { + sol::object obj_mixed_table(lv_mixed_table.value()); + sol::object obj_mixed_nested_table(lv_mixed_nested_table.value()); + + REQUIRE(obj_mixed_table.is()); + REQUIRE(obj_mixed_nested_table.is()); + + std::vector> mixed_table_value = obj_mixed_table.as>>(); + std::vector mixed_nested_table_value = obj_mixed_nested_table.as>(); + + REQUIRE(mixed_table_truth == mixed_table_value); + REQUIRE(mixed_nested_table_truth == mixed_nested_table_value); + } + SECTION("pushing/popping") { + lua["obj_mixed_table"] = lv_mixed_table; + lua["obj_mixed_nested_table"] = lv_mixed_nested_table; + + sol::lua_value obj_mixed_table = lua["obj_mixed_table"]; + sol::lua_value obj_mixed_nested_table = lua["obj_mixed_nested_table"]; + + REQUIRE(obj_mixed_table.is()); + REQUIRE(obj_mixed_nested_table.is()); + + std::vector> mixed_table_value = obj_mixed_table.as>>(); + std::vector mixed_nested_table_value = obj_mixed_nested_table.as>(); + REQUIRE(mixed_table_truth == mixed_table_value); REQUIRE(mixed_nested_table_truth == mixed_nested_table_value); } @@ -148,6 +221,7 @@ TEST_CASE("lua_value/basic types", "make sure we can stick values and nested val const int_entry userdata_truth = int_entry(3); const std::vector int_table_truth = { 1, 2, 3, 4, 5 }; + const std::map int_map_truth = { {1, 2}, {3, 4}, {5, 6} }; sol::lua_value lv_int(lua, 1); sol::lua_value lv_double(lua, 2.0); @@ -157,6 +231,7 @@ TEST_CASE("lua_value/basic types", "make sure we can stick values and nested val sol::lua_value lv_nil(lua, sol::lua_nil); sol::lua_value lv_userdata(lua, int_entry(3)); sol::lua_value lv_int_table(lua, { 1, 2, 3, 4, 5 }); + sol::lua_value lv_int_map(lua, { {1, 2}, {3, 4}, {5, 6} }); REQUIRE(lv_int.is()); REQUIRE(lv_double.is()); REQUIRE(lv_string.is()); @@ -166,6 +241,7 @@ TEST_CASE("lua_value/basic types", "make sure we can stick values and nested val REQUIRE(lv_userdata.is()); REQUIRE(lv_userdata.is()); REQUIRE(lv_int_table.is()); + REQUIRE(lv_int_map.is()); REQUIRE(lv_int.as() == 1); REQUIRE(lv_double.as() == 2.0); @@ -178,6 +254,8 @@ TEST_CASE("lua_value/basic types", "make sure we can stick values and nested val std::vector int_table_value_lv = lv_int_table.as>(); REQUIRE(int_table_truth == int_table_value_lv); + std::map int_map_value_lv = lv_int_map.as>(); + REQUIRE(int_map_truth == int_map_value_lv); SECTION("type check (object)") { sol::object obj_int(lv_int.value()); @@ -188,6 +266,7 @@ TEST_CASE("lua_value/basic types", "make sure we can stick values and nested val sol::object obj_nil(lv_nil.value()); sol::object obj_userdata(lv_userdata.value()); sol::object obj_int_table(lv_int_table.value()); + sol::object obj_int_map(lv_int_map.value()); REQUIRE(obj_int.is()); REQUIRE(obj_double.is()); @@ -198,6 +277,7 @@ TEST_CASE("lua_value/basic types", "make sure we can stick values and nested val REQUIRE(obj_userdata.is()); REQUIRE(obj_userdata.is()); REQUIRE(obj_int_table.is()); + REQUIRE(obj_int_map.is()); REQUIRE(obj_int.as() == 1); REQUIRE(obj_double.as() == 2.0); @@ -210,6 +290,8 @@ TEST_CASE("lua_value/basic types", "make sure we can stick values and nested val std::vector int_table_value = obj_int_table.as>(); REQUIRE(int_table_truth == int_table_value); + std::map int_map_value = obj_int_map.as>(); + REQUIRE(int_map_truth == int_map_value); } SECTION("push/popping") { lua["obj_int"] = lv_int; @@ -220,6 +302,7 @@ TEST_CASE("lua_value/basic types", "make sure we can stick values and nested val lua["obj_nil"] = lv_nil; lua["obj_userdata"] = lv_userdata; lua["obj_int_table"] = lv_int_table; + lua["obj_int_map"] = lv_int_map; // these all actually invoke the constructor // so do one .get<> explicitly to ensure it's @@ -233,6 +316,7 @@ TEST_CASE("lua_value/basic types", "make sure we can stick values and nested val sol::lua_value obj_nil = lua["obj_nil"]; sol::lua_value obj_userdata = lua["obj_userdata"]; sol::lua_value obj_int_table = lua["obj_int_table"]; + sol::lua_value obj_int_map = lua["obj_int_map"]; REQUIRE(obj_int.is()); REQUIRE(obj_double.is()); @@ -241,6 +325,7 @@ TEST_CASE("lua_value/basic types", "make sure we can stick values and nested val REQUIRE(obj_bool.is()); REQUIRE(obj_nil.is()); REQUIRE(obj_int_table.is()); + REQUIRE(obj_int_map.is()); REQUIRE(obj_int.as() == 1); REQUIRE(obj_double.as() == 2.0); @@ -252,6 +337,8 @@ TEST_CASE("lua_value/basic types", "make sure we can stick values and nested val std::vector int_table_value = obj_int_table.as>(); REQUIRE(int_table_truth == int_table_value); + std::map int_map_value = obj_int_map.as>(); + REQUIRE(int_map_truth == int_map_value); } SECTION("push/popping (object)") { lua["obj_int"] = lv_int; @@ -262,6 +349,7 @@ TEST_CASE("lua_value/basic types", "make sure we can stick values and nested val lua["obj_nil"] = lv_nil; lua["obj_userdata"] = lv_userdata; lua["obj_int_table"] = lv_int_table; + lua["obj_int_map"] = lv_int_map; sol::object obj_int = lua["obj_int"]; sol::object obj_double = lua["obj_double"]; @@ -271,6 +359,7 @@ TEST_CASE("lua_value/basic types", "make sure we can stick values and nested val sol::object obj_nil = lua["obj_nil"]; sol::object obj_userdata = lua["obj_userdata"]; sol::object obj_int_table = lua["obj_int_table"]; + sol::object obj_int_map = lua["obj_int_map"]; REQUIRE(obj_int.is()); REQUIRE(obj_double.is()); @@ -293,6 +382,8 @@ TEST_CASE("lua_value/basic types", "make sure we can stick values and nested val std::vector int_table_value = obj_int_table.as>(); REQUIRE(int_table_truth == int_table_value); + std::map int_map_value = obj_int_map.as>(); + REQUIRE(int_map_truth == int_map_value); } } diff --git a/tests/runtime_tests/source/tables.clear.cpp b/tests/runtime_tests/source/tables.clear.cpp new file mode 100644 index 00000000..ae92f39b --- /dev/null +++ b/tests/runtime_tests/source/tables.clear.cpp @@ -0,0 +1,74 @@ +// sol3 + +// The MIT License (MIT) + +// Copyright (c) 2013-2019 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. + +#include "sol_test.hpp" + +#include + +TEST_CASE("tables/clear", "clear method works and does not clobber stack") { + sol::state lua; + sol::stack_guard luasg(lua); + lua["t"] = sol::lua_value({ { "a", "b" }, { "c", "d" } }); + sol::table t = lua["t"]; + { + sol::stack_guard clearsg(lua); + t.clear(); + } + REQUIRE(!t["a"].valid()); + REQUIRE(!t["c"].valid()); +} + +TEST_CASE("tables/stack clear", "stack-based clear method works and does not clobber stack") { + sol::state lua; + SECTION("reference based") { + sol::stack_guard luasg(lua); + lua["t"] = sol::lua_value({ { "a", "b" }, { "c", "d" } }); + sol::table t = lua["t"]; + REQUIRE(t["a"] == std::string("b")); + REQUIRE(t["c"] == std::string("d")); + { + sol::stack_guard clearsg(lua); + sol::stack::clear(t); + } + REQUIRE(!t["a"].valid()); + REQUIRE(!t["c"].valid()); + } + SECTION("with index") { + sol::stack_guard luasg(lua); + lua["t"] = sol::lua_value({ { "a", "b" }, { "c", "d" } }); + sol::table t = lua["t"]; + REQUIRE(t["a"] == std::string("b")); + REQUIRE(t["c"] == std::string("d")); + { + sol::stack_guard ppclearsg(lua); + auto pp = sol::stack::push_pop(t); + int table_index = pp.index_of(t); + { + sol::stack_guard clearsg(lua); + sol::stack::clear(lua, table_index); + } + } + REQUIRE(!t["a"].valid()); + REQUIRE(!t["c"].valid()); + } +} diff --git a/tests/runtime_tests/source/usertypes.unregister.cpp b/tests/runtime_tests/source/usertypes.unregister.cpp new file mode 100644 index 00000000..3302b8e3 --- /dev/null +++ b/tests/runtime_tests/source/usertypes.unregister.cpp @@ -0,0 +1,147 @@ +// sol3 + +// The MIT License (MIT) + +// Copyright (c) 2013-2019 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. + +#include "sol_test.hpp" + +#include + +struct unregister_me { + double b = 5.5; + std::string f_val = "registered"; + + unregister_me() { + } + + std::string f() { + return f_val; + } +}; + +TEST_CASE("usertypes/unregister", "make sure that a class can still be bound but that it becomes completely unregistered") { + const sol::string_view line1 = "assert(u:f() == 'registered')"; + const sol::string_view line2 = "assert(urm.a() == 20)"; + const sol::string_view line3 = "assert(u.a() == 20) assert(u:a() == 20)"; + const sol::string_view line4 = "assert(u.b == 5.5)"; + + sol::state lua; + lua.open_libraries(); + auto register_urm = [&lua, &line1, &line2, &line3, &line4]() { + lua.new_usertype("urm", "f", &unregister_me::f, "a", []() { return 20; }, "b", &unregister_me::b); + { + sol::object urm_obj = lua["urm"]; + REQUIRE(urm_obj.get_type() == sol::type::table); + REQUIRE(urm_obj.is()); + REQUIRE(urm_obj.is()); + REQUIRE(urm_obj.is>()); + } + + lua["urm_unregister"] = [](sol::this_state ts) { + sol::state_view current_lua = ts; + sol::usertype urm = current_lua["urm"]; + urm.unregister(); + }; + + auto sresult0 = lua.safe_script("u = urm.new()", sol::script_pass_on_error); + REQUIRE(sresult0.valid()); + auto sresult1 = lua.safe_script(line1, sol::script_pass_on_error); + REQUIRE(sresult1.valid()); + auto sresult2 = lua.safe_script(line2, sol::script_pass_on_error); + REQUIRE(sresult2.valid()); + auto sresult3 = lua.safe_script(line3, sol::script_pass_on_error); + REQUIRE(sresult3.valid()); + auto sresult4 = lua.safe_script(line4, sol::script_pass_on_error); + REQUIRE(sresult4.valid()); + + unregister_me& u_orig = lua["u"]; + REQUIRE(u_orig.b == 5.5); + REQUIRE(u_orig.f() == "registered"); + }; + SECTION("unregister C++") { + register_urm(); + + { + sol::usertype urm = lua["urm"]; + urm.unregister(); + } + + auto result0 = lua.safe_script("u_fail = urm.new()", sol::script_pass_on_error); + REQUIRE_FALSE(result0.valid()); + auto result1 = lua.safe_script(line1, sol::script_pass_on_error); + REQUIRE_FALSE(result1.valid()); + auto result2 = lua.safe_script(line2, sol::script_pass_on_error); + REQUIRE_FALSE(result2.valid()); + auto result3 = lua.safe_script(line3, sol::script_pass_on_error); + REQUIRE_FALSE(result3.valid()); + auto result4 = lua.safe_script(line4, sol::script_pass_on_error); + REQUIRE_FALSE(result4.valid()); + + unregister_me& u = lua["u"]; + REQUIRE(u.b == 5.5); + REQUIRE(u.f() == "registered"); + } + SECTION("re-register") { + register_urm(); + + sol::protected_function urm_unregister_func = lua["urm_unregister"]; + auto unregister_result = urm_unregister_func(); + REQUIRE(unregister_result.valid()); + + auto result0 = lua.safe_script("u_fail2 = urm.new()", sol::script_pass_on_error); + REQUIRE_FALSE(result0.valid()); + auto result1 = lua.safe_script(line1, sol::script_pass_on_error); + REQUIRE_FALSE(result1.valid()); + auto result2 = lua.safe_script(line2, sol::script_pass_on_error); + REQUIRE_FALSE(result2.valid()); + auto result3 = lua.safe_script(line3, sol::script_pass_on_error); + REQUIRE_FALSE(result3.valid()); + auto result4 = lua.safe_script(line4, sol::script_pass_on_error); + REQUIRE_FALSE(result4.valid()); + + unregister_me& u = lua["u"]; + REQUIRE(u.b == 5.5); + REQUIRE(u.f() == "registered"); + + register_urm(); + } + SECTION("unregister lua") { + register_urm(); + + auto unregister_result = lua.safe_script("urm_unregister()", sol::script_pass_on_error); + REQUIRE(unregister_result.valid()); + + auto result0 = lua.safe_script("u_fail2 = urm.new()", sol::script_pass_on_error); + REQUIRE_FALSE(result0.valid()); + auto result1 = lua.safe_script(line1, sol::script_pass_on_error); + REQUIRE_FALSE(result1.valid()); + auto result2 = lua.safe_script(line2, sol::script_pass_on_error); + REQUIRE_FALSE(result2.valid()); + auto result3 = lua.safe_script(line3, sol::script_pass_on_error); + REQUIRE_FALSE(result3.valid()); + auto result4 = lua.safe_script(line4, sol::script_pass_on_error); + REQUIRE_FALSE(result4.valid()); + + unregister_me& u = lua["u"]; + REQUIRE(u.b == 5.5); + REQUIRE(u.f() == "registered"); + } +}