--[[ Specialized tables: list, array, set Authors: Lua Table Semantics Group lua-table-semantics@googlegroups.org http://groups.google.com/group/lua-table-semantics History: DL 2011-01-13 Implementation of 'list' Bugs and TODO's: Incompatible with 5.1. Error messages do not all give line number Object-oriented calls, e.g. l:append(v) for lists not implemented. Moot points: Fractional indices are allowed, but not non-negative integers. Is this the ideal choice?:if expand("%") == ""|browse confirm w|else|confirm w|endif ]] if _VERSION<"Lua 5.2" then error("This module requires Lua 5.2") end local index = {} -- unique key in proxy for the table itself local param = {} -- unique key in proxy for local parameters local function in_range (a,b,x) return a<=x and x<=b end local function in_Z(x) return type(x)=='number' and math.floor(x)==x end --[[ Table type 'list' Requirement: the positive numeric keys must form a solid block from 1 to n The namespace 'list' is used for the same functions as in the standard namespace 'table', except 'pack' which is not needed. The functions, as well as 'pairs' and 'ipairs', are redefined to operate on the proxy table. In addition, 'insert' tests that the insertion is in the range 1 to n+1. 'remove' tests that the removal is in the range 1 to n. ]] list = { table_type = 'list', insert = function(t,k,v) if v==nil then return end local p=t[param] if not (in_Z(k) and in_range(1,p.n+1,k)) then error('Attempt to insert value outside list',2) end p.n = p.n+1 table.insert(t[index],k,v) end; append = function(t,v) if v==nil then return end local p=t[param] p.n = p.n+1 table.insert(t[index],v) end; remove = function(t,v) local p=t[param] if not (in_Z(k) and in_range(1,p.n,k)) then error('Attempt to remove value outside list',2) end p.n=p.n-1 table.remove(t[index],v) end; sort = function(t,comp) table.sort(t[index],comp) end; concat = function(t,sep,i,j) table.concat(t[index],sep,i,j) end; unpack = function(t,i,j) return table.unpack(t[index],i,j) end } --[[ Values of table type 'list' # returns n t[k]=v checks that integer indices belong to the range 1..n+1. If so, t[k]=nil does the same as list.remove(t,k) and t[n+1]=non_nil increments n. ]] local list_mt = { __index = function(t,k) return t[index][k] end; __newindex = function(t,k,v) local p=t[param] t=t[index] if in_Z(k) then if not in_range(1,p.n+1,k) then error('Attempt to assign value outside list',2) end if v==nil then table.remove(t,k) p.n=p.n-1 return end if k==p.n+1 then p.n=k end end t[k]=v end; __len = function(t) return t[param].n end; __pairs = function(t) return pairs(t[index]) end; __ipairs = function(t) return ipairs(t[index]) end; } setmetatable(list,{ __call = function (self,t) local proxy={} proxy[index]=t local n=#t proxy[param]={n=n} local count=0 for k,v in pairs(t) do if in_Z(k) then if in_range(1,n,k) then count=count+1 else count=-1 break end end end if count~=n then error('Attempt to make a list from a table with holes',2) end setmetatable(proxy,list_mt) return proxy end }) function vanity_test() print (pcall(list,{1,2,3,nil,5})) local l = list{10,20,30} list.append(l,40) l[2]=200 l[3]=nil print (pcall(function() l[6]=6 end)) print (pcall(list.insert,l,'somewhere','something')) l['somewhere']='something' print('len(l)='..#l) for k,v in pairs(l) do print(k,v) end end