<> <> <> <<>> <<>> DIRECTORY Schedule; ScheduleImpl: CEDAR MONITOR LOCKS agenda USING agenda: Agenda EXPORTS Schedule ~ BEGIN OPEN Schedule; <> <<>> 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; }; <> <> <> <> <t THEN {>> <> <> <> <> <<};>> <> <<};>> <<>> 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; }; <> CreateAgenda: 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 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.