001/* 002 * Copyright (C) 2010 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.collect.testing; 018 019import com.google.common.annotations.GwtIncompatible; 020import com.google.errorprone.annotations.CanIgnoreReturnValue; 021import java.io.Serializable; 022import java.util.AbstractSet; 023import java.util.Collection; 024import java.util.Comparator; 025import java.util.Iterator; 026import java.util.Map; 027import java.util.NavigableMap; 028import java.util.NavigableSet; 029import java.util.Set; 030import java.util.SortedMap; 031import java.util.TreeMap; 032import org.checkerframework.checker.nullness.qual.Nullable; 033 034/** 035 * A wrapper around {@code TreeMap} that aggressively checks to see if keys are mutually comparable. 036 * This implementation passes the navigable map test suites. 037 * 038 * @author Louis Wasserman 039 */ 040@GwtIncompatible 041public final class SafeTreeMap<K, V> implements Serializable, NavigableMap<K, V> { 042 @SuppressWarnings("unchecked") 043 private static final Comparator<Object> NATURAL_ORDER = 044 new Comparator<Object>() { 045 @Override 046 public int compare(Object o1, Object o2) { 047 return ((Comparable<Object>) o1).compareTo(o2); 048 } 049 }; 050 051 private final NavigableMap<K, V> delegate; 052 053 public SafeTreeMap() { 054 this(new TreeMap<K, V>()); 055 } 056 057 public SafeTreeMap(Comparator<? super K> comparator) { 058 this(new TreeMap<K, V>(comparator)); 059 } 060 061 public SafeTreeMap(Map<? extends K, ? extends V> map) { 062 this(new TreeMap<K, V>(map)); 063 } 064 065 public SafeTreeMap(SortedMap<K, ? extends V> map) { 066 this(new TreeMap<K, V>(map)); 067 } 068 069 private SafeTreeMap(NavigableMap<K, V> delegate) { 070 this.delegate = delegate; 071 if (delegate == null) { 072 throw new NullPointerException(); 073 } 074 for (K k : keySet()) { 075 checkValid(k); 076 } 077 } 078 079 @Override 080 public @Nullable Entry<K, V> ceilingEntry(K key) { 081 return delegate.ceilingEntry(checkValid(key)); 082 } 083 084 @Override 085 public @Nullable K ceilingKey(K key) { 086 return delegate.ceilingKey(checkValid(key)); 087 } 088 089 @Override 090 public void clear() { 091 delegate.clear(); 092 } 093 094 @SuppressWarnings("unchecked") 095 @Override 096 public Comparator<? super K> comparator() { 097 Comparator<? super K> comparator = delegate.comparator(); 098 if (comparator == null) { 099 comparator = (Comparator<? super K>) NATURAL_ORDER; 100 } 101 return comparator; 102 } 103 104 @Override 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 114 public boolean containsValue(Object value) { 115 return delegate.containsValue(value); 116 } 117 118 @Override 119 public NavigableSet<K> descendingKeySet() { 120 return delegate.descendingKeySet(); 121 } 122 123 @Override 124 public NavigableMap<K, V> descendingMap() { 125 return new SafeTreeMap<>(delegate.descendingMap()); 126 } 127 128 @Override 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}