ScheduleImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Christian LeCocq October 20, 1986 3:39:33 pm PDT
History management package
CreateHistory:
PUBLIC PROC [t: ps, v:
REAL]
RETURNS [newHistory: History] ~ {
newHistory ← LIST[[t, v]];
};
KillHistory:
PUBLIC PROC [history: History] ~ {
h: History;
UNTIL history=
NIL
DO
h ← history;
history ← history.rest;
h.rest ← NIL;
ENDLOOP;
};
AddToHistory:
PUBLIC
PROC [oldHistory: History, t: ps, v:
REAL]
RETURNS [newHistory: History] ~ {
last, prev: History;
historyPt: HistoryPt ← [t, v];
newHistory ← oldHistory;
FOR ih: History ← oldHistory, ih.rest
UNTIL ih=
NIL
DO
IF ih.first.t>=t
THEN {
--if t occurs before the end of the current history then
ih.first ← historyPt; -- change the present and delete the "old future".
ih.rest ← NIL;
IF prev#NIL THEN IF prev.first.v=last.first.v AND prev.first.v=v THEN prev.rest ← last.rest;
RETURN;
};
prev ← last;
last ← ih;
ENDLOOP;
last.rest ← LIST[historyPt];
IF prev#NIL THEN IF prev.first.v=last.first.v AND prev.first.v=v THEN prev.rest ← last.rest;
};
ForgetBeginings:
PUBLIC PROC [oldHistory: History, t: ps]
RETURNS [newHistory: History] ~ {
newHistory ← oldHistory;
FOR ih: History ← oldHistory, ih.rest
UNTIL ih.rest=
NIL
DO
IF ih.rest.first.t>t
THEN {
newHistory ← ih;
RETURN;
};
ENDLOOP;
};
ForgetBeginings: PUBLIC PROC [oldHistory: History, t: ps] RETURNS [newHistory: History] ~ {
newHistory ← oldHistory;
FOR ih: History ← oldHistory, ih.rest UNTIL ih.rest=NIL DO
newHistory ← ih;
IF ih.rest.first.t>t THEN {
v: REAL ← VFromHistory[ih, t];
ih.first.v ← v;
ih.first.t ← t;
RETURN;
};
ENDLOOP;
};
FirstTimeOfHistory:
PUBLIC PROC [history: History]
RETURNS [t: ps] ~ {
t ← history.first.t
};
NextTimeOfHistory:
PUBLIC PROC [history: History, t: ps]
RETURNS [tnext: ps ← -1e30] ~ {
FOR ih: History ← history, ih.rest
UNTIL ih=
NIL
DO
IF ih.first.t>=t THEN RETURN[ih.first.t];
ENDLOOP;
};
LastTimeOfHistory:
PUBLIC PROC [history: History]
RETURNS [t: ps] ~ {
FOR ih: History ← history, ih.rest
UNTIL ih.rest=
NIL
DO REPEAT
FINISHED => t ← ih.first.t;
ENDLOOP;
};
LastValueOfHistory:
PUBLIC PROC [history: History]
RETURNS [v:
REAL] ~ {
FOR ih: History ← history, ih.rest
UNTIL ih.rest=
NIL
DO REPEAT
FINISHED => v ← ih.first.v;
ENDLOOP;
};
VFromHistory:
PUBLIC
PROC [history: History, t: ps]
RETURNS [v:
REAL] ~ {
t0: ps;
v0: REAL;
IF t < history.first.t THEN ERROR; -- Why should you return to the past ?
IF t=history.first.t THEN RETURN[history.first.v];
FOR ih: History ← history, ih.rest
UNTIL ih=
NIL
DO
IF t<=ih.first.t
THEN {
v ← v0 + (ih.first.v - v0)*(t-t0) /(ih.first.t - t0);
RETURN;
};
v0 ← ih.first.v;
t0 ← ih.first.t;
REPEAT
FINISHED => v ← v0;
ENDLOOP;
};
EnumerateHistory:
PUBLIC PROC [history: History, from, to: ps, action: HistoryProc]
RETURNS [invalidEnumeration:
BOOL ←
FALSE] ~ {
quit: BOOLEAN ← FALSE;
FOR ih: History ← history, ih.rest
UNTIL ih=
NIL
OR quit
OR ih.first.t>to
DO
IF ih.first.t>=from THEN quit ← action[ih.first.t, ih.first.v];
ENDLOOP;
};
Schedule:
PUBLIC PROC [hList:
LIST
OF History]
RETURNS [lt:
LIST
OF ps] ~ {
t: ps;
h: LIST OF History;
endlt: LIST OF ps;
finished: BOOLEAN ← FALSE;
endlt ← lt ← LIST[-1e30];
UNTIL finished
DO
finished ← TRUE;
t ← 1e30;
FOR ih:
LIST
OF History ← hList, ih.rest
UNTIL ih=
NIL
DO
IF ih.first#
NIL
THEN {
finished ← FALSE;
IF t>=ih.first.first.t
THEN {
t ← ih.first.first.t;
h ← ih;
};
};
ENDLOOP;
IF ~finished
THEN {
IF endlt.first#t
THEN {
endlt.rest ← LIST[t];
endlt ← endlt.rest;
};
h.first ← h.first.rest;
};
ENDLOOP;
lt ← lt.rest;
};
Agenda Gestion
Create
Agenda:
PUBLIC PROC [execute: ExecuteProc, data:
REF
ANY]
RETURNS [newAgenda: Agenda] ~ {
newAgenda ← NEW[AgendaRec ← [execute: execute, data: data]];
};
KillAgenda:
PUBLIC PROC [agenda: Agenda] ~ {
aList: LIST OF Event;
UNTIL agenda.list=
NIL
DO
agenda.list.first.ref ← NIL;
aList ← agenda.list;
agenda.list ← agenda.list.rest;
aList.rest ← NIL;
ENDLOOP;
agenda.data ← NIL;
};
InsertInAgenda:
PUBLIC ENTRY
PROC [agenda: Agenda, ref:
REF
ANY, t: ps] ~ {
ENABLE UNWIND => NULL;
cal: LIST OF Event;
IF t=-1e30 THEN RETURN;
IF agenda=NIL THEN ERROR; --don't try to insert in an empty ref
IF agenda.list=
NIL
THEN {
agenda.list ← LIST[[t, ref]];
agenda.nbOfEvents ← 1;
RETURN
};
IF t<agenda.list.first.t THEN ERROR; -- you try to add something to the past...
FOR ical:
LIST
OF Event ← agenda.list, ical.rest
UNTIL ical=
NIL
DO
IF t=ical.first.t THEN IF ref=ical.first.ref THEN RETURN;
IF t<ical.first
.t
THEN {
ical.rest ← CONS[ical.first, ical.rest];
ical.first.t ← t;
ical.first.ref ← ref;
agenda.nbOfEvents ← agenda.nbOfEvents+1;
RETURN;
};
cal ← ical;
ENDLOOP;
cal.rest ← LIST[[t, ref]];
agenda.nbOfEvents ← agenda.nbOfEvents+1;
};
DeleteEvent:
ENTRY PROC [agenda: Agenda] ~ {
ENABLE UNWIND => NULL;
aList: LIST OF Event ← agenda.list;
aList.first.ref ← NIL;
agenda.list ← agenda.list.rest;
aList.rest ← NIL;
agenda.nbOfEvents ← agenda.nbOfEvents-1;
};
ExecuteAgenda:
PUBLIC PROC [agenda: Agenda]
RETURNS [lastTime: ps] ~ {
ENABLE UNWIND => NULL;
WHILE agenda.list#
NIL
DO
agenda.execute[agenda.list.first.ref, agenda.list.first.t, agenda.data];
lastTime ← agenda.list.first.t;
DeleteEvent[agenda];
ENDLOOP;
};
END.