lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I don't understand exactly what you want. But: "Is it possible to write such a metatable?" Yes, maybe you want something like (attached: bytelist.c, test.lua)

I strongly agree with Dirk Laurie "Your main concern should be clarity, not speed"

2012/1/4 Dirk Laurie <dirk.laurie@gmail.com>
2012/1/4 Asim <asim.r.p@gmail.com>:

>
> I want to write a C function that returns a sequence of bytes.  This
> function should be called from Lua.  There are two options for the type of
> return value in Lua - userdata and string.
>

Your main concern should be clarity, not speed.  Is it conceivable
that you would wish to concatenate two of your bytesequences to form a
third?  If yes, by all means return a string.  If no, do it as
userdata.


/* gcc bytelist.c -pipe -shared -Wall -ansi `pkg-config --cflags --libs lua` -o bytelist.so */

/* Lua headers */
#include <lua.h>
#include <lauxlib.h>

/* C headers */
#include <stdio.h>
#include <stdlib.h>

typedef struct SByteList {
    int  len;
    char *data;
} TByteList;

int bytelist_new(lua_State* L);
int bytelist_len(lua_State* L);
int bytelist_get(lua_State* L);
int bytelist_set(lua_State* L);
int bytelist_MT_gc(lua_State* L);
int bytelist_MT_index(lua_State* L);
int bytelist_MT_newindex(lua_State* L);

static const struct luaL_reg bytelist [] =
{
    { "new"       , bytelist_new      },
    { "len"       , bytelist_len      },
    { "get"       , bytelist_get      },
    { "set"       , bytelist_set      },
    { NULL        , NULL              }
};

static const struct luaL_reg bytelist_MT [] =
{
    { "__gc"      , bytelist_MT_gc       },
    { "__index"   , bytelist_MT_index    },
    { "__newindex", bytelist_MT_newindex },
    { NULL        , NULL              }
};

int luaopen_bytelist(lua_State *L){
    luaL_register( L, "bytelist", bytelist    );
    luaL_newmetatable(L, "bytelistMT");
    luaL_register( L, NULL      , bytelist_MT );
    lua_setmetatable( L, -2 );

    return 1;
};

/* CLASS METHODS */

/*
+param:  length:number
+return: TByteList:userdata
*/
int bytelist_new(lua_State* L){
    luaL_checktype(L, 1, LUA_TNUMBER);

    /* create userdata:TByteList */
    TByteList *obj = (TByteList*) lua_newuserdata(L, sizeof(TByteList));
    obj->len       = lua_tointeger(L, 1);
    obj->data      = (char *) malloc( obj->len * sizeof(char) );

    luaL_getmetatable(L, "bytelistMT");
    lua_setmetatable(L, -2);

    return 1;
}

/*
+param:  TByteList:userdata
+return: len:number
*/
int bytelist_len(lua_State* L){
    luaL_checktype(L, 1, LUA_TUSERDATA);

    TByteList* obj = (TByteList*) lua_touserdata(L, 1);

    lua_pushinteger( L, obj->len );
    return 1;
}
/*
+param:  TByteList:userdata
+param:  position:number
+return: value:number (in fact the byte)
*/
int bytelist_get(lua_State* L){
    luaL_checktype(L, 1, LUA_TUSERDATA);
    luaL_checktype(L, 2, LUA_TNUMBER);

    TByteList* obj = (TByteList*) lua_touserdata(L, 1);
    int pos        = lua_tointeger(L, 2);

    if( pos > 0 && pos <= obj->len ){
        lua_pushinteger( L, (int) obj->data[ pos-1 ] );
        return 1;
    } else {
        lua_pushnil( L );
        lua_pushliteral( L, "invalid position" );
        return 2;
    }
}

/*
+param:  TByteList:userdata
+param:  position:number
+param:  value:number (in fact the byte)
+return: sucess:boolean
*/
int bytelist_set(lua_State* L){
    luaL_checktype(L, 1, LUA_TUSERDATA);
    luaL_checktype(L, 2, LUA_TNUMBER);
    luaL_checktype(L, 3, LUA_TNUMBER);

    TByteList* obj = (TByteList*) lua_touserdata(L, 1);
    int pos        = lua_tointeger(L, 2);

    if( pos > 0 && pos <= obj->len ){
        obj->data[ pos-1 ] = (char) lua_tointeger(L, 3);
        lua_pushboolean(L, 1);
        return 1;
    } else {
        lua_pushboolean(L, 0);
        lua_pushliteral( L, "invalid position" );
        return 2;
    }
}

/* METATABLE METHODS */

int bytelist_MT_gc(lua_State* L)
{
    luaL_checktype(L, 1, LUA_TUSERDATA);

    TByteList* obj = (TByteList*) lua_touserdata(L, 1);
    free( obj->data );

    return 0;
}

int bytelist_MT_index(lua_State* L)
{
    luaL_checktype(L, 1, LUA_TUSERDATA);

    if ( lua_isnumber( L, 2 ) ) {
        return bytelist_get( L );
    } else {
        lua_getglobal( L, "bytelist" );
        lua_pushvalue(L, 2);
        lua_rawget( L, -2);
        return 1;
    }

    return 0;
}

int bytelist_MT_newindex(lua_State* L)
{
    luaL_checktype(L, 1, LUA_TUSERDATA);

    if ( lua_isnumber( L, 2 ) ) {
        return bytelist_set( L );
    }

    return 0;
}


require 'bytelist'

bl = bytelist.new(1024)
print( bl:len() )

bl:set(1, 10)
bl:set(2, 20)
bl:set(3, 30)
print( bl:get(1), bl:get(2), bl:get(3) )

bl[4] = 40
bl[5] = 50
print( bl[1], bl[2], bl[3], bl[4], bl[5] )
print( bl:get(1), bl:get(2), bl:get(3), bl:get(4), bl:get(5) )