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 /**
29  * Provides a reversed-ordered view of a SortedMap. Not serializable.
30  *
31  * TODO: copy in equals and hashCode from AbstractMap
32  */
33 class ReverseOrderSortedMapView<K, V> extends AbstractMap<K, V> implements SortedMap<K, V> {
34     final SortedMap<K, V> base;
35     final Comparator<? super K> cmp;
36 
ReverseOrderSortedMapView(SortedMap<K, V> map)37     private ReverseOrderSortedMapView(SortedMap<K, V> map) {
38         base = map;
39         cmp = Collections.reverseOrder(map.comparator());
40     }
41 
of(SortedMap<K, V> map)42     public static <K, V> SortedMap<K, V> of(SortedMap<K, V> map) {
43         if (map instanceof ReverseOrderSortedMapView<K, V> rosmv) {
44             return rosmv.base;
45         } else {
46             return new ReverseOrderSortedMapView<>(map);
47         }
48     }
49 
50     // ========== Object ==========
51 
52     // equals: inherited from AbstractMap
53 
54     // hashCode: inherited from AbstractMap
55 
toString()56     public String toString() {
57         return toString(this, descendingEntryIterator(base));
58     }
59 
60     // ========== Map ==========
61 
clear()62     public void clear() {
63         base.clear();
64     }
65 
containsKey(Object key)66     public boolean containsKey(Object key) {
67         return base.containsKey(key);
68     }
69 
containsValue(Object value)70     public boolean containsValue(Object value) {
71         return base.containsValue(value);
72     }
73 
get(Object key)74     public V get(Object key) {
75         return base.get(key);
76     }
77 
isEmpty()78     public boolean isEmpty() {
79         return base.isEmpty();
80     }
81 
put(K key, V value)82     public V put(K key, V value) {
83         return base.put(key, value);
84     }
85 
putAll(Map<? extends K, ? extends V> m)86     public void putAll(Map<? extends K, ? extends V> m) {
87         base.putAll(m);
88     }
89 
remove(Object key)90     public V remove(Object key) {
91         return base.remove(key);
92     }
93 
size()94     public int size() {
95         return base.size();
96     }
97 
keySet()98     public Set<K> keySet() {
99         return new AbstractSet<>() {
100             // inherit add(), which throws UOE
101             public Iterator<K> iterator() { return descendingKeyIterator(base); }
102             public int size() { return base.size(); }
103             public void clear() { base.keySet().clear(); }
104             public boolean contains(Object o) { return base.keySet().contains(o); }
105             public boolean remove(Object o) { return base.keySet().remove(o); }
106         };
107     }
108 
109     public Collection<V> values() {
110         return new AbstractCollection<>() {
111             // inherit add(), which throws UOE
112             public Iterator<V> iterator() { return descendingValueIterator(base); }
113             public int size() { return base.size(); }
114             public void clear() { base.values().clear(); }
115             public boolean contains(Object o) { return base.values().contains(o); }
116             public boolean remove(Object o) { return base.values().remove(o); }
117         };
118     }
119 
120     public Set<Entry<K, V>> entrySet() {
121         return new AbstractSet<>() {
122             // inherit add(), which throws UOE
123             public Iterator<Entry<K, V>> iterator() { return descendingEntryIterator(base); }
124             public int size() { return base.size(); }
125             public void clear() { base.entrySet().clear(); }
126             public boolean contains(Object o) { return base.entrySet().contains(o); }
127             public boolean remove(Object o) { return base.entrySet().remove(o); }
128         };
129     }
130 
131     // ========== SequencedMap ==========
132 
133     public SortedMap<K, V> reversed() {
134         return base;
135     }
136 
137     public K firstKey() {
138         return base.lastKey();
139     }
140 
141     public K lastKey() {
142         return base.firstKey();
143     }
144 
145     public Map.Entry<K, V> firstEntry() {
146         return base.lastEntry();
147     }
148 
149     public Map.Entry<K, V> lastEntry() {
150         return base.firstEntry();
151     }
152 
153     public Map.Entry<K,V> pollFirstEntry() {
154         return base.pollLastEntry();
155     }
156 
157     public Map.Entry<K,V> pollLastEntry() {
158         return base.pollFirstEntry();
159     }
160 
161     public V putFirst(K k, V v) {
162         return base.putLast(k, v);
163     }
164 
165     public V putLast(K k, V v) {
166         return base.putFirst(k, v);
167     }
168 
169     // ========== SortedMap ==========
170 
171     public Comparator<? super K> comparator() {
172         return cmp;
173     }
174 
175     public SortedMap<K, V> subMap(K fromKey, K toKey) {
176         if (cmp.compare(fromKey, toKey) <= 0) {
177             return new Submap(fromKey, toKey);
178         } else {
179             throw new IllegalArgumentException();
180         }
181     }
182 
183     public SortedMap<K, V> headMap(K toKey) {
184         return new Submap(null, toKey);
185     }
186 
187     public SortedMap<K, V> tailMap(K fromKey) {
188         return new Submap(fromKey, null);
189     }
190 
191     // ========== Infrastructure ==========
192 
193     static <K, V> Iterator<K> descendingKeyIterator(SortedMap<K, V> map) {
194         return new Iterator<>() {
195             SortedMap<K, V> root = map;
196             SortedMap<K, V> view = map;
197             K prev = null;
198 
199             public boolean hasNext() {
200                 return ! view.isEmpty();
201             }
202 
203             public K next() {
204                 if (view.isEmpty())
205                     throw new NoSuchElementException();
206                 K k = prev = view.lastKey();
207                 view = root.headMap(k);
208                 return k;
209             }
210 
211             public void remove() {
212                 if (prev == null) {
213                     throw new IllegalStateException();
214                 } else {
215                     root.remove(prev);
216                     prev = null;
217                 }
218             }
219         };
220     }
221 
222     static <K, V> Iterator<V> descendingValueIterator(SortedMap<K, V> map) {
223         return new Iterator<>() {
224             Iterator<K> keyIterator = descendingKeyIterator(map);
225 
226             public boolean hasNext() {
227                 return keyIterator.hasNext();
228             }
229 
230             public V next() {
231                 return map.get(keyIterator.next());
232             }
233 
234             public void remove() {
235                 keyIterator.remove();
236             }
237         };
238     }
239 
240     static <K, V> Iterator<Map.Entry<K, V>> descendingEntryIterator(SortedMap<K, V> map) {
241         return new Iterator<>() {
242             Iterator<K> keyIterator = descendingKeyIterator(map);
243 
244             public boolean hasNext() {
245                 return keyIterator.hasNext();
246             }
247 
248             public Map.Entry<K, V> next() {
249                 K key = keyIterator.next();
250                 return new ViewEntry<>(map, key, map.get(key));
251             }
252 
253             public void remove() {
254                 keyIterator.remove();
255             }
256         };
257     }
258 
259     static class ViewEntry<K, V> implements Map.Entry<K, V> {
260         final Map<K, V> map;
261         final K key;
262         final V value;
263 
264         ViewEntry(Map<K, V> map, K key, V value) {
265             this.map = map;
266             this.key = key;
267             this.value = value;
268         }
269 
270         public K getKey()             { return key; }
271         public V getValue()           { return value; }
272         public V setValue(V newValue) { return map.put(key, newValue); }
273 
274         public boolean equals(Object o) {
275             return o instanceof Map.Entry<?, ?> e
276                     && Objects.equals(key, e.getKey())
277                     && Objects.equals(value, e.getValue());
278         }
279 
280         public int hashCode() {
281             return Objects.hashCode(key) ^ Objects.hashCode(value);
282         }
283 
284         public String toString() {
285             return key + "=" + value;
286         }
287     }
288 
289     // copied and modified from AbstractMap
290     static <K, V> String toString(Map<K, V> thisMap, Iterator<Entry<K,V>> i) {
291         if (! i.hasNext())
292             return "{}";
293 
294         StringBuilder sb = new StringBuilder();
295         sb.append('{');
296         for (;;) {
297             Entry<K,V> e = i.next();
298             K key = e.getKey();
299             V value = e.getValue();
300             sb.append(key   == thisMap ? "(this Map)" : key);
301             sb.append('=');
302             sb.append(value == thisMap ? "(this Map)" : value);
303             if (! i.hasNext())
304                 return sb.append('}').toString();
305             sb.append(',').append(' ');
306         }
307     }
308 
309     /**
310      * Used for various submap views. We can't use the base SortedMap's subMap,
311      * because of the asymmetry between from-inclusive and to-exclusive.
312      */
313     class Submap extends AbstractMap<K, V> implements SortedMap<K, V> {
314         final K head; // head key, or negative infinity if null
315         final K tail; // tail key, or positive infinity if null
316 
317         @SuppressWarnings("unchecked")
318         Submap(K head, K tail) {
319             this.head = head;
320             this.tail = tail;
321         }
322 
323         // returns whether e is above the head, inclusive
324         boolean aboveHead(K k) {
325             return head == null || cmp.compare(k, head) >= 0;
326         }
327 
328         // returns whether e is below the tail, exclusive
329         boolean belowTail(K k) {
330             return tail == null || cmp.compare(k, tail) < 0;
331         }
332 
333         Iterator<Entry<K, V>> entryIterator() {
334             return new Iterator<>() {
335                 Entry<K, V> cache = null;
336                 K prevKey = null;
337                 boolean dead = false;
338                 Iterator<Entry<K, V>> it = descendingEntryIterator(base);
339 
340                 public boolean hasNext() {
341                     if (dead)
342                         return false;
343 
344                     if (cache != null)
345                         return true;
346 
347                     while (it.hasNext()) {
348                         Entry<K, V> e = it.next();
349 
350                         if (! aboveHead(e.getKey()))
351                             continue;
352 
353                         if (! belowTail(e.getKey())) {
354                             dead = true;
355                             return false;
356                         }
357 
358                         cache = e;
359                         return true;
360                     }
361 
362                     return false;
363                 }
364 
365                 public Entry<K, V> next() {
366                     if (hasNext()) {
367                         Entry<K, V> e = cache;
368                         cache = null;
369                         prevKey = e.getKey();
370                         return e;
371                     } else {
372                         throw new NoSuchElementException();
373                     }
374                 }
375 
376                 public void remove() {
377                     if (prevKey == null) {
378                         throw new IllegalStateException();
379                     } else {
380                         base.remove(prevKey);
381                     }
382                 }
383             };
384         }
385 
386         // equals: inherited from AbstractMap
387 
388         // hashCode: inherited from AbstractMap
389 
390         public String toString() {
391             return ReverseOrderSortedMapView.toString(this, entryIterator());
392         }
393 
394         public Set<Entry<K, V>> entrySet() {
395             return new AbstractSet<>() {
396                 public Iterator<Entry<K, V>> iterator() {
397                     return entryIterator();
398                 }
399 
400                 public int size() {
401                     int sz = 0;
402                     for (var it = entryIterator(); it.hasNext();) {
403                         it.next();
404                         sz++;
405                     }
406                     return sz;
407                 }
408             };
409         }
410 
411         public V put(K key, V value) {
412             if (aboveHead(key) && belowTail(key))
413                 return base.put(key, value);
414             else
415                 throw new IllegalArgumentException();
416         }
417 
418         public V remove(Object o) {
419             @SuppressWarnings("unchecked")
420             K key = (K) o;
421             if (aboveHead(key) && belowTail(key))
422                 return base.remove(o);
423             else
424                 return null;
425         }
426 
427         public int size() {
428             return entrySet().size();
429         }
430 
431         public Comparator<? super K> comparator() {
432             return cmp;
433         }
434 
435         public K firstKey() {
436             return this.entryIterator().next().getKey();
437         }
438 
439         public K lastKey() {
440             var it = this.entryIterator();
441             if (! it.hasNext())
442                 throw new NoSuchElementException();
443             var last = it.next();
444             while (it.hasNext())
445                 last = it.next();
446             return last.getKey();
447         }
448 
449         public SortedMap<K, V> subMap(K from, K to) {
450             if (aboveHead(from) && belowTail(from) &&
451                 aboveHead(to) && belowTail(to) &&
452                 cmp.compare(from, to) <= 0) {
453                 return new Submap(from, to);
454             } else {
455                 throw new IllegalArgumentException();
456             }
457         }
458 
459         public SortedMap<K, V> headMap(K to) {
460             if (aboveHead(to) && belowTail(to))
461                 return new Submap(head, to);
462             else
463                 throw new IllegalArgumentException();
464         }
465 
466         public SortedMap<K, V> tailMap(K from) {
467             if (aboveHead(from) && belowTail(from))
468                 return new Submap(from, tail);
469             else
470                 throw new IllegalArgumentException();
471         }
472     }
473 }
474