RobotCore 1.0
WPILib port to raspberry Pi
Loading...
Searching...
No Matches
StringPrefixMap.java
1/*
2 * Copyright (C) 2018-2021 Niels Basjes
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.wpilib.util.collections.prefixmap;
18
19import java.util.AbstractCollection;
20import java.util.AbstractSet;
21import java.util.Collection;
22import java.util.Iterator;
23import java.util.Map;
24import java.util.Objects;
25import java.util.PrimitiveIterator;
26import java.util.Set;
27import java.util.TreeMap;
28import org.wpilib.util.collections.PrefixMap;
29
36public class StringPrefixMap<V> implements PrefixMap<V> {
37 private final PrefixTrie<V> m_prefixTrie;
38 private final TreeMap<String, V> m_allPrefixes;
39 private final Set<Map.Entry<String, V>> m_entrySet;
40 private final Set<String> m_keySet;
41 private final Collection<V> m_values;
42
44 @SuppressWarnings("this-escape")
45 public StringPrefixMap() {
46 m_prefixTrie = new StringPrefixTrie<>();
47 m_allPrefixes = new TreeMap<>();
48 m_entrySet = new EntrySet();
49 m_keySet = new KeySet();
50 m_values = new Values();
51 }
52
53 @Override
54 public boolean containsPrefix(PrimitiveIterator.OfInt prefix) {
55 return m_prefixTrie.containsPrefix(prefix);
56 }
57
58 private String storedKey(String key) {
59 return key;
60 }
61
62 @Override
63 public V put(String prefix, V value) {
64 Objects.requireNonNull(prefix, "The prefix may not be null");
65 Objects.requireNonNull(value, "The value may not be null");
66
67 V previousValue = m_prefixTrie.add(prefix, value);
68 m_allPrefixes.put(storedKey(prefix), value);
69 return previousValue;
70 }
71
72 @Override
73 public int size() {
74 return m_allPrefixes.size();
75 }
76
77 @Override
78 public void clear() {
79 m_prefixTrie.clear();
80 m_allPrefixes.clear();
81 }
82
83 @Override
84 public V remove(String prefix) {
85 Objects.requireNonNull(prefix, "The prefix may not be null");
86 V oldValue = m_prefixTrie.remove(prefix);
87 if (oldValue != null) {
88 m_allPrefixes.remove(storedKey(prefix));
89 }
90 return oldValue;
91 }
92
93 @Override
94 public V get(String prefix) {
95 return m_prefixTrie.get(prefix);
96 }
97
98 @Override
99 public V getShortestMatch(PrimitiveIterator.OfInt input) {
100 return m_prefixTrie.getShortestMatch(input);
101 }
102
103 @Override
104 public V getLongestMatch(PrimitiveIterator.OfInt input) {
105 return m_prefixTrie.getLongestMatch(input);
106 }
107
108 @Override
109 public Iterator<V> getAllMatches(PrimitiveIterator.OfInt input) {
110 return m_prefixTrie.getAllMatches(input);
111 }
112
113 @Override
114 public Set<Map.Entry<String, V>> entrySet() {
115 return m_entrySet;
116 }
117
118 @Override
119 public boolean containsKey(Object key) {
120 return key instanceof String && m_allPrefixes.containsKey(storedKey((String) key));
121 }
122
123 @Override
124 public boolean containsValue(Object value) {
125 return m_allPrefixes.containsValue(value);
126 }
127
128 @Override
129 public Set<String> keySet() {
130 return m_keySet;
131 }
132
133 @Override
134 public Collection<V> values() {
135 return m_values;
136 }
137
138 @Override
139 public boolean equals(Object obj) {
140 return obj == this || m_allPrefixes.equals(obj);
141 }
142
143 @Override
144 public int hashCode() {
145 return m_allPrefixes.hashCode();
146 }
147
148 private abstract class BackingIterator<T> implements Iterator<T> {
149 private final Iterator<Map.Entry<String, V>> m_iterator = m_allPrefixes.entrySet().iterator();
150 private Map.Entry<String, V> m_current;
151
152 @Override
153 public boolean hasNext() {
154 return m_iterator.hasNext();
155 }
156
157 protected Map.Entry<String, V> nextEntry() {
158 m_current = m_iterator.next();
159 return m_current;
160 }
161
162 @Override
163 public void remove() {
164 if (m_current == null) {
165 throw new IllegalStateException();
166 }
167 String key = m_current.getKey();
168 m_iterator.remove();
169 m_prefixTrie.remove(key);
170 m_current = null;
171 }
172 }
173
174 private final class EntryIterator extends BackingIterator<Map.Entry<String, V>> {
175 @Override
176 public Map.Entry<String, V> next() {
177 return new PrefixEntry(nextEntry());
178 }
179 }
180
181 private final class KeyIterator extends BackingIterator<String> {
182 @Override
183 public String next() {
184 return nextEntry().getKey();
185 }
186 }
187
188 private final class ValueIterator extends BackingIterator<V> {
189 @Override
190 public V next() {
191 return nextEntry().getValue();
192 }
193 }
194
195 private final class PrefixEntry implements Map.Entry<String, V> {
196 private final Map.Entry<String, V> m_entry;
197
198 PrefixEntry(Map.Entry<String, V> entry) {
199 m_entry = entry;
200 }
201
202 @Override
203 public String getKey() {
204 return m_entry.getKey();
205 }
206
207 @Override
208 public V getValue() {
209 return m_entry.getValue();
210 }
211
212 @Override
213 public V setValue(V value) {
214 Objects.requireNonNull(value, "The value may not be null");
215 m_prefixTrie.add(getKey(), value);
216 return m_entry.setValue(value);
217 }
218
219 @Override
220 public boolean equals(Object obj) {
221 if (!(obj instanceof Map.Entry<?, ?>)) {
222 return false;
223 }
224 Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj;
225 return Objects.equals(getKey(), other.getKey())
226 && Objects.equals(getValue(), other.getValue());
227 }
228
229 @Override
230 public int hashCode() {
231 return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
232 }
233 }
234
235 private final class EntrySet extends AbstractSet<Map.Entry<String, V>> {
236 @Override
237 public Iterator<Map.Entry<String, V>> iterator() {
238 return new EntryIterator();
239 }
240
241 @Override
242 public int size() {
243 return StringPrefixMap.this.size();
244 }
245
246 @Override
247 public boolean contains(Object obj) {
248 if (!(obj instanceof Map.Entry<?, ?>)) {
249 return false;
250 }
251 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
252 Object key = entry.getKey();
253 if (!(key instanceof String)) {
254 return false;
255 }
256 String prefix = storedKey((String) key);
257 return m_allPrefixes.containsKey(prefix)
258 && Objects.equals(m_allPrefixes.get(prefix), entry.getValue());
259 }
260
261 @Override
262 public boolean remove(Object obj) {
263 if (!(obj instanceof Map.Entry<?, ?>)) {
264 return false;
265 }
266 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
267 Object key = entry.getKey();
268 if (!(key instanceof String)) {
269 return false;
270 }
271 String prefix = storedKey((String) key);
272 if (!m_allPrefixes.containsKey(prefix)
273 || !Objects.equals(m_allPrefixes.get(prefix), entry.getValue())) {
274 return false;
275 }
276 StringPrefixMap.this.remove(prefix);
277 return true;
278 }
279
280 @Override
281 public void clear() {
282 StringPrefixMap.this.clear();
283 }
284 }
285
286 private final class KeySet extends AbstractSet<String> {
287 @Override
288 public Iterator<String> iterator() {
289 return new KeyIterator();
290 }
291
292 @Override
293 public int size() {
294 return StringPrefixMap.this.size();
295 }
296
297 @Override
298 public boolean contains(Object key) {
299 return StringPrefixMap.this.containsKey(key);
300 }
301
302 @Override
303 public boolean remove(Object key) {
304 return key instanceof String && StringPrefixMap.this.remove((String) key) != null;
305 }
306
307 @Override
308 public void clear() {
309 StringPrefixMap.this.clear();
310 }
311 }
312
313 private final class Values extends AbstractCollection<V> {
314 @Override
315 public Iterator<V> iterator() {
316 return new ValueIterator();
317 }
318
319 @Override
320 public int size() {
321 return StringPrefixMap.this.size();
322 }
323
324 @Override
325 public boolean contains(Object value) {
326 return StringPrefixMap.this.containsValue(value);
327 }
328
329 @Override
330 public void clear() {
331 StringPrefixMap.this.clear();
332 }
333 }
334}
boolean containsPrefix(PrimitiveIterator.OfInt prefix)
Iterator< V > getAllMatches(PrimitiveIterator.OfInt input)