2017-09-13 14:46:56 +08:00
// The MIT License (MIT)
2016-03-25 03:45:44 +08:00
2017-05-15 22:41:50 +08:00
// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors
2016-03-25 03:45:44 +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_CORE_HPP
# define SOL_STACK_CORE_HPP
# include "types.hpp"
2017-09-01 08:47:09 +08:00
# include "error_handler.hpp"
2016-03-25 03:45:44 +08:00
# include "reference.hpp"
2016-04-01 04:16:07 +08:00
# include "stack_reference.hpp"
2016-03-25 03:45:44 +08:00
# include "tuple.hpp"
# include "traits.hpp"
2016-04-24 22:09:05 +08:00
# include "tie.hpp"
2016-10-05 11:37:08 +08:00
# include "stack_guard.hpp"
2017-08-22 03:25:43 +08:00
# include "demangle.hpp"
# include "forward_detail.hpp"
2016-08-20 09:08:03 +08:00
# include <vector>
2017-08-06 07:20:28 +08:00
# include <forward_list>
2016-08-20 09:08:03 +08:00
# include <string>
2017-08-22 03:25:43 +08:00
# include <algorithm>
2016-03-25 03:45:44 +08:00
namespace sol {
2016-06-17 08:15:56 +08:00
namespace detail {
struct as_reference_tag { } ;
2016-08-24 09:42:27 +08:00
template < typename T >
struct as_pointer_tag { } ;
template < typename T >
struct as_value_tag { } ;
2017-09-23 06:54:33 +08:00
template < typename T >
struct as_table_tag { } ;
2016-06-17 08:15:56 +08:00
2017-09-13 14:46:56 +08:00
using unique_destructor = void ( * ) ( void * ) ;
2016-06-17 08:15:56 +08:00
template < typename T >
inline int unique_destruct ( lua_State * L ) {
void * memory = lua_touserdata ( L , 1 ) ;
T * * pointerpointer = static_cast < T * * > ( memory ) ;
2017-06-15 13:23:51 +08:00
unique_destructor & dx = * static_cast < unique_destructor * > ( static_cast < void * > ( pointerpointer + 1 ) ) ;
2016-06-17 08:15:56 +08:00
( dx ) ( memory ) ;
return 0 ;
}
2016-08-20 09:08:03 +08:00
2016-08-24 09:42:27 +08:00
template < typename T >
2017-08-22 03:25:43 +08:00
inline int user_alloc_destruct ( lua_State * L ) {
2016-11-23 15:39:52 +08:00
void * rawdata = lua_touserdata ( L , 1 ) ;
2016-08-24 09:42:27 +08:00
T * data = static_cast < T * > ( rawdata ) ;
std : : allocator < T > alloc ;
alloc . destroy ( data ) ;
return 0 ;
}
template < typename T >
2017-08-22 03:25:43 +08:00
inline int usertype_alloc_destruct ( lua_State * L ) {
2016-08-24 09:42:27 +08:00
void * rawdata = lua_touserdata ( L , 1 ) ;
T * * pdata = static_cast < T * * > ( rawdata ) ;
T * data = * pdata ;
std : : allocator < T > alloc { } ;
alloc . destroy ( data ) ;
return 0 ;
}
2017-08-22 03:25:43 +08:00
template < typename T >
inline int cannot_destruct ( lua_State * L ) {
return luaL_error ( L , " cannot call the destructor for '%s': it is either hidden (protected/private) or removed with ' = delete ' and thusly this type is being destroyed without properly destructing , invoking undefined behavior " , detail::demangle<T>().data()) ;
}
template < typename T , typename Real >
inline void usertype_unique_alloc_destroy ( void * memory ) {
T * * pointerpointer = static_cast < T * * > ( memory ) ;
unique_destructor * dx = static_cast < unique_destructor * > ( static_cast < void * > ( pointerpointer + 1 ) ) ;
Real * target = static_cast < Real * > ( static_cast < void * > ( dx + 1 ) ) ;
std : : allocator < Real > alloc ;
alloc . destroy ( target ) ;
}
2016-08-20 09:08:03 +08:00
template < typename T >
2017-09-13 14:46:56 +08:00
void reserve ( T & , std : : size_t ) {
}
2016-08-20 09:08:03 +08:00
template < typename T , typename Al >
void reserve ( std : : vector < T , Al > & arr , std : : size_t hint ) {
arr . reserve ( hint ) ;
}
template < typename T , typename Tr , typename Al >
void reserve ( std : : basic_string < T , Tr , Al > & arr , std : : size_t hint ) {
arr . reserve ( hint ) ;
}
2017-09-13 14:46:56 +08:00
} // namespace detail
2016-06-17 08:15:56 +08:00
namespace stack {
2017-09-13 14:46:56 +08:00
template < typename T , bool global = false , bool raw = false , typename = void >
2016-06-17 08:15:56 +08:00
struct field_getter ;
template < typename T , bool global = false , bool raw = false , typename = void >
struct probe_field_getter ;
2017-09-13 14:46:56 +08:00
template < typename T , bool global = false , bool raw = false , typename = void >
2016-06-17 08:15:56 +08:00
struct field_setter ;
2017-09-13 14:46:56 +08:00
template < typename T , typename = void >
2016-06-17 08:15:56 +08:00
struct getter ;
2017-09-13 14:46:56 +08:00
template < typename T , typename = void >
2016-06-17 08:15:56 +08:00
struct popper ;
2017-09-13 14:46:56 +08:00
template < typename T , typename = void >
2016-06-17 08:15:56 +08:00
struct pusher ;
2017-09-13 14:46:56 +08:00
template < typename T , type = lua_type_of < T > : : value , typename = void >
2016-06-17 08:15:56 +08:00
struct checker ;
2017-09-13 14:46:56 +08:00
template < typename T , typename = void >
2016-06-17 08:15:56 +08:00
struct check_getter ;
struct probe {
bool success ;
int levels ;
2017-09-13 14:46:56 +08:00
probe ( bool s , int l )
: success ( s ) , levels ( l ) {
}
2016-06-17 08:15:56 +08:00
2017-09-13 14:46:56 +08:00
operator bool ( ) const {
return success ;
} ;
2016-06-17 08:15:56 +08:00
} ;
2016-07-29 12:57:47 +08:00
struct record {
int last ;
int used ;
2017-09-13 14:46:56 +08:00
record ( )
: last ( ) , used ( ) {
}
2016-07-29 12:57:47 +08:00
void use ( int count ) {
last = count ;
used + = count ;
}
} ;
2016-06-17 08:15:56 +08:00
namespace stack_detail {
template < typename T >
struct strip {
typedef T type ;
} ;
template < typename T >
struct strip < std : : reference_wrapper < T > > {
typedef T & type ;
} ;
template < typename T >
2016-07-08 04:52:39 +08:00
struct strip < user < T > > {
typedef T & type ;
} ;
template < typename T >
2016-06-17 08:15:56 +08:00
struct strip < non_null < T > > {
typedef T type ;
} ;
template < typename T >
using strip_t = typename strip < T > : : type ;
2017-05-29 22:32:37 +08:00
2016-06-17 08:15:56 +08:00
const bool default_check_arguments =
2016-03-25 03:45:44 +08:00
# ifdef SOL_CHECK_ARGUMENTS
2016-06-17 08:15:56 +08:00
true ;
2016-03-25 03:45:44 +08:00
# else
2016-06-17 08:15:56 +08:00
false ;
2016-03-25 03:45:44 +08:00
# endif
2017-08-06 07:20:28 +08:00
template < typename C >
static int get_size_hint ( const C & c ) {
return static_cast < int > ( c . size ( ) ) ;
}
template < typename V , typename Al >
2017-08-07 14:07:21 +08:00
static int get_size_hint ( const std : : forward_list < V , Al > & ) {
2017-08-06 07:20:28 +08:00
// forward_list makes me sad
return static_cast < int > ( 32 ) ;
}
2017-09-13 14:46:56 +08:00
template < typename T >
2016-07-29 12:57:47 +08:00
inline decltype ( auto ) unchecked_get ( lua_State * L , int index , record & tracking ) {
2017-08-07 14:07:21 +08:00
getter < meta : : unqualified_t < T > > g { } ;
( void ) g ;
return g . get ( L , index , tracking ) ;
2016-06-17 08:15:56 +08:00
}
2017-05-29 22:32:37 +08:00
2017-09-13 14:46:56 +08:00
template < typename T , typename Arg , typename . . . Args >
2017-05-29 22:32:37 +08:00
inline int push_reference ( lua_State * L , Arg & & arg , Args & & . . . args ) {
typedef meta : : all <
std : : is_lvalue_reference < T > ,
meta : : neg < std : : is_const < T > > ,
meta : : neg < is_lua_primitive < meta : : unqualified_t < T > > > ,
2017-09-13 14:46:56 +08:00
meta : : neg < is_unique_usertype < meta : : unqualified_t < T > > > >
use_reference_tag ;
2017-05-29 22:32:37 +08:00
return pusher < std : : conditional_t < use_reference_tag : : value , detail : : as_reference_tag , meta : : unqualified_t < T > > > { } . push ( L , std : : forward < Arg > ( arg ) , std : : forward < Args > ( args ) . . . ) ;
}
2017-09-13 14:46:56 +08:00
} // namespace stack_detail
2016-06-17 08:15:56 +08:00
inline bool maybe_indexable ( lua_State * L , int index = - 1 ) {
type t = type_of ( L , index ) ;
return t = = type : : userdata | | t = = type : : table ;
}
2017-08-06 07:20:28 +08:00
inline int top ( lua_State * L ) {
return lua_gettop ( L ) ;
}
2017-09-13 14:46:56 +08:00
template < typename T , typename . . . Args >
2016-06-17 08:15:56 +08:00
inline int push ( lua_State * L , T & & t , Args & & . . . args ) {
return pusher < meta : : unqualified_t < T > > { } . push ( L , std : : forward < T > ( t ) , std : : forward < Args > ( args ) . . . ) ;
}
// overload allows to use a pusher of a specific type, but pass in any kind of args
2017-09-13 14:46:56 +08:00
template < typename T , typename Arg , typename . . . Args , typename = std : : enable_if_t < ! std : : is_same < T , Arg > : : value > >
2016-06-17 08:15:56 +08:00
inline int push ( lua_State * L , Arg & & arg , Args & & . . . args ) {
return pusher < meta : : unqualified_t < T > > { } . push ( L , std : : forward < Arg > ( arg ) , std : : forward < Args > ( args ) . . . ) ;
}
2017-09-13 14:46:56 +08:00
template < typename T , typename . . . Args >
2016-06-17 08:15:56 +08:00
inline int push_reference ( lua_State * L , T & & t , Args & & . . . args ) {
2017-05-29 22:32:37 +08:00
return stack_detail : : push_reference < T > ( L , std : : forward < T > ( t ) , std : : forward < Args > ( args ) . . . ) ;
}
2017-09-13 14:46:56 +08:00
template < typename T , typename Arg , typename . . . Args >
2017-05-29 22:32:37 +08:00
inline int push_reference ( lua_State * L , Arg & & arg , Args & & . . . args ) {
return stack_detail : : push_reference < T > ( L , std : : forward < Arg > ( arg ) , std : : forward < Args > ( args ) . . . ) ;
2016-06-17 08:15:56 +08:00
}
inline int multi_push ( lua_State * ) {
// do nothing
return 0 ;
}
2017-09-13 14:46:56 +08:00
template < typename T , typename . . . Args >
2016-06-17 08:15:56 +08:00
inline int multi_push ( lua_State * L , T & & t , Args & & . . . args ) {
int pushcount = push ( L , std : : forward < T > ( t ) ) ;
2017-09-23 06:54:33 +08:00
void ( detail : : swallow { ( pushcount + = stack : : push ( L , std : : forward < Args > ( args ) ) , 0 ) . . . } ) ;
2016-06-17 08:15:56 +08:00
return pushcount ;
}
inline int multi_push_reference ( lua_State * ) {
// do nothing
return 0 ;
}
2017-09-13 14:46:56 +08:00
template < typename T , typename . . . Args >
2016-06-17 08:15:56 +08:00
inline int multi_push_reference ( lua_State * L , T & & t , Args & & . . . args ) {
int pushcount = push_reference ( L , std : : forward < T > ( t ) ) ;
2017-09-23 06:54:33 +08:00
void ( detail : : swallow { ( pushcount + = stack : : push_reference ( L , std : : forward < Args > ( args ) ) , 0 ) . . . } ) ;
2016-06-17 08:15:56 +08:00
return pushcount ;
}
template < typename T , typename Handler >
2016-07-29 12:57:47 +08:00
bool check ( lua_State * L , int index , Handler & & handler , record & tracking ) {
2016-06-17 08:15:56 +08:00
typedef meta : : unqualified_t < T > Tu ;
checker < Tu > c ;
// VC++ has a bad warning here: shut it up
( void ) c ;
2016-07-29 12:57:47 +08:00
return c . check ( L , index , std : : forward < Handler > ( handler ) , tracking ) ;
}
template < typename T , typename Handler >
bool check ( lua_State * L , int index , Handler & & handler ) {
record tracking { } ;
return check < T > ( L , index , std : : forward < Handler > ( handler ) , tracking ) ;
2016-06-17 08:15:56 +08:00
}
template < typename T >
2016-08-23 10:45:06 +08:00
bool check ( lua_State * L , int index = - lua_size < meta : : unqualified_t < T > > : : value ) {
2016-06-17 08:15:56 +08:00
auto handler = no_panic ;
return check < T > ( L , index , handler ) ;
}
2017-09-13 14:46:56 +08:00
template < typename T , typename Handler >
2016-07-29 12:57:47 +08:00
inline decltype ( auto ) check_get ( lua_State * L , int index , Handler & & handler , record & tracking ) {
2017-08-06 07:20:28 +08:00
typedef meta : : unqualified_t < T > Tu ;
check_getter < Tu > cg { } ;
( void ) cg ;
return cg . get ( L , index , std : : forward < Handler > ( handler ) , tracking ) ;
2016-07-29 12:57:47 +08:00
}
2017-09-13 14:46:56 +08:00
template < typename T , typename Handler >
2016-06-17 08:15:56 +08:00
inline decltype ( auto ) check_get ( lua_State * L , int index , Handler & & handler ) {
2016-07-29 12:57:47 +08:00
record tracking { } ;
return check_get < T > ( L , index , handler , tracking ) ;
2016-06-17 08:15:56 +08:00
}
2017-09-13 14:46:56 +08:00
template < typename T >
2016-08-23 10:45:06 +08:00
inline decltype ( auto ) check_get ( lua_State * L , int index = - lua_size < meta : : unqualified_t < T > > : : value ) {
2016-06-17 08:15:56 +08:00
auto handler = no_panic ;
return check_get < T > ( L , index , handler ) ;
}
namespace stack_detail {
2016-03-25 03:45:44 +08:00
# ifdef SOL_CHECK_ARGUMENTS
2016-06-17 08:15:56 +08:00
template < typename T >
2016-07-29 12:57:47 +08:00
inline auto tagged_get ( types < T > , lua_State * L , int index , record & tracking ) - > decltype ( stack_detail : : unchecked_get < T > ( L , index , tracking ) ) {
2017-09-01 08:47:09 +08:00
auto op = check_get < T > ( L , index , type_panic_c_str , tracking ) ;
2016-11-26 09:47:15 +08:00
return * std : : move ( op ) ;
2016-06-17 08:15:56 +08:00
}
2016-03-25 03:45:44 +08:00
# else
2016-06-17 08:15:56 +08:00
template < typename T >
2016-07-29 12:57:47 +08:00
inline decltype ( auto ) tagged_get ( types < T > , lua_State * L , int index , record & tracking ) {
return stack_detail : : unchecked_get < T > ( L , index , tracking ) ;
2016-06-17 08:15:56 +08:00
}
2016-03-25 03:45:44 +08:00
# endif
2016-06-17 08:15:56 +08:00
template < typename T >
2016-07-29 12:57:47 +08:00
inline decltype ( auto ) tagged_get ( types < optional < T > > , lua_State * L , int index , record & tracking ) {
return stack_detail : : unchecked_get < optional < T > > ( L , index , tracking ) ;
2016-06-17 08:15:56 +08:00
}
2016-07-29 12:57:47 +08:00
template < bool b >
struct check_types {
template < typename T , typename . . . Args , typename Handler >
static bool check ( types < T , Args . . . > , lua_State * L , int firstargument , Handler & & handler , record & tracking ) {
if ( ! stack : : check < T > ( L , firstargument + tracking . used , handler , tracking ) )
return false ;
return check ( types < Args . . . > ( ) , L , firstargument , std : : forward < Handler > ( handler ) , tracking ) ;
}
template < typename Handler >
static bool check ( types < > , lua_State * , int , Handler & & , record & ) {
return true ;
}
} ;
template < >
struct check_types < false > {
template < typename . . . Args , typename Handler >
static bool check ( types < Args . . . > , lua_State * , int , Handler & & , record & ) {
return true ;
}
} ;
2017-09-13 14:46:56 +08:00
} // namespace stack_detail
2016-06-17 08:15:56 +08:00
2016-07-29 12:57:47 +08:00
template < bool b , typename . . . Args , typename Handler >
bool multi_check ( lua_State * L , int index , Handler & & handler , record & tracking ) {
return stack_detail : : check_types < b > { } . check ( types < meta : : unqualified_t < Args > . . . > ( ) , L , index , std : : forward < Handler > ( handler ) , tracking ) ;
}
template < bool b , typename . . . Args , typename Handler >
bool multi_check ( lua_State * L , int index , Handler & & handler ) {
record tracking { } ;
return multi_check < b , Args . . . > ( L , index , std : : forward < Handler > ( handler ) , tracking ) ;
}
template < bool b , typename . . . Args >
bool multi_check ( lua_State * L , int index ) {
auto handler = no_panic ;
return multi_check < b , Args . . . > ( L , index , handler ) ;
}
template < typename . . . Args , typename Handler >
bool multi_check ( lua_State * L , int index , Handler & & handler , record & tracking ) {
return multi_check < true , Args . . . > ( L , index , std : : forward < Handler > ( handler ) , tracking ) ;
}
template < typename . . . Args , typename Handler >
bool multi_check ( lua_State * L , int index , Handler & & handler ) {
return multi_check < true , Args . . . > ( L , index , std : : forward < Handler > ( handler ) ) ;
}
template < typename . . . Args >
bool multi_check ( lua_State * L , int index ) {
return multi_check < true , Args . . . > ( L , index ) ;
}
2017-09-13 14:46:56 +08:00
template < typename T >
2016-07-29 12:57:47 +08:00
inline decltype ( auto ) get ( lua_State * L , int index , record & tracking ) {
return stack_detail : : tagged_get ( types < T > ( ) , L , index , tracking ) ;
}
2017-09-13 14:46:56 +08:00
template < typename T >
2016-08-23 10:45:06 +08:00
inline decltype ( auto ) get ( lua_State * L , int index = - lua_size < meta : : unqualified_t < T > > : : value ) {
2016-07-29 12:57:47 +08:00
record tracking { } ;
return get < T > ( L , index , tracking ) ;
2016-06-17 08:15:56 +08:00
}
2017-09-13 14:46:56 +08:00
template < typename T >
2016-06-17 08:15:56 +08:00
inline decltype ( auto ) pop ( lua_State * L ) {
return popper < meta : : unqualified_t < T > > { } . pop ( L ) ;
}
template < bool global = false , bool raw = false , typename Key >
void get_field ( lua_State * L , Key & & key ) {
field_getter < meta : : unqualified_t < Key > , global , raw > { } . get ( L , std : : forward < Key > ( key ) ) ;
}
template < bool global = false , bool raw = false , typename Key >
void get_field ( lua_State * L , Key & & key , int tableindex ) {
field_getter < meta : : unqualified_t < Key > , global , raw > { } . get ( L , std : : forward < Key > ( key ) , tableindex ) ;
}
template < bool global = false , typename Key >
void raw_get_field ( lua_State * L , Key & & key ) {
get_field < global , true > ( L , std : : forward < Key > ( key ) ) ;
}
template < bool global = false , typename Key >
void raw_get_field ( lua_State * L , Key & & key , int tableindex ) {
get_field < global , true > ( L , std : : forward < Key > ( key ) , tableindex ) ;
}
template < bool global = false , bool raw = false , typename Key >
probe probe_get_field ( lua_State * L , Key & & key ) {
return probe_field_getter < meta : : unqualified_t < Key > , global , raw > { } . get ( L , std : : forward < Key > ( key ) ) ;
}
template < bool global = false , bool raw = false , typename Key >
probe probe_get_field ( lua_State * L , Key & & key , int tableindex ) {
return probe_field_getter < meta : : unqualified_t < Key > , global , raw > { } . get ( L , std : : forward < Key > ( key ) , tableindex ) ;
}
template < bool global = false , typename Key >
probe probe_raw_get_field ( lua_State * L , Key & & key ) {
return probe_get_field < global , true > ( L , std : : forward < Key > ( key ) ) ;
}
template < bool global = false , typename Key >
probe probe_raw_get_field ( lua_State * L , Key & & key , int tableindex ) {
return probe_get_field < global , true > ( L , std : : forward < Key > ( key ) , tableindex ) ;
}
template < bool global = false , bool raw = false , typename Key , typename Value >
void set_field ( lua_State * L , Key & & key , Value & & value ) {
field_setter < meta : : unqualified_t < Key > , global , raw > { } . set ( L , std : : forward < Key > ( key ) , std : : forward < Value > ( value ) ) ;
}
template < bool global = false , bool raw = false , typename Key , typename Value >
void set_field ( lua_State * L , Key & & key , Value & & value , int tableindex ) {
field_setter < meta : : unqualified_t < Key > , global , raw > { } . set ( L , std : : forward < Key > ( key ) , std : : forward < Value > ( value ) , tableindex ) ;
}
template < bool global = false , typename Key , typename Value >
void raw_set_field ( lua_State * L , Key & & key , Value & & value ) {
set_field < global , true > ( L , std : : forward < Key > ( key ) , std : : forward < Value > ( value ) ) ;
}
template < bool global = false , typename Key , typename Value >
void raw_set_field ( lua_State * L , Key & & key , Value & & value , int tableindex ) {
set_field < global , true > ( L , std : : forward < Key > ( key ) , std : : forward < Value > ( value ) , tableindex ) ;
}
2017-09-13 14:46:56 +08:00
} // namespace stack
} // namespace sol
2016-03-25 03:45:44 +08:00
# endif // SOL_STACK_CORE_HPP