]> hydra-www.ietfng.org Git - acmetensortoys-esp-lua_core/commitdiff
fifo{,sock}: lazy and "phantom" function entries
authorNathaniel Wesley Filardo <nwfilardo@gmail.com>
Wed, 6 Feb 2019 00:34:35 +0000 (00:34 +0000)
committerNathaniel Wesley Filardo <nwfilardo@gmail.com>
Fri, 22 Feb 2019 23:55:08 +0000 (23:55 +0000)
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
net/fifosock.lua
test/fifosocktest.lua

index eadc579dcfeb54adbcf6291b04c93ab1530fa345..962016a948d2aff7a639ae16fc47439cdf206bdb 100644 (file)
@@ -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()
index 2dfe7d4f5af9050d1d3545136b7330bf38cf17ea..6377bb4d0559708600555ac6b97068ab9342a510 100644 (file)
@@ -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
 
index 2efdc3f4b9a83b53e43a546b3cee127605da337c..46c6f5fa237e71d861458dfe3221614d44163d7e 100644 (file)
@@ -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")