1 /* 2 * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.util; 27 28 import java.util.function.Consumer; 29 import java.util.function.IntFunction; 30 import java.util.stream.Stream; 31 import java.util.stream.StreamSupport; 32 import jdk.internal.util.ArraysSupport; 33 34 /** 35 * Provides a reversed-ordered view of a SortedSet. Not serializable. 36 */ 37 class ReverseOrderSortedSetView<E> implements SortedSet<E> { 38 final SortedSet<E> base; 39 final Comparator<? super E> comp; 40 ReverseOrderSortedSetView(SortedSet<E> set)41 private ReverseOrderSortedSetView(SortedSet<E> set) { 42 base = set; 43 comp = Collections.reverseOrder(set.comparator()); 44 } 45 of(SortedSet<T> set)46 public static <T> SortedSet<T> of(SortedSet<T> set) { 47 if (set instanceof ReverseOrderSortedSetView<T> rossv) { 48 return rossv.base; 49 } else { 50 return new ReverseOrderSortedSetView<>(set); 51 } 52 } 53 54 // ========== Object ========== 55 56 // copied from AbstractSet equals(Object o)57 public boolean equals(Object o) { 58 if (o == this) 59 return true; 60 61 if (!(o instanceof Set)) 62 return false; 63 Collection<?> c = (Collection<?>) o; 64 if (c.size() != size()) 65 return false; 66 try { 67 return containsAll(c); 68 } catch (ClassCastException | NullPointerException unused) { 69 return false; 70 } 71 } 72 73 // copied from AbstractSet hashCode()74 public int hashCode() { 75 int h = 0; 76 Iterator<E> i = iterator(); 77 while (i.hasNext()) { 78 E obj = i.next(); 79 if (obj != null) 80 h += obj.hashCode(); 81 } 82 return h; 83 } 84 85 // copied from AbstractCollection toString()86 public String toString() { 87 Iterator<E> it = iterator(); 88 if (! it.hasNext()) 89 return "[]"; 90 91 StringBuilder sb = new StringBuilder(); 92 sb.append('['); 93 for (;;) { 94 E e = it.next(); 95 sb.append(e == this ? "(this Collection)" : e); 96 if (! it.hasNext()) 97 return sb.append(']').toString(); 98 sb.append(',').append(' '); 99 } 100 } 101 102 // ========== Iterable ========== 103 forEach(Consumer<? super E> action)104 public void forEach(Consumer<? super E> action) { 105 for (E e : this) 106 action.accept(e); 107 } 108 iterator()109 public Iterator<E> iterator() { 110 return descendingIterator(base); 111 } 112 spliterator()113 public Spliterator<E> spliterator() { 114 return Spliterators.spliterator(this, Spliterator.ORDERED); 115 } 116 117 // ========== Collection ========== 118 add(E e)119 public boolean add(E e) { 120 base.add(e); 121 return true; 122 } 123 addAll(Collection<? extends E> c)124 public boolean addAll(Collection<? extends E> c) { 125 return base.addAll(c); 126 } 127 clear()128 public void clear() { 129 base.clear(); 130 } 131 contains(Object o)132 public boolean contains(Object o) { 133 return base.contains(o); 134 } 135 containsAll(Collection<?> c)136 public boolean containsAll(Collection<?> c) { 137 return base.containsAll(c); 138 } 139 isEmpty()140 public boolean isEmpty() { 141 return base.isEmpty(); 142 } 143 parallelStream()144 public Stream<E> parallelStream() { 145 return StreamSupport.stream(spliterator(), true); 146 } 147 remove(Object o)148 public boolean remove(Object o) { 149 return base.remove(o); 150 } 151 removeAll(Collection<?> c)152 public boolean removeAll(Collection<?> c) { 153 return base.removeAll(c); 154 } 155 156 // copied from AbstractCollection retainAll(Collection<?> c)157 public boolean retainAll(Collection<?> c) { 158 return base.retainAll(c); 159 } 160 size()161 public int size() { 162 return base.size(); 163 } 164 stream()165 public Stream<E> stream() { 166 return StreamSupport.stream(spliterator(), false); 167 } 168 toArray()169 public Object[] toArray() { 170 return ArraysSupport.reverse(base.toArray()); 171 } 172 173 @SuppressWarnings("unchecked") toArray(T[] a)174 public <T> T[] toArray(T[] a) { 175 return ArraysSupport.toArrayReversed(base, a); 176 } 177 toArray(IntFunction<T[]> generator)178 public <T> T[] toArray(IntFunction<T[]> generator) { 179 return ArraysSupport.reverse(base.toArray(generator)); 180 } 181 182 // ========== SortedSet ========== 183 comparator()184 public Comparator<? super E> comparator() { 185 return comp; 186 } 187 first()188 public E first() { return base.last(); } 189 last()190 public E last() { return base.first(); } 191 headSet(E to)192 public SortedSet<E> headSet(E to) { 193 return new Subset(null, to); 194 } 195 subSet(E from, E to)196 public SortedSet<E> subSet(E from, E to) { 197 return new Subset(from, to); 198 } 199 tailSet(E from)200 public SortedSet<E> tailSet(E from) { 201 return new Subset(from, null); 202 } 203 204 // ========== Infrastructure ========== 205 descendingIterator(SortedSet<T> set)206 static <T> Iterator<T> descendingIterator(SortedSet<T> set) { 207 return new Iterator<>() { 208 SortedSet<T> root = set; 209 SortedSet<T> view = set; 210 T prev = null; 211 212 public boolean hasNext() { 213 return ! view.isEmpty(); 214 } 215 216 public T next() { 217 if (view.isEmpty()) 218 throw new NoSuchElementException(); 219 T t = prev = view.last(); 220 view = root.headSet(t); 221 return t; 222 } 223 224 public void remove() { 225 if (prev == null) { 226 throw new IllegalStateException(); 227 } else { 228 root.remove(prev); 229 prev = null; 230 } 231 } 232 }; 233 } 234 235 /** 236 * Used for various subset views. We can't use the base SortedSet's subset, 237 * because of the asymmetry between from-inclusive and to-exclusive. 238 */ 239 class Subset extends AbstractSet<E> implements SortedSet<E> { 240 final E head; // head element, or negative infinity if null 241 final E tail; // tail element, or positive infinity if null 242 final Comparator<E> cmp; 243 244 @SuppressWarnings("unchecked") Subset(E head, E tail)245 Subset(E head, E tail) { 246 this.head = head; 247 this.tail = tail; 248 Comparator<E> c = (Comparator<E>) ReverseOrderSortedSetView.this.comparator(); 249 if (c == null) 250 c = (Comparator<E>) Comparator.naturalOrder(); 251 cmp = c; 252 } 253 254 // returns whether e is above the head, inclusive aboveHead(E e)255 boolean aboveHead(E e) { 256 return head == null || cmp.compare(e, head) >= 0; 257 } 258 259 // returns whether e is below the tail, exclusive belowTail(E e)260 boolean belowTail(E e) { 261 return tail == null || cmp.compare(e, tail) < 0; 262 } 263 iterator()264 public Iterator<E> iterator() { 265 return new Iterator<>() { 266 E cache = null; 267 boolean dead = false; 268 Iterator<E> it = descendingIterator(base); 269 270 public boolean hasNext() { 271 if (dead) 272 return false; 273 274 if (cache != null) 275 return true; 276 277 while (it.hasNext()) { 278 E e = it.next(); 279 280 if (! aboveHead(e)) 281 continue; 282 283 if (! belowTail(e)) { 284 dead = true; 285 return false; 286 } 287 288 cache = e; 289 return true; 290 } 291 292 return false; 293 } 294 295 public E next() { 296 if (hasNext()) { 297 E e = cache; 298 cache = null; 299 return e; 300 } else { 301 throw new NoSuchElementException(); 302 } 303 } 304 }; 305 } 306 add(E e)307 public boolean add(E e) { 308 if (aboveHead(e) && belowTail(e)) 309 return base.add(e); 310 else 311 throw new IllegalArgumentException(); 312 } 313 remove(Object o)314 public boolean remove(Object o) { 315 @SuppressWarnings("unchecked") 316 E e = (E) o; 317 if (aboveHead(e) && belowTail(e)) 318 return base.remove(o); 319 else 320 return false; 321 } 322 size()323 public int size() { 324 int sz = 0; 325 for (E e : this) 326 sz++; 327 return sz; 328 } 329 comparator()330 public Comparator<? super E> comparator() { 331 return ReverseOrderSortedSetView.this.comparator(); 332 } 333 first()334 public E first() { 335 return this.iterator().next(); 336 } 337 last()338 public E last() { 339 var it = this.iterator(); 340 if (! it.hasNext()) 341 throw new NoSuchElementException(); 342 E last = it.next(); 343 while (it.hasNext()) 344 last = it.next(); 345 return last; 346 } 347 subSet(E from, E to)348 public SortedSet<E> subSet(E from, E to) { 349 if (aboveHead(from) && belowTail(from) && 350 aboveHead(to) && belowTail(to) && 351 cmp.compare(from, to) <= 0) { 352 return ReverseOrderSortedSetView.this.new Subset(from, to); 353 } else { 354 throw new IllegalArgumentException(); 355 } 356 } 357 headSet(E to)358 public SortedSet<E> headSet(E to) { 359 if (aboveHead(to) && belowTail(to)) 360 return ReverseOrderSortedSetView.this.new Subset(head, to); 361 else 362 throw new IllegalArgumentException(); 363 } 364 tailSet(E from)365 public SortedSet<E> tailSet(E from) { 366 if (aboveHead(from) && belowTail(from)) 367 return ReverseOrderSortedSetView.this.new Subset(null, tail); 368 else 369 throw new IllegalArgumentException(); 370 } 371 372 } 373 } 374