<<>> <> <> <> <> <> <> <> <> DIRECTORY PriorityQueue; PriorityQueueImpl: CEDAR MONITOR LOCKS pq USING pq: Ref EXPORTS PriorityQueue = BEGIN OPEN PriorityQueue; <> <> PQempty: PUBLIC ERROR = CODE; PQover: PUBLIC ERROR = CODE; IsPriorityQueue: PUBLIC PROC [ref: REF] RETURNS [BOOL] = { <<... returns TRUE iff the ref resulted from a Create operation>> WITH ref SELECT FROM pq: Ref => RETURN [TRUE]; ENDCASE => RETURN [FALSE]; }; Create: PUBLIC PROC [pred: SortPred, data: REF ¬ NIL] RETURNS [Ref] = { <<... creates a new priority queue with given sorting predicate>> pq: Ref ¬ NEW[Rep ¬ [pred: pred, data: data, size: 0, seq: NIL]]; RETURN [pq]; }; Predict: PUBLIC PROC [size: INT, pred: SortPred, data: REF ¬ NIL] RETURNS [Ref] = { <<... is just like create, but also uses a predicted size>> pq: Ref ¬ Create[pred, data]; IF size > MaxSize THEN size ¬ MaxSize; IF size > 0 THEN { seq: Seq ¬ NEW[SeqRep[size+1]]; pq.seq ¬ seq; }; pq.size ¬ 0; RETURN [pq]; }; Top: PUBLIC ENTRY PROC [pq: Ref] RETURNS [Item] = { <> IF pq.size = 0 THEN RETURN WITH ERROR PQempty; RETURN [pq.seq[1]]; }; Size: PUBLIC ENTRY PROC [pq: Ref] RETURNS [INT] = { <> RETURN [pq.size]; }; Empty: PUBLIC ENTRY PROC [pq: Ref] RETURNS [BOOL] = { <> RETURN [pq.size = 0]; }; Insert: PUBLIC ENTRY PROC [pq: Ref, item: Item] = { <<... inserts new item into the queue (signal PQover if resulting size goes over MaxSize)>> < NULL; >> size: NAT ¬ pq.size; -- figure out new size a: Seq ¬ pq.seq; -- grab the descriptor pred: SortPred ¬ pq.pred; -- and the predicate data: REF ¬ pq.data; -- and the predicate's data space: NAT ¬ IF a = NIL THEN 0 ELSE a.space; maxCard: NAT = MaxSize; -- to aid the poor little compiler <> size ¬ size + 1; IF size >= MaxSize THEN RETURN WITH ERROR PQover; <> IF size >= space THEN { seq: Seq ¬ NIL; IF space = 0 THEN space ¬ 1; SELECT space FROM < 2048 => space ¬ space + space; < maxCard-1024 => space ¬ space + 1024; ENDCASE => space ¬ MaxSize; seq ¬ NEW[SeqRep[space]]; FOR i: NAT IN [1..size) DO seq[i] ¬ a[i]; ENDLOOP; pq.seq ¬ a ¬ seq; }; { <> son: NAT ¬ size; dad: NAT ¬ son/2; WHILE dad > 0 AND pred[item, a[dad], data] DO <> a[son] ¬ a[dad]; son ¬ dad; dad ¬ son/2; ENDLOOP; a[son] ¬ item; -- finally insert the new item pq.size ¬ size; -- also update the size }; }; Remove: PUBLIC ENTRY PROC [pq: Ref] RETURNS [Item] = { <<... removes "best" item from queue (signal PQempty if empty)>> < NULL;>> size: NAT ¬ pq.size; -- current size of pq a: Seq ¬ pq.seq; -- desc to real stuff best: Item ¬ NIL; -- holder for best item item: Item ¬ NIL; -- holder for moving item pred: SortPred ¬ pq.pred; -- comparison predicate data: REF ¬ pq.data; -- and the predicate's data IF size = 0 THEN RETURN WITH ERROR PQempty; <> best ¬ a[1]; -- remember best item item ¬ a[size]; -- get moving item a[size] ¬ NIL; size ¬ size - 1; -- new size of pq pq.size ¬ size; -- also update size in pq IF size = 0 THEN RETURN [best]; <> { dad: NAT ¬ 1; -- current index for moving item maxdad: NAT ¬ size / 2; -- highest index for father item WHILE dad <= maxdad DO son: NAT ¬ dad + dad; sonItem: Item ¬ a[son]; IF son < size THEN { <> nson: NAT ¬ son + 1; nsonItem: Item ¬ a[nson]; IF pred[nsonItem, sonItem, data] THEN { son ¬ nson; sonItem ¬ nsonItem; }; }; IF pred[item, sonItem, data] THEN EXIT; a[dad] ¬ sonItem; dad ¬ son; ENDLOOP; a[dad] ¬ item; }; <> RETURN [best]; }; Copy: PUBLIC ENTRY PROC [pq: Ref] RETURNS [Ref] = { <<... returns copy of queue>> ENABLE UNWIND => NULL; size: NAT ¬ pq.size; npq: Ref ¬ Predict[size, pq.pred, pq.data]; src: Seq ¬ pq.seq; dst: Seq ¬ npq.seq; FOR i: NAT IN [1..size) DO dst[i] ¬ src[i]; ENDLOOP; npq.size ¬ size; RETURN [npq]; }; END.