001 /* 002 * Copyright (C) 2009 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package com.google.common.collect; 018 019 import static com.google.common.base.Preconditions.checkArgument; 020 import static com.google.common.base.Preconditions.checkNotNull; 021 import static com.google.common.collect.Maps.keyOrNull; 022 import static com.google.common.collect.SortedLists.KeyAbsentBehavior.INVERTED_INSERTION_INDEX; 023 import static com.google.common.collect.SortedLists.KeyAbsentBehavior.NEXT_HIGHER; 024 import static com.google.common.collect.SortedLists.KeyAbsentBehavior.NEXT_LOWER; 025 import static com.google.common.collect.SortedLists.KeyPresentBehavior.ANY_PRESENT; 026 027 import com.google.common.annotations.GwtCompatible; 028 import com.google.common.collect.SortedLists.KeyAbsentBehavior; 029 import com.google.common.collect.SortedLists.KeyPresentBehavior; 030 031 import java.util.Arrays; 032 import java.util.Collections; 033 import java.util.Comparator; 034 import java.util.List; 035 import java.util.Map; 036 import java.util.NavigableMap; 037 import java.util.NoSuchElementException; 038 import java.util.SortedMap; 039 import java.util.TreeMap; 040 041 import javax.annotation.Nullable; 042 043 /** 044 * An immutable {@link SortedMap}. Does not permit null keys or values. 045 * 046 * <p>Unlike {@link Collections#unmodifiableSortedMap}, which is a <i>view</i> 047 * of a separate map which can still change, an instance of {@code 048 * ImmutableSortedMap} contains its own data and will <i>never</i> change. 049 * {@code ImmutableSortedMap} is convenient for {@code public static final} maps 050 * ("constant maps") and also lets you easily make a "defensive copy" of a map 051 * provided to your class by a caller. 052 * 053 * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as 054 * it has no public or protected constructors. Thus, instances of this class are 055 * guaranteed to be immutable. 056 * 057 * <p>See the Guava User Guide article on <a href= 058 * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained"> 059 * immutable collections</a>. 060 * 061 * @author Jared Levy 062 * @author Louis Wasserman 063 * @since 2.0 (imported from Google Collections Library; implements {@code 064 * NavigableMap} since 12.0) 065 */ 066 @GwtCompatible(serializable = true, emulated = true) 067 public class ImmutableSortedMap<K, V> 068 extends ImmutableSortedMapFauxverideShim<K, V> implements NavigableMap<K, V> { 069 /* 070 * TODO(kevinb): Confirm that ImmutableSortedMap is faster to construct and 071 * uses less memory than TreeMap; then say so in the class Javadoc. 072 * 073 * TODO(kevinb): Create separate subclasses for empty, single-entry, and 074 * multiple-entry instances, if it's deemed beneficial. 075 */ 076 077 private static final Comparator<Comparable> NATURAL_ORDER = 078 Ordering.natural(); 079 080 private static final ImmutableSortedMap<Comparable, Object> 081 NATURAL_EMPTY_MAP = 082 new ImmutableSortedMap<Comparable, Object>( 083 ImmutableList.<Entry<Comparable, Object>>of(), NATURAL_ORDER); 084 085 /** 086 * Returns the empty sorted map. 087 */ 088 @SuppressWarnings("unchecked") 089 // unsafe, comparator() returns a comparator on the specified type 090 // TODO(kevinb): evaluate whether or not of().comparator() should return null 091 public static <K, V> ImmutableSortedMap<K, V> of() { 092 return (ImmutableSortedMap<K, V>) NATURAL_EMPTY_MAP; 093 } 094 095 @SuppressWarnings("unchecked") 096 private static <K, V> ImmutableSortedMap<K, V> emptyMap( 097 Comparator<? super K> comparator) { 098 if (NATURAL_ORDER.equals(comparator)) { 099 return (ImmutableSortedMap<K, V>) NATURAL_EMPTY_MAP; 100 } else { 101 return new ImmutableSortedMap<K, V>( 102 ImmutableList.<Entry<K, V>>of(), comparator); 103 } 104 } 105 106 /** 107 * Returns an immutable map containing a single entry. 108 */ 109 public static <K extends Comparable<? super K>, V> 110 ImmutableSortedMap<K, V> of(K k1, V v1) { 111 return new ImmutableSortedMap<K, V>( 112 ImmutableList.of(entryOf(k1, v1)), Ordering.natural()); 113 } 114 115 /** 116 * Returns an immutable sorted map containing the given entries, sorted by the 117 * natural ordering of their keys. 118 * 119 * @throws IllegalArgumentException if the two keys are equal according to 120 * their natural ordering 121 */ 122 public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V> 123 of(K k1, V v1, K k2, V v2) { 124 return new Builder<K, V>(Ordering.natural()) 125 .put(k1, v1).put(k2, v2).build(); 126 } 127 128 /** 129 * Returns an immutable sorted map containing the given entries, sorted by the 130 * natural ordering of their keys. 131 * 132 * @throws IllegalArgumentException if any two keys are equal according to 133 * their natural ordering 134 */ 135 public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V> 136 of(K k1, V v1, K k2, V v2, K k3, V v3) { 137 return new Builder<K, V>(Ordering.natural()) 138 .put(k1, v1).put(k2, v2).put(k3, v3).build(); 139 } 140 141 /** 142 * Returns an immutable sorted map containing the given entries, sorted by the 143 * natural ordering of their keys. 144 * 145 * @throws IllegalArgumentException if any two keys are equal according to 146 * their natural ordering 147 */ 148 public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V> 149 of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { 150 return new Builder<K, V>(Ordering.natural()) 151 .put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).build(); 152 } 153 154 /** 155 * Returns an immutable sorted map containing the given entries, sorted by the 156 * natural ordering of their keys. 157 * 158 * @throws IllegalArgumentException if any two keys are equal according to 159 * their natural ordering 160 */ 161 public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V> 162 of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { 163 return new Builder<K, V>(Ordering.natural()) 164 .put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).build(); 165 } 166 167 /** 168 * Returns an immutable map containing the same entries as {@code map}, sorted 169 * by the natural ordering of the keys. 170 * 171 * <p>Despite the method name, this method attempts to avoid actually copying 172 * the data when it is safe to do so. The exact circumstances under which a 173 * copy will or will not be performed are undocumented and subject to change. 174 * 175 * <p>This method is not type-safe, as it may be called on a map with keys 176 * that are not mutually comparable. 177 * 178 * @throws ClassCastException if the keys in {@code map} are not mutually 179 * comparable 180 * @throws NullPointerException if any key or value in {@code map} is null 181 * @throws IllegalArgumentException if any two keys are equal according to 182 * their natural ordering 183 */ 184 public static <K, V> ImmutableSortedMap<K, V> copyOf( 185 Map<? extends K, ? extends V> map) { 186 // Hack around K not being a subtype of Comparable. 187 // Unsafe, see ImmutableSortedSetFauxverideShim. 188 @SuppressWarnings("unchecked") 189 Ordering<K> naturalOrder = (Ordering<K>) Ordering.<Comparable>natural(); 190 return copyOfInternal(map, naturalOrder); 191 } 192 193 /** 194 * Returns an immutable map containing the same entries as {@code map}, with 195 * keys sorted by the provided comparator. 196 * 197 * <p>Despite the method name, this method attempts to avoid actually copying 198 * the data when it is safe to do so. The exact circumstances under which a 199 * copy will or will not be performed are undocumented and subject to change. 200 * 201 * @throws NullPointerException if any key or value in {@code map} is null 202 * @throws IllegalArgumentException if any two keys are equal according to the 203 * comparator 204 */ 205 public static <K, V> ImmutableSortedMap<K, V> copyOf( 206 Map<? extends K, ? extends V> map, Comparator<? super K> comparator) { 207 return copyOfInternal(map, checkNotNull(comparator)); 208 } 209 210 /** 211 * Returns an immutable map containing the same entries as the provided sorted 212 * map, with the same ordering. 213 * 214 * <p>Despite the method name, this method attempts to avoid actually copying 215 * the data when it is safe to do so. The exact circumstances under which a 216 * copy will or will not be performed are undocumented and subject to change. 217 * 218 * @throws NullPointerException if any key or value in {@code map} is null 219 */ 220 @SuppressWarnings("unchecked") 221 public static <K, V> ImmutableSortedMap<K, V> copyOfSorted( 222 SortedMap<K, ? extends V> map) { 223 Comparator<? super K> comparator = map.comparator(); 224 if (comparator == null) { 225 // If map has a null comparator, the keys should have a natural ordering, 226 // even though K doesn't explicitly implement Comparable. 227 comparator = (Comparator<? super K>) NATURAL_ORDER; 228 } 229 return copyOfInternal(map, comparator); 230 } 231 232 private static <K, V> ImmutableSortedMap<K, V> copyOfInternal( 233 Map<? extends K, ? extends V> map, Comparator<? super K> comparator) { 234 boolean sameComparator = false; 235 if (map instanceof SortedMap) { 236 SortedMap<?, ?> sortedMap = (SortedMap<?, ?>) map; 237 Comparator<?> comparator2 = sortedMap.comparator(); 238 sameComparator = (comparator2 == null) 239 ? comparator == NATURAL_ORDER 240 : comparator.equals(comparator2); 241 } 242 243 if (sameComparator && (map instanceof ImmutableSortedMap)) { 244 // TODO(kevinb): Prove that this cast is safe, even though 245 // Collections.unmodifiableSortedMap requires the same key type. 246 @SuppressWarnings("unchecked") 247 ImmutableSortedMap<K, V> kvMap = (ImmutableSortedMap<K, V>) map; 248 if (!kvMap.isPartialView()) { 249 return kvMap; 250 } 251 } 252 253 // "adding" type params to an array of a raw type should be safe as 254 // long as no one can ever cast that same array instance back to a 255 // raw type. 256 @SuppressWarnings("unchecked") 257 Entry<K, V>[] entries = map.entrySet().toArray(new Entry[0]); 258 259 for (int i = 0; i < entries.length; i++) { 260 Entry<K, V> entry = entries[i]; 261 entries[i] = entryOf(entry.getKey(), entry.getValue()); 262 } 263 264 List<Entry<K, V>> list = Arrays.asList(entries); 265 266 if (!sameComparator) { 267 sortEntries(list, comparator); 268 validateEntries(list, comparator); 269 } 270 271 return new ImmutableSortedMap<K, V>(ImmutableList.copyOf(list), comparator); 272 } 273 274 private static <K, V> void sortEntries( 275 List<Entry<K, V>> entries, final Comparator<? super K> comparator) { 276 Comparator<Entry<K, V>> entryComparator = new Comparator<Entry<K, V>>() { 277 278 @Override public int compare(Entry<K, V> entry1, Entry<K, V> entry2) { 279 return comparator.compare(entry1.getKey(), entry2.getKey()); 280 } 281 }; 282 283 Collections.sort(entries, entryComparator); 284 } 285 286 private static <K, V> void validateEntries(List<Entry<K, V>> entries, 287 Comparator<? super K> comparator) { 288 for (int i = 1; i < entries.size(); i++) { 289 if (comparator.compare( 290 entries.get(i - 1).getKey(), entries.get(i).getKey()) == 0) { 291 throw new IllegalArgumentException( 292 "Duplicate keys in mappings " + entries.get(i - 1) + " and " 293 + entries.get(i)); 294 } 295 } 296 } 297 298 /** 299 * Returns a builder that creates immutable sorted maps whose keys are 300 * ordered by their natural ordering. The sorted maps use {@link 301 * Ordering#natural()} as the comparator. 302 * 303 * <p>Note: the type parameter {@code K} extends {@code Comparable<K>} rather 304 * than {@code Comparable<? super K>} as a workaround for javac <a 305 * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug 306 * 6468354</a>. 307 */ 308 public static <K extends Comparable<K>, V> Builder<K, V> naturalOrder() { 309 return new Builder<K, V>(Ordering.natural()); 310 } 311 312 /** 313 * Returns a builder that creates immutable sorted maps with an explicit 314 * comparator. If the comparator has a more general type than the map's keys, 315 * such as creating a {@code SortedMap<Integer, String>} with a {@code 316 * Comparator<Number>}, use the {@link Builder} constructor instead. 317 * 318 * @throws NullPointerException if {@code comparator} is null 319 */ 320 public static <K, V> Builder<K, V> orderedBy(Comparator<K> comparator) { 321 return new Builder<K, V>(comparator); 322 } 323 324 /** 325 * Returns a builder that creates immutable sorted maps whose keys are 326 * ordered by the reverse of their natural ordering. 327 * 328 * <p>Note: the type parameter {@code K} extends {@code Comparable<K>} rather 329 * than {@code Comparable<? super K>} as a workaround for javac <a 330 * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug 331 * 6468354</a>. 332 */ 333 public static <K extends Comparable<K>, V> Builder<K, V> reverseOrder() { 334 return new Builder<K, V>(Ordering.natural().reverse()); 335 } 336 337 /** 338 * A builder for creating immutable sorted map instances, especially {@code 339 * public static final} maps ("constant maps"). Example: <pre> {@code 340 * 341 * static final ImmutableSortedMap<Integer, String> INT_TO_WORD = 342 * new ImmutableSortedMap.Builder<Integer, String>(Ordering.natural()) 343 * .put(1, "one") 344 * .put(2, "two") 345 * .put(3, "three") 346 * .build();}</pre> 347 * 348 * For <i>small</i> immutable sorted maps, the {@code ImmutableSortedMap.of()} 349 * methods are even more convenient. 350 * 351 * <p>Builder instances can be reused - it is safe to call {@link #build} 352 * multiple times to build multiple maps in series. Each map is a superset of 353 * the maps created before it. 354 * 355 * @since 2.0 (imported from Google Collections Library) 356 */ 357 public static class Builder<K, V> extends ImmutableMap.Builder<K, V> { 358 private final Comparator<? super K> comparator; 359 360 /** 361 * Creates a new builder. The returned builder is equivalent to the builder 362 * generated by {@link ImmutableSortedMap#orderedBy}. 363 */ 364 public Builder(Comparator<? super K> comparator) { 365 this.comparator = checkNotNull(comparator); 366 } 367 368 /** 369 * Associates {@code key} with {@code value} in the built map. Duplicate 370 * keys, according to the comparator (which might be the keys' natural 371 * order), are not allowed, and will cause {@link #build} to fail. 372 */ 373 @Override public Builder<K, V> put(K key, V value) { 374 entries.add(entryOf(key, value)); 375 return this; 376 } 377 378 /** 379 * Adds the given {@code entry} to the map, making it immutable if 380 * necessary. Duplicate keys, according to the comparator (which might be 381 * the keys' natural order), are not allowed, and will cause {@link #build} 382 * to fail. 383 * 384 * @since 11.0 385 */ 386 @Override public Builder<K, V> put(Entry<? extends K, ? extends V> entry) { 387 super.put(entry); 388 return this; 389 } 390 391 /** 392 * Associates all of the given map's keys and values in the built map. 393 * Duplicate keys, according to the comparator (which might be the keys' 394 * natural order), are not allowed, and will cause {@link #build} to fail. 395 * 396 * @throws NullPointerException if any key or value in {@code map} is null 397 */ 398 @Override public Builder<K, V> putAll(Map<? extends K, ? extends V> map) { 399 for (Entry<? extends K, ? extends V> entry : map.entrySet()) { 400 put(entry.getKey(), entry.getValue()); 401 } 402 return this; 403 } 404 405 /** 406 * Returns a newly-created immutable sorted map. 407 * 408 * @throws IllegalArgumentException if any two keys are equal according to 409 * the comparator (which might be the keys' natural order) 410 */ 411 @Override public ImmutableSortedMap<K, V> build() { 412 sortEntries(entries, comparator); 413 validateEntries(entries, comparator); 414 return new ImmutableSortedMap<K, V>( 415 ImmutableList.copyOf(entries), comparator); 416 } 417 } 418 419 final transient ImmutableList<Entry<K, V>> entries; 420 private final transient Comparator<? super K> comparator; 421 422 ImmutableSortedMap( 423 ImmutableList<Entry<K, V>> entries, Comparator<? super K> comparator) { 424 this.entries = entries; 425 this.comparator = comparator; 426 } 427 428 @Override 429 public int size() { 430 return entries.size(); 431 } 432 433 // Pretend the comparator can compare anything. If it turns out it can't 434 // compare two elements, it'll throw a CCE. Only methods that are specified to 435 // throw CCE should call this. 436 @SuppressWarnings("unchecked") 437 Comparator<Object> unsafeComparator() { 438 return (Comparator<Object>) comparator; 439 } 440 441 @Override public V get(@Nullable Object key) { 442 if (key == null) { 443 return null; 444 } 445 int i; 446 try { 447 i = index(key, ANY_PRESENT, INVERTED_INSERTION_INDEX); 448 } catch (ClassCastException e) { 449 return null; 450 } 451 return i >= 0 ? entries.get(i).getValue() : null; 452 } 453 454 @Override public boolean containsValue(@Nullable Object value) { 455 return value != null && Maps.containsValueImpl(this, value); 456 } 457 458 @Override boolean isPartialView() { 459 return entries.isPartialView(); 460 } 461 462 /** 463 * Returns an immutable set of the mappings in this map, sorted by the key 464 * ordering. 465 */ 466 @Override public ImmutableSet<Entry<K, V>> entrySet() { 467 return super.entrySet(); 468 } 469 470 @Override 471 ImmutableSet<Entry<K, V>> createEntrySet() { 472 return isEmpty() ? ImmutableSet.<Entry<K, V>>of() 473 : new EntrySet(); 474 } 475 476 @SuppressWarnings("serial") // uses writeReplace(), not default serialization 477 private class EntrySet extends ImmutableMap<K, V>.EntrySet { 478 @Override 479 public UnmodifiableIterator<Entry<K, V>> iterator() { 480 return entries.iterator(); 481 } 482 483 @Override 484 ImmutableList<Entry<K, V>> createAsList() { 485 // TODO(user): make the returned list delegate to the entrySet for contains checks 486 // can't do it right now without rewriting ImmutableAsList 487 return entries; 488 } 489 } 490 491 /** 492 * Returns an immutable sorted set of the keys in this map. 493 */ 494 @Override public ImmutableSortedSet<K> keySet() { 495 return (ImmutableSortedSet<K>) super.keySet(); 496 } 497 498 @Override 499 @SuppressWarnings("serial") // does not use default serialization 500 ImmutableSortedSet<K> createKeySet() { 501 if (isEmpty()) { 502 return ImmutableSortedSet.emptySet(comparator); 503 } 504 505 return new RegularImmutableSortedSet<K>( 506 new TransformedImmutableList<Entry<K, V>, K>(entries) { 507 508 @Override K transform(Entry<K, V> entry) { 509 return entry.getKey(); 510 } 511 }, comparator); 512 } 513 514 /** 515 * Returns an immutable collection of the values in this map, sorted by the 516 * ordering of the corresponding keys. 517 */ 518 @Override public ImmutableCollection<V> values() { 519 return super.values(); 520 } 521 522 /** 523 * Returns the comparator that orders the keys, which is 524 * {@link Ordering#natural()} when the natural ordering of the keys is used. 525 * Note that its behavior is not consistent with {@link TreeMap#comparator()}, 526 * which returns {@code null} to indicate natural ordering. 527 */ 528 @Override 529 public Comparator<? super K> comparator() { 530 return comparator; 531 } 532 533 @Override 534 public K firstKey() { 535 if (isEmpty()) { 536 throw new NoSuchElementException(); 537 } 538 return entries.get(0).getKey(); 539 } 540 541 @Override 542 public K lastKey() { 543 if (isEmpty()) { 544 throw new NoSuchElementException(); 545 } 546 return entries.get(size() - 1).getKey(); 547 } 548 549 /** 550 * This method returns a {@code ImmutableSortedMap}, consisting of the entries 551 * whose keys are less than {@code toKey}. 552 * 553 * <p>The {@link SortedMap#headMap} documentation states that a submap of a 554 * submap throws an {@link IllegalArgumentException} if passed a {@code toKey} 555 * greater than an earlier {@code toKey}. However, this method doesn't throw 556 * an exception in that situation, but instead keeps the original {@code 557 * toKey}. 558 */ 559 @Override 560 public ImmutableSortedMap<K, V> headMap(K toKey) { 561 return headMap(toKey, false); 562 } 563 564 /** 565 * This method returns a {@code ImmutableSortedMap}, consisting of the entries 566 * whose keys are less than (or equal to, if {@code inclusive}) {@code toKey}. 567 * 568 * <p>The {@link SortedMap#headMap} documentation states that a submap of a 569 * submap throws an {@link IllegalArgumentException} if passed a {@code toKey} 570 * greater than an earlier {@code toKey}. However, this method doesn't throw 571 * an exception in that situation, but instead keeps the original {@code 572 * toKey}. 573 * 574 * @since 12.0 575 */ 576 @Override 577 public ImmutableSortedMap<K, V> headMap(K toKey, boolean inclusive) { 578 int index; 579 if (inclusive) { 580 index = index(toKey, ANY_PRESENT, NEXT_LOWER) + 1; 581 } else { 582 index = index(toKey, ANY_PRESENT, NEXT_HIGHER); 583 } 584 return createSubmap(0, index); 585 } 586 587 /** 588 * This method returns a {@code ImmutableSortedMap}, consisting of the entries 589 * whose keys ranges from {@code fromKey}, inclusive, to {@code toKey}, 590 * exclusive. 591 * 592 * <p>The {@link SortedMap#subMap} documentation states that a submap of a 593 * submap throws an {@link IllegalArgumentException} if passed a {@code 594 * fromKey} less than an earlier {@code fromKey}. However, this method doesn't 595 * throw an exception in that situation, but instead keeps the original {@code 596 * fromKey}. Similarly, this method keeps the original {@code toKey}, instead 597 * of throwing an exception, if passed a {@code toKey} greater than an earlier 598 * {@code toKey}. 599 */ 600 @Override 601 public ImmutableSortedMap<K, V> subMap(K fromKey, K toKey) { 602 return subMap(fromKey, true, toKey, false); 603 } 604 605 /** 606 * This method returns a {@code ImmutableSortedMap}, consisting of the entries 607 * whose keys ranges from {@code fromKey} to {@code toKey}, inclusive or 608 * exclusive as indicated by the boolean flags. 609 * 610 * <p>The {@link SortedMap#subMap} documentation states that a submap of a 611 * submap throws an {@link IllegalArgumentException} if passed a {@code 612 * fromKey} less than an earlier {@code fromKey}. However, this method doesn't 613 * throw an exception in that situation, but instead keeps the original {@code 614 * fromKey}. Similarly, this method keeps the original {@code toKey}, instead 615 * of throwing an exception, if passed a {@code toKey} greater than an earlier 616 * {@code toKey}. 617 * 618 * @since 12.0 619 */ 620 @Override 621 public ImmutableSortedMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, 622 boolean toInclusive) { 623 checkNotNull(fromKey); 624 checkNotNull(toKey); 625 checkArgument(comparator.compare(fromKey, toKey) <= 0); 626 return tailMap(fromKey, fromInclusive).headMap(toKey, toInclusive); 627 } 628 629 /** 630 * This method returns a {@code ImmutableSortedMap}, consisting of the entries 631 * whose keys are greater than or equals to {@code fromKey}. 632 * 633 * <p>The {@link SortedMap#tailMap} documentation states that a submap of a 634 * submap throws an {@link IllegalArgumentException} if passed a {@code 635 * fromKey} less than an earlier {@code fromKey}. However, this method doesn't 636 * throw an exception in that situation, but instead keeps the original {@code 637 * fromKey}. 638 */ 639 @Override 640 public ImmutableSortedMap<K, V> tailMap(K fromKey) { 641 return tailMap(fromKey, true); 642 } 643 644 /** 645 * This method returns a {@code ImmutableSortedMap}, consisting of the entries 646 * whose keys are greater than (or equal to, if {@code inclusive}) 647 * {@code fromKey}. 648 * 649 * <p>The {@link SortedMap#tailMap} documentation states that a submap of a 650 * submap throws an {@link IllegalArgumentException} if passed a {@code 651 * fromKey} less than an earlier {@code fromKey}. However, this method doesn't 652 * throw an exception in that situation, but instead keeps the original {@code 653 * fromKey}. 654 * 655 * @since 12.0 656 */ 657 @Override 658 public ImmutableSortedMap<K, V> tailMap(K fromKey, boolean inclusive) { 659 int index; 660 if (inclusive) { 661 index = index(fromKey, ANY_PRESENT, NEXT_HIGHER); 662 } else { 663 index = index(fromKey, ANY_PRESENT, NEXT_LOWER) + 1; 664 } 665 return createSubmap(index, size()); 666 } 667 668 @Override 669 public Entry<K, V> lowerEntry(K key) { 670 return headMap(key, false).lastEntry(); 671 } 672 673 @Override 674 public K lowerKey(K key) { 675 return keyOrNull(lowerEntry(key)); 676 } 677 678 @Override 679 public Entry<K, V> floorEntry(K key) { 680 return headMap(key, true).lastEntry(); 681 } 682 683 @Override 684 public K floorKey(K key) { 685 return keyOrNull(floorEntry(key)); 686 } 687 688 @Override 689 public Entry<K, V> ceilingEntry(K key) { 690 return tailMap(key, true).firstEntry(); 691 } 692 693 @Override 694 public K ceilingKey(K key) { 695 return keyOrNull(ceilingEntry(key)); 696 } 697 698 @Override 699 public Entry<K, V> higherEntry(K key) { 700 return tailMap(key, false).firstEntry(); 701 } 702 703 @Override 704 public K higherKey(K key) { 705 return keyOrNull(higherEntry(key)); 706 } 707 708 @Override 709 public Entry<K, V> firstEntry() { 710 return isEmpty() ? null : entries.get(0); 711 } 712 713 @Override 714 public Entry<K, V> lastEntry() { 715 return isEmpty() ? null : entries.get(entries.size() - 1); 716 } 717 718 @Override 719 public final Entry<K, V> pollFirstEntry() { 720 throw new UnsupportedOperationException(); 721 } 722 723 @Override 724 public final Entry<K, V> pollLastEntry() { 725 throw new UnsupportedOperationException(); 726 } 727 728 private transient ImmutableSortedMap<K, V> descendingMap; 729 730 @Override 731 public ImmutableSortedMap<K, V> descendingMap() { 732 ImmutableSortedMap<K, V> result = descendingMap; 733 if (result == null) { 734 result = descendingMap = 735 new ImmutableSortedMap<K, V>(entries.reverse(), Ordering.from(comparator()).reverse()); 736 result.descendingMap = this; 737 } 738 return result; 739 } 740 741 @Override 742 public ImmutableSortedSet<K> navigableKeySet() { 743 return keySet(); 744 } 745 746 @Override 747 public ImmutableSortedSet<K> descendingKeySet() { 748 return descendingMap().keySet(); 749 } 750 751 private ImmutableList<K> keyList() { 752 return new TransformedImmutableList<Entry<K, V>, K>(entries) { 753 @Override 754 K transform(Entry<K, V> entry) { 755 return entry.getKey(); 756 } 757 }; 758 } 759 760 private int index( 761 Object key, KeyPresentBehavior presentBehavior, KeyAbsentBehavior absentBehavior) { 762 return SortedLists.binarySearch( 763 keyList(), checkNotNull(key), unsafeComparator(), presentBehavior, absentBehavior); 764 } 765 766 private ImmutableSortedMap<K, V> createSubmap( 767 int newFromIndex, int newToIndex) { 768 if (newFromIndex < newToIndex) { 769 return new ImmutableSortedMap<K, V>( 770 entries.subList(newFromIndex, newToIndex), comparator); 771 } else { 772 return emptyMap(comparator); 773 } 774 } 775 776 /** 777 * Serialized type for all ImmutableSortedMap instances. It captures the 778 * logical contents and they are reconstructed using public factory methods. 779 * This ensures that the implementation types remain as implementation 780 * details. 781 */ 782 private static class SerializedForm extends ImmutableMap.SerializedForm { 783 private final Comparator<Object> comparator; 784 @SuppressWarnings("unchecked") 785 SerializedForm(ImmutableSortedMap<?, ?> sortedMap) { 786 super(sortedMap); 787 comparator = (Comparator<Object>) sortedMap.comparator(); 788 } 789 @Override Object readResolve() { 790 Builder<Object, Object> builder = new Builder<Object, Object>(comparator); 791 return createMap(builder); 792 } 793 private static final long serialVersionUID = 0; 794 } 795 796 @Override Object writeReplace() { 797 return new SerializedForm(this); 798 } 799 800 // This class is never actually serialized directly, but we have to make the 801 // warning go away (and suppressing would suppress for all nested classes too) 802 private static final long serialVersionUID = 0; 803 }