2007-01-05

Reiterador II

Lua Versão «metatabela + corrotina» do artigo anterior:

local coroutine = coroutine
local math = math
local setmetatable = setmetatable
local table = table
local type = type

module "rand"

-- Criação da metatabela
local iter = { sec = {} }
iter.__index = iter
iter.__newindex = function (t, k, v)
error("Chave " .. k .. " não encontrada")
end

-- Construtor local
function iter:new(o)
o = o or {}
setmetatable(o, self)
return o
end

-- Método principal
function iter:next()
local _, r = coroutine.resume(self.co)
return r
end

-- Construtor público
function new(t)
-- É preciso receber um vetor
if type(t) ~= "table" then
error "Parâmetro deve ser um vetor"
end

-- Vetor vazio?
if table.getn(t) == 0 then
error "Vetor vazio"
end

-- Criação da corrotina
t.co = coroutine.create(function (t)
-- Inicialição
local m, e
coroutine.yield(nil)

-- Loop principal
while true do
m = table.getn(t)

-- Se o vetor estiver vazio, começa de novo
if m == 0 then
while table.getn(t.sec) > 0 do
table.insert(t, table.remove(t.sec, 1))
end
m = table.getn(t)
end

-- Seleciona um elemento aleatoriamente
e = table.remove(t, math.random(m))
table.insert(t.sec, e)
coroutine.yield(e)
end
end)

-- Passa a tabela principal para a corrotina
coroutine.resume(t.co, t)

return iter:new(t)
end


[]'s