Home | History | Annotate | Download | only in testing
      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 java.io.Serializable;
     20 import java.util.Collection;
     21 import java.util.Comparator;
     22 import java.util.Map;
     23 import java.util.NavigableMap;
     24 import java.util.NavigableSet;
     25 import java.util.Set;
     26 import java.util.SortedMap;
     27 import java.util.TreeMap;
     28 
     29 /**
     30  * A wrapper around {@code TreeMap} that aggressively checks to see if keys are
     31  * mutually comparable. This implementation passes the navigable map test
     32  * suites.
     33  *
     34  * @author Louis Wasserman
     35  */
     36 public final class SafeTreeMap<K, V>
     37     implements Serializable, NavigableMap<K, V> {
     38   @SuppressWarnings("unchecked")
     39   private static final Comparator NATURAL_ORDER = new Comparator<Comparable>() {
     40     @Override public int compare(Comparable o1, Comparable o2) {
     41       return o1.compareTo(o2);
     42     }
     43   };
     44   private final NavigableMap<K, V> delegate;
     45 
     46   public SafeTreeMap() {
     47     this(new TreeMap<K, V>());
     48   }
     49 
     50   public SafeTreeMap(Comparator<? super K> comparator) {
     51     this(new TreeMap<K, V>(comparator));
     52   }
     53 
     54   public SafeTreeMap(Map<? extends K, ? extends V> map) {
     55     this(new TreeMap<K, V>(map));
     56   }
     57 
     58   public SafeTreeMap(SortedMap<K, ? extends V> map) {
     59     this(new TreeMap<K, V>(map));
     60   }
     61 
     62   private SafeTreeMap(NavigableMap<K, V> delegate) {
     63     this.delegate = delegate;
     64     if (delegate == null) {
     65       throw new NullPointerException();
     66     }
     67     for (K k : keySet()) {
     68       checkValid(k);
     69     }
     70   }
     71 
     72   @Override public Entry<K, V> ceilingEntry(K key) {
     73     return delegate.ceilingEntry(checkValid(key));
     74   }
     75 
     76   @Override public K ceilingKey(K key) {
     77     return delegate.ceilingKey(checkValid(key));
     78   }
     79 
     80   @Override public void clear() {
     81     delegate.clear();
     82   }
     83 
     84   @SuppressWarnings("unchecked")
     85   @Override public Comparator<? super K> comparator() {
     86     Comparator<? super K> comparator = delegate.comparator();
     87     if (comparator == null) {
     88       comparator = NATURAL_ORDER;
     89     }
     90     return comparator;
     91   }
     92 
     93   @Override public boolean containsKey(Object key) {
     94     try {
     95       return delegate.containsKey(checkValid(key));
     96     } catch (NullPointerException e) {
     97       return false;
     98     } catch (ClassCastException e) {
     99       return false;
    100     }
    101   }
    102 
    103   @Override public boolean containsValue(Object value) {
    104     return delegate.containsValue(value);
    105   }
    106 
    107   @Override public NavigableSet<K> descendingKeySet() {
    108     return delegate.descendingKeySet();
    109   }
    110 
    111   @Override public NavigableMap<K, V> descendingMap() {
    112     return new SafeTreeMap<K, V>(delegate.descendingMap());
    113   }
    114 
    115   @Override public Set<Entry<K, V>> entrySet() {
    116     return delegate.entrySet();
    117   }
    118 
    119   @Override public Entry<K, V> firstEntry() {
    120     return delegate.firstEntry();
    121   }
    122 
    123   @Override public K firstKey() {
    124     return delegate.firstKey();
    125   }
    126 
    127   @Override public Entry<K, V> floorEntry(K key) {
    128     return delegate.floorEntry(checkValid(key));
    129   }
    130 
    131   @Override public K floorKey(K key) {
    132     return delegate.floorKey(checkValid(key));
    133   }
    134 
    135   @Override public V get(Object key) {
    136     return delegate.get(checkValid(key));
    137   }
    138 
    139   @Override public SortedMap<K, V> headMap(K toKey) {
    140     return headMap(toKey, false);
    141   }
    142 
    143   @Override public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
    144     return new SafeTreeMap<K, V>(
    145         delegate.headMap(checkValid(toKey), inclusive));
    146   }
    147 
    148   @Override public Entry<K, V> higherEntry(K key) {
    149     return delegate.higherEntry(checkValid(key));
    150   }
    151 
    152   @Override public K higherKey(K key) {
    153     return delegate.higherKey(checkValid(key));
    154   }
    155 
    156   @Override public boolean isEmpty() {
    157     return delegate.isEmpty();
    158   }
    159 
    160   @Override public NavigableSet<K> keySet() {
    161     return navigableKeySet();
    162   }
    163 
    164   @Override public Entry<K, V> lastEntry() {
    165     return delegate.lastEntry();
    166   }
    167 
    168   @Override public K lastKey() {
    169     return delegate.lastKey();
    170   }
    171 
    172   @Override public Entry<K, V> lowerEntry(K key) {
    173     return delegate.lowerEntry(checkValid(key));
    174   }
    175 
    176   @Override public K lowerKey(K key) {
    177     return delegate.lowerKey(checkValid(key));
    178   }
    179 
    180   @Override public NavigableSet<K> navigableKeySet() {
    181     return delegate.navigableKeySet();
    182   }
    183 
    184   @Override public Entry<K, V> pollFirstEntry() {
    185     return delegate.pollFirstEntry();
    186   }
    187 
    188   @Override public Entry<K, V> pollLastEntry() {
    189     return delegate.pollLastEntry();
    190   }
    191 
    192   @Override public V put(K key, V value) {
    193     return delegate.put(checkValid(key), value);
    194   }
    195 
    196   @Override public void putAll(Map<? extends K, ? extends V> map) {
    197     for (K key : map.keySet()) {
    198       checkValid(key);
    199     }
    200     delegate.putAll(map);
    201   }
    202 
    203   @Override public V remove(Object key) {
    204     return delegate.remove(checkValid(key));
    205   }
    206 
    207   @Override public int size() {
    208     return delegate.size();
    209   }
    210 
    211   @Override public NavigableMap<K, V> subMap(
    212       K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
    213     return new SafeTreeMap<K, V>(delegate.subMap(
    214         checkValid(fromKey), fromInclusive, checkValid(toKey), toInclusive));
    215   }
    216 
    217   @Override public SortedMap<K, V> subMap(K fromKey, K toKey) {
    218     return subMap(fromKey, true, toKey, false);
    219   }
    220 
    221   @Override public SortedMap<K, V> tailMap(K fromKey) {
    222     return tailMap(fromKey, true);
    223   }
    224 
    225   @Override public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
    226     return new SafeTreeMap<K, V>(
    227         delegate.tailMap(checkValid(fromKey), inclusive));
    228   }
    229 
    230   @Override public Collection<V> values() {
    231     return delegate.values();
    232   }
    233 
    234   private <T> T checkValid(T t) {
    235     // a ClassCastException is what's supposed to happen!
    236     @SuppressWarnings("unchecked")
    237     K k = (K) t;
    238     comparator().compare(k, k);
    239     return t;
    240   }
    241 
    242   @Override public boolean equals(Object obj) {
    243     return delegate.equals(obj);
    244   }
    245 
    246   @Override public int hashCode() {
    247     return delegate.hashCode();
    248   }
    249 
    250   @Override public String toString() {
    251     return delegate.toString();
    252   }
    253 
    254   private static final long serialVersionUID = 0L;
    255 }
    256