2014-04-26 07:41:03 +08:00
// The MIT License (MIT)
// Copyright (c) 2013 Danny Y., Rapptz
// 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.
2014-09-19 22:45:13 +08:00
# ifndef SOL_USERTYPE_HPP
2014-09-19 20:22:21 +08:00
# define SOL_USERTYPE_HPP
2014-04-26 07:41:03 +08:00
2014-04-26 08:53:36 +08:00
# include "state.hpp"
2014-04-26 10:05:58 +08:00
# include "function_types.hpp"
2014-09-19 20:22:21 +08:00
# include "usertype_traits.hpp"
2014-06-27 16:25:57 +08:00
# include "default_construct.hpp"
2014-04-26 07:41:03 +08:00
# include <vector>
2014-06-08 04:33:39 +08:00
# include <array>
# include <algorithm>
2014-04-26 07:41:03 +08:00
namespace sol {
2014-04-26 08:53:36 +08:00
namespace detail {
template < typename T , typename . . . Args >
inline std : : unique_ptr < T > make_unique ( Args & & . . . args ) {
return std : : unique_ptr < T > ( new T ( std : : forward < Args > ( args ) . . . ) ) ;
}
} // detail
2014-04-26 07:41:03 +08:00
2014-08-05 15:15:34 +08:00
const std : : array < std : : string , 2 > meta_variable_names = { {
2014-08-05 15:08:41 +08:00
" __index " ,
" __newindex "
2014-08-05 15:15:34 +08:00
} } ;
2014-08-05 15:08:41 +08:00
2014-08-05 15:15:34 +08:00
const std : : array < std : : string , 19 > meta_function_names = { {
2014-08-05 15:08:41 +08:00
" __index " ,
" __newindex " ,
" __mode " ,
" __call " ,
" __metatable " ,
" __tostring " ,
" __len " ,
" __unm " ,
" __add " ,
" __sub " ,
" __mul " ,
" __div " ,
" __mod " ,
" __pow " ,
" __concat " ,
" __eq " ,
" __lt " ,
" __le " ,
" __gc " ,
2014-08-05 15:15:34 +08:00
} } ;
2014-08-05 15:08:41 +08:00
enum class meta_function {
index ,
new_index ,
mode ,
call ,
metatable ,
to_string ,
length ,
unary_minus ,
addition ,
subtraction ,
multiplication ,
division ,
modulus ,
power_of ,
involution = power_of ,
concatenation ,
equal_to ,
less_than ,
less_than_or_equal_to ,
2014-08-09 19:54:58 +08:00
} ;
2014-08-05 15:08:41 +08:00
2014-04-27 06:23:56 +08:00
template < typename T >
2014-09-19 20:22:21 +08:00
class usertype {
2014-04-26 07:41:03 +08:00
private :
2014-07-28 03:56:24 +08:00
typedef std : : unordered_map < std : : string , std : : pair < std : : unique_ptr < base_function > , bool > > function_map_t ;
function_map_t indexmetafunctions , newindexmetafunctions ;
2014-04-26 07:41:03 +08:00
std : : vector < std : : string > functionnames ;
2014-07-28 03:56:24 +08:00
std : : vector < std : : unique_ptr < base_function > > metafunctions ;
2014-06-08 04:33:39 +08:00
std : : vector < luaL_Reg > metafunctiontable ;
std : : vector < luaL_Reg > ptrmetafunctiontable ;
2014-06-28 12:27:48 +08:00
lua_CFunction cleanup ;
2014-04-27 12:53:57 +08:00
2014-04-27 06:23:56 +08:00
template < typename . . . TTypes >
2014-04-26 07:41:03 +08:00
struct constructor {
2014-04-27 06:23:56 +08:00
template < typename . . . Args >
2014-04-27 12:53:57 +08:00
static void do_constructor ( lua_State * L , T * obj , call_syntax syntax , int , types < Args . . . > ) {
2014-06-27 16:34:16 +08:00
default_construct fx { } ;
2014-06-27 16:25:57 +08:00
stack : : get_call ( L , 1 + static_cast < int > ( syntax ) , fx , types < Args . . . > ( ) , obj ) ;
2014-06-27 16:34:16 +08:00
}
2014-04-26 07:41:03 +08:00
2014-04-27 12:53:57 +08:00
static void match_constructor ( lua_State * , T * , call_syntax , int ) {
2014-05-22 10:24:15 +08:00
throw error ( " No matching constructor for the arguments provided " ) ;
2014-04-26 12:19:36 +08:00
}
2014-04-27 12:53:57 +08:00
2014-04-27 06:23:56 +08:00
template < typename . . . CArgs , typename . . . Args >
static void match_constructor ( lua_State * L , T * obj , call_syntax syntax , int argcount , types < CArgs . . . > t , Args & & . . . args ) {
2014-08-11 08:49:34 +08:00
if ( argcount = = sizeof . . . ( CArgs ) ) {
2014-04-27 06:23:56 +08:00
do_constructor ( L , obj , syntax , argcount , t ) ;
2014-04-26 12:19:36 +08:00
return ;
}
2014-04-27 06:23:56 +08:00
match_constructor ( L , obj , syntax , argcount , std : : forward < Args > ( args ) . . . ) ;
2014-04-26 12:19:36 +08:00
}
2014-04-26 07:41:03 +08:00
2014-04-26 12:19:36 +08:00
static int construct ( lua_State * L ) {
2014-09-19 20:22:21 +08:00
auto & & meta = usertype_traits < T > : : metatable ;
2014-04-27 06:23:56 +08:00
call_syntax syntax = stack : : get_call_syntax ( L , meta ) ;
2014-04-26 12:19:36 +08:00
int argcount = lua_gettop ( L ) ;
2014-04-27 12:53:57 +08:00
2014-04-27 06:23:56 +08:00
void * udata = lua_newuserdata ( L , sizeof ( T ) ) ;
T * obj = static_cast < T * > ( udata ) ;
2014-06-27 16:25:57 +08:00
match_constructor ( L , obj , syntax , argcount - static_cast < int > ( syntax ) , typename identity < TTypes > : : type ( ) . . . ) ;
2014-04-27 12:53:57 +08:00
2014-08-11 08:49:34 +08:00
if ( luaL_newmetatable ( L , std : : addressof ( meta [ 0 ] ) ) = = 1 ) {
2014-06-09 17:30:00 +08:00
lua_pop ( L , 1 ) ;
2014-09-19 20:22:21 +08:00
std : : string err = " Unable to get usertype metatable for " ;
2014-06-09 17:30:00 +08:00
err + = meta ;
throw error ( err ) ;
}
lua_setmetatable ( L , - 2 ) ;
2014-04-27 12:53:57 +08:00
2014-04-27 06:23:56 +08:00
return 1 ;
2014-04-26 07:41:03 +08:00
}
} ;
struct destructor {
static int destruct ( lua_State * L ) {
2014-04-27 06:23:56 +08:00
userdata_t udata = stack : : get < userdata_t > ( L , 1 ) ;
2014-04-26 12:19:36 +08:00
T * obj = static_cast < T * > ( udata . value ) ;
2014-04-26 07:41:03 +08:00
std : : allocator < T > alloc { } ;
alloc . destroy ( obj ) ;
return 0 ;
}
} ;
2014-07-28 03:56:24 +08:00
template < std : : size_t N >
2014-08-11 08:49:34 +08:00
void build_cleanup ( ) {
2014-09-19 20:22:21 +08:00
cleanup = & base_function : : usertype < N > : : gc ;
2014-06-29 14:16:48 +08:00
}
2014-07-28 03:56:24 +08:00
template < std : : size_t N >
void build_function_tables ( function_map_t * & index , function_map_t * & newindex ) {
int extracount = 0 ;
2014-08-11 08:49:34 +08:00
if ( ! indexmetafunctions . empty ( ) ) {
if ( index = = nullptr ) {
2014-09-19 20:22:21 +08:00
auto idxptr = detail : : make_unique < usertype_indexing_function < void ( T : : * ) ( ) , T > > ( " __index " , nullptr ) ;
2014-07-28 03:56:24 +08:00
index = & ( idxptr - > functions ) ;
functionnames . emplace_back ( " __index " ) ;
metafunctions . emplace_back ( std : : move ( idxptr ) ) ;
std : : string & name = functionnames . back ( ) ;
2014-09-19 20:22:21 +08:00
metafunctiontable . push_back ( { name . c_str ( ) , & base_function : : usertype < N > : : call } ) ;
ptrmetafunctiontable . push_back ( { name . c_str ( ) , & base_function : : usertype < N > : : ref_call } ) ;
2014-07-28 03:56:24 +08:00
+ + extracount ;
}
auto & idx = * index ;
2014-08-11 08:49:34 +08:00
for ( auto & & namedfunc : indexmetafunctions ) {
2014-07-28 03:56:24 +08:00
idx . emplace ( std : : move ( namedfunc . first ) , std : : move ( namedfunc . second ) ) ;
}
2014-06-29 14:16:48 +08:00
}
2014-08-11 08:49:34 +08:00
if ( ! newindexmetafunctions . empty ( ) ) {
if ( newindex = = nullptr ) {
2014-09-19 20:22:21 +08:00
auto idxptr = detail : : make_unique < usertype_indexing_function < void ( T : : * ) ( ) , T > > ( " __newindex " , nullptr ) ;
2014-07-28 03:56:24 +08:00
newindex = & ( idxptr - > functions ) ;
functionnames . emplace_back ( " __newindex " ) ;
metafunctions . emplace_back ( std : : move ( idxptr ) ) ;
std : : string & name = functionnames . back ( ) ;
2014-08-11 08:49:34 +08:00
if ( extracount > 0 ) {
2014-09-19 20:22:21 +08:00
metafunctiontable . push_back ( { name . c_str ( ) , & base_function : : usertype < N + 1 > : : call } ) ;
ptrmetafunctiontable . push_back ( { name . c_str ( ) , & base_function : : usertype < N + 1 > : : ref_call } ) ;
2014-07-28 03:56:24 +08:00
}
else {
2014-09-19 20:22:21 +08:00
metafunctiontable . push_back ( { name . c_str ( ) , & base_function : : usertype < N > : : call } ) ;
ptrmetafunctiontable . push_back ( { name . c_str ( ) , & base_function : : usertype < N > : : ref_call } ) ;
2014-07-28 03:56:24 +08:00
}
+ + extracount ;
}
auto & idx = * newindex ;
2014-08-11 08:49:34 +08:00
for ( auto & & namedfunc : newindexmetafunctions ) {
2014-07-28 03:56:24 +08:00
idx . emplace ( std : : move ( namedfunc . first ) , std : : move ( namedfunc . second ) ) ;
}
}
2014-08-11 08:49:34 +08:00
switch ( extracount ) {
2014-07-28 03:56:24 +08:00
case 2 :
build_cleanup < N + 2 > ( ) ;
break ;
case 1 :
build_cleanup < N + 1 > ( ) ;
break ;
case 0 :
default :
build_cleanup < N + 0 > ( ) ;
break ;
2014-06-29 14:16:48 +08:00
}
}
2014-08-09 19:54:58 +08:00
template < std : : size_t N , typename Base , typename Ret >
bool build_function ( std : : true_type , function_map_t * & , function_map_t * & , std : : string funcname , Ret Base : : * func ) {
static_assert ( std : : is_base_of < Base , T > : : value , " Any registered function must be part of the class " ) ;
2014-07-28 03:56:24 +08:00
typedef typename std : : decay < decltype ( func ) > : : type function_type ;
2014-09-19 20:22:21 +08:00
indexmetafunctions . emplace ( funcname , std : : make_pair ( detail : : make_unique < usertype_variable_function < function_type , T > > ( func ) , false ) ) ;
newindexmetafunctions . emplace ( funcname , std : : make_pair ( detail : : make_unique < usertype_variable_function < function_type , T > > ( func ) , false ) ) ;
2014-07-28 03:56:24 +08:00
return false ;
}
2014-04-26 07:41:03 +08:00
2014-08-09 19:54:58 +08:00
template < typename Arg , typename . . . Args , typename Ret >
std : : unique_ptr < base_function > make_function ( const std : : string & , Ret ( * func ) ( Arg , Args . . . ) ) {
typedef Unqualified < Arg > Argu ;
static_assert ( std : : is_base_of < Argu , T > : : value , " Any non-member-function must have a first argument which is covariant with the desired userdata type. " ) ;
2014-04-27 15:25:47 +08:00
typedef typename std : : decay < decltype ( func ) > : : type function_type ;
2014-09-19 20:22:21 +08:00
return detail : : make_unique < usertype_function < function_type , T > > ( func ) ;
2014-08-09 19:54:58 +08:00
}
template < typename Base , typename Ret >
std : : unique_ptr < base_function > make_variable_function ( std : : true_type , const std : : string & , Ret Base : : * func ) {
static_assert ( std : : is_base_of < Base , T > : : value , " Any registered function must be part of the class " ) ;
typedef typename std : : decay < decltype ( func ) > : : type function_type ;
2014-09-19 20:22:21 +08:00
return detail : : make_unique < usertype_variable_function < function_type , T > > ( func ) ;
2014-08-09 19:54:58 +08:00
}
template < typename Base , typename Ret >
std : : unique_ptr < base_function > make_variable_function ( std : : false_type , const std : : string & , Ret Base : : * func ) {
static_assert ( std : : is_base_of < Base , T > : : value , " Any registered function must be part of the class " ) ;
typedef typename std : : decay < decltype ( func ) > : : type function_type ;
2014-09-19 20:22:21 +08:00
return detail : : make_unique < usertype_function < function_type , T > > ( func ) ;
2014-08-09 19:54:58 +08:00
}
template < typename Base , typename Ret >
std : : unique_ptr < base_function > make_function ( const std : : string & name , Ret Base : : * func ) {
typedef typename std : : decay < decltype ( func ) > : : type function_type ;
return make_variable_function ( std : : is_member_object_pointer < function_type > ( ) , name , func ) ;
}
template < typename Fx >
std : : unique_ptr < base_function > make_function ( const std : : string & , Fx & & func ) {
typedef Unqualified < Fx > Fxu ;
typedef typename std : : tuple_element < 0 , typename function_traits < Fxu > : : arg_tuple_type > : : type TArg ;
typedef Unqualified < TArg > TArgu ;
static_assert ( std : : is_base_of < TArgu , T > : : value , " Any non-member-function must have a first argument which is covariant with the desired userdata type. " ) ;
typedef typename std : : decay < decltype ( func ) > : : type function_type ;
2014-09-19 20:22:21 +08:00
return detail : : make_unique < usertype_function < function_type , T > > ( func ) ;
2014-08-09 19:54:58 +08:00
}
template < std : : size_t N , typename Fx >
bool build_function ( std : : false_type , function_map_t * & index , function_map_t * & newindex , std : : string funcname , Fx & & func ) {
typedef typename std : : decay < Fx > : : type function_type ;
2014-08-05 15:08:41 +08:00
auto metamethod = std : : find ( meta_function_names . begin ( ) , meta_function_names . end ( ) , funcname ) ;
2014-08-11 08:49:34 +08:00
if ( metamethod ! = meta_function_names . end ( ) ) {
2014-07-28 03:56:24 +08:00
functionnames . push_back ( std : : move ( funcname ) ) ;
std : : string & name = functionnames . back ( ) ;
2014-08-05 15:08:41 +08:00
auto indexmetamethod = std : : find ( meta_variable_names . begin ( ) , meta_variable_names . end ( ) , name ) ;
2014-07-28 03:56:24 +08:00
std : : unique_ptr < base_function > ptr ( nullptr ) ;
2014-08-11 08:49:34 +08:00
if ( indexmetamethod ! = meta_variable_names . end ( ) ) {
2014-09-19 20:22:21 +08:00
auto idxptr = detail : : make_unique < usertype_indexing_function < function_type , T > > ( name , func ) ;
2014-08-11 08:49:34 +08:00
switch ( std : : distance ( indexmetamethod , meta_variable_names . end ( ) ) ) {
2014-07-28 03:56:24 +08:00
case 0 :
index = & ( idxptr - > functions ) ;
break ;
case 1 :
newindex = & ( idxptr - > functions ) ;
break ;
default :
break ;
}
ptr = std : : move ( idxptr ) ;
}
else {
2014-08-09 19:54:58 +08:00
ptr = make_function ( funcname , std : : forward < Fx > ( func ) ) ;
2014-07-28 03:56:24 +08:00
}
metafunctions . emplace_back ( std : : move ( ptr ) ) ;
2014-09-19 20:22:21 +08:00
metafunctiontable . push_back ( { name . c_str ( ) , & base_function : : usertype < N > : : call } ) ;
ptrmetafunctiontable . push_back ( { name . c_str ( ) , & base_function : : usertype < N > : : ref_call } ) ;
2014-07-28 03:56:24 +08:00
return true ;
}
2014-08-09 19:54:58 +08:00
indexmetafunctions . emplace ( funcname , std : : make_pair ( make_function ( funcname , std : : forward < Fx > ( func ) ) , true ) ) ;
2014-07-28 03:56:24 +08:00
return false ;
}
2014-08-09 19:54:58 +08:00
template < std : : size_t N , typename Fx , typename . . . Args >
void build_function_tables ( function_map_t * & index , function_map_t * & newindex , std : : string funcname , Fx & & func , Args & & . . . args ) {
typedef typename std : : is_member_object_pointer < Unqualified < Fx > > : : type is_variable ;
2014-08-11 08:49:34 +08:00
static const std : : size_t V = static_cast < std : : size_t > ( ! is_variable : : value ) ;
if ( build_function < N > ( is_variable ( ) , index , newindex , std : : move ( funcname ) , std : : forward < Fx > ( func ) ) ) {
2014-07-28 03:56:24 +08:00
build_function_tables < N + V > ( index , newindex , std : : forward < Args > ( args ) . . . ) ;
2014-06-08 04:33:39 +08:00
}
else {
2014-07-28 03:56:24 +08:00
build_function_tables < N > ( index , newindex , std : : forward < Args > ( args ) . . . ) ;
2014-06-08 04:33:39 +08:00
}
2014-04-26 07:41:03 +08:00
}
2014-08-09 19:54:58 +08:00
template < std : : size_t N , typename Base , typename Ret , typename . . . Args >
void build_function_tables ( function_map_t * & index , function_map_t * & newindex , meta_function metafunc , Ret Base : : * func , Args & & . . . args ) {
2014-08-05 15:08:41 +08:00
std : : size_t idx = static_cast < std : : size_t > ( metafunc ) ;
const std : : string & funcname = meta_function_names [ idx ] ;
build_function_tables < N > ( index , newindex , funcname , std : : move ( func ) , std : : forward < Args > ( args ) . . . ) ;
2014-08-09 19:54:58 +08:00
}
2014-08-05 15:08:41 +08:00
2014-04-26 07:41:03 +08:00
public :
2014-04-27 06:23:56 +08:00
template < typename . . . Args >
2014-09-19 20:22:21 +08:00
usertype ( Args & & . . . args ) : usertype ( default_constructor , std : : forward < Args > ( args ) . . . ) { }
2014-04-26 07:41:03 +08:00
2014-04-27 06:23:56 +08:00
template < typename . . . Args , typename . . . CArgs >
2014-09-19 20:22:21 +08:00
usertype ( constructors < CArgs . . . > , Args & & . . . args ) {
2014-04-27 06:23:56 +08:00
functionnames . reserve ( sizeof . . . ( args ) + 2 ) ;
2014-06-28 12:27:48 +08:00
metafunctiontable . reserve ( sizeof . . . ( args ) ) ;
ptrmetafunctiontable . reserve ( sizeof . . . ( args ) ) ;
2014-07-28 03:56:24 +08:00
function_map_t * index = nullptr ;
function_map_t * newindex = nullptr ;
build_function_tables < 0 > ( index , newindex , std : : forward < Args > ( args ) . . . ) ;
indexmetafunctions . clear ( ) ;
newindexmetafunctions . clear ( ) ;
2014-04-26 07:41:03 +08:00
functionnames . push_back ( " new " ) ;
2014-07-28 03:56:24 +08:00
metafunctiontable . push_back ( { functionnames . back ( ) . c_str ( ) , & constructor < CArgs . . . > : : construct } ) ;
2014-04-27 06:23:56 +08:00
functionnames . push_back ( " __gc " ) ;
2014-06-28 12:27:48 +08:00
metafunctiontable . push_back ( { functionnames . back ( ) . c_str ( ) , & destructor : : destruct } ) ;
2014-06-07 10:54:45 +08:00
// ptr_functions does not participate in garbage collection/new,
// as all pointered types are considered
// to be references. This makes returns of
// `std::vector<int>&` and `std::vector<int>*` work
2014-04-27 12:53:57 +08:00
2014-08-05 15:31:59 +08:00
metafunctiontable . push_back ( { nullptr , nullptr } ) ;
ptrmetafunctiontable . push_back ( { nullptr , nullptr } ) ;
2014-04-26 07:41:03 +08:00
}
2014-08-11 08:49:34 +08:00
void push ( lua_State * L ) {
2014-06-29 14:16:48 +08:00
// push pointer tables first,
2014-07-28 03:56:24 +08:00
// but leave the regular T table on last
// so it can be linked to a type for usage with `.new(...)` or `:new(...)`
2014-09-19 20:22:21 +08:00
push_metatable ( L , usertype_traits < T * > : : metatable ,
2014-07-28 03:56:24 +08:00
metafunctions , ptrmetafunctiontable ) ;
lua_pop ( L , 1 ) ;
2014-09-19 20:22:21 +08:00
push_metatable ( L , usertype_traits < T > : : metatable ,
2014-07-28 03:56:24 +08:00
metafunctions , metafunctiontable ) ;
set_global_deleter ( L ) ;
}
2014-09-19 22:45:13 +08:00
private :
2014-08-09 19:54:58 +08:00
template < typename Meta , typename MetaFuncs , typename MetaFuncTable >
2014-07-28 03:56:24 +08:00
static void push_metatable ( lua_State * L , Meta & & metakey , MetaFuncs & & metafuncs , MetaFuncTable & & metafunctable ) {
luaL_newmetatable ( L , std : : addressof ( metakey [ 0 ] ) ) ;
2014-08-11 08:49:34 +08:00
if ( metafunctable . size ( ) > 1 ) {
2014-07-28 03:56:24 +08:00
// regular functions accessed through __index semantics
int up = push_upvalues ( L , metafuncs ) ;
luaL_setfuncs ( L , metafunctable . data ( ) , up ) ;
}
}
2014-08-11 08:49:34 +08:00
void set_global_deleter ( lua_State * L ) {
2014-06-29 14:16:48 +08:00
// Automatic deleter table -- stays alive until lua VM dies
// even if the user calls collectgarbage()
lua_createtable ( L , 0 , 0 ) ;
lua_createtable ( L , 0 , 1 ) ;
2014-07-28 03:56:24 +08:00
int up = push_upvalues < true > ( L , metafunctions ) ;
2014-06-29 14:16:48 +08:00
lua_pushcclosure ( L , cleanup , up ) ;
lua_setfield ( L , - 2 , " __gc " ) ;
lua_setmetatable ( L , - 2 ) ;
// gctable name by default has ♻ part of it
2014-09-19 20:22:21 +08:00
lua_setglobal ( L , std : : addressof ( usertype_traits < T > : : gctable [ 0 ] ) ) ;
2014-06-29 14:16:48 +08:00
}
2014-07-28 03:56:24 +08:00
2014-08-09 19:54:58 +08:00
template < bool release = false , typename TCont >
2014-08-11 08:49:34 +08:00
static int push_upvalues ( lua_State * L , TCont & & cont ) {
2014-07-28 03:56:24 +08:00
int n = 0 ;
2014-08-11 08:49:34 +08:00
for ( auto & c : cont ) {
if ( release ) {
2014-07-28 03:56:24 +08:00
stack : : push < upvalue_t > ( L , c . release ( ) ) ;
2014-08-11 08:49:34 +08:00
}
else {
2014-07-28 03:56:24 +08:00
stack : : push < upvalue_t > ( L , c . get ( ) ) ;
2014-08-11 08:49:34 +08:00
}
2014-07-28 03:56:24 +08:00
+ + n ;
}
return n ;
}
} ;
2014-06-07 10:54:45 +08:00
namespace stack {
2014-08-09 19:54:58 +08:00
template < typename T >
2014-09-19 20:22:21 +08:00
struct pusher < usertype < T > > {
static void push ( lua_State * L , usertype < T > & user ) {
2014-06-29 14:16:48 +08:00
user . push ( L ) ;
2014-06-07 10:54:45 +08:00
}
2014-04-26 07:41:03 +08:00
} ;
2014-06-07 10:54:45 +08:00
} // stack
2014-04-27 13:29:37 +08:00
} // sol
2014-04-26 07:41:03 +08:00
2014-09-19 20:22:21 +08:00
# endif // SOL_USERTYPE_HPP