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