Update patrons

Reduce compile-times by removing lambda shenanigans and moving data that is already serialized into runtime systems to runtime
Fix bugs with precedence ordering related to index and new_index
Prepare to add 20000 more if constexpr to reduce compile-times even further.
This commit is contained in:
ThePhD 2019-01-05 05:48:51 -05:00
parent 0a21fbf3f0
commit 59174e76af
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
24 changed files with 2667 additions and 1621 deletions

View File

@ -1,18 +1,26 @@
# Donators! ♥
# 🎉 Donators! ♥ 🎉
Thank you to all patrons, donators and contributors who help keep sol2 amazing.
Robert Salvet
Ορφέας Ζαφείρης - 2x Donations!
Michael Wallar
Johannes Schultz
Dailidzionak Ilya
- Robert Salvet
- Ορφέας Ζαφείρης - 2x Donations!
- Michael Wallar
- Johannes Schultz
- Dailidzionak Ilya
- BECKMANN & EGLE Industrieelektronik GmbH [bue.de](https://www.bue.de/)
# Patrons
# 🎉 Patrons! ♥ 🎉
Beyond just a one-time donation, patrons make a continued commitment to help keep sol2 supported and bug-free. Thank you for your patronage! Here are the supporters that wanted to be featured as sol2 contributors.
Michael Caisse
Joshua Fisher
- Michael Caisse
- Joshua Fisher
- Ορφέας Ζαφείρης
# Company Patrons / Supporters #
Companies who sign up for a long-term support contract or patronage are listed here! They really push forward what's possible with sol2 (and the newer v3)! Please reach out to phdofthehouse@gmail.com if you are interested in a custom solution or a long-term support contract that goes beyond the current release's needs!
- Intrepid Control Systems [intrepidcs.com](https://www.intrepidcs.com/)

View File

@ -1,233 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#.rst:
# FindLua
# -------
#
#
#
# Locate Lua library. This module defines
#
# ::
#
# LUA_FOUND - if false, do not try to link to Lua
# LUA_LIBRARIES - both lua and lualib
# LUA_INCLUDE_DIR - where to find lua.h
# LUA_LIBRARY_DIR - Dir(s) where Lua libraries are found
# LUA_VERSION_STRING - the version of Lua found
# LUA_VERSION_MAJOR - the major version of Lua
# LUA_VERSION_MINOR - the minor version of Lua
# LUA_VERSION_PATCH - the patch version of Lua
#
#
#
# Note that the expected include convention is
#
# ::
#
# #include "lua.h"
#
# and not
#
# ::
#
# #include <lua/lua.h>
#
# This is because, the lua location is not standardized and may exist in
# locations other than lua/
unset(_lua_include_subdirs)
unset(_lua_append_versions)
unset(_lua_library_names)
include(${CMAKE_CURRENT_LIST_DIR}/FindLua/set_version_vars.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/FindLua/version_check.cmake)
# # this is a function only to have all the variables inside go away automatically
# function(_lua_set_version_vars)
# set(LUA_VERSIONS5 5.3 5.2 5.1 5.0)
# if (Lua_FIND_VERSION_EXACT)
# if (Lua_FIND_VERSION_COUNT GREATER 1)
# set(_lua_append_versions ${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR})
# endif ()
# elseif (Lua_FIND_VERSION)
# # once there is a different major version supported this should become a loop
# if (NOT Lua_FIND_VERSION_MAJOR GREATER 5)
# if (Lua_FIND_VERSION_COUNT EQUAL 1)
# set(_lua_append_versions ${LUA_VERSIONS5})
# else ()
# foreach (subver IN LISTS LUA_VERSIONS5)
# if (NOT subver VERSION_LESS ${Lua_FIND_VERSION})
# list(APPEND _lua_append_versions ${subver})
# endif ()
# endforeach ()
# endif ()
# endif ()
# else ()
# # once there is a different major version supported this should become a loop
# set(_lua_append_versions ${LUA_VERSIONS5})
# endif ()
# list(APPEND _lua_include_subdirs "include/lua" "include")
# foreach (ver IN LISTS _lua_append_versions)
# string(REGEX MATCH "^([0-9]+)\\.([0-9]+)$" _ver "${ver}")
# list(APPEND _lua_include_subdirs
# include/lua${CMAKE_MATCH_1}${CMAKE_MATCH_2}
# include/lua${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
# include/lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
# )
# list(APPEND _lua_library_names
# lua${CMAKE_MATCH_1}${CMAKE_MATCH_2}
# lua${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
# lua.${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
# lua-${CMAKE_MATCH_1}.${CMAKE_MATCH_2}
# )
# endforeach ()
# set(_lua_include_subdirs "${_lua_include_subdirs}" PARENT_SCOPE)
# set(_lua_append_versions "${_lua_append_versions}" PARENT_SCOPE)
# endfunction(_lua_set_version_vars)
# function(_lua_check_header_version _hdr_file)
# # At least 5.[012] have different ways to express the version
# # so all of them need to be tested. Lua 5.2 defines LUA_VERSION
# # and LUA_RELEASE as joined by the C preprocessor, so avoid those.
# file(STRINGS "${_hdr_file}" lua_version_strings
# REGEX "^#define[ \t]+LUA_(RELEASE[ \t]+\"Lua [0-9]|VERSION([ \t]+\"Lua [0-9]|_[MR])).*")
# string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MAJOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MAJOR ";${lua_version_strings};")
# if (LUA_VERSION_MAJOR MATCHES "^[0-9]+$")
# string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MINOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MINOR ";${lua_version_strings};")
# string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_RELEASE[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_PATCH ";${lua_version_strings};")
# set(LUA_VERSION_STRING "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_PATCH}")
# else ()
# string(REGEX REPLACE ".*;#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
# if (NOT LUA_VERSION_STRING MATCHES "^[0-9.]+$")
# string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
# endif ()
# string(REGEX REPLACE "^([0-9]+)\\.[0-9.]*$" "\\1" LUA_VERSION_MAJOR "${LUA_VERSION_STRING}")
# string(REGEX REPLACE "^[0-9]+\\.([0-9]+)[0-9.]*$" "\\1" LUA_VERSION_MINOR "${LUA_VERSION_STRING}")
# string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]).*" "\\1" LUA_VERSION_PATCH "${LUA_VERSION_STRING}")
# endif ()
# foreach (ver IN LISTS _lua_append_versions)
# if (ver STREQUAL "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
# set(LUA_VERSION_MAJOR ${LUA_VERSION_MAJOR} PARENT_SCOPE)
# set(LUA_VERSION_MINOR ${LUA_VERSION_MINOR} PARENT_SCOPE)
# set(LUA_VERSION_PATCH ${LUA_VERSION_PATCH} PARENT_SCOPE)
# set(LUA_VERSION_STRING ${LUA_VERSION_STRING} PARENT_SCOPE)
# return()
# endif ()
# endforeach ()
# endfunction(_lua_check_header_version)
_lua_set_version_vars(lua "")
find_path(LUA_INCLUDE_DIR lua.h
HINTS
ENV LUA_DIR
PATH_SUFFIXES ${_lua_include_subdirs} include
PATHS
${LUA_DIR}
~/Library/Frameworks
/Library/Frameworks
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
/usr
/usr/local # Homebrew
)
if (LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h")
_lua_check_header_version("${LUA_INCLUDE_DIR}/lua.h" "LUA")
endif ()
if (NOT LUA_VERSION_STRING)
foreach (subdir IN LISTS _lua_include_subdirs)
unset(LUA_INCLUDE_PREFIX CACHE)
find_path(LUA_INCLUDE_PREFIX ${subdir}/lua.h
HINTS
ENV LUA_DIR
PATHS
${LUA_DIR}
~/Library/Frameworks
/Library/Frameworks
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
/usr
/usr/local
)
if (LUA_INCLUDE_PREFIX)
_lua_check_header_version("${LUA_INCLUDE_PREFIX}/${subdir}/lua.h")
if (LUA_VERSION_STRING)
set(LUA_INCLUDE_DIR "${LUA_INCLUDE_PREFIX}/${subdir}")
break()
endif ()
endif ()
endforeach ()
endif ()
unset(_lua_include_subdirs)
unset(_lua_append_versions)
find_library(LUA_LIBRARY
NAMES ${_lua_library_names} lua
HINTS
ENV LUA_DIR
PATH_SUFFIXES lib bin
PATHS
${LUA_DIR}
~/Library/Frameworks
/Library/Frameworks
/sw
/opt/local
/opt/csw
/opt
/usr
/usr/local
# From the include_dir
${LUA_INCLUDE_DIR}/../lib
)
unset(_lua_library_names)
if (LUA_LIBRARY)
# include the math library for Unix
if (UNIX AND NOT APPLE AND NOT BEOS)
find_library(LUA_MATH_LIBRARY m)
set(LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}")
# include dl library for statically-linked Lua library
get_filename_component(LUA_LIB_EXT ${LUA_LIBRARY} EXT)
if (LUA_LIB_EXT STREQUAL CMAKE_STATIC_LIBRARY_SUFFIX)
list(APPEND LUA_LIBRARIES ${CMAKE_DL_LIBS})
endif ()
# For Windows and Mac, don't need to explicitly include the math library
else ()
set(LUA_LIBRARIES "${LUA_LIBRARY}")
endif ()
set(LUA_LIBRARY_DIR )
foreach (lib ${LUA_LIBRARIES})
get_filename_component(lib_dir ${lib} DIRECTORY CACHE)
list(APPEND LUA_LIBRARY_DIR ${lib_dir})
endforeach ()
list(REMOVE_DUPLICATES LUA_LIBRARY_DIR)
endif ()
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if
# all listed variables are TRUE
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua
FOUND_VAR Lua_FOUND
REQUIRED_VARS LUA_LIBRARIES LUA_LIBRARY_DIR LUA_INCLUDE_DIR
VERSION_VAR LUA_VERSION_STRING)
mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARY LUA_LIBRARY_DIR LUA_MATH_LIBRARY)

View File

@ -236,10 +236,16 @@ prepend(LUA_VANILLA_LUA_SOURCES "${LUA_VANILLA_SOURCE_DIR}/" ${LUA_VANILLA_LUA_S
prepend(LUA_VANILLA_LUAC_SOURCES "${LUA_VANILLA_SOURCE_DIR}/" ${LUA_VANILLA_LUAC_SOURCES})
# download, just for the sake of download + extract
# have to use 2 different commands just to have an empty command
# that results in nothing being run
# TODO: talk to smarter CMake people...?
# or pull from local folder
if (LUA_LOCAL_DIR)
file(COPY "${LUA_LOCAL_DIR}/src"
DESTINATION "${LUA_BUILD_TOPLEVEL}")
file(COPY "${LUA_LOCAL_DIR}/include"
DESTINATION "${LUA_BUILD_TOPLEVEL}")
add_custom_target(LUA_VANILLA
DEPENDS "${LUA_VANILLA_LIB_SOURCES}" "${LUA_VANILLA_LUA_SOURCES}" "${LUA_VANILLA_LUAC_SOURCES}")
set(LUA_VANILLA_INCLUDE_DIRS ${LUA_VANILLA_INCLUDE_DIRS} "${LUA_VANILLA_SOURCE_DIR}" "${LUA_BUILD_TOPLEVEL}/include")
else()
ExternalProject_Add(LUA_VANILLA
BUILD_IN_SOURCE TRUE
BUILD_ALWAYS FALSE
@ -286,6 +292,9 @@ extern \"C\" {
COMMAND "${CMAKE_COMMAND}" -E copy "${LUA_VANILLA_SOURCE_LUA_HPP}" "${LUA_VANILLA_DESTINATION_LUA_HPP}")
endif()
set(LUA_VANILLA_INCLUDE_DIRS ${LUA_VANILLA_SOURCE_DIR})
endif()
message(STATUS "${LUA_VANILLA_INCLUDE_DIRS}")
# # Target names
set(liblua "liblua-${LUA_VANILLA_VERSION}")
set(luainterpreter "lua-${LUA_VANILLA_VERSION}")
@ -308,13 +317,12 @@ set_target_properties(${liblua}
C_STANDARD 99
C_EXTENSIONS TRUE
POSITION_INDEPENDENT_CODE TRUE
INCLUDE_DIRECTORIES ${LUA_VANILLA_SOURCE_DIR}
OUTPUT_NAME ${LUA_BUILD_LIBNAME}
RUNTIME_OUTPUT_NAME ${LUA_BUILD_LIBNAME}
LIBRARY_OUTPUT_NAME ${LUA_BUILD_LIBNAME}
ARCHIVE_OUTPUT_NAME ${LUA_BUILD_LIBNAME})
target_include_directories(${liblua}
PUBLIC ${LUA_VANILLA_SOURCE_DIR})
PUBLIC "${LUA_VANILLA_INCLUDE_DIRS}")
target_compile_definitions(${liblua}
PUBLIC LUA_COMPAT_ALL ${LUA_VANILLA_DLL_DEFINE})
if (MSVC)
@ -352,7 +360,7 @@ set_target_properties(${luainterpreter}
C_EXTENSIONS TRUE
OUTPUT_NAME lua-${LUA_VANILLA_VERSION})
target_include_directories(${luainterpreter}
PRIVATE ${LUA_VANILLA_SOURCE_DIR})
PRIVATE "${LUA_VANILLA_INCLUDE_DIRS}")
target_compile_definitions(${luainterpreter}
PUBLIC LUA_COMPAT_ALL ${LUA_VANILLA_DLL_DEFINE}
PRIVATE LUA_COMPAT_ALL ${LUA_VANILLA_DLL_DEFINE})
@ -394,7 +402,7 @@ set_target_properties(${luacompiler}
C_EXTENSIONS TRUE
OUTPUT_NAME luac-${LUA_VANILLA_VERSION})
target_include_directories(${luacompiler}
PRIVATE ${LUA_VANILLA_SOURCE_DIR})
PRIVATE "${LUA_VANILLA_INCLUDE_DIRS}")
target_compile_options(${luacompiler}
PRIVATE ${LUA_VANILLA_LUA_LUAC_COMPILER_OPTIONS})
target_compile_definitions(${luacompiler}

View File

@ -167,7 +167,7 @@ namespace sol {
typedef meta::tuple_types<typename traits::return_type> return_types;
typedef typename traits::free_args_list args_list;
// compile-time eliminate any functions that we know ahead of time are of improper arity
if (!traits::runtime_variadics_t::value && meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {
if constexpr (!traits::runtime_variadics_t::value && meta::find_in_pack_v<meta::index_value<traits::free_arity>, meta::index_value<M>...>::value) {
return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
if (!traits::runtime_variadics_t::value && traits::free_arity != fxarity) {

View File

@ -37,16 +37,33 @@
#define SOL_EXCEPTIONS_SAFE_PROPAGATION 1
#endif // Exceptions can be propagated safely using C++-compiled Lua
#else
#if defined(__has_include)
#if __has_include(<lua.hpp>)
#include <lua.hpp>
#endif // C++ Mangling for Lua
#else
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#if defined(SOL_LUAJIT) && SOL_LUAJIT
#include <luajit.h>
#endif
}
#endif // lua.hpp exists or does not
#else
#include <lua.hpp>
#endif // check for lua.hpp safely for Lua 5.1 derps
#endif // C++ Mangling for Lua vs. Not
#ifdef LUAJIT_VERSION
#ifndef SOL_LUAJIT
#define SOL_LUAJIT 1
#endif // sol luajit
#if defined(SOL_LUAJIT) && SOL_LUAJIT
#ifndef SOL_LUAJIT_VERSION
#define SOL_LUAJIT_VERSION LUAJIT_VERSION_NUM
#endif // SOL_LUAJIT_VERSION definition, if not present
#endif // sol luajit
#endif
#endif // luajit
#if SOL_LUAJIT && SOL_LUAJIT_VERSION >= 20100
@ -63,8 +80,8 @@
// Definitely 5.0
#define SOL_LUA_VERSION 500
#else
// ??? Not sure, assume 502?
#define SOL_LUA_VERSION 502
#endif // Lua Version 502, 501 || luajit, 500
// ??? Not sure, assume 503?
#define SOL_LUA_VERSION 503
#endif // Lua Version 503, 502, 501 || luajit, 500
#endif // SOL_VERSION_HPP

View File

@ -24,6 +24,7 @@
#ifndef SOL_DEMANGLE_HPP
#define SOL_DEMANGLE_HPP
#include "string_view.hpp"
#include <string>
#include <array>
#include <cctype>
@ -36,12 +37,22 @@ extern "C" {
namespace sol {
namespace detail {
inline constexpr std::array<string_view, 9> removals{ { "{anonymous}",
"(anonymous namespace)",
"public:",
"private:",
"protected:",
"struct ",
"class ",
"`anonymous-namespace'",
"`anonymous namespace'" } };
#if defined(__GNUC__) || defined(__clang__)
template <typename T, class seperator_mark = int>
inline std::string ctti_get_type_name() {
// cardinal sins from MINGW
using namespace std;
static const std::array<std::string, 2> removals = {{"{anonymous}", "(anonymous namespace)"}};
std::string name = __PRETTY_FUNCTION__;
std::size_t start = name.find_first_of('[');
start = name.find_first_of('=', start);
@ -75,7 +86,6 @@ namespace detail {
#elif defined(_MSC_VER)
template <typename T>
inline std::string ctti_get_type_name() {
static const std::array<std::string, 7> removals = {{"public:", "private:", "protected:", "struct ", "class ", "`anonymous-namespace'", "`anonymous namespace'"}};
std::string name = __FUNCSIG__;
std::size_t start = name.find("get_type_name");
if (start == std::string::npos)

View File

@ -58,7 +58,7 @@ namespace sol {
const char* name = lua_tolstring(L, -1, &sz);
std::string tn(name, static_cast<std::string::size_type>(sz));
lua_pop(L, 2);
return name;
return std::move(tn);
}
default:
break;

View File

@ -202,6 +202,14 @@ namespace sol {
struct record;
}
#if !defined(SOL_USE_BOOST) || (SOL_USE_BOOST == 0)
template <class T>
class optional;
template <class T>
class optional<T&>;
#endif
} // namespace sol
#define SOL_BASE_CLASSES(T, ...) \

View File

@ -36,22 +36,19 @@ namespace sol {
friend class state_view;
protected:
basic_metatable(detail::no_safety_tag, lua_nil_t n)
: base_t(n) {
basic_metatable(detail::no_safety_tag, lua_nil_t n) : base_t(n) {
}
basic_metatable(detail::no_safety_tag, lua_State* L, int index)
: base_t(L, index) {
basic_metatable(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) {
}
basic_metatable(detail::no_safety_tag, lua_State* L, ref_index index)
: base_t(L, index) {
basic_metatable(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) {
}
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_metatable>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_metatable(detail::no_safety_tag, T&& r) noexcept
: base_t(std::forward<T>(r)) {
template <typename T,
meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_metatable>>, meta::neg<std::is_same<base_type, stack_reference>>,
meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_metatable(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward<T>(r)) {
}
template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_metatable(detail::no_safety_tag, lua_State* L, T&& r) noexcept
: base_t(L, std::forward<T>(r)) {
basic_metatable(detail::no_safety_tag, lua_State* L, T&& r) noexcept : base_t(L, std::forward<T>(r)) {
}
public:
@ -62,39 +59,35 @@ namespace sol {
basic_metatable(basic_metatable&&) = default;
basic_metatable& operator=(const basic_metatable&) = default;
basic_metatable& operator=(basic_metatable&&) = default;
basic_metatable(const stack_reference& r)
: basic_metatable(r.lua_state(), r.stack_index()) {
basic_metatable(const stack_reference& r) : basic_metatable(r.lua_state(), r.stack_index()) {
}
basic_metatable(stack_reference&& r)
: basic_metatable(r.lua_state(), r.stack_index()) {
basic_metatable(stack_reference&& r) : basic_metatable(r.lua_state(), r.stack_index()) {
}
template <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_metatable(lua_State* L, T&& r)
: base_t(L, std::forward<T>(r)) {
basic_metatable(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) {
#if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES
auto pp = stack::push_pop(*this);
constructor_handler handler{};
stack::check<basic_metatable>(lua_state(), -1, handler);
#endif // Safety
}
basic_metatable(lua_State* L, int index = -1)
: basic_metatable(detail::no_safety, L, index) {
basic_metatable(lua_State* L, int index = -1) : basic_metatable(detail::no_safety, L, index) {
#if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES
constructor_handler handler{};
stack::check<basic_metatable>(L, index, handler);
#endif // Safety
}
basic_metatable(lua_State* L, ref_index index)
: basic_metatable(detail::no_safety, L, index) {
basic_metatable(lua_State* L, ref_index index) : basic_metatable(detail::no_safety, L, index) {
#if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES
auto pp = stack::push_pop(*this);
constructor_handler handler{};
stack::check<basic_metatable>(lua_state(), -1, handler);
#endif // Safety
}
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_metatable>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_metatable(T&& r) noexcept
: basic_metatable(detail::no_safety, std::forward<T>(r)) {
template <typename T,
meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_metatable>>, meta::neg<std::is_same<base_type, stack_reference>>,
meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_metatable(T&& r) noexcept : basic_metatable(detail::no_safety, std::forward<T>(r)) {
#if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES
if (!is_table<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this);
@ -103,8 +96,7 @@ namespace sol {
}
#endif // Safety
}
basic_metatable(lua_nil_t r) noexcept
: basic_metatable(detail::no_safety, r) {
basic_metatable(lua_nil_t r) noexcept : basic_metatable(detail::no_safety, r) {
}
template <typename Key, typename Value>
@ -128,11 +120,11 @@ namespace sol {
}
ustorage_base& base_storage = *static_cast<ustorage_base*>(stack::get<void*>(L, -1));
base_storage.clear();
stack_reference gnt(L, -1);
stack_reference gc_names_table(L, -1);
std::array<const char*, 6> registry_traits;
for (int i = 0; i < registry_traits.size(); ++i) {
u_detail::submetatable_type smt = static_cast<u_detail::submetatable_type>(i);
stack::get_field(L, smt, gnt.stack_index());
stack::get_field(L, smt, gc_names_table.stack_index());
registry_traits[i] = stack::get<const char*>(L, -1);
}
// get the registry

View File

@ -24,7 +24,7 @@
#ifndef SOL_OPTIONAL_HPP
#define SOL_OPTIONAL_HPP
#include "compatibility.hpp"
#include "forward.hpp"
#include "in_place.hpp"
#if defined(SOL_USE_BOOST) && SOL_USE_BOOST
#include <boost/optional.hpp>
@ -32,6 +32,10 @@
#include "optional_implementation.hpp"
#endif // Boost vs. Better optional
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#include <optional>
#endif
namespace sol {
#if defined(SOL_USE_BOOST) && SOL_USE_BOOST
@ -46,6 +50,10 @@ namespace sol {
struct is_optional : std::false_type {};
template <typename T>
struct is_optional<optional<T>> : std::true_type {};
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
template <typename T>
struct is_optional<std::optional<T>> : std::true_type {};
#endif
} // namespace meta
} // namespace sol

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,7 @@
#include <algorithm>
namespace sol {
template <typename base_t, bool aligned = false, typename handler_t = reference>
class basic_protected_function : public base_t {
public:

View File

@ -44,17 +44,21 @@
// we'll just let this alone for now
#elif defined _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4324) // structure was padded due to alignment specifier
#pragma warning(disable : 4503) // decorated name horse shit
#pragma warning(disable : 4702) // unreachable code
#pragma warning(disable : 4127) // 'conditional expression is constant' yeah that's the point your old compilers don't have `if constexpr` you jerk
#pragma warning(disable : 4505) // some other nonsense warning
//#pragma warning(disable : 4324) // structure was padded due to alignment specifier
//#pragma warning(disable : 4503) // decorated name horse shit
//#pragma warning(disable : 4702) // unreachable code
//#pragma warning(disable : 4127) // 'conditional expression is constant' yeah that's the point your old compilers don't have `if constexpr` you jerk
//#pragma warning(disable : 4505) // some other nonsense warning
#endif // clang++ vs. g++ vs. VC++
#include "forward.hpp"
#include "forward_detail.hpp"
#include "stack.hpp"
#include "object.hpp"
#include "function.hpp"
#include "protected_function.hpp"
#include "usertype.hpp"
#include "table.hpp"
#include "state.hpp"
#include "coroutine.hpp"
#include "thread.hpp"

View File

@ -69,6 +69,21 @@ namespace sol {
return chunkname.c_str();
}
}
inline void clear_entries(stack_reference r) {
stack::push(r.lua_state(), lua_nil);
while (lua_next(r.lua_state(), -2)) {
absolute_index key(r.lua_state(), -2);
auto pn = stack::pop_n(r.lua_state(), 1);
stack::set_field<false, true>(r.lua_state(), key, lua_nil, r.stack_index());
}
}
inline void clear_entries(const reference& registry_reference) {
auto pp = stack::push_pop(registry_reference);
stack_reference ref(registry_reference.lua_state(), -1);
clear_entries(ref);
}
} // namespace detail
namespace stack {
@ -189,13 +204,9 @@ namespace sol {
template <bool check_args = detail::default_safe_function_calls, bool clean_stack = true, typename Ret0, typename... Ret, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<meta::neg<std::is_void<Ret0>>::value>>
inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
decltype(auto) r = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
typedef meta::unqualified_t<decltype(r)> R;
typedef meta::any<is_stack_based<R>,
std::is_same<R, absolute_index>,
std::is_same<R, ref_index>,
std::is_same<R, raw_index>>
is_stack;
if (clean_stack && !is_stack::value) {
using R = meta::unqualified_t<decltype(r)>;
using is_stack = meta::any<is_stack_based<R>, std::is_same<R, absolute_index>, std::is_same<R, ref_index>, std::is_same<R, raw_index>>;
if constexpr (clean_stack && !is_stack::value) {
lua_settop(L, 0);
}
return push_reference(L, std::forward<decltype(r)>(r));

View File

@ -479,7 +479,8 @@ namespace sol { namespace stack {
if (stack_detail::check_metatable<as_container_t<U>>(L, metatableindex))
return true;
bool success = false;
if (derive<T>::value || weak_derive<T>::value) {
bool has_derived = derive<T>::value || weak_derive<T>::value;
if (has_derived) {
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
luaL_checkstack(L, 1, detail::not_enough_stack_space_string);
#endif // make sure stack doesn't overflow

View File

@ -1244,8 +1244,10 @@ namespace sol {
else if constexpr (!std::is_pointer_v<T>) {
return &usertype_alloc_destruct<T>;
}
else {
return &cannot_destruct<T>;
}
}
template <typename T>
inline lua_CFunction make_destructor(std::false_type) {
@ -1321,11 +1323,20 @@ namespace sol {
template <typename T, typename Op>
int comparsion_operator_wrap(lua_State* L) {
auto maybel = stack::unqualified_check_get<T&>(L, 1);
if (maybel) {
if (!maybel) {
return stack::push(L, false);
}
auto mayber = stack::unqualified_check_get<T&>(L, 2);
if (mayber) {
auto& l = *maybel;
auto& r = *mayber;
if (!mayber) {
return stack::push(L, false);
}
decltype(auto) l = *maybel;
decltype(auto) r = *mayber;
if constexpr (std::is_same_v<no_comp, Op>) {
std::equal_to<> op;
return stack::push(L, op(detail::ptr(l), detail::ptr(r)));
}
else {
if constexpr (std::is_same_v<std::equal_to<>, Op> // cf-hack
|| std::is_same_v<std::less_equal<>, Op> //
|| std::is_same_v<std::less_equal<>, Op>) { //
@ -1333,16 +1344,10 @@ namespace sol {
return stack::push(L, true);
}
}
else if constexpr (std::is_same_v<no_comp, Op>) {
std::equal_to<> op;
return stack::push(L, op(detail::ptr(l), detail::ptr(r)));
}
Op op;
return stack::push(L, op(detail::deref(l), detail::deref(r)));
}
}
return stack::push(L, false);
}
template <typename T, typename IFx, typename Fx>
void insert_default_registrations(IFx&& ifx, Fx&& fx);

View File

@ -791,7 +791,8 @@ namespace sol { namespace stack {
}
static T* get_no_lua_nil_from(lua_State* L, void* udata, int index, record&) {
if (derive<T>::value || weak_derive<T>::value) {
bool has_derived = derive<T>::value || weak_derive<T>::value;
if (has_derived) {
if (lua_getmetatable(L, index) == 1) {
lua_getfield(L, -1, &detail::base_class_cast_key()[0]);
if (type_of(L, -1) != type::lua_nil) {

View File

@ -34,9 +34,11 @@ namespace stack {
struct probe_field_getter {
template <typename Key>
probe get(lua_State* L, Key&& key, int tableindex = -2) {
if (!b && !maybe_indexable(L, tableindex)) {
if constexpr(!b) {
if (!maybe_indexable(L, tableindex)) {
return probe(false, 0);
}
}
get_field<b, raw>(L, std::forward<Key>(key), tableindex);
return probe(check<P>(L), 1);
}

View File

@ -46,6 +46,23 @@
namespace sol {
namespace stack {
namespace stack_detail {
template <typename T>
inline bool integer_value_fits(const T& value) {
if constexpr (sizeof(T) < sizeof(lua_Integer) || (std::is_signed<T>::value && sizeof(T) == sizeof(lua_Integer))) {
(void)value;
return true;
}
else {
auto u_min = static_cast<std::intmax_t>((std::numeric_limits<lua_Integer>::min)());
auto u_max = static_cast<std::uintmax_t>((std::numeric_limits<lua_Integer>::max)());
auto t_min = static_cast<std::intmax_t>((std::numeric_limits<T>::min)());
auto t_max = static_cast<std::uintmax_t>((std::numeric_limits<T>::max)());
return (u_min <= t_min || value >= static_cast<T>(u_min)) && (u_max >= t_max || value <= static_cast<T>(u_max));
}
}
}
inline int push_environment_of(lua_State* L, int index = -1) {
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
luaL_checkstack(L, 1, detail::not_enough_stack_space_environment);
@ -241,17 +258,7 @@ namespace sol {
luaL_checkstack(L, 1, detail::not_enough_stack_space_integral);
#endif // make sure stack doesn't overflow
#if SOL_LUA_VERSION >= 503
static auto integer_value_fits = [](T const& value) {
if (sizeof(T) < sizeof(lua_Integer) || (std::is_signed<T>::value && sizeof(T) == sizeof(lua_Integer))) {
return true;
}
auto u_min = static_cast<std::intmax_t>((std::numeric_limits<lua_Integer>::min)());
auto u_max = static_cast<std::uintmax_t>((std::numeric_limits<lua_Integer>::max)());
auto t_min = static_cast<std::intmax_t>((std::numeric_limits<T>::min)());
auto t_max = static_cast<std::uintmax_t>((std::numeric_limits<T>::max)());
return (u_min <= t_min || value >= static_cast<T>(u_min)) && (u_max >= t_max || value <= static_cast<T>(u_max));
};
if (integer_value_fits(value)) {
if (stack_detail::integer_value_fits<T>(value)) {
lua_pushinteger(L, static_cast<lua_Integer>(value));
return 1;
}
@ -813,7 +820,7 @@ namespace sol {
}
static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) {
if (sizeof(wchar_t) == 2) {
if constexpr (sizeof(wchar_t) == 2) {
const char16_t* sb = reinterpret_cast<const char16_t*>(strb);
const char16_t* se = reinterpret_cast<const char16_t*>(stre);
return stack::push(L, sb, se);

View File

@ -53,11 +53,9 @@ namespace sol {
basic_string_view(const std::string& r)
: basic_string_view(r.data(), r.size()) {
}
basic_string_view(const Char* ptr)
: basic_string_view(ptr, Traits::length(ptr)) {
constexpr basic_string_view(const Char* ptr) : basic_string_view(ptr, Traits::length(ptr)) {
}
basic_string_view(const Char* ptr, std::size_t sz)
: s(sz), p(ptr) {
constexpr basic_string_view(const Char* ptr, std::size_t sz) : s(sz), p(ptr) {
}
static int compare(const Char* lhs_p, std::size_t lhs_sz, const Char* rhs_p, std::size_t rhs_sz) {
@ -71,31 +69,31 @@ namespace sol {
return 0;
}
const Char* begin() const {
constexpr const Char* begin() const {
return p;
}
const Char* end() const {
constexpr const Char* end() const {
return p + s;
}
const Char* cbegin() const {
constexpr const Char* cbegin() const {
return p;
}
const Char* cend() const {
constexpr const Char* cend() const {
return p + s;
}
const Char* data() const {
constexpr const Char* data() const {
return p;
}
std::size_t size() const {
constexpr std::size_t size() const {
return s;
}
std::size_t length() const {
constexpr std::size_t length() const {
return size();
}

View File

@ -66,31 +66,6 @@ namespace sol {
template <typename... Args>
using is_global = meta::all<meta::boolean<top_level>, meta::is_c_str<Args>...>;
template <typename Fx>
void for_each(std::true_type, Fx&& fx) const {
auto pp = stack::push_pop(*this);
stack::push(base_t::lua_state(), lua_nil);
while (lua_next(base_t::lua_state(), -2)) {
object key(base_t::lua_state(), -2);
object value(base_t::lua_state(), -1);
std::pair<object&, object&> keyvalue(key, value);
auto pn = stack::pop_n(base_t::lua_state(), 1);
fx(keyvalue);
}
}
template <typename Fx>
void for_each(std::false_type, Fx&& fx) const {
auto pp = stack::push_pop(*this);
stack::push(base_t::lua_state(), lua_nil);
while (lua_next(base_t::lua_state(), -2)) {
object key(base_t::lua_state(), -2);
object value(base_t::lua_state(), -1);
auto pn = stack::pop_n(base_t::lua_state(), 1);
fx(key, value);
}
}
template <bool raw, typename Ret0, typename Ret1, typename... Ret, std::size_t... I, typename Keys>
auto tuple_get(types<Ret0, Ret1, Ret...>, std::index_sequence<0, 1, I...>, Keys&& keys) const
-> decltype(stack::pop<std::tuple<Ret0, Ret1, Ret...>>(nullptr)) {
@ -384,7 +359,7 @@ namespace sol {
for (const auto& kvp : items) {
target.set(kvp.first, kvp.second);
}
if (read_only) {
if constexpr (read_only) {
table x = create_with(meta_function::new_index, detail::fail_on_newindex, meta_function::index, target);
table shim = create_named(name, metatable_key, x);
return shim;
@ -395,10 +370,29 @@ namespace sol {
}
}
template <typename Fx>
template <typename Key = object, typename Value = object, typename Fx>
void for_each(Fx&& fx) const {
typedef meta::is_invokable<Fx(std::pair<object, object>)> is_paired;
for_each(is_paired(), std::forward<Fx>(fx));
if constexpr (std::is_invocable_v<Fx, Key, Value>) {
auto pp = stack::push_pop(*this);
stack::push(base_t::lua_state(), lua_nil);
while (lua_next(base_t::lua_state(), -2)) {
Key key(base_t::lua_state(), -2);
Value value(base_t::lua_state(), -1);
auto pn = stack::pop_n(base_t::lua_state(), 1);
fx(key, value);
}
}
else {
auto pp = stack::push_pop(*this);
stack::push(base_t::lua_state(), lua_nil);
while (lua_next(base_t::lua_state(), -2)) {
Key key(base_t::lua_state(), -2);
Value value(base_t::lua_state(), -1);
auto pn = stack::pop_n(base_t::lua_state(), 1);
std::pair<Key&, Value&> keyvalue(key, value);
fx(keyvalue);
}
}
}
size_t size() const {

View File

@ -800,9 +800,14 @@ namespace sol {
|| std::is_base_of<stack_reference, meta::unqualified_t<T>>::value> {};
template <typename T>
struct is_lua_reference_or_proxy : std::integral_constant<bool,
is_lua_reference<meta::unqualified_t<T>>::value
|| meta::is_specialization_of<meta::unqualified_t<T>, proxy>::value> {};
inline constexpr bool is_lua_reference_v = is_lua_reference<T>::value;
template <typename T>
struct is_lua_reference_or_proxy
: std::integral_constant<bool, is_lua_reference<meta::unqualified_t<T>>::value || meta::is_specialization_of<meta::unqualified_t<T>, proxy>::value> {};
template <typename T>
inline constexpr bool is_lua_reference_or_proxy_v = is_lua_reference_or_proxy<T>::value;
template <typename T>
struct is_transparent_argument : std::false_type {};

View File

@ -44,6 +44,8 @@ namespace sol { namespace u_detail {
usertype_storage<T>& get_usertype_storage(lua_State* L);
using index_call_function = int(lua_State*, void*);
using change_indexing_mem_func
= void (usertype_storage_base::*)(lua_State*, submetatable_type, void*, stack_reference&, lua_CFunction, lua_CFunction, lua_CFunction, lua_CFunction);
struct index_call_storage {
index_call_function* index;
@ -51,6 +53,10 @@ namespace sol { namespace u_detail {
void* binding_data;
};
struct new_index_call_storage : index_call_storage {
void* new_binding_data;
};
struct binding_base {
virtual void* data() = 0;
virtual ~binding_base() {
@ -148,6 +154,130 @@ namespace sol { namespace u_detail {
return new_index_fail(L);
}
struct string_for_each_metatable_func {
bool is_destruction = false;
bool is_index = false;
bool is_new_index = false;
bool poison_indexing = false;
bool is_unqualified_lua_CFunction = false;
bool is_unqualified_lua_reference = false;
std::string* p_key = nullptr;
reference* p_binding_ref = nullptr;
lua_CFunction call_func = nullptr;
index_call_storage* p_ics = nullptr;
usertype_storage_base* p_usb = nullptr;
void* p_derived_usb = nullptr;
lua_CFunction idx_call = nullptr,
new_idx_call = nullptr,
meta_idx_call = nullptr,
meta_new_idx_call = nullptr;
change_indexing_mem_func change_indexing;
void operator()(lua_State* L, submetatable_type smt, reference& fast_index_table) {
std::string& key = *p_key;
usertype_storage_base& usb = *p_usb;
index_call_storage& ics = *p_ics;
if (smt == submetatable_type::named) {
// do not override __call or
// other specific meta functions on named metatable:
// we need that for call construction
// and other amenities
return;
}
int fast_index_table_push = fast_index_table.push();
stack_reference t(L, -fast_index_table_push);
if (poison_indexing) {
(usb.*change_indexing)(L,
smt,
p_derived_usb,
t,
idx_call,
new_idx_call,
meta_idx_call,
meta_new_idx_call);
}
if (is_destruction
&& (smt == submetatable_type::reference || smt == submetatable_type::const_reference || smt == submetatable_type::named
|| smt == submetatable_type::unique)) {
// gc does not apply to us here
// for reference types (raw T*, std::ref)
// for the named metatable itself,
// or for unique_usertypes, which do their own custom destruction
t.pop();
return;
}
if (is_index || is_new_index) {
// do not serialize the new_index and index functions here directly
// we control those...
t.pop();
return;
}
if (is_unqualified_lua_CFunction) {
stack::set_field<false, true>(L, key, call_func, t.stack_index());
}
else if (is_unqualified_lua_reference) {
reference& binding_ref = *p_binding_ref;
stack::set_field<false, true>(L, key, binding_ref, t.stack_index());
}
else {
stack::set_field<false, true>(L, key, make_closure(call_func, nullptr, ics.binding_data), t.stack_index());
}
t.pop();
}
};
struct lua_reference_func {
reference key;
reference value;
void operator()(lua_State* L, submetatable_type smt, reference& fast_index_table) {
if (smt == submetatable_type::named) {
return;
}
int fast_index_table_push = fast_index_table.push();
stack_reference t(L, -fast_index_table_push);
stack::set_field<false, true>(L, key, value, t.stack_index());
t.pop();
}
};
struct update_bases_func {
detail::inheritance_check_function base_class_check_func;
detail::inheritance_cast_function base_class_cast_func;
lua_CFunction idx_call, new_idx_call, meta_idx_call, meta_new_idx_call;
usertype_storage_base* p_usb;
void* p_derived_usb;
change_indexing_mem_func change_indexing;
void operator()(lua_State* L, submetatable_type smt, reference& fast_index_table) {
int fast_index_table_push = fast_index_table.push();
stack_reference t(L, -fast_index_table_push);
stack::set_field(L, detail::base_class_check_key(), reinterpret_cast<void*>(base_class_check_func), t.stack_index());
stack::set_field(L, detail::base_class_cast_key(), reinterpret_cast<void*>(base_class_cast_func), t.stack_index());
// change indexing, forcefully
(p_usb->*change_indexing)(L,
smt,
p_derived_usb,
t,
idx_call,
new_idx_call,
meta_idx_call,
meta_new_idx_call);
t.pop();
}
};
struct binding_data_equals {
void* binding_data;
binding_data_equals(void* b) : binding_data(b) {}
bool operator()(const std::unique_ptr<binding_base>& ptr) const {
return binding_data == ptr->data();
}
};
struct usertype_storage_base {
public:
std::vector<std::unique_ptr<binding_base>> storage;
@ -163,13 +293,10 @@ namespace sol { namespace u_detail {
reference type_table;
reference gc_names_table;
reference named_metatable;
std::bitset<64> properties;
index_call_storage base_index;
index_call_storage base_new_index;
lua_CFunction weak_base_index;
lua_CFunction weak_base_new_index;
new_index_call_storage base_index;
bool is_using_index;
bool is_using_new_index;
std::bitset<64> properties;
usertype_storage_base(lua_State* L)
: storage()
@ -182,17 +309,14 @@ namespace sol { namespace u_detail {
, type_table(make_reference(L, create))
, gc_names_table(make_reference(L, create))
, named_metatable(make_reference(L, create))
, properties()
, base_index()
, base_new_index()
, is_using_index(false)
, is_using_new_index(false) {
, is_using_new_index(false)
, properties() {
base_index.binding_data = nullptr;
base_index.index = index_target_fail;
base_index.new_index = index_target_fail;
base_new_index.binding_data = nullptr;
base_new_index.index = new_index_target_fail;
base_new_index.new_index = new_index_target_fail;
base_index.new_index = new_index_target_fail;
base_index.new_binding_data = nullptr;
}
template <typename Fx>
@ -242,7 +366,7 @@ namespace sol { namespace u_detail {
"The size of this data pointer is too small to fit the inheritance checking function: Please file "
"a bug report.");
static_assert(!meta::any_same<T, Bases...>::value, "base classes cannot list the original class as part of the bases");
if (sizeof...(Bases) < 1) {
if constexpr (sizeof...(Bases) < 1) {
return;
}
@ -250,31 +374,18 @@ namespace sol { namespace u_detail {
void* derived_this = static_cast<void*>(static_cast<usertype_storage<T>*>(this));
auto change_indexing_and_set_weak_derive = [&](lua_State* L, submetatable_type smt, reference& fast_index_table) {
int fast_index_table_push = fast_index_table.push();
stack_reference t(L, -fast_index_table_push);
static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function),
"The size of this data pointer is too small to fit the inheritance checking function: file a "
"bug report.");
static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function),
"The size of this data pointer is too small to fit the inheritance checking function: file a "
"bug report.");
auto base_class_check_func = &detail::inheritance<T>::template type_check_with<Bases...>;
auto base_class_cast_func = &detail::inheritance<T>::template type_cast_with<Bases...>;
stack::set_field(L, detail::base_class_check_key(), reinterpret_cast<void*>(base_class_check_func), t.stack_index());
stack::set_field(L, detail::base_class_cast_key(), reinterpret_cast<void*>(base_class_cast_func), t.stack_index());
// change indexing, forcefully
change_indexing(L,
smt,
derived_this,
t,
&usertype_storage<T>::template index_call_with_bases<Bases...>,
&usertype_storage<T>::template new_index_call_with_bases<Bases...>,
&usertype_storage<T>::template meta_index_call_with_bases<Bases...>,
&usertype_storage<T>::template meta_new_index_call_with_bases<Bases...>);
t.pop();
};
this->for_each_table(L, change_indexing_and_set_weak_derive);
update_bases_func for_each_fx;
for_each_fx.base_class_check_func = &detail::inheritance<T>::template type_check_with<Bases...>;
for_each_fx.base_class_cast_func = &detail::inheritance<T>::template type_cast_with<Bases...>;
for_each_fx.idx_call = &usertype_storage<T>::template index_call_with_bases<false, Bases...>;
for_each_fx.new_idx_call = &usertype_storage<T>::template index_call_with_bases<true, Bases...>;
for_each_fx.meta_idx_call = &usertype_storage<T>::template meta_index_call_with_bases<false, Bases...>;
for_each_fx.meta_new_idx_call = &usertype_storage<T>::template meta_index_call_with_bases<true, Bases...>;
for_each_fx.p_usb = this;
for_each_fx.p_derived_usb = derived_this;
for_each_fx.change_indexing = &usertype_storage_base::change_indexing;
for_each_fx.p_derived_usb = derived_this;
this->for_each_table(L, for_each_fx);
}
void clear() {
@ -286,7 +397,7 @@ namespace sol { namespace u_detail {
// then replace unqualified_getter/setter
}
template <typename Base>
template <bool is_new_index, typename Base>
static void base_walk_index(lua_State* L, usertype_storage_base& self, bool& keep_going, int& base_result) {
using bases = typename base<Base>::type;
if (!keep_going) {
@ -296,25 +407,11 @@ namespace sol { namespace u_detail {
(void)self;
// TODO: get base table, dump it out
usertype_storage_base& base_storage = get_usertype_storage<Base>(L);
base_result = self_index_call<true>(bases(), L, base_storage);
base_result = self_index_call<is_new_index, true>(bases(), L, base_storage);
keep_going = base_result == base_walking_failed_index;
}
template <typename Base>
static void base_walk_new_index(lua_State* L, usertype_storage_base& self, bool& keep_going, int& base_result) {
using bases = typename base<Base>::type;
if (!keep_going) {
return;
}
(void)L;
(void)self;
// TODO: get base table, dump it out
usertype_storage_base& base_storage = get_usertype_storage<Base>(L);
base_result = self_new_index_call<true>(bases(), L, base_storage);
keep_going = base_result == base_walking_failed_index;
}
template <bool base_walking = false, bool from_named_metatable = false, typename... Bases>
template <bool is_new_index = false, bool base_walking = false, bool from_named_metatable = false, typename... Bases>
static inline int self_index_call(types<Bases...>, lua_State* L, usertype_storage_base& self) {
type k_type = stack::get<type>(L, 2);
if (k_type == type::string) {
@ -328,9 +425,14 @@ namespace sol { namespace u_detail {
}
if (target != nullptr) {
// let the target decide what to do
if constexpr (is_new_index) {
return (target->new_index)(L, target->binding_data);
}
else {
return (target->index)(L, target->binding_data);
}
}
}
else if (k_type != type::nil && k_type != type::none) {
reference* target = nullptr;
{
@ -341,96 +443,63 @@ namespace sol { namespace u_detail {
}
}
if (target != nullptr) {
if constexpr(is_new_index) {
// set value and return
*target = reference(L, 3);
return 0;
}
else {
// push target to return
// what we found
return stack::push(L, *target);
}
}
}
// retrieve bases and walk through them.
bool keep_going = true;
int base_result;
detail::swallow{ 1, (base_walk_index<Bases>(L, self, keep_going, base_result), 1)... };
if (sizeof...(Bases) > 0 && !keep_going) {
(void)keep_going;
(void)base_result;
detail::swallow{ 1, (base_walk_index<is_new_index, Bases>(L, self, keep_going, base_result), 1)... };
if constexpr (sizeof...(Bases) > 0) {
if (!keep_going) {
return base_result;
}
if (base_walking) {
}
if constexpr (base_walking) {
// if we're JUST base-walking then don't index-fail, just
// return the false bits
return base_walking_failed_index;
}
if constexpr (from_named_metatable) {
else if constexpr (from_named_metatable) {
if constexpr (is_new_index) {
self.set(L, reference(L, raw_index(2)), reference(L, raw_index(3)));
return 0;
}
else {
return index_fail(L);
}
}
else {
if constexpr (is_new_index) {
return self.base_index.new_index(L, self.base_index.new_binding_data);
}
else {
return self.base_index.index(L, self.base_index.binding_data);
}
}
template <bool base_walking = false, bool from_named_metatable = false, typename... Bases>
static inline int self_new_index_call(types<Bases...>, lua_State* L, usertype_storage_base& self) {
type k_type = stack::get<type>(L, 2);
if (k_type == type::string) {
index_call_storage* target = nullptr;
{
string_view k = stack::get<string_view>(L, 2);
auto it = self.string_keys.find(k);
if (it != self.string_keys.cend()) {
target = &it->second;
}
}
if (target != nullptr) {
// set value through
// new_index call, whatever that entails,
// and return
return (target->new_index)(L, target->binding_data);
}
}
else if (k_type != type::nil && k_type != type::none) {
reference* target = nullptr;
{
stack_reference k = stack::get<stack_reference>(L, 2);
auto it = self.auxiliary_keys.find(k);
if (it != self.auxiliary_keys.cend()) {
target = &it->second;
}
}
if (target != nullptr) {
// set value and return
*target = reference(L, 3);
return 0;
}
}
// retrieve bases and walk through them.
bool keep_going = true;
int base_result;
detail::swallow{ 1, (base_walk_new_index<Bases>(L, self, keep_going, base_result), 1)... };
if (sizeof...(Bases) > 0 && !keep_going) {
return base_result;
}
if (base_walking) {
// if we're JUST base-walking then don't index-fail, just
// return the false bits
return base_walking_failed_index;
}
if constexpr (from_named_metatable) {
self.set(L, reference(L, raw_index(2)), reference(L, raw_index(3)));
return 0;
}
else {
return self.base_new_index.new_index(L, self.base_new_index.binding_data);
}
}
void change_indexing(lua_State* L, submetatable_type submetatable_type, void* derived_this, stack_reference& t, lua_CFunction index,
void change_indexing(lua_State* L, submetatable_type submetatable, void* derived_this, stack_reference& t, lua_CFunction index,
lua_CFunction new_index, lua_CFunction meta_index, lua_CFunction meta_new_index) {
usertype_storage_base& this_base = *this;
void* base_this = static_cast<void*>(&this_base);
this->is_using_index |= true;
this->is_using_new_index |= true;
if (submetatable_type == submetatable_type::named) {
//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());
stack::set_field<false, true>(L,
@ -460,68 +529,38 @@ namespace sol { namespace u_detail {
using usertype_storage_base::usertype_storage_base;
template <bool from_named_metatable>
template <bool is_new_index, bool from_named_metatable>
static inline int index_call_(lua_State* L) {
using bases = typename base<T>::type;
usertype_storage_base& self = stack::get<light<usertype_storage_base>>(L, upvalue_index(usertype_storage_index));
return self_index_call<false, from_named_metatable>(bases(), L, self);
return self_index_call<is_new_index, false, from_named_metatable>(bases(), L, self);
}
template <bool from_named_metatable, typename... Bases>
template <bool is_new_index, bool from_named_metatable, typename... Bases>
static inline int index_call_with_bases_(lua_State* L) {
using bases = types<Bases...>;
usertype_storage_base& self = stack::get<light<usertype_storage_base>>(L, upvalue_index(usertype_storage_index));
return self_index_call<false, from_named_metatable>(bases(), L, self);
}
template <bool from_named_metatable>
static inline int new_index_call_(lua_State* L) {
using bases = typename base<T>::type;
usertype_storage_base& self = stack::get<light<usertype_storage_base>>(L, upvalue_index(usertype_storage_index));
return self_new_index_call<false, from_named_metatable>(bases(), L, self);
}
template <bool from_named_metatable, typename... Bases>
static inline int new_index_call_with_bases_(lua_State* L) {
using bases = types<Bases...>;
usertype_storage_base& self = stack::get<light<usertype_storage_base>>(L, upvalue_index(usertype_storage_index));
return self_new_index_call<false, from_named_metatable>(bases(), L, self);
return self_index_call<is_new_index, false, from_named_metatable>(bases(), L, self);
}
template <bool is_new_index>
static inline int index_call(lua_State* L) {
return detail::static_trampoline<&index_call_<false>>(L);
return detail::static_trampoline<&index_call_<is_new_index, false>>(L);
}
template <typename... Bases>
template <bool is_new_index, typename... Bases>
static inline int index_call_with_bases(lua_State* L) {
return detail::static_trampoline<&index_call_with_bases_<false, Bases...>>(L);
}
static inline int new_index_call(lua_State* L) {
return detail::static_trampoline<&new_index_call_<false>>(L);
}
template <typename... Bases>
static inline int new_index_call_with_bases(lua_State* L) {
return detail::static_trampoline<&new_index_call_with_bases_<false, Bases...>>(L);
return detail::static_trampoline<&index_call_with_bases_<is_new_index, false, Bases...>>(L);
}
template <bool is_new_index>
static inline int meta_index_call(lua_State* L) {
return detail::static_trampoline<&index_call_<true>>(L);
return detail::static_trampoline<&index_call_<is_new_index, true>>(L);
}
template <typename... Bases>
template <bool is_new_index, typename... Bases>
static inline int meta_index_call_with_bases(lua_State* L) {
return detail::static_trampoline<&index_call_with_bases_<true, Bases...>>(L);
}
static inline int meta_new_index_call(lua_State* L) {
return detail::static_trampoline<&new_index_call_<true>>(L);
}
template <typename... Bases>
static inline int meta_new_index_call_with_bases(lua_State* L) {
return detail::static_trampoline<&new_index_call_with_bases_<true, Bases...>>(L);
return detail::static_trampoline<&index_call_with_bases_<is_new_index, true, Bases...>>(L);
}
template <typename Key, typename Value>
@ -557,9 +596,7 @@ namespace sol { namespace u_detail {
auto string_it = this->string_keys.find(s);
if (string_it != this->string_keys.cend()) {
const auto& binding_data = string_it->second.binding_data;
storage_it = std::find_if(this->storage.begin(), this->storage.end(), [&binding_data](const std::unique_ptr<binding_base>& b) {
return b->data() == binding_data;
});
storage_it = std::find_if(this->storage.begin(), this->storage.end(), binding_data_equals(binding_data));
this->string_keys.erase(string_it);
}
@ -580,75 +617,58 @@ namespace sol { namespace u_detail {
index_call_storage ics;
ics.binding_data = b.data();
ics.index = is_index ? &Binding::template call_with_<true, is_var_bind::value> : &Binding::template index_call_with_<true, is_var_bind::value>;
ics.new_index = is_new_index ? &Binding::template call_with_<false, is_var_bind::value>
: &Binding::template index_call_with_<false, is_var_bind::value>;
// need to swap everything to use fast indexing here
auto for_each_backing_metatable = [&](lua_State* L, submetatable_type smt, reference& fast_index_table) {
if (smt == submetatable_type::named) {
// do not override __call or
// other specific meta functions on named metatable:
// we need that for call construction
// and other amenities
return;
ics.new_index
= is_new_index ? &Binding::template call_with_<false, is_var_bind::value> : &Binding::template index_call_with_<false, is_var_bind::value>;
string_for_each_metatable_func for_each_fx;
for_each_fx.is_destruction = is_destruction;
for_each_fx.is_index = is_index;
for_each_fx.is_new_index = is_new_index;
for_each_fx.poison_indexing = poison_indexing;
for_each_fx.p_key = &s;
for_each_fx.p_ics = &ics;
if constexpr (is_lua_c_function_v<ValueU>) {
for_each_fx.is_unqualified_lua_CFunction = true;
for_each_fx.call_func = *static_cast<lua_CFunction*>(ics.binding_data);
}
int fast_index_table_push = fast_index_table.push();
stack_reference t(L, -fast_index_table_push);
if (poison_indexing) {
change_indexing(L,
smt,
derived_this,
t,
&usertype_storage<T>::index_call,
&usertype_storage<T>::new_index_call,
&usertype_storage<T>::meta_index_call,
&usertype_storage<T>::meta_new_index_call);
}
if (is_destruction
&& (smt == submetatable_type::reference || smt == submetatable_type::const_reference || smt == submetatable_type::named
|| smt == submetatable_type::unique)) {
// gc does not apply to us here
// for reference types (raw T*, std::ref)
// for the named metatable itself,
// or for unique_usertypes, which do their own custom destruction
t.pop();
return;
}
if constexpr (is_lua_c_function_v<ValueU> || is_lua_reference_or_proxy<ValueU>::value) {
stack::set_field<false, true>(L, s, b.data_, t.stack_index());
else if constexpr (is_lua_reference_or_proxy_v<ValueU>) {
for_each_fx.is_unqualified_lua_reference = true;
for_each_fx.p_binding_ref = static_cast<reference*>(ics.binding_data);
}
else {
stack::set_field<false, true>(L, s, make_closure(&b.template call<false, is_var_bind::value>, nullptr, ics.binding_data), t.stack_index());
for_each_fx.call_func = &b.template call<false, is_var_bind::value>;
}
t.pop();
};
for_each_fx.p_usb = this;
for_each_fx.p_derived_usb = derived_this;
for_each_fx.idx_call = &usertype_storage<T>::template index_call<false>;
for_each_fx.new_idx_call = &usertype_storage<T>::template index_call<true>;
for_each_fx.meta_idx_call = &usertype_storage<T>::template meta_index_call<false>;
for_each_fx.meta_new_idx_call = &usertype_storage<T>::template meta_index_call<true>;
for_each_fx.change_indexing = &usertype_storage_base::change_indexing;
// set base index and base new_index
// functions here
if (is_index) {
this->base_index = ics;
this->base_index.index = ics.index;
this->base_index.binding_data = ics.binding_data;
}
if (is_new_index) {
this->base_new_index = ics;
this->base_index.new_index = ics.new_index;
this->base_index.new_binding_data = ics.binding_data;
}
this->for_each_table(L, for_each_backing_metatable);
this->for_each_table(L, for_each_fx);
this->add_entry(s, std::move(ics));
}
else {
// the reference-based implementation might compare poorly and hash
// poorly in some cases...
if constexpr (is_lua_reference<KeyU>::value && is_lua_reference<ValueU>::value) {
if constexpr (is_lua_reference_v<KeyU> && is_lua_reference_v<ValueU>) {
if (key.get_type() == type::string) {
stack::push(L, key);
std::string string_key = stack::pop<std::string>(L);
this->set<T>(L, string_key, std::forward<Value>(value));
}
else {
auto ref_additions_fx = [&](lua_State* L, submetatable_type smt, reference& fast_index_table) {
if (smt == submetatable_type::named) {
return;
}
int fast_index_table_push = fast_index_table.push();
stack_reference t(L, -fast_index_table_push);
stack::set_field<false, true>(L, key, value, t.stack_index());
t.pop();
};
lua_reference_func ref_additions_fx{ key, value };
this->for_each_table(L, ref_additions_fx);
this->auxiliary_keys.insert_or_assign(std::forward<Key>(key), std::forward<Value>(value));
@ -657,15 +677,8 @@ namespace sol { namespace u_detail {
else {
reference ref_key = make_reference(L, std::forward<Key>(key));
reference ref_value = make_reference(L, std::forward<Value>(value));
auto ref_additions_fx = [&](lua_State* L, submetatable_type smt, reference& fast_index_table) {
if (smt == submetatable_type::named) {
return;
}
int fast_index_table_push = fast_index_table.push();
stack_reference t(L, -fast_index_table_push);
stack::set_field<false, true>(L, ref_key, ref_value, t.stack_index());
t.pop();
};
lua_reference_func ref_additions_fx{ key, value };
this->for_each_table(L, ref_additions_fx);
this->auxiliary_keys.insert_or_assign(std::move(ref_key), std::move(ref_value));
}
@ -952,11 +965,11 @@ namespace sol { namespace u_detail {
stack_reference stack_metametatable(L, -storage.named_index_table.push());
stack::set_field<false, true>(L,
meta_function::index,
make_closure(uts::meta_index_call, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic),
make_closure(uts::template meta_index_call<false>, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic),
stack_metametatable.stack_index());
stack::set_field<false, true>(L,
meta_function::new_index,
make_closure(uts::meta_new_index_call, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic),
make_closure(uts::template meta_index_call<true>, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic),
stack_metametatable.stack_index());
stack_metametatable.pop();
}
@ -966,7 +979,7 @@ namespace sol { namespace u_detail {
stack::set_field<false, true>(L, meta_function::index, t, t.stack_index());
stack::set_field<false, true>(L,
meta_function::new_index,
make_closure(uts::new_index_call, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic),
make_closure(uts::template index_call<true>, nullptr, light_storage, light_base_storage, nullptr, toplevel_magic),
t.stack_index());
storage.is_using_new_index = true;
}

View File

@ -31,6 +31,29 @@
#include <list>
#include <memory>
struct new_index_test_object {
bool new_indexed = false;
bool borf_new_indexed = false;
float GetLevel(int x) const {
return static_cast<float>(x);
}
static void nidx(new_index_test_object& self, std::string_view key, sol::stack_object value) {
if (key == "borf" && value.is<double>() && value.as<double>() == 2) {
self.borf_new_indexed = true;
return;
}
self.new_indexed = true;
}
static sol::object idx(sol::stack_object self, std::string_view key) {
if (key == "bark") {
return sol::object(self.lua_state(), sol::in_place, &new_index_test_object::GetLevel);
}
return sol::lua_nil;
}
};
TEST_CASE("usertype/runtime-extensibility", "Check if usertypes are runtime extensible") {
struct thing {
@ -339,3 +362,44 @@ TEST_CASE("usertype/meta-key-retrievals", "allow for special meta keys (__index,
REQUIRE(keys[3] == "__call");
}
}
TEST_CASE("usertype/new_index and index", "a custom new_index and index only kicks in after the values pre-ordained on the index and new_index tables are assigned") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<new_index_test_object>("new_index_test_object",
sol::meta_function::index,
&new_index_test_object::idx,
sol::meta_function::new_index,
&new_index_test_object::nidx,
"Level",
&new_index_test_object::GetLevel);
const auto& code = R"(a = new_index_test_object.new()
print(a:Level(1))
print(a:Level(2))
print(a:Level(3)))";
auto result0 = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(result0.valid());
auto result1 = lua.safe_script("print(a:bark(1))", sol::script_pass_on_error);
REQUIRE(result1.valid());
auto result2 = lua.safe_script("assert(a.Level2 == nil)", sol::script_pass_on_error);
REQUIRE(result2.valid());
auto result3 = lua.safe_script("a:Level3()", sol::script_pass_on_error);
REQUIRE_FALSE(result3.valid());
new_index_test_object& a = lua["a"];
REQUIRE_FALSE(a.borf_new_indexed);
REQUIRE_FALSE(a.new_indexed);
auto resultnormal = lua.safe_script("a.normal = 'foo'", sol::script_pass_on_error);
REQUIRE(resultnormal.valid());
REQUIRE_FALSE(a.borf_new_indexed);
REQUIRE(a.new_indexed);
auto resultborf = lua.safe_script("a.borf = 2", sol::script_pass_on_error);
REQUIRE(resultborf.valid());
REQUIRE(a.borf_new_indexed);
REQUIRE(a.new_indexed);
}