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
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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
39 private final M current;
40
41
42
43
44
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
55
56
57 protected M getMap()
58 {
59 return this.current;
60 }
61
62
63
64
65
66
67 protected M fill(final M map)
68 {
69 map.putAll(this.current);
70 return map;
71 }
72
73
74
75
76
77
78
79 protected M fill(final Time time, final M map)
80 {
81
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
91
92
93 @Override
94 public void clear()
95 {
96 new HashSet<>(this.current.keySet()).forEach(this::remove);
97 }
98
99
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
114 @Override
115 public void putAll(final Map<? extends K, ? extends V> m)
116 {
117 m.forEach(this::put);
118 }
119
120
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));
130 return this.current.remove(key);
131 }
132 return null;
133 }
134
135
136
137
138 @Override
139 public int size()
140 {
141 return this.current.size();
142 }
143
144
145 @Override
146 public boolean isEmpty()
147 {
148 return this.current.isEmpty();
149 }
150
151
152 @Override
153 public boolean containsKey(final Object key)
154 {
155 return this.current.containsKey(key);
156 }
157
158
159 @Override
160 public boolean containsValue(final Object value)
161 {
162 return this.current.containsValue(value);
163 }
164
165
166 @Override
167 public V get(final Object key)
168 {
169 return this.current.get(key);
170 }
171
172
173 @Override
174 public Set<K> keySet()
175 {
176 return Collections.unmodifiableSet(this.current.keySet());
177 }
178
179
180 @Override
181 public Collection<V> values()
182 {
183 return Collections.unmodifiableCollection(this.current.values());
184 }
185
186
187 @Override
188 public Set<Entry<K, V>> entrySet()
189 {
190
191 return Collections.unmodifiableMap(this.current).entrySet();
192 }
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211 public static class EventMap<K, V, M extends Map<K, V>> extends AbstractHistorical.EventValue<K>
212 {
213
214
215 private final boolean contained;
216
217
218 private final V previousValue;
219
220
221
222
223
224
225
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
236
237
238 public void restore(final M map)
239 {
240 if (this.contained)
241 {
242 map.put(getValue(), this.previousValue);
243 }
244 else
245 {
246 map.remove(getValue());
247 }
248 }
249
250
251 @Override
252 public String toString()
253 {
254 return "EventMap [contained=" + this.contained + ", previousValue=" + this.previousValue + "]";
255 }
256
257 }
258
259 }