You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
3.0 KiB
Lua

-- =========================================
-- tuple, A minimal tuple class for Lua
-- https://github.com/Yonaba/tuple.lua
-- =========================================
local unpack = unpack or table.unpack
local setmetatable = setmetatable
local ipairs = ipairs
local tostring = tostring
local min = math.min
local type = type
local assert = assert
local select = select
local t_concat = table.concat
local tuple = {}
tuple.__index = tuple
-- Collects values i to j to return a new tuple
function tuple.__call(t, i, j)
return tuple(unpack(t, i, j))
end
-- Returns a string representation of tuple
function tuple:__tostring()
local t = self:toArray()
for k, v in ipairs(t) do
t[k] = tostring(v)
end
return ('(%s)'):format(t_concat(t, ', '))
end
-- Tuple elements iterator function
function tuple:elements(...)
local i = 0
return function(...)
i = i + 1
if self[i] ~= nil then
return i, self[i]
end
end
end
-- Returns tuple length
function tuple:len()
return self.n
end
-- Tests if tuple contains element v
function tuple:has(v)
for k, _v in ipairs(self) do
if _v == v then
return true
end
end
return false
end
-- Does this tuple includes all elements in tuple other ?
function tuple:includes(other)
if self.n < other.n then
return false
end
for _, element in other:elements() do
if not self:has(element) then
return false
end
end
return true
end
-- Converts tuple to simpe array ?
function tuple:toArray()
return {unpack(self)}
end
-- ==========
-- Operators
-- ==========
-- Tuple equality test
function tuple:__eq(other)
if self.n ~= other.n then
return false
end
for i, element in other:elements() do
if element ~= self[i] then
return false
end
end
return true
end
-- Tuple relational <= comparison
function tuple:__le(other)
local n = min(self.n, other.n)
for i = 1, n do
if (self[i] > other[i]) then
return false
end
end
return true
end
-- Tuple relational < comparison
function tuple:__lt(other)
local n = min(self.n, other.n)
for i = 1, n do
if self[i] >= other[i] then
return false
end
end
return true
end
-- Tuple addition
function tuple.__add(a, b)
local t = a()
for _, element in b:elements() do
t[#t + 1] = element
end
t.n = #t
return t
end
-- Multiplication
function tuple.__mul(t, n)
if type(n) == 'number' then
assert(math.floor(n) == n, ('Wrong argument n. Integer expected, got (%s)'):format(n))
local _t
for i = 1, n do
_t = (_t or tuple()) + t
end
return _t
else
return n * t
end
end
-- Class constructor, wrapping up and return
return setmetatable(tuple, {
__call = function(self, ...)
local new_tuple = {
n = select('#', ...),
...,
}
return setmetatable(new_tuple, tuple)
end,
})