(* The Great Win32 Language Shootout http://dada.perl.it/shootout/ contributed by Isaac Gouy (Modula2 novice) To compile: xc =m lists To run: lists 16 *) MODULE Lists; <* m2extensions + *> <* storage + *> (* Prefer unqualified procedures *) FROM LanguageShootout IMPORT N; FROM STextIO IMPORT WriteString, WriteLn; FROM SWholeIO IMPORT WriteCard; (* We need an ADT let's implement a double-linked list *) TYPE Node_Ptr = POINTER TO Queue_Node; Queue_Node = RECORD prev, next: Node_Ptr; item: CARDINAL; END; Queue_Ptr = POINTER TO Queue_Type; Queue_Type = RECORD first, last: Node_Ptr; length: CARDINAL; END; Queue_Positions = (First, Last); VAR node, node2: Node_Ptr; PROCEDURE Initialize(VAR q: Queue_Ptr); BEGIN NEW(q); q^.length := 0; q^.first := NIL; q^.last := NIL; END Initialize; PROCEDURE Add(position: Queue_Positions; VAR q: Queue_Ptr; item: CARDINAL); BEGIN NEW(node); node^.item := item; INC(q^.length); IF q^.length = 1 THEN node^.prev := NIL; node^.next := NIL; q^.first := node; q^.last := node; ELSE IF position = First THEN node^.prev := NIL; node^.next := q^.first; q^.first^.prev := node; q^.first := node; ELSE node^.prev := q^.last; node^.next := NIL; q^.last^.next := node; q^.last := node; END; END; END Add; PROCEDURE Remove(position: Queue_Positions; VAR q: Queue_Ptr): CARDINAL; VAR item: CARDINAL; BEGIN IF q^.length = 0 THEN RETURN 0; END; IF position = First THEN node := q^.first; ELSE node := q^.last; END; item := node^.item; DEC(q^.length); IF q^.length = 0 THEN q^.first := NIL; q^.last := NIL; ELSE IF position = First THEN q^.first := node^.next; q^.first^.prev := NIL; ELSE q^.last := node^.prev; q^.last^.next := NIL; END; END; DISPOSE(node); RETURN item; END Remove; PROCEDURE Dispose(VAR q: Queue_Ptr); BEGIN WHILE q^.first # NIL DO node := q^.first^.next; DISPOSE(q^.first); q^.first := node; END; DISPOSE(q); END Dispose; PROCEDURE Copy(q: Queue_Ptr; VAR qcopy: Queue_Ptr); BEGIN node2 := q^.first ; WHILE node2 # NIL DO Add(Last, qcopy, node2^.item); node2 := node2^.next; END; END Copy; PROCEDURE Reverse(VAR q: Queue_Ptr); BEGIN node := q^.first; q^.first := q^.last; q^.last := node; WHILE node # NIL DO node2 := node^.next; node^.next := node^.prev; node^.prev := node2; node := node2; END; END Reverse; PROCEDURE Length(q: Queue_Ptr): CARDINAL; BEGIN RETURN q^.length; END Length; PROCEDURE FirstItem(q: Queue_Ptr): CARDINAL; BEGIN IF q^.length = 0 THEN RETURN 0; ELSE RETURN q^.first^.item; END; END FirstItem; PROCEDURE Equal(q,q2: Queue_Ptr): BOOLEAN; BEGIN IF q^.length # q2^.length THEN RETURN FALSE; END; node := q^.first; node2 := q2^.first; WHILE node # NIL DO IF node^.item # node2^.item THEN RETURN FALSE; END; node := node^.next; node2 := node2^.next; END; RETURN TRUE; END Equal; CONST SIZE = 10000; VAR L1, L2, L3: Queue_Ptr; i, m, n, lengthL1: CARDINAL; BEGIN n := N(); FOR m := 1 TO n DO NEW(L1); Initialize(L1); FOR i := 1 TO SIZE DO Add(Last, L1, i); END; NEW(L2); Initialize(L2); Copy(L1, L2); NEW(L3); Initialize(L3); WHILE Length(L2) > 0 DO Add(Last, L3, ( Remove(First, L2)) ); END; WHILE Length(L3) > 0 DO Add(Last, L2, ( Remove(Last, L3) )); END; Reverse(L1); IF FirstItem(L1) # SIZE THEN WriteString("First item of L1 # SIZE"); WriteLn; END; IF NOT Equal(L1, L2) THEN WriteString("L1 # L2"); WriteLn; END; lengthL1 := Length(L1); Dispose(L1); Dispose(L2); Dispose(L3); END; WriteCard(lengthL1,1); WriteLn; END Lists.