View Javadoc
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-2019 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     /**
212      * This iterator is returned to callers of the {@code iterator()} method. Multiple instances may be returned which use the
213      * same linked list of {@code SecondaryIteratorEntry}. Whenever an iterator runs to the end of this list, the primary
214      * iterator is requested to find the next object, if it has a next object.
215      * <p>
216      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
217      * <br>
218      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
219      * <p>
220      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 16 feb. 2018 <br>
221      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
222      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
223      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
224      */
225     public class PerceptionIterator implements Iterator<H>
226     {
227 
228         /** Last returned entry. */
229         private SecondaryIteratorEntry lastReturned;
230 
231         /** Next entry. */
232         private SecondaryIteratorEntry next;
233 
234         /** Constructor. */
235         @SuppressWarnings("synthetic-access")
236         PerceptionIterator()
237         {
238             this.next = AbstractPerceptionReiterable.this.first;
239         }
240 
241         /** {@inheritDoc} */
242         @Override
243         public boolean hasNext()
244         {
245             this.next = assureNext(this.next, this.lastReturned);
246             return this.next != null;
247         }
248 
249         /** {@inheritDoc} */
250         @SuppressWarnings("synthetic-access")
251         @Override
252         public H next()
253         {
254             this.next = assureNext(this.next, this.lastReturned);
255             if (this.next == null)
256             {
257                 throw new NoSuchElementException();
258             }
259             this.lastReturned = this.next;
260             this.next = this.lastReturned.next;
261             return this.lastReturned.getValue();
262         }
263 
264     }
265 
266     /**
267      * Helper method that assures that a next entry is available, if the primary iterator has a next value. This method may be
268      * used by any process that derives from the primary iterator.
269      * @param next SecondaryIteratorEntry; currently known next entry
270      * @param lastReturned SecondaryIteratorEntry; entry of last returned object or value
271      * @return IteratorEntry; next entry
272      */
273     @SuppressWarnings("synthetic-access")
274     synchronized SecondaryIteratorEntry assureNext(final SecondaryIteratorEntry next, final SecondaryIteratorEntry lastReturned)
275     {
276         if (next == null && getPrimaryIterator().hasNext())
277         {
278             addNext(getPrimaryIterator().next());
279             if (lastReturned == null)
280             {
281                 return AbstractPerceptionReiterable.this.first;
282             }
283             else
284             {
285                 return lastReturned.next;
286             }
287         }
288         return next;
289     }
290 
291     /**
292      * Class for {@code primaryIterator()} to return, implemented in subclasses.
293      * <p>
294      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
295      * <br>
296      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
297      * <p>
298      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 28 feb. 2018 <br>
299      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
300      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
301      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
302      */
303     protected class PrimaryIteratorEntry implements Comparable<PrimaryIteratorEntry>
304     {
305         /** Object. */
306         private final U object;
307 
308         /** Distance to the object. */
309         private final Length distance;
310 
311         /**
312          * Constructor.
313          * @param object U; object
314          * @param distance Length; distance
315          */
316         public PrimaryIteratorEntry(final U object, final Length distance)
317         {
318             this.object = object;
319             this.distance = distance;
320         }
321 
322         /** {@inheritDoc} */
323         @Override
324         public int compareTo(final PrimaryIteratorEntry o)
325         {
326             return this.distance.compareTo(o.distance);
327         }
328 
329         /**
330          * Returns the object.
331          * @return U; object
332          */
333         protected U getObject()
334         {
335             return this.object;
336         }
337     }
338 
339     /**
340      * Entries that make up a linked list of values for secondary iterators to iterate over.
341      * <p>
342      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
343      * <br>
344      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
345      * <p>
346      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 16 feb. 2018 <br>
347      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
348      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
349      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
350      */
351     private class SecondaryIteratorEntry
352     {
353         /** Value. */
354         private final U object;
355 
356         /** Distance to object. */
357         private final Length distance;
358 
359         /** Value. */
360         private H value;
361 
362         /** Next entry. */
363         private SecondaryIteratorEntry next;
364 
365         /**
366          * Constructor.
367          * @param object U; object
368          * @param distance Length; distance to object
369          */
370         SecondaryIteratorEntry(final U object, final Length distance)
371         {
372             this.object = object;
373             this.distance = distance;
374         }
375 
376         /**
377          * Returns the perceived version of the object.
378          * @return H; perceived version of the object
379          */
380         H getValue()
381         {
382             if (this.value == null)
383             {
384                 this.value = Try.assign(() -> perceive(AbstractPerceptionReiterable.this.getGtu(), this.object, this.distance),
385                         "Exception during perception of object.");
386             }
387             return this.value;
388         }
389     }
390 
391 }