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