-- LeftFeaturePQImpl.mesa -- A generic package to organize items -- in a priority queue, sorted by increasing order -- according to ValLess. -- last modified by E. McCreight, September 27, 1984 12:15 PM -- written by E. McCreight, February 8, 1982 2:04 PM DIRECTORY InlineDefs, LeftFeaturePQ; LeftFeaturePQImpl: PROGRAM IMPORTS InlineDefs, LeftFeaturePQ EXPORTS LeftFeaturePQ SHARES LeftFeaturePQ = BEGIN OPEN LeftFeaturePQ; LeftFeaturePQUnderflow: PUBLIC SIGNAL = CODE; NewLeftFeaturePQ: PUBLIC PROCEDURE[zone: UNCOUNTED ZONE, max: CARDINAL ← 50] RETURNS[PQHandle] = BEGIN p: PQHandle ← zone.NEW[PQObject ← [zone: zone]]; p.s[0] ← zone.NEW[PQSeq[max]]; RETURN[p]; END; DestroyLeftFeaturePQ: PUBLIC PROCEDURE[p: PQHandle] RETURNS[PQHandle] = BEGIN zone: UNCOUNTED ZONE ← p.zone; FOR i: [0..maxNSeqs) IN [0..p.topSeq) DO zone.FREE[@p.s[i]] ENDLOOP; zone.FREE[@p]; RETURN[NIL]; END; -- of DestroyLeftFeaturePQ InsertLeftFeaturePQ: PUBLIC PROCEDURE[p: PQHandle, item: Item] = BEGIN GrowingPQ[p]; CheckPQ[p]; p.size ← p.size+1; IF p.topSeq=0 THEN BEGIN pqs: PQSeqPtr ← p.s[0]; i, j: CARDINAL; FOR j ← InlineDefs.LowHalf[p.size]-1, i WHILE j>0 DO i ← (j-1)/2; IF NOT ValLess[item, pqs[i]] THEN EXIT ELSE pqs[j] ← pqs[i]; ENDLOOP; pqs[j] ← item; END ELSE BEGIN i, j: LONG INTEGER; FOR j ← p.size-1, i WHILE j>0 DO i ← (j-1)/2; IF NOT ValLess[item, GetItem[p, i]] THEN EXIT ELSE SetItem[p, j, GetItem[p, i]]; ENDLOOP; SetItem[p, j, item]; END; CheckPQ[p]; END; ExtractLeftFeaturePQ: PUBLIC PROCEDURE[p: PQHandle] RETURNS[item: Item] = BEGIN result: Item ← p.s[0][0]; ShrinkingPQ[p]; CheckPQ[p]; IF (p.size ← p.size-1)>0 THEN BEGIN IF p.topSeq=0 THEN BEGIN pqs: PQSeqPtr ← p.s[0]; i, j: CARDINAL; r: CARDINAL ← InlineDefs.LowHalf[p.size]-1; -- max index item: Item ← pqs[InlineDefs.LowHalf[p.size]]; FOR i ← 0, j DO j ← i+i+1; IF j>r THEN EXIT; IF j<r AND ValLess[pqs[j+1], pqs[j]] THEN j ← j+1; IF NOT ValLess[pqs[j], item] THEN EXIT ELSE pqs[i] ← pqs[j]; ENDLOOP; pqs[i] ← item; END ELSE BEGIN i, j: LONG INTEGER; r: LONG INTEGER ← p.size-1; -- max index item: Item ← GetItem[p, p.size]; FOR i ← 0, j DO j ← i+i+1; IF j>r THEN EXIT; IF j<r AND ValLess[GetItem[p, j+1], GetItem[p, j]] THEN j ← j+1; IF NOT ValLess[GetItem[p, j], item] THEN EXIT ELSE SetItem[p, i, GetItem[p, j]]; ENDLOOP; SetItem[p, i, item]; END; END; CheckPQ[p]; RETURN[result]; END; MapEqualLeftFeaturePQ: PUBLIC PROCEDURE[p: PQHandle, proc: PROCEDURE[item: Item]] = BEGIN pqs: PQSeqPtr ← p.s[0]; stack: ARRAY[1..20) OF LONG INTEGER; stackTop: [0..20) ← 1; stack[stackTop] ← 0; WHILE 0<stackTop DO i: LONG INTEGER ← stack[stackTop]; item: Item; IF p.size<=i OR ValLess[pqs[0], (item ← GetItem[p, i])] THEN stackTop ← stackTop-1 ELSE BEGIN proc[item]; stack[stackTop] ← i+i+1; stackTop ← stackTop+1; stack[stackTop] ← i+i+2; END; ENDLOOP; END; -- of MapEqualLeftFeaturePQ DeleteEqualLeftFeaturePQ: PUBLIC PROCEDURE[p: PQHandle] = BEGIN original: Item ← p.s[0][0]; IF p.topSeq=0 THEN BEGIN size: CARDINAL ← InlineDefs.LowHalf[p.size]; pqs: PQSeqPtr ← p.s[0]; WHILE 0<size AND NOT ValLess[original, pqs[0]] DO i, j: CARDINAL; r: CARDINAL ← (size ← size-1); -- max index item: Item ← pqs[size]; FOR i ← 0, j DO j ← i+i+1; IF j>r THEN EXIT; IF j<r AND ValLess[pqs[j+1], pqs[j]] THEN j ← j+1; IF NOT ValLess[pqs[j], item] THEN EXIT ELSE pqs[i] ← pqs[j]; ENDLOOP; pqs[i] ← item; ENDLOOP; p.size ← size+1; [] ← ShrinkingPQ[p]; p.size ← size; END ELSE WHILE 0<p.size AND NOT ValLess[original, p.s[0][0]] DO [] ← ExtractLeftFeaturePQ[p]; ENDLOOP; END; -- of DeleteEqualLeftFeaturePQ GrowingPQ: PROCEDURE[p: PQHandle] = BEGIN IF p.size>=p.topSeq*maxItemsPerSeq+p.s[p.topSeq].max THEN BEGIN IF p.s[p.topSeq].max=maxItemsPerSeq THEN BEGIN -- new sequence p.topSeq ← p.topSeq+1; p.s[p.topSeq] ← p.zone.NEW[PQSeq[maxItemsPerSeq/2]]; END ELSE BEGIN -- lengthen existing sequence oldSeq: PQSeqPtr ← p.s[p.topSeq]; newSeq: PQSeqPtr ← p.zone.NEW[PQSeq[(IF p.topSeq>0 THEN maxItemsPerSeq ELSE MIN[maxItemsPerSeq, MAX[50, InlineDefs.LowHalf[(LONG[15]*p.size)/10]]])]]; FOR i: CARDINAL IN [0..InlineDefs.LowHalf[p.size MOD maxItemsPerSeq]) DO newSeq[i] ← oldSeq[i]; ENDLOOP; p.s[p.topSeq] ← newSeq; p.zone.FREE[@oldSeq]; END; END; END; ShrinkingPQ: PROCEDURE[p: PQHandle] = BEGIN WHILE p.size<1 DO SIGNAL LeftFeaturePQUnderflow ENDLOOP; IF p.topSeq>0 THEN BEGIN IF p.size < p.topSeq*maxItemsPerSeq-maxItemsPerSeq/2 THEN BEGIN -- get rid of entire top sequence END; END ELSE BEGIN IF MAX[p.size, 50]< p.s[0].max/2 THEN BEGIN -- shorten the (single) sequence oldSeq: PQSeqPtr ← p.s[0]; newSeq: PQSeqPtr ← p.zone.NEW[PQSeq[MAX[ InlineDefs.LowHalf[(LONG[15]*p.size)/10], 50]]]; FOR i: CARDINAL IN [0..InlineDefs.LowHalf[p.size]) DO newSeq[i] ← oldSeq[i]; ENDLOOP; p.s[0] ← newSeq; p.zone.FREE[@oldSeq]; END; END; END; GetItem: PROCEDURE [p: PQHandle, i: LONG INTEGER] RETURNS [item: Item] = BEGIN RETURN[p.s[InlineDefs.LowHalf[i/maxItemsPerSeq]][InlineDefs.LowHalf[i MOD maxItemsPerSeq]]]; END; SetItem: PROCEDURE [p: PQHandle, i: LONG INTEGER, item: Item] = BEGIN p.s[InlineDefs.LowHalf[i/maxItemsPerSeq]][InlineDefs.LowHalf[i MOD maxItemsPerSeq]] ← item; END; CheckPQ: PROCEDURE[p: PQHandle] = {NULL}; -- or DoCheckPQ[p] for checking PQDisorder: SIGNAL = CODE; DoCheckPQ: PROCEDURE[p: PQHandle] = BEGIN FOR i: LONG INTEGER IN [0..p.size/2) DO IF ValLess[GetItem[p, 2*i+1], GetItem[p, i]] OR ((2*i+2<p.size) AND ValLess[GetItem[p, 2*i+2], GetItem[p, i]]) THEN SIGNAL PQDisorder; ENDLOOP; END; END. -- of LeftFeaturePQImpl