lua-users home
lua-l archive

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


Hi,

A quick and dirty tuple implementation using the new multi-uservalue
userdata implementation.

Compile with `cc -shared -fPIC -o tuple.so ltuple.c`.

Use as follows:

Lua 5.4.0 (work1)  Copyright (C) 1994-2018 Lua.org, PUC-Rio
> tuple = require"tuple"
> function test(...) return tuple(...) end
> t = test(1,2,nil,4,nil)
> #t
5
> t[2], t[3], t[4]
2    nil    4
> for i,v in pairs(t) do print(i,v) end
1    1
2    2
3    nil
4    4
5    nil
>

Enjoy.

Regards,

Duane.
#include "lua.h"
#include "lauxlib.h"

int luaopen_tuple(lua_State *L);

static int
constructor(lua_State *L)
{
    unsigned short n = lua_gettop(L);
    unsigned short *nptr = lua_newuserdatauv(L, sizeof(n), n);
    *nptr = n;
    if (n) {
        lua_insert(L, 1);
        do {
            lua_setiuservalue(L, 1, n);
        } while (--n);
    }
    lua_pushvalue(L, lua_upvalueindex(1));
    lua_setmetatable(L, 1);
    return 1;
}

static int
tuple__len(lua_State *L)
{
    unsigned short *nptr = lua_touserdata(L, 1);
    lua_pushinteger(L, *nptr);
    return 1;
}

static int
tuple__index(lua_State *L)
{
    unsigned short *nptr = lua_touserdata(L, 1);
    lua_Integer idx = luaL_checkinteger(L, 2);
    luaL_argcheck(L, 0 < idx && idx <= *nptr, 2, "Index out of bounds");
    lua_getiuservalue(L, 1, idx);
    return 1;
}

static int
tuple__next(lua_State *L)
{
    lua_Integer idx;
    lua_settop(L, 2);
    if (lua_isnil(L, 2)) {
        idx = 1;
    } else {
        idx = luaL_checkinteger(L, 2)+1;
    }
    lua_pushinteger(L, idx);
    return (LUA_TNONE == lua_getiuservalue(L, 1, idx)) ? 1 : 2;
}

static int
tuple__pairs(lua_State *L)
{
    lua_pushcfunction(L, tuple__next);
    lua_pushvalue(L, 1);
    lua_pushinteger(L, 0);
    return 3;
}

static struct luaL_Reg tuple_m[] = {
    //{ "__add", NULL},                     /* Append */
    //{ "__div", NULL},                     /* Remove */
    //{ "__concat", NULL},                  /* Join */
    //{ "__bor", NULL},                     /* Split */
    { "__len",      tuple__len },
    //{ "__eq", NULL},
    //{ "__lt", NULL},
    //{ "__le", NULL},
    { "__index",    tuple__index },
    //{ "__name",     NULL }, /* Requires `setfuncs` placeholder patch */
    { "__pairs",    tuple__pairs },
    { NULL, NULL }
};

LUA_API int
luaopen_tuple(lua_State *L)
{
    luaL_newlib(L, tuple_m);
    lua_pushstring(L, "tuple");
    lua_setfield(L, -2, "__name");
    lua_pushcclosure(L, constructor, 1);
    return 1;
}