• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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.checkNotNull;
20 
21 import java.util.Comparator;
22 import java.util.Map;
23 import java.util.Map.Entry;
24 import java.util.SortedMap;
25 
26 import javax.annotation.Nullable;
27 
28 import com.google.common.annotations.Beta;
29 import com.google.common.annotations.GwtCompatible;
30 import com.google.common.annotations.GwtIncompatible;
31 import com.google.common.base.Function;
32 import com.google.common.base.Predicate;
33 import com.google.common.base.Predicates;
34 import com.google.common.collect.Maps.EntryTransformer;
35 
36 /**
37  * Static utility methods pertaining to {@link SortedMap} instances.
38  *
39  * @author Louis Wasserman
40  * @since 8.0
41  * @deprecated Use the identical methods in {@link Maps}. This class is
42  *             scheduled for deletion from Guava in Guava release 12.0.
43  */
44 @Beta
45 @Deprecated
46 @GwtCompatible
47 public final class SortedMaps {
SortedMaps()48   private SortedMaps() {}
49 
50   /**
51    * Returns a view of a sorted map where each value is transformed by a
52    * function. All other properties of the map, such as iteration order, are
53    * left intact. For example, the code: <pre>   {@code
54    *
55    *   SortedMap<String, Integer> map = ImmutableSortedMap.of("a", 4, "b", 9);
56    *   Function<Integer, Double> sqrt =
57    *       new Function<Integer, Double>() {
58    *         public Double apply(Integer in) {
59    *           return Math.sqrt((int) in);
60    *         }
61    *       };
62    *   SortedMap<String, Double> transformed =
63    *        Maps.transformSortedValues(map, sqrt);
64    *   System.out.println(transformed);}</pre>
65    *
66    * ... prints {@code {a=2.0, b=3.0}}.
67    *
68    * <p>Changes in the underlying map are reflected in this view. Conversely,
69    * this view supports removal operations, and these are reflected in the
70    * underlying map.
71    *
72    * <p>It's acceptable for the underlying map to contain null keys, and even
73    * null values provided that the function is capable of accepting null input.
74    * The transformed map might contain null values, if the function sometimes
75    * gives a null result.
76    *
77    * <p>The returned map is not thread-safe or serializable, even if the
78    * underlying map is.
79    *
80    * <p>The function is applied lazily, invoked when needed. This is necessary
81    * for the returned map to be a view, but it means that the function will be
82    * applied many times for bulk operations like {@link Map#containsValue} and
83    * {@code Map.toString()}. For this to perform well, {@code function} should
84    * be fast. To avoid lazy evaluation when the returned map doesn't need to be
85    * a view, copy the returned map into a new map of your choosing.
86    *
87    * @deprecated Use {@link Maps#transformValues(SortedMap, Function)}
88    */
transformValues( SortedMap<K, V1> fromMap, final Function<? super V1, V2> function)89   @Deprecated public static <K, V1, V2> SortedMap<K, V2> transformValues(
90       SortedMap<K, V1> fromMap, final Function<? super V1, V2> function) {
91     return Maps.transformValues(fromMap, function);
92   }
93 
94   /**
95    * Returns a view of a sorted map whose values are derived from the original
96    * sorted map's entries. In contrast to {@link #transformValues}, this
97    * method's entry-transformation logic may depend on the key as well as the
98    * value.
99    *
100    * <p>All other properties of the transformed map, such as iteration order,
101    * are left intact. For example, the code: <pre>   {@code
102    *
103    *   Map<String, Boolean> options =
104    *       ImmutableSortedMap.of("verbose", true, "sort", false);
105    *   EntryTransformer<String, Boolean, String> flagPrefixer =
106    *       new EntryTransformer<String, Boolean, String>() {
107    *         public String transformEntry(String key, Boolean value) {
108    *           return value ? key : "yes" + key;
109    *         }
110    *       };
111    *   SortedMap<String, String> transformed =
112    *       LabsMaps.transformSortedEntries(options, flagPrefixer);
113    *   System.out.println(transformed);}</pre>
114    *
115    * ... prints {@code {sort=yessort, verbose=verbose}}.
116    *
117    * <p>Changes in the underlying map are reflected in this view. Conversely,
118    * this view supports removal operations, and these are reflected in the
119    * underlying map.
120    *
121    * <p>It's acceptable for the underlying map to contain null keys and null
122    * values provided that the transformer is capable of accepting null inputs.
123    * The transformed map might contain null values if the transformer sometimes
124    * gives a null result.
125    *
126    * <p>The returned map is not thread-safe or serializable, even if the
127    * underlying map is.
128    *
129    * <p>The transformer is applied lazily, invoked when needed. This is
130    * necessary for the returned map to be a view, but it means that the
131    * transformer will be applied many times for bulk operations like {@link
132    * Map#containsValue} and {@link Object#toString}. For this to perform well,
133    * {@code transformer} should be fast. To avoid lazy evaluation when the
134    * returned map doesn't need to be a view, copy the returned map into a new
135    * map of your choosing.
136    *
137    * <p><b>Warning:</b> This method assumes that for any instance {@code k} of
138    * {@code EntryTransformer} key type {@code K}, {@code k.equals(k2)} implies
139    * that {@code k2} is also of type {@code K}. Using an {@code
140    * EntryTransformer} key type for which this may not hold, such as {@code
141    * ArrayList}, may risk a {@code ClassCastException} when calling methods on
142    * the transformed map.
143    *
144    * @deprecated Use {@link Maps#transformEntries(SortedMap, EntryTransformer)}
145    */
transformEntries( final SortedMap<K, V1> fromMap, EntryTransformer<? super K, ? super V1, V2> transformer)146   @Deprecated public static <K, V1, V2> SortedMap<K, V2> transformEntries(
147       final SortedMap<K, V1> fromMap,
148       EntryTransformer<? super K, ? super V1, V2> transformer) {
149     return Maps.transformEntries(fromMap, transformer);
150   }
151 
152   /**
153    * Computes the difference between two sorted maps, using the comparator of
154    * the left map, or {@code Ordering.natural()} if the left map uses the
155    * natural ordering of its elements. This difference is an immutable snapshot
156    * of the state of the maps at the time this method is called. It will never
157    * change, even if the maps change at a later time.
158    *
159    * <p>Since this method uses {@code TreeMap} instances internally, the keys of
160    * the right map must all compare as distinct according to the comparator
161    * of the left map.
162    *
163    * <p><b>Note:</b>If you only need to know whether two sorted maps have the
164    * same mappings, call {@code left.equals(right)} instead of this method.
165    *
166    * @param left the map to treat as the "left" map for purposes of comparison
167    * @param right the map to treat as the "right" map for purposes of comparison
168    * @return the difference between the two maps
169    * @deprecated Use {@link Maps#difference(SortedMap, Map)}
170    */
difference( SortedMap<K, ? extends V> left, Map<? extends K, ? extends V> right)171   @Deprecated public static <K, V> SortedMapDifference<K, V> difference(
172       SortedMap<K, ? extends V> left, Map<? extends K, ? extends V> right) {
173     return Maps.difference(left, right);
174   }
175 
176   /**
177    * Returns the specified comparator if not null; otherwise returns {@code
178    * Ordering.natural()}. This method is an abomination of generics; the only
179    * purpose of this method is to contain the ugly type-casting in one place.
180    */
181   @SuppressWarnings("unchecked")
orNaturalOrder( @ullable Comparator<? super E> comparator)182   static <E> Comparator<? super E> orNaturalOrder(
183       @Nullable Comparator<? super E> comparator) {
184     if (comparator != null) { // can't use ? : because of javac bug 5080917
185       return comparator;
186     }
187     return (Comparator<E>) Ordering.natural();
188   }
189 
190   /**
191    * Returns a sorted map containing the mappings in {@code unfiltered} whose
192    * keys satisfy a predicate. The returned map is a live view of {@code
193    * unfiltered}; changes to one affect the other.
194    *
195    * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
196    * values()} views have iterators that don't support {@code remove()}, but all
197    * other methods are supported by the map and its views. When given a key that
198    * doesn't satisfy the predicate, the map's {@code put()} and {@code putAll()}
199    * methods throw an {@link IllegalArgumentException}.
200    *
201    * <p>When methods such as {@code removeAll()} and {@code clear()} are called
202    * on the filtered map or its views, only mappings whose keys satisfy the
203    * filter will be removed from the underlying map.
204    *
205    * <p>The returned map isn't threadsafe or serializable, even if {@code
206    * unfiltered} is.
207    *
208    * <p>Many of the filtered map's methods, such as {@code size()},
209    * iterate across every key/value mapping in the underlying map and determine
210    * which satisfy the filter. When a live view is <i>not</i> needed, it may be
211    * faster to copy the filtered map and use the copy.
212    *
213    * <p><b>Warning:</b> {@code keyPredicate} must be <i>consistent with
214    * equals</i>, as documented at {@link Predicate#apply}. Do not provide a
215    * predicate such as {@code Predicates.instanceOf(ArrayList.class)}, which is
216    * inconsistent with equals.
217    */
218   @GwtIncompatible("untested")
filterKeys( SortedMap<K, V> unfiltered, final Predicate<? super K> keyPredicate)219   public static <K, V> SortedMap<K, V> filterKeys(
220       SortedMap<K, V> unfiltered, final Predicate<? super K> keyPredicate) {
221     // TODO: Return a subclass of Maps.FilteredKeyMap for slightly better
222     // performance.
223     checkNotNull(keyPredicate);
224     Predicate<Entry<K, V>> entryPredicate = new Predicate<Entry<K, V>>() {
225       @Override
226       public boolean apply(Entry<K, V> input) {
227         return keyPredicate.apply(input.getKey());
228       }
229     };
230     return filterEntries(unfiltered, entryPredicate);
231   }
232 
233   /**
234    * Returns a sorted map containing the mappings in {@code unfiltered} whose
235    * values satisfy a predicate. The returned map is a live view of {@code
236    * unfiltered}; changes to one affect the other.
237    *
238    * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
239    * values()} views have iterators that don't support {@code remove()}, but all
240    * other methods are supported by the map and its views. When given a value
241    * that doesn't satisfy the predicate, the map's {@code put()}, {@code
242    * putAll()}, and {@link Entry#setValue} methods throw an {@link
243    * IllegalArgumentException}.
244    *
245    * <p>When methods such as {@code removeAll()} and {@code clear()} are called
246    * on the filtered map or its views, only mappings whose values satisfy the
247    * filter will be removed from the underlying map.
248    *
249    * <p>The returned map isn't threadsafe or serializable, even if {@code
250    * unfiltered} is.
251    *
252    * <p>Many of the filtered map's methods, such as {@code size()},
253    * iterate across every key/value mapping in the underlying map and determine
254    * which satisfy the filter. When a live view is <i>not</i> needed, it may be
255    * faster to copy the filtered map and use the copy.
256    *
257    * <p><b>Warning:</b> {@code valuePredicate} must be <i>consistent with
258    * equals</i>, as documented at {@link Predicate#apply}. Do not provide a
259    * predicate such as {@code Predicates.instanceOf(ArrayList.class)}, which is
260    * inconsistent with equals.
261    */
262   @GwtIncompatible("untested")
filterValues( SortedMap<K, V> unfiltered, final Predicate<? super V> valuePredicate)263   public static <K, V> SortedMap<K, V> filterValues(
264       SortedMap<K, V> unfiltered, final Predicate<? super V> valuePredicate) {
265     checkNotNull(valuePredicate);
266     Predicate<Entry<K, V>> entryPredicate =
267         new Predicate<Entry<K, V>>() {
268           @Override
269           public boolean apply(Entry<K, V> input) {
270             return valuePredicate.apply(input.getValue());
271           }
272         };
273     return filterEntries(unfiltered, entryPredicate);
274   }
275 
276   /**
277    * Returns a sorted map containing the mappings in {@code unfiltered} that
278    * satisfy a predicate. The returned map is a live view of {@code unfiltered};
279    * changes to one affect the other.
280    *
281    * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
282    * values()} views have iterators that don't support {@code remove()}, but all
283    * other methods are supported by the map and its views. When given a
284    * key/value pair that doesn't satisfy the predicate, the map's {@code put()}
285    * and {@code putAll()} methods throw an {@link IllegalArgumentException}.
286    * Similarly, the map's entries have a {@link Entry#setValue} method that
287    * throws an {@link IllegalArgumentException} when the existing key and the
288    * provided value don't satisfy the predicate.
289    *
290    * <p>When methods such as {@code removeAll()} and {@code clear()} are called
291    * on the filtered map or its views, only mappings that satisfy the filter
292    * will be removed from the underlying map.
293    *
294    * <p>The returned map isn't threadsafe or serializable, even if {@code
295    * unfiltered} is.
296    *
297    * <p>Many of the filtered map's methods, such as {@code size()},
298    * iterate across every key/value mapping in the underlying map and determine
299    * which satisfy the filter. When a live view is <i>not</i> needed, it may be
300    * faster to copy the filtered map and use the copy.
301    *
302    * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with
303    * equals</i>, as documented at {@link Predicate#apply}.
304    */
305   @GwtIncompatible("untested")
filterEntries( SortedMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate)306   public static <K, V> SortedMap<K, V> filterEntries(
307       SortedMap<K, V> unfiltered,
308       Predicate<? super Entry<K, V>> entryPredicate) {
309     checkNotNull(entryPredicate);
310     return (unfiltered instanceof FilteredSortedMap)
311         ? filterFiltered((FilteredSortedMap<K, V>) unfiltered, entryPredicate)
312         : new FilteredSortedMap<K, V>(checkNotNull(unfiltered), entryPredicate);
313   }
314 
315   /**
316    * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when
317    * filtering a filtered sorted map.
318    */
filterFiltered( FilteredSortedMap<K, V> map, Predicate<? super Entry<K, V>> entryPredicate)319   private static <K, V> SortedMap<K, V> filterFiltered(
320       FilteredSortedMap<K, V> map,
321       Predicate<? super Entry<K, V>> entryPredicate) {
322     Predicate<Entry<K, V>> predicate
323         = Predicates.and(map.predicate, entryPredicate);
324     return new FilteredSortedMap<K, V>(map.sortedMap(), predicate);
325   }
326 
327   private static class FilteredSortedMap<K, V>
328       extends Maps.FilteredEntryMap<K, V> implements SortedMap<K, V> {
329 
FilteredSortedMap(SortedMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate)330     FilteredSortedMap(SortedMap<K, V> unfiltered,
331         Predicate<? super Entry<K, V>> entryPredicate) {
332       super(unfiltered, entryPredicate);
333     }
334 
sortedMap()335     SortedMap<K, V> sortedMap() {
336       return (SortedMap<K, V>) unfiltered;
337     }
338 
comparator()339     @Override public Comparator<? super K> comparator() {
340       return sortedMap().comparator();
341     }
342 
firstKey()343     @Override public K firstKey() {
344       // correctly throws NoSuchElementException when filtered map is empty.
345       return keySet().iterator().next();
346     }
347 
lastKey()348     @Override public K lastKey() {
349       SortedMap<K, V> headMap = sortedMap();
350       while (true) {
351         // correctly throws NoSuchElementException when filtered map is empty.
352         K key = headMap.lastKey();
353         if (apply(key, unfiltered.get(key))) {
354           return key;
355         }
356         headMap = sortedMap().headMap(key);
357       }
358     }
359 
headMap(K toKey)360     @Override public SortedMap<K, V> headMap(K toKey) {
361       return new FilteredSortedMap<K, V>(sortedMap().headMap(toKey), predicate);
362     }
363 
subMap(K fromKey, K toKey)364     @Override public SortedMap<K, V> subMap(K fromKey, K toKey) {
365       return new FilteredSortedMap<K, V>(
366           sortedMap().subMap(fromKey, toKey), predicate);
367     }
368 
tailMap(K fromKey)369     @Override public SortedMap<K, V> tailMap(K fromKey) {
370       return new FilteredSortedMap<K, V>(
371           sortedMap().tailMap(fromKey), predicate);
372     }
373   }
374 }
375