2016-03-14 21:53:24 +08:00
// The MIT License (MIT)
2013-11-25 17:56:27 +08:00
2017-05-15 22:41:50 +08:00
// Copyright (c) 2013-2017 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
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"
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 {
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 ( ) ;
}
}
2017-08-06 07:20:28 +08:00
} // detail
2016-06-20 05:59:40 +08:00
namespace stack {
namespace stack_detail {
template < typename T >
inline int push_as_upvalues ( lua_State * L , T & item ) {
typedef std : : decay_t < T > TValue ;
const static std : : size_t itemsize = sizeof ( TValue ) ;
const static std : : size_t voidsize = sizeof ( void * ) ;
const static std : : size_t voidsizem1 = voidsize - 1 ;
const static std : : size_t data_t_count = ( sizeof ( TValue ) + voidsizem1 ) / voidsize ;
typedef std : : array < void * , data_t_count > data_t ;
data_t data { { } } ;
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
}
2016-06-20 05:59:40 +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 ) {
2016-06-20 05:59:40 +08:00
const static std : : size_t data_t_count = ( sizeof ( T ) + ( sizeof ( void * ) - 1 ) ) / sizeof ( void * ) ;
typedef std : : array < void * , data_t_count > data_t ;
data_t voiddata { { } } ;
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
}
2016-07-29 12:57:47 +08:00
struct evaluator {
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 ) . . . ) ;
}
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-06-20 05:59:40 +08:00
template < bool checkargs = default_check_arguments , std : : size_t . . . I , typename R , typename . . . Args , typename Fx , typename . . . FxArgs , typename = std : : enable_if_t < ! std : : is_void < R > : : value > >
inline decltype ( auto ) call ( types < R > , types < Args . . . > ta , std : : index_sequence < I . . . > tai , lua_State * L , int start , Fx & & fx , FxArgs & & . . . args ) {
2016-05-19 14:15:42 +08:00
# ifndef _MSC_VER
2016-06-20 05:59:40 +08:00
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
# endif // This compiler make me so sad
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 { } ;
return evaluator { } . eval ( ta , tai , L , start , tracking , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( args ) . . . ) ;
2016-06-20 05:59:40 +08:00
}
2013-12-16 05:27:20 +08:00
2016-06-20 05:59:40 +08:00
template < bool checkargs = default_check_arguments , std : : size_t . . . I , typename . . . Args , typename Fx , typename . . . FxArgs >
inline void call ( types < void > , types < Args . . . > ta , std : : index_sequence < I . . . > tai , lua_State * L , int start , Fx & & fx , FxArgs & & . . . args ) {
2016-05-19 14:15:42 +08:00
# ifndef _MSC_VER
2016-06-20 05:59:40 +08:00
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. " ) ;
2016-05-19 14:15:42 +08:00
# endif // This compiler make me so fucking sad
2017-09-06 01:58:17 +08:00
argument_handler < types < void , 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 { } ;
evaluator { } . eval ( ta , tai , L , start , tracking , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( args ) . . . ) ;
2016-06-20 05:59:40 +08:00
}
} // stack_detail
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
}
template < bool check_args = stack_detail : : default_check_arguments , typename R , typename . . . Args , typename Fx , typename . . . FxArgs , typename = std : : enable_if_t < ! std : : is_void < R > : : value > >
inline decltype ( auto ) call ( types < R > tr , types < Args . . . > ta , lua_State * L , int start , Fx & & fx , FxArgs & & . . . args ) {
typedef std : : make_index_sequence < sizeof . . . ( Args ) > args_indices ;
return stack_detail : : call < check_args > ( tr , ta , args_indices ( ) , L , start , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( args ) . . . ) ;
}
template < bool check_args = stack_detail : : default_check_arguments , typename R , typename . . . Args , typename Fx , typename . . . FxArgs , typename = std : : enable_if_t < ! std : : is_void < R > : : value > >
inline decltype ( auto ) call ( types < R > tr , types < Args . . . > ta , lua_State * L , Fx & & fx , FxArgs & & . . . args ) {
return call < check_args > ( tr , ta , L , 1 , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( args ) . . . ) ;
}
template < bool check_args = stack_detail : : default_check_arguments , typename . . . Args , typename Fx , typename . . . FxArgs >
inline void call ( types < void > tr , types < Args . . . > ta , lua_State * L , int start , Fx & & fx , FxArgs & & . . . args ) {
typedef std : : make_index_sequence < sizeof . . . ( Args ) > args_indices ;
stack_detail : : call < check_args > ( tr , ta , args_indices ( ) , L , start , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( args ) . . . ) ;
}
template < bool check_args = stack_detail : : default_check_arguments , typename . . . Args , typename Fx , typename . . . FxArgs >
inline void call ( types < void > tr , types < Args . . . > ta , lua_State * L , Fx & & fx , FxArgs & & . . . args ) {
call < check_args > ( tr , ta , L , 1 , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( args ) . . . ) ;
}
template < bool check_args = stack_detail : : default_check_arguments , typename R , typename . . . Args , typename Fx , typename . . . FxArgs , typename = std : : enable_if_t < ! std : : is_void < R > : : value > >
inline decltype ( auto ) call_from_top ( types < R > tr , types < Args . . . > ta , lua_State * L , Fx & & fx , FxArgs & & . . . args ) {
2017-08-22 03:25:43 +08:00
typedef meta : : count_for_pack < lua_size , Args . . . > expected_count ;
return call < check_args > ( tr , ta , L , ( std : : max ) ( static_cast < int > ( lua_gettop ( L ) - expected_count : : value ) , static_cast < int > ( 0 ) ) , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( args ) . . . ) ;
2016-06-20 05:59:40 +08:00
}
template < bool check_args = stack_detail : : default_check_arguments , typename . . . Args , typename Fx , typename . . . FxArgs >
inline void call_from_top ( types < void > tr , types < Args . . . > ta , lua_State * L , Fx & & fx , FxArgs & & . . . args ) {
2017-08-22 03:25:43 +08:00
typedef meta : : count_for_pack < lua_size , Args . . . > expected_count ;
call < check_args > ( tr , ta , L , ( std : : max ) ( static_cast < int > ( lua_gettop ( L ) - expected_count : : value ) , static_cast < int > ( 0 ) ) , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( args ) . . . ) ;
2016-06-11 09:04:48 +08:00
}
2016-06-20 05:59:40 +08:00
2017-08-22 03:25:43 +08:00
template < bool check_args = stack_detail : : default_check_arguments , bool clean_stack = true , typename . . . Args , typename Fx , typename . . . FxArgs >
2016-06-20 05:59:40 +08:00
inline int call_into_lua ( types < void > tr , types < Args . . . > ta , lua_State * L , int start , Fx & & fx , FxArgs & & . . . fxargs ) {
call < check_args > ( tr , ta , L , start , std : : forward < Fx > ( fx ) , std : : forward < FxArgs > ( fxargs ) . . . ) ;
2017-08-22 03:25:43 +08:00
if ( clean_stack ) {
lua_settop ( L , 0 ) ;
}
2016-06-20 05:59:40 +08:00
return 0 ;
2016-06-11 09:04:48 +08:00
}
2017-08-22 03:25:43 +08:00
template < bool check_args = stack_detail : : default_check_arguments , 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 > >
2016-06-20 05:59:40 +08:00
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 ) . . . ) ;
2017-08-22 03:25:43 +08:00
typedef is_stack_based < meta : : unqualified_t < decltype ( r ) > > is_stack ;
if ( clean_stack & & ! is_stack : : value ) {
lua_settop ( L , 0 ) ;
}
2016-06-20 05:59:40 +08:00
return push_reference ( L , std : : forward < decltype ( r ) > ( r ) ) ;
2016-06-11 09:04:48 +08:00
}
2016-06-20 05:59:40 +08:00
2017-08-22 03:25:43 +08:00
template < bool check_args = stack_detail : : default_check_arguments , 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 ) {
typedef lua_bind_traits < meta : : unqualified_t < Fx > > traits_type ;
typedef typename traits_type : : args_list args_list ;
typedef typename traits_type : : returns_list 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
2016-11-16 11:45:34 +08:00
inline call_syntax get_call_syntax ( lua_State * L , const std : : string & key , int index ) {
if ( lua_gettop ( L ) = = 0 ) {
return call_syntax : : dot ;
}
2016-06-20 05:59:40 +08:00
luaL_getmetatable ( L , key . c_str ( ) ) ;
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
}
2017-08-07 14:07:21 +08:00
inline void script ( lua_State * L , const string_detail : : string_shim & code , const std : : string & chunkname = detail : : default_chunk_name ( ) , load_mode mode = load_mode : : any ) {
char basechunkname [ 17 ] = { } ;
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 ) ;
}
}
2016-06-20 05:59:40 +08:00
inline void luajit_exception_handler ( lua_State * L , int ( * handler ) ( lua_State * , lua_CFunction ) = detail : : c_trampoline ) {
2016-02-27 15:43:53 +08:00
# ifdef SOL_LUAJIT
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 ) {
2016-02-27 15:43:53 +08:00
# ifdef SOL_LUAJIT
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
}
} // stack
} // sol
2013-11-25 17:56:27 +08:00
2014-05-29 14:38:02 +08:00
# endif // SOL_STACK_HPP