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