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
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,
|
|
})
|