1 | package desmoj.core.simulator; |
2 | |
3 | import java.util.concurrent.TimeUnit; |
4 | |
5 | |
6 | /** |
7 | * TimeOperations is an utility class that provides arithmetic operations for |
8 | * the time classes TimeInstant and TimeSpan. It also holds the time settings, |
9 | * i.e. the granularity (epsilon) and the reference time unit. |
10 | * |
11 | * @version DESMO-J, Ver. 2.3.3 copyright (c) 2011 |
12 | * @author Felix Klueckmann |
13 | * |
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you |
15 | * may not use this file except in compliance with the License. You may |
16 | * obtain a copy of the License at |
17 | * http://www.apache.org/licenses/LICENSE-2.0 |
18 | * |
19 | * Unless required by applicable law or agreed to in writing, software |
20 | * distributed under the License is distributed on an "AS IS" BASIS, |
21 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
22 | * implied. See the License for the specific language governing |
23 | * permissions and limitations under the License. |
24 | * |
25 | */ |
26 | public final class TimeOperations { |
27 | |
28 | /** |
29 | * The granularity of simulation time. Default is MICROSECONDS. |
30 | */ |
31 | private static TimeUnit epsilon = TimeUnit.MICROSECONDS; |
32 | |
33 | /** |
34 | * The reference time unit specifying what is meant by the simulation time |
35 | * step of 1 in statements without an explicit declaration of a time unit |
36 | * like in <code>new TimeSpan(5)</code>. |
37 | */ |
38 | private static TimeUnit referenceUnit; |
39 | |
40 | /** |
41 | * The point in simulation time when the experiment has started. |
42 | */ |
43 | private static TimeInstant startTime; |
44 | private static TimeFormatter myTimeFormatter; |
45 | |
46 | // Suppress default constuctor for noninstantiability |
47 | private TimeOperations() { |
48 | } |
49 | |
50 | /** |
51 | * Returns a new TimeSpan object representing the sum of the given TimeSpan |
52 | * objects. Note that the simulation will stop immediately if the resulting |
53 | * sum is larger than Long.MAX_VALUE-1 (in the unit of epsilon). |
54 | * |
55 | * @return TimeSpan : A new TimeSpan as the sum of the TimeSpan parameters |
56 | * @param a |
57 | * TimeSpan : TimeSpan parameter a |
58 | * @param b |
59 | * TimeSpan : TimeSpan parameter b |
60 | */ |
61 | public static TimeSpan add(TimeSpan a, TimeSpan b) { |
62 | if (Long.MAX_VALUE - a.getTimeInEpsilon() - b.getTimeInEpsilon() < 1) { |
63 | // the resulting sum is too big |
64 | throw (new desmoj.core.exception.SimAbortedException( |
65 | new desmoj.core.report.ErrorMessage( |
66 | null, |
67 | "Can't add TimeSpan objects! Simulation aborted.", |
68 | "Class : TimeOperations Methode : add(TimeSpan a, TimeSpan b)", |
69 | "the resulting sum is too big. ", |
70 | "Can only create TimeSpan objects which are smaller than Long.MAX_VALUE (in the TimeUnit of epsilon).", |
71 | null))); |
72 | } |
73 | return new TimeSpan(a.getTimeInEpsilon() + b.getTimeInEpsilon(), |
74 | epsilon); |
75 | } |
76 | |
77 | /** |
78 | * Returns a new Time Instant determined from the instant passed to this |
79 | * method plus the time span passed to method. |
80 | * In other words, this method determines the instant that is a given |
81 | * span after the instant provided. |
82 | * Note that the simulation will stop immediately if the resulting |
83 | * instant is larger than Long.MAX_VALUE-1 (in the unit of epsilon). |
84 | * |
85 | * @return TimeSpan : A new TimeInstant determined from given TimeInstant plus |
86 | * the given TimeSpan |
87 | * @param span |
88 | * TimeSpan : parameter a |
89 | * @param instant |
90 | * TimeInstant : parameter b |
91 | */ |
92 | public static TimeInstant add(TimeSpan span, TimeInstant instant) { |
93 | return TimeOperations.add(instant, span); |
94 | } |
95 | |
96 | /** |
97 | * Returns a new Time Instant determined from the instant passed to this |
98 | * method plus the time span passed to method. |
99 | * In other words, this method determines the instant that is a given |
100 | * span after the instant provided. |
101 | * Note that the simulation will stop immediately if the resulting |
102 | * instant is larger than Long.MAX_VALUE-1 (in the unit of epsilon). |
103 | * |
104 | * @return TimeSpan : A new TimeInstant determined from given TimeInstant plus |
105 | * the given TimeSpan |
106 | * @param instant |
107 | * TimeInstant : parameter a |
108 | * @param span |
109 | * TimeSpan : parameter b |
110 | */ |
111 | public static TimeInstant add(TimeInstant instant, TimeSpan span) { |
112 | if (instant.getTimeInEpsilon() > 0) { |
113 | // overflow is possible |
114 | if (Long.MAX_VALUE - span.getTimeInEpsilon() |
115 | - instant.getTimeInEpsilon() < 1) { |
116 | // the resulting sum is too big |
117 | throw (new desmoj.core.exception.SimAbortedException( |
118 | new desmoj.core.report.ErrorMessage( |
119 | null, |
120 | "Can't add TimeSpan and TimeInstant objects! Simulation aborted.", |
121 | "Class : TimeOperations Methode : add(TimeSpan a, TimeInstant b)", |
122 | "the resulting sum is too big. ", |
123 | "Can only create TimeInstant objects which are before Long.MAX_VALUE (in the TimeUnit of epsilon).", |
124 | null))); |
125 | } |
126 | } |
127 | return new TimeInstant(span.getTimeInEpsilon() |
128 | + instant.getTimeInEpsilon(), epsilon); |
129 | } |
130 | |
131 | /** |
132 | * Returns a new Time Instant determined from the instant passed to this |
133 | * method minus the time span passed to method. |
134 | * In other words, this method determines the instant that is a given |
135 | * span before the instant provided. |
136 | * Note that the simulation will stop immediately if the resulting |
137 | * instant is smaller than 0 (in the unit of epsilon). |
138 | * |
139 | * @return TimeSpan : A new TimeInstant determined from given TimeInstant minus |
140 | * the given TimeSpan |
141 | * @param instant |
142 | * TimeInstant : parameter a |
143 | * @param span |
144 | * TimeSpan : parameter b |
145 | */ |
146 | public static TimeInstant subtract(TimeInstant instant, TimeSpan span) { |
147 | if (instant.getTimeInEpsilon() > 0) { |
148 | // prior to zero? |
149 | if (instant.getTimeInEpsilon() - span.getTimeInEpsilon() < 0) { |
150 | |
151 | // the resulting instant is prior to zero |
152 | throw (new desmoj.core.exception.SimAbortedException( |
153 | new desmoj.core.report.ErrorMessage( |
154 | null, |
155 | "Can't subtract TimeInstant and TimeSpan objects! Simulation aborted.", |
156 | "Class : TimeOperations Methode : subtract(TimeInstant a, TimeSpan b)", |
157 | "the resulting smaller than 0.", |
158 | "Can only create TimeInstant objects which are non-negative (in the TimeUnit of epsilon).", |
159 | null))); |
160 | } |
161 | } |
162 | return new TimeInstant(instant.getTimeInEpsilon() |
163 | - span.getTimeInEpsilon(), epsilon); |
164 | } |
165 | |
166 | |
167 | /** |
168 | * Returns a new TimeSpan object representing the absolute difference of the |
169 | * given TimeSpan objects. |
170 | * |
171 | * @return TimeSpan : A new TimeSpan as the absolute difference of the |
172 | * TimeSpan parameters |
173 | * @param a |
174 | * TimeSpan : TimeSpan parameter a |
175 | * @param b |
176 | * TimeSpan : TimeSpan parameter b |
177 | */ |
178 | public static TimeSpan diff(TimeSpan a, TimeSpan b) { |
179 | |
180 | if (TimeSpan.isShorter(a, b)) { |
181 | return new TimeSpan(b.getTimeInEpsilon() - a.getTimeInEpsilon(), |
182 | epsilon); |
183 | } |
184 | |
185 | return new TimeSpan(a.getTimeInEpsilon() - b.getTimeInEpsilon(), |
186 | epsilon); |
187 | } |
188 | |
189 | /** |
190 | * Returns a new TimeSpan object representing the absolute difference of the |
191 | * given TimeInstant objects, i.e. the span of time between the two instants |
192 | * of time. Note that the simulation will stop immediately if the resulting |
193 | * sum is larger than Long.MAX_VALUE-1 (in the unit of epsilon). |
194 | * |
195 | * @return TimeSpan : A new TimeSpan as the difference of the TimeSpan |
196 | * parameters |
197 | * @param a |
198 | * TimeInstant : parameter a |
199 | * @param b |
200 | * TimeInstant : parameter b |
201 | */ |
202 | public static TimeSpan diff(TimeInstant a, TimeInstant b) { |
203 | if (TimeInstant.isAfter(a, b)) { |
204 | // a is after b |
205 | if (b.getTimeInEpsilon() < 0) { |
206 | // the resulting difference could be too big. |
207 | |
208 | if (Long.MAX_VALUE - 1 + b.getTimeInEpsilon() < a |
209 | .getTimeInEpsilon()) { |
210 | // the resulting difference is too big. |
211 | throw (new desmoj.core.exception.SimAbortedException( |
212 | new desmoj.core.report.ErrorMessage( |
213 | null, |
214 | "Can't subtract TimeInstant objects! Simulation aborted.", |
215 | "Class : TimeOperations Methode : diff(TimeSpan a, TimeInstant b)", |
216 | "the resulting difference is too big. ", |
217 | "Can only create TimeSpan objects which are smaller than Long.MAX_VALUE (in the TimeUnit of epsilon).", |
218 | null))); |
219 | } |
220 | } |
221 | return new TimeSpan(a.getTimeInEpsilon() - b.getTimeInEpsilon(), |
222 | epsilon); |
223 | } else { |
224 | // b is after a |
225 | if (a.getTimeInEpsilon() < 0) { |
226 | // the resulting difference could be too big. |
227 | |
228 | if (Long.MAX_VALUE + a.getTimeInEpsilon() < b |
229 | .getTimeInEpsilon()) { |
230 | // the resulting difference is too big. |
231 | throw (new desmoj.core.exception.SimAbortedException( |
232 | new desmoj.core.report.ErrorMessage( |
233 | null, |
234 | "Can't subtract TimeInstant objects! Simulation aborted.", |
235 | "Class : TimeOperations Methode : diff(TimeSpan a, TimeInstant b)", |
236 | "the resulting difference is too big. ", |
237 | "Can only create TimeSpan objects which are smaller than Long.MAX_VALUE (in the TimeUnit of epsilon).", |
238 | null))); |
239 | } |
240 | } |
241 | |
242 | return new TimeSpan(b.getTimeInEpsilon() - a.getTimeInEpsilon(), |
243 | epsilon); |
244 | } |
245 | |
246 | } |
247 | |
248 | /** |
249 | * Returns a new TimeSpan object representing the product of the given |
250 | * TimeSpan and the factor of type double. Note that the simulation will |
251 | * stop immediately if the resulting product is larger than Long.MAX_VALUE-1 |
252 | * (in the unit of epsilon). |
253 | * |
254 | * @return TimeSpan : A new TimeSpan as the product of span and factor |
255 | * @param span |
256 | * TimeSpan : the span of time |
257 | * @param factor |
258 | * double : the scalar factor |
259 | */ |
260 | public static TimeSpan multiply(TimeSpan span, double factor) { |
261 | if (factor > 1) { |
262 | // the resulting product could be too big |
263 | if (Long.MAX_VALUE / factor < span.getTimeInEpsilon()) { |
264 | // the resulting product is too big |
265 | throw (new desmoj.core.exception.SimAbortedException( |
266 | new desmoj.core.report.ErrorMessage( |
267 | null, |
268 | "Can't multiply TimeSpan and double value! Simulation aborted.", |
269 | "Class : TimeOperations Methode : multiply(TimeSpan span, double factor)", |
270 | "the resulting product is too big. ", |
271 | "Can only create TimeSpan objects which are shorter than Long.MAX_VALUE (in the TimeUnit of epsilon).", |
272 | null))); |
273 | } |
274 | } |
275 | return new TimeSpan((long) (span.getTimeInEpsilon() * factor), epsilon); |
276 | } |
277 | |
278 | /** |
279 | * Returns a new TimeSpan object representing the product of the given |
280 | * TimeSpan and the factor of type double. Note that the simulation will |
281 | * stop immediately if the resulting product is larger than Long.MAX_VALUE-1 |
282 | * (in the unit of epsilon). |
283 | * |
284 | * @return TimeSpan : A new TimeSpan as the product of span and factor |
285 | * @param factor |
286 | * double : the scalar factor |
287 | * @param span |
288 | * TimeSpan : the span of time |
289 | */ |
290 | public static TimeSpan multiply(double factor, TimeSpan span) { |
291 | return TimeOperations.multiply(span, factor); |
292 | } |
293 | |
294 | /** |
295 | * Returns a new TimeSpan object representing the quotient of the given |
296 | * TimeSpan objects. |
297 | * |
298 | * @return TimeSpan : A new TimeSpan as the quotient of dividend and divisor |
299 | * @param dividend |
300 | * TimeSpan : the dividend |
301 | * @param divisor |
302 | * TimeSpan : the divisor |
303 | */ |
304 | public static double divide(TimeSpan dividend, TimeSpan divisor) { |
305 | if (divisor.getTimeInEpsilon() == 0) { |
306 | // cannot divide by zero |
307 | throw (new desmoj.core.exception.SimAbortedException( |
308 | new desmoj.core.report.ErrorMessage( |
309 | null, |
310 | "Can't divide TimeSpan values! Simulation aborted.", |
311 | "Class : TimeOperations Methode : divide(TimeSpan dividend, TimeSpan divisor)", |
312 | "Cannot devide by zero.", |
313 | "Never try to devide by zero.", null))); |
314 | } |
315 | return ((double) dividend.getTimeInEpsilon() / (double) divisor |
316 | .getTimeInEpsilon()); |
317 | |
318 | } |
319 | |
320 | /** |
321 | * Returns a new TimeSpan object representing the quotient of the given |
322 | * TimeSpan and the divisor of type double. Note that the simulation will |
323 | * stop immediately if the resulting quotient is larger than |
324 | * Long.MAX_VALUE-1 (in the unit of epsilon). |
325 | * |
326 | * @return TimeSpan : A new TimeSpan as the quotient of divident and divisor |
327 | * @param dividend |
328 | * TimeSpan : the dividend |
329 | * @param divisor |
330 | * double : the divisor |
331 | */ |
332 | public static TimeSpan divide(TimeSpan dividend, double divisor) { |
333 | if (divisor <= 0) { |
334 | // cannot divide by zero |
335 | throw (new desmoj.core.exception.SimAbortedException( |
336 | new desmoj.core.report.ErrorMessage( |
337 | null, |
338 | "Can't divide TimeSpan and double value! Simulation aborted.", |
339 | "Class : TimeOperations Methode : mdivide(TimeSpan dividend, double divisor)", |
340 | "Cannot devide by zero.", |
341 | "Never try to devide by zero.", null))); |
342 | } |
343 | if (divisor < 1) { |
344 | // the resulting quotient could be too big |
345 | if (Long.MAX_VALUE * divisor < dividend.getTimeInEpsilon()) { |
346 | // the resulting product is too big |
347 | throw (new desmoj.core.exception.SimAbortedException( |
348 | new desmoj.core.report.ErrorMessage( |
349 | null, |
350 | "Can't divide TimeSpan and double value! Simulation aborted.", |
351 | "Class : TimeOperations Methode : mdivide(TimeSpan dividend, double divisor)", |
352 | "the resulting quotient is too big. ", |
353 | "Can only create TimeSpan objects which are shorter than Long.MAX_VALUE (in the TimeUnit of epsilon).", |
354 | null))); |
355 | } |
356 | } |
357 | return new TimeSpan((long) (dividend.getTimeInEpsilon() / divisor), |
358 | epsilon); |
359 | } |
360 | |
361 | /** |
362 | * Returns the epsilon value representing the granularity of simulation time |
363 | * for this experiment. |
364 | * |
365 | * @return TimeUnit : The granularity of simulation time |
366 | */ |
367 | public static TimeUnit getEpsilon() { |
368 | return epsilon; |
369 | } |
370 | |
371 | /** |
372 | * Returns the smallest distinguishable TimeSpan. |
373 | * |
374 | * @return TimeSpan : The smallest distinguishable TimeSpan, i.e. one interval |
375 | * of the epsilon unit |
376 | */ |
377 | public static TimeSpan getEpsilonSpan() { |
378 | return new TimeSpan(1, epsilon); |
379 | } |
380 | |
381 | /** |
382 | * Returns the reference time unit specifying what is meant by the |
383 | * simulation time step of 1 in statements without an explicit declaration |
384 | * of a time unit like in <code>new TimeSpan(5)</code>. |
385 | * |
386 | * |
387 | * @return the reference time unit |
388 | * |
389 | */ |
390 | static TimeUnit getReferenceUnit() { |
391 | return referenceUnit; |
392 | } |
393 | |
394 | /** |
395 | * Sets the epsilon value representing the granularity of simulation time to |
396 | * the given TimeUnit parameter. This is a package private method for |
397 | * internal framework use only. |
398 | * |
399 | * @param epsilon |
400 | * TimeUnit : The granularity of simulation time, i.e. the |
401 | * smallest distinguishable span of simulation time. |
402 | */ |
403 | static void setEpsilon(TimeUnit epsilon) { |
404 | TimeOperations.epsilon = epsilon; |
405 | } |
406 | |
407 | /** |
408 | * Sets the reference time unit specifying what is meant by the simulation |
409 | * time step of 1 in statements without an explicit declaration of a time |
410 | * unit like in <code>new TimeSpan(5)</code>. This is a package private |
411 | * method for internal framework use only. |
412 | * |
413 | * |
414 | * @param referenceUnit |
415 | * the reference time unit |
416 | * |
417 | */ |
418 | static void setReferenceUnit(TimeUnit referenceUnit) { |
419 | TimeOperations.referenceUnit = referenceUnit; |
420 | } |
421 | |
422 | /** |
423 | * Formats the given instant of time according to the timeFormatter. This is |
424 | * a package private method for internal framework use only. |
425 | * |
426 | * @param instant |
427 | * the instant of time to be formatted |
428 | * |
429 | */ |
430 | |
431 | static String formatTimeInstant(TimeInstant instant) { |
432 | return myTimeFormatter.buildTimeString(instant); |
433 | } |
434 | |
435 | /** |
436 | * Formats the given span of time according to the timeFormatter. This is a |
437 | * package private method for internal framework use only. |
438 | * |
439 | * @param span |
440 | * the span of time to be formatted |
441 | * |
442 | */ |
443 | static String formatTimeSpan(TimeSpan span) { |
444 | return myTimeFormatter.buildTimeString(span); |
445 | } |
446 | |
447 | /** |
448 | * Returns the time Formatter. This is a package private method for internal |
449 | * framework use only. |
450 | */ |
451 | public static TimeFormatter getTimeFormatter() { |
452 | return myTimeFormatter; |
453 | } |
454 | |
455 | /** |
456 | * Sets the time Formatter. This is a package private method for internal |
457 | * framework use only. |
458 | * |
459 | * @param myTimeFormatter |
460 | * the Time Formatter |
461 | */ |
462 | static void setTimeFormatter(TimeFormatter myTimeFormatter) { |
463 | TimeOperations.myTimeFormatter = myTimeFormatter; |
464 | } |
465 | |
466 | /** |
467 | * Returns the TimeInstant when the experiment has started. |
468 | * |
469 | * @return TimeInstant : The point in simulation time, the experiment has |
470 | * started. |
471 | */ |
472 | public static TimeInstant getStartTime() { |
473 | return startTime; |
474 | } |
475 | |
476 | static void setStartTime(TimeInstant startTime) { |
477 | TimeOperations.startTime = startTime; |
478 | } |
479 | } |