Sort:
PUBLIC
PROC [list:
LIST
OF
REF
ANY, compareProc: CompareProc]
RETURNS [LIST OF REF ANY] = {
The sort is destructive and NOT stable, that is, the relative positions in the result of
nodes with equal keys is unpredictible. For a nondestructive sort, copy l first.
The sort does one CONS.
a, b, mergeTo: LIST OF REF ANY;
mergeToCons: LIST OF REF ANY = CONS[NIL, NIL];
max: CARDINAL = 22; --number of bits in word-address space minus 2
lists:
ARRAY [0..max)
OF
LIST
OF
REF
ANY ←
ALL [
NIL];
lists[0] is a sorted list of length 2 or NIL, lists[1] is a sorted list of length
4 or NIL, lists[2] is a sorted list of length 8 or NIL, etc.
When Sort returns, lists = ALL [NIL] again (we do some extra work to assure this).
x: CARDINAL; --[0..max]
xMax: CARDINAL ← 0; --[0..max)
make each pair of consecutive elements of l into a sorted list of length 2,
then merge it into lists.
UNTIL (a ← list) =
NIL
OR (b ← a.rest) =
NIL
DO
list ← b.rest;
IF compareProc[a.first, b.first] = less
THEN {
a.rest ← b;
b.rest ← NIL;
}
ELSE {
b.rest ← a;
a.rest ← NIL;
a ← b;
};
x ← 0;
DO
IF (b ← lists[x]) =
NIL
THEN {
lists[x] ← a; EXIT }
ELSE {
--merge (equal length) lists a and b
lists[x] ← NIL;
mergeTo ← mergeToCons;
DO
--assert a#NIL, b#NIL
IF compareProc[a.first, b.first] = less
THEN {
mergeTo.rest ← a; mergeTo ← a;
IF (a ← a.rest) = NIL THEN { mergeTo.rest ← b; EXIT } }
ELSE {
mergeTo.rest ← b; mergeTo ← b;
IF (b ← b.rest) = NIL THEN { mergeTo.rest ← a; EXIT } }
ENDLOOP;
a ← mergeToCons.rest;
x ← x+1;
IF x > xMax AND (xMax ← x) = max THEN ERROR }
ENDLOOP;
ENDLOOP;
xMax now contains the largest x such that lists[x] # NIL.
if l's length was even, a = NIL; if l's length was odd, a = single element list.
merge a and elements of lists into result (held in a).
x ← 0;
IF a =
NIL
THEN {
try to make a # NIL.
UNTIL (lists[x] # NIL OR x = xMax) DO x ← x+1 ENDLOOP;
a ← lists[x]; lists[x] ← NIL; x ← x+1 };
a # NIL OR x > xMax.
UNTIL x > xMax
DO
IF (b ← lists[x]) #
NIL
THEN {
lists[x] ← NIL;
mergeTo ← mergeToCons;
DO
a#NIL AND b#NIL
IF compareProc[a.first, b.first] = less
THEN {
mergeTo.rest ← a; mergeTo ← a;
IF (a ← a.rest) = NIL THEN { mergeTo.rest ← b; EXIT } }
ELSE {
mergeTo.rest ← b; mergeTo ← b;
IF (b ← b.rest) = NIL THEN { mergeTo.rest ← a; EXIT } }
ENDLOOP;
a ← mergeToCons.rest };
x ← x+1;
ENDLOOP;
RETURN [a]
}; --Sort
UniqueSort:
PUBLIC
PROC [list:
LIST
OF
REF
ANY, compareProc: CompareProc]
RETURNS[
LIST
OF
REF
ANY] = {
l: LIST OF REF ANY;
IF list = NIL THEN RETURN[NIL];
l ← list ← Sort[list, compareProc];
DO
IF l.rest = NIL THEN EXIT;
IF compareProc[l.first, l.rest.first] = equal THEN l.rest ← l.rest.rest
ELSE l ← l.rest;
ENDLOOP;
RETURN[list];
};
Compare:
PUBLIC CompareProc = {
IF ref1 =
NIL
THEN
RETURN[Rope.Compare[s1: NARROW[ref1, ROPE], s2: NARROW[ref2, ROPE], case: TRUE]];
WITH ref1
SELECT
FROM
rope: ROPE => RETURN[Rope.Compare[s1: rope, s2: NARROW[ref2, ROPE], case: TRUE]];
rli: REF INT => RETURN[CompareINT[rli^, NARROW[ref2, REF INT]^]];
atom: ATOM => RETURN[Rope.Compare[s1: Atom.GetPName[atom], s2: Atom.GetPName[NARROW[ref2, ATOM]], case: TRUE]];
ENDCASE => ERROR
};