Home | History | Annotate | Download | only in collect
      1 /*
      2  * Copyright (C) 2009 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.common.collect;
     18 
     19 import static com.google.common.base.Preconditions.checkArgument;
     20 import static com.google.common.base.Preconditions.checkNotNull;
     21 
     22 import com.google.common.annotations.GwtCompatible;
     23 
     24 import java.io.Serializable;
     25 import java.util.Arrays;
     26 import java.util.Collections;
     27 import java.util.Comparator;
     28 import java.util.List;
     29 import java.util.Map;
     30 import java.util.NoSuchElementException;
     31 import java.util.SortedMap;
     32 import java.util.TreeMap;
     33 
     34 import javax.annotation.Nullable;
     35 
     36 /**
     37  * An immutable {@link SortedMap}. Does not permit null keys or values.
     38  *
     39  * <p>Unlike {@link Collections#unmodifiableSortedMap}, which is a <i>view</i>
     40  * of a separate map which can still change, an instance of {@code
     41  * ImmutableSortedMap} contains its own data and will <i>never</i> change.
     42  * {@code ImmutableSortedMap} is convenient for {@code public static final} maps
     43  * ("constant maps") and also lets you easily make a "defensive copy" of a map
     44  * provided to your class by a caller.
     45  *
     46  * <p><b>Note</b>: Although this class is not final, it cannot be subclassed as
     47  * it has no public or protected constructors. Thus, instances of this class are
     48  * guaranteed to be immutable.
     49  *
     50  * @author Jared Levy
     51  * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library)
     52  */
     53 @GwtCompatible(serializable = true)
     54 public class ImmutableSortedMap<K, V>
     55     extends ImmutableSortedMapFauxverideShim<K, V> implements SortedMap<K, V> {
     56 
     57   // TODO: Confirm that ImmutableSortedMap is faster to construct and uses less
     58   // memory than TreeMap; then say so in the class Javadoc.
     59 
     60   // TODO: Create separate subclasses for empty, single-entry, and
     61   // multiple-entry instances.
     62 
     63   @SuppressWarnings("unchecked")
     64   private static final Comparator NATURAL_ORDER = Ordering.natural();
     65   private static final Entry<?, ?>[] EMPTY_ARRAY = new Entry<?, ?>[0];
     66 
     67   @SuppressWarnings("unchecked")
     68   private static final ImmutableMap<Object, Object> NATURAL_EMPTY_MAP
     69       = new ImmutableSortedMap<Object, Object>(EMPTY_ARRAY, NATURAL_ORDER);
     70 
     71   /**
     72    * Returns the empty sorted map.
     73    */
     74   // Casting to any type is safe because the set will never hold any elements.
     75   @SuppressWarnings("unchecked")
     76   public static <K, V> ImmutableSortedMap<K, V> of() {
     77     return (ImmutableSortedMap) NATURAL_EMPTY_MAP;
     78   }
     79 
     80   private static <K, V> ImmutableSortedMap<K, V> emptyMap(
     81       Comparator<? super K> comparator) {
     82     if (NATURAL_ORDER.equals(comparator)) {
     83       return ImmutableSortedMap.of();
     84     } else {
     85       return new ImmutableSortedMap<K, V>(EMPTY_ARRAY, comparator);
     86     }
     87   }
     88 
     89   /**
     90    * Returns an immutable map containing a single entry.
     91    */
     92   public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V>
     93       of(K k1, V v1) {
     94     Entry<?, ?>[] entries = { entryOf(k1, v1) };
     95     return new ImmutableSortedMap<K, V>(entries, Ordering.natural());
     96   }
     97 
     98   /**
     99    * Returns an immutable sorted map containing the given entries, sorted by the
    100    * natural ordering of their keys.
    101    *
    102    * @throws IllegalArgumentException if the two keys are equal according to
    103    *     their natural ordering
    104    */
    105   public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V>
    106       of(K k1, V v1, K k2, V v2) {
    107     return new Builder<K, V>(Ordering.natural())
    108         .put(k1, v1).put(k2, v2).build();
    109   }
    110 
    111   /**
    112    * Returns an immutable sorted map containing the given entries, sorted by the
    113    * natural ordering of their keys.
    114    *
    115    * @throws IllegalArgumentException if any two keys are equal according to
    116    *     their natural ordering
    117    */
    118   public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V>
    119       of(K k1, V v1, K k2, V v2, K k3, V v3) {
    120     return new Builder<K, V>(Ordering.natural())
    121         .put(k1, v1).put(k2, v2).put(k3, v3).build();
    122   }
    123 
    124   /**
    125    * Returns an immutable sorted map containing the given entries, sorted by the
    126    * natural ordering of their keys.
    127    *
    128    * @throws IllegalArgumentException if any two keys are equal according to
    129    *     their natural ordering
    130    */
    131   public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V>
    132       of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
    133     return new Builder<K, V>(Ordering.natural())
    134         .put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).build();
    135   }
    136 
    137   /**
    138    * Returns an immutable sorted map containing the given entries, sorted by the
    139    * natural ordering of their keys.
    140    *
    141    * @throws IllegalArgumentException if any two keys are equal according to
    142    *     their natural ordering
    143    */
    144   public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V>
    145       of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
    146     return new Builder<K, V>(Ordering.natural())
    147         .put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).build();
    148   }
    149 
    150   /**
    151    * Returns an immutable map containing the same entries as {@code map}, sorted
    152    * by the natural ordering of the keys.
    153    *
    154    * <p><b>Note:</b> Despite what the method name suggests, if {@code map} is an
    155    * {@code ImmutableSortedMap}, it may be returned instead of a copy.
    156    *
    157    * <p>This method is not type-safe, as it may be called on a map with keys
    158    * that are not mutually comparable.
    159    *
    160    * @throws ClassCastException if the keys in {@code map} are not mutually
    161    *     comparable
    162    * @throws NullPointerException if any key or value in {@code map} is null
    163    * @throws IllegalArgumentException if any two keys are equal according to
    164    *     their natural ordering
    165    */
    166   public static <K, V> ImmutableSortedMap<K, V> copyOf(
    167       Map<? extends K, ? extends V> map) {
    168     // Hack around K not being a subtype of Comparable.
    169     // Unsafe, see ImmutableSortedSetFauxverideShim.
    170     @SuppressWarnings("unchecked")
    171     Ordering<K> naturalOrder = (Ordering) Ordering.<Comparable>natural();
    172     return copyOfInternal(map, naturalOrder);
    173   }
    174 
    175   /**
    176    * Returns an immutable map containing the same entries as {@code map}, with
    177    * keys sorted by the provided comparator.
    178    *
    179    * <p><b>Note:</b> Despite what the method name suggests, if {@code map} is an
    180    * {@code ImmutableSortedMap}, it may be returned instead of a copy.
    181    *
    182    * @throws NullPointerException if any key or value in {@code map} is null
    183    * @throws IllegalArgumentException if any two keys are equal according to
    184    *     the comparator
    185    */
    186   public static <K, V> ImmutableSortedMap<K, V> copyOf(
    187       Map<? extends K, ? extends V> map, Comparator<? super K> comparator) {
    188     return copyOfInternal(map, checkNotNull(comparator));
    189   }
    190 
    191   /**
    192    * Returns an immutable map containing the same entries as the provided sorted
    193    * map, with the same ordering.
    194    *
    195    * <p><b>Note:</b> Despite what the method name suggests, if {@code map} is an
    196    * {@code ImmutableSortedMap}, it may be returned instead of a copy.
    197    *
    198    * @throws NullPointerException if any key or value in {@code map} is null
    199    */
    200   public static <K, V> ImmutableSortedMap<K, V> copyOfSorted(
    201       SortedMap<K, ? extends V> map) {
    202     // If map has a null comparator, the keys should have a natural ordering,
    203     // even though K doesn't explicitly implement Comparable.
    204     @SuppressWarnings("unchecked")
    205     Comparator<? super K> comparator =
    206         (map.comparator() == null) ? NATURAL_ORDER : map.comparator();
    207     return copyOfInternal(map, comparator);
    208   }
    209 
    210   private static <K, V> ImmutableSortedMap<K, V> copyOfInternal(
    211       Map<? extends K, ? extends V> map, Comparator<? super K> comparator) {
    212     boolean sameComparator = false;
    213     if (map instanceof SortedMap) {
    214       SortedMap<?, ?> sortedMap = (SortedMap<?, ?>) map;
    215       Comparator<?> comparator2 = sortedMap.comparator();
    216       sameComparator = (comparator2 == null)
    217           ? comparator == NATURAL_ORDER
    218           : comparator.equals(comparator2);
    219     }
    220 
    221     if (sameComparator && (map instanceof ImmutableSortedMap)) {
    222       // TODO: Prove that this cast is safe, even though
    223       // Collections.unmodifiableSortedMap requires the same key type.
    224       @SuppressWarnings("unchecked")
    225       ImmutableSortedMap<K, V> kvMap = (ImmutableSortedMap<K, V>) map;
    226       return kvMap;
    227     }
    228 
    229     // Using List to support concurrent map whose size changes
    230     List<Entry<?, ?>> list = Lists.newArrayListWithCapacity(map.size());
    231     for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
    232       list.add(entryOf(entry.getKey(), entry.getValue()));
    233     }
    234     Entry<?, ?>[] entryArray = list.toArray(new Entry<?, ?>[list.size()]);
    235 
    236     if (!sameComparator) {
    237       sortEntries(entryArray, comparator);
    238       validateEntries(entryArray, comparator);
    239     }
    240 
    241     return new ImmutableSortedMap<K, V>(entryArray, comparator);
    242   }
    243 
    244   private static void sortEntries(Entry<?, ?>[] entryArray,
    245       final Comparator<?> comparator) {
    246     Comparator<Entry<?, ?>> entryComparator = new Comparator<Entry<?, ?>>() {
    247       public int compare(Entry<?, ?> entry1, Entry<?, ?> entry2) {
    248         return ImmutableSortedSet.unsafeCompare(
    249             comparator, entry1.getKey(), entry2.getKey());
    250       }
    251     };
    252     Arrays.sort(entryArray, entryComparator);
    253   }
    254 
    255   private static void validateEntries(Entry<?, ?>[] entryArray,
    256       Comparator<?> comparator) {
    257     for (int i = 1; i < entryArray.length; i++) {
    258       if (ImmutableSortedSet.unsafeCompare(comparator,
    259           entryArray[i - 1].getKey(), entryArray[i].getKey()) == 0) {
    260         throw new IllegalArgumentException(
    261             "Duplicate keys in mappings "
    262                 + entryArray[i - 1] + " and " + entryArray[i]);
    263       }
    264     }
    265   }
    266 
    267   /**
    268    * Returns a builder that creates immutable sorted maps whose keys are
    269    * ordered by their natural ordering. The sorted maps use {@link
    270    * Ordering#natural()} as the comparator.
    271    *
    272    * <p>Note: the type parameter {@code K} extends {@code Comparable<K>} rather
    273    * than {@code Comparable<? super K>} as a workaround for javac <a
    274    * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug
    275    * 6468354</a>.
    276    */
    277   public static <K extends Comparable<K>, V> Builder<K, V> naturalOrder() {
    278     return new Builder<K, V>(Ordering.natural());
    279   }
    280 
    281   /**
    282    * Returns a builder that creates immutable sorted maps with an explicit
    283    * comparator. If the comparator has a more general type than the map's keys,
    284    * such as creating a {@code SortedMap<Integer, String>} with a {@code
    285    * Comparator<Number>}, use the {@link Builder} constructor instead.
    286    *
    287    * @throws NullPointerException if {@code comparator} is null
    288    */
    289   public static <K, V> Builder<K, V> orderedBy(Comparator<K> comparator) {
    290     return new Builder<K, V>(comparator);
    291   }
    292 
    293   /**
    294    * Returns a builder that creates immutable sorted maps whose keys are
    295    * ordered by the reverse of their natural ordering.
    296    *
    297    * <p>Note: the type parameter {@code K} extends {@code Comparable<K>} rather
    298    * than {@code Comparable<? super K>} as a workaround for javac <a
    299    * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug
    300    * 6468354</a>.
    301    */
    302   public static <K extends Comparable<K>, V> Builder<K, V> reverseOrder() {
    303     return new Builder<K, V>(Ordering.natural().reverse());
    304   }
    305 
    306   /**
    307    * A builder for creating immutable sorted map instances, especially {@code
    308    * public static final} maps ("constant maps"). Example: <pre>   {@code
    309    *
    310    *   static final ImmutableSortedMap<Integer, String> INT_TO_WORD =
    311    *       new ImmutableSortedMap.Builder<Integer, String>(Ordering.natural())
    312    *           .put(1, "one")
    313    *           .put(2, "two")
    314    *           .put(3, "three")
    315    *           .build();}</pre>
    316    *
    317    * For <i>small</i> immutable sorted maps, the {@code ImmutableSortedMap.of()}
    318    * methods are even more convenient.
    319    *
    320    * <p>Builder instances can be reused - it is safe to call {@link #build}
    321    * multiple times to build multiple maps in series. Each map is a superset of
    322    * the maps created before it.
    323    */
    324   public static final class Builder<K, V> extends ImmutableMap.Builder<K, V> {
    325     private final Comparator<? super K> comparator;
    326 
    327     /**
    328      * Creates a new builder. The returned builder is equivalent to the builder
    329      * generated by {@link ImmutableSortedMap#orderedBy}.
    330      */
    331     public Builder(Comparator<? super K> comparator) {
    332       this.comparator = checkNotNull(comparator);
    333     }
    334 
    335     /**
    336      * Associates {@code key} with {@code value} in the built map. Duplicate
    337      * keys, according to the comparator (which might be the keys' natural
    338      * order), are not allowed, and will cause {@link #build} to fail.
    339      */
    340     @Override public Builder<K, V> put(K key, V value) {
    341       entries.add(entryOf(key, value));
    342       return this;
    343     }
    344 
    345     /**
    346      * Associates all of the given map's keys and values in the built map.
    347      * Duplicate keys, according to the comparator (which might be the keys'
    348      * natural order), are not allowed, and will cause {@link #build} to fail.
    349      *
    350      * @throws NullPointerException if any key or value in {@code map} is null
    351      */
    352     @Override public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
    353       for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
    354         put(entry.getKey(), entry.getValue());
    355       }
    356       return this;
    357     }
    358 
    359     /**
    360      * Returns a newly-created immutable sorted map.
    361      *
    362      * @throws IllegalArgumentException if any two keys are equal according to
    363      *     the comparator (which might be the keys' natural order)
    364      */
    365     @Override public ImmutableSortedMap<K, V> build() {
    366       Entry<?, ?>[] entryArray
    367           = entries.toArray(new Entry<?, ?>[entries.size()]);
    368       sortEntries(entryArray, comparator);
    369       validateEntries(entryArray, comparator);
    370       return new ImmutableSortedMap<K, V>(entryArray, comparator);
    371     }
    372   }
    373 
    374   private final transient Entry<K, V>[] entries;
    375   private final transient Comparator<? super K> comparator;
    376   private final transient int fromIndex;
    377   private final transient int toIndex;
    378 
    379   private ImmutableSortedMap(Entry<?, ?>[] entries,
    380       Comparator<? super K> comparator, int fromIndex, int toIndex) {
    381     // each of the callers carefully put only Entry<K, V>s into the array!
    382     @SuppressWarnings("unchecked")
    383     Entry<K, V>[] tmp = (Entry<K, V>[]) entries;
    384     this.entries = tmp;
    385     this.comparator = comparator;
    386     this.fromIndex = fromIndex;
    387     this.toIndex = toIndex;
    388   }
    389 
    390   ImmutableSortedMap(Entry<?, ?>[] entries,
    391       Comparator<? super K> comparator) {
    392     this(entries, comparator, 0, entries.length);
    393   }
    394 
    395   public int size() {
    396     return toIndex - fromIndex;
    397   }
    398 
    399   @Override public V get(@Nullable Object key) {
    400     if (key == null) {
    401       return null;
    402     }
    403     int i;
    404     try {
    405       i = binarySearch(key);
    406     } catch (ClassCastException e) {
    407       return null;
    408     }
    409     return (i >= 0) ? entries[i].getValue() : null;
    410   }
    411 
    412   private int binarySearch(Object key) {
    413     int lower = fromIndex;
    414     int upper = toIndex - 1;
    415 
    416     while (lower <= upper) {
    417       int middle = lower + (upper - lower) / 2;
    418       int c = ImmutableSortedSet.unsafeCompare(
    419           comparator, key, entries[middle].getKey());
    420       if (c < 0) {
    421         upper = middle - 1;
    422       } else if (c > 0) {
    423         lower = middle + 1;
    424       } else {
    425         return middle;
    426       }
    427     }
    428 
    429     return -lower - 1;
    430   }
    431 
    432   @Override public boolean containsValue(@Nullable Object value) {
    433     if (value == null) {
    434       return false;
    435     }
    436     for (int i = fromIndex; i < toIndex; i++) {
    437       if (entries[i].getValue().equals(value)) {
    438         return true;
    439       }
    440     }
    441     return false;
    442   }
    443 
    444   private transient ImmutableSet<Entry<K, V>> entrySet;
    445 
    446   /**
    447    * Returns an immutable set of the mappings in this map, sorted by the key
    448    * ordering.
    449    */
    450   @Override public ImmutableSet<Entry<K, V>> entrySet() {
    451     ImmutableSet<Entry<K, V>> es = entrySet;
    452     return (es == null) ? (entrySet = createEntrySet()) : es;
    453   }
    454 
    455   private ImmutableSet<Entry<K, V>> createEntrySet() {
    456     return isEmpty() ? ImmutableSet.<Entry<K, V>>of()
    457         : new EntrySet<K, V>(this);
    458   }
    459 
    460   @SuppressWarnings("serial") // uses writeReplace(), not default serialization
    461   private static class EntrySet<K, V> extends ImmutableSet<Entry<K, V>> {
    462     final transient ImmutableSortedMap<K, V> map;
    463 
    464     EntrySet(ImmutableSortedMap<K, V> map) {
    465       this.map = map;
    466     }
    467 
    468     public int size() {
    469       return map.size();
    470     }
    471 
    472     @Override public UnmodifiableIterator<Entry<K, V>> iterator() {
    473       return Iterators.forArray(map.entries, map.fromIndex, size());
    474     }
    475 
    476     @Override public boolean contains(Object target) {
    477       if (target instanceof Entry) {
    478         Entry<?, ?> entry = (Entry<?, ?>) target;
    479         V mappedValue = map.get(entry.getKey());
    480         return mappedValue != null && mappedValue.equals(entry.getValue());
    481       }
    482       return false;
    483     }
    484 
    485     @Override Object writeReplace() {
    486       return new EntrySetSerializedForm<K, V>(map);
    487     }
    488   }
    489 
    490   private static class EntrySetSerializedForm<K, V> implements Serializable {
    491     final ImmutableSortedMap<K, V> map;
    492     EntrySetSerializedForm(ImmutableSortedMap<K, V> map) {
    493       this.map = map;
    494     }
    495     Object readResolve() {
    496       return map.entrySet();
    497     }
    498     private static final long serialVersionUID = 0;
    499   }
    500 
    501   private transient ImmutableSortedSet<K> keySet;
    502 
    503   /**
    504    * Returns an immutable sorted set of the keys in this map.
    505    */
    506   @Override public ImmutableSortedSet<K> keySet() {
    507     ImmutableSortedSet<K> ks = keySet;
    508     return (ks == null) ? (keySet = createKeySet()) : ks;
    509   }
    510 
    511   private ImmutableSortedSet<K> createKeySet() {
    512     if (isEmpty()) {
    513       return ImmutableSortedSet.emptySet(comparator);
    514     }
    515 
    516     // TODO: For better performance, don't create a separate array.
    517     Object[] array = new Object[size()];
    518     for (int i = fromIndex; i < toIndex; i++) {
    519       array[i - fromIndex] = entries[i].getKey();
    520     }
    521     return new RegularImmutableSortedSet<K>(array, comparator);
    522   }
    523 
    524   private transient ImmutableCollection<V> values;
    525 
    526   /**
    527    * Returns an immutable collection of the values in this map, sorted by the
    528    * ordering of the corresponding keys.
    529    */
    530   @Override public ImmutableCollection<V> values() {
    531     ImmutableCollection<V> v = values;
    532     return (v == null) ? (values = new Values<V>(this)) : v;
    533   }
    534 
    535   @SuppressWarnings("serial") // uses writeReplace(), not default serialization
    536   private static class Values<V> extends ImmutableCollection<V> {
    537     private final ImmutableSortedMap<?, V> map;
    538 
    539     Values(ImmutableSortedMap<?, V> map) {
    540       this.map = map;
    541     }
    542 
    543     public int size() {
    544       return map.size();
    545     }
    546 
    547     @Override public UnmodifiableIterator<V> iterator() {
    548       return new AbstractIterator<V>() {
    549         int index = map.fromIndex;
    550         @Override protected V computeNext() {
    551           return (index < map.toIndex)
    552               ? map.entries[index++].getValue()
    553               : endOfData();
    554         }
    555       };
    556     }
    557 
    558     @Override public boolean contains(Object target) {
    559       return map.containsValue(target);
    560     }
    561 
    562     @Override Object writeReplace() {
    563       return new ValuesSerializedForm<V>(map);
    564     }
    565   }
    566 
    567   private static class ValuesSerializedForm<V> implements Serializable {
    568     final ImmutableSortedMap<?, V> map;
    569     ValuesSerializedForm(ImmutableSortedMap<?, V> map) {
    570       this.map = map;
    571     }
    572     Object readResolve() {
    573       return map.values();
    574     }
    575     private static final long serialVersionUID = 0;
    576   }
    577 
    578   /**
    579    * Returns the comparator that orders the keys, which is
    580    * {@link Ordering#natural()} when the natural ordering of the keys is used.
    581    * Note that its behavior is not consistent with {@link TreeMap#comparator()},
    582    * which returns {@code null} to indicate natural ordering.
    583    */
    584   public Comparator<? super K> comparator() {
    585     return comparator;
    586   }
    587 
    588   public K firstKey() {
    589     if (isEmpty()) {
    590       throw new NoSuchElementException();
    591     }
    592     return entries[fromIndex].getKey();
    593   }
    594 
    595   public K lastKey() {
    596     if (isEmpty()) {
    597       throw new NoSuchElementException();
    598     }
    599     return entries[toIndex - 1].getKey();
    600   }
    601 
    602   /**
    603    * This method returns a {@code ImmutableSortedMap}, consisting of the entries
    604    * whose keys are less than {@code toKey}.
    605    *
    606    * <p>The {@link SortedMap#headMap} documentation states that a submap of a
    607    * submap throws an {@link IllegalArgumentException} if passed a {@code toKey}
    608    * greater than an earlier {@code toKey}. However, this method doesn't throw
    609    * an exception in that situation, but instead keeps the original {@code
    610    * toKey}.
    611    */
    612   public ImmutableSortedMap<K, V> headMap(K toKey) {
    613     int newToIndex = findSubmapIndex(checkNotNull(toKey));
    614     return createSubmap(fromIndex, newToIndex);
    615   }
    616 
    617   /**
    618    * This method returns a {@code ImmutableSortedMap}, consisting of the entries
    619    * whose keys ranges from {@code fromKey}, inclusive, to {@code toKey},
    620    * exclusive.
    621    *
    622    * <p>The {@link SortedMap#subMap} documentation states that a submap of a
    623    * submap throws an {@link IllegalArgumentException} if passed a {@code
    624    * fromKey} less than an earlier {@code fromKey}. However, this method doesn't
    625    * throw an exception in that situation, but instead keeps the original {@code
    626    * fromKey}. Similarly, this method keeps the original {@code toKey}, instead
    627    * of throwing an exception, if passed a {@code toKey} greater than an earlier
    628    * {@code toKey}.
    629    */
    630   public ImmutableSortedMap<K, V> subMap(K fromKey, K toKey) {
    631     checkNotNull(fromKey);
    632     checkNotNull(toKey);
    633     checkArgument(comparator.compare(fromKey, toKey) <= 0);
    634     int newFromIndex = findSubmapIndex(fromKey);
    635     int newToIndex = findSubmapIndex(toKey);
    636     return createSubmap(newFromIndex, newToIndex);
    637   }
    638 
    639   /**
    640    * This method returns a {@code ImmutableSortedMap}, consisting of the entries
    641    * whose keys are greater than or equals to {@code fromKey}.
    642    *
    643    * <p>The {@link SortedMap#tailMap} documentation states that a submap of a
    644    * submap throws an {@link IllegalArgumentException} if passed a {@code
    645    * fromKey} less than an earlier {@code fromKey}. However, this method doesn't
    646    * throw an exception in that situation, but instead keeps the original {@code
    647    * fromKey}.
    648    */
    649   public ImmutableSortedMap<K, V> tailMap(K fromKey) {
    650     int newFromIndex = findSubmapIndex(checkNotNull(fromKey));
    651     return createSubmap(newFromIndex, toIndex);
    652   }
    653 
    654   private int findSubmapIndex(K key) {
    655     int index = binarySearch(key);
    656     return (index >= 0) ? index : (-index - 1);
    657   }
    658 
    659   private ImmutableSortedMap<K, V> createSubmap(
    660       int newFromIndex, int newToIndex) {
    661     if (newFromIndex < newToIndex) {
    662       return new ImmutableSortedMap<K, V>(entries, comparator,
    663           newFromIndex, newToIndex);
    664     } else {
    665       return emptyMap(comparator);
    666     }
    667   }
    668 
    669   /**
    670    * Serialized type for all ImmutableSortedMap instances. It captures the
    671    * logical contents and they are reconstructed using public factory methods.
    672    * This ensures that the implementation types remain as implementation
    673    * details.
    674    */
    675   private static class SerializedForm extends ImmutableMap.SerializedForm {
    676     private final Comparator<Object> comparator;
    677     @SuppressWarnings("unchecked")
    678     SerializedForm(ImmutableSortedMap<?, ?> sortedMap) {
    679       super(sortedMap);
    680       comparator = (Comparator<Object>) sortedMap.comparator();
    681     }
    682     @Override Object readResolve() {
    683       Builder<Object, Object> builder = new Builder<Object, Object>(comparator);
    684       return createMap(builder);
    685     }
    686     private static final long serialVersionUID = 0;
    687   }
    688 
    689   @Override Object writeReplace() {
    690     return new SerializedForm(this);
    691   }
    692 
    693   // This class is never actually serialized directly, but we have to make the
    694   // warning go away (and suppressing would suppress for all nested classes too)
    695   private static final long serialVersionUID = 0;
    696 }
    697