2017-12-20 17:58:32 +08:00
// sol2
2017-09-13 14:46:56 +08:00
// The MIT License (MIT)
2016-03-25 03:45:44 +08:00
2018-02-20 10:15:26 +08:00
// Copyright (c) 2013-2018 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
2017-10-03 05:32:58 +08:00
inline void * align ( std : : size_t alignment , std : : size_t size , void * & ptr , std : : size_t & space , std : : size_t & required_space ) {
// this handels arbitrary alignments...
// make this into a power-of-2-only?
// actually can't: this is a C++14-compatible framework,
// power of 2 alignment is C++17
std : : uintptr_t initial = reinterpret_cast < std : : uintptr_t > ( ptr ) ;
std : : uintptr_t offby = static_cast < std : : uintptr_t > ( initial % alignment ) ;
std : : uintptr_t padding = ( alignment - offby ) % alignment ;
required_space + = size + padding ;
if ( space < required_space ) {
return nullptr ;
}
ptr = static_cast < void * > ( static_cast < char * > ( ptr ) + padding ) ;
space - = padding ;
return ptr ;
}
inline void * align ( std : : size_t alignment , std : : size_t size , void * & ptr , std : : size_t & space ) {
std : : size_t required_space = 0 ;
return align ( alignment , size , ptr , space , required_space ) ;
}
template < typename . . . Args >
inline std : : size_t aligned_space_for ( void * alignment = nullptr ) {
char * start = static_cast < char * > ( alignment ) ;
auto specific_align = [ & alignment ] ( std : : size_t a , std : : size_t s ) {
2017-11-17 20:20:17 +08:00
std : : size_t space = ( std : : numeric_limits < std : : size_t > : : max ) ( ) ;
2017-10-03 05:32:58 +08:00
alignment = align ( a , s , alignment , space ) ;
alignment = static_cast < void * > ( static_cast < char * > ( alignment ) + s ) ;
} ;
( void ) detail : : swallow { int { } , ( specific_align ( std : : alignment_of < Args > : : value , sizeof ( Args ) ) , int { } ) . . . } ;
return static_cast < char * > ( alignment ) - start ;
}
inline void * align_usertype_pointer ( void * ptr ) {
typedef std : : integral_constant < bool ,
2018-04-18 00:29:03 +08:00
# if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
2017-10-03 05:32:58 +08:00
false
# else
( std : : alignment_of < void * > : : value > 1 )
# endif
>
use_align ;
if ( ! use_align : : value ) {
return ptr ;
}
2017-11-17 20:20:17 +08:00
std : : size_t space = ( std : : numeric_limits < std : : size_t > : : max ) ( ) ;
2017-10-03 05:32:58 +08:00
return align ( std : : alignment_of < void * > : : value , sizeof ( void * ) , ptr , space ) ;
}
inline void * align_usertype_unique_destructor ( void * ptr ) {
typedef std : : integral_constant < bool ,
2018-04-18 00:29:03 +08:00
# if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
2017-10-03 05:32:58 +08:00
false
# else
( std : : alignment_of < unique_destructor > : : value > 1 )
# endif
>
use_align ;
if ( ! use_align : : value ) {
return static_cast < void * > ( static_cast < void * * > ( ptr ) + 1 ) ;
}
ptr = align_usertype_pointer ( ptr ) ;
ptr = static_cast < void * > ( static_cast < char * > ( ptr ) + sizeof ( void * ) ) ;
2017-11-17 20:20:17 +08:00
std : : size_t space = ( std : : numeric_limits < std : : size_t > : : max ) ( ) ;
2017-10-03 05:32:58 +08:00
return align ( std : : alignment_of < unique_destructor > : : value , sizeof ( unique_destructor ) , ptr , space ) ;
}
template < typename T , bool pre_aligned = false >
inline void * align_usertype_unique ( void * ptr ) {
typedef std : : integral_constant < bool ,
2018-04-18 00:29:03 +08:00
# if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
2017-10-03 05:32:58 +08:00
false
# else
( std : : alignment_of < T > : : value > 1 )
# endif
>
use_align ;
if ( ! pre_aligned ) {
ptr = align_usertype_unique_destructor ( ptr ) ;
ptr = static_cast < void * > ( static_cast < char * > ( ptr ) + sizeof ( unique_destructor ) ) ;
}
if ( ! use_align : : value ) {
return ptr ;
}
2017-11-17 20:20:17 +08:00
std : : size_t space = ( std : : numeric_limits < std : : size_t > : : max ) ( ) ;
2017-10-03 05:32:58 +08:00
return align ( std : : alignment_of < T > : : value , sizeof ( T ) , ptr , space ) ;
}
2016-06-17 08:15:56 +08:00
template < typename T >
2017-10-03 05:32:58 +08:00
inline void * align_user ( void * ptr ) {
typedef std : : integral_constant < bool ,
2018-04-18 00:29:03 +08:00
# if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
2017-10-03 05:32:58 +08:00
false
# else
( std : : alignment_of < T > : : value > 1 )
# endif
>
use_align ;
if ( ! use_align : : value ) {
return ptr ;
}
2017-11-17 20:20:17 +08:00
std : : size_t space = ( std : : numeric_limits < std : : size_t > : : max ) ( ) ;
2017-10-03 05:32:58 +08:00
return align ( std : : alignment_of < T > : : value , sizeof ( T ) , ptr , space ) ;
2016-06-17 08:15:56 +08:00
}
2016-08-20 09:08:03 +08:00
2016-08-24 09:42:27 +08:00
template < typename T >
2017-10-03 05:32:58 +08:00
inline T * * usertype_allocate_pointer ( lua_State * L ) {
typedef std : : integral_constant < bool ,
2018-04-18 00:29:03 +08:00
# if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
2017-10-03 05:32:58 +08:00
false
# else
( std : : alignment_of < T * > : : value > 1 )
# endif
>
use_align ;
if ( ! use_align : : value ) {
T * * pointerpointer = static_cast < T * * > ( lua_newuserdata ( L , sizeof ( T * ) ) ) ;
return pointerpointer ;
}
static const std : : size_t initial_size = aligned_space_for < T * > ( nullptr ) ;
static const std : : size_t misaligned_size = aligned_space_for < T * > ( reinterpret_cast < void * > ( 0x1 ) ) ;
std : : size_t allocated_size = initial_size ;
void * unadjusted = lua_newuserdata ( L , initial_size ) ;
void * adjusted = align ( std : : alignment_of < T * > : : value , sizeof ( T * ) , unadjusted , allocated_size ) ;
if ( adjusted = = nullptr ) {
lua_pop ( L , 1 ) ;
// what kind of absolute garbage trash allocator are we dealing with?
// whatever, add some padding in the case of MAXIMAL alignment waste...
allocated_size = misaligned_size ;
unadjusted = lua_newuserdata ( L , allocated_size ) ;
adjusted = align ( std : : alignment_of < T * > : : value , sizeof ( T * ) , unadjusted , allocated_size ) ;
if ( adjusted = = nullptr ) {
// trash allocator can burn in hell
lua_pop ( L , 1 ) ;
//luaL_error(L, "if you are the one that wrote this allocator you should feel bad for doing a worse job than malloc/realloc and should go read some books, yeah?");
luaL_error ( L , " cannot properly align memory for '%s' " , detail : : demangle < T * > ( ) . data ( ) ) ;
}
}
return static_cast < T * * > ( adjusted ) ;
}
template < typename T >
inline T * usertype_allocate ( lua_State * L ) {
typedef std : : integral_constant < bool ,
2018-04-18 00:29:03 +08:00
# if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
2017-10-03 05:32:58 +08:00
false
# else
( std : : alignment_of < T * > : : value > 1 | | std : : alignment_of < T > : : value > 1 )
# endif
>
use_align ;
if ( ! use_align : : value ) {
T * * pointerpointer = static_cast < T * * > ( lua_newuserdata ( L , sizeof ( T * ) + sizeof ( T ) ) ) ;
T * & pointerreference = * pointerpointer ;
T * allocationtarget = reinterpret_cast < T * > ( pointerpointer + 1 ) ;
pointerreference = allocationtarget ;
return allocationtarget ;
}
/* the assumption is that `lua_newuserdata` -- unless someone
passes a specific lua_Alloc that gives us bogus , un - aligned pointers
- - uses malloc , which tends to hand out more or less aligned pointers to memory
( most of the time , anyhow )
but it ' s not guaranteed , so we have to do a post - adjustment check and increase padding
we do this preliminarily with compile - time stuff , to see
if we strike lucky with the allocator and alignment values
otherwise , we have to re - allocate the userdata and
over - allocate some space for additional padding because
compilers are optimized for aligned reads / writes
( and clang will barf UBsan errors on us for not being aligned )
*/
static const std : : size_t initial_size = aligned_space_for < T * , T > ( nullptr ) ;
static const std : : size_t misaligned_size = aligned_space_for < T * , T > ( reinterpret_cast < void * > ( 0x1 ) ) ;
void * pointer_adjusted ;
void * data_adjusted ;
auto attempt_alloc = [ ] ( lua_State * L , std : : size_t allocated_size , void * & pointer_adjusted , void * & data_adjusted ) - > bool {
void * adjusted = lua_newuserdata ( L , allocated_size ) ;
pointer_adjusted = align ( std : : alignment_of < T * > : : value , sizeof ( T * ) , adjusted , allocated_size ) ;
if ( pointer_adjusted = = nullptr ) {
lua_pop ( L , 1 ) ;
return false ;
}
// subtract size of what we're going to allocate there
allocated_size - = sizeof ( T * ) ;
adjusted = static_cast < void * > ( static_cast < char * > ( pointer_adjusted ) + sizeof ( T * ) ) ;
data_adjusted = align ( std : : alignment_of < T > : : value , sizeof ( T ) , adjusted , allocated_size ) ;
if ( data_adjusted = = nullptr ) {
lua_pop ( L , 1 ) ;
return false ;
}
return true ;
} ;
bool result = attempt_alloc ( L , initial_size , pointer_adjusted , data_adjusted ) ;
if ( ! result ) {
// we're likely to get something that fails to perform the proper allocation a second time,
// so we use the suggested_new_size bump to help us out here
pointer_adjusted = nullptr ;
data_adjusted = nullptr ;
result = attempt_alloc ( L , misaligned_size , pointer_adjusted , data_adjusted ) ;
if ( ! result ) {
if ( pointer_adjusted = = nullptr ) {
luaL_error ( L , " aligned allocation of userdata block (pointer section) for '%s' failed " , detail : : demangle < T > ( ) . c_str ( ) ) ;
}
else {
luaL_error ( L , " aligned allocation of userdata block (data section) for '%s' failed " , detail : : demangle < T > ( ) . c_str ( ) ) ;
}
return nullptr ;
}
}
T * * pointerpointer = reinterpret_cast < T * * > ( pointer_adjusted ) ;
T * & pointerreference = * pointerpointer ;
T * allocationtarget = reinterpret_cast < T * > ( data_adjusted ) ;
pointerreference = allocationtarget ;
return allocationtarget ;
}
template < typename T , typename Real >
inline Real * usertype_unique_allocate ( lua_State * L , T * * & pref , unique_destructor * & dx ) {
typedef std : : integral_constant < bool ,
2018-04-18 00:29:03 +08:00
# if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
2017-10-03 05:32:58 +08:00
false
# else
( std : : alignment_of < T * > : : value > 1 | | std : : alignment_of < unique_destructor > : : value > 1 | | std : : alignment_of < Real > : : value > 1 )
# endif
>
use_align ;
if ( ! use_align : : value ) {
pref = static_cast < T * * > ( lua_newuserdata ( L , sizeof ( T * ) + sizeof ( detail : : unique_destructor ) + sizeof ( Real ) ) ) ;
dx = static_cast < detail : : unique_destructor * > ( static_cast < void * > ( pref + 1 ) ) ;
Real * mem = static_cast < Real * > ( static_cast < void * > ( dx + 1 ) ) ;
return mem ;
}
static const std : : size_t initial_size = aligned_space_for < T * , unique_destructor , Real > ( nullptr ) ;
static const std : : size_t misaligned_size = aligned_space_for < T * , unique_destructor , Real > ( reinterpret_cast < void * > ( 0x1 ) ) ;
void * pointer_adjusted ;
void * dx_adjusted ;
void * data_adjusted ;
auto attempt_alloc = [ ] ( lua_State * L , std : : size_t allocated_size , void * & pointer_adjusted , void * & dx_adjusted , void * & data_adjusted ) - > bool {
void * adjusted = lua_newuserdata ( L , allocated_size ) ;
pointer_adjusted = align ( std : : alignment_of < T * > : : value , sizeof ( T * ) , adjusted , allocated_size ) ;
if ( pointer_adjusted = = nullptr ) {
lua_pop ( L , 1 ) ;
return false ;
}
allocated_size - = sizeof ( T * ) ;
adjusted = static_cast < void * > ( static_cast < char * > ( pointer_adjusted ) + sizeof ( T * ) ) ;
dx_adjusted = align ( std : : alignment_of < unique_destructor > : : value , sizeof ( unique_destructor ) , adjusted , allocated_size ) ;
if ( dx_adjusted = = nullptr ) {
lua_pop ( L , 1 ) ;
return false ;
}
allocated_size - = sizeof ( unique_destructor ) ;
adjusted = static_cast < void * > ( static_cast < char * > ( dx_adjusted ) + sizeof ( unique_destructor ) ) ;
data_adjusted = align ( std : : alignment_of < Real > : : value , sizeof ( Real ) , adjusted , allocated_size ) ;
if ( data_adjusted = = nullptr ) {
lua_pop ( L , 1 ) ;
return false ;
}
return true ;
} ;
bool result = attempt_alloc ( L , initial_size , pointer_adjusted , dx_adjusted , data_adjusted ) ;
if ( ! result ) {
// we're likely to get something that fails to perform the proper allocation a second time,
// so we use the suggested_new_size bump to help us out here
pointer_adjusted = nullptr ;
dx_adjusted = nullptr ;
data_adjusted = nullptr ;
result = attempt_alloc ( L , misaligned_size , pointer_adjusted , dx_adjusted , data_adjusted ) ;
if ( ! result ) {
if ( pointer_adjusted = = nullptr ) {
luaL_error ( L , " aligned allocation of userdata block (pointer section) for '%s' failed " , detail : : demangle < T > ( ) . c_str ( ) ) ;
}
else if ( dx_adjusted = = nullptr ) {
luaL_error ( L , " aligned allocation of userdata block (deleter section) for '%s' failed " , detail : : demangle < Real > ( ) . c_str ( ) ) ;
}
else {
luaL_error ( L , " aligned allocation of userdata block (data section) for '%s' failed " , detail : : demangle < Real > ( ) . c_str ( ) ) ;
}
return nullptr ;
}
}
pref = static_cast < T * * > ( pointer_adjusted ) ;
dx = static_cast < detail : : unique_destructor * > ( dx_adjusted ) ;
Real * mem = static_cast < Real * > ( data_adjusted ) ;
return mem ;
}
template < typename T >
inline T * user_allocate ( lua_State * L ) {
typedef std : : integral_constant < bool ,
2018-04-18 00:29:03 +08:00
# if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
2017-10-03 05:32:58 +08:00
false
# else
( std : : alignment_of < T > : : value > 1 )
# endif
>
use_align ;
if ( ! use_align : : value ) {
T * pointer = static_cast < T * > ( lua_newuserdata ( L , sizeof ( T ) ) ) ;
return pointer ;
}
static const std : : size_t initial_size = aligned_space_for < T > ( nullptr ) ;
static const std : : size_t misaligned_size = aligned_space_for < T > ( reinterpret_cast < void * > ( 0x1 ) ) ;
std : : size_t allocated_size = initial_size ;
void * unadjusted = lua_newuserdata ( L , allocated_size ) ;
void * adjusted = align ( std : : alignment_of < T > : : value , sizeof ( T ) , unadjusted , allocated_size ) ;
if ( adjusted = = nullptr ) {
lua_pop ( L , 1 ) ;
// try again, add extra space for alignment padding
allocated_size = misaligned_size ;
unadjusted = lua_newuserdata ( L , allocated_size ) ;
adjusted = align ( std : : alignment_of < T > : : value , sizeof ( T ) , unadjusted , allocated_size ) ;
if ( adjusted = = nullptr ) {
lua_pop ( L , 1 ) ;
luaL_error ( L , " cannot properly align memory for '%s' " , detail : : demangle < T > ( ) . data ( ) ) ;
}
}
return static_cast < T * > ( adjusted ) ;
2016-08-24 09:42:27 +08:00
}
template < typename T >
2017-08-22 03:25:43 +08:00
inline int usertype_alloc_destruct ( lua_State * L ) {
2017-10-03 05:32:58 +08:00
void * memory = lua_touserdata ( L , 1 ) ;
memory = align_usertype_pointer ( memory ) ;
T * * pdata = static_cast < T * * > ( memory ) ;
2016-08-24 09:42:27 +08:00
T * data = * pdata ;
std : : allocator < T > alloc { } ;
2017-12-07 21:24:50 +08:00
std : : allocator_traits < std : : allocator < T > > : : destroy ( alloc , data ) ;
2016-08-24 09:42:27 +08:00
return 0 ;
}
2017-08-22 03:25:43 +08:00
template < typename T >
2017-10-03 05:32:58 +08:00
inline int unique_destruct ( lua_State * L ) {
void * memory = lua_touserdata ( L , 1 ) ;
memory = align_usertype_unique_destructor ( memory ) ;
unique_destructor & dx = * static_cast < unique_destructor * > ( memory ) ;
memory = static_cast < void * > ( static_cast < char * > ( memory ) + sizeof ( unique_destructor ) ) ;
( dx ) ( memory ) ;
return 0 ;
}
template < typename T >
inline int user_alloc_destruct ( lua_State * L ) {
void * memory = lua_touserdata ( L , 1 ) ;
memory = align_user < T > ( memory ) ;
T * data = static_cast < T * > ( memory ) ;
std : : allocator < T > alloc ;
2017-12-07 21:24:50 +08:00
std : : allocator_traits < std : : allocator < T > > : : destroy ( alloc , data ) ;
2017-10-03 05:32:58 +08:00
return 0 ;
2017-08-22 03:25:43 +08:00
}
template < typename T , typename Real >
inline void usertype_unique_alloc_destroy ( void * memory ) {
2017-10-03 05:32:58 +08:00
memory = align_usertype_unique < Real , true > ( memory ) ;
Real * target = static_cast < Real * > ( memory ) ;
2017-08-22 03:25:43 +08:00
std : : allocator < Real > alloc ;
2017-12-07 21:24:50 +08:00
std : : allocator_traits < std : : allocator < Real > > : : destroy ( alloc , target ) ;
2017-08-22 03:25:43 +08:00
}
2017-10-03 05:32:58 +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 : please bind a usertype and specify a custom destructor to define the behavior properly " , detail::demangle<T>().data()) ;
}
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-24 08:26:03 +08:00
template < typename T >
struct extensible { } ;
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 >
2017-09-24 08:26:03 +08:00
struct userdata_getter ;
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 >
2017-09-24 08:26:03 +08:00
struct userdata_checker ;
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
2017-09-25 04:04:10 +08:00
template < typename T >
struct strip_extensible { typedef T type ; } ;
template < typename T >
struct strip_extensible < extensible < T > > { typedef T type ; } ;
template < typename T >
using strip_extensible_t = typename strip_extensible < T > : : type ;
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-12-11 04:56:49 +08:00
template < typename T , typename Handler >
bool check_usertype ( std : : false_type , lua_State * L , int index , type indextype , Handler & & handler , record & tracking ) {
typedef meta : : unqualified_t < T > Tu ;
typedef detail : : as_value_tag < Tu > detail_t ;
return checker < detail_t , type : : userdata > { } . check ( types < meta : : unqualified_t < T > > ( ) , L , index , indextype , std : : forward < Handler > ( handler ) , tracking ) ;
}
template < typename T , typename Handler >
bool check_usertype ( std : : true_type , lua_State * L , int index , type indextype , Handler & & handler , record & tracking ) {
typedef meta : : unqualified_t < std : : remove_pointer_t < meta : : unqualified_t < T > > > Tu ;
typedef detail : : as_pointer_tag < Tu > detail_t ;
return checker < detail_t , type : : userdata > { } . check ( L , index , indextype , std : : forward < Handler > ( handler ) , tracking ) ;
}
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-11-22 03:33:27 +08:00
inline bool is_main_thread ( lua_State * L ) {
int ismainthread = lua_pushthread ( L ) ;
lua_pop ( L , 1 ) ;
return ismainthread = = 1 ;
}
inline void coroutine_create_guard ( lua_State * L ) {
if ( is_main_thread ( L ) ) {
return ;
}
int stacksize = lua_gettop ( L ) ;
if ( stacksize < 1 ) {
return ;
}
if ( type_of ( L , 1 ) ! = type : : function ) {
return ;
}
// well now we're screwed...
// we can clean the stack and pray it doesn't destroy anything?
lua_pop ( L , stacksize ) ;
}
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-12-11 04:56:49 +08:00
template < typename T , typename Handler >
bool check_usertype ( lua_State * L , int index , Handler & & handler , record & tracking ) {
type indextype = type_of ( L , index ) ;
return stack_detail : : check_usertype < T > ( std : : is_pointer < T > ( ) , L , index , indextype , std : : forward < Handler > ( handler ) , tracking ) ;
}
template < typename T , typename Handler >
bool check_usertype ( lua_State * L , int index , Handler & & handler ) {
record tracking { } ;
return check_usertype < T > ( L , index , std : : forward < Handler > ( handler ) , tracking ) ;
}
template < typename T >
bool check_usertype ( lua_State * L , int index = - lua_size < meta : : unqualified_t < T > > : : value ) {
auto handler = no_panic ;
return check_usertype < 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 {
2018-04-18 00:29:03 +08:00
# if defined(SOL_SAFE_GETTER) && SOL_SAFE_GETTER
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
}
2017-12-11 04:56:49 +08:00
template < typename T >
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-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
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-12-11 04:56:49 +08:00
template < typename T >
inline decltype ( auto ) get_usertype ( lua_State * L , int index , record & tracking ) {
2018-04-18 00:29:03 +08:00
# if defined(SOL_SAFE_GETTER) && SOL_SAFE_GETTER
2017-12-11 04:56:49 +08:00
return stack_detail : : tagged_get ( types < std : : conditional_t < std : : is_pointer < T > : : value , detail : : as_pointer_tag < std : : remove_pointer_t < T > > , detail : : as_value_tag < T > > > ( ) , L , index , tracking ) ;
# else
return stack_detail : : unchecked_get < std : : conditional_t < std : : is_pointer < T > : : value , detail : : as_pointer_tag < std : : remove_pointer_t < T > > , detail : : as_value_tag < T > > > ( L , index , tracking ) ;
# endif
}
template < typename T >
inline decltype ( auto ) get_usertype ( lua_State * L , int index = - lua_size < meta : : unqualified_t < T > > : : value ) {
record tracking { } ;
return get_usertype < T > ( L , index , tracking ) ;
}
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 ) ;
}
2018-03-30 16:51:29 +08:00
template < typename T , typename F >
2018-04-02 09:38:21 +08:00
inline void modify_unique_usertype_as ( const stack_reference & obj , F & & f ) {
2018-03-30 16:51:29 +08:00
typedef unique_usertype_traits < T > u_traits ;
void * raw = lua_touserdata ( obj . lua_state ( ) , obj . stack_index ( ) ) ;
void * ptr_memory = detail : : align_usertype_pointer ( raw ) ;
void * uu_memory = detail : : align_usertype_unique < T > ( raw ) ;
T & uu = * static_cast < T * > ( uu_memory ) ;
f ( uu ) ;
* static_cast < void * * > ( ptr_memory ) = static_cast < void * > ( u_traits : : get ( uu ) ) ;
}
template < typename F >
2018-04-02 09:38:21 +08:00
inline void modify_unique_usertype ( const stack_reference & obj , F & & f ) {
2018-03-30 16:51:29 +08:00
typedef meta : : bind_traits < meta : : unqualified_t < F > > bt ;
typedef typename bt : : template arg_at < 0 > T ;
modify_unique_usertype_as < meta : : unqualified_t < T > > ( obj , std : : forward < F > ( f ) ) ;
}
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