Copyright (C) 1994, Digital Equipment Corp.
GENERIC MODULE Sequence(Elem, Seq, Rep);
Where Seq = Sequence(Elem)
and Rep = SequenceRep(Elem, Seq)
.
REVEAL Seq.T = Rep.Public BRANDED Seq.Brand OBJECT
OVERRIDES
init := Init;
fromArray := FromArray;
addhi := Addhi;
addlo := Addlo;
remhi := Remhi;
remlo := Remlo;
put := Put;
size := Size;
gethi := Gethi;
getlo := Getlo;
get := Get
END;
VAR zero: Elem.T;
Modula-3 requires zero
to be initialized to a value of type Elem.T
.
With high probability the references within that value will be NIL.
Hence, setting elements of the sequence to zero
should avoid
storage leaks.
PROCEDURE Init(s: Seq.T; sizeHint: CARDINAL): Seq.T =
BEGIN
IF s.elem = NIL OR NUMBER(s.elem^) = 0 THEN
s.elem := NEW(Rep.RefArray, MAX(sizeHint, 1))
END (* IF *);
s.sz := 0; s.st := 0;
RETURN s
END Init;
PROCEDURE FromArray(s: Seq.T; READONLY a: ARRAY OF Elem.T): Seq.T =
BEGIN
s.sz := NUMBER(a);
s.st := 0;
s.elem := NEW(Rep.RefArray, MAX(s.sz, 1));
FOR i := 0 TO s.sz-1 DO
s.elem[i] := a[i]
END;
RETURN s
END FromArray;
PROCEDURE Addhi(s: Seq.T; READONLY x: Elem.T) =
BEGIN
IF s.sz = NUMBER(s.elem^) THEN Expand(s) END;
VAR i := s.st + s.sz; BEGIN
IF i >= NUMBER(s.elem^) THEN i := i - NUMBER(s.elem^) END;
s.elem[i] := x
END;
INC(s.sz)
END Addhi;
PROCEDURE Addlo(s: Seq.T; READONLY x: Elem.T) =
BEGIN
IF s.sz = NUMBER(s.elem^) THEN Expand(s) END;
VAR i := s.st; BEGIN
IF i = 0 THEN i := LAST(s.elem^) ELSE i := i - 1 END;
s.elem[i] := x;
s.st := i
END;
INC(s.sz)
END Addlo;
PROCEDURE Expand(s: Seq.T) =
VAR
n := NUMBER(s.elem^);
new := NEW(Rep.RefArray, 2 * n);
m := n - s.st;
BEGIN
SUBARRAY(new^, 0, m) := SUBARRAY(s.elem^, s.st, m);
SUBARRAY(new^, m, s.st) :=
SUBARRAY(s.elem^, 0, s.st);
s.st := 0;
s.elem := new
END Expand;
PROCEDURE Remhi(s: Seq.T): Elem.T =
VAR
j := s.st + s.sz - 1;
res: Elem.T;
BEGIN
IF j >= NUMBER(s.elem^) THEN j := j - NUMBER(s.elem^) END;
DEC(s.sz);
WITH z = s.elem[j] DO res := z; z := zero; END;
RETURN res;
END Remhi;
PROCEDURE Remlo(s: Seq.T): Elem.T =
VAR res: Elem.T;
BEGIN
WITH z = s.elem[s.st] DO res := z; z := zero; END;
DEC(s.sz);
INC(s.st);
IF s.st = NUMBER(s.elem^) THEN s.st := 0 END;
RETURN res
END Remlo;
PROCEDURE Put(s: Seq.T; i: CARDINAL; READONLY x: Elem.T) =
VAR j := s.st + i; BEGIN
<* ASSERT i < s.sz *>
IF j >= NUMBER(s.elem^) THEN j := j - NUMBER(s.elem^) END;
s.elem[j] := x
END Put;
PROCEDURE Get(s: Seq.T; i: CARDINAL): Elem.T =
VAR j := s.st + i; BEGIN
<* ASSERT i < s.sz *>
IF j >= NUMBER(s.elem^) THEN j := j - NUMBER(s.elem^) END;
RETURN s.elem[j]
END Get;
PROCEDURE Size(s: Seq.T): CARDINAL =
BEGIN
RETURN s.sz
END Size;
PROCEDURE Gethi(s: Seq.T): Elem.T =
VAR j := s.st + s.sz - 1; BEGIN
<* ASSERT s.sz > 0 *>
IF j >= NUMBER(s.elem^) THEN
j := j - NUMBER(s.elem^)
END;
RETURN s.elem[j]
END Gethi;
PROCEDURE Getlo(s: Seq.T): Elem.T =
BEGIN
<* ASSERT s.sz > 0 *>
RETURN s.elem[s.st]
END Getlo;
PROCEDURE Cat(s, t: T): T =
VAR u := NEW(Seq.T); BEGIN
u.sz := s.sz + t.sz;
u.elem := NEW(Rep.RefArray, MAX(u.sz, 1));
FOR i := 0 TO s.sz-1 DO
u.elem[i] := s.get(i)
END;
FOR i := 0 TO t.sz-1 DO
u.elem[i + s.sz] := t.get(i)
END;
RETURN u
END Cat;
PROCEDURE Sub(s: T; start: CARDINAL;
length: CARDINAL := LAST(CARDINAL)): T =
VAR u := NEW(Seq.T); BEGIN
IF start >= s.sz OR length = 0 THEN
u.sz := 0
ELSE
u.sz := MIN(length, s.sz - start)
END;
u.elem := NEW(Rep.RefArray, MAX(u.sz, 1));
FOR i := 0 TO u.sz-1 DO
u.elem[i] := s.get(start + i)
END;
RETURN u
END Sub;
BEGIN
END Sequence.