1 # Pure generic scheduler queue; Nat deadlines and never-reused FIFO IDs. 2 import Base 3 import bend-kit-collections@0.1.4.1/heap.bend as H 4 5 type Ticket<-A: Data> is Data: 6 Ticket{id: Nat, deadline: Nat, payload: A} 7 8 type State<-A: Data> is Data: 9 State{next_id: Nat, pending: H.Heap>, running: List<&2, Ticket>} 10 11 def id(-A: Data, t: Ticket) -> Nat: 12 match t: 13 case Ticket{i, d, x}: 14 i 15 16 def deadline(-A: Data, t: Ticket) -> Nat: 17 match t: 18 case Ticket{i, d, x}: 19 d 20 21 def payload(-A: Data, t: Ticket) -> A: 22 match t: 23 case Ticket{i, d, x}: 24 x 25 26 def le.same(b: Bool, i: Nat, j: Nat, d: Nat, e: Nat) -> Bool: 27 match b: 28 case True{}: 29 Nat.is_le(i, j) 30 case False{}: 31 Nat.is_le(d, e) 32 33 def le(-A: Data, a: Ticket, b: Ticket) -> Bool: 34 match a b: 35 case Ticket{i, +d, x} Ticket{j, +e, y}: 36 le.same(Nat.is_eq(d, e), i, j, d, e) 37 38 def new(-A: Data) -> State: 39 State{0n, H.Heap.new(Ticket), Nil{}} 40 41 def enqueue(~A: Data, d: Nat, x: A, s: State) -> State & Nat: 42 match s: 43 case State{+i, h, r}: 44 (State{1n+i, H.Heap.push(~Ticket, ~(a => b => le(A, a, b)), Ticket{i, d, x}, h), r}, i) 45 46 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>: 47 match b: 48 case False{}: 49 (State{i, h, r}, None{}) 50 case True{}: 51 +t = t 52 (State{i, H.Heap.merge(~Ticket, ~(a => b => le(A, a, b)), l, q), t <> r}, Some{t}) 53 54 def select(~A: Data, now: Nat, s: State) -> State & Maybe<&2, Ticket>: 55 match s: 56 case State{i, H.HLeaf{}, r}: 57 (State{i, H.HLeaf{}, r}, None{}) 58 case State{i, H.HNode{+n, +t, +l, +q}, r}: 59 select.due(~A, Nat.is_le(deadline(A, t), now), i, H.HNode{n, t, l, q}, r, t, l, q) 60 61 # ponytail: eager O(n) cancellation; indexed deletion if cancellation dominates. 62 def remove.list.keep(-A: Data, b: Bool, t: Ticket, rest: List<&2, Ticket>) -> List<&2, Ticket>: 63 match b: 64 case True{}: 65 rest 66 case False{}: 67 t <> rest 68 69 def remove.list(-A: Data, xs: List<&2, Ticket>, +i: Nat) -> List<&2, Ticket>: 70 match xs: 71 case Nil{}: 72 Nil{} 73 case Con{+t, rest}: 74 remove.list.keep(A, Nat.is_eq(id(A, t), i), t, remove.list(A, rest, i)) 75 76 def remove.heap.keep(~A: Data, b: Bool, t: Ticket, l: H.Heap>, r: H.Heap>) -> H.Heap>: 77 match b: 78 case True{}: 79 H.Heap.merge(~Ticket, ~(a => b => le(A, a, b)), l, r) 80 case False{}: 81 +l = l 82 +r = r 83 H.HNode{1n+Nat.add(H.Heap.size(Ticket, l), H.Heap.size(Ticket, r)), t, l, r} 84 85 def remove.heap(~A: Data, h: H.Heap>, +i: Nat) -> H.Heap>: 86 match h: 87 case H.HLeaf{}: 88 H.HLeaf{} 89 case H.HNode{n, +t, l, r}: 90 remove.heap.keep(~A, Nat.is_eq(id(A, t), i), t, remove.heap(~A, l, i), remove.heap(~A, r, i)) 91 92 def cancel(~A: Data, i: Nat, s: State) -> State: 93 match s: 94 case State{n, h, r}: 95 +i = i 96 State{n, remove.heap(~A, h, i), remove.list(A, r, i)} 97 98 # Reference observation for laws; completion uses the single-pass take below. 99 def find.list.choose(-A: Data, b: Bool, t: Ticket, rest: Maybe<&2, Ticket>) -> Maybe<&2, Ticket>: 100 match b: 101 case True{}: 102 Some{t} 103 case False{}: 104 rest 105 106 def find.list(-A: Data, xs: List<&2, Ticket>, +i: Nat) -> Maybe<&2, Ticket>: 107 match xs: 108 case Nil{}: 109 None{} 110 case Con{+t, rest}: 111 find.list.choose(A, Nat.is_eq(id(A, t), i), t, find.list(A, rest, i)) 112 113 type Taken<-A: Data> is Data: 114 Taken{remaining: List<&2, Ticket>, found: Maybe<&2, Ticket>} 115 116 # Remove all matching entries and return the first token in one traversal. 117 def take.keep(-A: Data, b: Bool, t: Ticket, result: Taken) -> Taken: 118 match b: 119 case True{}: 120 match result: 121 case Taken{rest, found}: 122 Taken{rest, Some{t}} 123 case False{}: 124 match result: 125 case Taken{rest, found}: 126 Taken{t <> rest, found} 127 128 def take.list(-A: Data, xs: List<&2, Ticket>, +i: Nat) -> Taken: 129 match xs: 130 case Nil{}: 131 Taken{Nil{}, None{}} 132 case Con{+t, rest}: 133 take.keep(A, Nat.is_eq(id(A, t), i), t, take.list(A, rest, i)) 134 135 def complete.taken(-A: Data, result: Taken, n: Nat, h: H.Heap>) -> State & Maybe<&2, Ticket>: 136 match result: 137 case Taken{r, found}: 138 (State{n, h, r}, found) 139 140 def complete(-A: Data, i: Nat, s: State) -> State & Maybe<&2, Ticket>: 141 match s: 142 case State{n, h, r}: 143 complete.taken(A, take.list(A, r, i), n, h) 144 145 def requeue.found(~A: Data, found: Maybe<&2, Ticket>, d: Nat, s: State) -> State & Bool: 146 match found: 147 case None{}: 148 (s, False{}) 149 case Some{Ticket{i, old, x}}: 150 match s: 151 case State{n, h, r}: 152 (State{n, H.Heap.push(~Ticket, ~(a => b => le(A, a, b)), Ticket{i, d, x}, h), r}, True{}) 153 154 def requeue.completed(~A: Data, r: State & Maybe<&2, Ticket>, d: Nat) -> State & Bool: 155 (s, found) = r 156 requeue.found(~A, found, d, s) 157 158 def requeue(~A: Data, i: Nat, d: Nat, s: State) -> State & Bool: 159 requeue.completed(~A, complete(A, i, s), d) 160 161 # Non-consuming observations used by adapters and laws. 162 def next_id(-A: Data, s: State) -> Nat: 163 match s: 164 case State{n, h, r}: 165 n 166 167 def pending(-A: Data, s: State) -> H.Heap>: 168 match s: 169 case State{n, h, r}: 170 h 171 172 def running(-A: Data, s: State) -> List<&2, Ticket>: 173 match s: 174 case State{n, h, r}: 175 r