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