From 9e01bb11a5af844980566d381db2bfa04f512324 Mon Sep 17 00:00:00 2001 From: heav Date: Mon, 28 Nov 2022 16:35:21 +0000 Subject: made an iterator library. --- czzc/init.lua | 6 ++- czzc/iter.lua | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 czzc/iter.lua diff --git a/czzc/init.lua b/czzc/init.lua index eea504b..04759b6 100644 --- a/czzc/init.lua +++ b/czzc/init.lua @@ -4,5 +4,7 @@ local function czzc_require(mod) end czzc_require"table" -czzc_require"string" -czzc_require"io" +--czzc_require"string" +--czzc_require"io" +czzc_require"iter" +czzc_require"math" \ No newline at end of file diff --git a/czzc/iter.lua b/czzc/iter.lua new file mode 100644 index 0000000..866b43a --- /dev/null +++ b/czzc/iter.lua @@ -0,0 +1,153 @@ +local M = {} + +-- an important thing to keep in mind: +-- factories often return three values, like ipairs. +-- the actual function, an "invariant state", and a control variable. +-- we'll just use closures to encapsulate this behaviour, but ipairs/pairs won't. +-- as such, functions passing around iterators also ought to pass those around. + +-- the idea is that you can map a function over outputs of an iterator. +-- for example, string.bytes over an iterator over characters of a string. +-- returns an iterator. +M.apply = function(fn, iter, ...) + return function() + local vals = {iter()} + if #vals > 0 then + -- me when lua versions. + return fn((unpack or table.unpack)(vals)) + end + end, ... +end + +-- apply, but only send n arguments of the iterator to the function. +M.apply_n = function(args_n, fn, iter, ...) + return function() + local vals = {iter()} + if #vals > 0 then + local pt1 = {} + local pt2 = {} + for i=1, args_n do + table.insert(pt1, vals[i]) + end + for i=args_n+1, #vals do + table.insert(pt2, vals[i]) + end + return fn(table.unpack(pt1)), table.unpack(pt2) + end + end, ... +end + +-- by factory, i mean a function generating iterators, like ipairs. +-- this returns a factory. +-- args_n is how many of the arguments to send to the function maximum, optionally. +M.apply_factory = function(fn, fact, args_n) + if not args_n then + return function(...) + return M.apply(fn, fact(...)) + end + else + return function(...) + return M.apply_n(args_n,fn, fact(...)) + end + end +end + +-- only works properly with iterators returning one value for now. +-- returns an array of all of its results. +M.collect = function(...) + local res = {} + for value, _ in ... do + table.insert(res, value) + end + return res +end + +-- works with iterators of up to 8 values. +-- there seems to be no way to make this generic, sorry. +-- returns an array of arrays. +M.multicollect = function(...) + local res = {} + for v1,v2,v3,v4,v5,v6,v7,v8 in ... do + table.insert(res, {v1,v2,v3,v4,v5,v6,v7,v8}) + end + return res +end + +-- gets an iterator's reverse. +M.reverse = function(...) + local res = M.multicollect(...) + local i = #res + return function() + if i>0 then + i = i - 1 + return table.unpack(res[i+1]) + end + end +end + +-- makes an iterator factory output reverses. +M.reverse_factory = function(factory) + return function(...) + return M.reverse(factory(...)) + end +end + +-- alright, enough of these meta functions. time for some cool iterators. + +-- returns character, index. +M.chars = function(str) + local i = 1 + return function() + if i <= #str then + i = i + 1 + return str:sub(i-1,i-1), i-1 + end + end +end + +-- returns all words, where words are defined as adjacent non-whitespace. +-- of the form word, index. +M.words = function(str) + local i = 0 + local it = str:gmatch("%S+") + return function() + i = i + 1 + return it(), i + end +end + +-- cool, right? +M.bytes = M.apply_factory(string.byte, M.chars, 1) + +-- iterates over the digits of a natural number starting with the +-- least significant one. i.e 1003: 3 -> 0 -> 0 -> 1. +-- returns digit index second, for if it's needed. +M.digits = function(n) + local digit = 0 + -- i think math.abs is the most reasonable way to handle negatives. + n = math.abs(n) + return function() + -- 0 is a special case since bee. + if n ~= 0 and n < 10^digit then return end + digit = digit + 1 + return math.floor(n/10^(digit-1))%10, digit + end +end +-- the same as above, but from the most significant instead, i.e 1003: 1 -> 0 -> 0 -> 3. +M.digits_msd = M.reverse_factory(M.digits) + +-- iterates over a table in reverse. +M.ipairs_rev = M.reverse_factory(ipairs) + +-- autogenerate reversed variants of certain iterators. +local to_be_reversed = { + "chars", + "bytes", + "words" +} + +for _, v in ipairs(to_be_reversed) do + M[v.."_rev"] = M.reverse_factory(M[v]) +end + +return M \ No newline at end of file -- cgit v1.2.3