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