View Javadoc
1   package org.opentrafficsim.core.perception.collections;
2   
3   import java.util.Collection;
4   import java.util.Collections;
5   import java.util.HashSet;
6   import java.util.Map;
7   import java.util.Objects;
8   import java.util.Set;
9   
10  import org.djunits.value.vdouble.scalar.Time;
11  import org.opentrafficsim.core.perception.AbstractHistorical;
12  import org.opentrafficsim.core.perception.HistoryManager;
13  import org.opentrafficsim.core.perception.collections.AbstractHistoricalMap.EventMap;
14  
15  import nl.tudelft.simulation.language.Throw;
16  
17  /**
18   * Map-valued historical state. The current map is always maintained, and past states of the map are obtained by applying the
19   * events between now and the requested time in reverse.<br>
20   * <br>
21   * The set views returned by this class are unmodifiable.
22   * <p>
23   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
24   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
25   * <p>
26   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 1 feb. 2018 <br>
27   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
28   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
29   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
30   * @param <K> key type
31   * @param <V> value type
32   * @param <M> map type
33   */
34  public abstract class AbstractHistoricalMap<K, V, M extends Map<K, V>> extends AbstractHistorical<K, EventMap<K, V, M>>
35          implements HistoricalMap<K, V>
36  {
37  
38      /** Current map. */
39      private final M current;
40  
41      /**
42       * Constructor.
43       * @param historyManager HistoryManager; history manager
44       * @param map M; initial map
45       */
46      protected AbstractHistoricalMap(final HistoryManager historyManager, final M map)
47      {
48          super(historyManager);
49          Throw.when(!map.isEmpty(), IllegalArgumentException.class, "The initial map should be empty.");
50          this.current = map;
51      }
52  
53      /**
54       * Returns the internal map.
55       * @return M; internal map
56       */
57      protected M getMap()
58      {
59          return this.current;
60      }
61  
62      /**
63       * Fill map with the current map.
64       * @param map M; map to fill
65       * @return M; input map filled
66       */
67      protected M fill(final M map)
68      {
69          map.putAll(this.current);
70          return map;
71      }
72  
73      /**
74       * Fill map with the map at the given simulation time.
75       * @param time Time; time
76       * @param map M; map to fill
77       * @return M; input map filled
78       */
79      protected M fill(final Time time, final M map)
80      {
81          // copy all current elements and decrement per event
82          map.putAll(this.current);
83          for (EventMap<K, V, M> event : getEvents(time))
84          {
85              event.restore(map);
86          }
87          return map;
88      }
89  
90      // Altering Map methods
91  
92      /** {@inheritDoc} */
93      @Override
94      public void clear()
95      {
96          new HashSet<>(this.current.keySet()).forEach(this::remove);
97      }
98  
99      /** {@inheritDoc} */
100     @Override
101     public V put(final K key, final V value)
102     {
103         boolean contained = this.current.containsKey(key);
104         V previousValue = contained ? this.current.get(key) : null;
105         if (!contained || !Objects.equals(previousValue, value))
106         {
107             addEvent(new EventMap<>(now().si, key, contained, previousValue));
108             return this.current.put(key, value);
109         }
110         return previousValue;
111     }
112 
113     /** {@inheritDoc} */
114     @Override
115     public void putAll(final Map<? extends K, ? extends V> m)
116     {
117         m.forEach(this::put);
118     }
119 
120     /** {@inheritDoc} */
121     @Override
122     @SuppressWarnings("unchecked")
123     public V remove(final Object key)
124     {
125         boolean contained = this.current.containsKey(key);
126         if (contained)
127         {
128             V previousValue = this.current.get(key);
129             addEvent(new EventMap<>(now().si, (K) key, contained, previousValue)); // contains, so safe cast
130             return this.current.remove(key);
131         }
132         return null;
133     }
134 
135     // Non-altering Map methods
136 
137     /** {@inheritDoc} */
138     @Override
139     public int size()
140     {
141         return this.current.size();
142     }
143 
144     /** {@inheritDoc} */
145     @Override
146     public boolean isEmpty()
147     {
148         return this.current.isEmpty();
149     }
150 
151     /** {@inheritDoc} */
152     @Override
153     public boolean containsKey(final Object key)
154     {
155         return this.current.containsKey(key);
156     }
157 
158     /** {@inheritDoc} */
159     @Override
160     public boolean containsValue(final Object value)
161     {
162         return this.current.containsValue(value);
163     }
164 
165     /** {@inheritDoc} */
166     @Override
167     public V get(final Object key)
168     {
169         return this.current.get(key);
170     }
171 
172     /** {@inheritDoc} */
173     @Override
174     public Set<K> keySet()
175     {
176         return Collections.unmodifiableSet(this.current.keySet());
177     }
178 
179     /** {@inheritDoc} */
180     @Override
181     public Collection<V> values()
182     {
183         return Collections.unmodifiableCollection(this.current.values());
184     }
185 
186     /** {@inheritDoc} */
187     @Override
188     public Set<Entry<K, V>> entrySet()
189     {
190         // need to ensure that the Entries themselves allow no alterations
191         return Collections.unmodifiableMap(this.current).entrySet();
192     }
193 
194     // Events
195 
196     /**
197      * Abstract super class for events that add or remove a value from the map.
198      * <p>
199      * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
200      * <br>
201      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
202      * <p>
203      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 1 jan. 2018 <br>
204      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
205      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
206      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
207      * @param <K> key type
208      * @param <V> value type
209      * @param <M> map type
210      */
211     public static class EventMap<K, V, M extends Map<K, V>> extends AbstractHistorical.EventValue<K>
212     {
213 
214         /** Whether the map contained the key prior to the event. */
215         private final boolean contained;
216 
217         /** Previous value in the map. */
218         private final V previousValue;
219 
220         /**
221          * Constructor.
222          * @param time double; time of event
223          * @param key K; key of event
224          * @param contained boolean; whether the map contained the key prior to the event
225          * @param previousValue V; previous value in the map
226          */
227         public EventMap(final double time, final K key, final boolean contained, final V previousValue)
228         {
229             super(time, key);
230             this.contained = contained;
231             this.previousValue = previousValue;
232         }
233 
234         /**
235          * Restores the map to the state of before the event.
236          * @param map M; map to restore
237          */
238         public void restore(final M map)
239         {
240             if (this.contained)
241             {
242                 map.put(getValue(), this.previousValue); // event value = map key
243             }
244             else
245             {
246                 map.remove(getValue()); // event value = map key
247             }
248         }
249 
250         /** {@inheritDoc} */
251         @Override
252         public String toString()
253         {
254             return "EventMap [contained=" + this.contained + ", previousValue=" + this.previousValue + "]";
255         }
256 
257     }
258 
259 }