• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Guava Authors
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  * http://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 
17 package com.google.common.collect.testing;
18 
19 import com.google.common.annotations.GwtIncompatible;
20 import com.google.errorprone.annotations.CanIgnoreReturnValue;
21 import java.io.Serializable;
22 import java.util.AbstractSet;
23 import java.util.Collection;
24 import java.util.Comparator;
25 import java.util.Iterator;
26 import java.util.Map;
27 import java.util.NavigableMap;
28 import java.util.NavigableSet;
29 import java.util.Set;
30 import java.util.SortedMap;
31 import java.util.TreeMap;
32 import org.checkerframework.checker.nullness.qual.Nullable;
33 
34 /**
35  * A wrapper around {@code TreeMap} that aggressively checks to see if keys are mutually comparable.
36  * This implementation passes the navigable map test suites.
37  *
38  * @author Louis Wasserman
39  */
40 @GwtIncompatible
41 public final class SafeTreeMap<K, V> implements Serializable, NavigableMap<K, V> {
42   @SuppressWarnings("unchecked")
43   private static final Comparator<Object> NATURAL_ORDER =
44       new Comparator<Object>() {
45         @Override
46         public int compare(Object o1, Object o2) {
47           return ((Comparable<Object>) o1).compareTo(o2);
48         }
49       };
50 
51   private final NavigableMap<K, V> delegate;
52 
SafeTreeMap()53   public SafeTreeMap() {
54     this(new TreeMap<K, V>());
55   }
56 
SafeTreeMap(Comparator<? super K> comparator)57   public SafeTreeMap(Comparator<? super K> comparator) {
58     this(new TreeMap<K, V>(comparator));
59   }
60 
SafeTreeMap(Map<? extends K, ? extends V> map)61   public SafeTreeMap(Map<? extends K, ? extends V> map) {
62     this(new TreeMap<K, V>(map));
63   }
64 
SafeTreeMap(SortedMap<K, ? extends V> map)65   public SafeTreeMap(SortedMap<K, ? extends V> map) {
66     this(new TreeMap<K, V>(map));
67   }
68 
SafeTreeMap(NavigableMap<K, V> delegate)69   private SafeTreeMap(NavigableMap<K, V> delegate) {
70     this.delegate = delegate;
71     if (delegate == null) {
72       throw new NullPointerException();
73     }
74     for (K k : keySet()) {
75       checkValid(k);
76     }
77   }
78 
79   @Override
ceilingEntry(K key)80   public @Nullable Entry<K, V> ceilingEntry(K key) {
81     return delegate.ceilingEntry(checkValid(key));
82   }
83 
84   @Override
ceilingKey(K key)85   public @Nullable K ceilingKey(K key) {
86     return delegate.ceilingKey(checkValid(key));
87   }
88 
89   @Override
clear()90   public void clear() {
91     delegate.clear();
92   }
93 
94   @SuppressWarnings("unchecked")
95   @Override
comparator()96   public Comparator<? super K> comparator() {
97     Comparator<? super K> comparator = delegate.comparator();
98     if (comparator == null) {
99       comparator = (Comparator<? super K>) NATURAL_ORDER;
100     }
101     return comparator;
102   }
103 
104   @Override
containsKey(Object key)105   public boolean containsKey(Object key) {
106     try {
107       return delegate.containsKey(checkValid(key));
108     } catch (NullPointerException | ClassCastException e) {
109       return false;
110     }
111   }
112 
113   @Override
containsValue(Object value)114   public boolean containsValue(Object value) {
115     return delegate.containsValue(value);
116   }
117 
118   @Override
descendingKeySet()119   public NavigableSet<K> descendingKeySet() {
120     return delegate.descendingKeySet();
121   }
122 
123   @Override
descendingMap()124   public NavigableMap<K, V> descendingMap() {
125     return new SafeTreeMap<>(delegate.descendingMap());
126   }
127 
128   @Override
entrySet()129   public Set<Entry<K, V>> entrySet() {
130     return new AbstractSet<Entry<K, V>>() {
131       private Set<Entry<K, V>> delegate() {
132         return delegate.entrySet();
133       }
134 
135       @Override
136       public boolean contains(Object object) {
137         try {
138           return delegate().contains(object);
139         } catch (NullPointerException | ClassCastException e) {
140           return false;
141         }
142       }
143 
144       @Override
145       public Iterator<Entry<K, V>> iterator() {
146         return delegate().iterator();
147       }
148 
149       @Override
150       public int size() {
151         return delegate().size();
152       }
153 
154       @Override
155       public boolean remove(Object o) {
156         return delegate().remove(o);
157       }
158 
159       @Override
160       public void clear() {
161         delegate().clear();
162       }
163     };
164   }
165 
166   @Override
167   public @Nullable Entry<K, V> firstEntry() {
168     return delegate.firstEntry();
169   }
170 
171   @Override
172   public K firstKey() {
173     return delegate.firstKey();
174   }
175 
176   @Override
177   public @Nullable Entry<K, V> floorEntry(K key) {
178     return delegate.floorEntry(checkValid(key));
179   }
180 
181   @Override
182   public @Nullable K floorKey(K key) {
183     return delegate.floorKey(checkValid(key));
184   }
185 
186   @Override
187   public @Nullable V get(Object key) {
188     return delegate.get(checkValid(key));
189   }
190 
191   @Override
192   public SortedMap<K, V> headMap(K toKey) {
193     return headMap(toKey, false);
194   }
195 
196   @Override
197   public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
198     return new SafeTreeMap<>(delegate.headMap(checkValid(toKey), inclusive));
199   }
200 
201   @Override
202   public @Nullable Entry<K, V> higherEntry(K key) {
203     return delegate.higherEntry(checkValid(key));
204   }
205 
206   @Override
207   public @Nullable K higherKey(K key) {
208     return delegate.higherKey(checkValid(key));
209   }
210 
211   @Override
212   public boolean isEmpty() {
213     return delegate.isEmpty();
214   }
215 
216   @Override
217   public NavigableSet<K> keySet() {
218     return navigableKeySet();
219   }
220 
221   @Override
222   public @Nullable Entry<K, V> lastEntry() {
223     return delegate.lastEntry();
224   }
225 
226   @Override
227   public K lastKey() {
228     return delegate.lastKey();
229   }
230 
231   @Override
232   public @Nullable Entry<K, V> lowerEntry(K key) {
233     return delegate.lowerEntry(checkValid(key));
234   }
235 
236   @Override
237   public @Nullable K lowerKey(K key) {
238     return delegate.lowerKey(checkValid(key));
239   }
240 
241   @Override
242   public NavigableSet<K> navigableKeySet() {
243     return delegate.navigableKeySet();
244   }
245 
246   @Override
247   public @Nullable Entry<K, V> pollFirstEntry() {
248     return delegate.pollFirstEntry();
249   }
250 
251   @Override
252   public @Nullable Entry<K, V> pollLastEntry() {
253     return delegate.pollLastEntry();
254   }
255 
256   @Override
257   public @Nullable V put(K key, V value) {
258     return delegate.put(checkValid(key), value);
259   }
260 
261   @Override
262   public void putAll(Map<? extends K, ? extends V> map) {
263     for (K key : map.keySet()) {
264       checkValid(key);
265     }
266     delegate.putAll(map);
267   }
268 
269   @Override
270   public @Nullable V remove(Object key) {
271     return delegate.remove(checkValid(key));
272   }
273 
274   @Override
275   public int size() {
276     return delegate.size();
277   }
278 
279   @Override
280   public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
281     return new SafeTreeMap<>(
282         delegate.subMap(checkValid(fromKey), fromInclusive, checkValid(toKey), toInclusive));
283   }
284 
285   @Override
286   public SortedMap<K, V> subMap(K fromKey, K toKey) {
287     return subMap(fromKey, true, toKey, false);
288   }
289 
290   @Override
291   public SortedMap<K, V> tailMap(K fromKey) {
292     return tailMap(fromKey, true);
293   }
294 
295   @Override
296   public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
297     return new SafeTreeMap<>(delegate.tailMap(checkValid(fromKey), inclusive));
298   }
299 
300   @Override
301   public Collection<V> values() {
302     return delegate.values();
303   }
304 
305   @CanIgnoreReturnValue
306   private <T> T checkValid(T t) {
307     // a ClassCastException is what's supposed to happen!
308     @SuppressWarnings("unchecked")
309     K k = (K) t;
310     int unused = comparator().compare(k, k);
311     return t;
312   }
313 
314   @Override
315   public boolean equals(@Nullable Object obj) {
316     return delegate.equals(obj);
317   }
318 
319   @Override
320   public int hashCode() {
321     return delegate.hashCode();
322   }
323 
324   @Override
325   public String toString() {
326     return delegate.toString();
327   }
328 
329   private static final long serialVersionUID = 0L;
330 }
331