Coverage Summary for Class: RegularImmutableSortedSet (com.google.common.collect)
| Class | Class, % | Method, % | Line, % |
|---|---|---|---|
| RegularImmutableSortedSet | 100% (1/1) | 34.4% (11/32) | 29.5% (33/112) |
1 /* 2 * Copyright (C) 2009 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; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 21 import com.google.common.annotations.GwtCompatible; 22 import com.google.common.annotations.GwtIncompatible; 23 import java.util.Collection; 24 import java.util.Collections; 25 import java.util.Comparator; 26 import java.util.Iterator; 27 import java.util.NoSuchElementException; 28 import java.util.Set; 29 import java.util.Spliterator; 30 import java.util.function.Consumer; 31 import org.checkerframework.checker.nullness.qual.Nullable; 32 33 /** 34 * An immutable sorted set with one or more elements. TODO(jlevy): Consider separate class for a 35 * single-element sorted set. 36 * 37 * @author Jared Levy 38 * @author Louis Wasserman 39 */ 40 @GwtCompatible(serializable = true, emulated = true) 41 @SuppressWarnings({"serial", "rawtypes"}) 42 final class RegularImmutableSortedSet<E> extends ImmutableSortedSet<E> { 43 static final RegularImmutableSortedSet<Comparable> NATURAL_EMPTY_SET = 44 new RegularImmutableSortedSet<>(ImmutableList.<Comparable>of(), Ordering.natural()); 45 46 private final transient ImmutableList<E> elements; 47 48 RegularImmutableSortedSet(ImmutableList<E> elements, Comparator<? super E> comparator) { 49 super(comparator); 50 this.elements = elements; 51 } 52 53 @Override 54 Object[] internalArray() { 55 return elements.internalArray(); 56 } 57 58 @Override 59 int internalArrayStart() { 60 return elements.internalArrayStart(); 61 } 62 63 @Override 64 int internalArrayEnd() { 65 return elements.internalArrayEnd(); 66 } 67 68 @Override 69 public UnmodifiableIterator<E> iterator() { 70 return elements.iterator(); 71 } 72 73 @GwtIncompatible // NavigableSet 74 @Override 75 public UnmodifiableIterator<E> descendingIterator() { 76 return elements.reverse().iterator(); 77 } 78 79 @Override 80 public Spliterator<E> spliterator() { 81 return asList().spliterator(); 82 } 83 84 @Override 85 public void forEach(Consumer<? super E> action) { 86 elements.forEach(action); 87 } 88 89 @Override 90 public int size() { 91 return elements.size(); 92 } 93 94 @Override 95 public boolean contains(@Nullable Object o) { 96 try { 97 return o != null && unsafeBinarySearch(o) >= 0; 98 } catch (ClassCastException e) { 99 return false; 100 } 101 } 102 103 @Override 104 public boolean containsAll(Collection<?> targets) { 105 // TODO(jlevy): For optimal performance, use a binary search when 106 // targets.size() < size() / log(size()) 107 // TODO(kevinb): see if we can share code with OrderedIterator after it 108 // graduates from labs. 109 if (targets instanceof Multiset) { 110 targets = ((Multiset<?>) targets).elementSet(); 111 } 112 if (!SortedIterables.hasSameComparator(comparator(), targets) || (targets.size() <= 1)) { 113 return super.containsAll(targets); 114 } 115 116 /* 117 * If targets is a sorted set with the same comparator, containsAll can run 118 * in O(n) time stepping through the two collections. 119 */ 120 Iterator<E> thisIterator = iterator(); 121 122 Iterator<?> thatIterator = targets.iterator(); 123 // known nonempty since we checked targets.size() > 1 124 125 if (!thisIterator.hasNext()) { 126 return false; 127 } 128 129 Object target = thatIterator.next(); 130 E current = thisIterator.next(); 131 try { 132 while (true) { 133 int cmp = unsafeCompare(current, target); 134 135 if (cmp < 0) { 136 if (!thisIterator.hasNext()) { 137 return false; 138 } 139 current = thisIterator.next(); 140 } else if (cmp == 0) { 141 if (!thatIterator.hasNext()) { 142 return true; 143 } 144 target = thatIterator.next(); 145 146 } else if (cmp > 0) { 147 return false; 148 } 149 } 150 } catch (NullPointerException | ClassCastException e) { 151 return false; 152 } 153 } 154 155 private int unsafeBinarySearch(Object key) throws ClassCastException { 156 return Collections.binarySearch(elements, key, unsafeComparator()); 157 } 158 159 @Override 160 boolean isPartialView() { 161 return elements.isPartialView(); 162 } 163 164 @Override 165 int copyIntoArray(Object[] dst, int offset) { 166 return elements.copyIntoArray(dst, offset); 167 } 168 169 @Override 170 public boolean equals(@Nullable Object object) { 171 if (object == this) { 172 return true; 173 } 174 if (!(object instanceof Set)) { 175 return false; 176 } 177 178 Set<?> that = (Set<?>) object; 179 if (size() != that.size()) { 180 return false; 181 } else if (isEmpty()) { 182 return true; 183 } 184 185 if (SortedIterables.hasSameComparator(comparator, that)) { 186 Iterator<?> otherIterator = that.iterator(); 187 try { 188 Iterator<E> iterator = iterator(); 189 while (iterator.hasNext()) { 190 Object element = iterator.next(); 191 Object otherElement = otherIterator.next(); 192 if (otherElement == null || unsafeCompare(element, otherElement) != 0) { 193 return false; 194 } 195 } 196 return true; 197 } catch (ClassCastException e) { 198 return false; 199 } catch (NoSuchElementException e) { 200 return false; // concurrent change to other set 201 } 202 } 203 return containsAll(that); 204 } 205 206 @Override 207 public E first() { 208 if (isEmpty()) { 209 throw new NoSuchElementException(); 210 } 211 return elements.get(0); 212 } 213 214 @Override 215 public E last() { 216 if (isEmpty()) { 217 throw new NoSuchElementException(); 218 } 219 return elements.get(size() - 1); 220 } 221 222 @Override 223 public E lower(E element) { 224 int index = headIndex(element, false) - 1; 225 return (index == -1) ? null : elements.get(index); 226 } 227 228 @Override 229 public E floor(E element) { 230 int index = headIndex(element, true) - 1; 231 return (index == -1) ? null : elements.get(index); 232 } 233 234 @Override 235 public E ceiling(E element) { 236 int index = tailIndex(element, true); 237 return (index == size()) ? null : elements.get(index); 238 } 239 240 @Override 241 public E higher(E element) { 242 int index = tailIndex(element, false); 243 return (index == size()) ? null : elements.get(index); 244 } 245 246 @Override 247 ImmutableSortedSet<E> headSetImpl(E toElement, boolean inclusive) { 248 return getSubSet(0, headIndex(toElement, inclusive)); 249 } 250 251 int headIndex(E toElement, boolean inclusive) { 252 int index = Collections.binarySearch(elements, checkNotNull(toElement), comparator()); 253 if (index >= 0) { 254 return inclusive ? index + 1 : index; 255 } else { 256 return ~index; 257 } 258 } 259 260 @Override 261 ImmutableSortedSet<E> subSetImpl( 262 E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { 263 return tailSetImpl(fromElement, fromInclusive).headSetImpl(toElement, toInclusive); 264 } 265 266 @Override 267 ImmutableSortedSet<E> tailSetImpl(E fromElement, boolean inclusive) { 268 return getSubSet(tailIndex(fromElement, inclusive), size()); 269 } 270 271 int tailIndex(E fromElement, boolean inclusive) { 272 int index = Collections.binarySearch(elements, checkNotNull(fromElement), comparator()); 273 if (index >= 0) { 274 return inclusive ? index : index + 1; 275 } else { 276 return ~index; 277 } 278 } 279 280 // Pretend the comparator can compare anything. If it turns out it can't 281 // compare two elements, it'll throw a CCE. Only methods that are specified to 282 // throw CCE should call this. 283 @SuppressWarnings("unchecked") 284 Comparator<Object> unsafeComparator() { 285 return (Comparator<Object>) comparator; 286 } 287 288 RegularImmutableSortedSet<E> getSubSet(int newFromIndex, int newToIndex) { 289 if (newFromIndex == 0 && newToIndex == size()) { 290 return this; 291 } else if (newFromIndex < newToIndex) { 292 return new RegularImmutableSortedSet<E>( 293 elements.subList(newFromIndex, newToIndex), comparator); 294 } else { 295 return emptySet(comparator); 296 } 297 } 298 299 @Override 300 int indexOf(@Nullable Object target) { 301 if (target == null) { 302 return -1; 303 } 304 int position; 305 try { 306 position = Collections.binarySearch(elements, target, unsafeComparator()); 307 } catch (ClassCastException e) { 308 return -1; 309 } 310 return (position >= 0) ? position : -1; 311 } 312 313 @Override 314 ImmutableList<E> createAsList() { 315 return (size() <= 1) ? elements : new ImmutableSortedAsList<E>(this, elements); 316 } 317 318 @Override 319 ImmutableSortedSet<E> createDescendingSet() { 320 Comparator<? super E> reversedOrder = Collections.reverseOrder(comparator); 321 return isEmpty() 322 ? emptySet(reversedOrder) 323 : new RegularImmutableSortedSet<E>(elements.reverse(), reversedOrder); 324 } 325 }