Tentatively supports (?) #589 with sol::yielding and sol::yielding_t
Added Catch as a cmake module
This commit is contained in:
ThePhD 2018-02-17 00:18:26 -05:00
parent eca9ec46fd
commit 67116a67f9
18 changed files with 616 additions and 198 deletions

View File

@ -69,29 +69,25 @@ endif()
# # # General project flags # # # General project flags
if (MSVC) if (MSVC)
add_definitions(/DUNICODE /D_UNICODE /D_SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING /D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING /D_CRT_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_DEPRECATE) add_definitions(/DUNICODE /D_UNICODE /D_CRT_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_DEPRECATE)
# Warning level, exceptions # Warning level, exceptions
add_compile_options(/W4 /EHsc) add_compile_options(/W4 /EHsc)
if (NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") if (NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(/MP) add_compile_options(/MP)
endif() endif()
else() else()
if (IS_X86)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
endif()
add_compile_options(-Wno-unknown-warning -Wno-unknown-warning-option -Wall -Wextra -Wpedantic -pedantic -pedantic-errors) add_compile_options(-Wno-unknown-warning -Wno-unknown-warning-option -Wall -Wextra -Wpedantic -pedantic -pedantic-errors)
endif() endif()
# # # General project output locations # # # General project output locations
if (IS_X86 OR CMAKE_SIZEOF_VOID_P EQUAL 4) if (IS_X86 OR CMAKE_SIZEOF_VOID_P EQUAL 4)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/x86/lib") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x86/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/x86/bin") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x86/bin")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/x86/bin") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x86/bin")
else() else()
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/x64/lib") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x64/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/x64/bin") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x64/bin")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/x64/bin") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x64/bin")
endif() endif()
# # # Modules # # # Modules

View File

@ -47,6 +47,8 @@ environment:
# apparently, I can't quite make LLVM work right now... # apparently, I can't quite make LLVM work right now...
#- LUA_VERSION: 5.3.4 #- LUA_VERSION: 5.3.4
# LLVM_VERSION: 4.0.0 # LLVM_VERSION: 4.0.0
- LUA_VERSION: 5.3.4
MINGW_VERSION: 7.2.0
- LUA_VERSION: 5.3.4 - LUA_VERSION: 5.3.4
MINGW_VERSION: 6.3.0 MINGW_VERSION: 6.3.0
- LUA_VERSION: luajit-2.0.5 - LUA_VERSION: luajit-2.0.5
@ -56,8 +58,8 @@ environment:
- LUA_VERSION: 5.3.4 - LUA_VERSION: 5.3.4
- LUA_VERSION: 5.2.4 - LUA_VERSION: 5.2.4
- LUA_VERSION: 5.1.5 - LUA_VERSION: 5.1.5
#- LUA_VERSION: luajit-2.0.5 - LUA_VERSION: luajit-2.0.5
#- LUA_VERSION: luajit-2.1.0-beta3 - LUA_VERSION: luajit-2.1.0-beta3
matrix: matrix:
allow_failures: allow_failures:
@ -82,6 +84,8 @@ matrix:
LUA_VERSION: 5.2.4 LUA_VERSION: 5.2.4
- platform: x86 - platform: x86
LUA_VERSION: 5.1.5 LUA_VERSION: 5.1.5
- platform: x86
MINGW_VERSION: 7.2.0
# Get rid of redundant Visual Studio 2015 builds # Get rid of redundant Visual Studio 2015 builds
- image: Visual Studio 2015 - image: Visual Studio 2015
LUA_VERSION: 5.1.5 LUA_VERSION: 5.1.5
@ -107,6 +111,7 @@ init:
- set llvm_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%"=="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%"=="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%"=="6.3.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 "%LLVM_VERSION%"=="4.0.0" (set llvm_path=C:\Program Files\LLVM\bin)
- if "%PLATFORM%"=="x64" (set python_path=C:\Python36-x64) - if "%PLATFORM%"=="x64" (set python_path=C:\Python36-x64)
- set PATH=%python_path%;%PATH% - set PATH=%python_path%;%PATH%
@ -128,6 +133,7 @@ init:
- 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 "%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%"=="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%"=="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 "%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)
# # Last printouts # # Last printouts
# print out generator information # print out generator information

View File

@ -0,0 +1,79 @@
# # # # sol2
# The MIT License (MIT)
#
# Copyright (c) 2013-2017 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(ExternalProject)
include(FindPackageHandleStandardArgs)
include(Common/Core)
# # Base variables
if (CATCH_VERSION)
set(catch_version ${CATCH_VERSION})
else()
set(catch_version 2.0.1)
endif()
set(catch_lib catch_lib_${catch_version})
# # Useful locations
set(catch_build_toplevel "${CMAKE_BINARY_DIR}/vendor/catch_${catch_version}")
set(catch_include_dirs "${catch_build_toplevel}")
# # catch library sources
set(catch_sources catch.hpp)
prepend(catch_sources "${catch_build_toplevel}/" ${catch_sources})
# # External project to get sources
ExternalProject_Add(CATCH_BUILD_SOURCE
BUILD_IN_SOURCE TRUE
BUILD_ALWAYS FALSE
DOWNLOAD_NO_EXTRACT TRUE
URL https://github.com/catchorg/Catch2/releases/download/v${catch_version}/catch.hpp
TLS_VERIFY TRUE
PREFIX ${catch_build_toplevel}
SOURCE_DIR ${catch_build_toplevel}
DOWNLOAD_DIR ${catch_build_toplevel}
TMP_DIR "${catch_build_toplevel}-tmp"
STAMP_DIR "${catch_build_toplevel}-stamp"
INSTALL_DIR "${catch_build_toplevel}/local"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
BUILD_BYPRODUCTS "${catch_sources}")
add_library(${catch_lib} INTERFACE)
add_dependencies(${catch_lib} CATCH_BUILD_SOURCE)
target_include_directories(${catch_lib} INTERFACE ${catch_include_dirs})
if (MSVC)
target_add_compile_options(${catch_lib} INTERFACE
/D_SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING)
endif()
set(CATCH_FOUND TRUE)
set(CATCH_LIBRARIES ${catch_lib})
set(CATCH_INCLUDE_DIRS ${catch_include_dirs})
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Catch
FOUND_VAR CATCH_FOUND
REQUIRED_VARS CATCH_LIBRARIES CATCH_INCLUDE_DIRS
VERSION_VAR catch_version)

View File

@ -285,11 +285,9 @@ set_target_properties(${liblua}
LIBRARY_OUTPUT_NAME ${LUA_BUILD_LIBNAME} LIBRARY_OUTPUT_NAME ${LUA_BUILD_LIBNAME}
ARCHIVE_OUTPUT_NAME ${LUA_BUILD_LIBNAME}) ARCHIVE_OUTPUT_NAME ${LUA_BUILD_LIBNAME})
target_include_directories(${liblua} target_include_directories(${liblua}
PRIVATE ${LUA_VANILLA_SOURCE_DIR}
PUBLIC ${LUA_VANILLA_SOURCE_DIR}) PUBLIC ${LUA_VANILLA_SOURCE_DIR})
target_compile_definitions(${liblua} target_compile_definitions(${liblua}
PUBLIC LUA_COMPAT_ALL ${LUA_VANILLA_DLL_DEFINE} PUBLIC LUA_COMPAT_ALL ${LUA_VANILLA_DLL_DEFINE})
PRIVATE LUA_COMPAT_ALL ${LUA_VANILLA_DLL_DEFINE})
if (MSVC) if (MSVC)
target_compile_options(${liblua} target_compile_options(${liblua}
PRIVATE /W1) PRIVATE /W1)
@ -298,8 +296,8 @@ else()
PRIVATE -w) PRIVATE -w)
endif() endif()
if (WIN32) if (WIN32)
#target_compile_definitions(${liblua} target_compile_definitions(${liblua}
# PRIVATE LUA_USE_WINDOWS) PRIVATE LUA_USE_WINDOWS)
else() else()
target_compile_definitions(${liblua} target_compile_definitions(${liblua}
PRIVATE LUA_USE_LINUX) PRIVATE LUA_USE_LINUX)

View File

@ -65,9 +65,17 @@ function(make_require_from_dll_example target_lib is_single)
target_link_libraries(${example_lib_name} PRIVATE ${LUA_LIBRARIES}) target_link_libraries(${example_lib_name} PRIVATE ${LUA_LIBRARIES})
endif() endif()
else() else()
target_link_libraries(${example_lib_name} PUBLIC ${LUA_LIBRARIES}) if (lua_lib_type MATCHES "STATIC")
target_link_libraries(${example_lib_name} PRIVATE ${LUA_LIBRARIES})
set_target_properties(${example_lib_name} PROPERTIES
WINDOWS_EXPORT_ALL_SYMBOLS TRUE
LINK_FLAGS "/OPT:NOREF /WHOLEARCHIVE:lua-5.2.4.lib")
else()
target_link_libraries(${example_lib_name} PRIVATE ${LUA_LIBRARIES})
endif()
endif() endif()
target_link_libraries(${example_lib_name} PRIVATE ${target_lib}) target_link_libraries(${example_lib_name} PRIVATE ${target_lib})
target_include_directories(${example_lib_name} PUBLIC "${LUA_INCLUDE_DIRS}")
# add executable target that represents require_from_dll program # add executable target that represents require_from_dll program
add_executable(${example_name} ${require_from_dll_sources}) add_executable(${example_name} ${require_from_dll_sources})

View File

@ -28,10 +28,15 @@
#include "stack.hpp" #include "stack.hpp"
#include "function_result.hpp" #include "function_result.hpp"
#include "thread.hpp" #include "thread.hpp"
#include "protected_handler.hpp"
namespace sol { namespace sol {
template <typename base_t> template <typename base_t>
class basic_coroutine : public base_t { class basic_coroutine : public base_t {
public:
typedef reference handler_t;
handler_t error_handler;
private: private:
call_status stats = call_status::yielded; call_status stats = call_status::yielded;
@ -59,53 +64,130 @@ namespace sol {
protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) { protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) {
int firstreturn = 1; int firstreturn = 1;
luacall(n, LUA_MULTRET); luacall(n, LUA_MULTRET);
int poststacksize = lua_gettop(lua_state()); int poststacksize = lua_gettop(this->lua_state());
int returncount = poststacksize - (firstreturn - 1); int returncount = poststacksize - (firstreturn - 1);
if (error()) { if (error()) {
return protected_function_result(lua_state(), lua_absindex(lua_state(), -1), 1, returncount, status()); if (error_handler.valid()) {
string_view err = stack::get<string_view>(this->lua_state(), poststacksize);
error_handler.push();
stack::push(this->lua_state(), err);
lua_call(lua_state(), 1, 1);
} }
return protected_function_result(lua_state(), firstreturn, returncount, returncount, status()); return protected_function_result(this->lua_state(), lua_absindex(this->lua_state(), -1), 1, returncount, status());
}
return protected_function_result(this->lua_state(), firstreturn, returncount, returncount, status());
} }
public: public:
using base_t::lua_state; using base_t::lua_state;
basic_coroutine() noexcept = default; basic_coroutine() = default;
basic_coroutine(const basic_coroutine&) noexcept = default; template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_coroutine>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>>, meta::neg<std::is_same<base_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_coroutine(basic_coroutine&&) noexcept = default; basic_coroutine(T&& r) noexcept
basic_coroutine& operator=(const basic_coroutine&) noexcept = default; : base_t(std::forward<T>(r)), error_handler(detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) {
basic_coroutine& operator=(basic_coroutine&&) noexcept = default; #ifdef SOL_SAFE_REFERENCES
template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_coroutine>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> if (!is_function<meta::unqualified_t<T>>::value) {
basic_coroutine(T&& r) auto pp = stack::push_pop(*this);
: base_t(std::forward<T>(r)) { constructor_handler handler{};
stack::check<basic_coroutine>(lua_state(), -1, handler);
} }
basic_coroutine(lua_nil_t r) #endif // Safety
: base_t(r) {
} }
basic_coroutine(const stack_reference& r) noexcept basic_coroutine(const basic_coroutine&) = default;
: basic_coroutine(r.lua_state(), r.stack_index()) { basic_coroutine& operator=(const basic_coroutine&) = default;
basic_coroutine(basic_coroutine&&) = default;
basic_coroutine& operator=(basic_coroutine&&) = default;
basic_coroutine(const basic_function<base_t>& b)
: basic_coroutine(b, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(b.lua_state())) {
} }
basic_coroutine(stack_reference&& r) noexcept basic_coroutine(basic_function<base_t>&& b)
: basic_coroutine(r.lua_state(), r.stack_index()) { : basic_coroutine(std::move(b), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(b.lua_state())) {
} }
basic_coroutine(const basic_function<base_t>& b, handler_t eh)
: base_t(b), error_handler(std::move(eh)) {
}
basic_coroutine(basic_function<base_t>&& b, handler_t eh)
: base_t(std::move(b)), error_handler(std::move(eh)) {
}
basic_coroutine(const stack_reference& r)
: basic_coroutine(r.lua_state(), r.stack_index(), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) {
}
basic_coroutine(stack_reference&& r)
: basic_coroutine(r.lua_state(), r.stack_index(), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) {
}
basic_coroutine(const stack_reference& r, handler_t eh)
: basic_coroutine(r.lua_state(), r.stack_index(), std::move(eh)) {
}
basic_coroutine(stack_reference&& r, handler_t eh)
: basic_coroutine(r.lua_state(), r.stack_index(), std::move(eh)) {
}
template <typename Super>
basic_coroutine(const proxy_base<Super>& p)
: basic_coroutine(p, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(p.lua_state())) {
}
template <typename Super>
basic_coroutine(proxy_base<Super>&& p)
: basic_coroutine(std::move(p), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(p.lua_state())) {
}
template <typename Proxy, typename Handler, meta::enable<std::is_base_of<proxy_base_tag, meta::unqualified_t<Proxy>>, meta::neg<is_lua_index<meta::unqualified_t<Handler>>>> = meta::enabler>
basic_coroutine(Proxy&& p, Handler&& eh)
: basic_coroutine(detail::force_cast<base_t>(p), std::forward<Handler>(eh)) {
}
template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_coroutine(lua_State* L, T&& r) basic_coroutine(lua_State* L, T&& r)
: base_t(L, std::forward<T>(r)) { : basic_coroutine(L, std::forward<T>(r), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) {
}
template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_coroutine(lua_State* L, T&& r, handler_t eh)
: base_t(L, std::forward<T>(r)), error_handler(std::move(eh)) {
#ifdef SOL_SAFE_REFERENCES #ifdef SOL_SAFE_REFERENCES
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
constructor_handler handler{}; constructor_handler handler{};
stack::check<basic_coroutine>(lua_state(), -1, handler); stack::check<basic_coroutine>(lua_state(), -1, handler);
#endif // Safety #endif // Safety
} }
basic_coroutine(lua_nil_t n)
: base_t(n), error_handler(n) {
}
basic_coroutine(lua_State* L, int index = -1) basic_coroutine(lua_State* L, int index = -1)
: base_t(L, index) { : basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) {
}
basic_coroutine(lua_State* L, int index, handler_t eh)
: base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_SAFE_REFERENCES #ifdef SOL_SAFE_REFERENCES
constructor_handler handler{}; constructor_handler handler{};
stack::check<basic_coroutine>(lua_state(), index, handler); stack::check<basic_coroutine>(L, index, handler);
#endif // Safety
}
basic_coroutine(lua_State* L, absolute_index index)
: basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) {
}
basic_coroutine(lua_State* L, absolute_index index, handler_t eh)
: base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_SAFE_REFERENCES
constructor_handler handler{};
stack::check<basic_coroutine>(L, index, handler);
#endif // Safety
}
basic_coroutine(lua_State* L, raw_index index)
: basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) {
}
basic_coroutine(lua_State* L, raw_index index, handler_t eh)
: base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_SAFE_REFERENCES
constructor_handler handler{};
stack::check<basic_coroutine>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_coroutine(lua_State* L, ref_index index) basic_coroutine(lua_State* L, ref_index index)
: base_t(L, index) { : basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) {
}
basic_coroutine(lua_State* L, ref_index index, handler_t eh)
: base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_SAFE_REFERENCES #ifdef SOL_SAFE_REFERENCES
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
constructor_handler handler{}; constructor_handler handler{};

View File

@ -39,50 +39,51 @@ namespace sol {
struct call_indicator {}; struct call_indicator {};
} // namespace function_detail } // namespace function_detail
namespace stack { namespace stack {
template <typename... Sigs> template <typename... Sigs>
struct pusher<function_sig<Sigs...>> { struct pusher<function_sig<Sigs...>> {
template <typename... Sig, typename Fx, typename... Args> template <bool is_yielding, typename... Sig, typename Fx, typename... Args>
static void select_convertible(std::false_type, types<Sig...>, lua_State* L, Fx&& fx, Args&&... args) { static void select_convertible(std::false_type, types<Sig...>, lua_State* L, Fx&& fx, Args&&... args) {
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx; typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
typedef function_detail::functor_function<clean_fx> F; typedef function_detail::functor_function<clean_fx, is_yielding> F;
set_fx<F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <typename R, typename... A, typename Fx, typename... Args> template <bool is_yielding, typename R, typename... A, typename Fx, typename... Args>
static void select_convertible(std::true_type, types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) { static void select_convertible(std::true_type, types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) {
using fx_ptr_t = R (*)(A...); using fx_ptr_t = R (*)(A...);
fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx)); fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx));
select_function(std::true_type(), L, fxptr, std::forward<Args>(args)...); select_function<is_yielding>(std::true_type(), L, fxptr, std::forward<Args>(args)...);
} }
template <typename R, typename... A, typename Fx, typename... Args> template <bool is_yielding, typename R, typename... A, typename Fx, typename... Args>
static void select_convertible(types<R(A...)> t, lua_State* L, Fx&& fx, Args&&... args) { static void select_convertible(types<R(A...)> t, lua_State* L, Fx&& fx, Args&&... args) {
typedef std::decay_t<meta::unwrap_unqualified_t<Fx>> raw_fx_t; typedef std::decay_t<meta::unwrap_unqualified_t<Fx>> raw_fx_t;
typedef R (*fx_ptr_t)(A...); typedef R (*fx_ptr_t)(A...);
typedef std::is_convertible<raw_fx_t, fx_ptr_t> is_convertible; typedef std::is_convertible<raw_fx_t, fx_ptr_t> is_convertible;
select_convertible(is_convertible(), t, L, std::forward<Fx>(fx), std::forward<Args>(args)...); select_convertible<is_yielding>(is_convertible(), t, L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <typename Fx, typename... Args> template <bool is_yielding, typename Fx, typename... Args>
static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) {
typedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig; typedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig;
select_convertible(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); select_convertible<is_yielding>(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <typename Fx, typename T, typename... Args> template <bool is_yielding, typename Fx, typename T, typename... Args>
static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx; typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
typedef function_detail::member_variable<meta::unwrap_unqualified_t<T>, clean_fx> F; typedef function_detail::member_variable<meta::unwrap_unqualified_t<T>, clean_fx, is_yielding> F;
set_fx<F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...); set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
} }
template <typename Fx, typename T, typename... Args> template <bool is_yielding, typename Fx, typename T, typename... Args>
static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef std::decay_t<Fx> dFx; typedef std::decay_t<Fx> dFx;
dFx memfxptr(std::forward<Fx>(fx)); dFx memfxptr(std::forward<Fx>(fx));
auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...); auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call; lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call;
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
@ -91,49 +92,51 @@ namespace sol {
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
template <typename Fx, typename... Args> template <bool is_yielding, typename Fx, typename... Args>
static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
select_convertible(types<Sigs...>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); select_convertible<is_yielding>(types<Sigs...>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <typename Fx, typename T, typename... Args, meta::disable<meta::is_specialization_of<function_detail::class_indicator, meta::unqualified_t<T>>> = meta::enabler> template <bool is_yielding, typename Fx, typename T, typename... Args, meta::disable<meta::is_specialization_of<function_detail::class_indicator, meta::unqualified_t<T>>> = meta::enabler>
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference; typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference;
select_reference_member_variable(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...); select_reference_member_variable<is_yielding>(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
} }
template <typename Fx, typename C> template <bool is_yielding, typename Fx, typename C>
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) { static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) {
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::call; lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx, is_yielding>::call;
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx); upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
template <typename Fx> template <bool is_yielding, typename Fx>
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) { static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) {
typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C; typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::call; lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx, is_yielding>::call;
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx); upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
template <typename Fx, typename T, typename... Args> template <bool is_yielding, typename Fx, typename T, typename... Args>
static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef std::decay_t<Fx> clean_fx; typedef std::decay_t<Fx> clean_fx;
typedef function_detail::member_function<meta::unwrap_unqualified_t<T>, clean_fx> F; typedef function_detail::member_function<meta::unwrap_unqualified_t<T>, clean_fx, is_yielding> F;
set_fx<F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...); set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
} }
template <typename Fx, typename T, typename... Args> template <bool is_yielding, typename Fx, typename T, typename... Args>
static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef std::decay_t<Fx> dFx; typedef std::decay_t<Fx> dFx;
dFx memfxptr(std::forward<Fx>(fx)); dFx memfxptr(std::forward<Fx>(fx));
auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...); auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call; lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call;
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
@ -142,45 +145,47 @@ namespace sol {
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
template <typename Fx, typename... Args> template <bool is_yielding, typename Fx, typename... Args>
static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
select_member_variable(meta::is_member_object<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); select_member_variable<is_yielding>(meta::is_member_object<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <typename Fx, typename T, typename... Args, meta::disable<meta::is_specialization_of<function_detail::class_indicator, meta::unqualified_t<T>>> = meta::enabler> template <bool is_yielding, typename Fx, typename T, typename... Args, meta::disable<meta::is_specialization_of<function_detail::class_indicator, meta::unqualified_t<T>>> = meta::enabler>
static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference; typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference;
select_reference_member_function(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...); select_reference_member_function<is_yielding>(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
} }
template <typename Fx, typename C> template <bool is_yielding, typename Fx, typename C>
static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) { static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) {
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx>::call; lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx, is_yielding>::call;
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx); upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
template <typename Fx> template <bool is_yielding, typename Fx>
static void select_member_function(std::true_type, lua_State* L, Fx&& fx) { static void select_member_function(std::true_type, lua_State* L, Fx&& fx) {
typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C; typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx>::call; lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx, is_yielding>::call;
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx); upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
template <typename Fx, typename... Args> template <bool is_yielding, typename Fx, typename... Args>
static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
select_member_function(std::is_member_function_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); select_member_function<is_yielding>(std::is_member_function_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <typename Fx, typename... Args> template <bool is_yielding, typename Fx, typename... Args>
static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) { static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) {
std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...); std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...);
lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx>::call; lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx, is_yielding>::call;
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
@ -188,29 +193,34 @@ namespace sol {
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
template <bool is_yielding>
static void select_function(std::true_type, lua_State* L, lua_CFunction f) { static void select_function(std::true_type, lua_State* L, lua_CFunction f) {
// TODO: support yielding
stack::push(L, f); stack::push(L, f);
} }
#ifdef SOL_NOEXCEPT_FUNCTION_TYPE #ifdef SOL_NOEXCEPT_FUNCTION_TYPE
template <bool is_yielding>
static void select_function(std::true_type, lua_State* L, detail::lua_CFunction_noexcept f) { static void select_function(std::true_type, lua_State* L, detail::lua_CFunction_noexcept f) {
// TODO: support yielding
stack::push(L, f); stack::push(L, f);
} }
#endif // noexcept function type #endif // noexcept function type
template <typename Fx, typename... Args, meta::disable<is_lua_reference<meta::unqualified_t<Fx>>> = meta::enabler> template <bool is_yielding, typename Fx, typename... Args, meta::disable<is_lua_reference<meta::unqualified_t<Fx>>> = meta::enabler>
static void select(lua_State* L, Fx&& fx, Args&&... args) { static void select(lua_State* L, Fx&& fx, Args&&... args) {
select_function(std::is_function<std::remove_pointer_t<meta::unqualified_t<Fx>>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); select_function<is_yielding>(std::is_function<std::remove_pointer_t<meta::unqualified_t<Fx>>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <typename Fx, meta::enable<is_lua_reference<meta::unqualified_t<Fx>>> = meta::enabler> template <bool is_yielding, typename Fx, meta::enable<is_lua_reference<meta::unqualified_t<Fx>>> = meta::enabler>
static void select(lua_State* L, Fx&& fx) { static void select(lua_State* L, Fx&& fx) {
// TODO: hoist into lambda in this case??
stack::push(L, std::forward<Fx>(fx)); stack::push(L, std::forward<Fx>(fx));
} }
template <typename Fx, typename... Args> template <bool is_yielding, typename Fx, typename... Args>
static void set_fx(lua_State* L, Args&&... args) { static void set_fx(lua_State* L, Args&&... args) {
lua_CFunction freefunc = function_detail::call<meta::unqualified_t<Fx>, 2>; lua_CFunction freefunc = function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding>;
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
@ -218,12 +228,36 @@ namespace sol {
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
template <typename... Args> template <typename Arg0, typename... Args, meta::disable<std::is_same<detail::yield_tag_t, meta::unqualified_t<Arg0>>> = meta::enabler>
static int push(lua_State* L, Args&&... args) { static int push(lua_State* L, Arg0&& arg0, Args&&... args) {
// Set will always place one thing (function) on the stack // Set will always place one thing (function) on the stack
select(L, std::forward<Args>(args)...); select<false>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...);
return 1; return 1;
} }
template <typename... Args>
static int push(lua_State* L, detail::yield_tag_t, Args&&... args) {
// Set will always place one thing (function) on the stack
select<true>(L, std::forward<Args>(args)...);
return 1;
}
};
template <typename T>
struct pusher<yielding_t<T>> {
template <typename... Args>
static int push(lua_State* L, const yielding_t<T>& f, Args&&... args) {
pusher<function_sig<>> p{};
(void)p;
return p.push(L, detail::yield_tag, f.func, std::forward<Args>(args)...);
}
template <typename... Args>
static int push(lua_State* L, yielding_t<T>&& f, Args&&... args) {
pusher<function_sig<>> p{};
(void)p;
return p.push(L, detail::yield_tag, f.func, std::forward<Args>(args)...);
}
}; };
template <typename T, typename... Args> template <typename T, typename... Args>
@ -257,7 +291,9 @@ namespace sol {
struct pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> { struct pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> {
template <typename F, typename... Args> template <typename F, typename... Args>
static int push(lua_State* L, F&& f, Args&&... args) { static int push(lua_State* L, F&& f, Args&&... args) {
return pusher<function_sig<>>{}.push(L, std::forward<F>(f), std::forward<Args>(args)...); pusher<function_sig<>> p{};
(void)p;
return p.push(L, std::forward<F>(f), std::forward<Args>(args)...);
} }
}; };
@ -352,25 +388,25 @@ namespace sol {
struct pusher<factory_wrapper<Functions...>> { struct pusher<factory_wrapper<Functions...>> {
static int push(lua_State* L, const factory_wrapper<Functions...>& fw) { static int push(lua_State* L, const factory_wrapper<Functions...>& fw) {
typedef function_detail::overloaded_function<0, Functions...> F; typedef function_detail::overloaded_function<0, Functions...> F;
pusher<function_sig<>>{}.set_fx<F>(L, fw.functions); pusher<function_sig<>>{}.set_fx<false, F>(L, fw.functions);
return 1; return 1;
} }
static int push(lua_State* L, factory_wrapper<Functions...>&& fw) { static int push(lua_State* L, factory_wrapper<Functions...>&& fw) {
typedef function_detail::overloaded_function<0, Functions...> F; typedef function_detail::overloaded_function<0, Functions...> F;
pusher<function_sig<>>{}.set_fx<F>(L, std::move(fw.functions)); pusher<function_sig<>>{}.set_fx<false, F>(L, std::move(fw.functions));
return 1; return 1;
} }
static int push(lua_State* L, const factory_wrapper<Functions...>& set, function_detail::call_indicator) { static int push(lua_State* L, const factory_wrapper<Functions...>& set, function_detail::call_indicator) {
typedef function_detail::overloaded_function<1, Functions...> F; typedef function_detail::overloaded_function<1, Functions...> F;
pusher<function_sig<>>{}.set_fx<F>(L, set.functions); pusher<function_sig<>>{}.set_fx<false, F>(L, set.functions);
return 1; return 1;
} }
static int push(lua_State* L, factory_wrapper<Functions...>&& set, function_detail::call_indicator) { static int push(lua_State* L, factory_wrapper<Functions...>&& set, function_detail::call_indicator) {
typedef function_detail::overloaded_function<1, Functions...> F; typedef function_detail::overloaded_function<1, Functions...> F;
pusher<function_sig<>>{}.set_fx<F>(L, std::move(set.functions)); pusher<function_sig<>>{}.set_fx<false, F>(L, std::move(set.functions));
return 1; return 1;
} }
}; };

View File

@ -30,10 +30,16 @@
namespace sol { namespace sol {
namespace function_detail { namespace function_detail {
template <typename Fx, int start = 1> template <typename Fx, int start = 1, bool is_yielding = false>
inline int call(lua_State* L) { inline int call(lua_State* L) {
Fx& fx = stack::get<user<Fx>>(L, upvalue_index(start)); Fx& fx = stack::get<user<Fx>>(L, upvalue_index(start));
return fx(L); int nr = fx(L);
if (is_yielding) {
return lua_yield(L, nr);
}
else {
return nr;
}
} }
} }
} // namespace sol::function_detail } // namespace sol::function_detail

View File

@ -28,7 +28,7 @@
namespace sol { namespace sol {
namespace function_detail { namespace function_detail {
template <typename Func> template <typename Func, bool is_yielding>
struct functor_function { struct functor_function {
typedef std::decay_t<meta::unwrap_unqualified_t<Func>> function_type; typedef std::decay_t<meta::unwrap_unqualified_t<Func>> function_type;
function_type fx; function_type fx;
@ -39,7 +39,13 @@ namespace function_detail {
} }
int call(lua_State* L) { int call(lua_State* L) {
return call_detail::call_wrapped<void, true, false>(L, fx); int nr = call_detail::call_wrapped<void, true, false>(L, fx);
if (is_yielding) {
return lua_yield(L, nr);
}
else {
return nr;
}
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
@ -48,7 +54,7 @@ namespace function_detail {
} }
}; };
template <typename T, typename Function> template <typename T, typename Function, bool is_yielding>
struct member_function { struct member_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef meta::function_return_t<function_type> return_type; typedef meta::function_return_t<function_type> return_type;
@ -62,7 +68,13 @@ namespace function_detail {
} }
int call(lua_State* L) { int call(lua_State* L) {
return call_detail::call_wrapped<T, true, false, -1>(L, invocation, detail::unwrap(detail::deref(member))); int nr = call_detail::call_wrapped<T, true, false, -1>(L, invocation, detail::unwrap(detail::deref(member)));
if (is_yielding) {
return lua_yield(L, nr);
}
else {
return nr;
}
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
@ -71,7 +83,7 @@ namespace function_detail {
} }
}; };
template <typename T, typename Function> template <typename T, typename Function, bool is_yielding>
struct member_variable { struct member_variable {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef typename meta::bind_traits<function_type>::return_type return_type; typedef typename meta::bind_traits<function_type>::return_type return_type;
@ -86,14 +98,23 @@ namespace function_detail {
} }
int call(lua_State* L) { int call(lua_State* L) {
int nr;
{
M mem = detail::unwrap(detail::deref(member)); M mem = detail::unwrap(detail::deref(member));
switch (lua_gettop(L)) { switch (lua_gettop(L)) {
case 0: case 0:
return call_detail::call_wrapped<T, true, false, -1>(L, var, mem); nr = call_detail::call_wrapped<T, true, false, -1>(L, var, mem);
case 1: case 1:
return call_detail::call_wrapped<T, false, false, -1>(L, var, mem); nr = call_detail::call_wrapped<T, false, false, -1>(L, var, mem);
default: default:
return luaL_error(L, "sol: incorrect number of arguments to member variable function"); nr = luaL_error(L, "sol: incorrect number of arguments to member variable function");
}
}
if (is_yielding) {
return lua_yield(L, nr);
}
else {
return nr;
} }
} }

View File

@ -28,7 +28,7 @@
namespace sol { namespace sol {
namespace function_detail { namespace function_detail {
template <typename Function> template <typename Function, bool is_yielding>
struct upvalue_free_function { struct upvalue_free_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef meta::bind_traits<function_type> traits_type; typedef meta::bind_traits<function_type> traits_type;
@ -40,7 +40,13 @@ namespace function_detail {
} }
static int call(lua_State* L) { static int call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
if (is_yielding) {
return lua_yield(L, nr);
}
else {
return nr;
}
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
@ -48,7 +54,7 @@ namespace function_detail {
} }
}; };
template <typename T, typename Function> template <typename T, typename Function, bool is_yielding>
struct upvalue_member_function { struct upvalue_member_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type; typedef lua_bind_traits<function_type> traits_type;
@ -67,7 +73,13 @@ namespace function_detail {
} }
static int call(lua_State* L) { static int call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
if (is_yielding) {
return lua_yield(L, nr);
}
else {
return nr;
}
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
@ -75,7 +87,7 @@ namespace function_detail {
} }
}; };
template <typename T, typename Function> template <typename T, typename Function, bool is_yielding>
struct upvalue_member_variable { struct upvalue_member_variable {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type; typedef lua_bind_traits<function_type> traits_type;
@ -101,7 +113,13 @@ namespace function_detail {
} }
static int call(lua_State* L) { static int call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
if (is_yielding) {
return lua_yield(L, nr);
}
else {
return nr;
}
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
@ -109,8 +127,8 @@ namespace function_detail {
} }
}; };
template <typename T, typename Function> template <typename T, typename Function, bool is_yielding>
struct upvalue_member_variable<T, readonly_wrapper<Function>> { struct upvalue_member_variable<T, readonly_wrapper<Function>, is_yielding> {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type; typedef lua_bind_traits<function_type> traits_type;
@ -133,7 +151,13 @@ namespace function_detail {
} }
static int call(lua_State* L) { static int call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
if (is_yielding) {
return lua_yield(L, nr);
}
else {
return nr;
}
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
@ -141,7 +165,7 @@ namespace function_detail {
} }
}; };
template <typename T, typename Function> template <typename T, typename Function, bool is_yielding>
struct upvalue_this_member_function { struct upvalue_this_member_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type; typedef lua_bind_traits<function_type> traits_type;
@ -155,7 +179,13 @@ namespace function_detail {
} }
static int call(lua_State* L) { static int call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
if (is_yielding) {
return lua_yield(L, nr);
}
else {
return nr;
}
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
@ -163,7 +193,7 @@ namespace function_detail {
} }
}; };
template <typename T, typename Function> template <typename T, typename Function, bool is_yielding>
struct upvalue_this_member_variable { struct upvalue_this_member_variable {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
@ -183,7 +213,13 @@ namespace function_detail {
} }
static int call(lua_State* L) { static int call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
if (is_yielding) {
return lua_yield(L, nr);
}
else {
return nr;
}
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
@ -191,8 +227,8 @@ namespace function_detail {
} }
}; };
template <typename T, typename Function> template <typename T, typename Function, bool is_yielding>
struct upvalue_this_member_variable<T, readonly_wrapper<Function>> { struct upvalue_this_member_variable<T, readonly_wrapper<Function>, is_yielding> {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type; typedef lua_bind_traits<function_type> traits_type;
@ -210,7 +246,13 @@ namespace function_detail {
} }
static int call(lua_State* L) { static int call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
if (is_yielding) {
return lua_yield(L, nr);
}
else {
return nr;
}
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {

View File

@ -28,86 +28,23 @@
#include "stack.hpp" #include "stack.hpp"
#include "protected_function_result.hpp" #include "protected_function_result.hpp"
#include "unsafe_function.hpp" #include "unsafe_function.hpp"
#include "protected_handler.hpp"
#include <cstdint> #include <cstdint>
#include <algorithm> #include <algorithm>
namespace sol { namespace sol {
namespace detail {
inline const char (&default_handler_name())[9] {
static const char name[9] = "sol.\xF0\x9F\x94\xA9";
return name;
}
template <bool b, typename target_t = reference>
struct protected_handler {
typedef is_stack_based<target_t> is_stack;
const target_t& target;
int stackindex;
protected_handler(std::false_type, const target_t& target)
: target(target), stackindex(0) {
if (b) {
stackindex = lua_gettop(target.lua_state()) + 1;
target.push();
}
}
protected_handler(std::true_type, const target_t& target)
: target(target), stackindex(0) {
if (b) {
stackindex = target.stack_index();
}
}
protected_handler(const target_t& target)
: protected_handler(is_stack(), target) {
}
bool valid() const noexcept {
return b;
}
~protected_handler() {
if (!is_stack::value && stackindex != 0) {
lua_remove(target.lua_state(), stackindex);
}
}
};
template <typename base_t, typename T>
basic_function<base_t> force_cast(T& p) {
return p;
}
} // namespace detail
template <typename base_t, bool aligned = false, typename handler_t = reference> template <typename base_t, bool aligned = false, typename handler_t = reference>
class basic_protected_function : public base_t { class basic_protected_function : public base_t {
public: public:
typedef is_stack_based<handler_t> is_stack_handler; typedef is_stack_based<handler_t> is_stack_handler;
static handler_t get_default_handler(lua_State* L) { static handler_t get_default_handler(lua_State* L) {
if (is_stack_handler::value || L == nullptr) return detail::get_default_handler<handler_t, is_main_threaded<base_t>::value>(L);
return handler_t(L, lua_nil);
L = is_main_threaded<base_t>::value ? main_thread(L, L) : L;
lua_getglobal(L, detail::default_handler_name());
auto pp = stack::pop_n(L, 1);
return handler_t(L, -1);
} }
template <typename T> template <typename T>
static void set_default_handler(const T& ref) { static void set_default_handler(const T& ref) {
if (ref.lua_state() == nullptr) { detail::set_default_handler(ref.lua_state(), ref);
return;
}
lua_State* L = ref.lua_state();
if (!ref.valid()) {
lua_pushnil(L);
lua_setglobal(L, detail::default_handler_name());
}
else {
ref.push();
lua_setglobal(L, detail::default_handler_name());
}
} }
private: private:

108
sol/protected_handler.hpp Normal file
View File

@ -0,0 +1,108 @@
// sol2
// The MIT License (MIT)
// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_PROTECTED_HANDLER_HPP
#define SOL_PROTECTED_HANDLER_HPP
#include "reference.hpp"
#include "stack.hpp"
#include "protected_function_result.hpp"
#include "unsafe_function.hpp"
#include <cstdint>
namespace sol {
namespace detail {
inline const char(&default_handler_name())[9]{
static const char name[9] = "sol.\xF0\x9F\x94\xA9";
return name;
}
template <bool b, typename target_t = reference>
struct protected_handler {
typedef is_stack_based<target_t> is_stack;
const target_t& target;
int stackindex;
protected_handler(std::false_type, const target_t& target)
: target(target), stackindex(0) {
if (b) {
stackindex = lua_gettop(target.lua_state()) + 1;
target.push();
}
}
protected_handler(std::true_type, const target_t& target)
: target(target), stackindex(0) {
if (b) {
stackindex = target.stack_index();
}
}
protected_handler(const target_t& target)
: protected_handler(is_stack(), target) {
}
bool valid() const noexcept {
return b;
}
~protected_handler() {
if (!is_stack::value && stackindex != 0) {
lua_remove(target.lua_state(), stackindex);
}
}
};
template <typename base_t, typename T>
basic_function<base_t> force_cast(T& p) {
return p;
}
template <typename Reference, bool is_main_ref = false>
static Reference get_default_handler(lua_State* L) {
if (is_stack_based<Reference>::value || L == nullptr)
return Reference(L, lua_nil);
L = is_main_ref ? main_thread(L, L) : L;
lua_getglobal(L, default_handler_name());
auto pp = stack::pop_n(L, 1);
return Reference(L, -1);
}
template <typename T>
static void set_default_handler(lua_State* L, const T& ref) {
if (L == nullptr) {
return;
}
if (!ref.valid()) {
lua_pushnil(L);
lua_setglobal(L, default_handler_name());
}
else {
ref.push(L);
lua_setglobal(L, default_handler_name());
}
}
} // namespace detail
} // namespace sol
#endif // SOL_PROTECTED_HANDLER_HPP

View File

@ -146,7 +146,11 @@ namespace sol {
} }
int push() const noexcept { int push() const noexcept {
return get<reference>().push(lua_state()); return push(this->lua_state());
}
int push(lua_State* L) const noexcept {
return get<reference>().push(L);
} }
type get_type() const { type get_type() const {

View File

@ -200,6 +200,9 @@ namespace sol {
struct unchecked_t {}; struct unchecked_t {};
const unchecked_t unchecked = unchecked_t{}; const unchecked_t unchecked = unchecked_t{};
struct yield_tag_t {};
const yield_tag_t yield_tag = yield_tag_t{};
} // namespace detail } // namespace detail
struct lua_nil_t {}; struct lua_nil_t {};
@ -224,6 +227,30 @@ namespace sol {
struct no_metatable_t {}; struct no_metatable_t {};
const no_metatable_t no_metatable = {}; const no_metatable_t no_metatable = {};
template <typename T>
struct yielding_t {
T func;
yielding_t() = default;
yielding_t(const yielding_t&) = default;
yielding_t(yielding_t&&) = default;
yielding_t& operator=(const yielding_t&) = default;
yielding_t& operator=(yielding_t&&) = default;
template <typename Arg, meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, yielding_t>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler>
yielding_t(Arg&& arg)
: func(std::forward<Arg>(arg)) {
}
template <typename Arg0, typename Arg1, typename... Args>
yielding_t(Arg0&& arg0, Arg1&& arg1, Args&&... args)
: func(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {
}
};
template <typename F>
inline yielding_t<std::decay_t<F>> yielding(F&& f) {
return yielding_t<std::decay_t<F>>(std::forward<F>(f));
}
typedef std::remove_pointer_t<lua_CFunction> lua_CFunction_ref; typedef std::remove_pointer_t<lua_CFunction> lua_CFunction_ref;
template <typename T> template <typename T>

View File

@ -22,10 +22,10 @@
# # # # sol2 tests # # # # sol2 tests
find_package(CATCH 2.0.1 REQUIRED)
file(GLOB SOL2_TEST_SOURCES test*.cpp) file(GLOB SOL2_TEST_SOURCES test*.cpp)
source_group(test_sources FILES ${SOL2_TEST_SOURCES}) source_group(test_sources FILES ${SOL2_TEST_SOURCES})
file(DOWNLOAD https://github.com/catchorg/Catch2/releases/download/v2.0.1/catch.hpp ${CMAKE_BINARY_DIR}/vendor/Catch/include/catch.hpp)
#file(DOWNLOAD https://github.com/catchorg/Catch2/releases/download/v1.11.0/catch.hpp ${CMAKE_BINARY_DIR}/vendor/Catch/include/catch.hpp)
function(CREATE_TEST test_target_name test_name is_single) function(CREATE_TEST test_target_name test_name is_single)
if (is_single) if (is_single)
@ -46,8 +46,6 @@ function(CREATE_TEST test_target_name test_name is_single)
target_link_libraries(${test_target_name} sol2) target_link_libraries(${test_target_name} sol2)
endif() endif()
target_include_directories(${test_target_name}
PRIVATE "${LUA_INCLUDE_DIR}" "${CMAKE_BINARY_DIR}/vendor/Catch/include/")
if (MSVC) if (MSVC)
if (NOT CMAKE_COMPILER_ID MATCHES "Clang") if (NOT CMAKE_COMPILER_ID MATCHES "Clang")
target_compile_options(${test_target_name} target_compile_options(${test_target_name}
@ -63,9 +61,22 @@ function(CREATE_TEST test_target_name test_name is_single)
endif() endif()
target_compile_features(${test_target_name} target_compile_features(${test_target_name}
PRIVATE ${CXX_FEATURES}) PRIVATE ${CXX_FEATURES})
# if CMAKE_DL_LIBS is empty, then that just resolves to nothingness if (CMAKE_DL_LIBS)
target_link_libraries(${test_target_name} target_link_libraries(${test_target_name}
Threads::Threads ${LUA_LIBRARIES} ${CMAKE_DL_LIBS}) ${CMAKE_DL_LIBS})
endif()
target_link_libraries(${test_target_name}
Threads::Threads ${LUA_LIBRARIES} ${CATCH_LIBRARIES})
if (IS_X86)
target_compile_options(${test_target_name} BEFORE PRIVATE -m32)
endif()
if(MINGW AND IS_X86)
#set_target_properties(${test_target_name}
# PROPERTIES
# LINK_FLAGS -static-libstdc++)
endif()
add_test(NAME ${test_name} COMMAND ${test_target_name}) add_test(NAME ${test_name} COMMAND ${test_target_name})
install(TARGETS ${test_target_name} RUNTIME DESTINATION bin) install(TARGETS ${test_target_name} RUNTIME DESTINATION bin)

View File

@ -3,7 +3,7 @@
struct pre_main { struct pre_main {
pre_main() { pre_main() {
#ifdef SOL2_CI #ifdef SOL2_CI
#ifdef _MSC_VER #ifdef _MSC_VER
_set_abort_behavior(0, _WRITE_ABORT_MSG); _set_abort_behavior(0, _WRITE_ABORT_MSG);
#endif #endif
#endif #endif

View File

@ -530,3 +530,55 @@ end
REQUIRE(s4 == 0); REQUIRE(s4 == 0);
REQUIRE(s5 == 0); REQUIRE(s5 == 0);
} }
TEST_CASE("coroutines/yielding", "test that a sol2 bound function can yield when marked yieldable") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
int i = 0;
auto func = [&i]() {
++i;
return i;
};
struct h {
int x = 500;
int func() const {
return x;
}
} hobj{};
lua["f"] = sol::yielding(func);
lua["g"] = sol::yielding([]() { return 300; });
lua["h"] = sol::yielding(&h::func);
lua["hobj"] = &hobj;
sol::string_view code = R"(
co1 = coroutine.create(f)
success1, value1 = coroutine.resume(co1)
co2 = coroutine.create(g)
success2, value2 = coroutine.resume(co2)
co3 = coroutine.create(function()
h(hobj)
end)
success3, value3 = coroutine.resume(co3)
)";
auto result = lua.safe_script(code);
REQUIRE(result.valid());
bool success1 = lua["success1"];
int value1 = lua["value1"];
REQUIRE(success1);
REQUIRE(value1 == 1);
bool success2 = lua["success2"];
int value2 = lua["value2"];
REQUIRE(success2);
REQUIRE(value2 == 300);
bool success3 = lua["success3"];
int value3 = lua["value3"];
REQUIRE(success3);
REQUIRE(value3 == 500);
}

View File

@ -23,6 +23,9 @@
#pragma once #pragma once
#ifndef SOL_TEST_SOL_HPP
#define SOL_TEST_SOL_HPP
#ifndef SOL_CHECK_ARGUMENTS #ifndef SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1 #define SOL_CHECK_ARGUMENTS 1
#endif // SOL_CHECK_ARGUMENTS #endif // SOL_CHECK_ARGUMENTS
@ -60,3 +63,5 @@ struct test_stack_guard {
endtop = lua_gettop(L); endtop = lua_gettop(L);
} }
}; };
#endif // SOL_TEST_SOL_HPP