SafeTreeMap.java revision 7dd252788645e940eada959bdde927426e2531c9
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
17package com.google.common.collect.testing;
18
19import java.io.Serializable;
20import java.util.Collection;
21import java.util.Comparator;
22import java.util.Map;
23import java.util.Set;
24import java.util.SortedMap;
25import java.util.TreeMap;
26
27/**
28 * A wrapper around {@code TreeMap} that aggressively checks to see if keys are
29 * mutually comparable. This implementation passes the navigable map test
30 * suites.
31 *
32 * @author Louis Wasserman
33 */
34public final class SafeTreeMap<K, V> implements Serializable, SortedMap<K, V> {
35  @SuppressWarnings("unchecked")
36  private static final Comparator NATURAL_ORDER = new Comparator<Comparable>() {
37    @Override public int compare(Comparable o1, Comparable o2) {
38      return o1.compareTo(o2);
39    }
40  };
41  private final SortedMap<K, V> delegate;
42
43  public SafeTreeMap() {
44    this(new TreeMap<K, V>());
45  }
46
47  public SafeTreeMap(Comparator<? super K> comparator) {
48    this(new TreeMap<K, V>(comparator));
49  }
50
51  public SafeTreeMap(Map<? extends K, ? extends V> map) {
52    this(new TreeMap<K, V>(map));
53  }
54
55  private SafeTreeMap(SortedMap<K, V> delegate) {
56    this.delegate = delegate;
57    if (delegate == null) {
58      throw new NullPointerException();
59    }
60    for (K k : keySet()) {
61      checkValid(k);
62    }
63  }
64
65  @Override public void clear() {
66    delegate.clear();
67  }
68
69  @SuppressWarnings("unchecked")
70  @Override public Comparator<? super K> comparator() {
71    Comparator<? super K> comparator = delegate.comparator();
72    if (comparator == null) {
73      comparator = NATURAL_ORDER;
74    }
75    return comparator;
76  }
77
78  @Override public boolean containsKey(Object key) {
79    try {
80      return delegate.containsKey(checkValid(key));
81    } catch (NullPointerException e) {
82      return false;
83    } catch (ClassCastException e) {
84      return false;
85    }
86  }
87
88  @Override public boolean containsValue(Object value) {
89    return delegate.containsValue(value);
90  }
91
92  @Override public Set<Entry<K, V>> entrySet() {
93    return delegate.entrySet();
94  }
95
96  @Override public K firstKey() {
97    return delegate.firstKey();
98  }
99
100  @Override public V get(Object key) {
101    return delegate.get(checkValid(key));
102  }
103
104  @Override public SortedMap<K, V> headMap(K toKey) {
105    return new SafeTreeMap<K, V>(delegate.headMap(checkValid(toKey)));
106  }
107
108  @Override public boolean isEmpty() {
109    return delegate.isEmpty();
110  }
111
112  @Override public Set<K> keySet() {
113    return delegate.keySet();
114  }
115
116  @Override public K lastKey() {
117    return delegate.lastKey();
118  }
119
120  @Override public V put(K key, V value) {
121    return delegate.put(checkValid(key), value);
122  }
123
124  @Override public void putAll(Map<? extends K, ? extends V> map) {
125    for (K key : map.keySet()) {
126      checkValid(key);
127    }
128    delegate.putAll(map);
129  }
130
131  @Override public V remove(Object key) {
132    return delegate.remove(checkValid(key));
133  }
134
135  @Override public int size() {
136    return delegate.size();
137  }
138
139  @Override public SortedMap<K, V> subMap(K fromKey, K toKey) {
140    return new SafeTreeMap<K, V>(delegate.subMap(checkValid(fromKey), checkValid(toKey)));
141  }
142
143  @Override public SortedMap<K, V> tailMap(K fromKey) {
144    return new SafeTreeMap<K, V>(delegate.tailMap(checkValid(fromKey)));
145  }
146
147  @Override public Collection<V> values() {
148    return delegate.values();
149  }
150
151  private <T> T checkValid(T t) {
152    // a ClassCastException is what's supposed to happen!
153    @SuppressWarnings("unchecked")
154    K k = (K) t;
155    comparator().compare(k, k);
156    return t;
157  }
158
159  @Override public boolean equals(Object obj) {
160    return delegate.equals(obj);
161  }
162
163  @Override public int hashCode() {
164    return delegate.hashCode();
165  }
166
167  @Override public String toString() {
168    return delegate.toString();
169  }
170
171  private static final long serialVersionUID = 0L;
172
173}
174