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.Iterator;
23import java.util.SortedSet;
24import java.util.TreeSet;
25
26/**
27 * A wrapper around {@code TreeSet} that aggressively checks to see if elements
28 * are mutually comparable. This implementation passes the navigable set test
29 * suites.
30 *
31 * @author Louis Wasserman
32 */
33public final class SafeTreeSet<E> implements Serializable, SortedSet<E> {
34  @SuppressWarnings("unchecked")
35  private static final Comparator<Object> NATURAL_ORDER = new Comparator<Object>() {
36    @Override public int compare(Object o1, Object o2) {
37      return ((Comparable<Object>) o1).compareTo(o2);
38    }
39  };
40  private final SortedSet<E> delegate;
41
42  public SafeTreeSet() {
43    this(new TreeSet<E>());
44  }
45
46  public SafeTreeSet(Collection<? extends E> collection) {
47    this(new TreeSet<E>(collection));
48  }
49
50  public SafeTreeSet(Comparator<? super E> comparator) {
51    this(new TreeSet<E>(comparator));
52  }
53
54  private SafeTreeSet(SortedSet<E> delegate) {
55    this.delegate = delegate;
56    for (E e : this) {
57      checkValid(e);
58    }
59  }
60
61  @Override public boolean add(E element) {
62    return delegate.add(checkValid(element));
63  }
64
65  @Override public boolean addAll(Collection<? extends E> collection) {
66    for (E e : collection) {
67      checkValid(e);
68    }
69    return delegate.addAll(collection);
70  }
71
72  @Override public void clear() {
73    delegate.clear();
74  }
75
76  @SuppressWarnings("unchecked")
77  @Override public Comparator<? super E> comparator() {
78    Comparator<? super E> comparator = delegate.comparator();
79    if (comparator == null) {
80      comparator = (Comparator<? super E>) NATURAL_ORDER;
81    }
82    return comparator;
83  }
84
85  @Override public boolean contains(Object object) {
86    return delegate.contains(checkValid(object));
87  }
88
89  @Override public boolean containsAll(Collection<?> c) {
90    return delegate.containsAll(c);
91  }
92
93  @Override public E first() {
94    return delegate.first();
95  }
96
97  @Override public SortedSet<E> headSet(E toElement) {
98    return new SafeTreeSet<E>(delegate.headSet(checkValid(toElement)));
99  }
100
101  @Override public boolean isEmpty() {
102    return delegate.isEmpty();
103  }
104
105  @Override public Iterator<E> iterator() {
106    return delegate.iterator();
107  }
108
109  @Override public E last() {
110    return delegate.last();
111  }
112
113  @Override public boolean remove(Object object) {
114    return delegate.remove(checkValid(object));
115  }
116
117  @Override public boolean removeAll(Collection<?> c) {
118    return delegate.removeAll(c);
119  }
120
121  @Override public boolean retainAll(Collection<?> c) {
122    return delegate.retainAll(c);
123  }
124
125  @Override public int size() {
126    return delegate.size();
127  }
128
129
130  @Override public SortedSet<E> subSet(E fromElement, E toElement) {
131    return new SafeTreeSet<E>(delegate.subSet(checkValid(fromElement), checkValid(toElement)));
132  }
133
134  @Override public SortedSet<E> tailSet(E fromElement) {
135    return new SafeTreeSet<E>(delegate.tailSet(checkValid(fromElement)));
136  }
137
138  @Override public Object[] toArray() {
139    return delegate.toArray();
140  }
141
142  @Override public <T> T[] toArray(T[] a) {
143    return delegate.toArray(a);
144  }
145
146  private <T> T checkValid(T t) {
147    // a ClassCastException is what's supposed to happen!
148    @SuppressWarnings("unchecked")
149    E e = (E) t;
150    comparator().compare(e, e);
151    return t;
152  }
153
154  @Override public boolean equals(Object obj) {
155    return delegate.equals(obj);
156  }
157
158  @Override public int hashCode() {
159    return delegate.hashCode();
160  }
161
162  @Override public String toString() {
163    return delegate.toString();
164  }
165
166  private static final long serialVersionUID = 0L;
167}
168