Cleanup; Cleared warnings in the logic core
[Mograsim.git] / net.mograsim.logic.core / src / net / mograsim / logic / core / timeline / Timeline.java
1 package net.mograsim.logic.core.timeline;\r
2 \r
3 import java.util.ArrayList;\r
4 import java.util.List;\r
5 import java.util.PriorityQueue;\r
6 import java.util.function.BooleanSupplier;\r
7 import java.util.function.Consumer;\r
8 import java.util.function.LongSupplier;\r
9 \r
10 /**\r
11  * Orders Events by the time they are due to be executed. Can execute Events individually.\r
12  * \r
13  * @author Fabian Stemmler\r
14  *\r
15  */\r
16 public class Timeline\r
17 {\r
18         private PriorityQueue<InnerEvent> events;\r
19         private LongSupplier time;\r
20         private long lastTimeUpdated = 0;\r
21 \r
22         private final List<Consumer<TimelineEvent>> eventAddedListener;\r
23 \r
24         public Timeline(int initCapacity)\r
25         {\r
26                 events = new PriorityQueue<>(initCapacity);\r
27 \r
28                 eventAddedListener = new ArrayList<>();\r
29                 time = () -> lastTimeUpdated;\r
30         }\r
31 \r
32         /**\r
33          * @param timestamp exclusive\r
34          * @return true if the first event is later than the timestamp\r
35          */\r
36         public BooleanSupplier laterThan(long timestamp)\r
37         {\r
38                 return () -> timeCmp(events.peek().getTiming(), timestamp) > 0;\r
39         }\r
40 \r
41         public boolean hasNext()\r
42         {\r
43                 return !events.isEmpty();\r
44         }\r
45 \r
46         /**\r
47          * Executes all events at the next timestamp, at which there are any\r
48          */\r
49         public void executeNext()\r
50         {\r
51                 InnerEvent first = events.peek();\r
52                 if (first != null)\r
53                         executeUntil(laterThan(first.getTiming()), -1);\r
54         }\r
55 \r
56         public void executeAll()\r
57         {\r
58                 while (hasNext())\r
59                         executeNext();\r
60         }\r
61 \r
62         /**\r
63          * Executes all events until a given condition is met. The simulation process can be constrained by a real world timestamp.\r
64          * \r
65          * @param condition  the condition until which the events are be processed\r
66          * @param stopMillis the System.currentTimeMillis() when simulation definitely needs to stop. A value of -1 means no timeout.\r
67          * @return State of the event execution\r
68          * @formatter:off\r
69          * <code>NOTHING_DONE</code> if the {@link Timeline} was already empty\r
70          * <code>EXEC_OUT_OF_TIME</code> if the given maximum time was reached\r
71          * <code>EXEC_UNTIL_CONDITION</code> if the condition was met\r
72          * <code>EXEC_UNTIL_EMPTY</code> if events were executed until the {@link Timeline} was empty\r
73          * @formatter:on\r
74          * @author Christian Femers, Fabian Stemmler\r
75          */\r
76         public ExecutionResult executeUntil(BooleanSupplier condition, long stopMillis)\r
77         {\r
78                 if (events.isEmpty())\r
79                 {\r
80                         lastTimeUpdated = getSimulationTime();\r
81                         return ExecutionResult.NOTHING_DONE;\r
82                 }\r
83                 int checkStop = 0;\r
84                 InnerEvent first = events.peek();\r
85                 while (hasNext() && !condition.getAsBoolean())\r
86                 {\r
87                         events.remove();\r
88                         lastTimeUpdated = first.getTiming();\r
89                         first.run();\r
90                         // Don't check after every run\r
91                         checkStop = (checkStop + 1) % 10;\r
92                         if (checkStop == 0 && System.currentTimeMillis() >= stopMillis)\r
93                                 return ExecutionResult.EXEC_OUT_OF_TIME;\r
94                         first = events.peek();\r
95                 }\r
96                 lastTimeUpdated = getSimulationTime();\r
97                 return hasNext() ? ExecutionResult.EXEC_UNTIL_EMPTY : ExecutionResult.EXEC_UNTIL_CONDITION;\r
98         }\r
99 \r
100         public void setTimeFunction(LongSupplier time)\r
101         {\r
102                 this.time = time;\r
103         }\r
104 \r
105         public long getSimulationTime()\r
106         {\r
107                 return time.getAsLong();\r
108         }\r
109 \r
110         public long nextEventTime()\r
111         {\r
112                 if (!hasNext())\r
113                         return -1;\r
114                 return events.peek().getTiming();\r
115         }\r
116 \r
117         public void reset()\r
118         {\r
119                 events.clear();\r
120                 lastTimeUpdated = 0;\r
121         }\r
122 \r
123         public void addEventAddedListener(Consumer<TimelineEvent> listener)\r
124         {\r
125                 eventAddedListener.add(listener);\r
126         }\r
127 \r
128         public void removeEventAddedListener(Consumer<TimelineEvent> listener)\r
129         {\r
130                 eventAddedListener.remove(listener);\r
131         }\r
132 \r
133         /**\r
134          * Adds an Event to the {@link Timeline}\r
135          * \r
136          * @param function       The {@link TimelineEventHandler} that will be executed, when the {@link InnerEvent} occurs on the timeline.\r
137          * @param relativeTiming The amount of MI ticks in which the {@link InnerEvent} is called, starting from the current time.\r
138          */\r
139         public void addEvent(TimelineEventHandler function, int relativeTiming)\r
140         {\r
141                 long timing = getSimulationTime() + relativeTiming;\r
142                 TimelineEvent event = new TimelineEvent(timing);\r
143                 events.add(new InnerEvent(function, event));\r
144                 eventAddedListener.forEach(l -> l.accept(event));\r
145         }\r
146 \r
147         private class InnerEvent implements Runnable, Comparable<InnerEvent>\r
148         {\r
149                 private final TimelineEventHandler function;\r
150                 private final TimelineEvent event;\r
151 \r
152                 /**\r
153                  * Creates an {@link InnerEvent}\r
154                  * \r
155                  * @param function {@link TimelineEventHandler} to be executed when the {@link InnerEvent} occurs\r
156                  * @param timing   Point in the MI simulation {@link Timeline}, at which the {@link InnerEvent} is executed;\r
157                  */\r
158                 InnerEvent(TimelineEventHandler function, TimelineEvent event)\r
159                 {\r
160                         this.function = function;\r
161                         this.event = event;\r
162                 }\r
163 \r
164                 public long getTiming()\r
165                 {\r
166                         return event.getTiming();\r
167                 }\r
168 \r
169                 @Override\r
170                 public void run()\r
171                 {\r
172                         function.handle(event);\r
173                 }\r
174 \r
175                 @Override\r
176                 public String toString()\r
177                 {\r
178                         return event.toString();\r
179                 }\r
180 \r
181                 @Override\r
182                 public int compareTo(InnerEvent o)\r
183                 {\r
184                         return timeCmp(getTiming(), o.getTiming());\r
185                 }\r
186         }\r
187 \r
188         public static int timeCmp(long a, long b)\r
189         {\r
190                 return Long.signum(a - b);\r
191         }\r
192 \r
193         @Override\r
194         public String toString()\r
195         {\r
196                 return String.format("Simulation time: %s, Last update: %d, Events: %s", getSimulationTime(), lastTimeUpdated, events.toString());\r
197         }\r
198 \r
199         public enum ExecutionResult\r
200         {\r
201                 NOTHING_DONE, EXEC_UNTIL_EMPTY, EXEC_UNTIL_CONDITION, EXEC_OUT_OF_TIME\r
202         }\r
203 }