require 'classlib' class.Tuple() function Tuple:__init(...) -- construct with initial elements self.elem = {...} self.n = #self.elem end function Tuple:__tostring() -- string representation local function ascii(e) return type(e) == 'string' and string.format('%q', e) or tostring(e) end local s = '' for i, v in ipairs(self.elem) do s = #s == 0 and ascii(v) or s .. ', ' .. ascii(v) end return '(' .. s .. ')' end local function checkrange(i, max) assert(i >= 1 and i <= max, 'Index must be >= 1 and <= ' .. max) end local function checkindex(i, max) assert(type(i) == 'number', 'Index must be a number') checkrange(i, max) end function Tuple:push(i, v) -- push an element anywhere if v == nil then v = i i = self.n + 1 -- by default push at the end end if v == nil then return end -- pushing nil has no effect checkindex(i, self.n + 1) -- allow appending table.insert(self.elem, i, v) -- insert it self.n = self.n + 1 -- count it end function Tuple:pop(i) -- pop an element anywhere if i == nil then i = self.n -- by default pop at the end if i == 0 then return nil end end local e = self[i] self[i] = nil -- remove it return e -- return it end function Tuple:clear() -- empty tuple self.elem = {} self.n = 0 end function Tuple:size() -- tuple size return self.n end function Tuple:__get(i) -- read an element if type(i) ~= 'number' then return nil end checkrange(i, self.n + 1) -- allow reading one past the end return self.elem[i] -- read it end function Tuple:__set(i, v) -- assign an element if type(i) ~= 'number' then return false end checkrange(i, self.n + 1) -- allow assigning one past the end if v == nil then if i <= self.n then -- if removing, count it table.remove(self.elem, i) self.n = self.n - 1 end return true end if i == self.n + 1 then -- if appending, count it self.n = i end self.elem[i] = v -- assign it return true end