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