lua-users home
lua-l archive

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


2012/12/15 TNHarris <telliamed@whoopdedo.org>:

>
> This makes me wish that table.insert accepted multiple values.
>
>     table.insert(t, 1, 1, 2)
>

Try the attached module.
/* xtable.c   Enhanced drop-in replacements for some table library functions
   (c) 2012 Dirk Laurie, same license as 
   Lua 5.2.1 (c) 1994-2012 Lua.org, PUC-Rio
   from which much of the code has been borrowed anyway
*/

/* compile with `cc -shared xtable.c -o xtable.so`                 */

#include <stddef.h>

#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

#define aux_getn(L,n)  \
        (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n))

/* xtable.concat(list,sep,i,j) enhancements:
 *   - respects metamethods: if sep is a string, returns the same as
 *        list[i]..sep..list[i+1]..sep.. ... sep..list[j].."" 
 *     (suggestion: if you define this __concat metamethod for strings only:
 *        getmetatable"".__concat =
 *           function(a,b) return tostring(a)..tostring(b) end
 *      then xtable.concat can concatenate anything)   
 *   - when sep is a table or a function, respectively returns the same as
 *        list[i]..sep[i+1]..list[i+1]..sep[i+2].. ... sep[j]..list[j]..""   
 *        list[i]..sep(i+1)..list[i+1]..sep(i+2).. ... sep(j)..list[j].."" 
 */
static int xconcat (lua_State *L) {
  size_t lsep;
  int i, last, n;
  luaL_checktype(L, 1, LUA_TTABLE);
  int tr = lua_type(L, 2);
  if (!lua_isnoneornil(L,2)) luaL_argcheck(L, 
    tr == LUA_TNUMBER || tr == LUA_TSTRING || tr == LUA_TFUNCTION || 
    tr == LUA_TTABLE, 2, "string/function/table expected");
  char *sep="";
  if ( tr == LUA_TNUMBER || tr == LUA_TSTRING ) 
      sep = (char *) luaL_optlstring(L, 2, "", &lsep);
  i = luaL_optint(L, 3, 1);
  last = luaL_opt(L, luaL_checkint, 4, luaL_len(L, 1));
  lua_pushstring(L,"");
  if (i>last) return 1;
  lua_checkstack(L,(last-i+1)*2);
  lua_pushinteger(L,i);
  lua_gettable(L,1);
  n=1;
  for (i++; i <= last; i++) {
    switch (tr) {
      case LUA_TFUNCTION: { 
        lua_pushvalue(L,2);  
        lua_pushinteger(L,i);
        lua_call(L,1,1);
        break;
      }
      case LUA_TTABLE: { 
        lua_pushinteger(L,i); 
        lua_gettable(L,2); 
        break; 
      } 
      default: lua_pushstring(L,sep);
    }
    lua_pushinteger(L,i);
    lua_gettable(L,1);
    n+=2;  
  }
  lua_concat(L,n);
  return 1;
}

/* xtable.insert(list,pos,...) enhancements:
 *   - accepts multiple values to be inserted
 *   - two-argument append functionality removed (yes, an enhancement)
 */
static int xinsert (lua_State *L) {
  int n = aux_getn(L, 1);  /* #list */
  int pos = luaL_checkint(L, 2); /* where to insert */
  int m = lua_gettop(L)-2; /* number of elements to be inserted */
  luaL_argcheck(L,m>2,3,"two-argument insert no longer supported");  
  int i;
  for (i = n; i >= pos; i--) {  /* move up elements */
    lua_rawgeti(L, 1, i);
    lua_rawseti(L, 1, i+m);  /* t[i+m] = t[i] */
  }
  for (i=pos+m-1; i>=pos; i--) 
     lua_rawseti(L, 1, i);  /* t[i] = v */
  return 0;
}

/* xtable.append(list,...) enhancements over table.insert(list,value):
 *   - accepts multiple values to be appended
 */
static int xappend (lua_State *L) {
  int n = aux_getn(L, 1);  /* #list */
  int m = lua_gettop(L)-1; /* number of elements to be appended */  
  int i;
  for (i=n+m; i>n; i--) 
     lua_rawseti(L, 1, i);  /* t[i] = v */
   return 0;
}

static const luaL_Reg tab_funcs[] = {
  {"concat", xconcat},
  {"insert", xinsert},
  {"append", xappend},  
  {NULL, NULL}
};

LUAMOD_API int luaopen_xtable (lua_State *L) {
  luaL_newlib(L, tab_funcs);
  return 1;
}

Attachment: test-xtable.lua
Description: Binary data