JunoStorageImpl.mesa
Coded June 81 by Greg Nelson.
Last edited by GNelson (?) January 19, 1984 1:52 pm
Last edited by Stolfi June 2, 1984 8:14:56 am PDT

Defines record types, allocation and deallocation functions.

TO FIX: Is it necessary for it to be a monitor?.

TO FIX: Frames in constraints --- pass them to NewXXX procedures?.

DIRECTORY

JunoStorage;

JunoStorageImpl: MONITOR

EXPORTS JunoStorage =

BEGIN OPEN JunoStorage;

- - - - POINTS

pointAvail: Point ← NIL;

nPoints, mPoints: INT ← 0;
nPoints counts calls to NewPoint, mPoints counts actual allocations

NewPoint
: PUBLIC ENTRY PROC [coords: Coords, visible: BOOLFALSE] RETURNS [p: Point] =

BEGIN
IF pointAvail = NIL THEN
THROUGH [1..50] DO
pointAvail ← NEW [PointRec ← [link: pointAvail]];
mPoints ← mPoints+1
ENDLOOP;
p ← pointAvail;
pointAvail ← pointAvail.link;
p.link ← NIL;
p^ ← [coords: coords, visible: visible, link: NIL];
nPoints ← nPoints+1
END;

DeletePoint
: PUBLIC PROC [p, ant: Point, list: PointList] RETURNS [newList: PointList] =

BEGIN
IF p = list.first THEN
{IF ant # NIL THEN ERROR;
newList.first ← p.link}
ELSE
{IF ant = NIL THEN
{ant ← list.first;
WHILE ant.link # p DO ant ← ant.link ENDLOOP}
ELSE
{IF ant.link # p THEN ERROR};
ant.link ← p.link;
newList.first ← list.first};
newList.last ← IF p = list.last THEN ant ELSE list.last;
p.link ← NIL
END;

InsertPoint
: PUBLIC PROC [p, ant: Point, list: PointList] RETURNS [newList: PointList] =

BEGIN
IF ant = NIL THEN
{p.link ← list.first;
newList.first ← p}
ELSE
{p.link ← ant.link;
ant.link ← p;
newList.first ← list.first};
newList.last ← IF p.link = NIL THEN p ELSE list.last
END;

GcPoints
: PUBLIC PROC [start: Point, lim: Point ← NIL] =

BEGIN
t: Point;
GcIt: ENTRY PROC [p: Point] = {p^ ← [link: pointAvail]; pointAvail ← p};
WHILE start # lim DO
t ← start.link; GcIt[start]; start ← t
ENDLOOP
END;

- - - - CONSTRAINTS

constrAvail: ARRAY ConstrKind OF Constr ← ALL[NIL];

nConstrs, mConstrs: ARRAY ConstrKind OF INTALL[0];
nConstrs counts total allocations, mConstrs counts max in use at same time

NewConstr: ENTRY PROC [kind: ConstrKind] RETURNS [cp: Constr] =

BEGIN
IF constrAvail[kind] = NIL THEN

BEGIN -- Create a bunch of new records
t: Constr;
THROUGH [1..50] DO
t ← constrAvail[kind];
constrAvail[kind] ←
SELECT kind FROM
ver => NEW[ver ConstrRec],
ccw => NEW[ccw ConstrRec],
para => NEW[para ConstrRec],
perp => NEW[perp ConstrRec],
cong => NEW[cong ConstrRec],
at => NEW[at ConstrRec],
hor => NEW[hor ConstrRec],
ENDCASE => ERROR;
constrAvail[kind].link ← t;
mConstrs[kind] ← mConstrs[kind]+1
ENDLOOP
END;

cp ← constrAvail[kind];
constrAvail[kind] ← constrAvail[kind].link;
cp.link ← NIL;
nConstrs[kind] ← nConstrs[kind]+1
END;

DeleteConstr: PUBLIC PROC [c, ant: Constr, list: ConstrList] RETURNS [newList: ConstrList] =

BEGIN
IF c = list.first THEN
{IF ant # NIL THEN ERROR;
newList.first ← c.link}
ELSE
{IF ant = NIL THEN
{ant ← list.first;
WHILE ant.link # c DO ant ← ant.link ENDLOOP}
ELSE
{IF ant.link # c THEN ERROR};
ant.link ← c.link;
newList.first ← list.first};
newList.last ← IF c = list.last THEN ant ELSE list.last;
c.link ← NIL
END;

InsertConstr: PUBLIC PROC [c, ant: Constr, list: ConstrList] RETURNS [newList: ConstrList] =

BEGIN
IF ant = NIL THEN
{c.link ← list.first;
newList.first ← c}
ELSE
{c.link ← ant.link;
ant.link ← c;
newList.first ← list.first};
newList.last ← IF c.link = NIL THEN c ELSE list.last
END;

GcConstrs: PUBLIC PROC [start: Constr, lim: Constr ← NIL] =

BEGIN
t: Constr;
GcIt: ENTRY PROC [c: Constr] = {c.link ← constrAvail[c.kind]; constrAvail[c.kind] ← c};
WHILE start # lim DO
t ← start.link;
GcIt[start];
start ← t
ENDLOOP
END;

NewHor: PUBLIC PROC [i,j: Point]
RETURNS [cp: HorConstr] =

BEGIN
IF i = NIL OR j = NIL THEN ERROR;
cp ← NARROW [NewConstr[hor]];
cp.i ← i;
cp.j ← j
END;

NewVer: PUBLIC PROC [i,j: Point]
RETURNS [cp: VerConstr] =

BEGIN
IF i = NIL OR j = NIL THEN ERROR;
cp ← NARROW [NewConstr[ver]];
cp.i ← i;
cp.j ← j;
END;

NewPara: PUBLIC PROC [i,j,k,l: Point]
RETURNS [cp: ParaConstr] =

BEGIN
IF i = NIL OR j = NIL OR k = NIL OR l=NIL THEN ERROR;
cp ← NARROW [NewConstr[para]];
cp.i ← i;
cp.j ← j;
cp.k ← k;
cp.l ← l
END;

NewPerp: PUBLIC PROC [i,j,k,l: Point]
RETURNS [cp: PerpConstr] =

BEGIN
IF i = NIL OR j = NIL OR k = NIL OR l=NIL THEN ERROR;
cp ← NARROW [NewConstr[perp]];
cp.i ← i;
cp.j ← j;
cp.k ← k;
cp.l ← l
END;

NewCong: PUBLIC PROC [i,j,k,l: Point]
RETURNS [cp: CongConstr] =

BEGIN
IF i = NIL OR j = NIL OR k = NIL OR l=NIL THEN ERROR;
cp ← NARROW [NewConstr[cong]];
cp.i ← i;
cp.j ← j;
cp.k ← k;
cp.l ← l
END;

NewAt: PUBLIC PROC [p: Point, coords: Coords]
RETURNS [cp: AtConstr] =

BEGIN
IF p = NIL THEN ERROR;
cp ← NARROW [NewConstr[at]];
cp.p ← p;
cp.coords ← coords;
END;

NewCcw: PUBLIC PROC [i,j,k: Point]
RETURNS [cp: CcwConstr] =

BEGIN
IF i = NIL OR j = NIL OR k = NIL THEN ERROR;
cp ← NARROW [NewConstr[ccw]];
cp.i ← i;
cp.j ← j;
cp.k ← k
END;

- - - - ACTIONS

actionAvail: Action ← NIL;

nActions, mActions: INT ← 0;
nActions counts total allocations, mActions counts max in use at same time

NewAction: PUBLIC ENTRY PROC [kind: ActionKind, args: ActionArgs]
RETURNS [ap: Action] =

BEGIN
IF actionAvail = NIL THEN

BEGIN
t: Action;
THROUGH [1..50] DO
t ← actionAvail;
actionAvail ← NEW[ActionRec];
actionAvail.link ← t;
mActions ← mActions + 1
ENDLOOP
END;

ap ← actionAvail;
actionAvail ← actionAvail.link;
ap^ ← [link: NIL, kind: kind, args: args];
nActions ← nActions+1
END;

DeleteAction: PUBLIC PROC [a, ant: Action, list: ActionList] RETURNS [newList: ActionList] =

BEGIN
IF a = list.first THEN
{IF ant # NIL THEN ERROR;
newList.first ← a.link}
ELSE
{IF ant = NIL THEN
{ant ← list.first;
WHILE ant.link # a DO ant ← ant.link ENDLOOP}
ELSE
{IF ant.link # a THEN ERROR};
ant.link ← a.link;
newList.first ← list.first};
newList.last ← IF a = list.last THEN ant ELSE list.last;
a.link ← NIL
END;

InsertAction: PUBLIC PROC [a, ant: Action, list: ActionList] RETURNS [newList: ActionList] =

BEGIN
IF ant = NIL THEN
{a.link ← list.first;
newList.first ← a}
ELSE
{a.link ← ant.link;
ant.link ← a;
newList.first ← list.first};
newList.last ← IF a.link = NIL THEN a ELSE list.last
END;

GcActions: PUBLIC PROC [start: Action, lim: Action ← NIL] =

BEGIN
t: Action;
GcIt: ENTRY PROC [a: Action] =
{a^ ← [link: actionAvail, kind: draw, args: NIL]; actionAvail ← a};
WHILE start # lim DO
t ← start.link;
GcList[start.args, NIL];
GcIt[start];
start ← t
ENDLOOP
END;

- - - - LISTS

listAvail: List ← NIL;

nLists, mLists: INT ← 0;
nLists counts total list cell allocations, mLists counts max in use at same time

Cons: PUBLIC ENTRY PROC [first: REF ANY, rest: List] RETURNS [cons: List] =

BEGIN
IF listAvail = NIL THEN

BEGIN
THROUGH [1..100] DO
listAvail ← CONS[NIL, listAvail];
mLists ← mLists+1
ENDLOOP
END;

cons ← listAvail;
listAvail ← listAvail.rest;
cons.first ← first; cons.rest ← rest;
nLists ← nLists+1
END;

GcList: PUBLIC PROC [start: LIST OF REF ANY, lim: LIST OF REF ANYNIL] =

BEGIN
t: LIST OF REF ANY;
GcIt: ENTRY PROC [s: LIST OF REF ANY] = {s.first ← NIL; s.rest ← listAvail; listAvail ← s};
WHILE start # lim DO
t ← start.rest;
GcIt[start];
start ← t
ENDLOOP
END;

- - - - INITIALIZATION

InitStorage: PROC =
Allocator warming-up exercises

BEGIN
GcPoints[NewPoint[[0, 0]], NIL];
FOR kind: ConstrKind IN ConstrKind DO
GcConstrs[NewConstr[kind], NIL]
ENDLOOP;
GcActions[NewAction[kind: draw, args: NIL], NIL];
GcList[Cons[NIL, NIL], NIL]
END;

InitStorage[]

END.