From 74d258ecb0744f9a4809270580c67dc4df903c4e Mon Sep 17 00:00:00 2001 From: Nathaniel Wesley Filardo Date: Wed, 6 Feb 2019 00:34:35 +0000 Subject: [PATCH] fifo{,sock}: lazy and "phantom" function entries fifo already supported functions acting as lazy generators of events, so now teach it about phantom entries (which just cause additional dequeueing). Push support down into fifosock and add tests. --- fifo/fifo.lua | 22 ++++++++++++++++------ net/fifosock.lua | 16 +++++++++++++++- test/fifosocktest.lua | 35 +++++++++++++++++++++++++++++++++-- 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/fifo/fifo.lua b/fifo/fifo.lua index eadc579..962016a 100644 --- a/fifo/fifo.lua +++ b/fifo/fifo.lua @@ -1,15 +1,25 @@ --- Remove an element and pass it to k; if that returns a function, leave that +-- Remove an element and pass it to k; if that returns a value, leave that -- pending at the top of the fifo. Thus, we can get events that do multiple --- things. If the queue is empty, do not invoke k but flag it to enable --- immediate execution at the next call to queue. +-- things. -- --- Returns 'true' if the queue was not empty, 'false' otherwise. +-- If k returns nil, the fifo will be advanced. Moreover, k may return a +-- second result, a boolean, which indicates whether or not this dequeue +-- "counts" as one; this is useful for "phantom" elements in the fifo, such as +-- (placeholders for) callbacks to observers, that cannot otherwise act as +-- ordinary fifo elements do. +-- +-- If the queue is empty, do not invoke k but flag it to enable immediate +-- execution at the next call to queue. +-- +-- Returns 'true' if the queue contained at least one non-phantom entry, +-- 'false' otherwise. local function dequeue(q,k) if #q > 0 then - local new = k(q[1]) + local new, again = k(q[1]) if new == nil then table.remove(q,1) + if again then return dequeue(q, k) end -- note tail call else q[1] = new end return true @@ -23,7 +33,7 @@ end -- subsequent dequeues. local function queue(q,a,k) table.insert(q,a) - if k ~= nil and q._go then q._go = false; q:dequeue(k) end + if k ~= nil and q._go then q._go = false; dequeue(q, k) end end -- return a FIFO constructor return function() diff --git a/net/fifosock.lua b/net/fifosock.lua index 2dfe7d4..6377bb4 100644 --- a/net/fifosock.lua +++ b/net/fifosock.lua @@ -11,7 +11,16 @@ local insert = table.insert local fifo = OVL.fifo() return function(sock) - local ssend = function(s) sock:send(s) end + local ssend = function(s) + ns = nil + if type(s) == "function" then s, ns = s() end + if s ~= nil then + sock:send(s) + return ns or nil, false + else + return nil, true + end + end local fsmall, lsmall, fbig = {}, 0, fifo() -- Move fsmall to fbig; might send if fbig empty @@ -32,6 +41,11 @@ return function(sock) -- don't sweat the petty things if s == nil or s == "" then return end + -- Our fifos can take functions; these can be useful for either lazy + -- generators or callbacks for parts of the stream having been sent. + -- Go ahead and queue this thing in the right place. + if type(s) == "function" then promote(); fbig:queue(s, ssend); return; end + -- small fifo would overfill? promote it if lsmall + #s > BIGTHRESH or #fsmall >= FSMALLLIM then promote() end diff --git a/test/fifosocktest.lua b/test/fifosocktest.lua index 2efdc3f..46c6f5f 100644 --- a/test/fifosocktest.lua +++ b/test/fifosocktest.lua @@ -2,8 +2,9 @@ OVL={} OVL.fifo = function() return dofile("./fifo/fifo.lua") end package.loaded["fifosock"] = dofile("./net/fifosock.lua") --- vprint = print -vprint = function() end +verbose = false + +vprint = verbose and print or function() end outs = {} fakesock = { @@ -64,4 +65,34 @@ sent() ; fcheck(string.rep("b",256)) sent() ; fcheck(string.rep("c",260)) sent() ; fchecke() +-- test a lazy generator +local ix = 0 +local function gen() vprint("GEN", ix); ix = ix + 1; return ("a" .. ix), ix < 3 and gen end +fsend(gen) +fsend("b") +fcheck("a1") +sent() ; fcheck("a2") +sent() ; fcheck("a3") +sent() ; fcheck("b") +sent() ; fchecke() + +-- test a completeion-like callback that does send text +local ix = 0 +local function gen() vprint("GEN"); ix = 1; return "efgh", nil end +fsend("abcd"); fsend(gen); fsend("ijkl") +assert (ix == 0) + fcheck("abcd"); assert (ix == 0) +sent() ; fcheck("efgh"); assert (ix == 1); ix = 0 +sent() ; fcheck("ijkl"); assert (ix == 0) +sent() ; fchecke() + +-- and one that doesn't +local ix = 0 +local function gen() vprint("GEN"); ix = 1; return nil, nil end +fsend("abcd"); fsend(gen); fsend("ijkl") +assert (ix == 0) + fcheck("abcd"); assert (ix == 0) +sent() ; fcheck("ijkl"); assert (ix == 1); ix = 0 +sent() ; fchecke() ; assert (ix == 0) + print("All tests OK") -- 2.50.1