001 /* 002 * Copyright (C) 2010 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.checkNotNull; 020 021 import java.util.Comparator; 022 import java.util.Map; 023 import java.util.Map.Entry; 024 import java.util.SortedMap; 025 026 import javax.annotation.Nullable; 027 028 import com.google.common.annotations.Beta; 029 import com.google.common.annotations.GwtCompatible; 030 import com.google.common.annotations.GwtIncompatible; 031 import com.google.common.base.Function; 032 import com.google.common.base.Predicate; 033 import com.google.common.base.Predicates; 034 import com.google.common.collect.Maps.EntryTransformer; 035 036 /** 037 * Static utility methods pertaining to {@link SortedMap} instances. 038 * 039 * @author Louis Wasserman 040 * @since 8.0 041 * @deprecated Use the identical methods in {@link Maps}. This class is 042 * scheduled for deletion from Guava in Guava release 12.0. 043 */ 044 @Beta 045 @Deprecated 046 @GwtCompatible 047 public final class SortedMaps { 048 private SortedMaps() {} 049 050 /** 051 * Returns a view of a sorted map where each value is transformed by a 052 * function. All other properties of the map, such as iteration order, are 053 * left intact. For example, the code: <pre> {@code 054 * 055 * SortedMap<String, Integer> map = ImmutableSortedMap.of("a", 4, "b", 9); 056 * Function<Integer, Double> sqrt = 057 * new Function<Integer, Double>() { 058 * public Double apply(Integer in) { 059 * return Math.sqrt((int) in); 060 * } 061 * }; 062 * SortedMap<String, Double> transformed = 063 * Maps.transformSortedValues(map, sqrt); 064 * System.out.println(transformed);}</pre> 065 * 066 * ... prints {@code {a=2.0, b=3.0}}. 067 * 068 * <p>Changes in the underlying map are reflected in this view. Conversely, 069 * this view supports removal operations, and these are reflected in the 070 * underlying map. 071 * 072 * <p>It's acceptable for the underlying map to contain null keys, and even 073 * null values provided that the function is capable of accepting null input. 074 * The transformed map might contain null values, if the function sometimes 075 * gives a null result. 076 * 077 * <p>The returned map is not thread-safe or serializable, even if the 078 * underlying map is. 079 * 080 * <p>The function is applied lazily, invoked when needed. This is necessary 081 * for the returned map to be a view, but it means that the function will be 082 * applied many times for bulk operations like {@link Map#containsValue} and 083 * {@code Map.toString()}. For this to perform well, {@code function} should 084 * be fast. To avoid lazy evaluation when the returned map doesn't need to be 085 * a view, copy the returned map into a new map of your choosing. 086 * 087 * @deprecated Use {@link Maps#transformValues(SortedMap, Function)} 088 */ 089 @Deprecated public static <K, V1, V2> SortedMap<K, V2> transformValues( 090 SortedMap<K, V1> fromMap, final Function<? super V1, V2> function) { 091 return Maps.transformValues(fromMap, function); 092 } 093 094 /** 095 * Returns a view of a sorted map whose values are derived from the original 096 * sorted map's entries. In contrast to {@link #transformValues}, this 097 * method's entry-transformation logic may depend on the key as well as the 098 * value. 099 * 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 */ 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 */ 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") 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") 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") 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") 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 */ 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 330 FilteredSortedMap(SortedMap<K, V> unfiltered, 331 Predicate<? super Entry<K, V>> entryPredicate) { 332 super(unfiltered, entryPredicate); 333 } 334 335 SortedMap<K, V> sortedMap() { 336 return (SortedMap<K, V>) unfiltered; 337 } 338 339 @Override public Comparator<? super K> comparator() { 340 return sortedMap().comparator(); 341 } 342 343 @Override public K firstKey() { 344 // correctly throws NoSuchElementException when filtered map is empty. 345 return keySet().iterator().next(); 346 } 347 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 360 @Override public SortedMap<K, V> headMap(K toKey) { 361 return new FilteredSortedMap<K, V>(sortedMap().headMap(toKey), predicate); 362 } 363 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 369 @Override public SortedMap<K, V> tailMap(K fromKey) { 370 return new FilteredSortedMap<K, V>( 371 sortedMap().tailMap(fromKey), predicate); 372 } 373 } 374 }