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