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-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 }