View Javadoc
1   /*
2    * Copyright (C) 2007 The Guava Authors
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  
21  import com.google.common.annotations.Beta;
22  import com.google.common.annotations.GwtCompatible;
23  
24  import java.util.Comparator;
25  import java.util.NoSuchElementException;
26  import java.util.SortedMap;
27  
28  import javax.annotation.Nullable;
29  
30  /**
31   * A sorted map which forwards all its method calls to another sorted map.
32   * Subclasses should override one or more methods to modify the behavior of
33   * the backing sorted map as desired per the <a
34   * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
35   *
36   * <p><i>Warning:</i> The methods of {@code ForwardingSortedMap} forward
37   * <i>indiscriminately</i> to the methods of the delegate. For example,
38   * overriding {@link #put} alone <i>will not</i> change the behavior of {@link
39   * #putAll}, which can lead to unexpected behavior. In this case, you should
40   * override {@code putAll} as well, either providing your own implementation, or
41   * delegating to the provided {@code standardPutAll} method.
42   *
43   * <p>Each of the {@code standard} methods, where appropriate, use the
44   * comparator of the map to test equality for both keys and values, unlike
45   * {@code ForwardingMap}.
46   *
47   * <p>The {@code standard} methods and the collection views they return are not
48   * guaranteed to be thread-safe, even when all of the methods that they depend
49   * on are thread-safe.
50   *
51   * @author Mike Bostock
52   * @author Louis Wasserman
53   * @since 2.0 (imported from Google Collections Library)
54   */
55  @GwtCompatible
56  public abstract class ForwardingSortedMap<K, V> extends ForwardingMap<K, V>
57      implements SortedMap<K, V> {
58    // TODO(user): identify places where thread safety is actually lost
59  
60    /** Constructor for use by subclasses. */
61    protected ForwardingSortedMap() {}
62  
63    @Override protected abstract SortedMap<K, V> delegate();
64  
65    @Override
66    public Comparator<? super K> comparator() {
67      return delegate().comparator();
68    }
69  
70    @Override
71    public K firstKey() {
72      return delegate().firstKey();
73    }
74  
75    @Override
76    public SortedMap<K, V> headMap(K toKey) {
77      return delegate().headMap(toKey);
78    }
79  
80    @Override
81    public K lastKey() {
82      return delegate().lastKey();
83    }
84  
85    @Override
86    public SortedMap<K, V> subMap(K fromKey, K toKey) {
87      return delegate().subMap(fromKey, toKey);
88    }
89  
90    @Override
91    public SortedMap<K, V> tailMap(K fromKey) {
92      return delegate().tailMap(fromKey);
93    }
94  
95    /**
96     * A sensible implementation of {@link SortedMap#keySet} in terms of the methods of
97     * {@code ForwardingSortedMap}. In many cases, you may wish to override
98     * {@link ForwardingSortedMap#keySet} to forward to this implementation or a subclass thereof.
99     *
100    * @since 15.0
101    */
102   @Beta
103   protected class StandardKeySet extends Maps.SortedKeySet<K, V> {
104     /** Constructor for use by subclasses. */
105     public StandardKeySet() {
106       super(ForwardingSortedMap.this);
107     }
108   }
109 
110   // unsafe, but worst case is a CCE is thrown, which callers will be expecting
111   @SuppressWarnings("unchecked")
112   private int unsafeCompare(Object k1, Object k2) {
113     Comparator<? super K> comparator = comparator();
114     if (comparator == null) {
115       return ((Comparable<Object>) k1).compareTo(k2);
116     } else {
117       return ((Comparator<Object>) comparator).compare(k1, k2);
118     }
119   }
120 
121   /**
122    * A sensible definition of {@link #containsKey} in terms of the {@code
123    * firstKey()} method of {@link #tailMap}. If you override {@link #tailMap},
124    * you may wish to override {@link #containsKey} to forward to this
125    * implementation.
126    *
127    * @since 7.0
128    */
129   @Override @Beta protected boolean standardContainsKey(@Nullable Object key) {
130     try {
131       // any CCE will be caught
132       @SuppressWarnings("unchecked")
133       SortedMap<Object, V> self = (SortedMap<Object, V>) this;
134       Object ceilingKey = self.tailMap(key).firstKey();
135       return unsafeCompare(ceilingKey, key) == 0;
136     } catch (ClassCastException e) {
137       return false;
138     } catch (NoSuchElementException e) {
139       return false;
140     } catch (NullPointerException e) {
141       return false;
142     }
143   }
144 
145   /**
146    * A sensible default implementation of {@link #subMap(Object, Object)} in
147    * terms of {@link #headMap(Object)} and {@link #tailMap(Object)}. In some
148    * situations, you may wish to override {@link #subMap(Object, Object)} to
149    * forward to this implementation.
150    *
151    * @since 7.0
152    */
153   @Beta protected SortedMap<K, V> standardSubMap(K fromKey, K toKey) {
154     checkArgument(unsafeCompare(fromKey, toKey) <= 0, "fromKey must be <= toKey");
155     return tailMap(fromKey).headMap(toKey);
156   }
157 }