• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     @SuppressWarnings("DoNotCall")
162     public V putFirst(K k, V v) {
163         return base.putLast(k, v);
164     }
165 
166     @SuppressWarnings("DoNotCall")
167     public V putLast(K k, V v) {
168         return base.putFirst(k, v);
169     }
170 
171     // ========== SortedMap ==========
172 
173     public Comparator<? super K> comparator() {
174         return cmp;
175     }
176 
177     public SortedMap<K, V> subMap(K fromKey, K toKey) {
178         if (cmp.compare(fromKey, toKey) <= 0) {
179             return new Submap(fromKey, toKey);
180         } else {
181             throw new IllegalArgumentException();
182         }
183     }
184 
185     public SortedMap<K, V> headMap(K toKey) {
186         return new Submap(null, toKey);
187     }
188 
189     public SortedMap<K, V> tailMap(K fromKey) {
190         return new Submap(fromKey, null);
191     }
192 
193     // ========== Infrastructure ==========
194 
195     static <K, V> Iterator<K> descendingKeyIterator(SortedMap<K, V> map) {
196         return new Iterator<>() {
197             SortedMap<K, V> root = map;
198             SortedMap<K, V> view = map;
199             K prev = null;
200 
201             public boolean hasNext() {
202                 return ! view.isEmpty();
203             }
204 
205             public K next() {
206                 if (view.isEmpty())
207                     throw new NoSuchElementException();
208                 K k = prev = view.lastKey();
209                 view = root.headMap(k);
210                 return k;
211             }
212 
213             public void remove() {
214                 if (prev == null) {
215                     throw new IllegalStateException();
216                 } else {
217                     root.remove(prev);
218                     prev = null;
219                 }
220             }
221         };
222     }
223 
224     static <K, V> Iterator<V> descendingValueIterator(SortedMap<K, V> map) {
225         return new Iterator<>() {
226             Iterator<K> keyIterator = descendingKeyIterator(map);
227 
228             public boolean hasNext() {
229                 return keyIterator.hasNext();
230             }
231 
232             public V next() {
233                 return map.get(keyIterator.next());
234             }
235 
236             public void remove() {
237                 keyIterator.remove();
238             }
239         };
240     }
241 
242     static <K, V> Iterator<Map.Entry<K, V>> descendingEntryIterator(SortedMap<K, V> map) {
243         return new Iterator<>() {
244             Iterator<K> keyIterator = descendingKeyIterator(map);
245 
246             public boolean hasNext() {
247                 return keyIterator.hasNext();
248             }
249 
250             public Map.Entry<K, V> next() {
251                 K key = keyIterator.next();
252                 return new ViewEntry<>(map, key, map.get(key));
253             }
254 
255             public void remove() {
256                 keyIterator.remove();
257             }
258         };
259     }
260 
261     static class ViewEntry<K, V> implements Map.Entry<K, V> {
262         final Map<K, V> map;
263         final K key;
264         final V value;
265 
266         ViewEntry(Map<K, V> map, K key, V value) {
267             this.map = map;
268             this.key = key;
269             this.value = value;
270         }
271 
272         public K getKey()             { return key; }
273         public V getValue()           { return value; }
274         public V setValue(V newValue) { return map.put(key, newValue); }
275 
276         public boolean equals(Object o) {
277             return o instanceof Map.Entry<?, ?> e
278                     && Objects.equals(key, e.getKey())
279                     && Objects.equals(value, e.getValue());
280         }
281 
282         public int hashCode() {
283             return Objects.hashCode(key) ^ Objects.hashCode(value);
284         }
285 
286         public String toString() {
287             return key + "=" + value;
288         }
289     }
290 
291     // copied and modified from AbstractMap
292     static <K, V> String toString(Map<K, V> thisMap, Iterator<Entry<K,V>> i) {
293         if (! i.hasNext())
294             return "{}";
295 
296         StringBuilder sb = new StringBuilder();
297         sb.append('{');
298         for (;;) {
299             Entry<K,V> e = i.next();
300             K key = e.getKey();
301             V value = e.getValue();
302             sb.append(key   == thisMap ? "(this Map)" : key);
303             sb.append('=');
304             sb.append(value == thisMap ? "(this Map)" : value);
305             if (! i.hasNext())
306                 return sb.append('}').toString();
307             sb.append(',').append(' ');
308         }
309     }
310 
311     /**
312      * Used for various submap views. We can't use the base SortedMap's subMap,
313      * because of the asymmetry between from-inclusive and to-exclusive.
314      */
315     class Submap extends AbstractMap<K, V> implements SortedMap<K, V> {
316         final K head; // head key, or negative infinity if null
317         final K tail; // tail key, or positive infinity if null
318 
319         @SuppressWarnings("unchecked")
320         Submap(K head, K tail) {
321             this.head = head;
322             this.tail = tail;
323         }
324 
325         // returns whether e is above the head, inclusive
326         boolean aboveHead(K k) {
327             return head == null || cmp.compare(k, head) >= 0;
328         }
329 
330         // returns whether e is below the tail, exclusive
331         boolean belowTail(K k) {
332             return tail == null || cmp.compare(k, tail) < 0;
333         }
334 
335         Iterator<Entry<K, V>> entryIterator() {
336             return new Iterator<>() {
337                 Entry<K, V> cache = null;
338                 K prevKey = null;
339                 boolean dead = false;
340                 Iterator<Entry<K, V>> it = descendingEntryIterator(base);
341 
342                 public boolean hasNext() {
343                     if (dead)
344                         return false;
345 
346                     if (cache != null)
347                         return true;
348 
349                     while (it.hasNext()) {
350                         Entry<K, V> e = it.next();
351 
352                         if (! aboveHead(e.getKey()))
353                             continue;
354 
355                         if (! belowTail(e.getKey())) {
356                             dead = true;
357                             return false;
358                         }
359 
360                         cache = e;
361                         return true;
362                     }
363 
364                     return false;
365                 }
366 
367                 public Entry<K, V> next() {
368                     if (hasNext()) {
369                         Entry<K, V> e = cache;
370                         cache = null;
371                         prevKey = e.getKey();
372                         return e;
373                     } else {
374                         throw new NoSuchElementException();
375                     }
376                 }
377 
378                 public void remove() {
379                     if (prevKey == null) {
380                         throw new IllegalStateException();
381                     } else {
382                         base.remove(prevKey);
383                     }
384                 }
385             };
386         }
387 
388         // equals: inherited from AbstractMap
389 
390         // hashCode: inherited from AbstractMap
391 
392         public String toString() {
393             return ReverseOrderSortedMapView.toString(this, entryIterator());
394         }
395 
396         public Set<Entry<K, V>> entrySet() {
397             return new AbstractSet<>() {
398                 public Iterator<Entry<K, V>> iterator() {
399                     return entryIterator();
400                 }
401 
402                 public int size() {
403                     int sz = 0;
404                     for (var it = entryIterator(); it.hasNext();) {
405                         it.next();
406                         sz++;
407                     }
408                     return sz;
409                 }
410             };
411         }
412 
413         public V put(K key, V value) {
414             if (aboveHead(key) && belowTail(key))
415                 return base.put(key, value);
416             else
417                 throw new IllegalArgumentException();
418         }
419 
420         public V remove(Object o) {
421             @SuppressWarnings("unchecked")
422             K key = (K) o;
423             if (aboveHead(key) && belowTail(key))
424                 return base.remove(o);
425             else
426                 return null;
427         }
428 
429         public int size() {
430             return entrySet().size();
431         }
432 
433         public Comparator<? super K> comparator() {
434             return cmp;
435         }
436 
437         public K firstKey() {
438             return this.entryIterator().next().getKey();
439         }
440 
441         public K lastKey() {
442             var it = this.entryIterator();
443             if (! it.hasNext())
444                 throw new NoSuchElementException();
445             var last = it.next();
446             while (it.hasNext())
447                 last = it.next();
448             return last.getKey();
449         }
450 
451         public SortedMap<K, V> subMap(K from, K to) {
452             if (aboveHead(from) && belowTail(from) &&
453                 aboveHead(to) && belowTail(to) &&
454                 cmp.compare(from, to) <= 0) {
455                 return new Submap(from, to);
456             } else {
457                 throw new IllegalArgumentException();
458             }
459         }
460 
461         public SortedMap<K, V> headMap(K to) {
462             if (aboveHead(to) && belowTail(to))
463                 return new Submap(head, to);
464             else
465                 throw new IllegalArgumentException();
466         }
467 
468         public SortedMap<K, V> tailMap(K from) {
469             if (aboveHead(from) && belowTail(from))
470                 return new Submap(from, tail);
471             else
472                 throw new IllegalArgumentException();
473         }
474     }
475 }
476