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.Objects; 29 import java.util.function.Consumer; 30 import java.util.function.IntFunction; 31 import java.util.function.Predicate; 32 import java.util.function.UnaryOperator; 33 import java.util.stream.Stream; 34 import java.util.stream.StreamSupport; 35 import jdk.internal.util.ArraysSupport; 36 37 /** 38 * Provides a reverse-ordered view of a List. Not serializable. 39 */ 40 class ReverseOrderListView<E> implements List<E> { 41 42 final List<E> base; 43 final boolean modifiable; 44 of(List<T> list, boolean modifiable)45 public static <T> List<T> of(List<T> list, boolean modifiable) { 46 if (list instanceof ReverseOrderListView<T> rolv) { 47 return rolv.base; 48 } else if (list instanceof RandomAccess) { 49 return new ReverseOrderListView.Rand<>(list, modifiable); 50 } else { 51 return new ReverseOrderListView<>(list, modifiable); 52 } 53 } 54 55 static class Rand<E> extends ReverseOrderListView<E> implements RandomAccess { Rand(List<E> list, boolean modifiable)56 Rand(List<E> list, boolean modifiable) { 57 super(list, modifiable); 58 } 59 } 60 ReverseOrderListView(List<E> list, boolean modifiable)61 private ReverseOrderListView(List<E> list, boolean modifiable) { 62 this.base = list; 63 this.modifiable = modifiable; 64 } 65 66 /** 67 * Throws if this list is unmodifiable. This should be called from every mutator 68 * method. For bulk ops (addAll, removeAll, etc.) this throws unconditionally. 69 * In contrast, if the base list inherits a bulk op implementation from AbstractList, 70 * it might not throw if no actual mutation would be attempted (e.g., addAll on an 71 * empty collection). Arguably calling this is unnecessary for individual ops, 72 * for which the base list should always throw, but it's easier to verify the right 73 * behavior if every mutator of this class always checks. 74 */ checkModifiable()75 void checkModifiable() { 76 if (! modifiable) { 77 throw new UnsupportedOperationException(); 78 } 79 } 80 81 class DescendingIterator implements Iterator<E> { 82 final ListIterator<E> it = base.listIterator(base.size()); hasNext()83 public boolean hasNext() { return it.hasPrevious(); } next()84 public E next() { return it.previous(); } remove()85 public void remove() { 86 checkModifiable(); 87 it.remove(); 88 // TODO - make sure ListIterator is positioned correctly afterward 89 } 90 } 91 92 class DescendingListIterator implements ListIterator<E> { 93 final ListIterator<E> it; 94 DescendingListIterator(int size, int pos)95 DescendingListIterator(int size, int pos) { 96 if (pos < 0 || pos > size) 97 throw new IndexOutOfBoundsException(); 98 it = base.listIterator(size - pos); 99 } 100 hasNext()101 public boolean hasNext() { 102 return it.hasPrevious(); 103 } 104 next()105 public E next() { 106 return it.previous(); 107 } 108 hasPrevious()109 public boolean hasPrevious() { 110 return it.hasNext(); 111 } 112 previous()113 public E previous() { 114 return it.next(); 115 } 116 nextIndex()117 public int nextIndex() { 118 return base.size() - it.nextIndex(); 119 } 120 previousIndex()121 public int previousIndex() { 122 return nextIndex() - 1; 123 } 124 remove()125 public void remove() { 126 checkModifiable(); 127 it.remove(); 128 } 129 set(E e)130 public void set(E e) { 131 checkModifiable(); 132 it.set(e); 133 } 134 add(E e)135 public void add(E e) { 136 checkModifiable(); 137 it.add(e); 138 it.previous(); 139 } 140 } 141 142 // ========== Iterable ========== 143 forEach(Consumer<? super E> action)144 public void forEach(Consumer<? super E> action) { 145 for (E e : this) 146 action.accept(e); 147 } 148 iterator()149 public Iterator<E> iterator() { 150 return new DescendingIterator(); 151 } 152 spliterator()153 public Spliterator<E> spliterator() { 154 return Spliterators.spliterator(this, Spliterator.ORDERED); 155 } 156 157 // ========== Collection ========== 158 add(E e)159 public boolean add(E e) { 160 checkModifiable(); 161 base.add(0, e); 162 return true; 163 } 164 addAll(Collection<? extends E> c)165 public boolean addAll(Collection<? extends E> c) { 166 checkModifiable(); 167 168 @SuppressWarnings("unchecked") 169 E[] adds = (E[]) c.toArray(); 170 if (adds.length == 0) { 171 return false; 172 } else { 173 base.addAll(0, Arrays.asList(ArraysSupport.reverse(adds))); 174 return true; 175 } 176 } 177 clear()178 public void clear() { 179 checkModifiable(); 180 base.clear(); 181 } 182 contains(Object o)183 public boolean contains(Object o) { 184 return base.contains(o); 185 } 186 containsAll(Collection<?> c)187 public boolean containsAll(Collection<?> c) { 188 return base.containsAll(c); 189 } 190 191 // copied from AbstractList equals(Object o)192 public boolean equals(Object o) { 193 if (o == this) 194 return true; 195 if (!(o instanceof List)) 196 return false; 197 198 ListIterator<E> e1 = listIterator(); 199 ListIterator<?> e2 = ((List<?>) o).listIterator(); 200 while (e1.hasNext() && e2.hasNext()) { 201 E o1 = e1.next(); 202 Object o2 = e2.next(); 203 if (!(o1==null ? o2==null : o1.equals(o2))) 204 return false; 205 } 206 return !(e1.hasNext() || e2.hasNext()); 207 } 208 209 // copied from AbstractList hashCode()210 public int hashCode() { 211 int hashCode = 1; 212 for (E e : this) 213 hashCode = 31*hashCode + (e==null ? 0 : e.hashCode()); 214 return hashCode; 215 } 216 isEmpty()217 public boolean isEmpty() { 218 return base.isEmpty(); 219 } 220 parallelStream()221 public Stream<E> parallelStream() { 222 return StreamSupport.stream(spliterator(), true); 223 } 224 225 // copied from AbstractCollection remove(Object o)226 public boolean remove(Object o) { 227 checkModifiable(); 228 Iterator<E> it = iterator(); 229 if (o==null) { 230 while (it.hasNext()) { 231 if (it.next()==null) { 232 it.remove(); 233 return true; 234 } 235 } 236 } else { 237 while (it.hasNext()) { 238 if (o.equals(it.next())) { 239 it.remove(); 240 return true; 241 } 242 } 243 } 244 return false; 245 } 246 247 // copied from AbstractCollection removeAll(Collection<?> c)248 public boolean removeAll(Collection<?> c) { 249 checkModifiable(); 250 Objects.requireNonNull(c); 251 boolean modified = false; 252 Iterator<?> it = iterator(); 253 while (it.hasNext()) { 254 if (c.contains(it.next())) { 255 it.remove(); 256 modified = true; 257 } 258 } 259 return modified; 260 } 261 262 // copied from AbstractCollection retainAll(Collection<?> c)263 public boolean retainAll(Collection<?> c) { 264 checkModifiable(); 265 Objects.requireNonNull(c); 266 boolean modified = false; 267 Iterator<E> it = iterator(); 268 while (it.hasNext()) { 269 if (!c.contains(it.next())) { 270 it.remove(); 271 modified = true; 272 } 273 } 274 return modified; 275 } 276 size()277 public int size() { 278 return base.size(); 279 } 280 stream()281 public Stream<E> stream() { 282 return StreamSupport.stream(spliterator(), false); 283 } 284 toArray()285 public Object[] toArray() { 286 return ArraysSupport.reverse(base.toArray()); 287 } 288 289 @SuppressWarnings("unchecked") toArray(T[] a)290 public <T> T[] toArray(T[] a) { 291 return ArraysSupport.toArrayReversed(base, a); 292 } 293 toArray(IntFunction<T[]> generator)294 public <T> T[] toArray(IntFunction<T[]> generator) { 295 return ArraysSupport.reverse(base.toArray(generator)); 296 } 297 298 // copied from AbstractCollection toString()299 public String toString() { 300 Iterator<E> it = iterator(); 301 if (! it.hasNext()) 302 return "[]"; 303 304 StringBuilder sb = new StringBuilder(); 305 sb.append('['); 306 for (;;) { 307 E e = it.next(); 308 sb.append(e == this ? "(this Collection)" : e); 309 if (! it.hasNext()) 310 return sb.append(']').toString(); 311 sb.append(',').append(' '); 312 } 313 } 314 315 // ========== List ========== 316 add(int index, E element)317 public void add(int index, E element) { 318 checkModifiable(); 319 int size = base.size(); 320 checkClosedRange(index, size); 321 base.add(size - index, element); 322 } 323 addAll(int index, Collection<? extends E> c)324 public boolean addAll(int index, Collection<? extends E> c) { 325 checkModifiable(); 326 int size = base.size(); 327 checkClosedRange(index, size); 328 @SuppressWarnings("unchecked") 329 E[] adds = (E[]) c.toArray(); 330 if (adds.length == 0) { 331 return false; 332 } else { 333 base.addAll(size - index, Arrays.asList(ArraysSupport.reverse(adds))); 334 return true; 335 } 336 } 337 get(int i)338 public E get(int i) { 339 int size = base.size(); 340 Objects.checkIndex(i, size); 341 return base.get(size - i - 1); 342 } 343 indexOf(Object o)344 public int indexOf(Object o) { 345 int i = base.lastIndexOf(o); 346 return i == -1 ? -1 : base.size() - i - 1; 347 } 348 lastIndexOf(Object o)349 public int lastIndexOf(Object o) { 350 int i = base.indexOf(o); 351 return i == -1 ? -1 : base.size() - i - 1; 352 } 353 listIterator()354 public ListIterator<E> listIterator() { 355 return new DescendingListIterator(base.size(), 0); 356 } 357 listIterator(int index)358 public ListIterator<E> listIterator(int index) { 359 int size = base.size(); 360 checkClosedRange(index, size); 361 return new DescendingListIterator(size, index); 362 } 363 remove(int index)364 public E remove(int index) { 365 checkModifiable(); 366 int size = base.size(); 367 Objects.checkIndex(index, size); 368 return base.remove(size - index - 1); 369 } 370 removeIf(Predicate<? super E> filter)371 public boolean removeIf(Predicate<? super E> filter) { 372 checkModifiable(); 373 return base.removeIf(filter); 374 } 375 replaceAll(UnaryOperator<E> operator)376 public void replaceAll(UnaryOperator<E> operator) { 377 checkModifiable(); 378 base.replaceAll(operator); 379 } 380 sort(Comparator<? super E> c)381 public void sort(Comparator<? super E> c) { 382 checkModifiable(); 383 base.sort(Collections.reverseOrder(c)); 384 } 385 set(int index, E element)386 public E set(int index, E element) { 387 checkModifiable(); 388 int size = base.size(); 389 Objects.checkIndex(index, size); 390 return base.set(size - index - 1, element); 391 } 392 subList(int fromIndex, int toIndex)393 public List<E> subList(int fromIndex, int toIndex) { 394 int size = base.size(); 395 Objects.checkFromToIndex(fromIndex, toIndex, size); 396 return new ReverseOrderListView<>(base.subList(size - toIndex, size - fromIndex), modifiable); 397 } 398 checkClosedRange(int index, int size)399 static void checkClosedRange(int index, int size) { 400 if (index < 0 || index > size) { 401 throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); 402 } 403 } 404 } 405