├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── appveyor.yml ├── lakeconfig.lua ├── lakefile ├── rockspecs ├── vararg-1.0-1.rockspec ├── vararg-1.1-1.rockspec ├── vararg-1.1.patch1-1.rockspec ├── vararg-1.2-1.rockspec ├── vararg-1.2-2.rockspec ├── vararg-lua-1.1.patch1-1.rockspec ├── vararg-lua-1.2-1.rockspec ├── vararg-lua-1.2-2.rockspec ├── vararg-lua-scm-0.rockspec └── vararg-scm-0.rockspec ├── test ├── .luacov └── test.lua ├── vararg.c └── vararg.lua /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: c 3 | 4 | python: 5 | - "2.7" 6 | 7 | sudo: false 8 | 9 | env: 10 | global: 11 | - LVA_CC_FLAGS="-O2 -fPIC -ftest-coverage -fprofile-arcs" 12 | - LVA_LD_FLAGS="-shared --coverage" 13 | 14 | matrix: 15 | include: 16 | - env: LUA="lua 5.1" VARARG=vararg 17 | os: osx 18 | - env: LUA="lua 5.1" VARARG=vararg 19 | os: linux 20 | - env: LUA="lua 5.2" VARARG=vararg 21 | os: linux 22 | - env: LUA="lua 5.3" VARARG=vararg 23 | os: linux 24 | - env: LUA="lua 5.4" VARARG=vararg 25 | os: linux 26 | - env: LUA="luajit 2.0" VARARG=vararg 27 | os: linux 28 | - env: LUA="luajit 2.1" VARARG=vararg 29 | os: linux 30 | - env: LUA="lua 5.1" VARARG=vararg-lua 31 | os: linux 32 | - env: LUA="lua 5.2" VARARG=vararg-lua 33 | os: linux 34 | - env: LUA="lua 5.3" VARARG=vararg-lua 35 | os: linux 36 | - env: LUA="lua 5.4" VARARG=vararg-lua 37 | os: linux 38 | - env: LUA="luajit 2.0" VARARG=vararg-lua 39 | os: linux 40 | - env: LUA="luajit 2.1" VARARG=vararg-lua 41 | os: linux 42 | 43 | cache: 44 | directories: 45 | - here 46 | - $HOME/.cache/pip 47 | 48 | branches: 49 | only: 50 | - master 51 | - curl_mime 52 | 53 | before_install: 54 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export PATH=$PATH:~/Library/Python/2.7/bin/; fi 55 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export LVA_LD_FLAGS="-bundle -undefined dynamic_lookup -all_load --coverage"; fi 56 | - pip2 install --user cpp-coveralls 57 | - pip2 install --user hererocks 58 | - hererocks here -r^ --$LUA 59 | - source here/bin/activate 60 | 61 | install: 62 | - luarocks make rockspecs/$VARARG-scm-0.rockspec CFLAGS="$LVA_CC_FLAGS" LIBFLAG="$LVA_LD_FLAGS" 63 | 64 | before_script: 65 | - luarocks show luacov > /dev/null 2>&1 || luarocks install luacov 66 | 67 | script: 68 | - cd test 69 | - lua -lluacov test.lua 70 | 71 | after_success: 72 | - luarocks show luafilesystem > /dev/null 2>&1 || luarocks install luafilesystem 73 | - luarocks show lua-path > /dev/null 2>&1 || luarocks install lua-path 74 | - luarocks show lua-curl > /dev/null 2>&1 || luarocks install lua-curl 75 | - luarocks show luacov-coveralls > /dev/null 2>&1 || luarocks install luacov-coveralls 76 | - if [ $VARARG = "vararg" ]; then 77 | cd $TRAVIS_BUILD_DIR; 78 | coveralls -i vararg.c; 79 | else 80 | luacov-coveralls; 81 | fi 82 | 83 | notifications: 84 | email: 85 | on_success: change 86 | on_failure: always 87 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2010-2011 Tecgraf, PUC-Rio. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= 2 | 3 | LUA_HOME= /usr/local 4 | LUA_INC= $(LUA_HOME)/include 5 | LUA_LIB= $(LUA_HOME)/lib 6 | LUA_BIN= $(LUA_HOME)/bin 7 | 8 | # Your platform. See PLATS for possible values. 9 | PLAT= none 10 | 11 | CC= gcc 12 | CFLAGS= -O2 -Wall -I$(LUA_INC) $(MYCFLAGS) 13 | LDFLAGS= -L$(LUA_LIB) $(MYLDFLAGS) 14 | LIBS= $(MYLIBS) 15 | 16 | AR= ar rcu 17 | RANLIB= ranlib 18 | RM= rm -f 19 | 20 | MYCFLAGS= 21 | MYLDFLAGS= 22 | MYLIBS= 23 | 24 | # == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE ======= 25 | 26 | PLATS= linux solaris macosx 27 | 28 | LIBNAME= vararg 29 | 30 | OBJ= vararg.o 31 | LIB= lib$(LIBNAME).a 32 | SO= lib$(LIBNAME).so 33 | 34 | default: $(PLAT) 35 | 36 | all: a so 37 | 38 | o: $(OBJ) 39 | 40 | a: $(LIB) 41 | 42 | so: $(SO) 43 | 44 | # Static Libraies 45 | 46 | $(LIB): $(OBJ) 47 | $(AR) $@ $? 48 | $(RANLIB) $@ 49 | 50 | # Dynamic Libraies 51 | 52 | $(SO): $(OBJ) 53 | $(LD) $(LDFLAGS) -o $@ $? 54 | 55 | clean: 56 | $(RM) $(OBJ) $(LIB) $(SO) 57 | 58 | echo: 59 | @echo "CC = $(CC)" 60 | @echo "CFLAGS = $(CFLAGS)" 61 | @echo "AR = $(AR)" 62 | @echo "RANLIB = $(RANLIB)" 63 | @echo "RM = $(RM)" 64 | @echo "MYCFLAGS = $(MYCFLAGS)" 65 | @echo "MYLDFLAGS = $(MYLDFLAGS)" 66 | @echo "MYLIBS = $(MYLIBS)" 67 | 68 | # Convenience targets for usual platforms 69 | ALL= all 70 | 71 | none: 72 | @echo "Please do 'make PLATFORM' where PLATFORM is one of these:" 73 | @echo " $(PLATS)" 74 | 75 | linux: 76 | $(MAKE) $(ALL) LD="gcc" MYCFLAGS="-fpic $(MYCFLAGS)" \ 77 | MYLDFLAGS="-Wl,-E -O -shared $(MYLDFLAGS)" 78 | 79 | solaris: 80 | $(MAKE) $(ALL) LD="gcc" MYCFLAGS="-fpic $(MYCFLAGS)" \ 81 | MYLDFLAGS="-O -shared $(MYLDFLAGS)" 82 | 83 | macosx: 84 | $(MAKE) $(ALL) MYCFLAGS="-fno-common $(MYCFLAGS)" \ 85 | MYLDFLAGS="-bundle -undefined dynamic_lookup $(MYLDFLAGS)" \ 86 | LD='export MACOSX_DEPLOYMENT_TARGET="10.3"; gcc' 87 | 88 | # (end of Makefile) 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Unofficial repositary of [vararg](http://www.tecgraf.puc-rio.br/~maia/lua/vararg) 2 | [![Licence](http://img.shields.io/badge/Licence-MIT-brightgreen.svg)](LICENSE) 3 | [![Build Status](https://travis-ci.org/moteus/lua-vararg.png?branch=master)](https://travis-ci.org/moteus/lua-vararg) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/8lo89111mnndhdmx?svg=true)](https://ci.appveyor.com/project/moteus/lua-vararg) 5 | [![Coverage Status](https://coveralls.io/repos/moteus/lua-vararg/badge.png?branch=master)](https://coveralls.io/r/moteus/lua-vararg?branch=master) 6 | 7 | `vararg` is a Lua library for manipulation of variable arguements (vararg) of 8 | functions. These functions basically allow you to do things with vararg that 9 | cannot be efficiently done in pure Lua but can be easily done through the C API. 10 | 11 | Actually, the main motivation for this library was the 'pack' function, which 12 | is an elegant alternative for the possible new standard function 'table.pack' 13 | and the praised 'apairs'. Also 'pack' allows an interesting implementaiton of 14 | tuples in pure Lua. 15 | 16 | ## Changes since official `vararg` v1.1 17 | 18 | * C version supports Lua 5.2/5.3 19 | * Fix bugs on Lua version. Now it pass all tests. 20 | * Lua and C version are fully compatible (excapt error messages). 21 | * Use call metamethod as alias for pack method (`vararg(...)` is same as `vararg.pack(...)`) 22 | * Add `va.count` function 23 | * Add `va.at` function 24 | 25 | ## pack 26 | 27 | `args = pack(...)` 28 | 29 | | vararg | lua | 30 | |---------------------|---------------------------| 31 | | args() | ... | 32 | | args("#") | select("#", ...) | 33 | | args(i) | (select(i, ...)) | 34 | | args(i, j) | unpack({...}, i, j) | 35 | | for i,v in args do | for i,v in ipairs{...} do | 36 | 37 | ## vararg methods 38 | 39 | Assume this shortcuts 40 | ```lua 41 | tremove = function(t, i) table.remove(t, i) return t end 42 | tinsert = function(t, i, v) table.insert(t, i, v) return t end 43 | tset = function(t, i, v) t[i] = v return t end 44 | tappend = function(t, v) t[#t+1] = v return t end 45 | ``` 46 | 47 | | vararg | lua | 48 | |--------------------|----------------------------------------------------------| 49 | | count(...) | select("#", ...) | 50 | | range(i, j, ...) | unpack({...}, i, j) | 51 | | at(i, ...) | range(i, i, ...) | 52 | | remove(i, ...) | unpack(tremove({...},i),1,count(...)-1) | 53 | | insert(v, i, ...) | unpack(tinsert({...},i,v),1,count(...)+1) | 54 | | replace(v, i, ...) | unpack(tset({...}, i, v) t,1,count(...)) | 55 | | append(v, ...) | unpack(tappend({...},v),1,count(...)+1) | 56 | | map(f, ...) | t={} for i, arg in pack(...) do t[i]=f(arg) end unpack(t)| 57 | | concat(f1,f2,...) | return all the values returned by functions 'f1,f2,...' | 58 | 59 | ## Examples 60 | 61 | Implement basic `bind` function 62 | 63 | ```Lua 64 | function bind(f, ...) 65 | local args = va(...) 66 | return function(...) 67 | return f(va.concat(args, va(...)) 68 | end 69 | end 70 | debug_print = bint(print, '[debug]') 71 | debug_print('hello') 72 | ``` 73 | 74 | Pack in to array returned values from several functions 75 | 76 | ```Lua 77 | function f(...) return ... end 78 | 79 | t = {va.concat( 80 | va(f(1,2,3)), 81 | va(f(4,5,6)), 82 | )} 83 | 84 | -- t = {1,2,3,4,5,6} 85 | ``` 86 | 87 | Write to stdout but convert values to string. 88 | ```Lua 89 | function write(...) 90 | return io.write(va.map(tostring, ...)) 91 | end 92 | 93 | local hello = setmetatable({},{__tostring = function() return "Hello" end}) 94 | 95 | write(hello, " world!!! ", nil, '\n') 96 | ``` 97 | 98 | Parse IPv4 address 99 | ```Lua 100 | local n1,n2,n3,n4 = va.map(tonumber, string.match(ip, "^(%d+)%.(%d+)%.(%d+)%.(%d+)$")) 101 | -- test nX as number 102 | ``` 103 | 104 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.1.2.{build} 2 | 3 | environment: 4 | matrix: 5 | - LUA: "lua 5.1" 6 | VARARG: vararg 7 | - LUA: "lua 5.1" 8 | VARARG: vararg-lua 9 | - LUA: "lua 5.2" 10 | VARARG: vararg 11 | - LUA: "lua 5.2" 12 | VARARG: vararg-lua 13 | - LUA: "lua 5.3" 14 | VARARG: vararg 15 | - LUA: "lua 5.3" 16 | VARARG: vararg-lua 17 | - LUA: "lua 5.4" 18 | VARARG: vararg 19 | - LUA: "lua 5.4" 20 | VARARG: vararg-lua 21 | 22 | platform: 23 | - x64 24 | # - x86 25 | - mingw 26 | 27 | matrix: 28 | allow_failures: 29 | - platform: mingw 30 | 31 | cache: 32 | - c:\hererocks -> appveyor.yml 33 | - c:\external -> appveyor.yml 34 | 35 | before_build: 36 | - set PATH=C:\Python27\Scripts;%PATH% 37 | - pip install hererocks 38 | - if /I "%platform%"=="x86" set HR_TARGET=vs_32 39 | - if /I "%platform%"=="x64" set HR_TARGET=vs_64 40 | - if /I "%platform%"=="mingw" set HR_TARGET=mingw 41 | - if /I "%platform%"=="mingw" set PATH=C:\MinGW\bin;%PATH% 42 | - hererocks env --%LUA% --target %HR_TARGET% -rlatest 43 | - call env\bin\activate 44 | 45 | build_script: 46 | - luarocks make rockspecs/%VARARG%-scm-0.rockspec 47 | 48 | before_test: 49 | # - luarocks show luafilesystem > nul 2>&1 || luarocks install luafilesystem 50 | # - luarocks show lua-path > nul 2>&1 || luarocks install lua-path 51 | # - luarocks show lua-curl > nul 2>&1 || luarocks install lua-curl 52 | # - luarocks show luacov-coveralls > nul 2>&1 || luarocks install luacov-coveralls 53 | 54 | test_script: 55 | - cd test 56 | - lua test.lua 57 | -------------------------------------------------------------------------------- /lakeconfig.lua: -------------------------------------------------------------------------------- 1 | function vc_version() 2 | local VER = lake.compiler_version() 3 | MSVC_VER = ({ 4 | [15] = '9'; 5 | [16] = '10'; 6 | })[VER.MAJOR] or '' 7 | return MSVC_VER 8 | end 9 | 10 | local function arkey(t) 11 | assert(type(t) == 'table') 12 | local keys = {} 13 | for k in pairs(t) do 14 | assert(type(k) == 'number') 15 | table.insert(keys, k) 16 | end 17 | table.sort(keys) 18 | return keys 19 | end 20 | 21 | local function ikeys(t) 22 | local keys = arkey(t) 23 | local i = 0 24 | return function() 25 | i = i + 1 26 | local k = keys[i] 27 | if k == nil then return end 28 | return k, t[k] 29 | end 30 | end 31 | 32 | local function expand(arr, t) 33 | if t == nil then return arr end 34 | 35 | if type(t) ~= 'table' then 36 | table.insert(arr, t) 37 | return arr 38 | end 39 | 40 | for _, v in ikeys(t) do 41 | expand(arr, v) 42 | end 43 | 44 | return arr 45 | end 46 | 47 | function L(...) 48 | return expand({}, {...}) 49 | end 50 | 51 | J = J or path.join 52 | 53 | IF = IF or lake.choose or choose 54 | 55 | function prequire(...) 56 | local ok, mod = pcall(require, ...) 57 | if ok then return mod end 58 | end 59 | 60 | function each_join(dir, list) 61 | for i, v in ipairs(list) do 62 | list[i] = path.join(dir, v) 63 | end 64 | return list 65 | end 66 | 67 | function run(file, cwd) 68 | print() 69 | print("run " .. file) 70 | if not TESTING then 71 | if cwd then lake.chdir(cwd) end 72 | local status, code = utils.execute( LUA_RUNNER .. ' ' .. file ) 73 | if cwd then lake.chdir("<") end 74 | print() 75 | return status, code 76 | end 77 | return true, 0 78 | end 79 | 80 | function run_test(name, params) 81 | local test_dir = J(ROOT, 'test') 82 | local cmd = J(test_dir, name) 83 | if params then cmd = cmd .. ' ' .. params end 84 | local ok = run(cmd, test_dir) 85 | print("TEST " .. cmd .. (ok and ' - pass!' or ' - fail!')) 86 | end 87 | 88 | function spawn(file, cwd) 89 | local winapi = prequire "winapi" 90 | if not winapi then 91 | print(file, ' error: Test needs winapi!') 92 | return false 93 | end 94 | print("spawn " .. file) 95 | if not TESTING then 96 | if cwd then lake.chdir(cwd) end 97 | assert(winapi.shell_exec(nil, LUA_RUNNER, file, cwd)) 98 | if cwd then lake.chdir("<") end 99 | print() 100 | end 101 | return true 102 | end 103 | 104 | function as_bool(v,d) 105 | if v == nil then return not not d end 106 | local n = tonumber(v) 107 | if n == 0 then return false end 108 | if n then return true end 109 | return false 110 | end 111 | 112 | ----------------------- 113 | -- needs -- 114 | ----------------------- 115 | 116 | lake.define_need('lua53', function() 117 | return { 118 | incdir = J(ENV.LUA_DIR_5_3, 'include'); 119 | libdir = J(ENV.LUA_DIR_5_3, 'lib'); 120 | libs = {'lua53'}; 121 | } 122 | end) 123 | 124 | lake.define_need('lua52', function() 125 | return { 126 | incdir = J(ENV.LUA_DIR_5_2, 'include'); 127 | libdir = J(ENV.LUA_DIR_5_2, 'lib'); 128 | libs = {'lua52'}; 129 | } 130 | end) 131 | 132 | lake.define_need('lua51', function() 133 | return { 134 | incdir = J(ENV.LUA_DIR, 'include'); 135 | libdir = J(ENV.LUA_DIR, 'lib'); 136 | libs = {'lua5.1'}; 137 | } 138 | end) -------------------------------------------------------------------------------- /lakefile: -------------------------------------------------------------------------------- 1 | PROJECT = 'vararg' 2 | 3 | if LUA_VER == '5.3' then 4 | LUA_NEED = 'lua53' 5 | LUA_DIR = ENV.LUA_DIR_5_3 or ENV.LUA_DIR 6 | LUA_RUNNER = 'lua53' 7 | elseif LUA_VER == '5.2' then 8 | LUA_NEED = 'lua52' 9 | LUA_DIR = ENV.LUA_DIR_5_2 or ENV.LUA_DIR 10 | LUA_RUNNER = 'lua52' 11 | else 12 | LUA_NEED = 'lua51' 13 | LUA_DIR = ENV.LUA_DIR 14 | LUA_RUNNER = 'lua' 15 | end 16 | 17 | ROOT = ROOT or J(LUA_DIR,'libs',PROJECT) 18 | LUADIR = LUADIR or J(ROOT, 'share') 19 | LIBDIR = LIBDIR or J(ROOT, 'share') 20 | DYNAMIC = as_bool(DYNAMIC, false) 21 | 22 | vararg = c.shared{PROJECT, 23 | base = '.'; 24 | src = {PROJECT .. '.c'}; 25 | needs = {LUA_NEED}; 26 | dynamic = DYNAMIC; 27 | strip = true; 28 | libflags = {IF(MSVC, '/EXPORT:luaopen_' .. PROJECT)}; 29 | } 30 | 31 | target('build', vararg) 32 | 33 | install = target('install', { 34 | file.group{odir=LIBDIR; src = vararg }; 35 | file.group{odir=J(ROOT, 'test'); src = J('test', 'test.lua') }; 36 | }) 37 | 38 | target('test', install, function() 39 | run_test("test.lua") 40 | end) 41 | 42 | default('build') 43 | -------------------------------------------------------------------------------- /rockspecs/vararg-1.0-1.rockspec: -------------------------------------------------------------------------------- 1 | package="vararg" 2 | version="1.0-1" 3 | source = { 4 | url = "https://github.com/moteus/lua-vararg/archive/v1.0.zip", 5 | dir = "lua-vararg-1.0", 6 | } 7 | description = { 8 | summary = "Manipulation of variable arguments", 9 | detailed = [[ 10 | 'vararg' is a Lua library for manipulation of variable arguments (vararg) of 11 | functions. These functions basically allows you to do things with vararg that 12 | cannot be efficiently done in pure Lua, but can be easily done through the C API. 13 | ]], 14 | homepage = "http://www.tecgraf.puc-rio.br/~maia/lua/vararg/", 15 | license = "MIT/X11" 16 | } 17 | dependencies = { 18 | "lua >= 5.1" 19 | } 20 | 21 | build = { 22 | copy_directories = {}, 23 | type = "builtin", 24 | modules = { 25 | vararg = { 26 | sources = "vararg.c", 27 | }, 28 | }, 29 | } 30 | -------------------------------------------------------------------------------- /rockspecs/vararg-1.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package="vararg" 2 | version="1.1-1" 3 | source = { 4 | url = "https://github.com/moteus/lua-vararg/archive/v1.1.zip", 5 | dir = "lua-vararg-1.1", 6 | } 7 | description = { 8 | summary = "Manipulation of variable arguments", 9 | detailed = [[ 10 | 'vararg' is a Lua library for manipulation of variable arguments (vararg) of 11 | functions. These functions basically allows you to do things with vararg that 12 | cannot be efficiently done in pure Lua, but can be easily done through the C API. 13 | ]], 14 | homepage = "http://www.tecgraf.puc-rio.br/~maia/lua/vararg/", 15 | license = "MIT/X11" 16 | } 17 | dependencies = { 18 | "lua >= 5.1" 19 | } 20 | 21 | build = { 22 | copy_directories = {}, 23 | type = "builtin", 24 | modules = { 25 | vararg = { 26 | sources = "vararg.c", 27 | }, 28 | }, 29 | } 30 | -------------------------------------------------------------------------------- /rockspecs/vararg-1.1.patch1-1.rockspec: -------------------------------------------------------------------------------- 1 | package="vararg" 2 | version="1.1.patch1-1" 3 | source = { 4 | url = "https://github.com/moteus/lua-vararg/archive/v1.1.patch1.zip", 5 | dir = "lua-vararg-1.1.patch1", 6 | } 7 | description = { 8 | summary = "Manipulation of variable arguments", 9 | detailed = [[ 10 | 'vararg' is a Lua library for manipulation of variable arguments (vararg) of 11 | functions. These functions basically allows you to do things with vararg that 12 | cannot be efficiently done in pure Lua, but can be easily done through the C API. 13 | ]], 14 | homepage = "http://www.tecgraf.puc-rio.br/~maia/lua/vararg/", 15 | license = "MIT/X11" 16 | } 17 | dependencies = { 18 | "lua >= 5.1, < 5.3" 19 | } 20 | 21 | build = { 22 | copy_directories = {}, 23 | type = "builtin", 24 | modules = { 25 | vararg = "vararg.c" 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /rockspecs/vararg-1.2-1.rockspec: -------------------------------------------------------------------------------- 1 | package="vararg" 2 | version="1.2-1" 3 | 4 | source = { 5 | url = "https://github.com/moteus/lua-vararg/archive/v1.2.zip", 6 | dir = "lua-vararg-1.2", 7 | } 8 | 9 | description = { 10 | summary = "Manipulation of variable arguments", 11 | detailed = [[ 12 | 'vararg' is a Lua library for manipulation of variable arguments (vararg) of 13 | functions. These functions basically allows you to do things with vararg that 14 | cannot be efficiently done in pure Lua, but can be easily done through the C API. 15 | ]], 16 | homepage = "http://www.tecgraf.puc-rio.br/~maia/lua/vararg/", 17 | license = "MIT/X11" 18 | } 19 | 20 | dependencies = { 21 | "lua >= 5.1, < 5.4" 22 | } 23 | 24 | build = { 25 | copy_directories = {"test"}, 26 | type = "builtin", 27 | modules = { 28 | vararg = "vararg.c" 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /rockspecs/vararg-1.2-2.rockspec: -------------------------------------------------------------------------------- 1 | package="vararg" 2 | version="1.2-2" 3 | 4 | source = { 5 | url = "https://github.com/moteus/lua-vararg/archive/v1.2.zip", 6 | dir = "lua-vararg-1.2", 7 | } 8 | 9 | description = { 10 | summary = "Manipulation of variable arguments", 11 | detailed = [[ 12 | 'vararg' is a Lua library for manipulation of variable arguments (vararg) of 13 | functions. These functions basically allows you to do things with vararg that 14 | cannot be efficiently done in pure Lua, but can be easily done through the C API. 15 | ]], 16 | homepage = "http://www.tecgraf.puc-rio.br/~maia/lua/vararg/", 17 | license = "MIT/X11" 18 | } 19 | 20 | dependencies = { 21 | "lua >= 5.1, < 5.5" 22 | } 23 | 24 | build = { 25 | copy_directories = {"test"}, 26 | type = "builtin", 27 | modules = { 28 | vararg = "vararg.c" 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /rockspecs/vararg-lua-1.1.patch1-1.rockspec: -------------------------------------------------------------------------------- 1 | package="vararg-lua" 2 | version="1.1.patch1-1" 3 | source = { 4 | url = "https://github.com/moteus/lua-vararg/archive/v1.1.patch1.zip", 5 | dir = "lua-vararg-1.1.patch1", 6 | } 7 | description = { 8 | summary = "Manipulation of variable arguments", 9 | detailed = [[ 10 | 'vararg' is a Lua library for manipulation of variable arguments (vararg) of 11 | functions. These functions basically allows you to do things with vararg that 12 | cannot be efficiently done in pure Lua, but can be easily done through the C API. 13 | ]], 14 | homepage = "http://www.tecgraf.puc-rio.br/~maia/lua/vararg/", 15 | license = "MIT/X11" 16 | } 17 | dependencies = { 18 | "lua >= 5.1, < 5.3" 19 | } 20 | 21 | build = { 22 | copy_directories = {}, 23 | type = "builtin", 24 | modules = { 25 | vararg = "vararg.lua", 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /rockspecs/vararg-lua-1.2-1.rockspec: -------------------------------------------------------------------------------- 1 | package="vararg-lua" 2 | version="1.2-1" 3 | source = { 4 | url = "https://github.com/moteus/lua-vararg/archive/v1.2.zip", 5 | dir = "lua-vararg-1.2", 6 | } 7 | description = { 8 | summary = "Manipulation of variable arguments", 9 | detailed = [[ 10 | 'vararg' is a Lua library for manipulation of variable arguments (vararg) of 11 | functions. These functions basically allows you to do things with vararg that 12 | cannot be efficiently done in pure Lua, but can be easily done through the C API. 13 | ]], 14 | homepage = "http://www.tecgraf.puc-rio.br/~maia/lua/vararg/", 15 | license = "MIT/X11" 16 | } 17 | dependencies = { 18 | "lua >= 5.1, < 5.4" 19 | } 20 | 21 | build = { 22 | copy_directories = {"test"}, 23 | type = "builtin", 24 | modules = { 25 | vararg = "vararg.lua", 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /rockspecs/vararg-lua-1.2-2.rockspec: -------------------------------------------------------------------------------- 1 | package="vararg-lua" 2 | version="1.2-2" 3 | source = { 4 | url = "https://github.com/moteus/lua-vararg/archive/v1.2.zip", 5 | dir = "lua-vararg-1.2", 6 | } 7 | description = { 8 | summary = "Manipulation of variable arguments", 9 | detailed = [[ 10 | 'vararg' is a Lua library for manipulation of variable arguments (vararg) of 11 | functions. These functions basically allows you to do things with vararg that 12 | cannot be efficiently done in pure Lua, but can be easily done through the C API. 13 | ]], 14 | homepage = "http://www.tecgraf.puc-rio.br/~maia/lua/vararg/", 15 | license = "MIT/X11" 16 | } 17 | dependencies = { 18 | "lua >= 5.1, < 5.5" 19 | } 20 | 21 | build = { 22 | copy_directories = {"test"}, 23 | type = "builtin", 24 | modules = { 25 | vararg = "vararg.lua", 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /rockspecs/vararg-lua-scm-0.rockspec: -------------------------------------------------------------------------------- 1 | package="vararg-lua" 2 | version="scm-0" 3 | source = { 4 | url = "https://github.com/moteus/lua-vararg/archive/master.zip", 5 | dir = "lua-vararg-master", 6 | } 7 | description = { 8 | summary = "Manipulation of variable arguments", 9 | detailed = [[ 10 | 'vararg' is a Lua library for manipulation of variable arguments (vararg) of 11 | functions. These functions basically allows you to do things with vararg that 12 | cannot be efficiently done in pure Lua, but can be easily done through the C API. 13 | ]], 14 | homepage = "http://www.tecgraf.puc-rio.br/~maia/lua/vararg/", 15 | license = "MIT/X11" 16 | } 17 | dependencies = { 18 | "lua >= 5.1, < 5.5" 19 | } 20 | 21 | build = { 22 | copy_directories = {}, 23 | type = "builtin", 24 | modules = { 25 | vararg = "vararg.lua", 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /rockspecs/vararg-scm-0.rockspec: -------------------------------------------------------------------------------- 1 | package="vararg" 2 | version="scm-0" 3 | source = { 4 | url = "https://github.com/moteus/lua-vararg/archive/master.zip", 5 | dir = "lua-vararg-master", 6 | } 7 | description = { 8 | summary = "Manipulation of variable arguments", 9 | detailed = [[ 10 | 'vararg' is a Lua library for manipulation of variable arguments (vararg) of 11 | functions. These functions basically allows you to do things with vararg that 12 | cannot be efficiently done in pure Lua, but can be easily done through the C API. 13 | ]], 14 | homepage = "http://www.tecgraf.puc-rio.br/~maia/lua/vararg/", 15 | license = "MIT/X11" 16 | } 17 | dependencies = { 18 | "lua >= 5.1, < 5.5" 19 | } 20 | 21 | build = { 22 | copy_directories = {"test"}, 23 | type = "builtin", 24 | modules = { 25 | vararg = "vararg.c" 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /test/.luacov: -------------------------------------------------------------------------------- 1 | --- Global configuration file. Copy, customize and store in your 2 | -- project folder as '.luacov' for project specific configuration 3 | -- @class module 4 | -- @name luacov.defaults 5 | return { 6 | 7 | -- default filename to load for config options if not provided 8 | -- only has effect in 'luacov.defaults.lua' 9 | ["configfile"] = ".luacov", 10 | 11 | -- filename to store stats collected 12 | ["statsfile"] = "luacov.stats.out", 13 | 14 | -- filename to store report 15 | ["reportfile"] = "luacov.report.json", 16 | 17 | -- Run reporter on completion? (won't work for ticks) 18 | runreport = false, 19 | 20 | -- Delete stats file after reporting? 21 | deletestats = false, 22 | 23 | -- Patterns for files to include when reporting 24 | -- all will be included if nothing is listed 25 | -- (exclude overrules include, do not include 26 | -- the .lua extension) 27 | ["include"] = { 28 | "/vararg$", 29 | }, 30 | 31 | -- Patterns for files to exclude when reporting 32 | -- all will be included if nothing is listed 33 | -- (exclude overrules include, do not include 34 | -- the .lua extension) 35 | ["exclude"] = { 36 | }, 37 | 38 | -- configuration for luacov-coveralls reporter 39 | ["coveralls"] = { 40 | 41 | ["debug"] = true, 42 | 43 | ["pathcorrect"] = { 44 | {"/usr/local/share/lua/5.%d", ""}; 45 | }, 46 | 47 | }, 48 | 49 | } 50 | -------------------------------------------------------------------------------- /test/test.lua: -------------------------------------------------------------------------------- 1 | local _G = require "_G" 2 | local assert = _G.assert 3 | local pcall = _G.pcall 4 | local print = _G.print 5 | local select = _G.select 6 | local type = _G.type 7 | 8 | local math = require "math" 9 | local ceil = math.ceil 10 | local huge = math.huge 11 | local min = math.min 12 | 13 | local table = require "table" 14 | local unpack = table.unpack or _G.unpack 15 | 16 | local vararg = require "vararg" 17 | local pack = vararg.pack 18 | local range = vararg.range 19 | local insert = vararg.insert 20 | local remove = vararg.remove 21 | local replace = vararg.replace 22 | local append = vararg.append 23 | local concat = vararg.concat 24 | local map = vararg.map 25 | local count = vararg.count 26 | local at = vararg.at 27 | 28 | local LUA_VER_MAJ, LUA_VER_MIN = string.match(_VERSION, "(%d+)%.(%d+)") 29 | local LUA_VER = LUA_VER_MAJ * 100 + LUA_VER_MIN 30 | 31 | -- auxiliary functions---------------------------------------------------------- 32 | 33 | local values = {} 34 | local maxstack 35 | for i = 1, huge do 36 | if not pcall(unpack, values, 1, 2^i) then 37 | local min, max = 2^(i-1), 2^i 38 | while min < max do 39 | local mid = ceil((min+max)/2) 40 | if pcall(unpack, values, 1, mid) then 41 | min = mid 42 | else 43 | max = mid-1 44 | end 45 | end 46 | maxstack = max 47 | break 48 | end 49 | end 50 | 51 | -- @fixme Lua 5.2 incorrect calculate maxstack 52 | if maxstack > 255 then maxstack = 255 end 53 | 54 | for i = 1, maxstack, 2 do 55 | values[i] = i 56 | end 57 | 58 | local function tpack(...) 59 | return {..., n=select("#", ...)} 60 | end 61 | 62 | local function assertsame(v, i, j, ...) 63 | local count = select("#", ...) 64 | assert(count == j-i+1, count..","..i..","..j) 65 | for pos = 1, count do 66 | assert(v[i+pos-1] == select(pos, ...)) 67 | end 68 | end 69 | 70 | local function asserterror(expected, f, ...) 71 | local ok, actual = pcall(f, ...) 72 | assert(ok == false, "error was expected") 73 | if os.getenv("VARARG") ~= "vararg-lua" then 74 | if LUA_VER >= 503 then 75 | -- Lua 5.3 pass function names instead question mark 76 | expected = string.gsub(expected, "'%?'", "'.-'") 77 | expected = string.gsub(expected, "([%(%)])", "%%%1") 78 | assert(actual:find(expected), "wrong error, got "..actual) 79 | else 80 | assert(actual:find(expected, 1, true), "wrong error, got "..actual) 81 | end 82 | end 83 | end 84 | 85 | -- test 'pack' function -------------------------------------------------------- 86 | 87 | local function make_testpack(pack) return function (...) 88 | local v = {...} 89 | local n = select("#", ...) 90 | local p = pack(...) 91 | assertsame(v, 1, n, p()) 92 | assert(n == p("#")) 93 | for i,pv in p do assert(v[i] == pv) end 94 | for i = 1, n do 95 | assert(v[i] == p(i)) 96 | if n > 0 then 97 | assert(v[i] == p(i-n-1)) 98 | end 99 | end 100 | for i = 1, n, 10 do 101 | local j = i+9 102 | assertsame(v, i, j, p(i, j)) 103 | if n > j then 104 | assertsame(v, i, j, p(i-n-1, j-n-1)) 105 | end 106 | end 107 | end end 108 | 109 | make_testpack(pack)() 110 | make_testpack(pack)({},{},{}) 111 | make_testpack(pack)(nil) 112 | make_testpack(pack)(nil, nil) 113 | make_testpack(pack)(nil, 1, nil) 114 | make_testpack(pack)(unpack(values, 1, 254)) 115 | 116 | make_testpack(vararg)() 117 | make_testpack(vararg)({},{},{}) 118 | make_testpack(vararg)(nil) 119 | make_testpack(vararg)(nil, nil) 120 | make_testpack(vararg)(nil, 1, nil) 121 | make_testpack(vararg)(unpack(values, 1, 254)) 122 | 123 | local ok, err = pcall(pack, unpack(values, 1, 255)) 124 | if ok then -- Lua version 125 | assert(type(err) == "function") 126 | else -- C version 127 | assert(ok == false and err == "too many values to pack") 128 | end 129 | 130 | -- test 'range' function ------------------------------------------------------- 131 | 132 | local function testrange(n, ...) 133 | local v = {...} 134 | for c = 1, 3 do 135 | for i = 1, n, c do 136 | local j = min(i+c-1, n) 137 | assertsame(v, i, j, range(i, j, ...)) 138 | local n = select("#", ...) 139 | if n > 0 then 140 | assertsame(v, i, j, range(i-n-1, j-n-1, ...)) 141 | end 142 | end 143 | end 144 | end 145 | 146 | asserterror("bad argument #1 to '?' (index out of bounds)", range, 0, 0, 1,2,3) 147 | 148 | testrange(10) 149 | testrange(10, 1,2,3,4,5,6,7,8,9,0) 150 | testrange(maxstack, unpack(values, 1, maxstack)) 151 | 152 | assertsame({}, 1, 1, range(1, 1)) 153 | 154 | assertsame({}, 0, -1, range(2, 1)) 155 | 156 | -- test other functions -------------------------------------------------------- 157 | 158 | assertsame({1,2,3,4,5}, 1, 5, insert(3, 3, 1,2,4,5)) 159 | assertsame({1,2,3,4,5}, 1, 5, insert(4,-1, 1,2,3,5)) 160 | assertsame({1,2,nil,4}, 1, 4, insert(4, 4, 1,2)) 161 | assertsame({nil,nil,3}, 1, 3, insert(3, 3)) 162 | 163 | assertsame({1,2,3,4,5}, 1, 5, replace(3, 3, 1,2,0,4,5)) 164 | assertsame({1,2,3,4,5}, 1, 5, replace(5,-1, 1,2,3,4,0)) 165 | assertsame({1,2,nil,4}, 1, 4, replace(4, 4, 1,2)) 166 | assertsame({nil,nil,3}, 1, 3, replace(3, 3)) 167 | 168 | assertsame({1,2,3,4,5}, 1, 5, remove( 3, 1,2,0,3,4,5)) 169 | assertsame({1,2,3,4,5}, 1, 5, remove(-1, 1,2,3,4,5,0)) 170 | assertsame({1,2,nil,4}, 1, 4, remove( 4, 1,2,nil,0,4)) 171 | assertsame({nil,nil,3}, 1, 3, remove( 3, nil,nil,0,3)) 172 | assertsame({1,2,3,4,5}, 1, 5, remove(10, 1,2,3,4,5)) 173 | 174 | assertsame({1,2,3,4,5}, 1, 5, append(5, 1,2,3,4)) 175 | assertsame({1,2,nil,4}, 1, 4, append(4, 1,2,nil)) 176 | assertsame({nil,nil,3}, 1, 3, append(3, nil,nil)) 177 | 178 | assertsame({1,2,3,4,5,6,7,8,9}, 1, 9, concat(pack(1,2,3), 179 | pack(4,5,6), 180 | pack(7,8,9))) 181 | 182 | -- test function errors and expectional conditions --------------------------- 183 | 184 | assertsame({"1","2","3","4","5"}, 1, 5, map(tostring, 1,2,3,4,5)) 185 | assertsame({"1","2","nil","4" }, 1, 4, map(tostring, 1,2,nil,4)) 186 | assertsame({"nil","nil","3" }, 1, 3, map(tostring, nil,nil,3)) 187 | assertsame({"1","nil","nil" }, 1, 3, map(tostring, 1,nil,nil)) 188 | 189 | asserterror("bad argument #2 to '?' (number expected, got no value)", insert) 190 | asserterror("bad argument #2 to '?' (number expected, got no value)", insert, nil) 191 | asserterror("bad argument #2 to '?' (number expected, got nil)", insert, nil, nil) 192 | asserterror("bad argument #2 to '?' (index out of bounds)", insert, nil, 0) 193 | 194 | asserterror("bad argument #2 to '?' (number expected, got no value)", replace) 195 | asserterror("bad argument #2 to '?' (number expected, got no value)", replace, nil) 196 | asserterror("bad argument #2 to '?' (number expected, got nil)", replace, nil, nil) 197 | asserterror("bad argument #2 to '?' (index out of bounds)", replace, nil, 0) 198 | 199 | asserterror("bad argument #1 to '?' (number expected, got no value)", remove) 200 | asserterror("bad argument #1 to '?' (number expected, got nil)", remove, nil) 201 | asserterror("bad argument #1 to '?' (index out of bounds)", remove, 0) 202 | 203 | assertsame({}, 1, 0, append()) 204 | assertsame({nil}, 1, 1, append(nil)) 205 | 206 | assertsame({}, 1, 0, concat()) 207 | asserterror("attempt to call a nil value", concat, nil) 208 | 209 | asserterror("bad argument #1 to '?' (value expected)", map) 210 | assertsame({}, 1, 0, map(nil)) 211 | asserterror("attempt to call a nil value", map, nil, nil) 212 | 213 | assert(0 == count()) 214 | assert(1 == count(nil)) 215 | assert(3 == count(nil, 2, nil)) 216 | 217 | asserterror("bad argument #1 to '?' (index out of bounds)", at, 0) 218 | asserterror("bad argument #1 to '?' (index out of bounds)", at, -1) 219 | assertsame({}, 0, -1, at(1)) 220 | assertsame({}, 0, -1, at(2)) 221 | assertsame({}, 1, 1, at(1, nil)) 222 | assertsame({}, 0, -1, at(2, nil)) 223 | assertsame({2}, 1, 1, at(2, 1,2,3)) 224 | assertsame({2}, 1, 1, at(-2, 1,2,3)) 225 | 226 | print("done!") 227 | -------------------------------------------------------------------------------- /vararg.c: -------------------------------------------------------------------------------- 1 | /* 2 | 'vararg' is a Lua library for manipulation of variable arguements (vararg) of 3 | functions. These functions basically allow you to do things with vararg that 4 | cannot be efficiently done in pure Lua but can be easily done through the C API. 5 | 6 | Actually, the main motivation for this library was the 'pack' function, which 7 | is an elegant alternative for the possible new standard function 'table.pack' 8 | and the praised 'apairs'. Also 'pack' allows an interesting implementaiton of 9 | tuples in pure Lua. 10 | 11 | p = pack(...) 12 | p() --> ... 13 | p("#") --> select("#", ...) 14 | p(i) --> (select(i, ...)) 15 | p(i, j) --> unpack({...}, i, j) 16 | for i,v in p do --> for i,v in apairs(...) do 17 | range(i, j, ...) --> unpack({...}, i, j) 18 | remove(i, ...) --> t={...} table.remove(t,i) return unpack(t,1,select("#",...)-1) 19 | insert(v, i, ...) --> t={...} table.insert(t,i,v) return unpack(t,1,select("#",...)+1) 20 | replace(v, i, ...) --> t={...} t[i]=v return unpack(t,1,select("#",...)) 21 | append(v, ...) --> c=select("#",...)+1 return unpack({[c]=val,...},1,c) 22 | map(f, ...) --> t={} n=select("#",...) for i=1,n do t[i]=f((select(i,...))) end return unpack(t,1,n) 23 | concat(f1,f2,...) --> return all the values returned by functions 'f1,f2,...' 24 | count(...) --> select("#", ...) 25 | at(i, ...) --> if select("#", ...) >= i then rutrn (select(i, ...)) end 26 | */ 27 | 28 | #define LUA_VALIBNAME "vararg" 29 | 30 | #include "lua.h" 31 | #include "lauxlib.h" 32 | 33 | #if LUA_VERSION_NUM >= 503 /* Lua 5.3 */ 34 | 35 | #ifndef luaL_checkint 36 | #define luaL_checkint luaL_checkinteger 37 | #endif 38 | 39 | #ifndef luaL_optint 40 | #define luaL_optint luaL_optinteger 41 | #endif 42 | 43 | #endif 44 | 45 | #if LUA_VERSION_NUM >= 502 46 | 47 | #ifndef luaL_register 48 | 49 | static void luaL_register (lua_State *L, const char *libname, const luaL_Reg *l){ 50 | if(libname) lua_newtable(L); 51 | luaL_setfuncs(L, l, 0); 52 | } 53 | 54 | #endif 55 | 56 | #endif 57 | 58 | static int _optindex(lua_State *L, int arg, int top, int def) { 59 | int idx = (def ? luaL_optint(L, arg, def) : luaL_checkint(L, arg)); 60 | idx = (idx>=0 ? idx : top+idx+1); /* convert a stack index to positive */ 61 | if (idx<=0) luaL_argerror(L, arg, "index out of bounds"); 62 | return idx; 63 | } 64 | 65 | static int luaVA_tuple(lua_State *L) { 66 | int n = lua_tointeger(L, lua_upvalueindex(1)); /* number of packed values */ 67 | int type = lua_type(L, 1); 68 | if (type == LUA_TNIL) { 69 | int i = lua_tointeger(L, 2); 70 | if(++i > 0 && i <= n) { 71 | lua_pushinteger(L, i); 72 | lua_pushvalue(L, lua_upvalueindex(i+1)); 73 | return 2; 74 | } 75 | } else if (type == LUA_TSTRING && *lua_tostring(L, 1) == '#') { 76 | lua_pushinteger(L, n); 77 | return 1; 78 | } else { 79 | int i = 1, e = n; 80 | if (lua_gettop(L)) { 81 | i = _optindex(L, 1, n, 0); 82 | e = _optindex(L, 2, n, i); 83 | n = e-i+1; /* number of results */ 84 | luaL_checkstack(L, n, "too many results to unpack"); 85 | } 86 | for(; i<=e; ++i) lua_pushvalue(L, lua_upvalueindex(i+1)); 87 | return n; 88 | } 89 | return 0; 90 | } 91 | 92 | static int luaVA_pack(lua_State *L) { 93 | int top = lua_gettop(L); 94 | if (top >= 255) luaL_error(L, "too many values to pack"); 95 | lua_pushinteger(L, top); 96 | lua_insert(L, 1); 97 | lua_pushcclosure(L, luaVA_tuple, top+1); 98 | return 1; 99 | } 100 | 101 | static int luaVA_range(lua_State *L) { 102 | int n, i, e; 103 | n = lua_gettop(L); 104 | i = _optindex(L, 1, n-2, 0)+2; 105 | e = _optindex(L, 2, n-2, 0)+2; 106 | if (i > e) return 0; /* empty range */ 107 | if (!lua_checkstack(L, e-n)) /* space for extra nil's */ 108 | luaL_error(L, "range is too big"); 109 | lua_settop(L, e); 110 | return e-i+1; 111 | } 112 | 113 | static int luaVA_at(lua_State *L) { 114 | int n, i; 115 | n = lua_gettop(L); 116 | i = _optindex(L, 1, n-1, 0)+1; 117 | if (i > n) return 0; /* no value */ 118 | lua_settop(L, i); 119 | return 1; 120 | } 121 | 122 | static int luaVA_count(lua_State *L) { 123 | int n = lua_gettop(L); 124 | lua_settop(L, 0); 125 | lua_pushinteger(L, n); 126 | return 1; 127 | } 128 | 129 | static int luaVA_insert(lua_State *L) { 130 | int i, n; 131 | n = lua_gettop(L); 132 | i = _optindex(L, 2, n-2, 0)+2; 133 | if (i > n) { 134 | if (!lua_checkstack(L, i-n)) /* space for extra nil's */ 135 | luaL_error(L, "index is too big"); 136 | lua_settop(L, i-1); 137 | lua_pushvalue(L, 1); 138 | return i-2; 139 | } 140 | lua_pushvalue(L, 1); 141 | lua_insert(L, i); 142 | return n-1; 143 | } 144 | 145 | static int luaVA_remove(lua_State *L) { 146 | int i, n; 147 | n = lua_gettop(L); 148 | i = _optindex(L, 1, n-1, 0)+1; 149 | if (i <= n) { 150 | lua_remove(L, i); 151 | --n; 152 | } 153 | return n-1; 154 | } 155 | 156 | static int luaVA_replace(lua_State *L) { 157 | int i, n; 158 | n = lua_gettop(L); 159 | i = _optindex(L, 2, n-2, 0)+2; 160 | if (i > n) { 161 | if (!lua_checkstack(L, i-n)) /* space for extra nil's */ 162 | luaL_error(L, "index is too big"); 163 | lua_settop(L, i-1); 164 | lua_pushvalue(L, 1); 165 | return i-2; 166 | } 167 | lua_pushvalue(L, 1); 168 | lua_replace(L, i); 169 | return n-2; 170 | } 171 | 172 | static int luaVA_append(lua_State *L) { 173 | lua_pushvalue(L, 1); 174 | return lua_gettop(L)-1; 175 | } 176 | 177 | static int luaVA_map(lua_State *L) { 178 | int top = lua_gettop(L); 179 | int i; 180 | luaL_checkany(L, 1); 181 | for(i=2; i<=top; ++i) { 182 | lua_pushvalue(L, 1); 183 | lua_pushvalue(L, i); 184 | lua_call(L, 1, 1); 185 | lua_replace(L, i); /* to avoid the stack to double in size */ 186 | } 187 | return top-1; 188 | } 189 | 190 | static int luaVA_concat(lua_State *L) { 191 | int top = lua_gettop(L); 192 | int i; 193 | for(i=1; i<=top; ++i) { 194 | lua_pushvalue(L, i); 195 | lua_call(L, 0, LUA_MULTRET); 196 | } 197 | return lua_gettop(L)-top; 198 | } 199 | 200 | static int luaVA_call(lua_State *L) { 201 | lua_remove(L, 1); 202 | return luaVA_pack(L); 203 | } 204 | 205 | static const luaL_Reg va_funcs[] = { 206 | { "pack", luaVA_pack }, 207 | { "range", luaVA_range }, 208 | { "insert", luaVA_insert }, 209 | { "remove", luaVA_remove }, 210 | { "replace", luaVA_replace }, 211 | { "append", luaVA_append }, 212 | { "map", luaVA_map }, 213 | { "concat", luaVA_concat }, 214 | { "count", luaVA_count }, 215 | { "at", luaVA_at }, 216 | 217 | {NULL, NULL} 218 | }; 219 | 220 | LUALIB_API int luaopen_vararg(lua_State *L) { 221 | luaL_register(L, LUA_VALIBNAME, va_funcs); 222 | lua_newtable(L); 223 | lua_pushcfunction(L, luaVA_call); 224 | lua_setfield(L, -2, "__call"); 225 | lua_setmetatable(L, -2); 226 | return 1; 227 | } 228 | -------------------------------------------------------------------------------- /vararg.lua: -------------------------------------------------------------------------------- 1 | local math = require "math" 2 | local table = require "table" 3 | 4 | local error, assert, select = error, assert, select 5 | local max, unpack = math.max, table.unpack or unpack 6 | local setmetatable = setmetatable 7 | 8 | local tinsert2 = function(t, n, i, v) 9 | -- lua 5.2 rise error if index out of range 10 | -- assert(type(t) =='table') 11 | -- assert(type(n) =='number') 12 | -- assert(type(i) =='number') 13 | if i > n then 14 | t[i] = v 15 | return i 16 | end 17 | 18 | for j = n, i, -1 do 19 | t[j + 1] = t[j] 20 | end 21 | t[i] = v 22 | 23 | return n+1 24 | end 25 | 26 | local tremove2 = function(t, n, i) 27 | -- lua 5.2 rise error if index out of range 28 | -- assert(type(t) =='table') 29 | -- assert(type(n) =='number') 30 | -- assert(type(i) =='number') 31 | if i > n then 32 | for j = n+1, i do 33 | t[j] = nil 34 | end 35 | return n 36 | end 37 | 38 | for j = i, n do 39 | t[j] = t[j+1] 40 | end 41 | 42 | return n-1 43 | end 44 | 45 | local function idx(i, n, d) 46 | if i == nil then 47 | if not d then 48 | return error("number expected, got nil", 2) 49 | end 50 | return d 51 | end 52 | if i < 0 then 53 | i = n+i+1 54 | end 55 | if i <= 0 then 56 | return error("index out of bounds", 2) 57 | end 58 | return i 59 | end 60 | 61 | local function pack(...) 62 | local n = select("#", ...) 63 | local v = {...} 64 | return function(...) 65 | if (...) == "#" then 66 | return n 67 | else 68 | local argc = select("#", ...) 69 | if argc == 0 then 70 | return unpack(v, 1, n) 71 | else 72 | local i, j = ... 73 | if i == nil then 74 | if j == nil then j = 0 end 75 | i = j+1 76 | if i > 0 and i <= n then 77 | return i, v[i] 78 | end 79 | else 80 | i = idx(i, n, 1) 81 | j = idx(j, n, i) 82 | return unpack(v, i, j) 83 | end 84 | end 85 | end 86 | end 87 | end 88 | 89 | local function range(i, j, ...) 90 | local n = select("#", ...) 91 | i, j = idx(i,n), idx(j,n) 92 | if i > j then return end 93 | return unpack({...}, i, j) 94 | end 95 | 96 | local function remove(i, ...) 97 | local n = select("#", ...) 98 | local t = {...} 99 | i = idx(i, n) 100 | assert(i>0, "index out of bounds") 101 | if i<=n then 102 | n = tremove2(t, n, i) 103 | end 104 | return unpack(t, 1, n) 105 | end 106 | 107 | local function insert(v, i, ...) 108 | local n = select("#", ...) 109 | local t = {...} 110 | i = idx(i, n) 111 | assert(i > 0, "index out of bounds") 112 | n = tinsert2(t, n, i, v) 113 | return unpack(t, 1, n) 114 | end 115 | 116 | local function replace(v, i, ...) 117 | local n = select("#", ...) 118 | local t = {...} 119 | i = idx(i, n) 120 | assert(i > 0, "index out of bounds") 121 | t[i] = v 122 | n = max(n, i) 123 | return unpack(t, 1, n) 124 | end 125 | 126 | local function append(...) 127 | local n = select("#",...) 128 | if n <= 1 then return ... end 129 | local t = {select(2, ...)} 130 | t[n] = (...) 131 | return unpack(t, 1, n) 132 | end 133 | 134 | local function map(...) 135 | local n = select("#", ...) 136 | assert(n > 0) 137 | local f = ... 138 | local t = {} 139 | for i = 2, n do 140 | t[i-1] = f((select(i, ...))) 141 | end 142 | return unpack(t, 1, n-1) 143 | end 144 | 145 | local function packinto(n, t, ...) 146 | local c = select("#", ...) 147 | for i = 1, c do 148 | t[n+i] = select(i, ...) 149 | end 150 | return n+c 151 | end 152 | 153 | local function concat(...) 154 | local n = 0 155 | local t = {} 156 | for i = 1, select("#", ...) do 157 | local f = select(i, ...) 158 | n = packinto(n, t, f()) 159 | end 160 | return unpack(t, 1, n) 161 | end 162 | 163 | local function count(...) 164 | return select("#", ...) 165 | end 166 | 167 | local function at(i, ...) 168 | local n = select("#", ...) 169 | i = idx(i,n) 170 | if i > n then return end 171 | return (select(i, ...)) 172 | end 173 | 174 | return setmetatable({ 175 | pack = pack, 176 | range = range, 177 | insert = insert, 178 | remove = remove, 179 | replace = replace, 180 | append = append, 181 | map = map, 182 | concat = concat, 183 | count = count, 184 | at = at, 185 | },{ 186 | __call = function(_, ...) 187 | return pack(...) 188 | end 189 | }) 190 | --------------------------------------------------------------------------------