2014-02-03 03:49:30 +00:00
/*
* A Lua userdata object for 64 - bit signed / unsigned integers .
* $ Id : wslua_int64 . c , v 1.0 2013 / 03 / 31 02 : 08 : 32 hadrielk Exp $
2014-02-05 20:14:04 +00:00
*
* I , Hadriel Kaplan , the author of wslua_int6464 . c , wish to put it in
* the Public Domain . That is not universally accepted , however ,
* so you may license it under the FreeBSD License instead , which is an open
* source license approved for GPL use as well as commercial etc .
* It ' s even less restrictive than the MIT license , because it requires
* no attribution anywhere - I don ' t * want * attribution .
Copyright ( C ) 2013 Hadriel Kaplan < hadrielk @ yahoo . com >
All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are met :
1. Redistributions of source code must retain the above copyright notice , this
list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright notice ,
this list of conditions and the following disclaimer in the documentation
and / or other materials provided with the distribution .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND
ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies ,
either expressed or implied , of the FreeBSD Project .
*/
2014-02-03 03:49:30 +00:00
# include "config.h"
# include "wslua.h"
/* WSLUA_MODULE Int64 Handling 64-bit Integers */
# define LUATYPE64_STRING_SIZE 21 /* string to hold 18446744073709551615 */
WSLUA_CLASS_DEFINE_BASE ( Int64 , NOP , NOP , 0 ) ;
/*
Int64 represents a 64 bit signed integer .
Lua uses one single number representation which can be chosen at compile time and since
it is often set to IEEE 754 double precision floating point , we cannot store a 64 bit integer
with full precision .
For details , see : http : //lua-users.org/wiki/FloatingPoint
*/
/* these declarations are here because some funcs in Int64 need to know about UInt64 */
UInt64 toUInt64 ( lua_State * L , int i ) ;
gboolean isUInt64 ( lua_State * L , int i ) ;
UInt64 checkUInt64 ( lua_State * L , int i ) ;
/* A checkInt64 but that also auto-converts numbers, strings, and UINT64 to a gint64 */
static gint64 getInt64 ( lua_State * L , int i )
{
gchar * end = NULL ;
( void ) end ;
switch ( lua_type ( L , i ) )
{
case LUA_TNUMBER :
return ( gint64 ) luaL_checknumber ( L , i ) ;
case LUA_TSTRING :
return g_ascii_strtoll ( luaL_checkstring ( L , i ) , & end , 10 ) ;
case LUA_TUSERDATA :
if ( isUInt64 ( L , i ) ) {
return ( Int64 ) toUInt64 ( L , i ) ;
break ;
}
/* fall through */
default :
return checkInt64 ( L , i ) ;
}
}
/* Encodes Int64 userdata into Lua string struct with given endianess */
void Int64_pack ( lua_State * L , luaL_Buffer * b , gint idx , gboolean asLittleEndian ) {
gint64 value = checkInt64 ( L , idx ) ;
gint8 buff [ sizeof ( gint64 ) ] ;
if ( asLittleEndian ) {
guint i ;
for ( i = 0 ; i < sizeof ( gint64 ) ; i + + ) {
buff [ i ] = ( value & 0xff ) ;
value > > = 8 ;
}
}
else {
gint i ;
for ( i = sizeof ( gint64 ) - 1 ; i > = 0 ; i - - ) {
buff [ i ] = ( value & 0xff ) ;
value > > = 8 ;
}
}
luaL_addlstring ( b , ( char * ) buff , sizeof ( gint64 ) ) ;
}
WSLUA_METHOD Int64_encode ( lua_State * L ) {
/* Encodes the Int64 number into an 8-byte Lua string, using given endianess */
# define WSLUA_OPTARG_Int64_encode_ENDIAN 2 /* If set to true then little-endian is used, if false then big-endian; if missing/nil, native host endian */
luaL_Buffer b ;
gboolean asLittleEndian = ( G_BYTE_ORDER = = G_LITTLE_ENDIAN ) ? TRUE : FALSE ;
if ( lua_gettop ( L ) > = WSLUA_OPTARG_Int64_encode_ENDIAN ) {
if ( lua_type ( L , WSLUA_OPTARG_Int64_encode_ENDIAN ) = = LUA_TBOOLEAN )
asLittleEndian = lua_toboolean ( L , WSLUA_OPTARG_Int64_encode_ENDIAN ) ;
}
luaL_buffinit ( L , & b ) ;
Int64_pack ( L , & b , 1 , asLittleEndian ) ;
luaL_pushresult ( & b ) ;
WSLUA_RETURN ( 1 ) ; /* The Lua string */
}
/* Decodes from string buffer struct into Int64 userdata, with given endianess */
int Int64_unpack ( lua_State * L , const gchar * buff , gboolean asLittleEndian ) {
gint64 value = 0 ;
gint i ;
if ( asLittleEndian ) {
for ( i = sizeof ( gint64 ) - 1 ; i > = 0 ; i - - ) {
value < < = 8 ;
value | = ( gint64 ) ( guchar ) buff [ i ] ;
}
}
else {
for ( i = 0 ; i < ( gint ) sizeof ( gint64 ) ; i + + ) {
value < < = 8 ;
value | = ( gint64 ) ( guchar ) buff [ i ] ;
}
}
pushInt64 ( L , value ) ;
return 1 ;
}
WSLUA_CONSTRUCTOR Int64_decode ( lua_State * L ) {
/* Decodes an 8-byte Lua string, using given endianess, into a new Int64 object */
# define WSLUA_ARG_Int64_decode_STRING 1 /* The Lua string containing a binary 64-bit integer */
# define WSLUA_OPTARG_Int64_decode_ENDIAN 2 /* If set to true then little-endian is used, if false then big-endian; if missing/nil, native host endian */
gboolean asLittleEndian = ( G_BYTE_ORDER = = G_LITTLE_ENDIAN ) ? TRUE : FALSE ;
size_t len = 0 ;
const gchar * s = luaL_checklstring ( L , WSLUA_ARG_Int64_decode_STRING , & len ) ;
if ( lua_gettop ( L ) > = WSLUA_OPTARG_Int64_decode_ENDIAN ) {
if ( lua_type ( L , WSLUA_OPTARG_Int64_decode_ENDIAN ) = = LUA_TBOOLEAN )
asLittleEndian = lua_toboolean ( L , WSLUA_OPTARG_Int64_decode_ENDIAN ) ;
}
if ( len = = sizeof ( gint64 ) ) {
Int64_unpack ( L , s , asLittleEndian ) ;
} else {
lua_pushnil ( L ) ;
}
WSLUA_RETURN ( 1 ) ; /* The Int64 object created, or nil on failure */
}
WSLUA_CONSTRUCTOR Int64_new ( lua_State * L ) { /* Creates a Int64 Object */
# define WSLUA_OPTARG_Int64_new_VALUE 1 /* A number, UInt64, Int64, or string of ascii digits to assign the value of the new Int64 (default=0) */
# define WSLUA_OPTARG_Int64_new_HIGHVALUE 2 /* If this is a number and the first argument was a number, then the first will be treated as a lower 32-bits, and this is the high-order 32 bit number */
gint64 value = 0 ;
if ( lua_gettop ( L ) > = 1 ) {
switch ( lua_type ( L , WSLUA_OPTARG_Int64_new_VALUE ) ) {
case LUA_TNUMBER :
value = ( gint64 ) lua_tonumber ( L , WSLUA_OPTARG_Int64_new_VALUE ) ;
if ( lua_gettop ( L ) = = 2 & & lua_type ( L , WSLUA_OPTARG_Int64_new_HIGHVALUE ) = = LUA_TNUMBER ) {
gint64 h = ( gint64 ) lua_tonumber ( L , WSLUA_OPTARG_Int64_new_HIGHVALUE ) ;
value & = 0x00000000FFFFFFFF ;
h < < = 32 ; h & = 0xFFFFFFFF00000000 ;
value + = h ;
}
break ;
case LUA_TSTRING :
case LUA_TUSERDATA :
value = getInt64 ( L , WSLUA_OPTARG_Int64_new_VALUE ) ;
break ;
default :
WSLUA_OPTARG_ERROR ( Int64_new , VALUE , " must be a number, UInt64, Int64, or string " ) ;
break ;
}
}
pushInt64 ( L , value ) ;
WSLUA_RETURN ( 1 ) ; /* The new Int64 object. */
}
WSLUA_CONSTRUCTOR Int64_max ( lua_State * L ) { /* Gets the max possible value */
pushInt64 ( L , G_MAXINT64 ) ;
WSLUA_RETURN ( 1 ) ; /* The new Int64 object of the max value. */
}
WSLUA_CONSTRUCTOR Int64_min ( lua_State * L ) { /* Gets the min possible value */
pushInt64 ( L , G_MININT64 ) ;
WSLUA_RETURN ( 1 ) ; /* The new Int64 object of the min value. */
}
WSLUA_METHOD Int64_tonumber ( lua_State * L ) {
/* Returns a Lua number of the Int64 value - this may lose precision. */
lua_pushnumber ( L , ( lua_Number ) checkInt64 ( L , 1 ) ) ;
WSLUA_RETURN ( 1 ) ; /* The Lua number */
}
WSLUA_CONSTRUCTOR Int64_fromhex ( lua_State * L ) { /* Creates an Int64 object from the given hex string */
guint64 result = 0 ;
size_t len = 0 ;
const gchar * s = luaL_checklstring ( L , 1 , & len ) ;
if ( s & & len > 0 ) {
sscanf ( s , " % " G_GINT64_MODIFIER " x " , & result ) ;
}
pushInt64 ( L , ( gint64 ) result ) ;
WSLUA_RETURN ( 1 ) ; /* The new Int64 object. */
}
WSLUA_METHOD Int64_tohex ( lua_State * L ) {
/* Returns a hex string of the Int64 value. */
# define WSLUA_OPTARG_Int64_new_NUMBYTES 2 /* The number of hex-chars/nibbles to generate, negative means uppercase (default=16) */
gint64 b = getInt64 ( L , 1 ) ;
gint n = luaL_optint ( L , WSLUA_OPTARG_Int64_new_NUMBYTES , 16 ) ;
const gchar * hexdigits = " 0123456789abcdef " ;
gchar buf [ 16 ] ;
gint i ;
if ( n < 0 ) { n = - n ; hexdigits = " 0123456789ABCDEF " ; }
if ( n > 16 ) n = 16 ;
for ( i = n - 1 ; i > = 0 ; - - i ) { buf [ i ] = hexdigits [ b & 15 ] ; b > > = 4 ; }
lua_pushlstring ( L , buf , ( size_t ) n ) ;
WSLUA_RETURN ( 1 ) ; /* The string hex */
}
WSLUA_METHOD Int64_higher ( lua_State * L ) {
/* Returns a Lua number of the higher 32-bits of the Int64 value. (negative Int64 will return a negative Lua number) */
gint64 num = getInt64 ( L , 1 ) ;
gint64 b = num ;
lua_Number n ;
if ( b < 0 ) b = - b ; /* masking/shifting negative int64 isn't working on some platforms */
b & = 0x7FFFFFFF00000000 ;
b > > = 32 ;
n = ( lua_Number ) ( guint32 ) ( b & 0x00000000FFFFFFFFF ) ;
if ( num < 0 ) n = - n ;
lua_pushnumber ( L , n ) ;
WSLUA_RETURN ( 1 ) ; /* The Lua number */
}
WSLUA_METHOD Int64_lower ( lua_State * L ) {
/* Returns a Lua number of the lower 32-bits of the Int64 value. (always positive) */
gint64 b = getInt64 ( L , 1 ) ;
if ( b < 0 ) b = - b ; /* masking/shifting negative int64 isn't working on some platforms */
lua_pushnumber ( L , ( guint32 ) ( b & 0x00000000FFFFFFFFF ) ) ;
WSLUA_RETURN ( 1 ) ; /* The Lua number */
}
WSLUA_METAMETHOD Int64__tostring ( lua_State * L ) {
/* Converts the Int64 into a string of decimal digits */
gint64 num = getInt64 ( L , 1 ) ;
gchar s [ LUATYPE64_STRING_SIZE ] ;
if ( sprintf ( s , " % " G_GINT64_MODIFIER " d " , num ) < 0 )
luaL_error ( L , " Error writing Int64 to a string " ) ;
lua_pushstring ( L , s ) ;
WSLUA_RETURN ( 1 ) ; /* The Lua string */
}
WSLUA_METAMETHOD Int64__unm ( lua_State * L ) {
/* Returns the negative of the Int64, in a new Int64 */
pushInt64 ( L , - ( getInt64 ( L , 1 ) ) ) ;
WSLUA_RETURN ( 1 ) ; /* The new Int64 */
}
# define WSLUA_MATH_OP_FUNC(obj,op) \
/* use the 'get' form so we can accept numbers as well */ \
obj num1 = get # # obj ( L , 1 ) ; \
obj num2 = get # # obj ( L , 2 ) ; \
push # # obj ( L , ( num1 ) op ( num2 ) ) ; \
return 1
WSLUA_METAMETHOD Int64__add ( lua_State * L ) {
/* Adds two Int64 together and returns a new one (this may wrap the value) */
WSLUA_MATH_OP_FUNC ( Int64 , + ) ;
}
WSLUA_METAMETHOD Int64__sub ( lua_State * L ) {
/* Subtracts two Int64 and returns a new one (this may wrap the value) */
WSLUA_MATH_OP_FUNC ( Int64 , - ) ;
}
WSLUA_METAMETHOD Int64__mul ( lua_State * L ) {
/* Multiplies two Int64 and returns a new one (this may truncate the value) */
WSLUA_MATH_OP_FUNC ( Int64 , * ) ;
}
WSLUA_METAMETHOD Int64__div ( lua_State * L ) {
/* Divides two Int64 and returns a new one (integer divide, no remainder) */
WSLUA_MATH_OP_FUNC ( Int64 , / ) ;
}
WSLUA_METAMETHOD Int64__mod ( lua_State * L ) {
/* Divides two Int64 and returns a new one of the remainder */
WSLUA_MATH_OP_FUNC ( Int64 , % ) ;
}
WSLUA_METAMETHOD Int64__pow ( lua_State * L ) {
/* The first Int64 is taken to the power of the second Int64, returning a new one (this may truncate the value) */
gint64 num1 = getInt64 ( L , 1 ) ;
gint64 num2 = getInt64 ( L , 2 ) ;
gint64 result ;
if ( num1 = = 2 ) {
result = ( num2 > = 8 * ( gint64 ) sizeof ( gint64 ) ) ? 0 : ( ( gint64 ) 1 < < num2 ) ;
}
else {
for ( result = 1 ; num2 > 0 ; num2 > > = 1 ) {
if ( num2 & 1 ) result * = num1 ;
num1 * = num1 ;
}
}
pushInt64 ( L , result ) ;
WSLUA_RETURN ( 1 ) ; /* The Int64 object */
}
# define WSLUA_COMP_OP_FUNC(obj,op) \
obj num1 = get # # obj ( L , 1 ) ; \
obj num2 = get # # obj ( L , 2 ) ; \
lua_pushboolean ( L , ( num1 ) op ( num2 ) ) ; \
return 1
WSLUA_METAMETHOD Int64__eq ( lua_State * L ) {
/* Returns true if both Int64 are equal */
WSLUA_COMP_OP_FUNC ( Int64 , = = ) ;
}
WSLUA_METAMETHOD Int64__lt ( lua_State * L ) {
/* Returns true if first Int64 < second */
WSLUA_COMP_OP_FUNC ( Int64 , < ) ;
}
WSLUA_METAMETHOD Int64__le ( lua_State * L ) {
/* Returns true if first Int64 <= second */
WSLUA_COMP_OP_FUNC ( Int64 , < = ) ;
}
WSLUA_METHOD Int64_bnot ( lua_State * L ) {
/* Returns a Int64 of the bitwise 'not' operation. */
pushInt64 ( L , ~ ( getInt64 ( L , 1 ) ) ) ;
WSLUA_RETURN ( 1 ) ; /* The Int64 object */
}
# define WSLUA_BIT_OP_FUNC(obj,op) \
gint32 i ; \
obj num = get # # obj ( L , 1 ) ; \
for ( i = lua_gettop ( L ) ; i > 1 ; i - - ) { \
num op get # # obj ( L , i ) ; \
} \
push # # obj ( L , num ) ; \
return 1
WSLUA_METHOD Int64_band ( lua_State * L ) {
/* Returns a Int64 of the bitwise 'and' operation, with the given number/Int64/UIn64. Note that multiple arguments are allowed. */
WSLUA_BIT_OP_FUNC ( Int64 , & = ) ;
WSLUA_RETURN ( 1 ) ; /* The Int64 object */
}
WSLUA_METHOD Int64_bor ( lua_State * L ) {
/* Returns a Int64 of the bitwise 'or' operation, with the given number/Int64/UIn64. Note that multiple arguments are allowed. */
WSLUA_BIT_OP_FUNC ( Int64 , | = ) ;
WSLUA_RETURN ( 1 ) ; /* The Int64 object */
}
WSLUA_METHOD Int64_bxor ( lua_State * L ) {
/* Returns a Int64 of the bitwise 'xor' operation, with the given number/Int64/UIn64. Note that multiple arguments are allowed. */
WSLUA_BIT_OP_FUNC ( Int64 , ^ = ) ;
WSLUA_RETURN ( 1 ) ; /* The Int64 object */
}
WSLUA_METHOD Int64_lshift ( lua_State * L ) {
/* Returns a Int64 of the bitwise logical left-shift operation, by the given number of bits. */
# define WSLUA_ARG_Int64_lshift_NUMBITS 2 /* The number of bits to left-shift by */
guint64 b = ( guint64 ) getInt64 ( L , 1 ) ;
2014-02-04 00:56:49 +00:00
guint32 n = ( guint32 ) luaL_checknumber ( L , WSLUA_ARG_Int64_lshift_NUMBITS ) ;
2014-02-03 03:49:30 +00:00
pushInt64 ( L , ( gint64 ) ( b < < n ) ) ;
WSLUA_RETURN ( 1 ) ; /* The Int64 object */
}
WSLUA_METHOD Int64_rshift ( lua_State * L ) {
/* Returns a Int64 of the bitwise logical right-shift operation, by the given number of bits. */
# define WSLUA_ARG_Int64_rshift_NUMBITS 2 /* The number of bits to right-shift by */
guint64 b = ( guint64 ) getInt64 ( L , 1 ) ;
2014-02-04 00:56:49 +00:00
guint32 n = ( guint32 ) luaL_checknumber ( L , WSLUA_ARG_Int64_rshift_NUMBITS ) ;
2014-02-03 03:49:30 +00:00
pushInt64 ( L , ( gint64 ) ( b > > n ) ) ;
WSLUA_RETURN ( 1 ) ; /* The Int64 object */
}
WSLUA_METHOD Int64_arshift ( lua_State * L ) {
/* Returns a Int64 of the bitwise arithmetic right-shift operation, by the given number of bits. */
# define WSLUA_ARG_Int64_arshift_NUMBITS 2 /* The number of bits to right-shift by */
gint64 b = getInt64 ( L , 1 ) ;
2014-02-04 00:56:49 +00:00
gint32 n = ( gint32 ) luaL_checknumber ( L , WSLUA_ARG_Int64_arshift_NUMBITS ) ;
2014-02-03 03:49:30 +00:00
pushInt64 ( L , ( b > > n ) ) ;
WSLUA_RETURN ( 1 ) ; /* The Int64 object */
}
WSLUA_METHOD Int64_rol ( lua_State * L ) {
/* Returns a Int64 of the bitwise left rotation operation, by the given number of bits (up to 63). */
# define WSLUA_ARG_Int64_rol_NUMBITS 2 /* The number of bits to roll left by */
guint64 b = ( guint64 ) getInt64 ( L , 1 ) ;
2014-02-04 00:56:49 +00:00
guint32 n = ( guint32 ) luaL_checknumber ( L , WSLUA_ARG_Int64_rol_NUMBITS ) ;
2014-02-03 03:49:30 +00:00
pushInt64 ( L , ( gint64 ) ( ( b < < n ) | ( b > > ( 64 - n ) ) ) ) ;
WSLUA_RETURN ( 1 ) ; /* The Int64 object */
}
WSLUA_METHOD Int64_ror ( lua_State * L ) {
/* Returns a Int64 of the bitwise right rotation operation, by the given number of bits (up to 63). */
# define WSLUA_ARG_Int64_ror_NUMBITS 2 /* The number of bits to roll right by */
guint64 b = ( guint64 ) getInt64 ( L , 1 ) ;
2014-02-04 00:56:49 +00:00
guint32 n = ( guint32 ) luaL_checknumber ( L , WSLUA_ARG_Int64_ror_NUMBITS ) ;
2014-02-03 03:49:30 +00:00
pushInt64 ( L , ( gint64 ) ( ( b < < ( 64 - n ) ) | ( b > > n ) ) ) ;
WSLUA_RETURN ( 1 ) ; /* The Int64 object */
}
WSLUA_METHOD Int64_bswap ( lua_State * L ) {
/* Returns a Int64 of the bytes swapped. This can be used to convert little-endian 64 bit numbers to big-endian 64 bit numbers or vice versa. */
guint64 b = ( guint64 ) getInt64 ( L , 1 ) ;
guint64 result = 0 ;
size_t i ;
for ( i = 0 ; i < sizeof ( gint64 ) ; i + + ) {
result < < = 8 ;
result | = ( b & 0x00000000000000FF ) ;
b > > = 8 ;
}
pushInt64 ( L , ( gint64 ) result ) ;
WSLUA_RETURN ( 1 ) ; /* The Int64 object */
}
/* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
static int Int64__gc ( lua_State * L _U_ ) {
return 0 ;
}
static const luaL_Reg Int64_methods [ ] = {
{ " new " , Int64_new } ,
{ " max " , Int64_max } ,
{ " min " , Int64_min } ,
{ " tonumber " , Int64_tonumber } ,
{ " fromhex " , Int64_fromhex } ,
{ " tohex " , Int64_tohex } ,
{ " higher " , Int64_higher } ,
{ " lower " , Int64_lower } ,
{ " encode " , Int64_encode } ,
{ " decode " , Int64_decode } ,
{ " bnot " , Int64_bnot } ,
{ " band " , Int64_band } ,
{ " bor " , Int64_bor } ,
{ " bxor " , Int64_bxor } ,
{ " lshift " , Int64_lshift } ,
{ " rshift " , Int64_rshift } ,
{ " arshift " , Int64_arshift } ,
{ " rol " , Int64_rol } ,
{ " ror " , Int64_ror } ,
{ " bswap " , Int64_bswap } ,
{ NULL , NULL }
} ;
static const luaL_Reg Int64_meta [ ] = {
{ " __tostring " , Int64__tostring } ,
{ " __concat " , wslua__concat } ,
{ " __unm " , Int64__unm } ,
{ " __add " , Int64__add } ,
{ " __sub " , Int64__sub } ,
{ " __mul " , Int64__mul } ,
{ " __div " , Int64__div } ,
{ " __mod " , Int64__mod } ,
{ " __pow " , Int64__pow } ,
{ " __eq " , Int64__eq } ,
{ " __lt " , Int64__lt } ,
{ " __le " , Int64__le } ,
{ NULL , NULL }
} ;
LUALIB_API int Int64_register ( lua_State * L ) {
WSLUA_REGISTER_CLASS ( Int64 ) ;
return 0 ;
}
WSLUA_CLASS_DEFINE_BASE ( UInt64 , NOP , NOP , 0 ) ;
/* UInt64 represents a 64 bit unsigned integer, similar to Int64. */
/* A checkUInt64 but that also auto-converts numbers, strings, and Int64 to a guint64 */
static guint64 getUInt64 ( lua_State * L , int i )
{
gchar * end = NULL ;
( void ) end ;
switch ( lua_type ( L , i ) )
{
case LUA_TNUMBER :
2014-02-04 00:56:49 +00:00
return ( guint64 ) luaL_checknumber ( L , i ) ;
2014-02-03 03:49:30 +00:00
case LUA_TSTRING :
return g_ascii_strtoull ( luaL_checkstring ( L , i ) , & end , 10 ) ;
case LUA_TUSERDATA :
if ( isInt64 ( L , i ) ) {
return ( UInt64 ) toInt64 ( L , i ) ;
break ;
}
/* fall through */
default :
return checkUInt64 ( L , i ) ;
}
}
/* Encodes UInt64 userdata into Lua string struct with given endianess */
void UInt64_pack ( lua_State * L , luaL_Buffer * b , gint idx , gboolean asLittleEndian ) {
guint64 value = checkUInt64 ( L , idx ) ;
gint8 buff [ sizeof ( guint64 ) ] ;
if ( asLittleEndian ) {
guint i ;
for ( i = 0 ; i < sizeof ( guint64 ) ; i + + ) {
buff [ i ] = ( value & 0xff ) ;
value > > = 8 ;
}
}
else {
gint i ;
for ( i = sizeof ( guint64 ) - 1 ; i > = 0 ; i - - ) {
buff [ i ] = ( value & 0xff ) ;
value > > = 8 ;
}
}
luaL_addlstring ( b , ( char * ) buff , sizeof ( guint64 ) ) ;
}
WSLUA_METHOD UInt64_encode ( lua_State * L ) {
/* Encodes the UInt64 number into an 8-byte Lua binary string, using given endianess */
# define WSLUA_OPTARG_UInt64_encode_ENDIAN 2 /* If set to true then little-endian is used, if false then big-endian; if missing/nil, native host endian */
luaL_Buffer b ;
gboolean asLittleEndian = ( G_BYTE_ORDER = = G_LITTLE_ENDIAN ) ? TRUE : FALSE ;
if ( lua_gettop ( L ) > = 2 ) {
if ( lua_type ( L , 2 ) = = LUA_TBOOLEAN )
asLittleEndian = lua_toboolean ( L , 2 ) ;
}
luaL_buffinit ( L , & b ) ;
UInt64_pack ( L , & b , 1 , asLittleEndian ) ;
luaL_pushresult ( & b ) ;
WSLUA_RETURN ( 1 ) ; /* The Lua binary string */
}
/* Decodes from string buffer struct into UInt64 userdata, with given endianess */
int UInt64_unpack ( lua_State * L , const gchar * buff , gboolean asLittleEndian ) {
guint64 value = 0 ;
gint i ;
if ( asLittleEndian ) {
for ( i = sizeof ( guint64 ) - 1 ; i > = 0 ; i - - ) {
value < < = 8 ;
value | = ( guint64 ) ( guchar ) buff [ i ] ;
}
}
else {
for ( i = 0 ; i < ( gint ) sizeof ( guint64 ) ; i + + ) {
value < < = 8 ;
value | = ( guint64 ) ( guchar ) buff [ i ] ;
}
}
pushUInt64 ( L , value ) ;
return 1 ;
}
WSLUA_CONSTRUCTOR UInt64_decode ( lua_State * L ) {
/* Decodes an 8-byte Lua binary string, using given endianess, into a new UInt64 object */
# define WSLUA_ARG_UInt64_decode_STRING 1 /* The Lua string containing a binary 64-bit integer */
# define WSLUA_OPTARG_UInt64_decode_ENDIAN 2 /* If set to true then little-endian is used, if false then big-endian; if missing/nil, native host endian */
gboolean asLittleEndian = ( G_BYTE_ORDER = = G_LITTLE_ENDIAN ) ? TRUE : FALSE ;
size_t len = 0 ;
const gchar * s = luaL_checklstring ( L , WSLUA_ARG_UInt64_decode_STRING , & len ) ;
if ( lua_gettop ( L ) > = WSLUA_OPTARG_UInt64_decode_ENDIAN ) {
if ( lua_type ( L , WSLUA_OPTARG_UInt64_decode_ENDIAN ) = = LUA_TBOOLEAN )
asLittleEndian = lua_toboolean ( L , WSLUA_OPTARG_UInt64_decode_ENDIAN ) ;
}
if ( len = = sizeof ( guint64 ) ) {
UInt64_unpack ( L , s , asLittleEndian ) ;
} else {
lua_pushnil ( L ) ;
}
WSLUA_RETURN ( 1 ) ; /* The UInt64 object created, or nil on failure */
}
WSLUA_CONSTRUCTOR UInt64_new ( lua_State * L ) { /* Creates a UInt64 Object */
# define WSLUA_OPTARG_UInt64_new_VALUE 1 /* A number, UInt64, Int64, or string of digits to assign the value of the new UInt64 (default=0) */
# define WSLUA_OPTARG_UInt64_new_HIGHVALUE 2 /* If this is a number and the first argument was a number, then the first will be treated as a lower 32-bits, and this is the high-order 32 bit number */
guint64 value = 0 ;
if ( lua_gettop ( L ) > = 1 ) {
switch ( lua_type ( L , WSLUA_OPTARG_UInt64_new_VALUE ) ) {
case LUA_TNUMBER :
value = ( guint64 ) lua_tonumber ( L , WSLUA_OPTARG_UInt64_new_VALUE ) ;
if ( lua_gettop ( L ) = = 2 & & lua_type ( L , WSLUA_OPTARG_UInt64_new_HIGHVALUE ) = = LUA_TNUMBER ) {
guint64 h = ( guint64 ) lua_tonumber ( L , WSLUA_OPTARG_UInt64_new_HIGHVALUE ) ;
value & = 0x00000000FFFFFFFF ;
h < < = 32 ; h & = 0xFFFFFFFF00000000 ;
value + = h ;
}
break ;
case LUA_TSTRING :
case LUA_TUSERDATA :
value = getUInt64 ( L , WSLUA_OPTARG_UInt64_new_VALUE ) ;
break ;
default :
WSLUA_OPTARG_ERROR ( UInt64_new , VALUE , " must be a number, UInt64, Int64, or string " ) ;
break ;
}
}
pushUInt64 ( L , value ) ;
WSLUA_RETURN ( 1 ) ; /* The new UInt64 object. */
}
WSLUA_CONSTRUCTOR UInt64_max ( lua_State * L ) { /* Gets the max possible value */
pushUInt64 ( L , G_MAXUINT64 ) ;
WSLUA_RETURN ( 1 ) ; /* The max value. */
}
WSLUA_CONSTRUCTOR UInt64_min ( lua_State * L ) { /* Gets the min possible value (i.e., 0) */
pushUInt64 ( L , 0 ) ;
WSLUA_RETURN ( 1 ) ; /* The min value. */
}
WSLUA_METHOD UInt64_tonumber ( lua_State * L ) {
/* Returns a Lua number of the UInt64 value - this may lose precision. */
lua_pushnumber ( L , ( lua_Number ) checkUInt64 ( L , 1 ) ) ;
WSLUA_RETURN ( 1 ) ; /* The Lua number */
}
WSLUA_METAMETHOD UInt64__tostring ( lua_State * L ) {
/* Converts the UInt64 into a string */
guint64 num = getUInt64 ( L , 1 ) ;
gchar s [ LUATYPE64_STRING_SIZE ] ;
if ( sprintf ( s , " % " G_GINT64_MODIFIER " u " , ( guint64 ) num ) < 0 )
luaL_error ( L , " Error writing UInt64 to a string " ) ;
lua_pushstring ( L , s ) ;
WSLUA_RETURN ( 1 ) ; /* The Lua string */
}
WSLUA_CONSTRUCTOR UInt64_fromhex ( lua_State * L ) { /* Creates a UInt64 object from the given hex string */
guint64 result = 0 ;
size_t len = 0 ;
const gchar * s = luaL_checklstring ( L , 1 , & len ) ;
if ( s & & len > 0 ) {
sscanf ( s , " % " G_GINT64_MODIFIER " x " , & result ) ;
}
pushUInt64 ( L , result ) ;
WSLUA_RETURN ( 1 ) ; /* The new UInt64 object. */
}
WSLUA_METHOD UInt64_tohex ( lua_State * L ) {
/* Returns a hex string of the UInt64 value. */
# define WSLUA_OPTARG_Int64_new_NUMBYTES 2 /* The number of hex-chars/nibbles to generate, negative means uppercase (default=16) */
guint64 b = getUInt64 ( L , 1 ) ;
gint n = luaL_optint ( L , WSLUA_OPTARG_Int64_new_NUMBYTES , 16 ) ;
const gchar * hexdigits = " 0123456789abcdef " ;
gchar buf [ 16 ] ;
gint i ;
if ( n < 0 ) { n = - n ; hexdigits = " 0123456789ABCDEF " ; }
if ( n > 16 ) n = 16 ;
for ( i = n - 1 ; i > = 0 ; - - i ) { buf [ i ] = hexdigits [ b & 15 ] ; b > > = 4 ; }
lua_pushlstring ( L , buf , ( size_t ) n ) ;
WSLUA_RETURN ( 1 ) ; /* The string hex */
}
WSLUA_METHOD UInt64_higher ( lua_State * L ) {
/* Returns a Lua number of the higher 32-bits of the UInt64 value. */
guint64 num = getUInt64 ( L , 1 ) ;
guint64 b = num ;
lua_Number n ;
b & = 0xFFFFFFFF00000000 ;
b > > = 32 ;
n = ( lua_Number ) ( guint32 ) ( b & 0x00000000FFFFFFFFF ) ;
lua_pushnumber ( L , n ) ;
WSLUA_RETURN ( 1 ) ; /* The Lua number */
}
WSLUA_METHOD UInt64_lower ( lua_State * L ) {
/* Returns a Lua number of the lower 32-bits of the UInt64 value. */
guint64 b = getUInt64 ( L , 1 ) ;
lua_pushnumber ( L , ( guint32 ) ( b & 0x00000000FFFFFFFFF ) ) ;
WSLUA_RETURN ( 1 ) ; /* The Lua number */
}
WSLUA_METAMETHOD UInt64__unm ( lua_State * L ) {
/* Returns the UInt64, in a new UInt64, since unsigned integers can't be negated. */
pushUInt64 ( L , getUInt64 ( L , 1 ) ) ;
WSLUA_RETURN ( 1 ) ; /* The UInt64 object */
}
WSLUA_METAMETHOD UInt64__add ( lua_State * L ) {
/* Adds two UInt64 together and returns a new one (this may wrap the value) */
WSLUA_MATH_OP_FUNC ( UInt64 , + ) ;
}
WSLUA_METAMETHOD UInt64__sub ( lua_State * L ) {
/* Subtracts two UInt64 and returns a new one (this may wrap the value) */
WSLUA_MATH_OP_FUNC ( UInt64 , - ) ;
}
WSLUA_METAMETHOD UInt64__mul ( lua_State * L ) {
/* Multiplies two UInt64 and returns a new one (this may truncate the value) */
WSLUA_MATH_OP_FUNC ( UInt64 , * ) ;
}
WSLUA_METAMETHOD UInt64__div ( lua_State * L ) {
/* Divides two UInt64 and returns a new one (integer divide, no remainder) */
WSLUA_MATH_OP_FUNC ( UInt64 , / ) ;
}
WSLUA_METAMETHOD UInt64__mod ( lua_State * L ) {
/* Divides two UInt64 and returns a new one of the remainder */
WSLUA_MATH_OP_FUNC ( UInt64 , % ) ;
}
WSLUA_METAMETHOD UInt64__pow ( lua_State * L ) {
/* The first UInt64 is taken to the power of the second UInt64/number, returning a new one (this may truncate the value) */
guint64 num1 = getUInt64 ( L , 1 ) ;
guint64 num2 = getUInt64 ( L , 2 ) ;
guint64 result ;
if ( num1 = = 2 ) {
result = ( num2 > = 8 * ( guint64 ) sizeof ( guint64 ) ) ? 0 : ( ( guint64 ) 1 < < num2 ) ;
}
else {
for ( result = 1 ; num2 > 0 ; num2 > > = 1 ) {
if ( num2 & 1 ) result * = num1 ;
num1 * = num1 ;
}
}
pushUInt64 ( L , result ) ;
WSLUA_RETURN ( 1 ) ; /* The UInt64 object */
}
WSLUA_METAMETHOD UInt64__eq ( lua_State * L ) {
/* Returns true if both UInt64 are equal */
WSLUA_COMP_OP_FUNC ( UInt64 , = = ) ;
}
WSLUA_METAMETHOD UInt64__lt ( lua_State * L ) {
/* Returns true if first UInt64 < second */
WSLUA_COMP_OP_FUNC ( UInt64 , < ) ;
}
WSLUA_METAMETHOD UInt64__le ( lua_State * L ) {
/* Returns true if first UInt64 <= second */
WSLUA_COMP_OP_FUNC ( UInt64 , < = ) ;
}
WSLUA_METHOD UInt64_bnot ( lua_State * L ) {
/* Returns a UInt64 of the bitwise 'not' operation. */
pushUInt64 ( L , ~ ( getUInt64 ( L , 1 ) ) ) ;
WSLUA_RETURN ( 1 ) ; /* The UInt64 object */
}
WSLUA_METHOD UInt64_band ( lua_State * L ) {
/* Returns a UInt64 of the bitwise 'and' operation, with the given number/Int64/UIn64. Note that multiple arguments are allowed. */
WSLUA_BIT_OP_FUNC ( UInt64 , & = ) ;
WSLUA_RETURN ( 1 ) ; /* The UInt64 object */
}
WSLUA_METHOD UInt64_bor ( lua_State * L ) {
/* Returns a UInt64 of the bitwise 'or' operation, with the given number/Int64/UIn64. Note that multiple arguments are allowed. */
WSLUA_BIT_OP_FUNC ( UInt64 , | = ) ;
WSLUA_RETURN ( 1 ) ; /* The UInt64 object */
}
WSLUA_METHOD UInt64_bxor ( lua_State * L ) {
/* Returns a UInt64 of the bitwise 'xor' operation, with the given number/Int64/UIn64. Note that multiple arguments are allowed. */
WSLUA_BIT_OP_FUNC ( UInt64 , ^ = ) ;
WSLUA_RETURN ( 1 ) ; /* The UInt64 object */
}
WSLUA_METHOD UInt64_lshift ( lua_State * L ) {
/* Returns a UInt64 of the bitwise logical left-shift operation, by the given number of bits. */
# define WSLUA_ARG_UInt64_lshift_NUMBITS 2 /* The number of bits to left-shift by */
guint64 b = getUInt64 ( L , 1 ) ;
2014-02-04 00:56:49 +00:00
guint32 n = ( guint32 ) luaL_checknumber ( L , WSLUA_ARG_UInt64_lshift_NUMBITS ) ;
2014-02-03 03:49:30 +00:00
pushUInt64 ( L , ( b < < n ) ) ;
WSLUA_RETURN ( 1 ) ; /* The UInt64 object */
}
WSLUA_METHOD UInt64_rshift ( lua_State * L ) {
/* Returns a UInt64 of the bitwise logical right-shift operation, by the given number of bits. */
# define WSLUA_ARG_UInt64_rshift_NUMBITS 2 /* The number of bits to right-shift by */
guint64 b = getUInt64 ( L , 1 ) ;
2014-02-04 00:56:49 +00:00
guint32 n = ( guint32 ) luaL_checknumber ( L , WSLUA_ARG_UInt64_rshift_NUMBITS ) ;
2014-02-03 03:49:30 +00:00
pushUInt64 ( L , ( b > > n ) ) ;
WSLUA_RETURN ( 1 ) ; /* The UInt64 object */
}
WSLUA_METHOD UInt64_arshift ( lua_State * L ) {
/* Returns a UInt64 of the bitwise arithmetic right-shift operation, by the given number of bits. */
# define WSLUA_ARG_UInt64_arshift_NUMBITS 2 /* The number of bits to right-shift by */
guint64 b = getUInt64 ( L , 1 ) ;
2014-02-04 00:56:49 +00:00
guint32 n = ( guint32 ) luaL_checknumber ( L , WSLUA_ARG_UInt64_arshift_NUMBITS ) ;
2014-02-03 03:49:30 +00:00
pushUInt64 ( L , ( b > > n ) ) ;
WSLUA_RETURN ( 1 ) ; /* The UInt64 object */
}
WSLUA_METHOD UInt64_rol ( lua_State * L ) {
/* Returns a UInt64 of the bitwise left rotation operation, by the given number of bits (up to 63). */
# define WSLUA_ARG_UInt64_rol_NUMBITS 2 /* The number of bits to roll left by */
guint64 b = getUInt64 ( L , 1 ) ;
2014-02-04 00:56:49 +00:00
guint32 n = ( guint32 ) luaL_checknumber ( L , WSLUA_ARG_UInt64_rol_NUMBITS ) ;
2014-02-03 03:49:30 +00:00
pushUInt64 ( L , ( ( b < < n ) | ( b > > ( 64 - n ) ) ) ) ;
WSLUA_RETURN ( 1 ) ; /* The UInt64 object */
}
WSLUA_METHOD UInt64_ror ( lua_State * L ) {
/* Returns a UInt64 of the bitwise right rotation operation, by the given number of bits (up to 63). */
# define WSLUA_ARG_UInt64_ror_NUMBITS 2 /* The number of bits to roll right by */
guint64 b = getUInt64 ( L , 1 ) ;
2014-02-04 00:56:49 +00:00
guint32 n = ( guint32 ) luaL_checknumber ( L , WSLUA_ARG_UInt64_ror_NUMBITS ) ;
2014-02-03 03:49:30 +00:00
pushUInt64 ( L , ( ( b < < ( 64 - n ) ) | ( b > > n ) ) ) ;
WSLUA_RETURN ( 1 ) ; /* The UInt64 object */
}
WSLUA_METHOD UInt64_bswap ( lua_State * L ) {
/* Returns a UInt64 of the bytes swapped. This can be used to convert little-endian 64 bit numbers to big-endian 64 bit numbers or vice versa. */
guint64 b = getUInt64 ( L , 1 ) ;
guint64 result = 0 ;
size_t i ;
for ( i = 0 ; i < sizeof ( guint64 ) ; i + + ) {
result < < = 8 ;
result | = ( b & 0x00000000000000FF ) ;
b > > = 8 ;
}
pushUInt64 ( L , result ) ;
WSLUA_RETURN ( 1 ) ; /* The UInt64 object */
}
/* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
static int UInt64__gc ( lua_State * L _U_ ) {
return 0 ;
}
static const luaL_Reg UInt64_methods [ ] = {
{ " new " , UInt64_new } ,
{ " max " , UInt64_max } ,
{ " min " , UInt64_min } ,
{ " tonumber " , UInt64_tonumber } ,
{ " fromhex " , UInt64_fromhex } ,
{ " tohex " , UInt64_tohex } ,
{ " higher " , UInt64_higher } ,
{ " lower " , UInt64_lower } ,
{ " encode " , UInt64_encode } ,
{ " decode " , UInt64_decode } ,
{ " bnot " , UInt64_bnot } ,
{ " band " , UInt64_band } ,
{ " bor " , UInt64_bor } ,
{ " bxor " , UInt64_bxor } ,
{ " lshift " , UInt64_lshift } ,
{ " rshift " , UInt64_rshift } ,
{ " arshift " , UInt64_arshift } ,
{ " rol " , UInt64_rol } ,
{ " ror " , UInt64_ror } ,
{ " bswap " , UInt64_bswap } ,
{ NULL , NULL }
} ;
static const luaL_Reg UInt64_meta [ ] = {
{ " __tostring " , UInt64__tostring } ,
{ " __concat " , wslua__concat } ,
{ " __unm " , UInt64__unm } ,
{ " __add " , UInt64__add } ,
{ " __sub " , UInt64__sub } ,
{ " __mul " , UInt64__mul } ,
{ " __div " , UInt64__div } ,
{ " __mod " , UInt64__mod } ,
{ " __pow " , UInt64__pow } ,
{ " __eq " , UInt64__eq } ,
{ " __lt " , UInt64__lt } ,
{ " __le " , UInt64__le } ,
{ NULL , NULL }
} ;
LUALIB_API int UInt64_register ( lua_State * L ) {
WSLUA_REGISTER_CLASS ( UInt64 ) ;
return 0 ;
}