FANDOM


local function vararg_any(...) return select('#', ...) ~= 0 end
 
local function vararg_if(some, none, ...)
    if vararg_any(...) then
		return some(...)
	elseif none then
		return none()
	end
end
 
local function identity(...) return ... end
 
local iterfuncs = {}
local wrap
local mt = {
	__index = function(t, k)
		return function(_, ...)
			return iterfuncs[k](t.iter, ...)
		end
	end,
	__call = function(t) return t.iter() end,
    __tostring = function(t) return "<iterator>" end
}
 
 
do
	-- call f for each item in iter
	iterfuncs.each = function(iter, f)
		repeat
			local done = false
			vararg_if(f, function() done = true	end, iter())
		until done
	end
 
	-- maps item... to f(item)...
	iterfuncs.map = function(iter, f)
		return wrap(function()
			return vararg_if(f, nil, iter())
		end)
	end
 
	-- call f(item from it1, item from it2) for each
	iterfuncs.zip = function(iter, iter2, f)
		return wrap(function()
			return vararg_if(function(...)
				local n = select('#', ...)
				return vararg_if(function(...)
					if select('#', ...) > n then
						return ...
					end
				end, nil, ..., iter2())
			end, nil, iter())
		end)
	end
 
	-- keeps only items where f(item) is truthy
	iterfuncs.filter = function(iter, pred)
		pred = pred or identity
		local inner
		inner = function()
			return vararg_if(function(...)
				if pred(...) then
					return ...
				else
					return inner()
				end
			end, nil, iter())
		end
		return wrap(inner)
	end
 
	-- returns true if pred(item) is true for any item
	iterfuncs.any = function(iter, pred)
		pred = pred or identity
		repeat
			local done = false
			local ok = vararg_if(pred, function() done = true end, iter())
			if ok then return true end
		until done
		return false
	end
 
	-- returns true if pred(item) is true for all items
	iterfuncs.all = function(iter, pred)
		pred = pred or identity
		return not iterfuncs.any(iter, function(...) return not pred(...) end)
	end
 
	-- converts a 1-iterator to a list
	iterfuncs.to_list = function(iter)
		local res = {}
		iterfuncs.each(iter, function(...)
			local arity = select('#', ...)
			if arity ~= 1 then
				error(("Expected 1-iterator, got %d-iterator"):format(arity))
			end
			local x = ...
			res[#res+1] = x
		end)
		return res
	end
 
	-- converts a 2-iterator to a dict
	iterfuncs.to_dict = function(iter)
		local res = {}
		iterfuncs.each(iter, function(...)
			local arity = select('#', ...)
			if arity ~= 2 then
				error(("Expected 2-iterator, got %d-iterator"):format(arity))
			end
			local k, v = ...
			res[k] = v
		end)
		return res
	end
 
	-- joins a 1-iterator
	iterfuncs.join = function(iter, val)
		return table.concat(iterfuncs.to_list(iter), val)
	end
end
 
 
local funcs = {}
funcs.range = function(n)
	local i = 1
	return wrap(function()
		if i < n then
			local cur = i
			i = i + 1
			return cur
		else
			return
		end
	end)
end
funcs.pairs = function(t)
    local next = pairs(t)  -- fix for scribuntu
	local k, v = next(t, k)
	return wrap(function()
		if k then
			local curk, curv = k, v
			k, v = next(t, k)
			return curk, curv
		end
	end)
end
funcs.values = function(t)
	return iterfuncs.map(funcs.pairs(t), function(k, v) return v end)
end
funcs.keys = function(t)
	return iterfuncs.map(funcs.pairs(t), function(k, v) return k end)
end
 
 
-- syntactic sugar - adds method to an iterator
wrap = function(iter)
    if type(iter) == 'function' then
        return setmetatable({iter=iter}, mt)
    elseif getmetatable(iter) == mt then
        return iter
    elseif type(iter) == 'table' then
        return funcs.values(iter)
    end
end
 
setmetatable(funcs, {
	__call = function(t, iter) return wrap(iter) end
})
 
 
return funcs

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.