1 package org.opentrafficsim.road.gtu.lane.perception;
2
3 import java.util.Iterator;
4 import java.util.NoSuchElementException;
5 import java.util.function.Supplier;
6
7 import org.djunits.value.vdouble.scalar.Length;
8 import org.djutils.exceptions.Try;
9 import org.opentrafficsim.base.parameters.ParameterException;
10 import org.opentrafficsim.core.gtu.GTUException;
11 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
12 import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
13
14 /**
15 * This class uses a single primary iterator which a subclass defines, and makes sure that all elements are only looked up and
16 * created once. It does so by storing the elements in a linked list. All calls to {@code iterator()} return an iterator which
17 * iterates over the linked list. If an iterator runs to the end of the linked list, the primary iterator is requested to add an
18 * element if it has one.
19 * <p>
20 * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
21 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
22 * <p>
23 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 20 feb. 2018 <br>
24 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
25 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
26 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
27 * @param <H> headway type
28 * @param <U> underlying object type
29 */
30 public abstract class AbstractPerceptionReiterable<H extends Headway, U> implements PerceptionCollectable<H, U>
31 {
32
33 /** First entry. */
34 private SecondaryIteratorEntry first;
35
36 /** Last entry generated by the primary iterator. */
37 private SecondaryIteratorEntry last;
38
39 /** Primary iterator. */
40 private Iterator<PrimaryIteratorEntry> primaryIterator;
41
42 /** Perceiving GTU. */
43 private final LaneBasedGTU gtu;
44
45 /**
46 * Constructor.
47 * @param perceivingGtu LaneBasedGTU; perceiving GTU
48 */
49 protected AbstractPerceptionReiterable(final LaneBasedGTU perceivingGtu)
50 {
51 this.gtu = perceivingGtu;
52 }
53
54 /**
55 * Returns the GTU.
56 * @return LaneBasedGTU; GTU
57 */
58 protected LaneBasedGTU getGtu()
59 {
60 return this.gtu;
61 }
62
63 /**
64 * Returns the primary iterator.
65 * @return Iterator; primary iterator
66 */
67 final Iterator<PrimaryIteratorEntry> getPrimaryIterator()
68 {
69 if (this.primaryIterator == null)
70 {
71 this.primaryIterator = primaryIterator();
72 }
73 return this.primaryIterator;
74 }
75
76 /**
77 * Returns the primary iterator. This method is called once by AbstractPerceptionReiterable.
78 * @return Iterator; primary iterator
79 */
80 protected abstract Iterator<PrimaryIteratorEntry> primaryIterator();
81
82 /**
83 * Returns a perceived version of the underlying object.
84 * @param perceivingGtu LaneBasedGTU; perceiving GTU
85 * @param object U; underlying object
86 * @param distance Length; distance to the object
87 * @return H; perceived version of the underlying object
88 * @throws GTUException on exception
89 * @throws ParameterException on invalid parameter value or missing parameter
90 */
91 protected abstract H perceive(LaneBasedGTU perceivingGtu, U object, Length distance)
92 throws GTUException, ParameterException;
93
94 /** {@inheritDoc} */
95 @Override
96 public final synchronized H first()
97 {
98 assureFirst();
99 if (this.first == null)
100 {
101 return null;
102 }
103 return this.first.getValue();
104 }
105
106 /**
107 * Assures a first SecondaryIteratorEntry is present, if the primary iterator has any elements.
108 */
109 private synchronized void assureFirst()
110 {
111 if (this.first == null && getPrimaryIterator().hasNext())
112 {
113 addNext(getPrimaryIterator().next());
114 }
115 }
116
117 /**
118 * Adds an iterator entry to the internal linked list.
119 * @param next PrimaryIteratorEntry; next object
120 */
121 @SuppressWarnings("synthetic-access")
122 final void addNext(final PrimaryIteratorEntry next)
123 {
124 SecondaryIteratorEntry entry = new SecondaryIteratorEntry(next.object, next.distance);
125 if (AbstractPerceptionReiterable.this.last == null)
126 {
127 AbstractPerceptionReiterable.this.first = entry;
128 AbstractPerceptionReiterable.this.last = entry;
129 }
130 else
131 {
132 AbstractPerceptionReiterable.this.last.next = entry;
133 AbstractPerceptionReiterable.this.last = entry;
134 }
135 }
136
137 /** {@inheritDoc} */
138 @Override
139 public final boolean isEmpty()
140 {
141 return first() == null;
142 }
143
144 /** {@inheritDoc} */
145 @Override
146 public final Iterator<H> iterator()
147 {
148 return new PerceptionIterator();
149 }
150
151 /** {@inheritDoc} */
152 @SuppressWarnings("synthetic-access")
153 @Override
154 public final <C, I> C collect(final Supplier<I> identity, final PerceptionAccumulator<? super U, I> accumulator,
155 final PerceptionFinalizer<C, I> finalizer)
156 {
157 Intermediate<I> intermediate = new Intermediate<>(identity.get());
158 assureFirst();
159 if (this.first != null)
160 {
161 SecondaryIteratorEntry lastReturned = null;
162 SecondaryIteratorEntry next = this.first;
163 next = assureNext(next, lastReturned);
164 while (next != null && !intermediate.isStop())
165 {
166 intermediate = accumulator.accumulate(intermediate, next.object, next.distance);
167 intermediate.step();
168 lastReturned = next;
169 next = lastReturned.next;
170 next = assureNext(next, lastReturned);
171 }
172 }
173 return finalizer.collect(intermediate.getObject());
174 }
175
176 /** {@inheritDoc} */
177 @Override
178 public Iterator<U> underlying()
179 {
180 assureFirst();
181 SecondaryIteratorEntry firstInContext = this.first;
182 return new Iterator<U>()
183 {
184 /** Last returned iterator entry. */
185 private SecondaryIteratorEntry lastReturned = null;
186
187 /** Next iterator entry. */
188 private SecondaryIteratorEntry next = firstInContext;
189
190 /** {@inheritDoc} */
191 @Override
192 public boolean hasNext()
193 {
194 this.next = assureNext(this.next, this.lastReturned);
195 return this.next != null;
196 }
197
198 /** {@inheritDoc} */
199 @SuppressWarnings("synthetic-access")
200 @Override
201 public U next()
202 {
203 this.lastReturned = this.next;
204 this.next = this.lastReturned.next;
205 this.next = assureNext(this.next, this.lastReturned);
206 return this.lastReturned.object;
207 }
208 };
209 }
210
211 /** {@inheritDoc} */
212 @Override
213 public Iterator<UnderlyingDistance<U>> underlyingWithDistance()
214 {
215 assureFirst();
216 SecondaryIteratorEntry firstInContext = this.first;
217 return new Iterator<UnderlyingDistance<U>>()
218 {
219 /** Last returned iterator entry. */
220 private SecondaryIteratorEntry lastReturned = null;
221
222 /** Next iterator entry. */
223 private SecondaryIteratorEntry next = firstInContext;
224
225 /** {@inheritDoc} */
226 @Override
227 public boolean hasNext()
228 {
229 this.next = assureNext(this.next, this.lastReturned);
230 return this.next != null;
231 }
232
233 /** {@inheritDoc} */
234 @SuppressWarnings("synthetic-access")
235 @Override
236 public UnderlyingDistance<U> next()
237 {
238 this.lastReturned = this.next;
239 this.next = this.lastReturned.next;
240 this.next = assureNext(this.next, this.lastReturned);
241 return new UnderlyingDistance<>(this.lastReturned.object, this.lastReturned.distance);
242 }
243 };
244 }
245
246 /**
247 * This iterator is returned to callers of the {@code iterator()} method. Multiple instances may be returned which use the
248 * same linked list of {@code SecondaryIteratorEntry}. Whenever an iterator runs to the end of this list, the primary
249 * iterator is requested to find the next object, if it has a next object.
250 * <p>
251 * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
252 * <br>
253 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
254 * <p>
255 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 16 feb. 2018 <br>
256 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
257 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
258 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
259 */
260 public class PerceptionIterator implements Iterator<H>
261 {
262
263 /** Last returned entry. */
264 private SecondaryIteratorEntry lastReturned;
265
266 /** Next entry. */
267 private SecondaryIteratorEntry next;
268
269 /** Constructor. */
270 @SuppressWarnings("synthetic-access")
271 PerceptionIterator()
272 {
273 this.next = AbstractPerceptionReiterable.this.first;
274 }
275
276 /** {@inheritDoc} */
277 @Override
278 public boolean hasNext()
279 {
280 this.next = assureNext(this.next, this.lastReturned);
281 return this.next != null;
282 }
283
284 /** {@inheritDoc} */
285 @SuppressWarnings("synthetic-access")
286 @Override
287 public H next()
288 {
289 this.next = assureNext(this.next, this.lastReturned);
290 if (this.next == null)
291 {
292 throw new NoSuchElementException();
293 }
294 this.lastReturned = this.next;
295 this.next = this.lastReturned.next;
296 return this.lastReturned.getValue();
297 }
298
299 }
300
301 /**
302 * Helper method that assures that a next entry is available, if the primary iterator has a next value. This method may be
303 * used by any process that derives from the primary iterator.
304 * @param next SecondaryIteratorEntry; currently known next entry
305 * @param lastReturned SecondaryIteratorEntry; entry of last returned object or value
306 * @return IteratorEntry; next entry
307 */
308 @SuppressWarnings("synthetic-access")
309 synchronized SecondaryIteratorEntry assureNext(final SecondaryIteratorEntry next, final SecondaryIteratorEntry lastReturned)
310 {
311 if (next == null && getPrimaryIterator().hasNext())
312 {
313 addNext(getPrimaryIterator().next());
314 if (lastReturned == null)
315 {
316 return AbstractPerceptionReiterable.this.first;
317 }
318 else
319 {
320 return lastReturned.next;
321 }
322 }
323 return next;
324 }
325
326 /**
327 * Class for {@code primaryIterator()} to return, implemented in subclasses.
328 * <p>
329 * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
330 * <br>
331 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
332 * <p>
333 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 28 feb. 2018 <br>
334 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
335 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
336 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
337 */
338 protected class PrimaryIteratorEntry implements Comparable<PrimaryIteratorEntry>
339 {
340 /** Object. */
341 private final U object;
342
343 /** Distance to the object. */
344 private final Length distance;
345
346 /**
347 * Constructor.
348 * @param object U; object
349 * @param distance Length; distance
350 */
351 public PrimaryIteratorEntry(final U object, final Length distance)
352 {
353 this.object = object;
354 this.distance = distance;
355 }
356
357 /** {@inheritDoc} */
358 @Override
359 public int compareTo(final PrimaryIteratorEntry o)
360 {
361 return this.distance.compareTo(o.distance);
362 }
363
364 /**
365 * Returns the object.
366 * @return U; object
367 */
368 protected U getObject()
369 {
370 return this.object;
371 }
372 }
373
374 /**
375 * Entries that make up a linked list of values for secondary iterators to iterate over.
376 * <p>
377 * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
378 * <br>
379 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
380 * <p>
381 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 16 feb. 2018 <br>
382 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
383 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
384 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
385 */
386 private class SecondaryIteratorEntry
387 {
388 /** Value. */
389 private final U object;
390
391 /** Distance to object. */
392 private final Length distance;
393
394 /** Value. */
395 private H value;
396
397 /** Next entry. */
398 private SecondaryIteratorEntry next;
399
400 /**
401 * Constructor.
402 * @param object U; object
403 * @param distance Length; distance to object
404 */
405 SecondaryIteratorEntry(final U object, final Length distance)
406 {
407 this.object = object;
408 this.distance = distance;
409 }
410
411 /**
412 * Returns the perceived version of the object.
413 * @return H; perceived version of the object
414 */
415 H getValue()
416 {
417 if (this.value == null)
418 {
419 this.value = Try.assign(() -> perceive(AbstractPerceptionReiterable.this.getGtu(), this.object, this.distance),
420 "Exception during perception of object.");
421 }
422 return this.value;
423 }
424 }
425
426 }