Reiterador II
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