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.Collection;
023import java.util.Comparator;
024import java.util.Iterator;
025import java.util.NavigableSet;
026import java.util.SortedSet;
027import java.util.TreeSet;
028import org.checkerframework.checker.nullness.qual.Nullable;
029
030/**
031 * A wrapper around {@code TreeSet} that aggressively checks to see if elements are mutually
032 * comparable. This implementation passes the navigable set test suites.
033 *
034 * @author Louis Wasserman
035 */
036@GwtIncompatible
037public final class SafeTreeSet<E> implements Serializable, NavigableSet<E> {
038  @SuppressWarnings("unchecked")
039  private static final Comparator<Object> NATURAL_ORDER =
040      new Comparator<Object>() {
041        @Override
042        public int compare(Object o1, Object o2) {
043          return ((Comparable<Object>) o1).compareTo(o2);
044        }
045      };
046
047  private final NavigableSet<E> delegate;
048
049  public SafeTreeSet() {
050    this(new TreeSet<E>());
051  }
052
053  public SafeTreeSet(Collection<? extends E> collection) {
054    this(new TreeSet<E>(collection));
055  }
056
057  public SafeTreeSet(Comparator<? super E> comparator) {
058    this(new TreeSet<E>(comparator));
059  }
060
061  public SafeTreeSet(SortedSet<E> set) {
062    this(new TreeSet<E>(set));
063  }
064
065  private SafeTreeSet(NavigableSet<E> delegate) {
066    this.delegate = delegate;
067    for (E e : this) {
068      checkValid(e);
069    }
070  }
071
072  @Override
073  public boolean add(E element) {
074    return delegate.add(checkValid(element));
075  }
076
077  @Override
078  public boolean addAll(Collection<? extends E> collection) {
079    for (E e : collection) {
080      checkValid(e);
081    }
082    return delegate.addAll(collection);
083  }
084
085  @Override
086  public @Nullable E ceiling(E e) {
087    return delegate.ceiling(checkValid(e));
088  }
089
090  @Override
091  public void clear() {
092    delegate.clear();
093  }
094
095  @SuppressWarnings("unchecked")
096  @Override
097  public Comparator<? super E> comparator() {
098    Comparator<? super E> comparator = delegate.comparator();
099    if (comparator == null) {
100      comparator = (Comparator<? super E>) NATURAL_ORDER;
101    }
102    return comparator;
103  }
104
105  @Override
106  public boolean contains(Object object) {
107    return delegate.contains(checkValid(object));
108  }
109
110  @Override
111  public boolean containsAll(Collection<?> c) {
112    return delegate.containsAll(c);
113  }
114
115  @Override
116  public Iterator<E> descendingIterator() {
117    return delegate.descendingIterator();
118  }
119
120  @Override
121  public NavigableSet<E> descendingSet() {
122    return new SafeTreeSet<>(delegate.descendingSet());
123  }
124
125  @Override
126  public E first() {
127    return delegate.first();
128  }
129
130  @Override
131  public @Nullable E floor(E e) {
132    return delegate.floor(checkValid(e));
133  }
134
135  @Override
136  public SortedSet<E> headSet(E toElement) {
137    return headSet(toElement, false);
138  }
139
140  @Override
141  public NavigableSet<E> headSet(E toElement, boolean inclusive) {
142    return new SafeTreeSet<>(delegate.headSet(checkValid(toElement), inclusive));
143  }
144
145  @Override
146  public @Nullable E higher(E e) {
147    return delegate.higher(checkValid(e));
148  }
149
150  @Override
151  public boolean isEmpty() {
152    return delegate.isEmpty();
153  }
154
155  @Override
156  public Iterator<E> iterator() {
157    return delegate.iterator();
158  }
159
160  @Override
161  public E last() {
162    return delegate.last();
163  }
164
165  @Override
166  public @Nullable E lower(E e) {
167    return delegate.lower(checkValid(e));
168  }
169
170  @Override
171  public @Nullable E pollFirst() {
172    return delegate.pollFirst();
173  }
174
175  @Override
176  public @Nullable E pollLast() {
177    return delegate.pollLast();
178  }
179
180  @Override
181  public boolean remove(Object object) {
182    return delegate.remove(checkValid(object));
183  }
184
185  @Override
186  public boolean removeAll(Collection<?> c) {
187    return delegate.removeAll(c);
188  }
189
190  @Override
191  public boolean retainAll(Collection<?> c) {
192    return delegate.retainAll(c);
193  }
194
195  @Override
196  public int size() {
197    return delegate.size();
198  }
199
200  @Override
201  public NavigableSet<E> subSet(
202      E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
203    return new SafeTreeSet<>(
204        delegate.subSet(
205            checkValid(fromElement), fromInclusive, checkValid(toElement), toInclusive));
206  }
207
208  @Override
209  public SortedSet<E> subSet(E fromElement, E toElement) {
210    return subSet(fromElement, true, toElement, false);
211  }
212
213  @Override
214  public SortedSet<E> tailSet(E fromElement) {
215    return tailSet(fromElement, true);
216  }
217
218  @Override
219  public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
220    return new SafeTreeSet<>(delegate.tailSet(checkValid(fromElement), inclusive));
221  }
222
223  @Override
224  public Object[] toArray() {
225    return delegate.toArray();
226  }
227
228  @Override
229  public <T> T[] toArray(T[] a) {
230    return delegate.toArray(a);
231  }
232
233  @CanIgnoreReturnValue
234  private <T> T checkValid(T t) {
235    // a ClassCastException is what's supposed to happen!
236    @SuppressWarnings("unchecked")
237    E e = (E) t;
238    int unused = comparator().compare(e, e);
239    return t;
240  }
241
242  @Override
243  public boolean equals(@Nullable Object obj) {
244    return delegate.equals(obj);
245  }
246
247  @Override
248  public int hashCode() {
249    return delegate.hashCode();
250  }
251
252  @Override
253  public String toString() {
254    return delegate.toString();
255  }
256
257  private static final long serialVersionUID = 0L;
258}