2018-09-28 13:27:38 +08:00
// sol3
2018-02-20 10:15:26 +08:00
2017-09-13 14:46:56 +08:00
// The MIT License (MIT)
2013-11-25 17:56:27 +08:00
2018-02-20 10:15:26 +08:00
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
2013-11-25 17:56:27 +08:00
// 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_STACK_HPP
# define SOL_STACK_HPP
2018-03-10 11:27:49 +08:00
# include "trampoline.hpp"
2016-03-25 03:45:44 +08:00
# include "stack_core.hpp"
2016-04-01 04:16:07 +08:00
# include "stack_reference.hpp"
2016-03-25 03:45:44 +08:00
# include "stack_check.hpp"
# include "stack_get.hpp"
# include "stack_check_get.hpp"
# include "stack_push.hpp"
# include "stack_pop.hpp"
# include "stack_field.hpp"
2016-03-25 17:27:19 +08:00
# include "stack_probe.hpp"
2018-12-20 12:17:15 +08:00
2013-12-10 06:01:52 +08:00
# include <cstring>
2016-03-25 03:45:44 +08:00
# include <array>
2013-11-25 17:56:27 +08:00
2016-06-20 05:59:40 +08:00
namespace sol {
2017-08-06 07:20:28 +08:00
namespace detail {
2017-09-07 03:09:51 +08:00
using typical_chunk_name_t = char [ 32 ] ;
2017-08-06 07:20:28 +08:00
inline const std : : string & default_chunk_name ( ) {
2017-08-07 14:27:08 +08:00
static const std : : string name = " " ;
2017-08-06 07:20:28 +08:00
return name ;
}
2017-08-07 14:07:21 +08:00
template < std : : size_t N >
const char * make_chunk_name ( const string_view & code , const std : : string & chunkname , char ( & basechunkname ) [ N ] ) {
if ( chunkname . empty ( ) ) {
auto it = code . cbegin ( ) ;
auto e = code . cend ( ) ;
std : : size_t i = 0 ;
2017-08-07 19:54:43 +08:00
static const std : : size_t n = N - 4 ;
2017-08-07 14:07:21 +08:00
for ( i = 0 ; i < n & & it ! = e ; + + i , + + it ) {
basechunkname [ i ] = * it ;
}
2017-08-07 19:54:43 +08:00
if ( it ! = e ) {
for ( std : : size_t c = 0 ; c < 3 ; + + i , + + c ) {
2017-08-07 19:59:13 +08:00
basechunkname [ i ] = ' . ' ;
2017-08-07 19:54:43 +08:00
}
}
2017-08-07 14:07:21 +08:00
basechunkname [ i ] = ' \0 ' ;
return & basechunkname [ 0 ] ;
}
else {
return chunkname . c_str ( ) ;
}
}
2019-01-05 18:48:51 +08:00
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 ) ;
}
2017-09-13 14:46:56 +08:00
} // namespace detail
2017-08-06 07:20:28 +08:00
2016-06-20 05:59:40 +08:00
namespace stack {
namespace stack_detail {
2017-09-13 14:46:56 +08:00
template < typename T >
2016-06-20 05:59:40 +08:00
inline int push_as_upvalues ( lua_State * L , T & item ) {
typedef std : : decay_t < T > TValue ;
2017-12-20 17:58:32 +08:00
static const std : : size_t itemsize = sizeof ( TValue ) ;
static const std : : size_t voidsize = sizeof ( void * ) ;
static const std : : size_t voidsizem1 = voidsize - 1 ;
static const std : : size_t data_t_count = ( sizeof ( TValue ) + voidsizem1 ) / voidsize ;
2016-06-20 05:59:40 +08:00
typedef std : : array < void * , data_t_count > data_t ;
2017-09-14 12:35:40 +08:00
data_t data { { } } ;
2016-06-20 05:59:40 +08:00
std : : memcpy ( & data [ 0 ] , std : : addressof ( item ) , itemsize ) ;
int pushcount = 0 ;
for ( auto & & v : data ) {
pushcount + = push ( L , lightuserdata_value ( v ) ) ;
}
return pushcount ;
2016-06-11 09:04:48 +08:00
}
2017-09-13 14:46:56 +08:00
template < typename T >
2017-05-10 01:24:56 +08:00
inline std : : pair < T , int > get_as_upvalues ( lua_State * L , int index = 2 ) {
2017-12-20 17:58:32 +08:00
static const std : : size_t data_t_count = ( sizeof ( T ) + ( sizeof ( void * ) - 1 ) ) / sizeof ( void * ) ;
2016-06-20 05:59:40 +08:00
typedef std : : array < void * , data_t_count > data_t ;
2017-09-14 12:35:40 +08:00
data_t voiddata { { } } ;
2016-06-20 05:59:40 +08:00
for ( std : : size_t i = 0 , d = 0 ; d < sizeof ( T ) ; + + i , d + = sizeof ( void * ) ) {
2016-07-08 04:52:39 +08:00
voiddata [ i ] = get < lightuserdata_value > ( L , upvalue_index ( index + + ) ) ;
2016-06-20 05:59:40 +08:00
}
return std : : pair < T , int > ( * reinterpret_cast < T * > ( static_cast < void * > ( voiddata . data ( ) ) ) , index ) ;
2016-06-11 09:04:48 +08:00
}
2019-01-14 10:46:53 +08:00
template < typename Fx , typename . . . Args >
static decltype ( auto ) eval ( types < > , std : : index_sequence < > , lua_State * , int , record & , Fx & & fx , Args & & . . . args ) {
return std : : forward < Fx > ( fx ) ( std : : forward < Args > ( args ) . . . ) ;
}
2017-09-13 14:46:56 +08:00
2019-01-14 10:46:53 +08:00
template < typename Fx , typename Arg , typename . . . Args , std : : size_t I , std : : size_t . . . Is , typename . . . FxArgs >
static decltype ( auto ) eval ( types < Arg , Args . . . > , std : : index_sequence < I , Is . . . > , lua_State * L , int start , record & tracking , Fx & & fx , FxArgs & & . . . fxargs ) {
return eval ( types < Args . . . > ( ) , std : : index_sequence < Is . . . > ( ) , L , start , tracking , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( fxargs ) . . . , stack_detail : : unchecked_get < Arg > ( L , start + tracking . used , tracking ) ) ;
}
2016-07-29 12:57:47 +08:00
2019-02-11 04:02:40 +08:00
template < bool checkargs = detail : : default_safe_function_calls , std : : size_t . . . I , typename R , typename . . . Args , typename Fx , typename . . . FxArgs >
2016-06-20 05:59:40 +08:00
inline decltype ( auto ) call ( types < R > , types < Args . . . > ta , std : : index_sequence < I . . . > tai , lua_State * L , int start , Fx & & fx , FxArgs & & . . . args ) {
static_assert ( meta : : all < meta : : is_not_move_only < Args > . . . > : : value , " One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention. " ) ;
2017-09-06 01:58:17 +08:00
argument_handler < types < R , Args . . . > > handler { } ;
2017-09-01 08:47:09 +08:00
multi_check < checkargs , Args . . . > ( L , start , handler ) ;
2016-07-29 12:57:47 +08:00
record tracking { } ;
2019-02-11 04:02:40 +08:00
if constexpr ( std : : is_void_v < R > ) {
eval ( ta , tai , L , start , tracking , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( args ) . . . ) ;
}
else {
return eval ( ta , tai , L , start , tracking , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( args ) . . . ) ;
}
2016-06-20 05:59:40 +08:00
}
2017-09-13 14:46:56 +08:00
} // namespace stack_detail
2016-06-20 05:59:40 +08:00
2016-06-20 07:13:01 +08:00
template < typename T >
int set_ref ( lua_State * L , T & & arg , int tableindex = - 2 ) {
push ( L , std : : forward < T > ( arg ) ) ;
return luaL_ref ( L , tableindex ) ;
2016-06-20 05:59:40 +08:00
}
2019-02-11 04:02:40 +08:00
template < bool check_args = detail : : default_safe_function_calls , typename R , typename . . . Args , typename Fx , typename . . . FxArgs >
2016-06-20 05:59:40 +08:00
inline decltype ( auto ) call ( types < R > tr , types < Args . . . > ta , lua_State * L , int start , Fx & & fx , FxArgs & & . . . args ) {
2019-02-11 04:02:40 +08:00
using args_indices = std : : make_index_sequence < sizeof . . . ( Args ) > ;
if constexpr ( std : : is_void_v < R > ) {
stack_detail : : call < check_args > ( tr , ta , args_indices ( ) , L , start , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( args ) . . . ) ;
}
else {
return stack_detail : : call < check_args > ( tr , ta , args_indices ( ) , L , start , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( args ) . . . ) ;
}
2016-06-20 05:59:40 +08:00
}
2019-02-11 04:02:40 +08:00
template < bool check_args = detail : : default_safe_function_calls , typename R , typename . . . Args , typename Fx , typename . . . FxArgs >
2016-06-20 05:59:40 +08:00
inline decltype ( auto ) call ( types < R > tr , types < Args . . . > ta , lua_State * L , Fx & & fx , FxArgs & & . . . args ) {
2019-02-11 04:02:40 +08:00
if constexpr ( std : : is_void_v < R > ) {
call < check_args > ( tr , ta , L , 1 , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( args ) . . . ) ;
}
else {
return call < check_args > ( tr , ta , L , 1 , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( args ) . . . ) ;
}
2016-06-20 05:59:40 +08:00
}
2019-02-11 04:02:40 +08:00
template < bool check_args = detail : : default_safe_function_calls , typename R , typename . . . Args , typename Fx , typename . . . FxArgs >
2016-06-20 05:59:40 +08:00
inline decltype ( auto ) call_from_top ( types < R > tr , types < Args . . . > ta , lua_State * L , Fx & & fx , FxArgs & & . . . args ) {
2019-02-11 04:02:40 +08:00
using expected_count_t = meta : : count_for_pack < lua_size , Args . . . > ;
if constexpr ( std : : is_void_v < R > ) {
call < check_args > ( tr ,
ta ,
L ,
2019-02-11 18:50:35 +08:00
( std : : max ) ( static_cast < int > ( lua_gettop ( L ) - expected_count_t : : value ) , static_cast < int > ( 0 ) ) ,
2019-02-11 04:02:40 +08:00
std : : forward < Fx > ( fx ) ,
std : : forward < FxArgs > ( args ) . . . ) ;
}
else {
return call < check_args > ( tr ,
ta ,
L ,
( std : : max ) ( static_cast < int > ( lua_gettop ( L ) - expected_count_t : : value ) , static_cast < int > ( 0 ) ) ,
std : : forward < Fx > ( fx ) ,
std : : forward < FxArgs > ( args ) . . . ) ;
2017-08-22 03:25:43 +08:00
}
2016-06-11 09:04:48 +08:00
}
2019-02-11 04:02:40 +08:00
template < bool check_args = detail : : default_safe_function_calls , bool clean_stack = true , typename Ret0 , typename . . . Ret , typename . . . Args , typename Fx , typename . . . FxArgs >
inline int call_into_lua ( types < Ret0 , Ret . . . > tr , types < Args . . . > ta , lua_State * L , int start , Fx & & fx , FxArgs & & . . . fxargs ) {
if constexpr ( std : : is_void_v < Ret0 > ) {
call < check_args > ( tr , ta , L , start , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( fxargs ) . . . ) ;
if constexpr ( clean_stack ) {
lua_settop ( L , 0 ) ;
}
return 0 ;
}
else {
( void ) tr ;
decltype ( auto ) r = call < check_args > ( types < meta : : return_type_t < Ret0 , Ret . . . > > ( ) , ta , L , start , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( fxargs ) . . . ) ;
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 ) ) ;
2017-08-22 03:25:43 +08:00
}
2016-06-11 09:04:48 +08:00
}
2016-06-20 05:59:40 +08:00
2017-12-08 10:46:43 +08:00
template < bool check_args = detail : : default_safe_function_calls , bool clean_stack = true , typename Fx , typename . . . FxArgs >
2016-06-20 05:59:40 +08:00
inline int call_lua ( lua_State * L , int start , Fx & & fx , FxArgs & & . . . fxargs ) {
2019-02-11 04:02:40 +08:00
using traits_type = lua_bind_traits < meta : : unqualified_t < Fx > > ;
using args_list = typename traits_type : : args_list ;
using returns_list = typename traits_type : : returns_list ;
2017-08-22 03:25:43 +08:00
return call_into_lua < check_args , clean_stack > ( returns_list ( ) , args_list ( ) , L , start , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( fxargs ) . . . ) ;
2016-06-11 09:04:48 +08:00
}
2016-06-20 05:59:40 +08:00
2018-01-29 11:21:13 +08:00
inline call_syntax get_call_syntax ( lua_State * L , const string_view & key , int index ) {
2018-12-20 12:17:15 +08:00
if ( lua_gettop ( L ) < 1 ) {
2016-11-16 11:45:34 +08:00
return call_syntax : : dot ;
}
2018-01-29 11:21:13 +08:00
luaL_getmetatable ( L , key . data ( ) ) ;
2016-07-29 01:33:08 +08:00
auto pn = pop_n ( L , 1 ) ;
2016-11-16 11:45:34 +08:00
if ( lua_compare ( L , - 1 , index , LUA_OPEQ ) ! = 1 ) {
return call_syntax : : dot ;
2016-06-20 05:59:40 +08:00
}
2016-11-16 11:45:34 +08:00
return call_syntax : : colon ;
2016-06-11 09:04:48 +08:00
}
2018-08-10 23:17:31 +08:00
inline void script ( lua_State * L , lua_Reader reader , void * data , const std : : string & chunkname = detail : : default_chunk_name ( ) , load_mode mode = load_mode : : any ) {
detail : : typical_chunk_name_t basechunkname = { } ;
const char * chunknametarget = detail : : make_chunk_name ( " lua_Reader " , chunkname , basechunkname ) ;
if ( lua_load ( L , reader , data , chunknametarget , to_string ( mode ) . c_str ( ) ) | | lua_pcall ( L , 0 , LUA_MULTRET , 0 ) ) {
lua_error ( L ) ;
}
}
2017-09-06 08:29:21 +08:00
inline void script ( lua_State * L , const string_view & code , const std : : string & chunkname = detail : : default_chunk_name ( ) , load_mode mode = load_mode : : any ) {
2017-09-07 03:09:51 +08:00
detail : : typical_chunk_name_t basechunkname = { } ;
2017-08-07 14:07:21 +08:00
const char * chunknametarget = detail : : make_chunk_name ( code , chunkname , basechunkname ) ;
if ( luaL_loadbufferx ( L , code . data ( ) , code . size ( ) , chunknametarget , to_string ( mode ) . c_str ( ) ) | | lua_pcall ( L , 0 , LUA_MULTRET , 0 ) ) {
2016-06-23 01:26:27 +08:00
lua_error ( L ) ;
}
}
2017-08-06 07:20:28 +08:00
inline void script_file ( lua_State * L , const std : : string & filename , load_mode mode = load_mode : : any ) {
if ( luaL_loadfilex ( L , filename . c_str ( ) , to_string ( mode ) . c_str ( ) ) | | lua_pcall ( L , 0 , LUA_MULTRET , 0 ) ) {
2016-06-23 01:26:27 +08:00
lua_error ( L ) ;
}
}
2017-09-13 14:46:56 +08:00
inline void luajit_exception_handler ( lua_State * L , int ( * handler ) ( lua_State * , lua_CFunction ) = detail : : c_trampoline ) {
2018-12-23 04:36:42 +08:00
# if defined(SOL_LUAJIT) && (!defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || !(SOL_EXCEPTIONS_SAFE_PROPAGATION))
2017-09-13 07:15:23 +08:00
if ( L = = nullptr ) {
return ;
}
2018-12-20 12:17:15 +08:00
# if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
luaL_checkstack ( L , 1 , detail : : not_enough_stack_space_generic ) ;
# endif // make sure stack doesn't overflow
2016-06-20 05:59:40 +08:00
lua_pushlightuserdata ( L , ( void * ) handler ) ;
2016-07-29 01:33:08 +08:00
auto pn = pop_n ( L , 1 ) ;
2016-06-20 05:59:40 +08:00
luaJIT_setmode ( L , - 1 , LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON ) ;
2016-02-27 15:59:47 +08:00
# else
2016-06-20 05:59:40 +08:00
( void ) L ;
( void ) handler ;
2016-02-27 15:43:53 +08:00
# endif
2016-06-20 05:59:40 +08:00
}
2016-02-27 15:43:53 +08:00
2016-06-20 05:59:40 +08:00
inline void luajit_exception_off ( lua_State * L ) {
2017-11-12 07:33:56 +08:00
# if defined(SOL_LUAJIT)
2017-09-13 07:15:23 +08:00
if ( L = = nullptr ) {
return ;
}
2016-06-20 05:59:40 +08:00
luaJIT_setmode ( L , - 1 , LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_OFF ) ;
2016-02-27 15:59:47 +08:00
# else
2016-06-20 05:59:40 +08:00
( void ) L ;
2016-02-27 15:43:53 +08:00
# endif
2016-06-20 05:59:40 +08:00
}
2017-09-13 14:46:56 +08:00
} // namespace stack
} // namespace sol
2013-11-25 17:56:27 +08:00
2014-05-29 14:38:02 +08:00
# endif // SOL_STACK_HPP