# Pure generic scheduler queue; Nat deadlines and never-reused FIFO IDs. import Base import bend-kit-collections@0.1.2.0/heap.bend as H type Ticket<-A: Data> is Data: Ticket{id: Nat, deadline: Nat, payload: A} type State<-A: Data> is Data: State{next_id: Nat, pending: H.Heap>, running: List<&2, Ticket>} def id(-A: Data, t: Ticket) -> Nat: match t: case Ticket{i, d, x}: i def deadline(-A: Data, t: Ticket) -> Nat: match t: case Ticket{i, d, x}: d def payload(-A: Data, t: Ticket) -> A: match t: case Ticket{i, d, x}: x def le.same(b: Bool, i: Nat, j: Nat, d: Nat, e: Nat) -> Bool: match b: case True{}: Nat.is_le(i, j) case False{}: Nat.is_le(d, e) def le(-A: Data, a: Ticket, b: Ticket) -> Bool: match a b: case Ticket{i, +d, x} Ticket{j, +e, y}: le.same(Nat.is_eq(d, e), i, j, d, e) def new(-A: Data) -> State: State{0n, H.Heap.new(Ticket), Nil{}} def enqueue(~A: Data, d: Nat, x: A, s: State) -> State & Nat: match s: case State{+i, h, r}: (State{1n+i, H.Heap.push(~Ticket, ~(a => b => le(A, a, b)), Ticket{i, d, x}, h), r}, i) def select.due(~A: Data, b: Bool, i: Nat, h: H.Heap>, r: List<&2, Ticket>, t: Ticket, l: H.Heap>, q: H.Heap>) -> State & Maybe<&2, Ticket>: match b: case False{}: (State{i, h, r}, None{}) case True{}: +t = t (State{i, H.Heap.merge(~Ticket, ~(a => b => le(A, a, b)), l, q), t <> r}, Some{t}) def select(~A: Data, now: Nat, s: State) -> State & Maybe<&2, Ticket>: match s: case State{i, H.HLeaf{}, r}: (State{i, H.HLeaf{}, r}, None{}) case State{i, H.HNode{+n, +t, +l, +q}, r}: select.due(~A, Nat.is_le(deadline(A, t), now), i, H.HNode{n, t, l, q}, r, t, l, q) # ponytail: eager O(n) cancellation; indexed deletion if cancellation dominates. def remove.list.keep(-A: Data, b: Bool, t: Ticket, rest: List<&2, Ticket>) -> List<&2, Ticket>: match b: case True{}: rest case False{}: t <> rest def remove.list(-A: Data, xs: List<&2, Ticket>, +i: Nat) -> List<&2, Ticket>: match xs: case Nil{}: Nil{} case Con{+t, rest}: remove.list.keep(A, Nat.is_eq(id(A, t), i), t, remove.list(A, rest, i)) def remove.heap.keep(~A: Data, b: Bool, t: Ticket, l: H.Heap>, r: H.Heap>) -> H.Heap>: match b: case True{}: H.Heap.merge(~Ticket, ~(a => b => le(A, a, b)), l, r) case False{}: +l = l +r = r H.HNode{1n+Nat.add(H.Heap.size(Ticket, l), H.Heap.size(Ticket, r)), t, l, r} def remove.heap(~A: Data, h: H.Heap>, +i: Nat) -> H.Heap>: match h: case H.HLeaf{}: H.HLeaf{} case H.HNode{n, +t, l, r}: remove.heap.keep(~A, Nat.is_eq(id(A, t), i), t, remove.heap(~A, l, i), remove.heap(~A, r, i)) def cancel(~A: Data, i: Nat, s: State) -> State: match s: case State{n, h, r}: +i = i State{n, remove.heap(~A, h, i), remove.list(A, r, i)} # Reference observation for laws; completion uses the single-pass take below. def find.list.choose(-A: Data, b: Bool, t: Ticket, rest: Maybe<&2, Ticket>) -> Maybe<&2, Ticket>: match b: case True{}: Some{t} case False{}: rest def find.list(-A: Data, xs: List<&2, Ticket>, +i: Nat) -> Maybe<&2, Ticket>: match xs: case Nil{}: None{} case Con{+t, rest}: find.list.choose(A, Nat.is_eq(id(A, t), i), t, find.list(A, rest, i)) type Taken<-A: Data> is Data: Taken{remaining: List<&2, Ticket>, found: Maybe<&2, Ticket>} # Remove all matching entries and return the first token in one traversal. def take.keep(-A: Data, b: Bool, t: Ticket, result: Taken) -> Taken: match b: case True{}: match result: case Taken{rest, found}: Taken{rest, Some{t}} case False{}: match result: case Taken{rest, found}: Taken{t <> rest, found} def take.list(-A: Data, xs: List<&2, Ticket>, +i: Nat) -> Taken: match xs: case Nil{}: Taken{Nil{}, None{}} case Con{+t, rest}: take.keep(A, Nat.is_eq(id(A, t), i), t, take.list(A, rest, i)) def complete.taken(-A: Data, result: Taken, n: Nat, h: H.Heap>) -> State & Maybe<&2, Ticket>: match result: case Taken{r, found}: (State{n, h, r}, found) def complete(-A: Data, i: Nat, s: State) -> State & Maybe<&2, Ticket>: match s: case State{n, h, r}: complete.taken(A, take.list(A, r, i), n, h) def requeue.found(~A: Data, found: Maybe<&2, Ticket>, d: Nat, s: State) -> State & Bool: match found: case None{}: (s, False{}) case Some{Ticket{i, old, x}}: match s: case State{n, h, r}: (State{n, H.Heap.push(~Ticket, ~(a => b => le(A, a, b)), Ticket{i, d, x}, h), r}, True{}) def requeue.completed(~A: Data, r: State & Maybe<&2, Ticket>, d: Nat) -> State & Bool: (s, found) = r requeue.found(~A, found, d, s) def requeue(~A: Data, i: Nat, d: Nat, s: State) -> State & Bool: requeue.completed(~A, complete(A, i, s), d) # Non-consuming observations used by adapters and laws. def next_id(-A: Data, s: State) -> Nat: match s: case State{n, h, r}: n def pending(-A: Data, s: State) -> H.Heap>: match s: case State{n, h, r}: h def running(-A: Data, s: State) -> List<&2, Ticket>: match s: case State{n, h, r}: r