aboutsummaryrefslogtreecommitdiffstats
path: root/guava/src/com/google/common/collect
diff options
context:
space:
mode:
Diffstat (limited to 'guava/src/com/google/common/collect')
-rw-r--r--guava/src/com/google/common/collect/AbstractBiMap.java76
-rw-r--r--guava/src/com/google/common/collect/AbstractLinkedIterator.java (renamed from guava/src/com/google/common/collect/AbstractSequentialIterator.java)19
-rw-r--r--guava/src/com/google/common/collect/AbstractListMultimap.java9
-rw-r--r--guava/src/com/google/common/collect/AbstractMapBasedMultimap.java1567
-rw-r--r--guava/src/com/google/common/collect/AbstractMapBasedMultiset.java116
-rw-r--r--guava/src/com/google/common/collect/AbstractMultimap.java1318
-rw-r--r--guava/src/com/google/common/collect/AbstractMultiset.java18
-rw-r--r--guava/src/com/google/common/collect/AbstractNavigableMap.java198
-rw-r--r--guava/src/com/google/common/collect/AbstractRangeSet.java123
-rw-r--r--guava/src/com/google/common/collect/AbstractSetMultimap.java10
-rw-r--r--guava/src/com/google/common/collect/AbstractSortedKeySortedSetMultimap.java56
-rw-r--r--guava/src/com/google/common/collect/AbstractSortedMultiset.java38
-rw-r--r--guava/src/com/google/common/collect/AbstractSortedSetMultimap.java19
-rw-r--r--guava/src/com/google/common/collect/AllEqualOrdering.java66
-rw-r--r--guava/src/com/google/common/collect/ArrayListMultimap.java6
-rw-r--r--guava/src/com/google/common/collect/ArrayTable.java382
-rw-r--r--guava/src/com/google/common/collect/AsynchronousComputationException.java37
-rw-r--r--guava/src/com/google/common/collect/BiMap.java4
-rw-r--r--guava/src/com/google/common/collect/BoundType.java19
-rw-r--r--guava/src/com/google/common/collect/BstAggregate.java41
-rw-r--r--guava/src/com/google/common/collect/BstBalancePolicy.java45
-rw-r--r--guava/src/com/google/common/collect/BstCountBasedBalancePolicies.java212
-rw-r--r--guava/src/com/google/common/collect/BstInOrderPath.java126
-rw-r--r--guava/src/com/google/common/collect/BstModificationResult.java74
-rw-r--r--guava/src/com/google/common/collect/BstModifier.java49
-rw-r--r--guava/src/com/google/common/collect/BstMutationResult.java156
-rw-r--r--guava/src/com/google/common/collect/BstMutationRule.java77
-rw-r--r--guava/src/com/google/common/collect/BstNode.java125
-rw-r--r--guava/src/com/google/common/collect/BstNodeFactory.java46
-rw-r--r--guava/src/com/google/common/collect/BstOperations.java228
-rw-r--r--guava/src/com/google/common/collect/BstPath.java74
-rw-r--r--guava/src/com/google/common/collect/BstPathFactory.java38
-rw-r--r--guava/src/com/google/common/collect/BstRangeOps.java175
-rw-r--r--guava/src/com/google/common/collect/BstSide.java40
-rw-r--r--guava/src/com/google/common/collect/CartesianList.java164
-rw-r--r--guava/src/com/google/common/collect/ClassToInstanceMap.java7
-rw-r--r--guava/src/com/google/common/collect/Collections2.java389
-rw-r--r--guava/src/com/google/common/collect/ComparatorOrdering.java12
-rw-r--r--guava/src/com/google/common/collect/ComparisonChain.java44
-rw-r--r--guava/src/com/google/common/collect/CompoundOrdering.java13
-rw-r--r--guava/src/com/google/common/collect/ComputationException.java4
-rw-r--r--guava/src/com/google/common/collect/ComputingConcurrentHashMap.java9
-rw-r--r--guava/src/com/google/common/collect/ConcurrentHashMultiset.java85
-rw-r--r--guava/src/com/google/common/collect/ContiguousSet.java72
-rw-r--r--guava/src/com/google/common/collect/Count.java4
-rw-r--r--guava/src/com/google/common/collect/Cut.java12
-rw-r--r--guava/src/com/google/common/collect/DescendingImmutableSortedMultiset.java49
-rw-r--r--guava/src/com/google/common/collect/DescendingImmutableSortedSet.java114
-rw-r--r--guava/src/com/google/common/collect/DescendingMultiset.java140
-rw-r--r--guava/src/com/google/common/collect/DiscreteDomain.java155
-rw-r--r--guava/src/com/google/common/collect/DiscreteDomains.java125
-rw-r--r--guava/src/com/google/common/collect/EmptyContiguousSet.java14
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableBiMap.java77
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableList.java52
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableMap.java95
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableMultiset.java67
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableSet.java22
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableSortedMap.java107
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableSortedMultiset.java73
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableSortedSet.java32
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableTable.java6
-rw-r--r--guava/src/com/google/common/collect/EnumBiMap.java15
-rw-r--r--guava/src/com/google/common/collect/EnumHashBiMap.java13
-rw-r--r--guava/src/com/google/common/collect/EnumMultiset.java17
-rw-r--r--guava/src/com/google/common/collect/FilteredEntryMultimap.java406
-rw-r--r--guava/src/com/google/common/collect/FilteredKeyMultimap.java228
-rw-r--r--guava/src/com/google/common/collect/FilteredMultimap.java40
-rw-r--r--guava/src/com/google/common/collect/FluentIterable.java531
-rw-r--r--guava/src/com/google/common/collect/ForwardingBlockingDeque.java123
-rw-r--r--guava/src/com/google/common/collect/ForwardingCollection.java29
-rw-r--r--guava/src/com/google/common/collect/ForwardingDeque.java129
-rw-r--r--guava/src/com/google/common/collect/ForwardingImmutableCollection.java30
-rw-r--r--guava/src/com/google/common/collect/ForwardingImmutableList.java29
-rw-r--r--guava/src/com/google/common/collect/ForwardingImmutableMap.java29
-rw-r--r--guava/src/com/google/common/collect/ForwardingImmutableSet.java29
-rw-r--r--guava/src/com/google/common/collect/ForwardingList.java17
-rw-r--r--guava/src/com/google/common/collect/ForwardingMap.java29
-rw-r--r--guava/src/com/google/common/collect/ForwardingMapEntry.java4
-rw-r--r--guava/src/com/google/common/collect/ForwardingMultiset.java34
-rw-r--r--guava/src/com/google/common/collect/ForwardingNavigableMap.java397
-rw-r--r--guava/src/com/google/common/collect/ForwardingNavigableSet.java238
-rw-r--r--guava/src/com/google/common/collect/ForwardingQueue.java7
-rw-r--r--guava/src/com/google/common/collect/ForwardingSet.java21
-rw-r--r--guava/src/com/google/common/collect/ForwardingTable.java2
-rw-r--r--guava/src/com/google/common/collect/GeneralRange.java135
-rw-r--r--guava/src/com/google/common/collect/GenericMapMaker.java30
-rw-r--r--guava/src/com/google/common/collect/HashBasedTable.java6
-rw-r--r--guava/src/com/google/common/collect/HashBiMap.java636
-rw-r--r--guava/src/com/google/common/collect/HashMultimap.java2
-rw-r--r--guava/src/com/google/common/collect/Hashing.java39
-rw-r--r--guava/src/com/google/common/collect/ImmutableAsList.java39
-rw-r--r--guava/src/com/google/common/collect/ImmutableBiMap.java130
-rw-r--r--guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java9
-rw-r--r--guava/src/com/google/common/collect/ImmutableCollection.java35
-rw-r--r--guava/src/com/google/common/collect/ImmutableEnumMap.java151
-rw-r--r--guava/src/com/google/common/collect/ImmutableEnumSet.java13
-rw-r--r--guava/src/com/google/common/collect/ImmutableList.java204
-rw-r--r--guava/src/com/google/common/collect/ImmutableListMultimap.java26
-rw-r--r--guava/src/com/google/common/collect/ImmutableMap.java158
-rw-r--r--guava/src/com/google/common/collect/ImmutableMapEntrySet.java76
-rw-r--r--guava/src/com/google/common/collect/ImmutableMapKeySet.java95
-rw-r--r--guava/src/com/google/common/collect/ImmutableMapValues.java91
-rw-r--r--guava/src/com/google/common/collect/ImmutableMultimap.java279
-rw-r--r--guava/src/com/google/common/collect/ImmutableMultiset.java92
-rw-r--r--guava/src/com/google/common/collect/ImmutableRangeMap.java299
-rw-r--r--guava/src/com/google/common/collect/ImmutableRangeSet.java608
-rw-r--r--guava/src/com/google/common/collect/ImmutableSet.java260
-rw-r--r--guava/src/com/google/common/collect/ImmutableSetMultimap.java85
-rw-r--r--guava/src/com/google/common/collect/ImmutableSortedAsList.java97
-rw-r--r--guava/src/com/google/common/collect/ImmutableSortedMap.java480
-rw-r--r--guava/src/com/google/common/collect/ImmutableSortedMultiset.java162
-rw-r--r--guava/src/com/google/common/collect/ImmutableSortedSet.java261
-rw-r--r--guava/src/com/google/common/collect/ImmutableTable.java36
-rw-r--r--guava/src/com/google/common/collect/Interners.java40
-rw-r--r--guava/src/com/google/common/collect/Iterables.java149
-rw-r--r--guava/src/com/google/common/collect/Iterators.java182
-rw-r--r--guava/src/com/google/common/collect/LinkedHashMultimap.java584
-rw-r--r--guava/src/com/google/common/collect/LinkedHashMultiset.java4
-rw-r--r--guava/src/com/google/common/collect/LinkedListMultimap.java456
-rw-r--r--guava/src/com/google/common/collect/ListMultimap.java7
-rw-r--r--guava/src/com/google/common/collect/Lists.java253
-rw-r--r--guava/src/com/google/common/collect/MapConstraints.java3
-rw-r--r--guava/src/com/google/common/collect/MapMaker.java147
-rw-r--r--guava/src/com/google/common/collect/MapMakerInternalMap.java171
-rw-r--r--guava/src/com/google/common/collect/Maps.java2126
-rw-r--r--guava/src/com/google/common/collect/MinMaxPriorityQueue.java7
-rw-r--r--guava/src/com/google/common/collect/Multimap.java157
-rw-r--r--guava/src/com/google/common/collect/Multimaps.java888
-rw-r--r--guava/src/com/google/common/collect/Multiset.java18
-rw-r--r--guava/src/com/google/common/collect/Multisets.java562
-rw-r--r--guava/src/com/google/common/collect/MutableClassToInstanceMap.java4
-rw-r--r--guava/src/com/google/common/collect/ObjectArrays.java23
-rw-r--r--guava/src/com/google/common/collect/Ordering.java718
-rw-r--r--guava/src/com/google/common/collect/PeekingIterator.java4
-rw-r--r--guava/src/com/google/common/collect/Platform.java67
-rw-r--r--guava/src/com/google/common/collect/Queues.java127
-rw-r--r--guava/src/com/google/common/collect/Range.java706
-rw-r--r--guava/src/com/google/common/collect/RangeMap.java134
-rw-r--r--guava/src/com/google/common/collect/RangeSet.java206
-rw-r--r--guava/src/com/google/common/collect/Ranges.java77
-rw-r--r--guava/src/com/google/common/collect/RegularContiguousSet.java69
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableAsList.java91
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableBiMap.java282
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableList.java68
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableMap.java138
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableMultiset.java57
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableSortedMap.java130
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableSortedMultiset.java205
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableSortedSet.java104
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableTable.java564
-rw-r--r--guava/src/com/google/common/collect/SetMultimap.java11
-rw-r--r--guava/src/com/google/common/collect/Sets.java851
-rw-r--r--guava/src/com/google/common/collect/SingletonImmutableBiMap.java96
-rw-r--r--guava/src/com/google/common/collect/SingletonImmutableList.java45
-rw-r--r--guava/src/com/google/common/collect/SingletonImmutableMap.java162
-rw-r--r--guava/src/com/google/common/collect/SingletonImmutableTable.java6
-rw-r--r--guava/src/com/google/common/collect/SortedIterables.java151
-rw-r--r--guava/src/com/google/common/collect/SortedLists.java12
-rw-r--r--guava/src/com/google/common/collect/SortedMapDifference.java2
-rw-r--r--guava/src/com/google/common/collect/SortedMaps.java374
-rw-r--r--guava/src/com/google/common/collect/SortedMultiset.java16
-rw-r--r--guava/src/com/google/common/collect/SortedMultisetBridge.java31
-rw-r--r--guava/src/com/google/common/collect/SortedMultisets.java183
-rw-r--r--guava/src/com/google/common/collect/SortedSetMultimap.java7
-rw-r--r--guava/src/com/google/common/collect/StandardTable.java132
-rw-r--r--guava/src/com/google/common/collect/Synchronized.java413
-rw-r--r--guava/src/com/google/common/collect/Table.java7
-rw-r--r--guava/src/com/google/common/collect/Tables.java8
-rw-r--r--guava/src/com/google/common/collect/TransformedImmutableList.java128
-rw-r--r--guava/src/com/google/common/collect/TransformedIterator.java55
-rw-r--r--guava/src/com/google/common/collect/TransformedListIterator.java71
-rw-r--r--guava/src/com/google/common/collect/TreeBasedTable.java4
-rw-r--r--guava/src/com/google/common/collect/TreeMultimap.java85
-rw-r--r--guava/src/com/google/common/collect/TreeMultiset.java1091
-rw-r--r--guava/src/com/google/common/collect/TreeRangeMap.java618
-rw-r--r--guava/src/com/google/common/collect/TreeRangeSet.java851
-rw-r--r--guava/src/com/google/common/collect/UnmodifiableIterator.java4
-rw-r--r--guava/src/com/google/common/collect/UnmodifiableListIterator.java6
-rw-r--r--guava/src/com/google/common/collect/UnmodifiableSortedMultiset.java114
-rw-r--r--guava/src/com/google/common/collect/UsingToStringOrdering.java5
-rw-r--r--guava/src/com/google/common/collect/WellBehavedMap.java67
-rw-r--r--guava/src/com/google/common/collect/package-info.java10
182 files changed, 9881 insertions, 19724 deletions
diff --git a/guava/src/com/google/common/collect/AbstractBiMap.java b/guava/src/com/google/common/collect/AbstractBiMap.java
index 44ab8c7..2a94f88 100644
--- a/guava/src/com/google/common/collect/AbstractBiMap.java
+++ b/guava/src/com/google/common/collect/AbstractBiMap.java
@@ -49,7 +49,7 @@ abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
implements BiMap<K, V>, Serializable {
private transient Map<K, V> delegate;
- transient AbstractBiMap<V, K> inverse;
+ private transient AbstractBiMap<V, K> inverse;
/** Package-private constructor for creating a map-backed bimap. */
AbstractBiMap(Map<K, V> forward, Map<V, K> backward) {
@@ -67,20 +67,6 @@ abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
}
/**
- * Returns its input, or throws an exception if this is not a valid key.
- */
- K checkKey(@Nullable K key) {
- return key;
- }
-
- /**
- * Returns its input, or throws an exception if this is not a valid value.
- */
- V checkValue(@Nullable V value) {
- return value;
- }
-
- /**
* Specifies the delegate maps going in each direction. Called by the
* constructor and by subclasses during deserialization.
*/
@@ -100,24 +86,22 @@ abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
// Query Operations (optimizations)
- @Override public boolean containsValue(@Nullable Object value) {
+ @Override public boolean containsValue(Object value) {
return inverse.containsKey(value);
}
// Modification Operations
- @Override public V put(@Nullable K key, @Nullable V value) {
+ @Override public V put(K key, V value) {
return putInBothMaps(key, value, false);
}
@Override
- public V forcePut(@Nullable K key, @Nullable V value) {
+ public V forcePut(K key, V value) {
return putInBothMaps(key, value, true);
}
private V putInBothMaps(@Nullable K key, @Nullable V value, boolean force) {
- checkKey(key);
- checkValue(value);
boolean containedKey = containsKey(key);
if (containedKey && Objects.equal(value, get(key))) {
return value;
@@ -140,7 +124,7 @@ abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
inverse.delegate.put(newValue, key);
}
- @Override public V remove(@Nullable Object key) {
+ @Override public V remove(Object key) {
return containsKey(key) ? removeFromBothMaps(key) : null;
}
@@ -207,7 +191,27 @@ abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
}
@Override public Iterator<K> iterator() {
- return Maps.keyIterator(entrySet().iterator());
+ final Iterator<Entry<K, V>> iterator = delegate.entrySet().iterator();
+ return new Iterator<K>() {
+ Entry<K, V> entry;
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+ @Override
+ public K next() {
+ entry = iterator.next();
+ return entry.getKey();
+ }
+ @Override
+ public void remove() {
+ checkState(entry != null);
+ V value = entry.getValue();
+ iterator.remove();
+ removeFromInverseMap(value);
+ }
+ };
}
}
@@ -230,7 +234,23 @@ abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
}
@Override public Iterator<V> iterator() {
- return Maps.valueIterator(entrySet().iterator());
+ final Iterator<V> iterator = delegate.values().iterator();
+ return new Iterator<V>() {
+ V valueToRemove;
+
+ @Override public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override public V next() {
+ return valueToRemove = iterator.next();
+ }
+
+ @Override public void remove() {
+ iterator.remove();
+ removeFromInverseMap(valueToRemove);
+ }
+ };
}
@Override public Object[] toArray() {
@@ -363,16 +383,6 @@ abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
* instances have inverse() methods that return the other.
*/
- @Override
- K checkKey(K key) {
- return inverse.checkValue(key);
- }
-
- @Override
- V checkValue(V value) {
- return inverse.checkKey(value);
- }
-
/**
* @serialData the forward bimap
*/
diff --git a/guava/src/com/google/common/collect/AbstractSequentialIterator.java b/guava/src/com/google/common/collect/AbstractLinkedIterator.java
index c6567f5..e796b9b 100644
--- a/guava/src/com/google/common/collect/AbstractSequentialIterator.java
+++ b/guava/src/com/google/common/collect/AbstractLinkedIterator.java
@@ -16,6 +16,7 @@
package com.google.common.collect;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import java.util.NoSuchElementException;
@@ -30,18 +31,18 @@ import javax.annotation.Nullable;
*
* <p>Example: <pre> {@code
*
- * Iterator<Integer> powersOfTwo =
- * new AbstractSequentialIterator<Integer>(1) {
- * protected Integer computeNext(Integer previous) {
- * return (previous == 1 << 30) ? null : previous * 2;
- * }
- * };}</pre>
+ * Iterator<Integer> powersOfTwo = new AbstractLinkedIterator<Integer>(1) {
+ * protected Integer computeNext(Integer previous) {
+ * return (previous == 1 << 30) ? null : previous * 2;
+ * }
+ * };}</pre>
*
* @author Chris Povirk
- * @since 12.0 (in Guava as {@code AbstractLinkedIterator} since 8.0)
+ * @since 8.0
*/
+@Beta
@GwtCompatible
-public abstract class AbstractSequentialIterator<T>
+public abstract class AbstractLinkedIterator<T>
extends UnmodifiableIterator<T> {
private T nextOrNull;
@@ -49,7 +50,7 @@ public abstract class AbstractSequentialIterator<T>
* Creates a new iterator with the given first element, or, if {@code
* firstOrNull} is null, creates a new empty iterator.
*/
- protected AbstractSequentialIterator(@Nullable T firstOrNull) {
+ protected AbstractLinkedIterator(@Nullable T firstOrNull) {
this.nextOrNull = firstOrNull;
}
diff --git a/guava/src/com/google/common/collect/AbstractListMultimap.java b/guava/src/com/google/common/collect/AbstractListMultimap.java
index 3759c93..ad24011 100644
--- a/guava/src/com/google/common/collect/AbstractListMultimap.java
+++ b/guava/src/com/google/common/collect/AbstractListMultimap.java
@@ -26,7 +26,7 @@ import javax.annotation.Nullable;
/**
* Basic implementation of the {@link ListMultimap} interface. It's a wrapper
- * around {@link AbstractMapBasedMultimap} that converts the returned collections into
+ * around {@link AbstractMultimap} that converts the returned collections into
* {@code Lists}. The {@link #createCollection} method must return a {@code
* List}.
*
@@ -35,7 +35,7 @@ import javax.annotation.Nullable;
*/
@GwtCompatible
abstract class AbstractListMultimap<K, V>
- extends AbstractMapBasedMultimap<K, V> implements ListMultimap<K, V> {
+ extends AbstractMultimap<K, V> implements ListMultimap<K, V> {
/**
* Creates a new multimap that uses the provided map.
*
@@ -48,11 +48,6 @@ abstract class AbstractListMultimap<K, V>
@Override abstract List<V> createCollection();
- @Override
- List<V> createUnmodifiableEmptyCollection() {
- return ImmutableList.of();
- }
-
// Following Javadoc copied from ListMultimap.
/**
diff --git a/guava/src/com/google/common/collect/AbstractMapBasedMultimap.java b/guava/src/com/google/common/collect/AbstractMapBasedMultimap.java
deleted file mode 100644
index 0a1edf3..0000000
--- a/guava/src/com/google/common/collect/AbstractMapBasedMultimap.java
+++ /dev/null
@@ -1,1567 +0,0 @@
-/*
- * Copyright (C) 2007 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
-
-import java.io.Serializable;
-import java.util.AbstractCollection;
-import java.util.AbstractMap;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.NavigableMap;
-import java.util.NavigableSet;
-import java.util.RandomAccess;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.SortedSet;
-
-import javax.annotation.Nullable;
-
-/**
- * Basic implementation of the {@link Multimap} interface. This class represents
- * a multimap as a map that associates each key with a collection of values. All
- * methods of {@link Multimap} are supported, including those specified as
- * optional in the interface.
- *
- * <p>To implement a multimap, a subclass must define the method {@link
- * #createCollection()}, which creates an empty collection of values for a key.
- *
- * <p>The multimap constructor takes a map that has a single entry for each
- * distinct key. When you insert a key-value pair with a key that isn't already
- * in the multimap, {@code AbstractMapBasedMultimap} calls {@link #createCollection()}
- * to create the collection of values for that key. The subclass should not call
- * {@link #createCollection()} directly, and a new instance should be created
- * every time the method is called.
- *
- * <p>For example, the subclass could pass a {@link java.util.TreeMap} during
- * construction, and {@link #createCollection()} could return a {@link
- * java.util.TreeSet}, in which case the multimap's iterators would propagate
- * through the keys and values in sorted order.
- *
- * <p>Keys and values may be null, as long as the underlying collection classes
- * support null elements.
- *
- * <p>The collections created by {@link #createCollection()} may or may not
- * allow duplicates. If the collection, such as a {@link Set}, does not support
- * duplicates, an added key-value pair will replace an existing pair with the
- * same key and value, if such a pair is present. With collections like {@link
- * List} that allow duplicates, the collection will keep the existing key-value
- * pairs while adding a new pair.
- *
- * <p>This class is not threadsafe when any concurrent operations update the
- * multimap, even if the underlying map and {@link #createCollection()} method
- * return threadsafe classes. Concurrent read operations will work correctly. To
- * allow concurrent update operations, wrap your multimap with a call to {@link
- * Multimaps#synchronizedMultimap}.
- *
- * <p>For serialization to work, the subclass must specify explicit
- * {@code readObject} and {@code writeObject} methods.
- *
- * @author Jared Levy
- * @author Louis Wasserman
- */
-@GwtCompatible(emulated = true)
-abstract class AbstractMapBasedMultimap<K, V> extends AbstractMultimap<K, V>
- implements Serializable {
- /*
- * Here's an outline of the overall design.
- *
- * The map variable contains the collection of values associated with each
- * key. When a key-value pair is added to a multimap that didn't previously
- * contain any values for that key, a new collection generated by
- * createCollection is added to the map. That same collection instance
- * remains in the map as long as the multimap has any values for the key. If
- * all values for the key are removed, the key and collection are removed
- * from the map.
- *
- * The get method returns a WrappedCollection, which decorates the collection
- * in the map (if the key is present) or an empty collection (if the key is
- * not present). When the collection delegate in the WrappedCollection is
- * empty, the multimap may contain subsequently added values for that key. To
- * handle that situation, the WrappedCollection checks whether map contains
- * an entry for the provided key, and if so replaces the delegate.
- */
-
- private transient Map<K, Collection<V>> map;
- private transient int totalSize;
-
- /**
- * Creates a new multimap that uses the provided map.
- *
- * @param map place to store the mapping from each key to its corresponding
- * values
- * @throws IllegalArgumentException if {@code map} is not empty
- */
- protected AbstractMapBasedMultimap(Map<K, Collection<V>> map) {
- checkArgument(map.isEmpty());
- this.map = map;
- }
-
- /** Used during deserialization only. */
- final void setMap(Map<K, Collection<V>> map) {
- this.map = map;
- totalSize = 0;
- for (Collection<V> values : map.values()) {
- checkArgument(!values.isEmpty());
- totalSize += values.size();
- }
- }
-
- /**
- * Creates an unmodifiable, empty collection of values.
- *
- * <p>This is used in {@link #removeAll} on an empty key.
- */
- Collection<V> createUnmodifiableEmptyCollection() {
- return unmodifiableCollectionSubclass(createCollection());
- }
-
- /**
- * Creates the collection of values for a single key.
- *
- * <p>Collections with weak, soft, or phantom references are not supported.
- * Each call to {@code createCollection} should create a new instance.
- *
- * <p>The returned collection class determines whether duplicate key-value
- * pairs are allowed.
- *
- * @return an empty collection of values
- */
- abstract Collection<V> createCollection();
-
- /**
- * Creates the collection of values for an explicitly provided key. By
- * default, it simply calls {@link #createCollection()}, which is the correct
- * behavior for most implementations. The {@link LinkedHashMultimap} class
- * overrides it.
- *
- * @param key key to associate with values in the collection
- * @return an empty collection of values
- */
- Collection<V> createCollection(@Nullable K key) {
- return createCollection();
- }
-
- Map<K, Collection<V>> backingMap() {
- return map;
- }
-
- // Query Operations
-
- @Override
- public int size() {
- return totalSize;
- }
-
- @Override
- public boolean containsKey(@Nullable Object key) {
- return map.containsKey(key);
- }
-
- // Modification Operations
-
- @Override
- public boolean put(@Nullable K key, @Nullable V value) {
- Collection<V> collection = map.get(key);
- if (collection == null) {
- collection = createCollection(key);
- if (collection.add(value)) {
- totalSize++;
- map.put(key, collection);
- return true;
- } else {
- throw new AssertionError("New Collection violated the Collection spec");
- }
- } else if (collection.add(value)) {
- totalSize++;
- return true;
- } else {
- return false;
- }
- }
-
- private Collection<V> getOrCreateCollection(@Nullable K key) {
- Collection<V> collection = map.get(key);
- if (collection == null) {
- collection = createCollection(key);
- map.put(key, collection);
- }
- return collection;
- }
-
- // Bulk Operations
-
- /**
- * {@inheritDoc}
- *
- * <p>The returned collection is immutable.
- */
- @Override
- public Collection<V> replaceValues(@Nullable K key, Iterable<? extends V> values) {
- Iterator<? extends V> iterator = values.iterator();
- if (!iterator.hasNext()) {
- return removeAll(key);
- }
-
- // TODO(user): investigate atomic failure?
- Collection<V> collection = getOrCreateCollection(key);
- Collection<V> oldValues = createCollection();
- oldValues.addAll(collection);
-
- totalSize -= collection.size();
- collection.clear();
-
- while (iterator.hasNext()) {
- if (collection.add(iterator.next())) {
- totalSize++;
- }
- }
-
- return unmodifiableCollectionSubclass(oldValues);
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>The returned collection is immutable.
- */
- @Override
- public Collection<V> removeAll(@Nullable Object key) {
- Collection<V> collection = map.remove(key);
-
- if (collection == null) {
- return createUnmodifiableEmptyCollection();
- }
-
- Collection<V> output = createCollection();
- output.addAll(collection);
- totalSize -= collection.size();
- collection.clear();
-
- return unmodifiableCollectionSubclass(output);
- }
-
- Collection<V> unmodifiableCollectionSubclass(Collection<V> collection) {
- // We don't deal with NavigableSet here yet for GWT reasons -- instead,
- // non-GWT TreeMultimap explicitly overrides this and uses NavigableSet.
- if (collection instanceof SortedSet) {
- return Collections.unmodifiableSortedSet((SortedSet<V>) collection);
- } else if (collection instanceof Set) {
- return Collections.unmodifiableSet((Set<V>) collection);
- } else if (collection instanceof List) {
- return Collections.unmodifiableList((List<V>) collection);
- } else {
- return Collections.unmodifiableCollection(collection);
- }
- }
-
- @Override
- public void clear() {
- // Clear each collection, to make previously returned collections empty.
- for (Collection<V> collection : map.values()) {
- collection.clear();
- }
- map.clear();
- totalSize = 0;
- }
-
- // Views
-
- /**
- * {@inheritDoc}
- *
- * <p>The returned collection is not serializable.
- */
- @Override
- public Collection<V> get(@Nullable K key) {
- Collection<V> collection = map.get(key);
- if (collection == null) {
- collection = createCollection(key);
- }
- return wrapCollection(key, collection);
- }
-
- /**
- * Generates a decorated collection that remains consistent with the values in
- * the multimap for the provided key. Changes to the multimap may alter the
- * returned collection, and vice versa.
- */
- Collection<V> wrapCollection(@Nullable K key, Collection<V> collection) {
- // We don't deal with NavigableSet here yet for GWT reasons -- instead,
- // non-GWT TreeMultimap explicitly overrides this and uses NavigableSet.
- if (collection instanceof SortedSet) {
- return new WrappedSortedSet(key, (SortedSet<V>) collection, null);
- } else if (collection instanceof Set) {
- return new WrappedSet(key, (Set<V>) collection);
- } else if (collection instanceof List) {
- return wrapList(key, (List<V>) collection, null);
- } else {
- return new WrappedCollection(key, collection, null);
- }
- }
-
- private List<V> wrapList(
- @Nullable K key, List<V> list, @Nullable WrappedCollection ancestor) {
- return (list instanceof RandomAccess)
- ? new RandomAccessWrappedList(key, list, ancestor)
- : new WrappedList(key, list, ancestor);
- }
-
- /**
- * Collection decorator that stays in sync with the multimap values for a key.
- * There are two kinds of wrapped collections: full and subcollections. Both
- * have a delegate pointing to the underlying collection class.
- *
- * <p>Full collections, identified by a null ancestor field, contain all
- * multimap values for a given key. Its delegate is a value in {@link
- * AbstractMapBasedMultimap#map} whenever the delegate is non-empty. The {@code
- * refreshIfEmpty}, {@code removeIfEmpty}, and {@code addToMap} methods ensure
- * that the {@code WrappedCollection} and map remain consistent.
- *
- * <p>A subcollection, such as a sublist, contains some of the values for a
- * given key. Its ancestor field points to the full wrapped collection with
- * all values for the key. The subcollection {@code refreshIfEmpty}, {@code
- * removeIfEmpty}, and {@code addToMap} methods call the corresponding methods
- * of the full wrapped collection.
- */
- private class WrappedCollection extends AbstractCollection<V> {
- final K key;
- Collection<V> delegate;
- final WrappedCollection ancestor;
- final Collection<V> ancestorDelegate;
-
- WrappedCollection(@Nullable K key, Collection<V> delegate,
- @Nullable WrappedCollection ancestor) {
- this.key = key;
- this.delegate = delegate;
- this.ancestor = ancestor;
- this.ancestorDelegate
- = (ancestor == null) ? null : ancestor.getDelegate();
- }
-
- /**
- * If the delegate collection is empty, but the multimap has values for the
- * key, replace the delegate with the new collection for the key.
- *
- * <p>For a subcollection, refresh its ancestor and validate that the
- * ancestor delegate hasn't changed.
- */
- void refreshIfEmpty() {
- if (ancestor != null) {
- ancestor.refreshIfEmpty();
- if (ancestor.getDelegate() != ancestorDelegate) {
- throw new ConcurrentModificationException();
- }
- } else if (delegate.isEmpty()) {
- Collection<V> newDelegate = map.get(key);
- if (newDelegate != null) {
- delegate = newDelegate;
- }
- }
- }
-
- /**
- * If collection is empty, remove it from {@code AbstractMapBasedMultimap.this.map}.
- * For subcollections, check whether the ancestor collection is empty.
- */
- void removeIfEmpty() {
- if (ancestor != null) {
- ancestor.removeIfEmpty();
- } else if (delegate.isEmpty()) {
- map.remove(key);
- }
- }
-
- K getKey() {
- return key;
- }
-
- /**
- * Add the delegate to the map. Other {@code WrappedCollection} methods
- * should call this method after adding elements to a previously empty
- * collection.
- *
- * <p>Subcollection add the ancestor's delegate instead.
- */
- void addToMap() {
- if (ancestor != null) {
- ancestor.addToMap();
- } else {
- map.put(key, delegate);
- }
- }
-
- @Override public int size() {
- refreshIfEmpty();
- return delegate.size();
- }
-
- @Override public boolean equals(@Nullable Object object) {
- if (object == this) {
- return true;
- }
- refreshIfEmpty();
- return delegate.equals(object);
- }
-
- @Override public int hashCode() {
- refreshIfEmpty();
- return delegate.hashCode();
- }
-
- @Override public String toString() {
- refreshIfEmpty();
- return delegate.toString();
- }
-
- Collection<V> getDelegate() {
- return delegate;
- }
-
- @Override public Iterator<V> iterator() {
- refreshIfEmpty();
- return new WrappedIterator();
- }
-
- /** Collection iterator for {@code WrappedCollection}. */
- class WrappedIterator implements Iterator<V> {
- final Iterator<V> delegateIterator;
- final Collection<V> originalDelegate = delegate;
-
- WrappedIterator() {
- delegateIterator = iteratorOrListIterator(delegate);
- }
-
- WrappedIterator(Iterator<V> delegateIterator) {
- this.delegateIterator = delegateIterator;
- }
-
- /**
- * If the delegate changed since the iterator was created, the iterator is
- * no longer valid.
- */
- void validateIterator() {
- refreshIfEmpty();
- if (delegate != originalDelegate) {
- throw new ConcurrentModificationException();
- }
- }
-
- @Override
- public boolean hasNext() {
- validateIterator();
- return delegateIterator.hasNext();
- }
-
- @Override
- public V next() {
- validateIterator();
- return delegateIterator.next();
- }
-
- @Override
- public void remove() {
- delegateIterator.remove();
- totalSize--;
- removeIfEmpty();
- }
-
- Iterator<V> getDelegateIterator() {
- validateIterator();
- return delegateIterator;
- }
- }
-
- @Override public boolean add(V value) {
- refreshIfEmpty();
- boolean wasEmpty = delegate.isEmpty();
- boolean changed = delegate.add(value);
- if (changed) {
- totalSize++;
- if (wasEmpty) {
- addToMap();
- }
- }
- return changed;
- }
-
- WrappedCollection getAncestor() {
- return ancestor;
- }
-
- // The following methods are provided for better performance.
-
- @Override public boolean addAll(Collection<? extends V> collection) {
- if (collection.isEmpty()) {
- return false;
- }
- int oldSize = size(); // calls refreshIfEmpty
- boolean changed = delegate.addAll(collection);
- if (changed) {
- int newSize = delegate.size();
- totalSize += (newSize - oldSize);
- if (oldSize == 0) {
- addToMap();
- }
- }
- return changed;
- }
-
- @Override public boolean contains(Object o) {
- refreshIfEmpty();
- return delegate.contains(o);
- }
-
- @Override public boolean containsAll(Collection<?> c) {
- refreshIfEmpty();
- return delegate.containsAll(c);
- }
-
- @Override public void clear() {
- int oldSize = size(); // calls refreshIfEmpty
- if (oldSize == 0) {
- return;
- }
- delegate.clear();
- totalSize -= oldSize;
- removeIfEmpty(); // maybe shouldn't be removed if this is a sublist
- }
-
- @Override public boolean remove(Object o) {
- refreshIfEmpty();
- boolean changed = delegate.remove(o);
- if (changed) {
- totalSize--;
- removeIfEmpty();
- }
- return changed;
- }
-
- @Override public boolean removeAll(Collection<?> c) {
- if (c.isEmpty()) {
- return false;
- }
- int oldSize = size(); // calls refreshIfEmpty
- boolean changed = delegate.removeAll(c);
- if (changed) {
- int newSize = delegate.size();
- totalSize += (newSize - oldSize);
- removeIfEmpty();
- }
- return changed;
- }
-
- @Override public boolean retainAll(Collection<?> c) {
- checkNotNull(c);
- int oldSize = size(); // calls refreshIfEmpty
- boolean changed = delegate.retainAll(c);
- if (changed) {
- int newSize = delegate.size();
- totalSize += (newSize - oldSize);
- removeIfEmpty();
- }
- return changed;
- }
- }
-
- private Iterator<V> iteratorOrListIterator(Collection<V> collection) {
- return (collection instanceof List)
- ? ((List<V>) collection).listIterator()
- : collection.iterator();
- }
-
- /** Set decorator that stays in sync with the multimap values for a key. */
- private class WrappedSet extends WrappedCollection implements Set<V> {
- WrappedSet(@Nullable K key, Set<V> delegate) {
- super(key, delegate, null);
- }
-
- @Override
- public boolean removeAll(Collection<?> c) {
- if (c.isEmpty()) {
- return false;
- }
- int oldSize = size(); // calls refreshIfEmpty
-
- // Guava issue 1013: AbstractSet and most JDK set implementations are
- // susceptible to quadratic removeAll performance on lists;
- // use a slightly smarter implementation here
- boolean changed = Sets.removeAllImpl((Set<V>) delegate, c);
- if (changed) {
- int newSize = delegate.size();
- totalSize += (newSize - oldSize);
- removeIfEmpty();
- }
- return changed;
- }
- }
-
- /**
- * SortedSet decorator that stays in sync with the multimap values for a key.
- */
- private class WrappedSortedSet extends WrappedCollection
- implements SortedSet<V> {
- WrappedSortedSet(@Nullable K key, SortedSet<V> delegate,
- @Nullable WrappedCollection ancestor) {
- super(key, delegate, ancestor);
- }
-
- SortedSet<V> getSortedSetDelegate() {
- return (SortedSet<V>) getDelegate();
- }
-
- @Override
- public Comparator<? super V> comparator() {
- return getSortedSetDelegate().comparator();
- }
-
- @Override
- public V first() {
- refreshIfEmpty();
- return getSortedSetDelegate().first();
- }
-
- @Override
- public V last() {
- refreshIfEmpty();
- return getSortedSetDelegate().last();
- }
-
- @Override
- public SortedSet<V> headSet(V toElement) {
- refreshIfEmpty();
- return new WrappedSortedSet(
- getKey(), getSortedSetDelegate().headSet(toElement),
- (getAncestor() == null) ? this : getAncestor());
- }
-
- @Override
- public SortedSet<V> subSet(V fromElement, V toElement) {
- refreshIfEmpty();
- return new WrappedSortedSet(
- getKey(), getSortedSetDelegate().subSet(fromElement, toElement),
- (getAncestor() == null) ? this : getAncestor());
- }
-
- @Override
- public SortedSet<V> tailSet(V fromElement) {
- refreshIfEmpty();
- return new WrappedSortedSet(
- getKey(), getSortedSetDelegate().tailSet(fromElement),
- (getAncestor() == null) ? this : getAncestor());
- }
- }
-
- @GwtIncompatible("NavigableSet")
- class WrappedNavigableSet extends WrappedSortedSet implements NavigableSet<V> {
- WrappedNavigableSet(
- @Nullable K key, NavigableSet<V> delegate, @Nullable WrappedCollection ancestor) {
- super(key, delegate, ancestor);
- }
-
- @Override
- NavigableSet<V> getSortedSetDelegate() {
- return (NavigableSet<V>) super.getSortedSetDelegate();
- }
-
- @Override
- public V lower(V v) {
- return getSortedSetDelegate().lower(v);
- }
-
- @Override
- public V floor(V v) {
- return getSortedSetDelegate().floor(v);
- }
-
- @Override
- public V ceiling(V v) {
- return getSortedSetDelegate().ceiling(v);
- }
-
- @Override
- public V higher(V v) {
- return getSortedSetDelegate().higher(v);
- }
-
- @Override
- public V pollFirst() {
- return Iterators.pollNext(iterator());
- }
-
- @Override
- public V pollLast() {
- return Iterators.pollNext(descendingIterator());
- }
-
- private NavigableSet<V> wrap(NavigableSet<V> wrapped) {
- return new WrappedNavigableSet(key, wrapped,
- (getAncestor() == null) ? this : getAncestor());
- }
-
- @Override
- public NavigableSet<V> descendingSet() {
- return wrap(getSortedSetDelegate().descendingSet());
- }
-
- @Override
- public Iterator<V> descendingIterator() {
- return new WrappedIterator(getSortedSetDelegate().descendingIterator());
- }
-
- @Override
- public NavigableSet<V> subSet(
- V fromElement, boolean fromInclusive, V toElement, boolean toInclusive) {
- return wrap(
- getSortedSetDelegate().subSet(fromElement, fromInclusive, toElement, toInclusive));
- }
-
- @Override
- public NavigableSet<V> headSet(V toElement, boolean inclusive) {
- return wrap(getSortedSetDelegate().headSet(toElement, inclusive));
- }
-
- @Override
- public NavigableSet<V> tailSet(V fromElement, boolean inclusive) {
- return wrap(getSortedSetDelegate().tailSet(fromElement, inclusive));
- }
- }
-
- /** List decorator that stays in sync with the multimap values for a key. */
- private class WrappedList extends WrappedCollection implements List<V> {
- WrappedList(@Nullable K key, List<V> delegate,
- @Nullable WrappedCollection ancestor) {
- super(key, delegate, ancestor);
- }
-
- List<V> getListDelegate() {
- return (List<V>) getDelegate();
- }
-
- @Override
- public boolean addAll(int index, Collection<? extends V> c) {
- if (c.isEmpty()) {
- return false;
- }
- int oldSize = size(); // calls refreshIfEmpty
- boolean changed = getListDelegate().addAll(index, c);
- if (changed) {
- int newSize = getDelegate().size();
- totalSize += (newSize - oldSize);
- if (oldSize == 0) {
- addToMap();
- }
- }
- return changed;
- }
-
- @Override
- public V get(int index) {
- refreshIfEmpty();
- return getListDelegate().get(index);
- }
-
- @Override
- public V set(int index, V element) {
- refreshIfEmpty();
- return getListDelegate().set(index, element);
- }
-
- @Override
- public void add(int index, V element) {
- refreshIfEmpty();
- boolean wasEmpty = getDelegate().isEmpty();
- getListDelegate().add(index, element);
- totalSize++;
- if (wasEmpty) {
- addToMap();
- }
- }
-
- @Override
- public V remove(int index) {
- refreshIfEmpty();
- V value = getListDelegate().remove(index);
- totalSize--;
- removeIfEmpty();
- return value;
- }
-
- @Override
- public int indexOf(Object o) {
- refreshIfEmpty();
- return getListDelegate().indexOf(o);
- }
-
- @Override
- public int lastIndexOf(Object o) {
- refreshIfEmpty();
- return getListDelegate().lastIndexOf(o);
- }
-
- @Override
- public ListIterator<V> listIterator() {
- refreshIfEmpty();
- return new WrappedListIterator();
- }
-
- @Override
- public ListIterator<V> listIterator(int index) {
- refreshIfEmpty();
- return new WrappedListIterator(index);
- }
-
- @Override
- public List<V> subList(int fromIndex, int toIndex) {
- refreshIfEmpty();
- return wrapList(getKey(),
- getListDelegate().subList(fromIndex, toIndex),
- (getAncestor() == null) ? this : getAncestor());
- }
-
- /** ListIterator decorator. */
- private class WrappedListIterator extends WrappedIterator
- implements ListIterator<V> {
- WrappedListIterator() {}
-
- public WrappedListIterator(int index) {
- super(getListDelegate().listIterator(index));
- }
-
- private ListIterator<V> getDelegateListIterator() {
- return (ListIterator<V>) getDelegateIterator();
- }
-
- @Override
- public boolean hasPrevious() {
- return getDelegateListIterator().hasPrevious();
- }
-
- @Override
- public V previous() {
- return getDelegateListIterator().previous();
- }
-
- @Override
- public int nextIndex() {
- return getDelegateListIterator().nextIndex();
- }
-
- @Override
- public int previousIndex() {
- return getDelegateListIterator().previousIndex();
- }
-
- @Override
- public void set(V value) {
- getDelegateListIterator().set(value);
- }
-
- @Override
- public void add(V value) {
- boolean wasEmpty = isEmpty();
- getDelegateListIterator().add(value);
- totalSize++;
- if (wasEmpty) {
- addToMap();
- }
- }
- }
- }
-
- /**
- * List decorator that stays in sync with the multimap values for a key and
- * supports rapid random access.
- */
- private class RandomAccessWrappedList extends WrappedList
- implements RandomAccess {
- RandomAccessWrappedList(@Nullable K key, List<V> delegate,
- @Nullable WrappedCollection ancestor) {
- super(key, delegate, ancestor);
- }
- }
-
- @Override
- Set<K> createKeySet() {
- // TreeMultimap uses NavigableKeySet explicitly, but we don't handle that here for GWT
- // compatibility reasons
- return (map instanceof SortedMap)
- ? new SortedKeySet((SortedMap<K, Collection<V>>) map) : new KeySet(map);
- }
-
- private class KeySet extends Maps.KeySet<K, Collection<V>> {
-
- /**
- * This is usually the same as map, except when someone requests a
- * subcollection of a {@link SortedKeySet}.
- */
- final Map<K, Collection<V>> subMap;
-
- KeySet(final Map<K, Collection<V>> subMap) {
- this.subMap = subMap;
- }
-
- @Override
- Map<K, Collection<V>> map() {
- return subMap;
- }
-
- @Override public Iterator<K> iterator() {
- final Iterator<Map.Entry<K, Collection<V>>> entryIterator
- = subMap.entrySet().iterator();
- return new Iterator<K>() {
- Map.Entry<K, Collection<V>> entry;
-
- @Override
- public boolean hasNext() {
- return entryIterator.hasNext();
- }
- @Override
- public K next() {
- entry = entryIterator.next();
- return entry.getKey();
- }
- @Override
- public void remove() {
- Iterators.checkRemove(entry != null);
- Collection<V> collection = entry.getValue();
- entryIterator.remove();
- totalSize -= collection.size();
- collection.clear();
- }
- };
- }
-
- // The following methods are included for better performance.
-
- @Override public boolean remove(Object key) {
- int count = 0;
- Collection<V> collection = subMap.remove(key);
- if (collection != null) {
- count = collection.size();
- collection.clear();
- totalSize -= count;
- }
- return count > 0;
- }
-
- @Override
- public void clear() {
- Iterators.clear(iterator());
- }
-
- @Override public boolean containsAll(Collection<?> c) {
- return subMap.keySet().containsAll(c);
- }
-
- @Override public boolean equals(@Nullable Object object) {
- return this == object || this.subMap.keySet().equals(object);
- }
-
- @Override public int hashCode() {
- return subMap.keySet().hashCode();
- }
- }
-
- private class SortedKeySet extends KeySet implements SortedSet<K> {
-
- SortedKeySet(SortedMap<K, Collection<V>> subMap) {
- super(subMap);
- }
-
- SortedMap<K, Collection<V>> sortedMap() {
- return (SortedMap<K, Collection<V>>) subMap;
- }
-
- @Override
- public Comparator<? super K> comparator() {
- return sortedMap().comparator();
- }
-
- @Override
- public K first() {
- return sortedMap().firstKey();
- }
-
- @Override
- public SortedSet<K> headSet(K toElement) {
- return new SortedKeySet(sortedMap().headMap(toElement));
- }
-
- @Override
- public K last() {
- return sortedMap().lastKey();
- }
-
- @Override
- public SortedSet<K> subSet(K fromElement, K toElement) {
- return new SortedKeySet(sortedMap().subMap(fromElement, toElement));
- }
-
- @Override
- public SortedSet<K> tailSet(K fromElement) {
- return new SortedKeySet(sortedMap().tailMap(fromElement));
- }
- }
-
- @GwtIncompatible("NavigableSet")
- class NavigableKeySet extends SortedKeySet implements NavigableSet<K> {
- NavigableKeySet(NavigableMap<K, Collection<V>> subMap) {
- super(subMap);
- }
-
- @Override
- NavigableMap<K, Collection<V>> sortedMap() {
- return (NavigableMap<K, Collection<V>>) super.sortedMap();
- }
-
- @Override
- public K lower(K k) {
- return sortedMap().lowerKey(k);
- }
-
- @Override
- public K floor(K k) {
- return sortedMap().floorKey(k);
- }
-
- @Override
- public K ceiling(K k) {
- return sortedMap().ceilingKey(k);
- }
-
- @Override
- public K higher(K k) {
- return sortedMap().higherKey(k);
- }
-
- @Override
- public K pollFirst() {
- return Iterators.pollNext(iterator());
- }
-
- @Override
- public K pollLast() {
- return Iterators.pollNext(descendingIterator());
- }
-
- @Override
- public NavigableSet<K> descendingSet() {
- return new NavigableKeySet(sortedMap().descendingMap());
- }
-
- @Override
- public Iterator<K> descendingIterator() {
- return descendingSet().iterator();
- }
-
- @Override
- public NavigableSet<K> headSet(K toElement) {
- return headSet(toElement, false);
- }
-
- @Override
- public NavigableSet<K> headSet(K toElement, boolean inclusive) {
- return new NavigableKeySet(sortedMap().headMap(toElement, inclusive));
- }
-
- @Override
- public NavigableSet<K> subSet(K fromElement, K toElement) {
- return subSet(fromElement, true, toElement, false);
- }
-
- @Override
- public NavigableSet<K> subSet(
- K fromElement, boolean fromInclusive, K toElement, boolean toInclusive) {
- return new NavigableKeySet(
- sortedMap().subMap(fromElement, fromInclusive, toElement, toInclusive));
- }
-
- @Override
- public NavigableSet<K> tailSet(K fromElement) {
- return tailSet(fromElement, true);
- }
-
- @Override
- public NavigableSet<K> tailSet(K fromElement, boolean inclusive) {
- return new NavigableKeySet(sortedMap().tailMap(fromElement, inclusive));
- }
- }
-
- /**
- * Removes all values for the provided key. Unlike {@link #removeAll}, it
- * returns the number of removed mappings.
- */
- private int removeValuesForKey(Object key) {
- Collection<V> collection = Maps.safeRemove(map, key);
-
- int count = 0;
- if (collection != null) {
- count = collection.size();
- collection.clear();
- totalSize -= count;
- }
- return count;
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>The iterator generated by the returned collection traverses the values
- * for one key, followed by the values of a second key, and so on.
- */
- @Override public Collection<V> values() {
- return super.values();
- }
-
- /*
- * TODO(kevinb): should we copy this javadoc to each concrete class, so that
- * classes like LinkedHashMultimap that need to say something different are
- * still able to {@inheritDoc} all the way from Multimap?
- */
-
- /**
- * {@inheritDoc}
- *
- * <p>The iterator generated by the returned collection traverses the values
- * for one key, followed by the values of a second key, and so on.
- *
- * <p>Each entry is an immutable snapshot of a key-value mapping in the
- * multimap, taken at the time the entry is returned by a method call to the
- * collection or its iterator.
- */
- @Override
- public Collection<Map.Entry<K, V>> entries() {
- return super.entries();
- }
-
- /**
- * Returns an iterator across all key-value map entries, used by {@code
- * entries().iterator()} and {@code values().iterator()}. The default
- * behavior, which traverses the values for one key, the values for a second
- * key, and so on, suffices for most {@code AbstractMapBasedMultimap} implementations.
- *
- * @return an iterator across map entries
- */
- @Override
- Iterator<Map.Entry<K, V>> entryIterator() {
- return new EntryIterator();
- }
-
- /** Iterator across all key-value pairs. */
- private class EntryIterator implements Iterator<Map.Entry<K, V>> {
- final Iterator<Map.Entry<K, Collection<V>>> keyIterator;
- K key;
- Collection<V> collection;
- Iterator<V> valueIterator;
-
- EntryIterator() {
- keyIterator = map.entrySet().iterator();
- if (keyIterator.hasNext()) {
- findValueIteratorAndKey();
- } else {
- valueIterator = Iterators.emptyModifiableIterator();
- }
- }
-
- void findValueIteratorAndKey() {
- Map.Entry<K, Collection<V>> entry = keyIterator.next();
- key = entry.getKey();
- collection = entry.getValue();
- valueIterator = collection.iterator();
- }
-
- @Override
- public boolean hasNext() {
- return keyIterator.hasNext() || valueIterator.hasNext();
- }
-
- @Override
- public Map.Entry<K, V> next() {
- if (!valueIterator.hasNext()) {
- findValueIteratorAndKey();
- }
- return Maps.immutableEntry(key, valueIterator.next());
- }
-
- @Override
- public void remove() {
- valueIterator.remove();
- if (collection.isEmpty()) {
- keyIterator.remove();
- }
- totalSize--;
- }
- }
-
- @Override
- Map<K, Collection<V>> createAsMap() {
- // TreeMultimap uses NavigableAsMap explicitly, but we don't handle that here for GWT
- // compatibility reasons
- return (map instanceof SortedMap)
- ? new SortedAsMap((SortedMap<K, Collection<V>>) map) : new AsMap(map);
- }
-
- private class AsMap extends AbstractMap<K, Collection<V>> {
- /**
- * Usually the same as map, but smaller for the headMap(), tailMap(), or
- * subMap() of a SortedAsMap.
- */
- final transient Map<K, Collection<V>> submap;
-
- AsMap(Map<K, Collection<V>> submap) {
- this.submap = submap;
- }
-
- transient Set<Map.Entry<K, Collection<V>>> entrySet;
-
- @Override public Set<Map.Entry<K, Collection<V>>> entrySet() {
- Set<Map.Entry<K, Collection<V>>> result = entrySet;
- return (result == null) ? entrySet = new AsMapEntries() : result;
- }
-
- // The following methods are included for performance.
-
- @Override public boolean containsKey(Object key) {
- return Maps.safeContainsKey(submap, key);
- }
-
- @Override public Collection<V> get(Object key) {
- Collection<V> collection = Maps.safeGet(submap, key);
- if (collection == null) {
- return null;
- }
- @SuppressWarnings("unchecked")
- K k = (K) key;
- return wrapCollection(k, collection);
- }
-
- @Override public Set<K> keySet() {
- return AbstractMapBasedMultimap.this.keySet();
- }
-
- @Override
- public int size() {
- return submap.size();
- }
-
- @Override public Collection<V> remove(Object key) {
- Collection<V> collection = submap.remove(key);
- if (collection == null) {
- return null;
- }
-
- Collection<V> output = createCollection();
- output.addAll(collection);
- totalSize -= collection.size();
- collection.clear();
- return output;
- }
-
- @Override public boolean equals(@Nullable Object object) {
- return this == object || submap.equals(object);
- }
-
- @Override public int hashCode() {
- return submap.hashCode();
- }
-
- @Override public String toString() {
- return submap.toString();
- }
-
- @Override
- public void clear() {
- if (submap == map) {
- AbstractMapBasedMultimap.this.clear();
- } else {
-
- Iterators.clear(new AsMapIterator());
- }
- }
-
- Entry<K, Collection<V>> wrapEntry(Entry<K, Collection<V>> entry) {
- K key = entry.getKey();
- return Maps.immutableEntry(key, wrapCollection(key, entry.getValue()));
- }
-
- class AsMapEntries extends Maps.EntrySet<K, Collection<V>> {
- @Override
- Map<K, Collection<V>> map() {
- return AsMap.this;
- }
-
- @Override public Iterator<Map.Entry<K, Collection<V>>> iterator() {
- return new AsMapIterator();
- }
-
- // The following methods are included for performance.
-
- @Override public boolean contains(Object o) {
- return Collections2.safeContains(submap.entrySet(), o);
- }
-
- @Override public boolean remove(Object o) {
- if (!contains(o)) {
- return false;
- }
- Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
- removeValuesForKey(entry.getKey());
- return true;
- }
- }
-
- /** Iterator across all keys and value collections. */
- class AsMapIterator implements Iterator<Map.Entry<K, Collection<V>>> {
- final Iterator<Map.Entry<K, Collection<V>>> delegateIterator
- = submap.entrySet().iterator();
- Collection<V> collection;
-
- @Override
- public boolean hasNext() {
- return delegateIterator.hasNext();
- }
-
- @Override
- public Map.Entry<K, Collection<V>> next() {
- Map.Entry<K, Collection<V>> entry = delegateIterator.next();
- collection = entry.getValue();
- return wrapEntry(entry);
- }
-
- @Override
- public void remove() {
- delegateIterator.remove();
- totalSize -= collection.size();
- collection.clear();
- }
- }
- }
-
- private class SortedAsMap extends AsMap
- implements SortedMap<K, Collection<V>> {
- SortedAsMap(SortedMap<K, Collection<V>> submap) {
- super(submap);
- }
-
- SortedMap<K, Collection<V>> sortedMap() {
- return (SortedMap<K, Collection<V>>) submap;
- }
-
- @Override
- public Comparator<? super K> comparator() {
- return sortedMap().comparator();
- }
-
- @Override
- public K firstKey() {
- return sortedMap().firstKey();
- }
-
- @Override
- public K lastKey() {
- return sortedMap().lastKey();
- }
-
- @Override
- public SortedMap<K, Collection<V>> headMap(K toKey) {
- return new SortedAsMap(sortedMap().headMap(toKey));
- }
-
- @Override
- public SortedMap<K, Collection<V>> subMap(K fromKey, K toKey) {
- return new SortedAsMap(sortedMap().subMap(fromKey, toKey));
- }
-
- @Override
- public SortedMap<K, Collection<V>> tailMap(K fromKey) {
- return new SortedAsMap(sortedMap().tailMap(fromKey));
- }
-
- SortedSet<K> sortedKeySet;
-
- // returns a SortedSet, even though returning a Set would be sufficient to
- // satisfy the SortedMap.keySet() interface
- @Override public SortedSet<K> keySet() {
- SortedSet<K> result = sortedKeySet;
- return (result == null) ? sortedKeySet = createKeySet() : result;
- }
-
- SortedSet<K> createKeySet() {
- return new SortedKeySet(sortedMap());
- }
- }
-
- @GwtIncompatible("NavigableAsMap")
- class NavigableAsMap extends SortedAsMap implements NavigableMap<K, Collection<V>> {
-
- NavigableAsMap(NavigableMap<K, Collection<V>> submap) {
- super(submap);
- }
-
- @Override
- NavigableMap<K, Collection<V>> sortedMap() {
- return (NavigableMap<K, Collection<V>>) super.sortedMap();
- }
-
- @Override
- public Entry<K, Collection<V>> lowerEntry(K key) {
- Entry<K, Collection<V>> entry = sortedMap().lowerEntry(key);
- return (entry == null) ? null : wrapEntry(entry);
- }
-
- @Override
- public K lowerKey(K key) {
- return sortedMap().lowerKey(key);
- }
-
- @Override
- public Entry<K, Collection<V>> floorEntry(K key) {
- Entry<K, Collection<V>> entry = sortedMap().floorEntry(key);
- return (entry == null) ? null : wrapEntry(entry);
- }
-
- @Override
- public K floorKey(K key) {
- return sortedMap().floorKey(key);
- }
-
- @Override
- public Entry<K, Collection<V>> ceilingEntry(K key) {
- Entry<K, Collection<V>> entry = sortedMap().ceilingEntry(key);
- return (entry == null) ? null : wrapEntry(entry);
- }
-
- @Override
- public K ceilingKey(K key) {
- return sortedMap().ceilingKey(key);
- }
-
- @Override
- public Entry<K, Collection<V>> higherEntry(K key) {
- Entry<K, Collection<V>> entry = sortedMap().higherEntry(key);
- return (entry == null) ? null : wrapEntry(entry);
- }
-
- @Override
- public K higherKey(K key) {
- return sortedMap().higherKey(key);
- }
-
- @Override
- public Entry<K, Collection<V>> firstEntry() {
- Entry<K, Collection<V>> entry = sortedMap().firstEntry();
- return (entry == null) ? null : wrapEntry(entry);
- }
-
- @Override
- public Entry<K, Collection<V>> lastEntry() {
- Entry<K, Collection<V>> entry = sortedMap().lastEntry();
- return (entry == null) ? null : wrapEntry(entry);
- }
-
- @Override
- public Entry<K, Collection<V>> pollFirstEntry() {
- return pollAsMapEntry(entrySet().iterator());
- }
-
- @Override
- public Entry<K, Collection<V>> pollLastEntry() {
- return pollAsMapEntry(descendingMap().entrySet().iterator());
- }
-
- Map.Entry<K, Collection<V>> pollAsMapEntry(Iterator<Entry<K, Collection<V>>> entryIterator) {
- if (!entryIterator.hasNext()) {
- return null;
- }
- Entry<K, Collection<V>> entry = entryIterator.next();
- Collection<V> output = createCollection();
- output.addAll(entry.getValue());
- entryIterator.remove();
- return Maps.immutableEntry(entry.getKey(), unmodifiableCollectionSubclass(output));
- }
-
- @Override
- public NavigableMap<K, Collection<V>> descendingMap() {
- return new NavigableAsMap(sortedMap().descendingMap());
- }
-
- @Override
- public NavigableSet<K> keySet() {
- return (NavigableSet<K>) super.keySet();
- }
-
- @Override
- NavigableSet<K> createKeySet() {
- return new NavigableKeySet(sortedMap());
- }
-
- @Override
- public NavigableSet<K> navigableKeySet() {
- return keySet();
- }
-
- @Override
- public NavigableSet<K> descendingKeySet() {
- return descendingMap().navigableKeySet();
- }
-
- @Override
- public NavigableMap<K, Collection<V>> subMap(K fromKey, K toKey) {
- return subMap(fromKey, true, toKey, false);
- }
-
- @Override
- public NavigableMap<K, Collection<V>> subMap(
- K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
- return new NavigableAsMap(sortedMap().subMap(fromKey, fromInclusive, toKey, toInclusive));
- }
-
- @Override
- public NavigableMap<K, Collection<V>> headMap(K toKey) {
- return headMap(toKey, false);
- }
-
- @Override
- public NavigableMap<K, Collection<V>> headMap(K toKey, boolean inclusive) {
- return new NavigableAsMap(sortedMap().headMap(toKey, false));
- }
-
- @Override
- public NavigableMap<K, Collection<V>> tailMap(K fromKey) {
- return tailMap(fromKey, true);
- }
-
- @Override
- public NavigableMap<K, Collection<V>> tailMap(K fromKey, boolean inclusive) {
- return new NavigableAsMap(sortedMap().tailMap(fromKey, inclusive));
- }
- }
-
- private static final long serialVersionUID = 2447537837011683357L;
-}
diff --git a/guava/src/com/google/common/collect/AbstractMapBasedMultiset.java b/guava/src/com/google/common/collect/AbstractMapBasedMultiset.java
index 6f14380..362386c 100644
--- a/guava/src/com/google/common/collect/AbstractMapBasedMultiset.java
+++ b/guava/src/com/google/common/collect/AbstractMapBasedMultiset.java
@@ -28,6 +28,7 @@ import com.google.common.primitives.Ints;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
+import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
@@ -37,7 +38,7 @@ import javax.annotation.Nullable;
/**
* Basic implementation of {@code Multiset<E>} backed by an instance of {@code
- * Map<E, Count>}.
+ * Map<E, AtomicInteger>}.
*
* <p>For serialization to work, the subclass must specify explicit {@code
* readObject} and {@code writeObject} methods.
@@ -63,6 +64,10 @@ abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
this.size = super.size();
}
+ Map<E, Count> backingMap() {
+ return backingMap;
+ }
+
/** Used during deserialization only. The backing map must be empty. */
void setBackingMap(Map<E, Count> backingMap) {
this.backingMap = backingMap;
@@ -119,7 +124,8 @@ abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
@Override
public void remove() {
- Iterators.checkRemove(toRemove != null);
+ checkState(toRemove != null,
+ "no calls to next() since the last call to remove()");
size -= toRemove.getValue().getAndSet(0);
backingEntries.remove();
toRemove = null;
@@ -153,7 +159,7 @@ abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
/*
* Not subclassing AbstractMultiset$MultisetIterator because next() needs to
- * retrieve the Map.Entry<E, Count> entry, which can then be used for
+ * retrieve the Map.Entry<E, AtomicInteger> entry, which can then be used for
* a more efficient remove() call.
*/
private class MapBasedMultisetIterator implements Iterator<E> {
@@ -199,8 +205,14 @@ abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
}
@Override public int count(@Nullable Object element) {
- Count frequency = Maps.safeGet(backingMap, element);
- return (frequency == null) ? 0 : frequency.get();
+ try {
+ Count frequency = backingMap.get(element);
+ return (frequency == null) ? 0 : frequency.get();
+ } catch (NullPointerException e) {
+ return 0;
+ } catch (ClassCastException e) {
+ return 0;
+ }
}
// Optional Operations - Modification Operations
@@ -261,7 +273,7 @@ abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
}
// Roughly a 33% performance improvement over AbstractMultiset.setCount().
- @Override public int setCount(@Nullable E element, int count) {
+ @Override public int setCount(E element, int count) {
checkNonnegative(count, "count");
Count existingCounter;
@@ -290,6 +302,98 @@ abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
return i.getAndSet(count);
}
+ private int removeAllOccurrences(@Nullable Object element,
+ Map<E, Count> map) {
+ Count frequency = map.remove(element);
+ if (frequency == null) {
+ return 0;
+ }
+ int numberRemoved = frequency.getAndSet(0);
+ size -= numberRemoved;
+ return numberRemoved;
+ }
+
+ // Views
+
+ @Override Set<E> createElementSet() {
+ return new MapBasedElementSet(backingMap);
+ }
+
+ // TODO(user): once TreeMultiset is replaced with a SortedMultiset
+ // implementation, replace this with a subclass of Multisets.ElementSet.
+ class MapBasedElementSet extends ForwardingSet<E> {
+
+ // This mapping is the usually the same as 'backingMap', but can be a
+ // submap in some implementations.
+ private final Map<E, Count> map;
+ private final Set<E> delegate;
+
+ MapBasedElementSet(Map<E, Count> map) {
+ this.map = map;
+ delegate = map.keySet();
+ }
+
+ @Override protected Set<E> delegate() {
+ return delegate;
+ }
+
+ @Override public Iterator<E> iterator() {
+ final Iterator<Map.Entry<E, Count>> entries
+ = map.entrySet().iterator();
+ return new Iterator<E>() {
+ Map.Entry<E, Count> toRemove;
+
+ @Override
+ public boolean hasNext() {
+ return entries.hasNext();
+ }
+
+ @Override
+ public E next() {
+ toRemove = entries.next();
+ return toRemove.getKey();
+ }
+
+ @Override
+ public void remove() {
+ checkState(toRemove != null,
+ "no calls to next() since the last call to remove()");
+ size -= toRemove.getValue().getAndSet(0);
+ entries.remove();
+ toRemove = null;
+ }
+ };
+ }
+
+ @Override public boolean remove(Object element) {
+ return removeAllOccurrences(element, map) != 0;
+ }
+
+ @Override public boolean removeAll(Collection<?> elementsToRemove) {
+ return Iterators.removeAll(iterator(), elementsToRemove);
+ }
+
+ @Override public boolean retainAll(Collection<?> elementsToRetain) {
+ return Iterators.retainAll(iterator(), elementsToRetain);
+ }
+
+ @Override public void clear() {
+ if (map == backingMap) {
+ AbstractMapBasedMultiset.this.clear();
+ } else {
+ Iterator<E> i = iterator();
+ while (i.hasNext()) {
+ i.next();
+ i.remove();
+ }
+ }
+ }
+
+ public Map<E, Count> getMap() {
+ return map;
+ }
+ }
+
// Don't allow default serialization.
@GwtIncompatible("java.io.ObjectStreamException")
@SuppressWarnings("unused") // actually used during deserialization
diff --git a/guava/src/com/google/common/collect/AbstractMultimap.java b/guava/src/com/google/common/collect/AbstractMultimap.java
index 13fdd00..38f69ec 100644
--- a/guava/src/com/google/common/collect/AbstractMultimap.java
+++ b/guava/src/com/google/common/collect/AbstractMultimap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Guava Authors
+ * Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,33 +16,170 @@
package com.google.common.collect;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
import com.google.common.annotations.GwtCompatible;
+import java.io.Serializable;
+import java.util.AbstractCollection;
+import java.util.AbstractMap;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.ConcurrentModificationException;
import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.RandomAccess;
import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
import javax.annotation.Nullable;
/**
- * A skeleton {@code Multimap} implementation, not necessarily in terms of a {@code Map}.
- *
+ * Basic implementation of the {@link Multimap} interface. This class represents
+ * a multimap as a map that associates each key with a collection of values. All
+ * methods of {@link Multimap} are supported, including those specified as
+ * optional in the interface.
+ *
+ * <p>To implement a multimap, a subclass must define the method {@link
+ * #createCollection()}, which creates an empty collection of values for a key.
+ *
+ * <p>The multimap constructor takes a map that has a single entry for each
+ * distinct key. When you insert a key-value pair with a key that isn't already
+ * in the multimap, {@code AbstractMultimap} calls {@link #createCollection()}
+ * to create the collection of values for that key. The subclass should not call
+ * {@link #createCollection()} directly, and a new instance should be created
+ * every time the method is called.
+ *
+ * <p>For example, the subclass could pass a {@link java.util.TreeMap} during
+ * construction, and {@link #createCollection()} could return a {@link
+ * java.util.TreeSet}, in which case the multimap's iterators would propagate
+ * through the keys and values in sorted order.
+ *
+ * <p>Keys and values may be null, as long as the underlying collection classes
+ * support null elements.
+ *
+ * <p>The collections created by {@link #createCollection()} may or may not
+ * allow duplicates. If the collection, such as a {@link Set}, does not support
+ * duplicates, an added key-value pair will replace an existing pair with the
+ * same key and value, if such a pair is present. With collections like {@link
+ * List} that allow duplicates, the collection will keep the existing key-value
+ * pairs while adding a new pair.
+ *
+ * <p>This class is not threadsafe when any concurrent operations update the
+ * multimap, even if the underlying map and {@link #createCollection()} method
+ * return threadsafe classes. Concurrent read operations will work correctly. To
+ * allow concurrent update operations, wrap your multimap with a call to {@link
+ * Multimaps#synchronizedMultimap}.
+ *
+ * <p>For serialization to work, the subclass must specify explicit
+ * {@code readObject} and {@code writeObject} methods.
+ *
+ * @author Jared Levy
* @author Louis Wasserman
*/
@GwtCompatible
-abstract class AbstractMultimap<K, V> implements Multimap<K, V> {
+abstract class AbstractMultimap<K, V> implements Multimap<K, V>, Serializable {
+ /*
+ * Here's an outline of the overall design.
+ *
+ * The map variable contains the collection of values associated with each
+ * key. When a key-value pair is added to a multimap that didn't previously
+ * contain any values for that key, a new collection generated by
+ * createCollection is added to the map. That same collection instance
+ * remains in the map as long as the multimap has any values for the key. If
+ * all values for the key are removed, the key and collection are removed
+ * from the map.
+ *
+ * The get method returns a WrappedCollection, which decorates the collection
+ * in the map (if the key is present) or an empty collection (if the key is
+ * not present). When the collection delegate in the WrappedCollection is
+ * empty, the multimap may contain subsequently added values for that key. To
+ * handle that situation, the WrappedCollection checks whether map contains
+ * an entry for the provided key, and if so replaces the delegate.
+ */
+
+ private transient Map<K, Collection<V>> map;
+ private transient int totalSize;
+
+ /**
+ * Creates a new multimap that uses the provided map.
+ *
+ * @param map place to store the mapping from each key to its corresponding
+ * values
+ * @throws IllegalArgumentException if {@code map} is not empty
+ */
+ protected AbstractMultimap(Map<K, Collection<V>> map) {
+ checkArgument(map.isEmpty());
+ this.map = map;
+ }
+
+ /** Used during deserialization only. */
+ final void setMap(Map<K, Collection<V>> map) {
+ this.map = map;
+ totalSize = 0;
+ for (Collection<V> values : map.values()) {
+ checkArgument(!values.isEmpty());
+ totalSize += values.size();
+ }
+ }
+
+ /**
+ * Creates the collection of values for a single key.
+ *
+ * <p>Collections with weak, soft, or phantom references are not supported.
+ * Each call to {@code createCollection} should create a new instance.
+ *
+ * <p>The returned collection class determines whether duplicate key-value
+ * pairs are allowed.
+ *
+ * @return an empty collection of values
+ */
+ abstract Collection<V> createCollection();
+
+ /**
+ * Creates the collection of values for an explicitly provided key. By
+ * default, it simply calls {@link #createCollection()}, which is the correct
+ * behavior for most implementations. The {@link LinkedHashMultimap} class
+ * overrides it.
+ *
+ * @param key key to associate with values in the collection
+ * @return an empty collection of values
+ */
+ Collection<V> createCollection(@Nullable K key) {
+ return createCollection();
+ }
+
+ Map<K, Collection<V>> backingMap() {
+ return map;
+ }
+
+ // Query Operations
+
+ @Override
+ public int size() {
+ return totalSize;
+ }
+
@Override
public boolean isEmpty() {
- return size() == 0;
+ return totalSize == 0;
+ }
+
+ @Override
+ public boolean containsKey(@Nullable Object key) {
+ return map.containsKey(key);
}
@Override
public boolean containsValue(@Nullable Object value) {
- for (Collection<V> collection : asMap().values()) {
+ for (Collection<V> collection : map.values()) {
if (collection.contains(value)) {
return true;
}
@@ -53,25 +190,72 @@ abstract class AbstractMultimap<K, V> implements Multimap<K, V> {
@Override
public boolean containsEntry(@Nullable Object key, @Nullable Object value) {
- Collection<V> collection = asMap().get(key);
+ Collection<V> collection = map.get(key);
return collection != null && collection.contains(value);
}
-
+
+ // Modification Operations
+
@Override
- public boolean remove(@Nullable Object key, @Nullable Object value) {
- Collection<V> collection = asMap().get(key);
- return collection != null && collection.remove(value);
+ public boolean put(@Nullable K key, @Nullable V value) {
+ Collection<V> collection = getOrCreateCollection(key);
+
+ if (collection.add(value)) {
+ totalSize++;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private Collection<V> getOrCreateCollection(@Nullable K key) {
+ Collection<V> collection = map.get(key);
+ if (collection == null) {
+ collection = createCollection(key);
+ map.put(key, collection);
+ }
+ return collection;
}
@Override
- public boolean put(@Nullable K key, @Nullable V value) {
- return get(key).add(value);
+ public boolean remove(@Nullable Object key, @Nullable Object value) {
+ Collection<V> collection = map.get(key);
+ if (collection == null) {
+ return false;
+ }
+
+ boolean changed = collection.remove(value);
+ if (changed) {
+ totalSize--;
+ if (collection.isEmpty()) {
+ map.remove(key);
+ }
+ }
+ return changed;
}
+ // Bulk Operations
+
@Override
public boolean putAll(@Nullable K key, Iterable<? extends V> values) {
- checkNotNull(values);
- return values.iterator().hasNext() && Iterables.addAll(get(key), values);
+ if (!values.iterator().hasNext()) {
+ return false;
+ }
+ Collection<V> collection = getOrCreateCollection(key);
+ int oldSize = collection.size();
+
+ boolean changed = false;
+ if (values instanceof Collection) {
+ Collection<? extends V> c = Collections2.cast(values);
+ changed = collection.addAll(c);
+ } else {
+ for (V value : values) {
+ changed |= collection.add(value);
+ }
+ }
+
+ totalSize += (collection.size() - oldSize);
+ return changed;
}
@Override
@@ -83,50 +267,597 @@ abstract class AbstractMultimap<K, V> implements Multimap<K, V> {
return changed;
}
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The returned collection is immutable.
+ */
@Override
- public Collection<V> replaceValues(@Nullable K key, Iterable<? extends V> values) {
- checkNotNull(values);
- Collection<V> result = removeAll(key);
- putAll(key, values);
- return result;
+ public Collection<V> replaceValues(
+ @Nullable K key, Iterable<? extends V> values) {
+ Iterator<? extends V> iterator = values.iterator();
+ if (!iterator.hasNext()) {
+ return removeAll(key);
+ }
+
+ Collection<V> collection = getOrCreateCollection(key);
+ Collection<V> oldValues = createCollection();
+ oldValues.addAll(collection);
+
+ totalSize -= collection.size();
+ collection.clear();
+
+ while (iterator.hasNext()) {
+ if (collection.add(iterator.next())) {
+ totalSize++;
+ }
+ }
+
+ return unmodifiableCollectionSubclass(oldValues);
}
-
- private transient Collection<Entry<K, V>> entries;
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The returned collection is immutable.
+ */
@Override
- public Collection<Entry<K, V>> entries() {
- Collection<Entry<K, V>> result = entries;
- return (result == null) ? entries = createEntries() : result;
+ public Collection<V> removeAll(@Nullable Object key) {
+ Collection<V> collection = map.remove(key);
+ Collection<V> output = createCollection();
+
+ if (collection != null) {
+ output.addAll(collection);
+ totalSize -= collection.size();
+ collection.clear();
+ }
+
+ return unmodifiableCollectionSubclass(output);
}
-
- Collection<Entry<K, V>> createEntries() {
- if (this instanceof SetMultimap) {
- return new Multimaps.EntrySet<K, V>() {
- @Override
- Multimap<K, V> multimap() {
- return AbstractMultimap.this;
+
+ private Collection<V> unmodifiableCollectionSubclass(
+ Collection<V> collection) {
+ if (collection instanceof SortedSet) {
+ return Collections.unmodifiableSortedSet((SortedSet<V>) collection);
+ } else if (collection instanceof Set) {
+ return Collections.unmodifiableSet((Set<V>) collection);
+ } else if (collection instanceof List) {
+ return Collections.unmodifiableList((List<V>) collection);
+ } else {
+ return Collections.unmodifiableCollection(collection);
+ }
+ }
+
+ @Override
+ public void clear() {
+ // Clear each collection, to make previously returned collections empty.
+ for (Collection<V> collection : map.values()) {
+ collection.clear();
+ }
+ map.clear();
+ totalSize = 0;
+ }
+
+ // Views
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The returned collection is not serializable.
+ */
+ @Override
+ public Collection<V> get(@Nullable K key) {
+ Collection<V> collection = map.get(key);
+ if (collection == null) {
+ collection = createCollection(key);
+ }
+ return wrapCollection(key, collection);
+ }
+
+ /**
+ * Generates a decorated collection that remains consistent with the values in
+ * the multimap for the provided key. Changes to the multimap may alter the
+ * returned collection, and vice versa.
+ */
+ private Collection<V> wrapCollection(
+ @Nullable K key, Collection<V> collection) {
+ if (collection instanceof SortedSet) {
+ return new WrappedSortedSet(key, (SortedSet<V>) collection, null);
+ } else if (collection instanceof Set) {
+ return new WrappedSet(key, (Set<V>) collection);
+ } else if (collection instanceof List) {
+ return wrapList(key, (List<V>) collection, null);
+ } else {
+ return new WrappedCollection(key, collection, null);
+ }
+ }
+
+ private List<V> wrapList(
+ @Nullable K key, List<V> list, @Nullable WrappedCollection ancestor) {
+ return (list instanceof RandomAccess)
+ ? new RandomAccessWrappedList(key, list, ancestor)
+ : new WrappedList(key, list, ancestor);
+ }
+
+ /**
+ * Collection decorator that stays in sync with the multimap values for a key.
+ * There are two kinds of wrapped collections: full and subcollections. Both
+ * have a delegate pointing to the underlying collection class.
+ *
+ * <p>Full collections, identified by a null ancestor field, contain all
+ * multimap values for a given key. Its delegate is a value in {@link
+ * AbstractMultimap#map} whenever the delegate is non-empty. The {@code
+ * refreshIfEmpty}, {@code removeIfEmpty}, and {@code addToMap} methods ensure
+ * that the {@code WrappedCollection} and map remain consistent.
+ *
+ * <p>A subcollection, such as a sublist, contains some of the values for a
+ * given key. Its ancestor field points to the full wrapped collection with
+ * all values for the key. The subcollection {@code refreshIfEmpty}, {@code
+ * removeIfEmpty}, and {@code addToMap} methods call the corresponding methods
+ * of the full wrapped collection.
+ */
+ private class WrappedCollection extends AbstractCollection<V> {
+ final K key;
+ Collection<V> delegate;
+ final WrappedCollection ancestor;
+ final Collection<V> ancestorDelegate;
+
+ WrappedCollection(@Nullable K key, Collection<V> delegate,
+ @Nullable WrappedCollection ancestor) {
+ this.key = key;
+ this.delegate = delegate;
+ this.ancestor = ancestor;
+ this.ancestorDelegate
+ = (ancestor == null) ? null : ancestor.getDelegate();
+ }
+
+ /**
+ * If the delegate collection is empty, but the multimap has values for the
+ * key, replace the delegate with the new collection for the key.
+ *
+ * <p>For a subcollection, refresh its ancestor and validate that the
+ * ancestor delegate hasn't changed.
+ */
+ void refreshIfEmpty() {
+ if (ancestor != null) {
+ ancestor.refreshIfEmpty();
+ if (ancestor.getDelegate() != ancestorDelegate) {
+ throw new ConcurrentModificationException();
}
+ } else if (delegate.isEmpty()) {
+ Collection<V> newDelegate = map.get(key);
+ if (newDelegate != null) {
+ delegate = newDelegate;
+ }
+ }
+ }
- @Override
- public Iterator<Entry<K, V>> iterator() {
- return entryIterator();
+ /**
+ * If collection is empty, remove it from {@code AbstractMultimap.this.map}.
+ * For subcollections, check whether the ancestor collection is empty.
+ */
+ void removeIfEmpty() {
+ if (ancestor != null) {
+ ancestor.removeIfEmpty();
+ } else if (delegate.isEmpty()) {
+ map.remove(key);
+ }
+ }
+
+ K getKey() {
+ return key;
+ }
+
+ /**
+ * Add the delegate to the map. Other {@code WrappedCollection} methods
+ * should call this method after adding elements to a previously empty
+ * collection.
+ *
+ * <p>Subcollection add the ancestor's delegate instead.
+ */
+ void addToMap() {
+ if (ancestor != null) {
+ ancestor.addToMap();
+ } else {
+ map.put(key, delegate);
+ }
+ }
+
+ @Override public int size() {
+ refreshIfEmpty();
+ return delegate.size();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ refreshIfEmpty();
+ return delegate.equals(object);
+ }
+
+ @Override public int hashCode() {
+ refreshIfEmpty();
+ return delegate.hashCode();
+ }
+
+ @Override public String toString() {
+ refreshIfEmpty();
+ return delegate.toString();
+ }
+
+ Collection<V> getDelegate() {
+ return delegate;
+ }
+
+ @Override public Iterator<V> iterator() {
+ refreshIfEmpty();
+ return new WrappedIterator();
+ }
+
+ /** Collection iterator for {@code WrappedCollection}. */
+ class WrappedIterator implements Iterator<V> {
+ final Iterator<V> delegateIterator;
+ final Collection<V> originalDelegate = delegate;
+
+ WrappedIterator() {
+ delegateIterator = iteratorOrListIterator(delegate);
+ }
+
+ WrappedIterator(Iterator<V> delegateIterator) {
+ this.delegateIterator = delegateIterator;
+ }
+
+ /**
+ * If the delegate changed since the iterator was created, the iterator is
+ * no longer valid.
+ */
+ void validateIterator() {
+ refreshIfEmpty();
+ if (delegate != originalDelegate) {
+ throw new ConcurrentModificationException();
}
- };
+ }
+
+ @Override
+ public boolean hasNext() {
+ validateIterator();
+ return delegateIterator.hasNext();
+ }
+
+ @Override
+ public V next() {
+ validateIterator();
+ return delegateIterator.next();
+ }
+
+ @Override
+ public void remove() {
+ delegateIterator.remove();
+ totalSize--;
+ removeIfEmpty();
+ }
+
+ Iterator<V> getDelegateIterator() {
+ validateIterator();
+ return delegateIterator;
+ }
}
- return new Multimaps.Entries<K, V>() {
+
+ @Override public boolean add(V value) {
+ refreshIfEmpty();
+ boolean wasEmpty = delegate.isEmpty();
+ boolean changed = delegate.add(value);
+ if (changed) {
+ totalSize++;
+ if (wasEmpty) {
+ addToMap();
+ }
+ }
+ return changed;
+ }
+
+ WrappedCollection getAncestor() {
+ return ancestor;
+ }
+
+ // The following methods are provided for better performance.
+
+ @Override public boolean addAll(Collection<? extends V> collection) {
+ if (collection.isEmpty()) {
+ return false;
+ }
+ int oldSize = size(); // calls refreshIfEmpty
+ boolean changed = delegate.addAll(collection);
+ if (changed) {
+ int newSize = delegate.size();
+ totalSize += (newSize - oldSize);
+ if (oldSize == 0) {
+ addToMap();
+ }
+ }
+ return changed;
+ }
+
+ @Override public boolean contains(Object o) {
+ refreshIfEmpty();
+ return delegate.contains(o);
+ }
+
+ @Override public boolean containsAll(Collection<?> c) {
+ refreshIfEmpty();
+ return delegate.containsAll(c);
+ }
+
+ @Override public void clear() {
+ int oldSize = size(); // calls refreshIfEmpty
+ if (oldSize == 0) {
+ return;
+ }
+ delegate.clear();
+ totalSize -= oldSize;
+ removeIfEmpty(); // maybe shouldn't be removed if this is a sublist
+ }
+
+ @Override public boolean remove(Object o) {
+ refreshIfEmpty();
+ boolean changed = delegate.remove(o);
+ if (changed) {
+ totalSize--;
+ removeIfEmpty();
+ }
+ return changed;
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ if (c.isEmpty()) {
+ return false;
+ }
+ int oldSize = size(); // calls refreshIfEmpty
+ boolean changed = delegate.removeAll(c);
+ if (changed) {
+ int newSize = delegate.size();
+ totalSize += (newSize - oldSize);
+ removeIfEmpty();
+ }
+ return changed;
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ checkNotNull(c);
+ int oldSize = size(); // calls refreshIfEmpty
+ boolean changed = delegate.retainAll(c);
+ if (changed) {
+ int newSize = delegate.size();
+ totalSize += (newSize - oldSize);
+ removeIfEmpty();
+ }
+ return changed;
+ }
+ }
+
+ private Iterator<V> iteratorOrListIterator(Collection<V> collection) {
+ return (collection instanceof List)
+ ? ((List<V>) collection).listIterator()
+ : collection.iterator();
+ }
+
+ /** Set decorator that stays in sync with the multimap values for a key. */
+ private class WrappedSet extends WrappedCollection implements Set<V> {
+ WrappedSet(@Nullable K key, Set<V> delegate) {
+ super(key, delegate, null);
+ }
+ }
+
+ /**
+ * SortedSet decorator that stays in sync with the multimap values for a key.
+ */
+ private class WrappedSortedSet extends WrappedCollection
+ implements SortedSet<V> {
+ WrappedSortedSet(@Nullable K key, SortedSet<V> delegate,
+ @Nullable WrappedCollection ancestor) {
+ super(key, delegate, ancestor);
+ }
+
+ SortedSet<V> getSortedSetDelegate() {
+ return (SortedSet<V>) getDelegate();
+ }
+
+ @Override
+ public Comparator<? super V> comparator() {
+ return getSortedSetDelegate().comparator();
+ }
+
+ @Override
+ public V first() {
+ refreshIfEmpty();
+ return getSortedSetDelegate().first();
+ }
+
+ @Override
+ public V last() {
+ refreshIfEmpty();
+ return getSortedSetDelegate().last();
+ }
+
+ @Override
+ public SortedSet<V> headSet(V toElement) {
+ refreshIfEmpty();
+ return new WrappedSortedSet(
+ getKey(), getSortedSetDelegate().headSet(toElement),
+ (getAncestor() == null) ? this : getAncestor());
+ }
+
+ @Override
+ public SortedSet<V> subSet(V fromElement, V toElement) {
+ refreshIfEmpty();
+ return new WrappedSortedSet(
+ getKey(), getSortedSetDelegate().subSet(fromElement, toElement),
+ (getAncestor() == null) ? this : getAncestor());
+ }
+
+ @Override
+ public SortedSet<V> tailSet(V fromElement) {
+ refreshIfEmpty();
+ return new WrappedSortedSet(
+ getKey(), getSortedSetDelegate().tailSet(fromElement),
+ (getAncestor() == null) ? this : getAncestor());
+ }
+ }
+
+ /** List decorator that stays in sync with the multimap values for a key. */
+ private class WrappedList extends WrappedCollection implements List<V> {
+ WrappedList(@Nullable K key, List<V> delegate,
+ @Nullable WrappedCollection ancestor) {
+ super(key, delegate, ancestor);
+ }
+
+ List<V> getListDelegate() {
+ return (List<V>) getDelegate();
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends V> c) {
+ if (c.isEmpty()) {
+ return false;
+ }
+ int oldSize = size(); // calls refreshIfEmpty
+ boolean changed = getListDelegate().addAll(index, c);
+ if (changed) {
+ int newSize = getDelegate().size();
+ totalSize += (newSize - oldSize);
+ if (oldSize == 0) {
+ addToMap();
+ }
+ }
+ return changed;
+ }
+
+ @Override
+ public V get(int index) {
+ refreshIfEmpty();
+ return getListDelegate().get(index);
+ }
+
+ @Override
+ public V set(int index, V element) {
+ refreshIfEmpty();
+ return getListDelegate().set(index, element);
+ }
+
+ @Override
+ public void add(int index, V element) {
+ refreshIfEmpty();
+ boolean wasEmpty = getDelegate().isEmpty();
+ getListDelegate().add(index, element);
+ totalSize++;
+ if (wasEmpty) {
+ addToMap();
+ }
+ }
+
+ @Override
+ public V remove(int index) {
+ refreshIfEmpty();
+ V value = getListDelegate().remove(index);
+ totalSize--;
+ removeIfEmpty();
+ return value;
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ refreshIfEmpty();
+ return getListDelegate().indexOf(o);
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ refreshIfEmpty();
+ return getListDelegate().lastIndexOf(o);
+ }
+
+ @Override
+ public ListIterator<V> listIterator() {
+ refreshIfEmpty();
+ return new WrappedListIterator();
+ }
+
+ @Override
+ public ListIterator<V> listIterator(int index) {
+ refreshIfEmpty();
+ return new WrappedListIterator(index);
+ }
+
+ @Override
+ public List<V> subList(int fromIndex, int toIndex) {
+ refreshIfEmpty();
+ return wrapList(getKey(),
+ getListDelegate().subList(fromIndex, toIndex),
+ (getAncestor() == null) ? this : getAncestor());
+ }
+
+ /** ListIterator decorator. */
+ private class WrappedListIterator extends WrappedIterator
+ implements ListIterator<V> {
+ WrappedListIterator() {}
+
+ public WrappedListIterator(int index) {
+ super(getListDelegate().listIterator(index));
+ }
+
+ private ListIterator<V> getDelegateListIterator() {
+ return (ListIterator<V>) getDelegateIterator();
+ }
+
@Override
- Multimap<K, V> multimap() {
- return AbstractMultimap.this;
+ public boolean hasPrevious() {
+ return getDelegateListIterator().hasPrevious();
}
@Override
- public Iterator<Entry<K, V>> iterator() {
- return entryIterator();
+ public V previous() {
+ return getDelegateListIterator().previous();
}
- };
+
+ @Override
+ public int nextIndex() {
+ return getDelegateListIterator().nextIndex();
+ }
+
+ @Override
+ public int previousIndex() {
+ return getDelegateListIterator().previousIndex();
+ }
+
+ @Override
+ public void set(V value) {
+ getDelegateListIterator().set(value);
+ }
+
+ @Override
+ public void add(V value) {
+ boolean wasEmpty = isEmpty();
+ getDelegateListIterator().add(value);
+ totalSize++;
+ if (wasEmpty) {
+ addToMap();
+ }
+ }
+ }
+ }
+
+ /**
+ * List decorator that stays in sync with the multimap values for a key and
+ * supports rapid random access.
+ */
+ private class RandomAccessWrappedList extends WrappedList
+ implements RandomAccess {
+ RandomAccessWrappedList(@Nullable K key, List<V> delegate,
+ @Nullable WrappedCollection ancestor) {
+ super(key, delegate, ancestor);
+ }
}
-
- abstract Iterator<Entry<K, V>> entryIterator();
private transient Set<K> keySet;
@@ -136,48 +867,484 @@ abstract class AbstractMultimap<K, V> implements Multimap<K, V> {
return (result == null) ? keySet = createKeySet() : result;
}
- Set<K> createKeySet() {
- return new Maps.KeySet<K, Collection<V>>() {
- @Override
- Map<K, Collection<V>> map() {
- return asMap();
+ private Set<K> createKeySet() {
+ return (map instanceof SortedMap)
+ ? new SortedKeySet((SortedMap<K, Collection<V>>) map) : new KeySet(map);
+ }
+
+ private class KeySet extends Maps.KeySet<K, Collection<V>> {
+
+ /**
+ * This is usually the same as map, except when someone requests a
+ * subcollection of a {@link SortedKeySet}.
+ */
+ final Map<K, Collection<V>> subMap;
+
+ KeySet(final Map<K, Collection<V>> subMap) {
+ this.subMap = subMap;
+ }
+
+ @Override
+ Map<K, Collection<V>> map() {
+ return subMap;
+ }
+
+ @Override public Iterator<K> iterator() {
+ return new Iterator<K>() {
+ final Iterator<Map.Entry<K, Collection<V>>> entryIterator
+ = subMap.entrySet().iterator();
+ Map.Entry<K, Collection<V>> entry;
+
+ @Override
+ public boolean hasNext() {
+ return entryIterator.hasNext();
+ }
+ @Override
+ public K next() {
+ entry = entryIterator.next();
+ return entry.getKey();
+ }
+ @Override
+ public void remove() {
+ checkState(entry != null);
+ Collection<V> collection = entry.getValue();
+ entryIterator.remove();
+ totalSize -= collection.size();
+ collection.clear();
+ }
+ };
+ }
+
+ // The following methods are included for better performance.
+
+ @Override public boolean remove(Object key) {
+ int count = 0;
+ Collection<V> collection = subMap.remove(key);
+ if (collection != null) {
+ count = collection.size();
+ collection.clear();
+ totalSize -= count;
}
- };
+ return count > 0;
+ }
+
+ @Override
+ public void clear() {
+ Iterators.clear(iterator());
+ }
+
+ @Override public boolean containsAll(Collection<?> c) {
+ return subMap.keySet().containsAll(c);
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ return this == object || this.subMap.keySet().equals(object);
+ }
+
+ @Override public int hashCode() {
+ return subMap.keySet().hashCode();
+ }
+ }
+
+ private class SortedKeySet extends KeySet implements SortedSet<K> {
+
+ SortedKeySet(SortedMap<K, Collection<V>> subMap) {
+ super(subMap);
+ }
+
+ SortedMap<K, Collection<V>> sortedMap() {
+ return (SortedMap<K, Collection<V>>) subMap;
+ }
+
+ @Override
+ public Comparator<? super K> comparator() {
+ return sortedMap().comparator();
+ }
+
+ @Override
+ public K first() {
+ return sortedMap().firstKey();
+ }
+
+ @Override
+ public SortedSet<K> headSet(K toElement) {
+ return new SortedKeySet(sortedMap().headMap(toElement));
+ }
+
+ @Override
+ public K last() {
+ return sortedMap().lastKey();
+ }
+
+ @Override
+ public SortedSet<K> subSet(K fromElement, K toElement) {
+ return new SortedKeySet(sortedMap().subMap(fromElement, toElement));
+ }
+
+ @Override
+ public SortedSet<K> tailSet(K fromElement) {
+ return new SortedKeySet(sortedMap().tailMap(fromElement));
+ }
}
-
- private transient Multiset<K> keys;
-
+
+ private transient Multiset<K> multiset;
+
@Override
public Multiset<K> keys() {
- Multiset<K> result = keys;
- return (result == null) ? keys = createKeys() : result;
+ Multiset<K> result = multiset;
+ if (result == null) {
+ return multiset = new Multimaps.Keys<K, V>() {
+ @Override Multimap<K, V> multimap() {
+ return AbstractMultimap.this;
+ }
+ };
+ }
+ return result;
}
-
- Multiset<K> createKeys() {
- return new Multimaps.Keys<K, V>(this);
+
+ /**
+ * Removes all values for the provided key. Unlike {@link #removeAll}, it
+ * returns the number of removed mappings.
+ */
+ private int removeValuesForKey(Object key) {
+ Collection<V> collection;
+ try {
+ collection = map.remove(key);
+ } catch (NullPointerException e) {
+ return 0;
+ } catch (ClassCastException e) {
+ return 0;
+ }
+
+ int count = 0;
+ if (collection != null) {
+ count = collection.size();
+ collection.clear();
+ totalSize -= count;
+ }
+ return count;
}
-
- private transient Collection<V> values;
-
+
+ private transient Collection<V> valuesCollection;
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The iterator generated by the returned collection traverses the values
+ * for one key, followed by the values of a second key, and so on.
+ */
+ @Override public Collection<V> values() {
+ Collection<V> result = valuesCollection;
+ if (result == null) {
+ return valuesCollection = new Multimaps.Values<K, V>() {
+ @Override Multimap<K, V> multimap() {
+ return AbstractMultimap.this;
+ }
+ };
+ }
+ return result;
+ }
+
+ private transient Collection<Map.Entry<K, V>> entries;
+
+ /*
+ * TODO(kevinb): should we copy this javadoc to each concrete class, so that
+ * classes like LinkedHashMultimap that need to say something different are
+ * still able to {@inheritDoc} all the way from Multimap?
+ */
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The iterator generated by the returned collection traverses the values
+ * for one key, followed by the values of a second key, and so on.
+ *
+ * <p>Each entry is an immutable snapshot of a key-value mapping in the
+ * multimap, taken at the time the entry is returned by a method call to the
+ * collection or its iterator.
+ */
@Override
- public Collection<V> values() {
- Collection<V> result = values;
- return (result == null) ? values = createValues() : result;
+ public Collection<Map.Entry<K, V>> entries() {
+ Collection<Map.Entry<K, V>> result = entries;
+ return (result == null) ? entries = createEntries() : result;
}
-
- Collection<V> createValues() {
- return new Multimaps.Values<K, V>(this);
+
+ Collection<Map.Entry<K, V>> createEntries() {
+ if (this instanceof SetMultimap) {
+ return new Multimaps.EntrySet<K, V>() {
+ @Override Multimap<K, V> multimap() {
+ return AbstractMultimap.this;
+ }
+
+ @Override public Iterator<Entry<K, V>> iterator() {
+ return createEntryIterator();
+ }
+ };
+ }
+ return new Multimaps.Entries<K, V>() {
+ @Override Multimap<K, V> multimap() {
+ return AbstractMultimap.this;
+ }
+
+ @Override public Iterator<Entry<K, V>> iterator() {
+ return createEntryIterator();
+ }
+ };
}
-
+
+ /**
+ * Returns an iterator across all key-value map entries, used by {@code
+ * entries().iterator()} and {@code values().iterator()}. The default
+ * behavior, which traverses the values for one key, the values for a second
+ * key, and so on, suffices for most {@code AbstractMultimap} implementations.
+ *
+ * @return an iterator across map entries
+ */
+ Iterator<Map.Entry<K, V>> createEntryIterator() {
+ return new EntryIterator();
+ }
+
+ /** Iterator across all key-value pairs. */
+ private class EntryIterator implements Iterator<Map.Entry<K, V>> {
+ final Iterator<Map.Entry<K, Collection<V>>> keyIterator;
+ K key;
+ Collection<V> collection;
+ Iterator<V> valueIterator;
+
+ EntryIterator() {
+ keyIterator = map.entrySet().iterator();
+ if (keyIterator.hasNext()) {
+ findValueIteratorAndKey();
+ } else {
+ valueIterator = Iterators.emptyModifiableIterator();
+ }
+ }
+
+ void findValueIteratorAndKey() {
+ Map.Entry<K, Collection<V>> entry = keyIterator.next();
+ key = entry.getKey();
+ collection = entry.getValue();
+ valueIterator = collection.iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return keyIterator.hasNext() || valueIterator.hasNext();
+ }
+
+ @Override
+ public Map.Entry<K, V> next() {
+ if (!valueIterator.hasNext()) {
+ findValueIteratorAndKey();
+ }
+ return Maps.immutableEntry(key, valueIterator.next());
+ }
+
+ @Override
+ public void remove() {
+ valueIterator.remove();
+ if (collection.isEmpty()) {
+ keyIterator.remove();
+ }
+ totalSize--;
+ }
+ }
+
private transient Map<K, Collection<V>> asMap;
-
+
@Override
public Map<K, Collection<V>> asMap() {
Map<K, Collection<V>> result = asMap;
return (result == null) ? asMap = createAsMap() : result;
}
-
- abstract Map<K, Collection<V>> createAsMap();
+
+ private Map<K, Collection<V>> createAsMap() {
+ return (map instanceof SortedMap)
+ ? new SortedAsMap((SortedMap<K, Collection<V>>) map) : new AsMap(map);
+ }
+
+ private class AsMap extends AbstractMap<K, Collection<V>> {
+ /**
+ * Usually the same as map, but smaller for the headMap(), tailMap(), or
+ * subMap() of a SortedAsMap.
+ */
+ final transient Map<K, Collection<V>> submap;
+
+ AsMap(Map<K, Collection<V>> submap) {
+ this.submap = submap;
+ }
+
+ transient Set<Map.Entry<K, Collection<V>>> entrySet;
+
+ @Override public Set<Map.Entry<K, Collection<V>>> entrySet() {
+ Set<Map.Entry<K, Collection<V>>> result = entrySet;
+ return (result == null) ? entrySet = new AsMapEntries() : result;
+ }
+
+ // The following methods are included for performance.
+
+ @Override public boolean containsKey(Object key) {
+ return Maps.safeContainsKey(submap, key);
+ }
+
+ @Override public Collection<V> get(Object key) {
+ Collection<V> collection = Maps.safeGet(submap, key);
+ if (collection == null) {
+ return null;
+ }
+ @SuppressWarnings("unchecked")
+ K k = (K) key;
+ return wrapCollection(k, collection);
+ }
+
+ @Override public Set<K> keySet() {
+ return AbstractMultimap.this.keySet();
+ }
+
+ @Override
+ public int size() {
+ return submap.size();
+ }
+
+ @Override public Collection<V> remove(Object key) {
+ Collection<V> collection = submap.remove(key);
+ if (collection == null) {
+ return null;
+ }
+
+ Collection<V> output = createCollection();
+ output.addAll(collection);
+ totalSize -= collection.size();
+ collection.clear();
+ return output;
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ return this == object || submap.equals(object);
+ }
+
+ @Override public int hashCode() {
+ return submap.hashCode();
+ }
+
+ @Override public String toString() {
+ return submap.toString();
+ }
+
+ @Override
+ public void clear() {
+ if (submap == map) {
+ AbstractMultimap.this.clear();
+ } else {
+
+ Iterators.clear(new AsMapIterator());
+ }
+ }
+
+ class AsMapEntries extends Maps.EntrySet<K, Collection<V>> {
+ @Override
+ Map<K, Collection<V>> map() {
+ return AsMap.this;
+ }
+
+ @Override public Iterator<Map.Entry<K, Collection<V>>> iterator() {
+ return new AsMapIterator();
+ }
+
+ // The following methods are included for performance.
+
+ @Override public boolean contains(Object o) {
+ return Collections2.safeContains(submap.entrySet(), o);
+ }
+
+ @Override public boolean remove(Object o) {
+ if (!contains(o)) {
+ return false;
+ }
+ Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
+ removeValuesForKey(entry.getKey());
+ return true;
+ }
+ }
+
+ /** Iterator across all keys and value collections. */
+ class AsMapIterator implements Iterator<Map.Entry<K, Collection<V>>> {
+ final Iterator<Map.Entry<K, Collection<V>>> delegateIterator
+ = submap.entrySet().iterator();
+ Collection<V> collection;
+
+ @Override
+ public boolean hasNext() {
+ return delegateIterator.hasNext();
+ }
+
+ @Override
+ public Map.Entry<K, Collection<V>> next() {
+ Map.Entry<K, Collection<V>> entry = delegateIterator.next();
+ K key = entry.getKey();
+ collection = entry.getValue();
+ return Maps.immutableEntry(key, wrapCollection(key, collection));
+ }
+
+ @Override
+ public void remove() {
+ delegateIterator.remove();
+ totalSize -= collection.size();
+ collection.clear();
+ }
+ }
+ }
+
+ private class SortedAsMap extends AsMap
+ implements SortedMap<K, Collection<V>> {
+ SortedAsMap(SortedMap<K, Collection<V>> submap) {
+ super(submap);
+ }
+
+ SortedMap<K, Collection<V>> sortedMap() {
+ return (SortedMap<K, Collection<V>>) submap;
+ }
+
+ @Override
+ public Comparator<? super K> comparator() {
+ return sortedMap().comparator();
+ }
+
+ @Override
+ public K firstKey() {
+ return sortedMap().firstKey();
+ }
+
+ @Override
+ public K lastKey() {
+ return sortedMap().lastKey();
+ }
+
+ @Override
+ public SortedMap<K, Collection<V>> headMap(K toKey) {
+ return new SortedAsMap(sortedMap().headMap(toKey));
+ }
+
+ @Override
+ public SortedMap<K, Collection<V>> subMap(K fromKey, K toKey) {
+ return new SortedAsMap(sortedMap().subMap(fromKey, toKey));
+ }
+
+ @Override
+ public SortedMap<K, Collection<V>> tailMap(K fromKey) {
+ return new SortedAsMap(sortedMap().tailMap(fromKey));
+ }
+
+ SortedSet<K> sortedKeySet;
+
+ // returns a SortedSet, even though returning a Set would be sufficient to
+ // satisfy the SortedMap.keySet() interface
+ @Override public SortedSet<K> keySet() {
+ SortedSet<K> result = sortedKeySet;
+ return (result == null)
+ ? sortedKeySet = new SortedKeySet(sortedMap()) : result;
+ }
+ }
// Comparison and hashing
@@ -187,7 +1354,7 @@ abstract class AbstractMultimap<K, V> implements Multimap<K, V> {
}
if (object instanceof Multimap) {
Multimap<?, ?> that = (Multimap<?, ?>) object;
- return this.asMap().equals(that.asMap());
+ return this.map.equals(that.asMap());
}
return false;
}
@@ -201,7 +1368,7 @@ abstract class AbstractMultimap<K, V> implements Multimap<K, V> {
* @see Map#hashCode
*/
@Override public int hashCode() {
- return asMap().hashCode();
+ return map.hashCode();
}
/**
@@ -212,6 +1379,9 @@ abstract class AbstractMultimap<K, V> implements Multimap<K, V> {
*/
@Override
public String toString() {
- return asMap().toString();
+ return map.toString();
}
+
+ private static final long serialVersionUID = 2447537837011683357L;
}
+
diff --git a/guava/src/com/google/common/collect/AbstractMultiset.java b/guava/src/com/google/common/collect/AbstractMultiset.java
index 20ea93f..c0d2c4a 100644
--- a/guava/src/com/google/common/collect/AbstractMultiset.java
+++ b/guava/src/com/google/common/collect/AbstractMultiset.java
@@ -65,7 +65,7 @@ abstract class AbstractMultiset<E> extends AbstractCollection<E>
}
@Override
- public int count(@Nullable Object element) {
+ public int count(Object element) {
for (Entry<E> entry : entrySet()) {
if (Objects.equal(entry.getElement(), element)) {
return entry.getCount();
@@ -82,26 +82,26 @@ abstract class AbstractMultiset<E> extends AbstractCollection<E>
}
@Override
- public int add(@Nullable E element, int occurrences) {
+ public int add(E element, int occurrences) {
throw new UnsupportedOperationException();
}
- @Override public boolean remove(@Nullable Object element) {
+ @Override public boolean remove(Object element) {
return remove(element, 1) > 0;
}
@Override
- public int remove(@Nullable Object element, int occurrences) {
+ public int remove(Object element, int occurrences) {
throw new UnsupportedOperationException();
}
@Override
- public int setCount(@Nullable E element, int count) {
+ public int setCount(E element, int count) {
return setCountImpl(this, element, count);
}
@Override
- public boolean setCount(@Nullable E element, int oldCount, int newCount) {
+ public boolean setCount(E element, int oldCount, int newCount) {
return setCountImpl(this, element, oldCount, newCount);
}
@@ -109,7 +109,7 @@ abstract class AbstractMultiset<E> extends AbstractCollection<E>
/**
* {@inheritDoc}
- *
+ *
* <p>This implementation is highly efficient when {@code elementsToAdd}
* is itself a {@link Multiset}.
*/
@@ -158,11 +158,11 @@ abstract class AbstractMultiset<E> extends AbstractCollection<E>
}
abstract Iterator<Entry<E>> entryIterator();
-
+
abstract int distinctElements();
private transient Set<Entry<E>> entrySet;
-
+
@Override public Set<Entry<E>> entrySet() {
Set<Entry<E>> result = entrySet;
return (result == null) ? entrySet = createEntrySet() : result;
diff --git a/guava/src/com/google/common/collect/AbstractNavigableMap.java b/guava/src/com/google/common/collect/AbstractNavigableMap.java
deleted file mode 100644
index f6defe6..0000000
--- a/guava/src/com/google/common/collect/AbstractNavigableMap.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import java.util.AbstractMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.NavigableMap;
-import java.util.NavigableSet;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.SortedMap;
-
-import javax.annotation.Nullable;
-
-/**
- * Skeletal implementation of {@link NavigableMap}.
- *
- * @author Louis Wasserman
- */
-abstract class AbstractNavigableMap<K, V> extends AbstractMap<K, V> implements NavigableMap<K, V> {
-
- @Override
- @Nullable
- public abstract V get(@Nullable Object key);
-
- @Override
- @Nullable
- public Entry<K, V> firstEntry() {
- return Iterators.getNext(entryIterator(), null);
- }
-
- @Override
- @Nullable
- public Entry<K, V> lastEntry() {
- return Iterators.getNext(descendingEntryIterator(), null);
- }
-
- @Override
- @Nullable
- public Entry<K, V> pollFirstEntry() {
- return Iterators.pollNext(entryIterator());
- }
-
- @Override
- @Nullable
- public Entry<K, V> pollLastEntry() {
- return Iterators.pollNext(descendingEntryIterator());
- }
-
- @Override
- public K firstKey() {
- Entry<K, V> entry = firstEntry();
- if (entry == null) {
- throw new NoSuchElementException();
- } else {
- return entry.getKey();
- }
- }
-
- @Override
- public K lastKey() {
- Entry<K, V> entry = lastEntry();
- if (entry == null) {
- throw new NoSuchElementException();
- } else {
- return entry.getKey();
- }
- }
-
- @Override
- @Nullable
- public Entry<K, V> lowerEntry(K key) {
- return headMap(key, false).lastEntry();
- }
-
- @Override
- @Nullable
- public Entry<K, V> floorEntry(K key) {
- return headMap(key, true).lastEntry();
- }
-
- @Override
- @Nullable
- public Entry<K, V> ceilingEntry(K key) {
- return tailMap(key, true).firstEntry();
- }
-
- @Override
- @Nullable
- public Entry<K, V> higherEntry(K key) {
- return tailMap(key, false).firstEntry();
- }
-
- @Override
- public K lowerKey(K key) {
- return Maps.keyOrNull(lowerEntry(key));
- }
-
- @Override
- public K floorKey(K key) {
- return Maps.keyOrNull(floorEntry(key));
- }
-
- @Override
- public K ceilingKey(K key) {
- return Maps.keyOrNull(ceilingEntry(key));
- }
-
- @Override
- public K higherKey(K key) {
- return Maps.keyOrNull(higherEntry(key));
- }
-
- abstract Iterator<Entry<K, V>> entryIterator();
-
- abstract Iterator<Entry<K, V>> descendingEntryIterator();
-
- @Override
- public SortedMap<K, V> subMap(K fromKey, K toKey) {
- return subMap(fromKey, true, toKey, false);
- }
-
- @Override
- public SortedMap<K, V> headMap(K toKey) {
- return headMap(toKey, false);
- }
-
- @Override
- public SortedMap<K, V> tailMap(K fromKey) {
- return tailMap(fromKey, true);
- }
-
- @Override
- public NavigableSet<K> navigableKeySet() {
- return new Maps.NavigableKeySet<K, V>(this);
- }
-
- @Override
- public Set<K> keySet() {
- return navigableKeySet();
- }
-
- @Override
- public abstract int size();
-
- @Override
- public Set<Entry<K, V>> entrySet() {
- return new Maps.EntrySet<K, V>() {
- @Override
- Map<K, V> map() {
- return AbstractNavigableMap.this;
- }
-
- @Override
- public Iterator<Entry<K, V>> iterator() {
- return entryIterator();
- }
- };
- }
-
- @Override
- public NavigableSet<K> descendingKeySet() {
- return descendingMap().navigableKeySet();
- }
-
- @Override
- public NavigableMap<K, V> descendingMap() {
- return new DescendingMap();
- }
-
- private final class DescendingMap extends Maps.DescendingMap<K, V> {
- @Override
- NavigableMap<K, V> forward() {
- return AbstractNavigableMap.this;
- }
-
- @Override
- Iterator<Entry<K, V>> entryIterator() {
- return descendingEntryIterator();
- }
- }
-
-}
diff --git a/guava/src/com/google/common/collect/AbstractRangeSet.java b/guava/src/com/google/common/collect/AbstractRangeSet.java
deleted file mode 100644
index e02f5da..0000000
--- a/guava/src/com/google/common/collect/AbstractRangeSet.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2011 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import javax.annotation.Nullable;
-
-/**
- * A skeletal implementation of {@code RangeSet}.
- *
- * @author Louis Wasserman
- */
-abstract class AbstractRangeSet<C extends Comparable> implements RangeSet<C> {
- AbstractRangeSet() {}
-
- @Override
- public boolean contains(C value) {
- return rangeContaining(value) != null;
- }
-
- @Override
- public Range<C> rangeContaining(C value) {
- checkNotNull(value);
- for (Range<C> range : asRanges()) {
- if (range.contains(value)) {
- return range;
- }
- }
- return null;
- }
-
- @Override
- public boolean isEmpty() {
- return asRanges().isEmpty();
- }
-
- @Override
- public void add(Range<C> range) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void remove(Range<C> range) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void clear() {
- remove(Range.<C>all());
- }
-
- @Override
- public boolean enclosesAll(RangeSet<C> other) {
- for (Range<C> range : other.asRanges()) {
- if (!encloses(range)) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public void addAll(RangeSet<C> other) {
- for (Range<C> range : other.asRanges()) {
- add(range);
- }
- }
-
- @Override
- public void removeAll(RangeSet<C> other) {
- for (Range<C> range : other.asRanges()) {
- remove(range);
- }
- }
-
- @Override
- public boolean encloses(Range<C> otherRange) {
- for (Range<C> range : asRanges()) {
- if (range.encloses(otherRange)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (obj instanceof RangeSet) {
- RangeSet<?> other = (RangeSet<?>) obj;
- return this.asRanges().equals(other.asRanges());
- }
- return false;
- }
-
- @Override
- public final int hashCode() {
- return asRanges().hashCode();
- }
-
- @Override
- public final String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append('{');
- for (Range<C> range : asRanges()) {
- builder.append(range);
- }
- builder.append('}');
- return builder.toString();
- }
-}
diff --git a/guava/src/com/google/common/collect/AbstractSetMultimap.java b/guava/src/com/google/common/collect/AbstractSetMultimap.java
index e43d8b1..fe68470 100644
--- a/guava/src/com/google/common/collect/AbstractSetMultimap.java
+++ b/guava/src/com/google/common/collect/AbstractSetMultimap.java
@@ -26,14 +26,14 @@ import javax.annotation.Nullable;
/**
* Basic implementation of the {@link SetMultimap} interface. It's a wrapper
- * around {@link AbstractMapBasedMultimap} that converts the returned collections into
+ * around {@link AbstractMultimap} that converts the returned collections into
* {@code Sets}. The {@link #createCollection} method must return a {@code Set}.
*
* @author Jared Levy
*/
@GwtCompatible
abstract class AbstractSetMultimap<K, V>
- extends AbstractMapBasedMultimap<K, V> implements SetMultimap<K, V> {
+ extends AbstractMultimap<K, V> implements SetMultimap<K, V> {
/**
* Creates a new multimap that uses the provided map.
*
@@ -46,10 +46,6 @@ abstract class AbstractSetMultimap<K, V>
@Override abstract Set<V> createCollection();
- @Override Set<V> createUnmodifiableEmptyCollection() {
- return ImmutableSet.of();
- }
-
// Following Javadoc copied from SetMultimap.
/**
@@ -117,7 +113,7 @@ abstract class AbstractSetMultimap<K, V>
* @return {@code true} if the method increased the size of the multimap, or
* {@code false} if the multimap already contained the key-value pair
*/
- @Override public boolean put(@Nullable K key, @Nullable V value) {
+ @Override public boolean put(K key, V value) {
return super.put(key, value);
}
diff --git a/guava/src/com/google/common/collect/AbstractSortedKeySortedSetMultimap.java b/guava/src/com/google/common/collect/AbstractSortedKeySortedSetMultimap.java
deleted file mode 100644
index c561b87..0000000
--- a/guava/src/com/google/common/collect/AbstractSortedKeySortedSetMultimap.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.Collection;
-import java.util.SortedMap;
-import java.util.SortedSet;
-
-/**
- * Basic implementation of a {@link SortedSetMultimap} with a sorted key set.
- *
- * This superclass allows {@code TreeMultimap} to override methods to return
- * navigable set and map types in non-GWT only, while GWT code will inherit the
- * SortedMap/SortedSet overrides.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible
-abstract class AbstractSortedKeySortedSetMultimap<K, V> extends AbstractSortedSetMultimap<K, V> {
-
- AbstractSortedKeySortedSetMultimap(SortedMap<K, Collection<V>> map) {
- super(map);
- }
-
- @Override
- public SortedMap<K, Collection<V>> asMap() {
- return (SortedMap<K, Collection<V>>) super.asMap();
- }
-
- @Override
- SortedMap<K, Collection<V>> backingMap() {
- return (SortedMap<K, Collection<V>>) super.backingMap();
- }
-
- @Override
- public SortedSet<K> keySet() {
- return (SortedSet<K>) super.keySet();
- }
-
-}
diff --git a/guava/src/com/google/common/collect/AbstractSortedMultiset.java b/guava/src/com/google/common/collect/AbstractSortedMultiset.java
index 7c277f8..b1a1d54 100644
--- a/guava/src/com/google/common/collect/AbstractSortedMultiset.java
+++ b/guava/src/com/google/common/collect/AbstractSortedMultiset.java
@@ -1,11 +1,11 @@
/*
* Copyright (C) 2011 The Guava Authors
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
@@ -20,9 +20,7 @@ import com.google.common.annotations.GwtCompatible;
import java.util.Comparator;
import java.util.Iterator;
-import java.util.NavigableSet;
-
-import javax.annotation.Nullable;
+import java.util.SortedSet;
/**
* This class provides a skeletal implementation of the {@link SortedMultiset} interface.
@@ -33,28 +31,33 @@ import javax.annotation.Nullable;
*
* @author Louis Wasserman
*/
-@GwtCompatible(emulated = true)
+@GwtCompatible
abstract class AbstractSortedMultiset<E> extends AbstractMultiset<E> implements SortedMultiset<E> {
- @GwtTransient final Comparator<? super E> comparator;
+ final Comparator<? super E> comparator;
// needed for serialization
@SuppressWarnings("unchecked")
AbstractSortedMultiset() {
this((Comparator) Ordering.natural());
}
-
+
AbstractSortedMultiset(Comparator<? super E> comparator) {
this.comparator = checkNotNull(comparator);
}
@Override
- public NavigableSet<E> elementSet() {
- return (NavigableSet<E>) super.elementSet();
+ public SortedSet<E> elementSet() {
+ return (SortedSet<E>) super.elementSet();
}
@Override
- NavigableSet<E> createElementSet() {
- return new SortedMultisets.NavigableElementSet<E>(this);
+ SortedSet<E> createElementSet() {
+ return new SortedMultisets.ElementSet<E>() {
+ @Override
+ SortedMultiset<E> multiset() {
+ return AbstractSortedMultiset.this;
+ }
+ };
}
@Override
@@ -99,11 +102,8 @@ abstract class AbstractSortedMultiset<E> extends AbstractMultiset<E> implements
}
@Override
- public SortedMultiset<E> subMultiset(@Nullable E fromElement, BoundType fromBoundType,
- @Nullable E toElement, BoundType toBoundType) {
- // These are checked elsewhere, but NullPointerTester wants them checked eagerly.
- checkNotNull(fromBoundType);
- checkNotNull(toBoundType);
+ public SortedMultiset<E> subMultiset(E fromElement, BoundType fromBoundType, E toElement,
+ BoundType toBoundType) {
return tailMultiset(fromElement, fromBoundType).headMultiset(toElement, toBoundType);
}
@@ -122,7 +122,7 @@ abstract class AbstractSortedMultiset<E> extends AbstractMultiset<E> implements
}
SortedMultiset<E> createDescendingMultiset() {
- return new DescendingMultiset<E>() {
+ return new SortedMultisets.DescendingMultiset<E>() {
@Override
SortedMultiset<E> forwardMultiset() {
return AbstractSortedMultiset.this;
diff --git a/guava/src/com/google/common/collect/AbstractSortedSetMultimap.java b/guava/src/com/google/common/collect/AbstractSortedSetMultimap.java
index ac74155..2be5f4b 100644
--- a/guava/src/com/google/common/collect/AbstractSortedSetMultimap.java
+++ b/guava/src/com/google/common/collect/AbstractSortedSetMultimap.java
@@ -19,8 +19,6 @@ package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.Map;
import java.util.SortedSet;
@@ -28,7 +26,7 @@ import javax.annotation.Nullable;
/**
* Basic implementation of the {@link SortedSetMultimap} interface. It's a
- * wrapper around {@link AbstractMapBasedMultimap} that converts the returned
+ * wrapper around {@link AbstractMultimap} that converts the returned
* collections into sorted sets. The {@link #createCollection} method
* must return a {@code SortedSet}.
*
@@ -47,18 +45,7 @@ abstract class AbstractSortedSetMultimap<K, V>
super(map);
}
- @Override
- abstract SortedSet<V> createCollection();
-
- @Override
- SortedSet<V> createUnmodifiableEmptyCollection() {
- Comparator<? super V> comparator = valueComparator();
- if (comparator == null) {
- return Collections.unmodifiableSortedSet(createCollection());
- } else {
- return ImmutableSortedSet.emptySet(valueComparator());
- }
- }
+ @Override abstract SortedSet<V> createCollection();
// Following Javadoc copied from Multimap and SortedSetMultimap.
@@ -101,7 +88,7 @@ abstract class AbstractSortedSetMultimap<K, V>
* <p>Any duplicates in {@code values} will be stored in the multimap once.
*/
@Override public SortedSet<V> replaceValues(
- @Nullable K key, Iterable<? extends V> values) {
+ K key, Iterable<? extends V> values) {
return (SortedSet<V>) super.replaceValues(key, values);
}
diff --git a/guava/src/com/google/common/collect/AllEqualOrdering.java b/guava/src/com/google/common/collect/AllEqualOrdering.java
deleted file mode 100644
index c30164b..0000000
--- a/guava/src/com/google/common/collect/AllEqualOrdering.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.io.Serializable;
-import java.util.List;
-
-import javax.annotation.Nullable;
-
-/**
- * An ordering that treats all references as equals, even nulls.
- *
- * @author Emily Soldal
- */
-@GwtCompatible(serializable = true)
-final class AllEqualOrdering extends Ordering<Object> implements Serializable {
- static final AllEqualOrdering INSTANCE = new AllEqualOrdering();
-
- @Override
- public int compare(@Nullable Object left, @Nullable Object right) {
- return 0;
- }
-
- @Override
- public <E> List<E> sortedCopy(Iterable<E> iterable) {
- return Lists.newArrayList(iterable);
- }
-
- @Override
- public <E> ImmutableList<E> immutableSortedCopy(Iterable<E> iterable) {
- return ImmutableList.copyOf(iterable);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public <S> Ordering<S> reverse() {
- return (Ordering<S>) this;
- }
-
- private Object readResolve() {
- return INSTANCE;
- }
-
- @Override
- public String toString() {
- return "Ordering.allEqual()";
- }
-
- private static final long serialVersionUID = 0;
-}
diff --git a/guava/src/com/google/common/collect/ArrayListMultimap.java b/guava/src/com/google/common/collect/ArrayListMultimap.java
index 759c073..43d42c3 100644
--- a/guava/src/com/google/common/collect/ArrayListMultimap.java
+++ b/guava/src/com/google/common/collect/ArrayListMultimap.java
@@ -55,10 +55,6 @@ import java.util.Map;
* multimap. Concurrent read operations will work correctly. To allow concurrent
* update operations, wrap your multimap with a call to {@link
* Multimaps#synchronizedListMultimap}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap">
- * {@code Multimap}</a>.
*
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
@@ -66,7 +62,7 @@ import java.util.Map;
@GwtCompatible(serializable = true, emulated = true)
public final class ArrayListMultimap<K, V> extends AbstractListMultimap<K, V> {
// Default from ArrayList
- private static final int DEFAULT_VALUES_PER_KEY = 3;
+ private static final int DEFAULT_VALUES_PER_KEY = 10;
@VisibleForTesting transient int expectedValuesPerKey;
diff --git a/guava/src/com/google/common/collect/ArrayTable.java b/guava/src/com/google/common/collect/ArrayTable.java
index 554265c..28eb5b8 100644
--- a/guava/src/com/google/common/collect/ArrayTable.java
+++ b/guava/src/com/google/common/collect/ArrayTable.java
@@ -17,23 +17,21 @@
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkElementIndex;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Objects;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.AbstractCollection;
+import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import javax.annotation.Nullable;
@@ -76,15 +74,10 @@ import javax.annotation.Nullable;
* implementations, synchronization is unnecessary between a thread that writes
* to one cell and a thread that reads from another.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table">
- * {@code Table}</a>.
- *
* @author Jared Levy
* @since 10.0
*/
@Beta
-@GwtCompatible(emulated = true)
public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
/**
@@ -162,23 +155,22 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
* columnKeys is empty but rowKeys isn't, the table is empty but
* containsRow() can return true and rowKeySet() isn't empty.
*/
- rowKeyToIndex = index(rowList);
- columnKeyToIndex = index(columnList);
+ ImmutableMap.Builder<R, Integer> rowBuilder = ImmutableMap.builder();
+ for (int i = 0; i < rowList.size(); i++) {
+ rowBuilder.put(rowList.get(i), i);
+ }
+ rowKeyToIndex = rowBuilder.build();
+
+ ImmutableMap.Builder<C, Integer> columnBuilder = ImmutableMap.builder();
+ for (int i = 0; i < columnList.size(); i++) {
+ columnBuilder.put(columnList.get(i), i);
+ }
+ columnKeyToIndex = columnBuilder.build();
@SuppressWarnings("unchecked")
V[][] tmpArray
= (V[][]) new Object[rowList.size()][columnList.size()];
array = tmpArray;
- // Necessary because in GWT the arrays are initialized with "undefined" instead of null.
- eraseAll();
- }
-
- private static <E> ImmutableMap<E, Integer> index(List<E> list) {
- ImmutableMap.Builder<E, Integer> columnBuilder = ImmutableMap.builder();
- for (int i = 0; i < list.size(); i++) {
- columnBuilder.put(list.get(i), i);
- }
- return columnBuilder.build();
}
private ArrayTable(Table<R, C, V> table) {
@@ -194,116 +186,11 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
@SuppressWarnings("unchecked")
V[][] copy = (V[][]) new Object[rowList.size()][columnList.size()];
array = copy;
- // Necessary because in GWT the arrays are initialized with "undefined" instead of null.
- eraseAll();
for (int i = 0; i < rowList.size(); i++) {
System.arraycopy(table.array[i], 0, copy[i], 0, table.array[i].length);
}
}
- private abstract static class ArrayMap<K, V> extends Maps.ImprovedAbstractMap<K, V> {
- private final ImmutableMap<K, Integer> keyIndex;
-
- private ArrayMap(ImmutableMap<K, Integer> keyIndex) {
- this.keyIndex = keyIndex;
- }
-
- @Override
- public Set<K> keySet() {
- return keyIndex.keySet();
- }
-
- K getKey(int index) {
- return keyIndex.keySet().asList().get(index);
- }
-
- abstract String getKeyRole();
-
- @Nullable abstract V getValue(int index);
-
- @Nullable abstract V setValue(int index, V newValue);
-
- @Override
- public int size() {
- return keyIndex.size();
- }
-
- @Override
- public boolean isEmpty() {
- return keyIndex.isEmpty();
- }
-
- @Override
- protected Set<Entry<K, V>> createEntrySet() {
- return new Maps.EntrySet<K, V>() {
- @Override
- Map<K, V> map() {
- return ArrayMap.this;
- }
-
- @Override
- public Iterator<Entry<K, V>> iterator() {
- return new AbstractIndexedListIterator<Entry<K, V>>(size()) {
- @Override
- protected Entry<K, V> get(final int index) {
- return new AbstractMapEntry<K, V>() {
- @Override
- public K getKey() {
- return ArrayMap.this.getKey(index);
- }
-
- @Override
- public V getValue() {
- return ArrayMap.this.getValue(index);
- }
-
- @Override
- public V setValue(V value) {
- return ArrayMap.this.setValue(index, value);
- }
- };
- }
- };
- }
- };
- }
-
- @Override
- public boolean containsKey(@Nullable Object key) {
- return keyIndex.containsKey(key);
- }
-
- @Override
- public V get(@Nullable Object key) {
- Integer index = keyIndex.get(key);
- if (index == null) {
- return null;
- } else {
- return getValue(index);
- }
- }
-
- @Override
- public V put(K key, V value) {
- Integer index = keyIndex.get(key);
- if (index == null) {
- throw new IllegalArgumentException(
- getKeyRole() + " " + key + " not in " + keyIndex.keySet());
- }
- return setValue(index, value);
- }
-
- @Override
- public V remove(Object key) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void clear() {
- throw new UnsupportedOperationException();
- }
- }
-
/**
* Returns, as an immutable list, the row keys provided when the table was
* constructed, including those that are mapped to null values only.
@@ -335,9 +222,6 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
* allowed column keys
*/
public V at(int rowIndex, int columnIndex) {
- // In GWT array access never throws IndexOutOfBoundsException.
- checkElementIndex(rowIndex, rowList.size());
- checkElementIndex(columnIndex, columnList.size());
return array[rowIndex][columnIndex];
}
@@ -357,9 +241,6 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
* allowed column keys
*/
public V set(int rowIndex, int columnIndex, @Nullable V value) {
- // In GWT array access never throws IndexOutOfBoundsException.
- checkElementIndex(rowIndex, rowList.size());
- checkElementIndex(columnIndex, columnList.size());
V oldValue = array[rowIndex][columnIndex];
array[rowIndex][columnIndex] = value;
return oldValue;
@@ -375,7 +256,6 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
*
* @param valueClass class of values stored in the returned array
*/
- @GwtIncompatible("reflection")
public V[][] toArray(Class<V> valueClass) {
// Can change to use varargs in JDK 1.6 if we want
@SuppressWarnings("unchecked") // TODO: safe?
@@ -451,8 +331,12 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
Integer rowIndex = rowKeyToIndex.get(rowKey);
Integer columnIndex = columnKeyToIndex.get(columnKey);
+ return getIndexed(rowIndex, columnIndex);
+ }
+
+ private V getIndexed(Integer rowIndex, Integer columnIndex) {
return (rowIndex == null || columnIndex == null)
- ? null : at(rowIndex, columnIndex);
+ ? null : array[rowIndex][columnIndex];
}
/**
@@ -602,7 +486,7 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
}
@Override
public V getValue() {
- return at(rowIndex, columnIndex);
+ return array[rowIndex][columnIndex];
}
};
}
@@ -620,7 +504,7 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
Integer columnIndex = columnKeyToIndex.get(cell.getColumnKey());
return rowIndex != null
&& columnIndex != null
- && Objects.equal(at(rowIndex, columnIndex), cell.getValue());
+ && Objects.equal(array[rowIndex][columnIndex], cell.getValue());
}
return false;
}
@@ -646,27 +530,68 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
? ImmutableMap.<R, V>of() : new Column(columnIndex);
}
- private class Column extends ArrayMap<R, V> {
+ private class Column extends AbstractMap<R, V> {
final int columnIndex;
Column(int columnIndex) {
- super(rowKeyToIndex);
this.columnIndex = columnIndex;
}
- @Override
- String getKeyRole() {
- return "Row";
+ ColumnEntrySet entrySet;
+
+ @Override public Set<Entry<R, V>> entrySet() {
+ ColumnEntrySet set = entrySet;
+ return (set == null) ? entrySet = new ColumnEntrySet(columnIndex) : set;
+ }
+
+ @Override public V get(Object rowKey) {
+ Integer rowIndex = rowKeyToIndex.get(rowKey);
+ return getIndexed(rowIndex, columnIndex);
+ }
+
+ @Override public boolean containsKey(Object rowKey) {
+ return rowKeyToIndex.containsKey(rowKey);
+ }
+
+ @Override public V put(R rowKey, V value) {
+ checkNotNull(rowKey);
+ Integer rowIndex = rowKeyToIndex.get(rowKey);
+ checkArgument(rowIndex != null, "Row %s not in %s", rowKey, rowList);
+ return set(rowIndex, columnIndex, value);
+ }
+
+ @Override public Set<R> keySet() {
+ return rowKeySet();
+ }
+ }
+
+ private class ColumnEntrySet extends AbstractSet<Entry<R, V>> {
+ final int columnIndex;
+
+ ColumnEntrySet(int columnIndex) {
+ this.columnIndex = columnIndex;
}
- @Override
- V getValue(int index) {
- return at(index, columnIndex);
+ @Override public Iterator<Entry<R, V>> iterator() {
+ return new AbstractIndexedListIterator<Entry<R, V>>(size()) {
+ @Override protected Entry<R, V> get(final int rowIndex) {
+ return new AbstractMapEntry<R, V>() {
+ @Override public R getKey() {
+ return rowList.get(rowIndex);
+ }
+ @Override public V getValue() {
+ return array[rowIndex][columnIndex];
+ }
+ @Override public V setValue(V value) {
+ return ArrayTable.this.set(rowIndex, columnIndex, value);
+ }
+ };
+ }
+ };
}
- @Override
- V setValue(int index, V newValue) {
- return set(index, columnIndex, newValue);
+ @Override public int size() {
+ return rowList.size();
}
}
@@ -689,32 +614,47 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
return (map == null) ? columnMap = new ColumnMap() : map;
}
- private class ColumnMap extends ArrayMap<C, Map<R, V>> {
- private ColumnMap() {
- super(columnKeyToIndex);
+ private class ColumnMap extends AbstractMap<C, Map<R, V>> {
+ transient ColumnMapEntrySet entrySet;
+
+ @Override public Set<Entry<C, Map<R, V>>> entrySet() {
+ ColumnMapEntrySet set = entrySet;
+ return (set == null) ? entrySet = new ColumnMapEntrySet() : set;
}
- @Override
- String getKeyRole() {
- return "Column";
+ @Override public Map<R, V> get(Object columnKey) {
+ Integer columnIndex = columnKeyToIndex.get(columnKey);
+ return (columnIndex == null) ? null : new Column(columnIndex);
}
- @Override
- Map<R, V> getValue(int index) {
- return new Column(index);
+ @Override public boolean containsKey(Object columnKey) {
+ return containsColumn(columnKey);
}
- @Override
- Map<R, V> setValue(int index, Map<R, V> newValue) {
- throw new UnsupportedOperationException();
+ @Override public Set<C> keySet() {
+ return columnKeySet();
}
- @Override
- public Map<R, V> put(C key, Map<R, V> value) {
+ @Override public Map<R, V> remove(Object columnKey) {
throw new UnsupportedOperationException();
}
}
+ private class ColumnMapEntrySet extends AbstractSet<Entry<C, Map<R, V>>> {
+ @Override public Iterator<Entry<C, Map<R, V>>> iterator() {
+ return new AbstractIndexedListIterator<Entry<C, Map<R, V>>>(size()) {
+ @Override protected Entry<C, Map<R, V>> get(int index) {
+ return Maps.<C, Map<R, V>>immutableEntry(columnList.get(index),
+ new Column(index));
+ }
+ };
+ }
+
+ @Override public int size() {
+ return columnList.size();
+ }
+ }
+
/**
* Returns a view of all mappings that have the given row key. If the
* row key isn't in {@link #rowKeySet()}, an empty immutable map is
@@ -735,27 +675,69 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
return (rowIndex == null) ? ImmutableMap.<C, V>of() : new Row(rowIndex);
}
- private class Row extends ArrayMap<C, V> {
+ private class Row extends AbstractMap<C, V> {
final int rowIndex;
Row(int rowIndex) {
- super(columnKeyToIndex);
this.rowIndex = rowIndex;
}
- @Override
- String getKeyRole() {
- return "Column";
+ RowEntrySet entrySet;
+
+ @Override public Set<Entry<C, V>> entrySet() {
+ RowEntrySet set = entrySet;
+ return (set == null) ? entrySet = new RowEntrySet(rowIndex) : set;
+ }
+
+ @Override public V get(Object columnKey) {
+ Integer columnIndex = columnKeyToIndex.get(columnKey);
+ return getIndexed(rowIndex, columnIndex);
+ }
+
+ @Override public boolean containsKey(Object columnKey) {
+ return containsColumn(columnKey);
+ }
+
+ @Override public V put(C columnKey, V value) {
+ checkNotNull(columnKey);
+ Integer columnIndex = columnKeyToIndex.get(columnKey);
+ checkArgument(columnIndex != null,
+ "Column %s not in %s", columnKey, columnList);
+ return set(rowIndex, columnIndex, value);
}
- @Override
- V getValue(int index) {
- return at(rowIndex, index);
+ @Override public Set<C> keySet() {
+ return columnKeySet();
}
+ }
+
+ private class RowEntrySet extends AbstractSet<Entry<C, V>> {
+ final int rowIndex;
- @Override
- V setValue(int index, V newValue) {
- return set(rowIndex, index, newValue);
+ RowEntrySet(int rowIndex) {
+ this.rowIndex = rowIndex;
+ }
+
+ @Override public Iterator<Entry<C, V>> iterator() {
+ return new AbstractIndexedListIterator<Entry<C, V>>(size()) {
+ @Override protected Entry<C, V> get(final int columnIndex) {
+ return new AbstractMapEntry<C, V>() {
+ @Override public C getKey() {
+ return columnList.get(columnIndex);
+ }
+ @Override public V getValue() {
+ return array[rowIndex][columnIndex];
+ }
+ @Override public V setValue(V value) {
+ return ArrayTable.this.set(rowIndex, columnIndex, value);
+ }
+ };
+ }
+ };
+ }
+
+ @Override public int size() {
+ return columnList.size();
}
}
@@ -778,32 +760,47 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
return (map == null) ? rowMap = new RowMap() : map;
}
- private class RowMap extends ArrayMap<R, Map<C, V>> {
- private RowMap() {
- super(rowKeyToIndex);
+ private class RowMap extends AbstractMap<R, Map<C, V>> {
+ transient RowMapEntrySet entrySet;
+
+ @Override public Set<Entry<R, Map<C, V>>> entrySet() {
+ RowMapEntrySet set = entrySet;
+ return (set == null) ? entrySet = new RowMapEntrySet() : set;
}
- @Override
- String getKeyRole() {
- return "Row";
+ @Override public Map<C, V> get(Object rowKey) {
+ Integer rowIndex = rowKeyToIndex.get(rowKey);
+ return (rowIndex == null) ? null : new Row(rowIndex);
}
- @Override
- Map<C, V> getValue(int index) {
- return new Row(index);
+ @Override public boolean containsKey(Object rowKey) {
+ return containsRow(rowKey);
}
- @Override
- Map<C, V> setValue(int index, Map<C, V> newValue) {
- throw new UnsupportedOperationException();
+ @Override public Set<R> keySet() {
+ return rowKeySet();
}
- @Override
- public Map<C, V> put(R key, Map<C, V> value) {
+ @Override public Map<C, V> remove(Object rowKey) {
throw new UnsupportedOperationException();
}
}
+ private class RowMapEntrySet extends AbstractSet<Entry<R, Map<C, V>>> {
+ @Override public Iterator<Entry<R, Map<C, V>>> iterator() {
+ return new AbstractIndexedListIterator<Entry<R, Map<C, V>>>(size()) {
+ @Override protected Entry<R, Map<C, V>> get(int index) {
+ return Maps.<R, Map<C, V>>immutableEntry(rowList.get(index),
+ new Row(index));
+ }
+ };
+ }
+
+ @Override public int size() {
+ return rowList.size();
+ }
+ }
+
private transient Collection<V> values;
/**
@@ -823,10 +820,11 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
private class Values extends AbstractCollection<V> {
@Override public Iterator<V> iterator() {
- return new TransformedIterator<Cell<R, C, V>, V>(cellSet().iterator()) {
- @Override
- V transform(Cell<R, C, V> cell) {
- return cell.getValue();
+ return new AbstractIndexedListIterator<V>(size()) {
+ @Override protected V get(int index) {
+ int rowIndex = index / columnList.size();
+ int columnIndex = index % columnList.size();
+ return array[rowIndex][columnIndex];
}
};
}
@@ -834,6 +832,10 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
@Override public int size() {
return ArrayTable.this.size();
}
+
+ @Override public boolean contains(Object value) {
+ return containsValue(value);
+ }
}
private static final long serialVersionUID = 0;
diff --git a/guava/src/com/google/common/collect/AsynchronousComputationException.java b/guava/src/com/google/common/collect/AsynchronousComputationException.java
new file mode 100644
index 0000000..e64e17b
--- /dev/null
+++ b/guava/src/com/google/common/collect/AsynchronousComputationException.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2009 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+/**
+ * Wraps an exception that occurred during a computation in a different thread.
+ *
+ * @author Bob Lee
+ * @since 2.0 (imported from Google Collections Library)
+ * @deprecated this class is unused by com.google.common.collect. <b>This class
+ * is scheduled for deletion in November 2012.</b>
+ */
+@Deprecated
+public
+class AsynchronousComputationException extends ComputationException {
+ /**
+ * Creates a new instance with the given cause.
+ */
+ public AsynchronousComputationException(Throwable cause) {
+ super(cause);
+ }
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/BiMap.java b/guava/src/com/google/common/collect/BiMap.java
index a6203e0..34d6677 100644
--- a/guava/src/com/google/common/collect/BiMap.java
+++ b/guava/src/com/google/common/collect/BiMap.java
@@ -28,10 +28,6 @@ import javax.annotation.Nullable;
* its values as well as that of its keys. This constraint enables bimaps to
* support an "inverse view", which is another bimap containing the same entries
* as this bimap but with reversed keys and values.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap">
- * {@code BiMap}</a>.
*
* @author Kevin Bourrillion
* @since 2.0 (imported from Google Collections Library)
diff --git a/guava/src/com/google/common/collect/BoundType.java b/guava/src/com/google/common/collect/BoundType.java
index 7b8f34b..3632b32 100644
--- a/guava/src/com/google/common/collect/BoundType.java
+++ b/guava/src/com/google/common/collect/BoundType.java
@@ -14,6 +14,7 @@
package com.google.common.collect;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
/**
@@ -23,26 +24,18 @@ import com.google.common.annotations.GwtCompatible;
*
* @since 10.0
*/
+@Beta
@GwtCompatible
public enum BoundType {
/**
* The endpoint value <i>is not</i> considered part of the set ("exclusive").
*/
- OPEN {
- @Override
- BoundType flip() {
- return CLOSED;
- }
- },
+ OPEN,
+
/**
* The endpoint value <i>is</i> considered part of the set ("inclusive").
*/
- CLOSED {
- @Override
- BoundType flip() {
- return OPEN;
- }
- };
+ CLOSED;
/**
* Returns the bound type corresponding to a boolean value for inclusivity.
@@ -50,6 +43,4 @@ public enum BoundType {
static BoundType forBoolean(boolean inclusive) {
return inclusive ? CLOSED : OPEN;
}
-
- abstract BoundType flip();
}
diff --git a/guava/src/com/google/common/collect/BstAggregate.java b/guava/src/com/google/common/collect/BstAggregate.java
new file mode 100644
index 0000000..84d150f
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstAggregate.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.annotations.GwtCompatible;
+
+import javax.annotation.Nullable;
+
+/**
+ * An integer-valued function on binary search tree nodes that adds between nodes.
+ *
+ * <p>The value of individual entries must fit into an {@code int}, but the value of an entire
+ * tree can require a {@code long}.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+interface BstAggregate<N extends BstNode<?, N>> {
+ /**
+ * The total value on an entire subtree. Must be equal to the sum of the {@link #entryValue
+ * entryValue} of this node and all its descendants.
+ */
+ long treeValue(@Nullable N tree);
+
+ /**
+ * The value on a single entry, ignoring its descendants.
+ */
+ int entryValue(N entry);
+}
diff --git a/guava/src/com/google/common/collect/BstBalancePolicy.java b/guava/src/com/google/common/collect/BstBalancePolicy.java
new file mode 100644
index 0000000..d1e93d0
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstBalancePolicy.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.annotations.GwtCompatible;
+
+import javax.annotation.Nullable;
+
+/**
+ * A local balancing policy for modified nodes in binary search trees.
+ *
+ * @author Louis Wasserman
+ * @param <N> The type of the nodes in the trees that this {@code BstRebalancePolicy} can
+ * rebalance.
+ */
+@GwtCompatible
+interface BstBalancePolicy<N extends BstNode<?, N>> {
+ /**
+ * Constructs a locally balanced tree around the key and value data in {@code source}, and the
+ * subtrees {@code left} and {@code right}. It is guaranteed that the resulting tree will have
+ * the same inorder traversal order as the subtree {@code left}, then the entry {@code source},
+ * then the subtree {@code right}.
+ */
+ N balance(BstNodeFactory<N> nodeFactory, N source, @Nullable N left, @Nullable N right);
+
+ /**
+ * Constructs a locally balanced tree around the subtrees {@code left} and {@code right}. It is
+ * guaranteed that the resulting tree will have the same inorder traversal order as the subtree
+ * {@code left}, then the subtree {@code right}.
+ */
+ @Nullable
+ N combine(BstNodeFactory<N> nodeFactory, @Nullable N left, @Nullable N right);
+}
diff --git a/guava/src/com/google/common/collect/BstCountBasedBalancePolicies.java b/guava/src/com/google/common/collect/BstCountBasedBalancePolicies.java
new file mode 100644
index 0000000..5b98b91
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstCountBasedBalancePolicies.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.BstOperations.extractMax;
+import static com.google.common.collect.BstOperations.extractMin;
+import static com.google.common.collect.BstOperations.insertMax;
+import static com.google.common.collect.BstOperations.insertMin;
+import static com.google.common.collect.BstSide.LEFT;
+import static com.google.common.collect.BstSide.RIGHT;
+
+import com.google.common.annotations.GwtCompatible;
+
+import javax.annotation.Nullable;
+
+/**
+ * A tree-size-based set of balancing policies, based on <a
+ * href="http://www.swiss.ai.mit.edu/~adams/BB/"> Stephen Adams, "Efficient sets: a balancing
+ * act."</a>.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+final class BstCountBasedBalancePolicies {
+ private BstCountBasedBalancePolicies() {}
+
+ private static final int SINGLE_ROTATE_RATIO = 4;
+ private static final int SECOND_ROTATE_RATIO = 2;
+
+ /**
+ * Returns a balance policy that does no balancing or the bare minimum (for {@code combine}).
+ */
+ public static <N extends BstNode<?, N>> BstBalancePolicy<N> noRebalancePolicy(
+ final BstAggregate<N> countAggregate) {
+ checkNotNull(countAggregate);
+ return new BstBalancePolicy<N>() {
+ @Override
+ public N balance(
+ BstNodeFactory<N> nodeFactory, N source, @Nullable N left, @Nullable N right) {
+ return checkNotNull(nodeFactory).createNode(source, left, right);
+ }
+
+ @Nullable
+ @Override
+ public N combine(BstNodeFactory<N> nodeFactory, @Nullable N left, @Nullable N right) {
+ if (left == null) {
+ return right;
+ } else if (right == null) {
+ return left;
+ } else if (countAggregate.treeValue(left) > countAggregate.treeValue(right)) {
+ return nodeFactory.createNode(
+ left, left.childOrNull(LEFT), combine(nodeFactory, left.childOrNull(RIGHT), right));
+ } else {
+ return nodeFactory.createNode(right, combine(nodeFactory, left, right.childOrNull(LEFT)),
+ right.childOrNull(RIGHT));
+ }
+ }
+ };
+ }
+
+ /**
+ * Returns a balance policy that expects the sizes of each side to be at most one node (added or
+ * removed) away from being balanced. {@code balance} takes {@code O(1)} time, and {@code
+ * combine} takes {@code O(log n)} time.
+ */
+ public static <K, N extends BstNode<K, N>> BstBalancePolicy<N> singleRebalancePolicy(
+ final BstAggregate<N> countAggregate) {
+ checkNotNull(countAggregate);
+ return new BstBalancePolicy<N>() {
+ @Override
+ public N balance(
+ BstNodeFactory<N> nodeFactory, N source, @Nullable N left, @Nullable N right) {
+ long countL = countAggregate.treeValue(left);
+ long countR = countAggregate.treeValue(right);
+ if (countL + countR > 1) {
+ if (countR >= SINGLE_ROTATE_RATIO * countL) {
+ return rotateL(nodeFactory, source, left, right);
+ } else if (countL >= SINGLE_ROTATE_RATIO * countR) {
+ return rotateR(nodeFactory, source, left, right);
+ }
+ }
+ return nodeFactory.createNode(source, left, right);
+ }
+
+ private N rotateL(BstNodeFactory<N> nodeFactory, N source, @Nullable N left, N right) {
+ checkNotNull(right);
+ N rl = right.childOrNull(LEFT);
+ N rr = right.childOrNull(RIGHT);
+ if (countAggregate.treeValue(rl) >= SECOND_ROTATE_RATIO * countAggregate.treeValue(rr)) {
+ right = singleR(nodeFactory, right, rl, rr);
+ }
+ return singleL(nodeFactory, source, left, right);
+ }
+
+ private N rotateR(BstNodeFactory<N> nodeFactory, N source, N left, @Nullable N right) {
+ checkNotNull(left);
+ N lr = left.childOrNull(RIGHT);
+ N ll = left.childOrNull(LEFT);
+ if (countAggregate.treeValue(lr) >= SECOND_ROTATE_RATIO * countAggregate.treeValue(ll)) {
+ left = singleL(nodeFactory, left, ll, lr);
+ }
+ return singleR(nodeFactory, source, left, right);
+ }
+
+ private N singleL(BstNodeFactory<N> nodeFactory, N source, @Nullable N left, N right) {
+ checkNotNull(right);
+ return nodeFactory.createNode(right,
+ nodeFactory.createNode(source, left, right.childOrNull(LEFT)),
+ right.childOrNull(RIGHT));
+ }
+
+ private N singleR(BstNodeFactory<N> nodeFactory, N source, N left, @Nullable N right) {
+ checkNotNull(left);
+ return nodeFactory.createNode(left, left.childOrNull(LEFT),
+ nodeFactory.createNode(source, left.childOrNull(RIGHT), right));
+ }
+
+ @Nullable
+ @Override
+ public N combine(BstNodeFactory<N> nodeFactory, @Nullable N left, @Nullable N right) {
+ if (left == null) {
+ return right;
+ } else if (right == null) {
+ return left;
+ }
+ N newRootSource;
+ if (countAggregate.treeValue(left) > countAggregate.treeValue(right)) {
+ BstMutationResult<K, N> extractLeftMax = extractMax(left, nodeFactory, this);
+ newRootSource = extractLeftMax.getOriginalTarget();
+ left = extractLeftMax.getChangedRoot();
+ } else {
+ BstMutationResult<K, N> extractRightMin = extractMin(right, nodeFactory, this);
+ newRootSource = extractRightMin.getOriginalTarget();
+ right = extractRightMin.getChangedRoot();
+ }
+ return nodeFactory.createNode(newRootSource, left, right);
+ }
+ };
+ }
+
+ /**
+ * Returns a balance policy that makes no assumptions on the relative balance of the two sides
+ * and performs a full rebalancing as necessary. Both {@code balance} and {@code combine} take
+ * {@code O(log n)} time.
+ */
+ public static <K, N extends BstNode<K, N>> BstBalancePolicy<N> fullRebalancePolicy(
+ final BstAggregate<N> countAggregate) {
+ checkNotNull(countAggregate);
+ final BstBalancePolicy<N> singleBalancePolicy =
+ BstCountBasedBalancePolicies.<K, N>singleRebalancePolicy(countAggregate);
+ return new BstBalancePolicy<N>() {
+ @Override
+ public N balance(
+ BstNodeFactory<N> nodeFactory, N source, @Nullable N left, @Nullable N right) {
+ if (left == null) {
+ return insertMin(right, source, nodeFactory, singleBalancePolicy);
+ } else if (right == null) {
+ return insertMax(left, source, nodeFactory, singleBalancePolicy);
+ }
+ long countL = countAggregate.treeValue(left);
+ long countR = countAggregate.treeValue(right);
+ if (SINGLE_ROTATE_RATIO * countL <= countR) {
+ N resultLeft = balance(nodeFactory, source, left, right.childOrNull(LEFT));
+ return singleBalancePolicy.balance(
+ nodeFactory, right, resultLeft, right.childOrNull(RIGHT));
+ } else if (SINGLE_ROTATE_RATIO * countR <= countL) {
+ N resultRight = balance(nodeFactory, source, left.childOrNull(RIGHT), right);
+ return singleBalancePolicy.balance(
+ nodeFactory, left, left.childOrNull(LEFT), resultRight);
+ } else {
+ return nodeFactory.createNode(source, left, right);
+ }
+ }
+
+ @Nullable
+ @Override
+ public N combine(BstNodeFactory<N> nodeFactory, @Nullable N left, @Nullable N right) {
+ if (left == null) {
+ return right;
+ } else if (right == null) {
+ return left;
+ }
+ long countL = countAggregate.treeValue(left);
+ long countR = countAggregate.treeValue(right);
+ if (SINGLE_ROTATE_RATIO * countL <= countR) {
+ N resultLeft = combine(nodeFactory, left, right.childOrNull(LEFT));
+ return singleBalancePolicy.balance(
+ nodeFactory, right, resultLeft, right.childOrNull(RIGHT));
+ } else if (SINGLE_ROTATE_RATIO * countR <= countL) {
+ N resultRight = combine(nodeFactory, left.childOrNull(RIGHT), right);
+ return singleBalancePolicy.balance(
+ nodeFactory, left, left.childOrNull(LEFT), resultRight);
+ } else {
+ return singleBalancePolicy.combine(nodeFactory, left, right);
+ }
+ }
+ };
+ }
+}
diff --git a/guava/src/com/google/common/collect/BstInOrderPath.java b/guava/src/com/google/common/collect/BstInOrderPath.java
new file mode 100644
index 0000000..de14c39
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstInOrderPath.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Optional;
+
+import java.util.NoSuchElementException;
+
+import javax.annotation.Nullable;
+
+/**
+ * A {@code BstPath} supporting inorder traversal operations.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+final class BstInOrderPath<N extends BstNode<?, N>> extends BstPath<N, BstInOrderPath<N>> {
+ /**
+ * The factory to use to construct {@code BstInOrderPath} values.
+ */
+ public static <N extends BstNode<?, N>> BstPathFactory<N, BstInOrderPath<N>> inOrderFactory() {
+ return new BstPathFactory<N, BstInOrderPath<N>>() {
+ @Override
+ public BstInOrderPath<N> extension(BstInOrderPath<N> path, BstSide side) {
+ return BstInOrderPath.extension(path, side);
+ }
+
+ @Override
+ public BstInOrderPath<N> initialPath(N root) {
+ return new BstInOrderPath<N>(root, null, null);
+ }
+ };
+ }
+
+ private static <N extends BstNode<?, N>> BstInOrderPath<N> extension(
+ BstInOrderPath<N> path, BstSide side) {
+ checkNotNull(path);
+ N tip = path.getTip();
+ return new BstInOrderPath<N>(tip.getChild(side), side, path);
+ }
+
+ private final BstSide sideExtension;
+ private transient Optional<BstInOrderPath<N>> prevInOrder;
+ private transient Optional<BstInOrderPath<N>> nextInOrder;
+
+ private BstInOrderPath(
+ N tip, @Nullable BstSide sideExtension, @Nullable BstInOrderPath<N> tail) {
+ super(tip, tail);
+ this.sideExtension = sideExtension;
+ assert (sideExtension == null) == (tail == null);
+ }
+
+ private Optional<BstInOrderPath<N>> computeNextInOrder(BstSide side) {
+ if (getTip().hasChild(side)) {
+ BstInOrderPath<N> path = extension(this, side);
+ BstSide otherSide = side.other();
+ while (path.getTip().hasChild(otherSide)) {
+ path = extension(path, otherSide);
+ }
+ return Optional.of(path);
+ } else {
+ BstInOrderPath<N> current = this;
+ while (current.sideExtension == side) {
+ current = current.getPrefix();
+ }
+ current = current.prefixOrNull();
+ return Optional.fromNullable(current);
+ }
+ }
+
+ private Optional<BstInOrderPath<N>> nextInOrder(BstSide side) {
+ Optional<BstInOrderPath<N>> result;
+ switch (side) {
+ case LEFT:
+ result = prevInOrder;
+ return (result == null) ? prevInOrder = computeNextInOrder(side) : result;
+ case RIGHT:
+ result = nextInOrder;
+ return (result == null) ? nextInOrder = computeNextInOrder(side) : result;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Returns {@code true} if there is a next path in an in-order traversal in the given direction.
+ */
+ public boolean hasNext(BstSide side) {
+ return nextInOrder(side).isPresent();
+ }
+
+ /**
+ * Returns the next path in an in-order traversal in the given direction.
+ *
+ * @throws NoSuchElementException if this would be the last path in an in-order traversal
+ */
+ public BstInOrderPath<N> next(BstSide side) {
+ if (!hasNext(side)) {
+ throw new NoSuchElementException();
+ }
+ return nextInOrder(side).get();
+ }
+
+ /**
+ * Returns the direction this path went in relative to its tail path, or {@code null} if this
+ * path has no tail.
+ */
+ public BstSide getSideOfExtension() {
+ return sideExtension;
+ }
+}
diff --git a/guava/src/com/google/common/collect/BstModificationResult.java b/guava/src/com/google/common/collect/BstModificationResult.java
new file mode 100644
index 0000000..2c7c036
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstModificationResult.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+
+import javax.annotation.Nullable;
+
+/**
+ * The result of a {@code BstModifier}.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+final class BstModificationResult<N extends BstNode<?, N>> {
+ enum ModificationType {
+ IDENTITY, REBUILDING_CHANGE, REBALANCING_CHANGE;
+ }
+
+ static <N extends BstNode<?, N>> BstModificationResult<N> identity(@Nullable N target) {
+ return new BstModificationResult<N>(target, target, ModificationType.IDENTITY);
+ }
+
+ static <N extends BstNode<?, N>> BstModificationResult<N> rebuildingChange(
+ @Nullable N originalTarget, @Nullable N changedTarget) {
+ return new BstModificationResult<N>(
+ originalTarget, changedTarget, ModificationType.REBUILDING_CHANGE);
+ }
+
+ static <N extends BstNode<?, N>> BstModificationResult<N> rebalancingChange(
+ @Nullable N originalTarget, @Nullable N changedTarget) {
+ return new BstModificationResult<N>(
+ originalTarget, changedTarget, ModificationType.REBALANCING_CHANGE);
+ }
+
+ @Nullable private final N originalTarget;
+ @Nullable private final N changedTarget;
+ private final ModificationType type;
+
+ private BstModificationResult(
+ @Nullable N originalTarget, @Nullable N changedTarget, ModificationType type) {
+ this.originalTarget = originalTarget;
+ this.changedTarget = changedTarget;
+ this.type = checkNotNull(type);
+ }
+
+ @Nullable
+ N getOriginalTarget() {
+ return originalTarget;
+ }
+
+ @Nullable
+ N getChangedTarget() {
+ return changedTarget;
+ }
+
+ ModificationType getType() {
+ return type;
+ }
+}
diff --git a/guava/src/com/google/common/collect/BstModifier.java b/guava/src/com/google/common/collect/BstModifier.java
new file mode 100644
index 0000000..d972800
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstModifier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.annotations.GwtCompatible;
+
+import javax.annotation.Nullable;
+
+/**
+ * A specification for a local change to an entry in a binary search tree.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+interface BstModifier<K, N extends BstNode<K, N>> {
+
+ /**
+ * Given a target key and the original entry (if any) with the specified key, returns the entry
+ * with key {@code key} after this mutation has been performed. The result must either be {@code
+ * null} or must have a key that compares as equal to {@code key}. A deletion operation, for
+ * example, would always return {@code null}, or an insertion operation would always return a
+ * non-null {@code insertedEntry}.
+ *
+ * <p>If this method returns a non-null entry of type {@code N}, any children it has will be
+ * ignored.
+ *
+ * <p>This method may return {@code originalEntry} itself to indicate that no change is made.
+ *
+ * @param key The key being targeted for modification.
+ * @param originalEntry The original entry in the binary search tree with the specified key, if
+ * any. No guarantees are made about the children of this entry when treated as a node; in
+ * particular, they are not necessarily the children of the corresponding node in the
+ * binary search tree.
+ * @return the entry (if any) with the specified key after this modification is performed
+ */
+ BstModificationResult<N> modify(K key, @Nullable N originalEntry);
+}
diff --git a/guava/src/com/google/common/collect/BstMutationResult.java b/guava/src/com/google/common/collect/BstMutationResult.java
new file mode 100644
index 0000000..68309a8
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstMutationResult.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.BstModificationResult.ModificationType.IDENTITY;
+import static com.google.common.collect.BstModificationResult.ModificationType.REBUILDING_CHANGE;
+import static com.google.common.collect.BstModificationResult.ModificationType.REBALANCING_CHANGE;
+import static com.google.common.collect.BstSide.LEFT;
+import static com.google.common.collect.BstSide.RIGHT;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.collect.BstModificationResult.ModificationType;
+
+import javax.annotation.Nullable;
+
+/**
+ * The result of a mutation operation performed at a single location in a binary search tree.
+ *
+ * @author Louis Wasserman
+ * @param <K> The key type of the nodes in the modified binary search tree.
+ * @param <N> The type of the nodes in the modified binary search tree.
+ */
+@GwtCompatible
+final class BstMutationResult<K, N extends BstNode<K, N>> {
+ /**
+ * Creates a {@code BstMutationResult}.
+ *
+ * @param targetKey The key targeted for modification. If {@code originalTarget} or {@code
+ * changedTarget} are non-null, their keys must compare as equal to {@code targetKey}.
+ * @param originalRoot The root of the subtree that was modified.
+ * @param changedRoot The root of the subtree, after the modification and any rebalancing.
+ * @param modificationResult The result of the local modification to an entry.
+ */
+ public static <K, N extends BstNode<K, N>> BstMutationResult<K, N> mutationResult(
+ @Nullable K targetKey, @Nullable N originalRoot, @Nullable N changedRoot,
+ BstModificationResult<N> modificationResult) {
+ return new BstMutationResult<K, N>(targetKey, originalRoot, changedRoot, modificationResult);
+ }
+
+ private final K targetKey;
+
+ @Nullable
+ private N originalRoot;
+
+ @Nullable
+ private N changedRoot;
+
+ private final BstModificationResult<N> modificationResult;
+
+ private BstMutationResult(@Nullable K targetKey, @Nullable N originalRoot,
+ @Nullable N changedRoot, BstModificationResult<N> modificationResult) {
+ this.targetKey = targetKey;
+ this.originalRoot = originalRoot;
+ this.changedRoot = changedRoot;
+ this.modificationResult = checkNotNull(modificationResult);
+ }
+
+ /**
+ * Returns the key which was the target of this modification.
+ */
+ public K getTargetKey() {
+ return targetKey;
+ }
+
+ /**
+ * Returns the root of the subtree that was modified.
+ */
+ @Nullable
+ public N getOriginalRoot() {
+ return originalRoot;
+ }
+
+ /**
+ * Returns the root of the subtree, after the modification and any rebalancing was performed.
+ */
+ @Nullable
+ public N getChangedRoot() {
+ return changedRoot;
+ }
+
+ /**
+ * Returns the entry in the original subtree with key {@code targetKey}, if any. This should not
+ * be treated as a subtree, but only as an entry, and no guarantees are made about its children
+ * when viewed as a subtree.
+ */
+ @Nullable
+ public N getOriginalTarget() {
+ return modificationResult.getOriginalTarget();
+ }
+
+ /**
+ * Returns the result of the modification to {@link #getOriginalTarget()}. This should not be
+ * treated as a subtree, but only as an entry, and no guarantees are made about its children when
+ * viewed as a subtree.
+ */
+ @Nullable
+ public N getChangedTarget() {
+ return modificationResult.getChangedTarget();
+ }
+
+ ModificationType modificationType() {
+ return modificationResult.getType();
+ }
+
+ /**
+ * If this mutation was to an immediate child subtree of the specified root on the specified
+ * side, returns the {@code BstMutationResult} of applying the mutation to the appropriate child
+ * of the specified root and rebalancing using the specified mutation rule.
+ */
+ public BstMutationResult<K, N> lift(N liftOriginalRoot, BstSide side,
+ BstNodeFactory<N> nodeFactory, BstBalancePolicy<N> balancePolicy) {
+ assert liftOriginalRoot != null & side != null & nodeFactory != null & balancePolicy != null;
+ switch (modificationType()) {
+ case IDENTITY:
+ this.originalRoot = this.changedRoot = liftOriginalRoot;
+ return this;
+ case REBUILDING_CHANGE:
+ case REBALANCING_CHANGE:
+ this.originalRoot = liftOriginalRoot;
+ N resultLeft = liftOriginalRoot.childOrNull(LEFT);
+ N resultRight = liftOriginalRoot.childOrNull(RIGHT);
+ switch (side) {
+ case LEFT:
+ resultLeft = changedRoot;
+ break;
+ case RIGHT:
+ resultRight = changedRoot;
+ break;
+ default:
+ throw new AssertionError();
+ }
+ if (modificationType() == REBUILDING_CHANGE) {
+ this.changedRoot = nodeFactory.createNode(liftOriginalRoot, resultLeft, resultRight);
+ } else {
+ this.changedRoot =
+ balancePolicy.balance(nodeFactory, liftOriginalRoot, resultLeft, resultRight);
+ }
+ return this;
+ default:
+ throw new AssertionError();
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/BstMutationRule.java b/guava/src/com/google/common/collect/BstMutationRule.java
new file mode 100644
index 0000000..7f90f8c
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstMutationRule.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+
+/**
+ * A rule for a local mutation to a binary search tree, that changes at most one entry. In addition
+ * to specifying how it modifies a particular entry via a {@code BstModifier}, it specifies a
+ * {@link BstBalancePolicy} for rebalancing the tree after the modification is performed and a
+ * {@link BstNodeFactory} for constructing newly rebalanced nodes.
+ *
+ * @author Louis Wasserman
+ * @param <K> The key type of the nodes in binary search trees that this rule can modify.
+ * @param <N> The type of the nodes in binary search trees that this rule can modify.
+ */
+@GwtCompatible
+final class BstMutationRule<K, N extends BstNode<K, N>> {
+ /**
+ * Constructs a {@code BstMutationRule} with the specified modifier, balance policy, and node
+ * factory.
+ */
+ public static <K, N extends BstNode<K, N>> BstMutationRule<K, N> createRule(
+ BstModifier<K, N> modifier, BstBalancePolicy<N> balancePolicy,
+ BstNodeFactory<N> nodeFactory) {
+ return new BstMutationRule<K, N>(modifier, balancePolicy, nodeFactory);
+ }
+
+ private final BstModifier<K, N> modifier;
+ private final BstBalancePolicy<N> balancePolicy;
+ private final BstNodeFactory<N> nodeFactory;
+
+ private BstMutationRule(BstModifier<K, N> modifier, BstBalancePolicy<N> balancePolicy,
+ BstNodeFactory<N> nodeFactory) {
+ this.balancePolicy = checkNotNull(balancePolicy);
+ this.nodeFactory = checkNotNull(nodeFactory);
+ this.modifier = checkNotNull(modifier);
+ }
+
+ /**
+ * Returns the {@link BstModifier} that specifies the change to a targeted entry in a binary
+ * search tree.
+ */
+ public BstModifier<K, N> getModifier() {
+ return modifier;
+ }
+
+ /**
+ * Returns the policy used to rebalance nodes in the tree after this modification has been
+ * performed.
+ */
+ public BstBalancePolicy<N> getBalancePolicy() {
+ return balancePolicy;
+ }
+
+ /**
+ * Returns the node factory used to create new nodes in the tree after this modification has been
+ * performed.
+ */
+ public BstNodeFactory<N> getNodeFactory() {
+ return nodeFactory;
+ }
+}
diff --git a/guava/src/com/google/common/collect/BstNode.java b/guava/src/com/google/common/collect/BstNode.java
new file mode 100644
index 0000000..818f85a
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstNode.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.BstSide.LEFT;
+import static com.google.common.collect.BstSide.RIGHT;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Comparator;
+
+import javax.annotation.Nullable;
+
+/**
+ * A reusable abstraction for a node in a binary search tree. Null keys are allowed.
+ *
+ * <p>The node is considered to be immutable. Any subclass with mutable fields must create a new
+ * {@code BstNode} object upon any mutation, as the {@code Bst} classes assume that two nodes
+ * {@code a} and {@code b} represent exactly the same tree if and only if {@code a == b}.
+ *
+ * <p>A {@code BstNode} can be considered to be an <i>entry</i>, containing a key and possibly some
+ * value data, or it can be considered to be a <i>subtree</i>, representative of it and all its
+ * descendants.
+ *
+ * @author Louis Wasserman
+ * @param <K> The key type associated with this tree.
+ * @param <N> The type of the nodes in this tree.
+ */
+@GwtCompatible
+class BstNode<K, N extends BstNode<K, N>> {
+ /**
+ * The key on which this binary search tree is ordered. All descendants of the left subtree of
+ * this node must have keys strictly less than {@code this.key}.
+ */
+ private final K key;
+
+ /**
+ * The left child of this node. A null value indicates that this node has no left child.
+ */
+ @Nullable
+ private final N left;
+
+ /**
+ * The right child of this node. A null value indicates that this node has no right child.
+ */
+ @Nullable
+ private final N right;
+
+ BstNode(@Nullable K key, @Nullable N left, @Nullable N right) {
+ this.key = key;
+ this.left = left;
+ this.right = right;
+ }
+
+ /**
+ * Returns the ordered key associated with this node.
+ */
+ @Nullable
+ public final K getKey() {
+ return key;
+ }
+
+ /**
+ * Returns the child on the specified side, or {@code null} if there is no such child.
+ */
+ @Nullable
+ public final N childOrNull(BstSide side) {
+ switch (side) {
+ case LEFT:
+ return left;
+ case RIGHT:
+ return right;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Returns {@code true} if this node has a child on the specified side.
+ */
+ public final boolean hasChild(BstSide side) {
+ return childOrNull(side) != null;
+ }
+
+ /**
+ * Returns this node's child on the specified side.
+ *
+ * @throws IllegalStateException if this node has no such child
+ */
+ public final N getChild(BstSide side) {
+ N child = childOrNull(side);
+ checkState(child != null);
+ return child;
+ }
+
+ /**
+ * Returns {@code true} if the traditional binary search tree ordering invariant holds with
+ * respect to the specified {@code comparator}.
+ */
+ protected final boolean orderingInvariantHolds(Comparator<? super K> comparator) {
+ checkNotNull(comparator);
+ boolean result = true;
+ if (hasChild(LEFT)) {
+ result &= comparator.compare(getChild(LEFT).getKey(), key) < 0;
+ }
+ if (hasChild(RIGHT)) {
+ result &= comparator.compare(getChild(RIGHT).getKey(), key) > 0;
+ }
+ return result;
+ }
+}
diff --git a/guava/src/com/google/common/collect/BstNodeFactory.java b/guava/src/com/google/common/collect/BstNodeFactory.java
new file mode 100644
index 0000000..8e1476c
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstNodeFactory.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.annotations.GwtCompatible;
+
+import javax.annotation.Nullable;
+
+/**
+ * A factory for copying nodes in binary search trees with different children.
+ *
+ * <p>Typically, nodes will carry more information than the fields in the {@link BstNode} class,
+ * often some kind of value or some aggregate data for the subtree. This factory is responsible for
+ * copying this additional data between nodes.
+ *
+ * @author Louis Wasserman
+ * @param <N> The type of the tree nodes constructed with this {@code BstNodeFactory}.
+ */
+@GwtCompatible
+abstract class BstNodeFactory<N extends BstNode<?, N>> {
+ /**
+ * Returns a new {@code N} with the key and value data from {@code source}, with left child
+ * {@code left}, and right child {@code right}. If {@code left} or {@code right} is null, the
+ * returned node will not have a child on the corresponding side.
+ */
+ public abstract N createNode(N source, @Nullable N left, @Nullable N right);
+
+ /**
+ * Returns a new {@code N} with the key and value data from {@code source} that is a leaf.
+ */
+ public final N createLeaf(N source) {
+ return createNode(source, null, null);
+ }
+}
diff --git a/guava/src/com/google/common/collect/BstOperations.java b/guava/src/com/google/common/collect/BstOperations.java
new file mode 100644
index 0000000..1f933d4
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstOperations.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.BstSide.LEFT;
+import static com.google.common.collect.BstSide.RIGHT;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Comparator;
+
+import javax.annotation.Nullable;
+
+/**
+ * Tools to perform single-key queries and mutations in binary search trees.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+final class BstOperations {
+ private BstOperations() {}
+
+ /**
+ * Returns the node with key {@code key} in {@code tree}, if any.
+ */
+ @Nullable
+ public static <K, N extends BstNode<K, N>> N seek(
+ Comparator<? super K> comparator, @Nullable N tree, @Nullable K key) {
+ checkNotNull(comparator);
+ if (tree == null) {
+ return null;
+ }
+ int cmp = comparator.compare(key, tree.getKey());
+ if (cmp == 0) {
+ return tree;
+ } else {
+ BstSide side = (cmp < 0) ? LEFT : RIGHT;
+ return seek(comparator, tree.childOrNull(side), key);
+ }
+ }
+
+ /**
+ * Returns the result of performing the mutation specified by {@code mutationRule} in {@code
+ * tree} at the location with key {@code key}.
+ *
+ * <ul>
+ * <li>If the returned {@link BstModificationResult} has type {@code IDENTITY}, the exact
+ * original tree is returned.
+ * <li>If the returned {@code BstModificationResult} has type {@code REBUILDING_CHANGE},
+ * the tree will be rebuilt with the node factory of the mutation rule, but not rebalanced.
+ * <li>If the returned {@code BstModificationResult} has type {@code REBALANCING_CHANGE},
+ * the tree will be rebalanced using the balance policy of the mutation rule.
+ * </ul>
+ */
+ public static <K, N extends BstNode<K, N>> BstMutationResult<K, N> mutate(
+ Comparator<? super K> comparator, BstMutationRule<K, N> mutationRule, @Nullable N tree,
+ @Nullable K key) {
+ checkNotNull(comparator);
+ checkNotNull(mutationRule);
+
+ if (tree != null) {
+ int cmp = comparator.compare(key, tree.getKey());
+ if (cmp != 0) {
+ BstSide side = (cmp < 0) ? LEFT : RIGHT;
+ BstMutationResult<K, N> mutation =
+ mutate(comparator, mutationRule, tree.childOrNull(side), key);
+ return mutation.lift(
+ tree, side, mutationRule.getNodeFactory(), mutationRule.getBalancePolicy());
+ }
+ }
+ return modify(tree, key, mutationRule);
+ }
+
+ /**
+ * Perform the local mutation at the tip of the specified path.
+ */
+ public static <K, N extends BstNode<K, N>> BstMutationResult<K, N> mutate(
+ BstInOrderPath<N> path, BstMutationRule<K, N> mutationRule) {
+ checkNotNull(path);
+ checkNotNull(mutationRule);
+ BstBalancePolicy<N> balancePolicy = mutationRule.getBalancePolicy();
+ BstNodeFactory<N> nodeFactory = mutationRule.getNodeFactory();
+ BstModifier<K, N> modifier = mutationRule.getModifier();
+
+ N target = path.getTip();
+ K key = target.getKey();
+ BstMutationResult<K, N> result = modify(target, key, mutationRule);
+ while (path.hasPrefix()) {
+ BstInOrderPath<N> prefix = path.getPrefix();
+ result = result.lift(prefix.getTip(), path.getSideOfExtension(), nodeFactory, balancePolicy);
+ path = prefix;
+ }
+ return result;
+ }
+
+ /**
+ * Perform the local mutation right here, at the specified node.
+ */
+ private static <K, N extends BstNode<K, N>> BstMutationResult<K, N> modify(
+ @Nullable N tree, K key, BstMutationRule<K, N> mutationRule) {
+ BstBalancePolicy<N> rebalancePolicy = mutationRule.getBalancePolicy();
+ BstNodeFactory<N> nodeFactory = mutationRule.getNodeFactory();
+ BstModifier<K, N> modifier = mutationRule.getModifier();
+
+ N originalRoot = tree;
+ N changedRoot;
+ N originalTarget = (tree == null) ? null : nodeFactory.createLeaf(tree);
+ BstModificationResult<N> modResult = modifier.modify(key, originalTarget);
+ N originalLeft = null;
+ N originalRight = null;
+ if (tree != null) {
+ originalLeft = tree.childOrNull(LEFT);
+ originalRight = tree.childOrNull(RIGHT);
+ }
+ switch (modResult.getType()) {
+ case IDENTITY:
+ changedRoot = tree;
+ break;
+ case REBUILDING_CHANGE:
+ if (modResult.getChangedTarget() != null) {
+ changedRoot =
+ nodeFactory.createNode(modResult.getChangedTarget(), originalLeft, originalRight);
+ } else if (tree == null) {
+ changedRoot = null;
+ } else {
+ throw new AssertionError(
+ "Modification result is a REBUILDING_CHANGE, but rebalancing required");
+ }
+ break;
+ case REBALANCING_CHANGE:
+ if (modResult.getChangedTarget() != null) {
+ changedRoot = rebalancePolicy.balance(
+ nodeFactory, modResult.getChangedTarget(), originalLeft, originalRight);
+ } else if (tree != null) {
+ changedRoot = rebalancePolicy.combine(nodeFactory, originalLeft, originalRight);
+ } else {
+ changedRoot = null;
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+ return BstMutationResult.mutationResult(key, originalRoot, changedRoot, modResult);
+ }
+
+ /**
+ * Returns the result of removing the minimum element from the specified subtree.
+ */
+ public static <K, N extends BstNode<K, N>> BstMutationResult<K, N> extractMin(
+ N root, BstNodeFactory<N> nodeFactory, BstBalancePolicy<N> balancePolicy) {
+ checkNotNull(root);
+ checkNotNull(nodeFactory);
+ checkNotNull(balancePolicy);
+ if (root.hasChild(LEFT)) {
+ BstMutationResult<K, N> subResult =
+ extractMin(root.getChild(LEFT), nodeFactory, balancePolicy);
+ return subResult.lift(root, LEFT, nodeFactory, balancePolicy);
+ }
+ return BstMutationResult.mutationResult(
+ root.getKey(), root, root.childOrNull(RIGHT),
+ BstModificationResult.rebalancingChange(root, null));
+ }
+
+ /**
+ * Returns the result of removing the maximum element from the specified subtree.
+ */
+ public static <K, N extends BstNode<K, N>> BstMutationResult<K, N> extractMax(
+ N root, BstNodeFactory<N> nodeFactory, BstBalancePolicy<N> balancePolicy) {
+ checkNotNull(root);
+ checkNotNull(nodeFactory);
+ checkNotNull(balancePolicy);
+ if (root.hasChild(RIGHT)) {
+ BstMutationResult<K, N> subResult =
+ extractMax(root.getChild(RIGHT), nodeFactory, balancePolicy);
+ return subResult.lift(root, RIGHT, nodeFactory, balancePolicy);
+ }
+ return BstMutationResult.mutationResult(root.getKey(), root, root.childOrNull(LEFT),
+ BstModificationResult.rebalancingChange(root, null));
+ }
+
+ /**
+ * Inserts the specified entry into the tree as the minimum entry. Assumes that {@code
+ * entry.getKey()} is less than the key of all nodes in the subtree {@code root}.
+ */
+ public static <N extends BstNode<?, N>> N insertMin(@Nullable N root, N entry,
+ BstNodeFactory<N> nodeFactory, BstBalancePolicy<N> balancePolicy) {
+ checkNotNull(entry);
+ checkNotNull(nodeFactory);
+ checkNotNull(balancePolicy);
+ if (root == null) {
+ return nodeFactory.createLeaf(entry);
+ } else {
+ return balancePolicy.balance(nodeFactory, root,
+ insertMin(root.childOrNull(LEFT), entry, nodeFactory, balancePolicy),
+ root.childOrNull(RIGHT));
+ }
+ }
+
+ /**
+ * Inserts the specified entry into the tree as the maximum entry. Assumes that {@code
+ * entry.getKey()} is greater than the key of all nodes in the subtree {@code root}.
+ */
+ public static <N extends BstNode<?, N>> N insertMax(@Nullable N root, N entry,
+ BstNodeFactory<N> nodeFactory, BstBalancePolicy<N> balancePolicy) {
+ checkNotNull(entry);
+ checkNotNull(nodeFactory);
+ checkNotNull(balancePolicy);
+ if (root == null) {
+ return nodeFactory.createLeaf(entry);
+ } else {
+ return balancePolicy.balance(nodeFactory, root, root.childOrNull(LEFT),
+ insertMax(root.childOrNull(RIGHT), entry, nodeFactory, balancePolicy));
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/BstPath.java b/guava/src/com/google/common/collect/BstPath.java
new file mode 100644
index 0000000..dd564c7
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstPath.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.annotations.GwtCompatible;
+
+import javax.annotation.Nullable;
+
+/**
+ * A path to a node in a binary search tree, originating at the root.
+ *
+ * @author Louis Wasserman
+ * @param <N> The type of nodes in this binary search tree.
+ * @param <P> This path type, and the path type of all suffix paths.
+ */
+@GwtCompatible
+abstract class BstPath<N extends BstNode<?, N>, P extends BstPath<N, P>> {
+ private final N tip;
+ @Nullable
+ private final P prefix;
+
+ BstPath(N tip, @Nullable P prefix) {
+ this.tip = checkNotNull(tip);
+ this.prefix = prefix;
+ }
+
+ /**
+ * Return the end of this {@code BstPath}, the deepest node in the path.
+ */
+ public final N getTip() {
+ return tip;
+ }
+
+ /**
+ * Returns {@code true} if this path has a prefix.
+ */
+ public final boolean hasPrefix() {
+ return prefix != null;
+ }
+
+ /**
+ * Returns the prefix of this path, which reaches to the parent of the end of this path. Returns
+ * {@code null} if this path has no prefix.
+ */
+ @Nullable
+ public final P prefixOrNull() {
+ return prefix;
+ }
+
+ /**
+ * Returns the prefix of this path, which reaches to the parent of the end of this path.
+ *
+ * @throws IllegalStateException if this path has no prefix.
+ */
+ public final P getPrefix() {
+ checkState(hasPrefix());
+ return prefix;
+ }
+}
diff --git a/guava/src/com/google/common/collect/BstPathFactory.java b/guava/src/com/google/common/collect/BstPathFactory.java
new file mode 100644
index 0000000..92086ae
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstPathFactory.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.annotations.GwtCompatible;
+
+/**
+ * A factory for extending paths in a binary search tree.
+ *
+ * @author Louis Wasserman
+ * @param <N> The type of binary search tree nodes used in the paths generated by this {@code
+ * BstPathFactory}.
+ * @param <P> The type of paths constructed by this {@code BstPathFactory}.
+ */
+@GwtCompatible
+interface BstPathFactory<N extends BstNode<?, N>, P extends BstPath<N, P>> {
+ /**
+ * Returns this path extended by one node to the specified {@code side}.
+ */
+ P extension(P path, BstSide side);
+
+ /**
+ * Returns the trivial path that starts at {@code root} and goes no further.
+ */
+ P initialPath(N root);
+}
diff --git a/guava/src/com/google/common/collect/BstRangeOps.java b/guava/src/com/google/common/collect/BstRangeOps.java
new file mode 100644
index 0000000..10d5931
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstRangeOps.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.BstSide.LEFT;
+import static com.google.common.collect.BstSide.RIGHT;
+
+import com.google.common.annotations.GwtCompatible;
+
+import javax.annotation.Nullable;
+
+/**
+ * A utility class with operations on binary search trees that operate on some interval.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+final class BstRangeOps {
+ /**
+ * Returns the total value of the specified aggregation function on the specified tree restricted
+ * to the specified range. Assumes that the tree satisfies the binary search ordering property
+ * relative to {@code range.comparator()}.
+ */
+ public static <K, N extends BstNode<K, N>> long totalInRange(
+ BstAggregate<? super N> aggregate, GeneralRange<K> range, @Nullable N root) {
+ checkNotNull(aggregate);
+ checkNotNull(range);
+ if (root == null || range.isEmpty()) {
+ return 0;
+ }
+ long total = aggregate.treeValue(root);
+ if (range.hasLowerBound()) {
+ total -= totalBeyondRangeToSide(aggregate, range, LEFT, root);
+ }
+ if (range.hasUpperBound()) {
+ total -= totalBeyondRangeToSide(aggregate, range, RIGHT, root);
+ }
+ return total;
+ }
+
+ // Returns total value strictly to the specified side of the specified range.
+ private static <K, N extends BstNode<K, N>> long totalBeyondRangeToSide(
+ BstAggregate<? super N> aggregate, GeneralRange<K> range, BstSide side, @Nullable N root) {
+ long accum = 0;
+ while (root != null) {
+ if (beyond(range, root.getKey(), side)) {
+ accum += aggregate.entryValue(root);
+ accum += aggregate.treeValue(root.childOrNull(side));
+ root = root.childOrNull(side.other());
+ } else {
+ root = root.childOrNull(side);
+ }
+ }
+ return accum;
+ }
+
+ /**
+ * Returns a balanced tree containing all nodes from the specified tree that were <i>not</i> in
+ * the specified range, using the specified balance policy. Assumes that the tree satisfies the
+ * binary search ordering property relative to {@code range.comparator()}.
+ */
+ @Nullable
+ public static <K, N extends BstNode<K, N>> N minusRange(GeneralRange<K> range,
+ BstBalancePolicy<N> balancePolicy, BstNodeFactory<N> nodeFactory, @Nullable N root) {
+ checkNotNull(range);
+ checkNotNull(balancePolicy);
+ checkNotNull(nodeFactory);
+ N higher = range.hasUpperBound()
+ ? subTreeBeyondRangeToSide(range, balancePolicy, nodeFactory, RIGHT, root)
+ : null;
+ N lower = range.hasLowerBound()
+ ? subTreeBeyondRangeToSide(range, balancePolicy, nodeFactory, LEFT, root)
+ : null;
+ return balancePolicy.combine(nodeFactory, lower, higher);
+ }
+
+ /*
+ * Returns a balanced tree containing all nodes in the specified tree that are strictly to the
+ * specified side of the specified range.
+ */
+ @Nullable
+ private static <K, N extends BstNode<K, N>> N subTreeBeyondRangeToSide(GeneralRange<K> range,
+ BstBalancePolicy<N> balancePolicy, BstNodeFactory<N> nodeFactory, BstSide side,
+ @Nullable N root) {
+ if (root == null) {
+ return null;
+ }
+ if (beyond(range, root.getKey(), side)) {
+ N left = root.childOrNull(LEFT);
+ N right = root.childOrNull(RIGHT);
+ switch (side) {
+ case LEFT:
+ right = subTreeBeyondRangeToSide(range, balancePolicy, nodeFactory, LEFT, right);
+ break;
+ case RIGHT:
+ left = subTreeBeyondRangeToSide(range, balancePolicy, nodeFactory, RIGHT, left);
+ break;
+ default:
+ throw new AssertionError();
+ }
+ return balancePolicy.balance(nodeFactory, root, left, right);
+ } else {
+ return subTreeBeyondRangeToSide(
+ range, balancePolicy, nodeFactory, side, root.childOrNull(side));
+ }
+ }
+
+ /**
+ * Returns the furthest path to the specified side in the specified tree that falls into the
+ * specified range.
+ */
+ @Nullable
+ public static <K, N extends BstNode<K, N>, P extends BstPath<N, P>> P furthestPath(
+ GeneralRange<K> range, BstSide side, BstPathFactory<N, P> pathFactory, @Nullable N root) {
+ checkNotNull(range);
+ checkNotNull(pathFactory);
+ checkNotNull(side);
+ if (root == null) {
+ return null;
+ }
+ P path = pathFactory.initialPath(root);
+ return furthestPath(range, side, pathFactory, path);
+ }
+
+ private static <K, N extends BstNode<K, N>, P extends BstPath<N, P>> P furthestPath(
+ GeneralRange<K> range, BstSide side, BstPathFactory<N, P> pathFactory, P currentPath) {
+ N tip = currentPath.getTip();
+ K tipKey = tip.getKey();
+ if (beyond(range, tipKey, side)) {
+ if (tip.hasChild(side.other())) {
+ currentPath = pathFactory.extension(currentPath, side.other());
+ return furthestPath(range, side, pathFactory, currentPath);
+ } else {
+ return null;
+ }
+ } else if (tip.hasChild(side)) {
+ P alphaPath = pathFactory.extension(currentPath, side);
+ alphaPath = furthestPath(range, side, pathFactory, alphaPath);
+ if (alphaPath != null) {
+ return alphaPath;
+ }
+ }
+ return beyond(range, tipKey, side.other()) ? null : currentPath;
+ }
+
+ /**
+ * Returns {@code true} if {@code key} is beyond the specified side of the specified range.
+ */
+ public static <K> boolean beyond(GeneralRange<K> range, @Nullable K key, BstSide side) {
+ checkNotNull(range);
+ switch (side) {
+ case LEFT:
+ return range.tooLow(key);
+ case RIGHT:
+ return range.tooHigh(key);
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private BstRangeOps() {}
+}
diff --git a/guava/src/com/google/common/collect/BstSide.java b/guava/src/com/google/common/collect/BstSide.java
new file mode 100644
index 0000000..5dec1bc
--- /dev/null
+++ b/guava/src/com/google/common/collect/BstSide.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.annotations.GwtCompatible;
+
+/**
+ * A side of a binary search tree node, used to index its children.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+enum BstSide {
+ LEFT {
+ @Override
+ public BstSide other() {
+ return RIGHT;
+ }
+ },
+ RIGHT {
+ @Override
+ public BstSide other() {
+ return LEFT;
+ }
+ };
+
+ abstract BstSide other();
+}
diff --git a/guava/src/com/google/common/collect/CartesianList.java b/guava/src/com/google/common/collect/CartesianList.java
deleted file mode 100644
index 62f9227..0000000
--- a/guava/src/com/google/common/collect/CartesianList.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkElementIndex;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.math.IntMath;
-
-import java.util.AbstractList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-
-import javax.annotation.Nullable;
-
-/**
- * Implementation of {@link Lists#cartesianProduct(List)}.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible
-final class CartesianList<E> extends AbstractList<List<E>> {
-
- private transient final ImmutableList<List<E>> axes;
- private transient final int[] axesSizeProduct;
-
- static <E> List<List<E>> create(List<? extends List<? extends E>> lists) {
- ImmutableList.Builder<List<E>> axesBuilder =
- new ImmutableList.Builder<List<E>>(lists.size());
- for (List<? extends E> list : lists) {
- List<E> copy = ImmutableList.copyOf(list);
- if (copy.isEmpty()) {
- return ImmutableList.of();
- }
- axesBuilder.add(copy);
- }
- return new CartesianList<E>(axesBuilder.build());
- }
-
- CartesianList(ImmutableList<List<E>> axes) {
- this.axes = axes;
- int[] axesSizeProduct = new int[axes.size() + 1];
- axesSizeProduct[axes.size()] = 1;
- try {
- for (int i = axes.size() - 1; i >= 0; i--) {
- axesSizeProduct[i] =
- IntMath.checkedMultiply(axesSizeProduct[i + 1], axes.get(i).size());
- }
- } catch (ArithmeticException e) {
- throw new IllegalArgumentException(
- "Cartesian product too large; must have size at most Integer.MAX_VALUE");
- }
- this.axesSizeProduct = axesSizeProduct;
- }
-
- private int getAxisIndexForProductIndex(int index, int axis) {
- return (index / axesSizeProduct[axis + 1]) % axes.get(axis).size();
- }
-
- @Override
- public ImmutableList<E> get(final int index) {
- checkElementIndex(index, size());
- return new ImmutableList<E>() {
-
- @Override
- public int size() {
- return axes.size();
- }
-
- @Override
- public E get(int axis) {
- checkElementIndex(axis, size());
- int axisIndex = getAxisIndexForProductIndex(index, axis);
- return axes.get(axis).get(axisIndex);
- }
-
- @Override
- boolean isPartialView() {
- return true;
- }
- };
- }
-
- @Override
- public int size() {
- return axesSizeProduct[0];
- }
-
- @Override
- public boolean contains(@Nullable Object o) {
- if (!(o instanceof List)) {
- return false;
- }
- List<?> list = (List<?>) o;
- if (list.size() != axes.size()) {
- return false;
- }
- ListIterator<?> itr = list.listIterator();
- while (itr.hasNext()) {
- int index = itr.nextIndex();
- if (!axes.get(index).contains(itr.next())) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public int indexOf(Object o) {
- if (!(o instanceof List)) {
- return -1;
- }
- List<?> l = (List<?>) o;
- if (l.size() != axes.size()) {
- return -1;
- }
- Iterator<?> lIterator = l.iterator();
- int i = 0;
- for (List<E> axis : axes) {
- Object lElement = lIterator.next();
- int axisIndex = axis.indexOf(lElement);
- if (axisIndex == -1) {
- return -1;
- }
- i = (i * axis.size()) + axisIndex;
- }
- return i;
- }
-
- @Override
- public int lastIndexOf(Object o) {
- if (!(o instanceof List)) {
- return -1;
- }
- List<?> l = (List<?>) o;
- if (l.size() != axes.size()) {
- return -1;
- }
- Iterator<?> lIterator = l.iterator();
- int i = 0;
- for (List<E> axis : axes) {
- Object lElement = lIterator.next();
- int axisIndex = axis.lastIndexOf(lElement);
- if (axisIndex == -1) {
- return -1;
- }
- i = (i * axis.size()) + axisIndex;
- }
- return i;
- }
-}
diff --git a/guava/src/com/google/common/collect/ClassToInstanceMap.java b/guava/src/com/google/common/collect/ClassToInstanceMap.java
index b3f535c..6b6fb5b 100644
--- a/guava/src/com/google/common/collect/ClassToInstanceMap.java
+++ b/guava/src/com/google/common/collect/ClassToInstanceMap.java
@@ -31,13 +31,6 @@ import javax.annotation.Nullable;
* <p>Like any other {@code Map<Class, Object>}, this map may contain entries
* for primitive types, and a primitive type and its corresponding wrapper type
* may map to different values.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#ClassToInstanceMap">
- * {@code ClassToInstanceMap}</a>.
- *
- * <p>To map a generic type to an instance of that type, use {@link
- * com.google.common.reflect.TypeToInstanceMap} instead.
*
* @param <B> the common supertype that all entries must share; often this is
* simply {@link Object}
diff --git a/guava/src/com/google/common/collect/Collections2.java b/guava/src/com/google/common/collect/Collections2.java
index 7805e0b..603fa8b 100644
--- a/guava/src/com/google/common/collect/Collections2.java
+++ b/guava/src/com/google/common/collect/Collections2.java
@@ -18,27 +18,21 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.math.LongMath.binomial;
-import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
-import com.google.common.math.IntMath;
import com.google.common.primitives.Ints;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
-import javax.annotation.Nullable;
-
/**
* Provides static methods for working with {@code Collection} instances.
*
@@ -95,33 +89,13 @@ public final class Collections2 {
/**
* Delegates to {@link Collection#contains}. Returns {@code false} if the
- * {@code contains} method throws a {@code ClassCastException} or
- * {@code NullPointerException}.
+ * {@code contains} method throws a {@code ClassCastException}.
*/
static boolean safeContains(Collection<?> collection, Object object) {
- checkNotNull(collection);
try {
return collection.contains(object);
} catch (ClassCastException e) {
return false;
- } catch (NullPointerException e) {
- return false;
- }
- }
-
- /**
- * Delegates to {@link Collection#remove}. Returns {@code false} if the
- * {@code remove} method throws a {@code ClassCastException} or
- * {@code NullPointerException}.
- */
- static boolean safeRemove(Collection<?> collection, Object object) {
- checkNotNull(collection);
- try {
- return collection.remove(object);
- } catch (ClassCastException e) {
- return false;
- } catch (NullPointerException e) {
- return false;
}
}
@@ -163,9 +137,6 @@ public final class Collections2 {
@Override
public boolean contains(Object element) {
try {
- // TODO(user): consider doing the predicate after unfiltered.contains,
- // which would reduce the risk of CCE here
-
// unsafe cast can result in a CCE from predicate.apply(), which we
// will catch
@SuppressWarnings("unchecked")
@@ -207,9 +178,6 @@ public final class Collections2 {
@Override
public boolean remove(Object element) {
try {
- // TODO(user): consider doing the predicate after unfiltered.contains,
- // which would reduce the risk of CCE here
-
// unsafe cast can result in a CCE from predicate.apply(), which we
// will catch
@SuppressWarnings("unchecked")
@@ -373,357 +341,8 @@ public final class Collections2 {
return (Collection<T>) iterable;
}
- static final Joiner STANDARD_JOINER = Joiner.on(", ").useForNull("null");
-
- /**
- * Returns a {@link Collection} of all the permutations of the specified
- * {@link Iterable}.
- *
- * <p><i>Notes:</i> This is an implementation of the algorithm for
- * Lexicographical Permutations Generation, described in Knuth's "The Art of
- * Computer Programming", Volume 4, Chapter 7, Section 7.2.1.2. The
- * iteration order follows the lexicographical order. This means that
- * the first permutation will be in ascending order, and the last will be in
- * descending order.
- *
- * <p>Duplicate elements are considered equal. For example, the list [1, 1]
- * will have only one permutation, instead of two. This is why the elements
- * have to implement {@link Comparable}.
- *
- * <p>An empty iterable has only one permutation, which is an empty list.
- *
- * <p>This method is equivalent to
- * {@code Collections2.orderedPermutations(list, Ordering.natural())}.
- *
- * @param elements the original iterable whose elements have to be permuted.
- * @return an immutable {@link Collection} containing all the different
- * permutations of the original iterable.
- * @throws NullPointerException if the specified iterable is null or has any
- * null elements.
- * @since 12.0
- */
- @Beta public static <E extends Comparable<? super E>>
- Collection<List<E>> orderedPermutations(Iterable<E> elements) {
- return orderedPermutations(elements, Ordering.natural());
- }
-
- /**
- * Returns a {@link Collection} of all the permutations of the specified
- * {@link Iterable} using the specified {@link Comparator} for establishing
- * the lexicographical ordering.
- *
- * <p>Examples: <pre> {@code
- *
- * for (List<String> perm : orderedPermutations(asList("b", "c", "a"))) {
- * println(perm);
- * }
- * // -> ["a", "b", "c"]
- * // -> ["a", "c", "b"]
- * // -> ["b", "a", "c"]
- * // -> ["b", "c", "a"]
- * // -> ["c", "a", "b"]
- * // -> ["c", "b", "a"]
- *
- * for (List<Integer> perm : orderedPermutations(asList(1, 2, 2, 1))) {
- * println(perm);
- * }
- * // -> [1, 1, 2, 2]
- * // -> [1, 2, 1, 2]
- * // -> [1, 2, 2, 1]
- * // -> [2, 1, 1, 2]
- * // -> [2, 1, 2, 1]
- * // -> [2, 2, 1, 1]}</pre>
- *
- * <p><i>Notes:</i> This is an implementation of the algorithm for
- * Lexicographical Permutations Generation, described in Knuth's "The Art of
- * Computer Programming", Volume 4, Chapter 7, Section 7.2.1.2. The
- * iteration order follows the lexicographical order. This means that
- * the first permutation will be in ascending order, and the last will be in
- * descending order.
- *
- * <p>Elements that compare equal are considered equal and no new permutations
- * are created by swapping them.
- *
- * <p>An empty iterable has only one permutation, which is an empty list.
- *
- * @param elements the original iterable whose elements have to be permuted.
- * @param comparator a comparator for the iterable's elements.
- * @return an immutable {@link Collection} containing all the different
- * permutations of the original iterable.
- * @throws NullPointerException If the specified iterable is null, has any
- * null elements, or if the specified comparator is null.
- * @since 12.0
- */
- @Beta public static <E> Collection<List<E>> orderedPermutations(
- Iterable<E> elements, Comparator<? super E> comparator) {
- return new OrderedPermutationCollection<E>(elements, comparator);
- }
-
- private static final class OrderedPermutationCollection<E>
- extends AbstractCollection<List<E>> {
- final ImmutableList<E> inputList;
- final Comparator<? super E> comparator;
- final int size;
-
- OrderedPermutationCollection(Iterable<E> input,
- Comparator<? super E> comparator) {
- this.inputList = Ordering.from(comparator).immutableSortedCopy(input);
- this.comparator = comparator;
- this.size = calculateSize(inputList, comparator);
- }
-
- /**
- * The number of permutations with repeated elements is calculated as
- * follows:
- * <ul>
- * <li>For an empty list, it is 1 (base case).</li>
- * <li>When r numbers are added to a list of n-r elements, the number of
- * permutations is increased by a factor of (n choose r).</li>
- * </ul>
- */
- private static <E> int calculateSize(
- List<E> sortedInputList, Comparator<? super E> comparator) {
- long permutations = 1;
- int n = 1;
- int r = 1;
- while (n < sortedInputList.size()) {
- int comparison = comparator.compare(
- sortedInputList.get(n - 1), sortedInputList.get(n));
- if (comparison < 0) {
- // We move to the next non-repeated element.
- permutations *= binomial(n, r);
- r = 0;
- if (!isPositiveInt(permutations)) {
- return Integer.MAX_VALUE;
- }
- }
- n++;
- r++;
- }
- permutations *= binomial(n, r);
- if (!isPositiveInt(permutations)) {
- return Integer.MAX_VALUE;
- }
- return (int) permutations;
- }
-
- @Override public int size() {
- return size;
- }
-
- @Override public boolean isEmpty() {
- return false;
- }
-
- @Override public Iterator<List<E>> iterator() {
- return new OrderedPermutationIterator<E>(inputList, comparator);
- }
-
- @Override public boolean contains(@Nullable Object obj) {
- if (obj instanceof List) {
- List<?> list = (List<?>) obj;
- return isPermutation(inputList, list);
- }
- return false;
- }
-
- @Override public String toString() {
- return "orderedPermutationCollection(" + inputList + ")";
- }
- }
-
- private static final class OrderedPermutationIterator<E>
- extends AbstractIterator<List<E>> {
-
- List<E> nextPermutation;
- final Comparator<? super E> comparator;
-
- OrderedPermutationIterator(List<E> list,
- Comparator<? super E> comparator) {
- this.nextPermutation = Lists.newArrayList(list);
- this.comparator = comparator;
- }
-
- @Override protected List<E> computeNext() {
- if (nextPermutation == null) {
- return endOfData();
- }
- ImmutableList<E> next = ImmutableList.copyOf(nextPermutation);
- calculateNextPermutation();
- return next;
- }
-
- void calculateNextPermutation() {
- int j = findNextJ();
- if (j == -1) {
- nextPermutation = null;
- return;
- }
-
- int l = findNextL(j);
- Collections.swap(nextPermutation, j, l);
- int n = nextPermutation.size();
- Collections.reverse(nextPermutation.subList(j + 1, n));
- }
-
- int findNextJ() {
- for (int k = nextPermutation.size() - 2; k >= 0; k--) {
- if (comparator.compare(nextPermutation.get(k),
- nextPermutation.get(k + 1)) < 0) {
- return k;
- }
- }
- return -1;
- }
-
- int findNextL(int j) {
- E ak = nextPermutation.get(j);
- for (int l = nextPermutation.size() - 1; l > j; l--) {
- if (comparator.compare(ak, nextPermutation.get(l)) < 0) {
- return l;
- }
- }
- throw new AssertionError("this statement should be unreachable");
- }
- }
-
- /**
- * Returns a {@link Collection} of all the permutations of the specified
- * {@link Collection}.
- *
- * <p><i>Notes:</i> This is an implementation of the Plain Changes algorithm
- * for permutations generation, described in Knuth's "The Art of Computer
- * Programming", Volume 4, Chapter 7, Section 7.2.1.2.
- *
- * <p>If the input list contains equal elements, some of the generated
- * permutations will be equal.
- *
- * <p>An empty collection has only one permutation, which is an empty list.
- *
- * @param elements the original collection whose elements have to be permuted.
- * @return an immutable {@link Collection} containing all the different
- * permutations of the original collection.
- * @throws NullPointerException if the specified collection is null or has any
- * null elements.
- * @since 12.0
- */
- @Beta public static <E> Collection<List<E>> permutations(
- Collection<E> elements) {
- return new PermutationCollection<E>(ImmutableList.copyOf(elements));
- }
-
- private static final class PermutationCollection<E>
- extends AbstractCollection<List<E>> {
- final ImmutableList<E> inputList;
-
- PermutationCollection(ImmutableList<E> input) {
- this.inputList = input;
- }
-
- @Override public int size() {
- return IntMath.factorial(inputList.size());
- }
-
- @Override public boolean isEmpty() {
- return false;
- }
-
- @Override public Iterator<List<E>> iterator() {
- return new PermutationIterator<E>(inputList);
- }
-
- @Override public boolean contains(@Nullable Object obj) {
- if (obj instanceof List) {
- List<?> list = (List<?>) obj;
- return isPermutation(inputList, list);
- }
- return false;
- }
-
- @Override public String toString() {
- return "permutations(" + inputList + ")";
- }
- }
-
- private static class PermutationIterator<E>
- extends AbstractIterator<List<E>> {
- final List<E> list;
- final int[] c;
- final int[] o;
- int j;
-
- PermutationIterator(List<E> list) {
- this.list = new ArrayList<E>(list);
- int n = list.size();
- c = new int[n];
- o = new int[n];
- for (int i = 0; i < n; i++) {
- c[i] = 0;
- o[i] = 1;
- }
- j = Integer.MAX_VALUE;
- }
-
- @Override protected List<E> computeNext() {
- if (j <= 0) {
- return endOfData();
- }
- ImmutableList<E> next = ImmutableList.copyOf(list);
- calculateNextPermutation();
- return next;
- }
+ static final Joiner STANDARD_JOINER = Joiner.on(", ");
- void calculateNextPermutation() {
- j = list.size() - 1;
- int s = 0;
-
- // Handle the special case of an empty list. Skip the calculation of the
- // next permutation.
- if (j == -1) {
- return;
- }
-
- while (true) {
- int q = c[j] + o[j];
- if (q < 0) {
- switchDirection();
- continue;
- }
- if (q == j + 1) {
- if (j == 0) {
- break;
- }
- s++;
- switchDirection();
- continue;
- }
-
- Collections.swap(list, j - c[j] + s, j - q + s);
- c[j] = q;
- break;
- }
- }
-
- void switchDirection() {
- o[j] = -o[j];
- j--;
- }
- }
-
- /**
- * Returns {@code true} if the second list is a permutation of the first.
- */
- private static boolean isPermutation(List<?> first,
- List<?> second) {
- if (first.size() != second.size()) {
- return false;
- }
- Multiset<?> firstSet = HashMultiset.create(first);
- Multiset<?> secondSet = HashMultiset.create(second);
- return firstSet.equals(secondSet);
- }
-
- private static boolean isPositiveInt(long n) {
- return n >= 0 && n <= Integer.MAX_VALUE;
- }
+ // TODO(user): Maybe move the mathematical methods to a separate
+ // package-permission class.
}
diff --git a/guava/src/com/google/common/collect/ComparatorOrdering.java b/guava/src/com/google/common/collect/ComparatorOrdering.java
index 5eb7612..77fe58d 100644
--- a/guava/src/com/google/common/collect/ComparatorOrdering.java
+++ b/guava/src/com/google/common/collect/ComparatorOrdering.java
@@ -21,7 +21,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
import java.io.Serializable;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@@ -53,17 +52,6 @@ final class ComparatorOrdering<T> extends Ordering<T> implements Serializable {
return list;
}
- // Override just to remove a level of indirection from inner loops
- @Override public <E extends T> ImmutableList<E> immutableSortedCopy(Iterable<E> iterable) {
- @SuppressWarnings("unchecked") // we'll only ever have E's in here
- E[] elements = (E[]) Iterables.toArray(iterable);
- for (E e : elements) {
- checkNotNull(e);
- }
- Arrays.sort(elements, comparator);
- return ImmutableList.asImmutableList(elements);
- }
-
@Override public boolean equals(@Nullable Object object) {
if (object == this) {
return true;
diff --git a/guava/src/com/google/common/collect/ComparisonChain.java b/guava/src/com/google/common/collect/ComparisonChain.java
index 2ed8cc4..cc90357 100644
--- a/guava/src/com/google/common/collect/ComparisonChain.java
+++ b/guava/src/com/google/common/collect/ComparisonChain.java
@@ -44,10 +44,6 @@ import javax.annotation.Nullable;
*
* <p>Once any comparison returns a nonzero value, remaining comparisons are
* "short-circuited".
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained#compare/compareTo">
- * {@code ComparisonChain}</a>.
*
* @author Mark Davis
* @author Kevin Bourrillion
@@ -87,10 +83,7 @@ public abstract class ComparisonChain {
@Override public ComparisonChain compare(double left, double right) {
return classify(Double.compare(left, right));
}
- @Override public ComparisonChain compareTrueFirst(boolean left, boolean right) {
- return classify(Booleans.compare(right, left)); // reversed
- }
- @Override public ComparisonChain compareFalseFirst(boolean left, boolean right) {
+ @Override public ComparisonChain compare(boolean left, boolean right) {
return classify(Booleans.compare(left, right));
}
ComparisonChain classify(int result) {
@@ -131,10 +124,7 @@ public abstract class ComparisonChain {
@Override public ComparisonChain compare(double left, double right) {
return this;
}
- @Override public ComparisonChain compareTrueFirst(boolean left, boolean right) {
- return this;
- }
- @Override public ComparisonChain compareFalseFirst(boolean left, boolean right) {
+ @Override public ComparisonChain compare(boolean left, boolean right) {
return this;
}
@Override public int result() {
@@ -186,35 +176,11 @@ public abstract class ComparisonChain {
public abstract ComparisonChain compare(double left, double right);
/**
- * Compares two {@code boolean} values, considering {@code true} to be less
- * than {@code false}, <i>if</i> the result of this comparison chain has not
+ * Compares two {@code boolean} values as specified by {@link
+ * Booleans#compare}, <i>if</i> the result of this comparison chain has not
* already been determined.
- *
- * @since 12.0
*/
- public abstract ComparisonChain compareTrueFirst(boolean left, boolean right);
-
- /**
- * Compares two {@code boolean} values, considering {@code false} to be less
- * than {@code true}, <i>if</i> the result of this comparison chain has not
- * already been determined.
- *
- * @since 12.0 (present as {@code compare} since 2.0)
- */
- public abstract ComparisonChain compareFalseFirst(boolean left, boolean right);
-
- /**
- * Old name of {@link #compareFalseFirst}.
- *
- * @deprecated Use {@link #compareFalseFirst}; or, if the parameters passed
- * are being either negated or reversed, undo the negation or reversal and
- * use {@link #compareTrueFirst}. <b>This method is scheduled for deletion
- * in September 2013.</b>
- */
- @Deprecated
- public final ComparisonChain compare(boolean left, boolean right) {
- return compareFalseFirst(left, right);
- }
+ public abstract ComparisonChain compare(boolean left, boolean right);
/**
* Ends this comparison chain and returns its result: a value having the
diff --git a/guava/src/com/google/common/collect/CompoundOrdering.java b/guava/src/com/google/common/collect/CompoundOrdering.java
index 26ebf54..f669a62 100644
--- a/guava/src/com/google/common/collect/CompoundOrdering.java
+++ b/guava/src/com/google/common/collect/CompoundOrdering.java
@@ -20,6 +20,7 @@ import com.google.common.annotations.GwtCompatible;
import java.io.Serializable;
import java.util.Comparator;
+import java.util.List;
/** An ordering that tries several comparators in order. */
@GwtCompatible(serializable = true)
@@ -36,11 +37,15 @@ final class CompoundOrdering<T> extends Ordering<T> implements Serializable {
this.comparators = ImmutableList.copyOf(comparators);
}
+ CompoundOrdering(List<? extends Comparator<? super T>> comparators,
+ Comparator<? super T> lastComparator) {
+ this.comparators = new ImmutableList.Builder<Comparator<? super T>>()
+ .addAll(comparators).add(lastComparator).build();
+ }
+
@Override public int compare(T left, T right) {
- // Avoid using the Iterator to avoid generating garbage (issue 979).
- int size = comparators.size();
- for (int i = 0; i < size; i++) {
- int result = comparators.get(i).compare(left, right);
+ for (Comparator<? super T> comparator : comparators) {
+ int result = comparator.compare(left, right);
if (result != 0) {
return result;
}
diff --git a/guava/src/com/google/common/collect/ComputationException.java b/guava/src/com/google/common/collect/ComputationException.java
index ac80d6a..5401aff 100644
--- a/guava/src/com/google/common/collect/ComputationException.java
+++ b/guava/src/com/google/common/collect/ComputationException.java
@@ -18,8 +18,6 @@ package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
-import javax.annotation.Nullable;
-
/**
* Wraps an exception that occurred during a computation.
*
@@ -31,7 +29,7 @@ public class ComputationException extends RuntimeException {
/**
* Creates a new instance with the given cause.
*/
- public ComputationException(@Nullable Throwable cause) {
+ public ComputationException(Throwable cause) {
super(cause);
}
private static final long serialVersionUID = 0;
diff --git a/guava/src/com/google/common/collect/ComputingConcurrentHashMap.java b/guava/src/com/google/common/collect/ComputingConcurrentHashMap.java
index eb7363a..1e37edc 100644
--- a/guava/src/com/google/common/collect/ComputingConcurrentHashMap.java
+++ b/guava/src/com/google/common/collect/ComputingConcurrentHashMap.java
@@ -223,8 +223,7 @@ class ComputingConcurrentHashMap<K, V> extends MapMakerInternalMap<K, V> {
}
@Override
- public ValueReference<K, V> copyFor(
- ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
+ public ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) {
return this;
}
@@ -263,8 +262,7 @@ class ComputingConcurrentHashMap<K, V> extends MapMakerInternalMap<K, V> {
}
@Override
- public ValueReference<K, V> copyFor(
- ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
+ public ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) {
return this;
}
@@ -305,8 +303,7 @@ class ComputingConcurrentHashMap<K, V> extends MapMakerInternalMap<K, V> {
}
@Override
- public ValueReference<K, V> copyFor(
- ReferenceQueue<V> queue, @Nullable V value, ReferenceEntry<K, V> entry) {
+ public ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) {
return this;
}
diff --git a/guava/src/com/google/common/collect/ConcurrentHashMultiset.java b/guava/src/com/google/common/collect/ConcurrentHashMultiset.java
index 1a1331b..46b8d6e 100644
--- a/guava/src/com/google/common/collect/ConcurrentHashMultiset.java
+++ b/guava/src/com/google/common/collect/ConcurrentHashMultiset.java
@@ -17,7 +17,6 @@
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Multisets.checkNonnegative;
@@ -31,7 +30,6 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
-import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -46,10 +44,6 @@ import javax.annotation.Nullable;
* A multiset that supports concurrent modifications and that provides atomic versions of most
* {@code Multiset} operations (exceptions where noted). Null elements are not supported.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset">
- * {@code Multiset}</a>.
- *
* @author Cliff L. Biffle
* @author mike nonemacher
* @since 2.0 (imported from Google Collections Library)
@@ -118,7 +112,7 @@ public final class ConcurrentHashMultiset<E> extends AbstractMultiset<E> impleme
* <p>Finally, soft/weak values can be used but are not very useful: the values are created
* internally and not exposed externally, so no one else will have a strong reference to the
* values. Weak keys on the other hand can be useful in some scenarios.
- *
+ *
* @since 7.0
*/
@Beta
@@ -151,11 +145,26 @@ public final class ConcurrentHashMultiset<E> extends AbstractMultiset<E> impleme
* @return the nonnegative number of occurrences of the element
*/
@Override public int count(@Nullable Object element) {
- AtomicInteger existingCounter = Maps.safeGet(countMap, element);
+ AtomicInteger existingCounter = safeGet(element);
return (existingCounter == null) ? 0 : existingCounter.get();
}
/**
+ * Depending on the type of the underlying map, map.get may throw NullPointerException or
+ * ClassCastException, if the object is null or of the wrong type. We usually just want to treat
+ * those cases as if the element isn't in the map, by catching the exceptions and returning null.
+ */
+ private AtomicInteger safeGet(Object element) {
+ try {
+ return countMap.get(element);
+ } catch (NullPointerException e) {
+ return null;
+ } catch (ClassCastException e) {
+ return null;
+ }
+ }
+
+ /**
* {@inheritDoc}
*
* <p>If the data in the multiset is modified by any other threads during this method,
@@ -209,14 +218,13 @@ public final class ConcurrentHashMultiset<E> extends AbstractMultiset<E> impleme
* the resulting amount would exceed {@link Integer#MAX_VALUE}
*/
@Override public int add(E element, int occurrences) {
- checkNotNull(element);
if (occurrences == 0) {
return count(element);
}
checkArgument(occurrences > 0, "Invalid occurrences: %s", occurrences);
while (true) {
- AtomicInteger existingCounter = Maps.safeGet(countMap, element);
+ AtomicInteger existingCounter = safeGet(element);
if (existingCounter == null) {
existingCounter = countMap.putIfAbsent(element, new AtomicInteger(occurrences));
if (existingCounter == null) {
@@ -264,22 +272,13 @@ public final class ConcurrentHashMultiset<E> extends AbstractMultiset<E> impleme
* @return the count of the element before the operation; possibly zero
* @throws IllegalArgumentException if {@code occurrences} is negative
*/
- /*
- * TODO(cpovirk): remove and removeExactly currently accept null inputs only
- * if occurrences == 0. This satisfies both NullPointerTester and
- * CollectionRemoveTester.testRemove_nullAllowed, but it's not clear that it's
- * a good policy, especially because, in order for the test to pass, the
- * parameter must be misleadingly annotated as @Nullable. I suspect that
- * we'll want to remove @Nullable, add an eager checkNotNull, and loosen up
- * testRemove_nullAllowed.
- */
@Override public int remove(@Nullable Object element, int occurrences) {
if (occurrences == 0) {
return count(element);
}
checkArgument(occurrences > 0, "Invalid occurrences: %s", occurrences);
- AtomicInteger existingCounter = Maps.safeGet(countMap, element);
+ AtomicInteger existingCounter = safeGet(element);
if (existingCounter == null) {
return 0;
}
@@ -318,7 +317,7 @@ public final class ConcurrentHashMultiset<E> extends AbstractMultiset<E> impleme
}
checkArgument(occurrences > 0, "Invalid occurrences: %s", occurrences);
- AtomicInteger existingCounter = Maps.safeGet(countMap, element);
+ AtomicInteger existingCounter = safeGet(element);
if (existingCounter == null) {
return false;
}
@@ -347,10 +346,9 @@ public final class ConcurrentHashMultiset<E> extends AbstractMultiset<E> impleme
* @throws IllegalArgumentException if {@code count} is negative
*/
@Override public int setCount(E element, int count) {
- checkNotNull(element);
checkNonnegative(count, "count");
while (true) {
- AtomicInteger existingCounter = Maps.safeGet(countMap, element);
+ AtomicInteger existingCounter = safeGet(element);
if (existingCounter == null) {
if (count == 0) {
return 0;
@@ -402,11 +400,10 @@ public final class ConcurrentHashMultiset<E> extends AbstractMultiset<E> impleme
* @throws IllegalArgumentException if {@code expectedOldCount} or {@code newCount} is negative
*/
@Override public boolean setCount(E element, int expectedOldCount, int newCount) {
- checkNotNull(element);
checkNonnegative(expectedOldCount, "oldCount");
checkNonnegative(newCount, "newCount");
- AtomicInteger existingCounter = Maps.safeGet(countMap, element);
+ AtomicInteger existingCounter = safeGet(element);
if (existingCounter == null) {
if (expectedOldCount != 0) {
return false;
@@ -451,23 +448,14 @@ public final class ConcurrentHashMultiset<E> extends AbstractMultiset<E> impleme
@Override protected Set<E> delegate() {
return delegate;
}
-
- @Override
- public boolean contains(@Nullable Object object) {
- return object != null && Collections2.safeContains(delegate, object);
- }
-
- @Override
- public boolean containsAll(Collection<?> collection) {
- return standardContainsAll(collection);
- }
-
@Override public boolean remove(Object object) {
- return object != null && Collections2.safeRemove(delegate, object);
- }
-
- @Override public boolean removeAll(Collection<?> c) {
- return standardRemoveAll(c);
+ try {
+ return delegate.remove(object);
+ } catch (NullPointerException e) {
+ return false;
+ } catch (ClassCastException e) {
+ return false;
+ }
}
};
}
@@ -559,6 +547,21 @@ public final class ConcurrentHashMultiset<E> extends AbstractMultiset<E> impleme
Iterators.addAll(list, iterator());
return list;
}
+
+ @Override public boolean remove(Object object) {
+ if (object instanceof Multiset.Entry) {
+ Multiset.Entry<?> entry = (Multiset.Entry<?>) object;
+ Object element = entry.getElement();
+ int entryCount = entry.getCount();
+ if (entryCount != 0) {
+ // Safe as long as we never add a new entry, which we won't.
+ @SuppressWarnings("unchecked")
+ Multiset<Object> multiset = (Multiset) multiset();
+ return multiset.setCount(element, entryCount, 0);
+ }
+ }
+ return false;
+ }
}
/**
diff --git a/guava/src/com/google/common/collect/ContiguousSet.java b/guava/src/com/google/common/collect/ContiguousSet.java
index dc9aa83..439f675 100644
--- a/guava/src/com/google/common/collect/ContiguousSet.java
+++ b/guava/src/com/google/common/collect/ContiguousSet.java
@@ -19,63 +19,19 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
-import java.util.Collections;
import java.util.NoSuchElementException;
-import java.util.Set;
/**
* A sorted set of contiguous values in a given {@link DiscreteDomain}.
*
- * <p><b>Warning:</b> Be extremely careful what you do with conceptually large instances (such as
- * {@code ContiguousSet.create(Range.greaterThan(0), DiscreteDomains.integers()}). Certain
- * operations on such a set can be performed efficiently, but others (such as {@link Set#hashCode}
- * or {@link Collections#frequency}) can cause major performance problems.
- *
* @author Gregory Kick
* @since 10.0
*/
@Beta
-@GwtCompatible(emulated = true)
-@SuppressWarnings("rawtypes") // allow ungenerified Comparable types
+@GwtCompatible
+@SuppressWarnings("unchecked") // allow ungenerified Comparable types
public abstract class ContiguousSet<C extends Comparable> extends ImmutableSortedSet<C> {
- /**
- * Returns a {@code ContiguousSet} containing the same values in the given domain
- * {@linkplain Range#contains contained} by the range.
- *
- * @throws IllegalArgumentException if neither range nor the domain has a lower bound, or if
- * neither has an upper bound
- *
- * @since 13.0
- */
- public static <C extends Comparable> ContiguousSet<C> create(
- Range<C> range, DiscreteDomain<C> domain) {
- checkNotNull(range);
- checkNotNull(domain);
- Range<C> effectiveRange = range;
- try {
- if (!range.hasLowerBound()) {
- effectiveRange = effectiveRange.intersection(Range.atLeast(domain.minValue()));
- }
- if (!range.hasUpperBound()) {
- effectiveRange = effectiveRange.intersection(Range.atMost(domain.maxValue()));
- }
- } catch (NoSuchElementException e) {
- throw new IllegalArgumentException(e);
- }
-
- // Per class spec, we are allowed to throw CCE if necessary
- boolean empty = effectiveRange.isEmpty()
- || Range.compareOrThrow(
- range.lowerBound.leastValueAbove(domain),
- range.upperBound.greatestValueBelow(domain)) > 0;
-
- return empty
- ? new EmptyContiguousSet<C>(domain)
- : new RegularContiguousSet<C>(effectiveRange, domain);
- }
-
final DiscreteDomain<C> domain;
ContiguousSet(DiscreteDomain<C> domain) {
@@ -84,14 +40,10 @@ public abstract class ContiguousSet<C extends Comparable> extends ImmutableSorte
}
@Override public ContiguousSet<C> headSet(C toElement) {
- return headSetImpl(checkNotNull(toElement), false);
+ return headSet(checkNotNull(toElement), false);
}
- /**
- * @since 12.0
- */
- @GwtIncompatible("NavigableSet")
- @Override public ContiguousSet<C> headSet(C toElement, boolean inclusive) {
+ @Override ContiguousSet<C> headSet(C toElement, boolean inclusive) {
return headSetImpl(checkNotNull(toElement), inclusive);
}
@@ -99,14 +51,10 @@ public abstract class ContiguousSet<C extends Comparable> extends ImmutableSorte
checkNotNull(fromElement);
checkNotNull(toElement);
checkArgument(comparator().compare(fromElement, toElement) <= 0);
- return subSetImpl(fromElement, true, toElement, false);
+ return subSet(fromElement, true, toElement, false);
}
- /**
- * @since 12.0
- */
- @GwtIncompatible("NavigableSet")
- @Override public ContiguousSet<C> subSet(C fromElement, boolean fromInclusive, C toElement,
+ @Override ContiguousSet<C> subSet(C fromElement, boolean fromInclusive, C toElement,
boolean toInclusive) {
checkNotNull(fromElement);
checkNotNull(toElement);
@@ -115,14 +63,10 @@ public abstract class ContiguousSet<C extends Comparable> extends ImmutableSorte
}
@Override public ContiguousSet<C> tailSet(C fromElement) {
- return tailSetImpl(checkNotNull(fromElement), true);
+ return tailSet(checkNotNull(fromElement), true);
}
- /**
- * @since 12.0
- */
- @GwtIncompatible("NavigableSet")
- @Override public ContiguousSet<C> tailSet(C fromElement, boolean inclusive) {
+ @Override ContiguousSet<C> tailSet(C fromElement, boolean inclusive){
return tailSetImpl(checkNotNull(fromElement), inclusive);
}
diff --git a/guava/src/com/google/common/collect/Count.java b/guava/src/com/google/common/collect/Count.java
index 768e298..a095119 100644
--- a/guava/src/com/google/common/collect/Count.java
+++ b/guava/src/com/google/common/collect/Count.java
@@ -29,6 +29,10 @@ import javax.annotation.Nullable;
final class Count implements Serializable {
private int value;
+ Count() {
+ this(0);
+ }
+
Count(int value) {
this.value = value;
}
diff --git a/guava/src/com/google/common/collect/Cut.java b/guava/src/com/google/common/collect/Cut.java
index 44e3450..204ea0c 100644
--- a/guava/src/com/google/common/collect/Cut.java
+++ b/guava/src/com/google/common/collect/Cut.java
@@ -161,9 +161,6 @@ abstract class Cut<C extends Comparable> implements Comparable<Cut<C>>, Serializ
@Override public int compareTo(Cut<Comparable<?>> o) {
return (o == this) ? 0 : -1;
}
- @Override public String toString() {
- return "-\u221e";
- }
private Object readResolve() {
return INSTANCE;
}
@@ -222,9 +219,6 @@ abstract class Cut<C extends Comparable> implements Comparable<Cut<C>>, Serializ
@Override public int compareTo(Cut<Comparable<?>> o) {
return (o == this) ? 0 : 1;
}
- @Override public String toString() {
- return "+\u221e";
- }
private Object readResolve() {
return INSTANCE;
}
@@ -286,9 +280,6 @@ abstract class Cut<C extends Comparable> implements Comparable<Cut<C>>, Serializ
@Override public int hashCode() {
return endpoint.hashCode();
}
- @Override public String toString() {
- return "\\" + endpoint + "/";
- }
private static final long serialVersionUID = 0;
}
@@ -351,9 +342,6 @@ abstract class Cut<C extends Comparable> implements Comparable<Cut<C>>, Serializ
@Override public int hashCode() {
return ~endpoint.hashCode();
}
- @Override public String toString() {
- return "/" + endpoint + "\\";
- }
private static final long serialVersionUID = 0;
}
}
diff --git a/guava/src/com/google/common/collect/DescendingImmutableSortedMultiset.java b/guava/src/com/google/common/collect/DescendingImmutableSortedMultiset.java
index d2d0088..f5630dd 100644
--- a/guava/src/com/google/common/collect/DescendingImmutableSortedMultiset.java
+++ b/guava/src/com/google/common/collect/DescendingImmutableSortedMultiset.java
@@ -1,11 +1,11 @@
/*
* Copyright (C) 2011 The Guava Authors
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
@@ -18,14 +18,14 @@ import javax.annotation.Nullable;
/**
* A descending wrapper around an {@code ImmutableSortedMultiset}
- *
+ *
* @author Louis Wasserman
*/
-@SuppressWarnings("serial") // uses writeReplace, not default serialization
final class DescendingImmutableSortedMultiset<E> extends ImmutableSortedMultiset<E> {
private final transient ImmutableSortedMultiset<E> forward;
DescendingImmutableSortedMultiset(ImmutableSortedMultiset<E> forward) {
+ super(forward.reverseComparator());
this.forward = forward;
}
@@ -50,29 +50,18 @@ final class DescendingImmutableSortedMultiset<E> extends ImmutableSortedMultiset
}
@Override
- public ImmutableSortedSet<E> elementSet() {
- return forward.elementSet().descendingSet();
+ ImmutableSortedSet<E> createElementSet() {
+ return forward.createDescendingElementSet();
}
@Override
- ImmutableSet<Entry<E>> createEntrySet() {
- final ImmutableSet<Entry<E>> forwardEntrySet = forward.entrySet();
- return new EntrySet() {
- @Override
- public int size() {
- return forwardEntrySet.size();
- }
-
- @Override
- public UnmodifiableIterator<Entry<E>> iterator() {
- return asList().iterator();
- }
-
- @Override
- ImmutableList<Entry<E>> createAsList() {
- return forwardEntrySet.asList().reverse();
- }
- };
+ ImmutableSortedSet<E> createDescendingElementSet() {
+ return forward.elementSet();
+ }
+
+ @Override
+ UnmodifiableIterator<Entry<E>> descendingEntryIterator() {
+ return forward.entryIterator();
}
@Override
@@ -91,6 +80,16 @@ final class DescendingImmutableSortedMultiset<E> extends ImmutableSortedMultiset
}
@Override
+ UnmodifiableIterator<Entry<E>> entryIterator() {
+ return forward.descendingEntryIterator();
+ }
+
+ @Override
+ int distinctElements() {
+ return forward.distinctElements();
+ }
+
+ @Override
boolean isPartialView() {
return forward.isPartialView();
}
diff --git a/guava/src/com/google/common/collect/DescendingImmutableSortedSet.java b/guava/src/com/google/common/collect/DescendingImmutableSortedSet.java
deleted file mode 100644
index 340d8b9..0000000
--- a/guava/src/com/google/common/collect/DescendingImmutableSortedSet.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtIncompatible;
-
-import javax.annotation.Nullable;
-
-/**
- * Skeletal implementation of {@link ImmutableSortedSet#descendingSet()}.
- *
- * @author Louis Wasserman
- */
-class DescendingImmutableSortedSet<E> extends ImmutableSortedSet<E> {
- private final ImmutableSortedSet<E> forward;
-
- DescendingImmutableSortedSet(ImmutableSortedSet<E> forward) {
- super(Ordering.from(forward.comparator()).reverse());
- this.forward = forward;
- }
-
- @Override
- public int size() {
- return forward.size();
- }
-
- @Override
- public UnmodifiableIterator<E> iterator() {
- return forward.descendingIterator();
- }
-
- @Override
- ImmutableSortedSet<E> headSetImpl(E toElement, boolean inclusive) {
- return forward.tailSet(toElement, inclusive).descendingSet();
- }
-
- @Override
- ImmutableSortedSet<E> subSetImpl(
- E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
- return forward.subSet(toElement, toInclusive, fromElement, fromInclusive).descendingSet();
- }
-
- @Override
- ImmutableSortedSet<E> tailSetImpl(E fromElement, boolean inclusive) {
- return forward.headSet(fromElement, inclusive).descendingSet();
- }
-
- @Override
- @GwtIncompatible("NavigableSet")
- public ImmutableSortedSet<E> descendingSet() {
- return forward;
- }
-
- @Override
- @GwtIncompatible("NavigableSet")
- public UnmodifiableIterator<E> descendingIterator() {
- return forward.iterator();
- }
-
- @Override
- @GwtIncompatible("NavigableSet")
- ImmutableSortedSet<E> createDescendingSet() {
- throw new AssertionError("should never be called");
- }
-
- @Override
- public E lower(E element) {
- return forward.higher(element);
- }
-
- @Override
- public E floor(E element) {
- return forward.ceiling(element);
- }
-
- @Override
- public E ceiling(E element) {
- return forward.floor(element);
- }
-
- @Override
- public E higher(E element) {
- return forward.lower(element);
- }
-
- @Override
- int indexOf(@Nullable Object target) {
- int index = forward.indexOf(target);
- if (index == -1) {
- return index;
- } else {
- return size() - 1 - index;
- }
- }
-
- @Override
- boolean isPartialView() {
- return forward.isPartialView();
- }
-}
diff --git a/guava/src/com/google/common/collect/DescendingMultiset.java b/guava/src/com/google/common/collect/DescendingMultiset.java
deleted file mode 100644
index d83f782..0000000
--- a/guava/src/com/google/common/collect/DescendingMultiset.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.NavigableSet;
-import java.util.Set;
-
-/**
- * A skeleton implementation of a descending multiset. Only needs
- * {@code forwardMultiset()} and {@code entryIterator()}.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible(emulated = true)
-abstract class DescendingMultiset<E> extends ForwardingMultiset<E>
- implements SortedMultiset<E> {
- abstract SortedMultiset<E> forwardMultiset();
-
- private transient Comparator<? super E> comparator;
-
- @Override public Comparator<? super E> comparator() {
- Comparator<? super E> result = comparator;
- if (result == null) {
- return comparator =
- Ordering.from(forwardMultiset().comparator()).<E>reverse();
- }
- return result;
- }
-
- private transient NavigableSet<E> elementSet;
-
- @Override public NavigableSet<E> elementSet() {
- NavigableSet<E> result = elementSet;
- if (result == null) {
- return elementSet = new SortedMultisets.NavigableElementSet<E>(this);
- }
- return result;
- }
-
- @Override public Entry<E> pollFirstEntry() {
- return forwardMultiset().pollLastEntry();
- }
-
- @Override public Entry<E> pollLastEntry() {
- return forwardMultiset().pollFirstEntry();
- }
-
- @Override public SortedMultiset<E> headMultiset(E toElement,
- BoundType boundType) {
- return forwardMultiset().tailMultiset(toElement, boundType)
- .descendingMultiset();
- }
-
- @Override public SortedMultiset<E> subMultiset(E fromElement,
- BoundType fromBoundType, E toElement, BoundType toBoundType) {
- return forwardMultiset().subMultiset(toElement, toBoundType, fromElement,
- fromBoundType).descendingMultiset();
- }
-
- @Override public SortedMultiset<E> tailMultiset(E fromElement,
- BoundType boundType) {
- return forwardMultiset().headMultiset(fromElement, boundType)
- .descendingMultiset();
- }
-
- @Override protected Multiset<E> delegate() {
- return forwardMultiset();
- }
-
- @Override public SortedMultiset<E> descendingMultiset() {
- return forwardMultiset();
- }
-
- @Override public Entry<E> firstEntry() {
- return forwardMultiset().lastEntry();
- }
-
- @Override public Entry<E> lastEntry() {
- return forwardMultiset().firstEntry();
- }
-
- abstract Iterator<Entry<E>> entryIterator();
-
- private transient Set<Entry<E>> entrySet;
-
- @Override public Set<Entry<E>> entrySet() {
- Set<Entry<E>> result = entrySet;
- return (result == null) ? entrySet = createEntrySet() : result;
- }
-
- Set<Entry<E>> createEntrySet() {
- return new Multisets.EntrySet<E>() {
- @Override Multiset<E> multiset() {
- return DescendingMultiset.this;
- }
-
- @Override public Iterator<Entry<E>> iterator() {
- return entryIterator();
- }
-
- @Override public int size() {
- return forwardMultiset().entrySet().size();
- }
- };
- }
-
- @Override public Iterator<E> iterator() {
- return Multisets.iteratorImpl(this);
- }
-
- @Override public Object[] toArray() {
- return standardToArray();
- }
-
- @Override public <T> T[] toArray(T[] array) {
- return standardToArray(array);
- }
-
- @Override public String toString() {
- return entrySet().toString();
- }
-} \ No newline at end of file
diff --git a/guava/src/com/google/common/collect/DiscreteDomain.java b/guava/src/com/google/common/collect/DiscreteDomain.java
index f2a2f9a..893bbbb 100644
--- a/guava/src/com/google/common/collect/DiscreteDomain.java
+++ b/guava/src/com/google/common/collect/DiscreteDomain.java
@@ -19,13 +19,11 @@ package com.google.common.collect;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
-import java.io.Serializable;
-import java.math.BigInteger;
import java.util.NoSuchElementException;
/**
* A descriptor for a <i>discrete</i> {@code Comparable} domain such as all
- * {@link Integer} instances. A discrete domain is one that supports the three basic
+ * {@link Integer}s. A discrete domain is one that supports the three basic
* operations: {@link #next}, {@link #previous} and {@link #distance}, according
* to their specifications. The methods {@link #minValue} and {@link #maxValue}
* should also be overridden for bounded types.
@@ -34,159 +32,13 @@ import java.util.NoSuchElementException;
* type; it cannot represent partial domains such as "prime integers" or
* "strings of length 5."
*
- * <p>See the Guava User Guide section on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/RangesExplained#Discrete_Domains">
- * {@code DiscreteDomain}</a>.
- *
* @author Kevin Bourrillion
* @since 10.0
+ * @see DiscreteDomains
*/
@GwtCompatible
@Beta
public abstract class DiscreteDomain<C extends Comparable> {
-
- /**
- * Returns the discrete domain for values of type {@code Integer}.
- *
- * @since 14.0 (since 10.0 as {@code DiscreteDomains.integers()})
- */
- public static DiscreteDomain<Integer> integers() {
- return IntegerDomain.INSTANCE;
- }
-
- private static final class IntegerDomain extends DiscreteDomain<Integer>
- implements Serializable {
- private static final IntegerDomain INSTANCE = new IntegerDomain();
-
- @Override public Integer next(Integer value) {
- int i = value;
- return (i == Integer.MAX_VALUE) ? null : i + 1;
- }
-
- @Override public Integer previous(Integer value) {
- int i = value;
- return (i == Integer.MIN_VALUE) ? null : i - 1;
- }
-
- @Override public long distance(Integer start, Integer end) {
- return (long) end - start;
- }
-
- @Override public Integer minValue() {
- return Integer.MIN_VALUE;
- }
-
- @Override public Integer maxValue() {
- return Integer.MAX_VALUE;
- }
-
- private Object readResolve() {
- return INSTANCE;
- }
-
- @Override
- public String toString() {
- return "DiscreteDomains.integers()";
- }
-
- private static final long serialVersionUID = 0;
- }
-
- /**
- * Returns the discrete domain for values of type {@code Long}.
- *
- * @since 14.0 (since 10.0 as {@code DiscreteDomains.longs()})
- */
- public static DiscreteDomain<Long> longs() {
- return LongDomain.INSTANCE;
- }
-
- private static final class LongDomain extends DiscreteDomain<Long>
- implements Serializable {
- private static final LongDomain INSTANCE = new LongDomain();
-
- @Override public Long next(Long value) {
- long l = value;
- return (l == Long.MAX_VALUE) ? null : l + 1;
- }
-
- @Override public Long previous(Long value) {
- long l = value;
- return (l == Long.MIN_VALUE) ? null : l - 1;
- }
-
- @Override public long distance(Long start, Long end) {
- long result = end - start;
- if (end > start && result < 0) { // overflow
- return Long.MAX_VALUE;
- }
- if (end < start && result > 0) { // underflow
- return Long.MIN_VALUE;
- }
- return result;
- }
-
- @Override public Long minValue() {
- return Long.MIN_VALUE;
- }
-
- @Override public Long maxValue() {
- return Long.MAX_VALUE;
- }
-
- private Object readResolve() {
- return INSTANCE;
- }
-
- @Override
- public String toString() {
- return "DiscreteDomains.longs()";
- }
-
- private static final long serialVersionUID = 0;
- }
-
- /**
- * Returns the discrete domain for values of type {@code BigInteger}.
- */
- // TODO(kevinb): make sure it's tested, and make it public
- static DiscreteDomain<BigInteger> bigIntegers() {
- return BigIntegerDomain.INSTANCE;
- }
-
- private static final class BigIntegerDomain extends DiscreteDomain<BigInteger>
- implements Serializable {
- private static final BigIntegerDomain INSTANCE = new BigIntegerDomain();
-
- private static final BigInteger MIN_LONG =
- BigInteger.valueOf(Long.MIN_VALUE);
- private static final BigInteger MAX_LONG =
- BigInteger.valueOf(Long.MAX_VALUE);
-
- @Override public BigInteger next(BigInteger value) {
- return value.add(BigInteger.ONE);
- }
-
- @Override public BigInteger previous(BigInteger value) {
- return value.subtract(BigInteger.ONE);
- }
-
- @Override public long distance(BigInteger start, BigInteger end) {
- return end.subtract(start).max(MIN_LONG).min(MAX_LONG).longValue();
- }
-
- private Object readResolve() {
- return INSTANCE;
- }
-
- @Override
- public String toString() {
- return "DiscreteDomains.bigIntegers()";
- }
-
- private static final long serialVersionUID = 0;
- }
-
/** Constructor for use by subclasses. */
protected DiscreteDomain() {}
@@ -224,7 +76,7 @@ public abstract class DiscreteDomain<C extends Comparable> {
* type.
*
* @return the distance as described above, or {@link Long#MIN_VALUE} or
- * {@link Long#MAX_VALUE} if the distance is too small or too large,
+ * {@link Long#MIN_VALUE} if the distance is too small or too large,
* respectively.
*/
public abstract long distance(C start, C end);
@@ -258,5 +110,4 @@ public abstract class DiscreteDomain<C extends Comparable> {
public C maxValue() {
throw new NoSuchElementException();
}
-
}
diff --git a/guava/src/com/google/common/collect/DiscreteDomains.java b/guava/src/com/google/common/collect/DiscreteDomains.java
index dac4628..8cb2ae7 100644
--- a/guava/src/com/google/common/collect/DiscreteDomains.java
+++ b/guava/src/com/google/common/collect/DiscreteDomains.java
@@ -16,22 +16,20 @@
package com.google.common.collect;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
+import java.io.Serializable;
+import java.math.BigInteger;
+
/**
* Factories for common {@link DiscreteDomain} instances.
*
- * <p>See the Guava User Guide section on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/RangesExplained#Discrete_Domains">
- * {@code DiscreteDomain}</a>.
- *
* @author Gregory Kick
* @since 10.0
- * @deprecated Merged into {@link DiscreteDomain}. This class is scheduled for deletion in release
- * 15.0.
*/
@GwtCompatible
-@Deprecated
+@Beta
public final class DiscreteDomains {
private DiscreteDomains() {}
@@ -39,13 +37,122 @@ public final class DiscreteDomains {
* Returns the discrete domain for values of type {@code Integer}.
*/
public static DiscreteDomain<Integer> integers() {
- return DiscreteDomain.integers();
+ return IntegerDomain.INSTANCE;
+ }
+
+ private static final class IntegerDomain extends DiscreteDomain<Integer>
+ implements Serializable {
+ private static final IntegerDomain INSTANCE = new IntegerDomain();
+
+ @Override public Integer next(Integer value) {
+ int i = value;
+ return (i == Integer.MAX_VALUE) ? null : i + 1;
+ }
+
+ @Override public Integer previous(Integer value) {
+ int i = value;
+ return (i == Integer.MIN_VALUE) ? null : i - 1;
+ }
+
+ @Override public long distance(Integer start, Integer end) {
+ return (long) end - start;
+ }
+
+ @Override public Integer minValue() {
+ return Integer.MIN_VALUE;
+ }
+
+ @Override public Integer maxValue() {
+ return Integer.MAX_VALUE;
+ }
+
+ private Object readResolve() {
+ return INSTANCE;
+ }
+
+ private static final long serialVersionUID = 0;
}
/**
* Returns the discrete domain for values of type {@code Long}.
*/
public static DiscreteDomain<Long> longs() {
- return DiscreteDomain.longs();
+ return LongDomain.INSTANCE;
+ }
+
+ private static final class LongDomain extends DiscreteDomain<Long>
+ implements Serializable {
+ private static final LongDomain INSTANCE = new LongDomain();
+
+ @Override public Long next(Long value) {
+ long l = value;
+ return (l == Long.MAX_VALUE) ? null : l + 1;
+ }
+
+ @Override public Long previous(Long value) {
+ long l = value;
+ return (l == Long.MIN_VALUE) ? null : l - 1;
+ }
+
+ @Override public long distance(Long start, Long end) {
+ long result = end - start;
+ if (end > start && result < 0) { // overflow
+ return Long.MAX_VALUE;
+ }
+ if (end < start && result > 0) { // underflow
+ return Long.MIN_VALUE;
+ }
+ return result;
+ }
+
+ @Override public Long minValue() {
+ return Long.MIN_VALUE;
+ }
+
+ @Override public Long maxValue() {
+ return Long.MAX_VALUE;
+ }
+
+ private Object readResolve() {
+ return INSTANCE;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns the discrete domain for values of type {@code BigInteger}.
+ */
+ // TODO(kevinb): make sure it's tested, and make it public
+ static DiscreteDomain<BigInteger> bigIntegers() {
+ return BigIntegerDomain.INSTANCE;
+ }
+
+ private static final class BigIntegerDomain extends DiscreteDomain<BigInteger>
+ implements Serializable {
+ private static final BigIntegerDomain INSTANCE = new BigIntegerDomain();
+
+ private static final BigInteger MIN_LONG =
+ BigInteger.valueOf(Long.MIN_VALUE);
+ private static final BigInteger MAX_LONG =
+ BigInteger.valueOf(Long.MAX_VALUE);
+
+ @Override public BigInteger next(BigInteger value) {
+ return value.add(BigInteger.ONE);
+ }
+
+ @Override public BigInteger previous(BigInteger value) {
+ return value.subtract(BigInteger.ONE);
+ }
+
+ @Override public long distance(BigInteger start, BigInteger end) {
+ return start.subtract(end).max(MIN_LONG).min(MAX_LONG).longValue();
+ }
+
+ private Object readResolve() {
+ return INSTANCE;
+ }
+
+ private static final long serialVersionUID = 0;
}
}
diff --git a/guava/src/com/google/common/collect/EmptyContiguousSet.java b/guava/src/com/google/common/collect/EmptyContiguousSet.java
index 4546349..2bec7bd 100644
--- a/guava/src/com/google/common/collect/EmptyContiguousSet.java
+++ b/guava/src/com/google/common/collect/EmptyContiguousSet.java
@@ -71,8 +71,8 @@ final class EmptyContiguousSet<C extends Comparable> extends ContiguousSet<C> {
return this;
}
- @GwtIncompatible("not used by GWT emulation")
- @Override int indexOf(Object target) {
+ //Abstract method doesn't exist in GWT emulation
+ /* @Override */ int indexOf(Object target) {
return -1;
}
@@ -80,11 +80,6 @@ final class EmptyContiguousSet<C extends Comparable> extends ContiguousSet<C> {
return Iterators.emptyIterator();
}
- @GwtIncompatible("NavigableSet")
- @Override public UnmodifiableIterator<C> descendingIterator() {
- return Iterators.emptyIterator();
- }
-
@Override boolean isPartialView() {
return false;
}
@@ -133,9 +128,4 @@ final class EmptyContiguousSet<C extends Comparable> extends ContiguousSet<C> {
Object writeReplace() {
return new SerializedForm<C>(domain);
}
-
- @GwtIncompatible("NavigableSet")
- ImmutableSortedSet<C> createDescendingSet() {
- return new EmptyImmutableSortedSet<C>(Ordering.natural().reverse());
- }
}
diff --git a/guava/src/com/google/common/collect/EmptyImmutableBiMap.java b/guava/src/com/google/common/collect/EmptyImmutableBiMap.java
deleted file mode 100644
index 5b862b3..0000000
--- a/guava/src/com/google/common/collect/EmptyImmutableBiMap.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-import javax.annotation.Nullable;
-
-/**
- * Bimap with no mappings.
- *
- * @author Jared Levy
- */
-@GwtCompatible(emulated = true)
-@SuppressWarnings("serial") // uses writeReplace(), not default serialization
-final class EmptyImmutableBiMap extends ImmutableBiMap<Object, Object> {
- static final EmptyImmutableBiMap INSTANCE = new EmptyImmutableBiMap();
-
- private EmptyImmutableBiMap() {}
-
- @Override public ImmutableBiMap<Object, Object> inverse() {
- return this;
- }
-
- @Override
- public int size() {
- return 0;
- }
-
- @Override
- public boolean isEmpty() {
- return true;
- }
-
- @Override
- public Object get(@Nullable Object key) {
- return null;
- }
-
- @Override
- public ImmutableSet<Entry<Object, Object>> entrySet() {
- return ImmutableSet.of();
- }
-
- @Override
- ImmutableSet<Entry<Object, Object>> createEntrySet() {
- throw new AssertionError("should never be called");
- }
-
- @Override
- public ImmutableSet<Object> keySet() {
- return ImmutableSet.of();
- }
-
- @Override
- boolean isPartialView() {
- return false;
- }
-
- Object readResolve() {
- return INSTANCE; // preserve singleton property
- }
-}
diff --git a/guava/src/com/google/common/collect/EmptyImmutableList.java b/guava/src/com/google/common/collect/EmptyImmutableList.java
index b854d2b..ec685dd 100644
--- a/guava/src/com/google/common/collect/EmptyImmutableList.java
+++ b/guava/src/com/google/common/collect/EmptyImmutableList.java
@@ -24,17 +24,45 @@ import com.google.common.annotations.GwtCompatible;
import java.util.Collection;
import java.util.List;
+import java.util.NoSuchElementException;
import javax.annotation.Nullable;
/**
* An empty immutable list.
- *
+ *
* @author Kevin Bourrillion
*/
@GwtCompatible(serializable = true, emulated = true)
final class EmptyImmutableList extends ImmutableList<Object> {
static final EmptyImmutableList INSTANCE = new EmptyImmutableList();
+ static final UnmodifiableListIterator<Object> ITERATOR =
+ new UnmodifiableListIterator<Object>() {
+
+ @Override public boolean hasNext() {
+ return false;
+ }
+
+ @Override public boolean hasPrevious() {
+ return false;
+ }
+
+ @Override public Object next() {
+ throw new NoSuchElementException();
+ }
+
+ @Override public int nextIndex() {
+ return 0;
+ }
+
+ @Override public Object previous() {
+ throw new NoSuchElementException();
+ }
+
+ @Override public int previousIndex() {
+ return -1;
+ }
+ };
private EmptyImmutableList() {}
@@ -51,20 +79,18 @@ final class EmptyImmutableList extends ImmutableList<Object> {
return false;
}
- @Override public boolean contains(@Nullable Object target) {
+ @Override public boolean contains(Object target) {
return false;
}
- @Override public boolean containsAll(Collection<?> targets) {
- return targets.isEmpty();
- }
-
@Override public UnmodifiableIterator<Object> iterator() {
- return listIterator();
+ return Iterators.emptyIterator();
}
+ private static final Object[] EMPTY_ARRAY = new Object[0];
+
@Override public Object[] toArray() {
- return ObjectArrays.EMPTY_ARRAY;
+ return EMPTY_ARRAY;
}
@Override public <T> T[] toArray(T[] a) {
@@ -98,13 +124,17 @@ final class EmptyImmutableList extends ImmutableList<Object> {
return this;
}
- @Override public UnmodifiableListIterator<Object> listIterator() {
- return Iterators.EMPTY_LIST_ITERATOR;
+ @Override public UnmodifiableListIterator<Object> listIterator(){
+ return ITERATOR;
}
@Override public UnmodifiableListIterator<Object> listIterator(int start) {
checkPositionIndex(start, 0);
- return Iterators.EMPTY_LIST_ITERATOR;
+ return ITERATOR;
+ }
+
+ @Override public boolean containsAll(Collection<?> targets) {
+ return targets.isEmpty();
}
@Override public boolean equals(@Nullable Object object) {
diff --git a/guava/src/com/google/common/collect/EmptyImmutableMap.java b/guava/src/com/google/common/collect/EmptyImmutableMap.java
new file mode 100644
index 0000000..8d58021
--- /dev/null
+++ b/guava/src/com/google/common/collect/EmptyImmutableMap.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * An empty immutable map.
+ *
+ * @author Jesse Wilson
+ * @author Kevin Bourrillion
+ */
+@GwtCompatible(serializable = true, emulated = true)
+final class EmptyImmutableMap extends ImmutableMap<Object, Object> {
+ static final EmptyImmutableMap INSTANCE = new EmptyImmutableMap();
+
+ private EmptyImmutableMap() {}
+
+ @Override public Object get(@Nullable Object key) {
+ return null;
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override public boolean isEmpty() {
+ return true;
+ }
+
+ @Override public boolean containsKey(@Nullable Object key) {
+ return false;
+ }
+
+ @Override public boolean containsValue(@Nullable Object value) {
+ return false;
+ }
+
+ @Override public ImmutableSet<Entry<Object, Object>> entrySet() {
+ return ImmutableSet.of();
+ }
+
+ @Override public ImmutableSet<Object> keySet() {
+ return ImmutableSet.of();
+ }
+
+ @Override public ImmutableCollection<Object> values() {
+ return ImmutableCollection.EMPTY_IMMUTABLE_COLLECTION;
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof Map) {
+ Map<?, ?> that = (Map<?, ?>) object;
+ return that.isEmpty();
+ }
+ return false;
+ }
+
+ @Override boolean isPartialView() {
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return 0;
+ }
+
+ @Override public String toString() {
+ return "{}";
+ }
+
+ Object readResolve() {
+ return INSTANCE; // preserve singleton property
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/EmptyImmutableMultiset.java b/guava/src/com/google/common/collect/EmptyImmutableMultiset.java
index 1931342..2a72a2b 100644
--- a/guava/src/com/google/common/collect/EmptyImmutableMultiset.java
+++ b/guava/src/com/google/common/collect/EmptyImmutableMultiset.java
@@ -1,12 +1,12 @@
/*
* Copyright (C) 2008 The Guava Authors
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -18,13 +18,11 @@ package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
-import java.util.Collection;
-
import javax.annotation.Nullable;
/**
* An empty immutable multiset.
- *
+ *
* @author Jared Levy
* @author Louis Wasserman
*/
@@ -38,51 +36,22 @@ final class EmptyImmutableMultiset extends ImmutableMultiset<Object> {
}
@Override
- public boolean contains(@Nullable Object object) {
- return false;
- }
-
- @Override
- public boolean containsAll(Collection<?> targets) {
- return targets.isEmpty();
- }
-
- @Override
- public UnmodifiableIterator<Object> iterator() {
- return Iterators.emptyIterator();
- }
-
- @Override
- public boolean equals(@Nullable Object object) {
- if (object instanceof Multiset) {
- Multiset<?> other = (Multiset<?>) object;
- return other.isEmpty();
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return 0;
- }
-
- @Override
public ImmutableSet<Object> elementSet() {
return ImmutableSet.of();
}
@Override
- public ImmutableSet<Entry<Object>> entrySet() {
- return ImmutableSet.of();
+ public int size() {
+ return 0;
}
@Override
- ImmutableSet<Entry<Object>> createEntrySet() {
- throw new AssertionError("should never be called");
+ UnmodifiableIterator<Entry<Object>> entryIterator() {
+ return Iterators.emptyIterator();
}
@Override
- public int size() {
+ int distinctElements() {
return 0;
}
@@ -92,22 +61,8 @@ final class EmptyImmutableMultiset extends ImmutableMultiset<Object> {
}
@Override
- public Object[] toArray() {
- return ObjectArrays.EMPTY_ARRAY;
- }
-
- @Override
- public <T> T[] toArray(T[] other) {
- return asList().toArray(other);
- }
-
- @Override
- public ImmutableList<Object> asList() {
- return ImmutableList.of();
- }
-
- Object readResolve() {
- return INSTANCE; // preserve singleton property
+ ImmutableSet<Entry<Object>> createEntrySet() {
+ return ImmutableSet.of();
}
private static final long serialVersionUID = 0;
diff --git a/guava/src/com/google/common/collect/EmptyImmutableSet.java b/guava/src/com/google/common/collect/EmptyImmutableSet.java
index e70b051..8722bdf 100644
--- a/guava/src/com/google/common/collect/EmptyImmutableSet.java
+++ b/guava/src/com/google/common/collect/EmptyImmutableSet.java
@@ -25,7 +25,7 @@ import javax.annotation.Nullable;
/**
* An empty immutable set.
- *
+ *
* @author Kevin Bourrillion
*/
@GwtCompatible(serializable = true, emulated = true)
@@ -43,14 +43,10 @@ final class EmptyImmutableSet extends ImmutableSet<Object> {
return true;
}
- @Override public boolean contains(@Nullable Object target) {
+ @Override public boolean contains(Object target) {
return false;
}
- @Override public boolean containsAll(Collection<?> targets) {
- return targets.isEmpty();
- }
-
@Override public UnmodifiableIterator<Object> iterator() {
return Iterators.emptyIterator();
}
@@ -59,17 +55,21 @@ final class EmptyImmutableSet extends ImmutableSet<Object> {
return false;
}
+ private static final Object[] EMPTY_ARRAY = new Object[0];
+
@Override public Object[] toArray() {
- return ObjectArrays.EMPTY_ARRAY;
+ return EMPTY_ARRAY;
}
@Override public <T> T[] toArray(T[] a) {
- return asList().toArray(a);
+ if (a.length > 0) {
+ a[0] = null;
+ }
+ return a;
}
- @Override
- public ImmutableList<Object> asList() {
- return ImmutableList.of();
+ @Override public boolean containsAll(Collection<?> targets) {
+ return targets.isEmpty();
}
@Override public boolean equals(@Nullable Object object) {
diff --git a/guava/src/com/google/common/collect/EmptyImmutableSortedMap.java b/guava/src/com/google/common/collect/EmptyImmutableSortedMap.java
deleted file mode 100644
index 0a1e854..0000000
--- a/guava/src/com/google/common/collect/EmptyImmutableSortedMap.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.Comparator;
-
-import javax.annotation.Nullable;
-
-/**
- * An empty immutable sorted map.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible(emulated = true)
-@SuppressWarnings("serial") // uses writeReplace, not default serialization
-final class EmptyImmutableSortedMap<K, V> extends ImmutableSortedMap<K, V> {
- private final transient ImmutableSortedSet<K> keySet;
-
- EmptyImmutableSortedMap(Comparator<? super K> comparator) {
- this.keySet = ImmutableSortedSet.emptySet(comparator);
- }
-
- EmptyImmutableSortedMap(
- Comparator<? super K> comparator, ImmutableSortedMap<K, V> descendingMap) {
- super(descendingMap);
- this.keySet = ImmutableSortedSet.emptySet(comparator);
- }
-
- @Override
- public V get(@Nullable Object key) {
- return null;
- }
-
- @Override
- public ImmutableSortedSet<K> keySet() {
- return keySet;
- }
-
- @Override
- public int size() {
- return 0;
- }
-
- @Override
- public boolean isEmpty() {
- return true;
- }
-
- @Override
- public ImmutableCollection<V> values() {
- return ImmutableList.of();
- }
-
- @Override
- public String toString() {
- return "{}";
- }
-
- @Override
- boolean isPartialView() {
- return false;
- }
-
- @Override
- public ImmutableSet<Entry<K, V>> entrySet() {
- return ImmutableSet.of();
- }
-
- @Override
- ImmutableSet<Entry<K, V>> createEntrySet() {
- throw new AssertionError("should never be called");
- }
-
- @Override
- public ImmutableSortedMap<K, V> headMap(K toKey, boolean inclusive) {
- checkNotNull(toKey);
- return this;
- }
-
- @Override
- public ImmutableSortedMap<K, V> tailMap(K fromKey, boolean inclusive) {
- checkNotNull(fromKey);
- return this;
- }
-
- @Override
- ImmutableSortedMap<K, V> createDescendingMap() {
- return new EmptyImmutableSortedMap<K, V>(Ordering.from(comparator()).reverse(), this);
- }
-}
diff --git a/guava/src/com/google/common/collect/EmptyImmutableSortedMultiset.java b/guava/src/com/google/common/collect/EmptyImmutableSortedMultiset.java
index a7ddf28..623050c 100644
--- a/guava/src/com/google/common/collect/EmptyImmutableSortedMultiset.java
+++ b/guava/src/com/google/common/collect/EmptyImmutableSortedMultiset.java
@@ -1,11 +1,11 @@
/*
* Copyright (C) 2011 The Guava Authors
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
@@ -16,7 +16,6 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
-import java.util.Collection;
import java.util.Comparator;
import javax.annotation.Nullable;
@@ -26,12 +25,9 @@ import javax.annotation.Nullable;
*
* @author Louis Wasserman
*/
-@SuppressWarnings("serial") // Uses writeReplace, not default serialization
final class EmptyImmutableSortedMultiset<E> extends ImmutableSortedMultiset<E> {
- private final ImmutableSortedSet<E> elementSet;
-
EmptyImmutableSortedMultiset(Comparator<? super E> comparator) {
- this.elementSet = ImmutableSortedSet.emptySet(comparator);
+ super(comparator);
}
@Override
@@ -50,33 +46,28 @@ final class EmptyImmutableSortedMultiset<E> extends ImmutableSortedMultiset<E> {
}
@Override
- public boolean contains(@Nullable Object object) {
- return false;
- }
-
- @Override
- public boolean containsAll(Collection<?> targets) {
- return targets.isEmpty();
+ public int size() {
+ return 0;
}
@Override
- public int size() {
- return 0;
+ ImmutableSortedSet<E> createElementSet() {
+ return ImmutableSortedSet.emptySet(comparator());
}
@Override
- public ImmutableSortedSet<E> elementSet() {
- return elementSet;
+ ImmutableSortedSet<E> createDescendingElementSet() {
+ return ImmutableSortedSet.emptySet(reverseComparator());
}
@Override
- public ImmutableSet<Entry<E>> entrySet() {
- return ImmutableSet.of();
+ UnmodifiableIterator<Entry<E>> descendingEntryIterator() {
+ return Iterators.emptyIterator();
}
@Override
- ImmutableSet<Entry<E>> createEntrySet() {
- throw new AssertionError("should never be called");
+ UnmodifiableIterator<Entry<E>> entryIterator() {
+ return Iterators.emptyIterator();
}
@Override
@@ -94,46 +85,12 @@ final class EmptyImmutableSortedMultiset<E> extends ImmutableSortedMultiset<E> {
}
@Override
- public UnmodifiableIterator<E> iterator() {
- return Iterators.emptyIterator();
- }
-
- @Override
- public boolean equals(@Nullable Object object) {
- if (object instanceof Multiset) {
- Multiset<?> other = (Multiset<?>) object;
- return other.isEmpty();
- }
- return false;
- }
-
- @Override
- public int hashCode() {
+ int distinctElements() {
return 0;
}
@Override
- public String toString() {
- return "[]";
- }
-
- @Override
boolean isPartialView() {
return false;
}
-
- @Override
- public Object[] toArray() {
- return ObjectArrays.EMPTY_ARRAY;
- }
-
- @Override
- public <T> T[] toArray(T[] other) {
- return asList().toArray(other);
- }
-
- @Override
- public ImmutableList<E> asList() {
- return ImmutableList.of();
- }
}
diff --git a/guava/src/com/google/common/collect/EmptyImmutableSortedSet.java b/guava/src/com/google/common/collect/EmptyImmutableSortedSet.java
index 9f5d522..e406163 100644
--- a/guava/src/com/google/common/collect/EmptyImmutableSortedSet.java
+++ b/guava/src/com/google/common/collect/EmptyImmutableSortedSet.java
@@ -17,7 +17,6 @@
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
import java.util.Collection;
import java.util.Comparator;
@@ -47,37 +46,33 @@ class EmptyImmutableSortedSet<E> extends ImmutableSortedSet<E> {
return true;
}
- @Override public boolean contains(@Nullable Object target) {
+ @Override public boolean contains(Object target) {
return false;
}
- @Override public boolean containsAll(Collection<?> targets) {
- return targets.isEmpty();
- }
-
@Override public UnmodifiableIterator<E> iterator() {
return Iterators.emptyIterator();
}
- @GwtIncompatible("NavigableSet")
- @Override public UnmodifiableIterator<E> descendingIterator() {
- return Iterators.emptyIterator();
- }
-
@Override boolean isPartialView() {
return false;
}
- @Override public ImmutableList<E> asList() {
- return ImmutableList.of();
- }
+ private static final Object[] EMPTY_ARRAY = new Object[0];
@Override public Object[] toArray() {
- return ObjectArrays.EMPTY_ARRAY;
+ return EMPTY_ARRAY;
}
@Override public <T> T[] toArray(T[] a) {
- return asList().toArray(a);
+ if (a.length > 0) {
+ a[0] = null;
+ }
+ return a;
+ }
+
+ @Override public boolean containsAll(Collection<?> targets) {
+ return targets.isEmpty();
}
@Override public boolean equals(@Nullable Object object) {
@@ -125,9 +120,4 @@ class EmptyImmutableSortedSet<E> extends ImmutableSortedSet<E> {
@Override int indexOf(@Nullable Object target) {
return -1;
}
-
- @Override
- ImmutableSortedSet<E> createDescendingSet() {
- return new EmptyImmutableSortedSet<E>(Ordering.from(comparator).reverse());
- }
}
diff --git a/guava/src/com/google/common/collect/EmptyImmutableTable.java b/guava/src/com/google/common/collect/EmptyImmutableTable.java
index 65b8042..61949ca 100644
--- a/guava/src/com/google/common/collect/EmptyImmutableTable.java
+++ b/guava/src/com/google/common/collect/EmptyImmutableTable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Guava Authors
+ * Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@ import javax.annotation.concurrent.Immutable;
/**
* An empty implementation of {@link ImmutableTable}.
*
- * @author Gregory Kick
+ * @author gak@google.com (Gregory Kick)
*/
@GwtCompatible
@Immutable
@@ -53,7 +53,7 @@ final class EmptyImmutableTable extends ImmutableTable<Object, Object, Object> {
@Override public boolean equals(@Nullable Object obj) {
if (obj == this) {
return true;
- } else if (obj instanceof Table) {
+ } else if (obj instanceof Table<?, ?, ?>) {
Table<?, ?, ?> that = (Table<?, ?, ?>) obj;
return that.isEmpty();
} else {
diff --git a/guava/src/com/google/common/collect/EnumBiMap.java b/guava/src/com/google/common/collect/EnumBiMap.java
index 05d84ed..9a94ddd 100644
--- a/guava/src/com/google/common/collect/EnumBiMap.java
+++ b/guava/src/com/google/common/collect/EnumBiMap.java
@@ -17,7 +17,6 @@
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
@@ -32,10 +31,6 @@ import java.util.Map;
* A {@code BiMap} backed by two {@code EnumMap} instances. Null keys and values
* are not permitted. An {@code EnumBiMap} and its inverse are both
* serializable.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap">
- * {@code BiMap}</a>.
*
* @author Mike Bostock
* @since 2.0 (imported from Google Collections Library)
@@ -111,16 +106,6 @@ public final class EnumBiMap<K extends Enum<K>, V extends Enum<V>>
return valueType;
}
- @Override
- K checkKey(K key) {
- return checkNotNull(key);
- }
-
- @Override
- V checkValue(V value) {
- return checkNotNull(value);
- }
-
/**
* @serialData the key class, value class, number of entries, first key, first
* value, second key, second value, and so on.
diff --git a/guava/src/com/google/common/collect/EnumHashBiMap.java b/guava/src/com/google/common/collect/EnumHashBiMap.java
index c43daf0..8f32515 100644
--- a/guava/src/com/google/common/collect/EnumHashBiMap.java
+++ b/guava/src/com/google/common/collect/EnumHashBiMap.java
@@ -16,8 +16,6 @@
package com.google.common.collect;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
@@ -35,10 +33,6 @@ import javax.annotation.Nullable;
* a {@code HashMap} instance for values-to-keys. Null keys are not permitted,
* but null values are. An {@code EnumHashBiMap} and its inverse are both
* serializable.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap">
- * {@code BiMap}</a>.
*
* @author Mike Bostock
* @since 2.0 (imported from Google Collections Library)
@@ -83,12 +77,7 @@ public final class EnumHashBiMap<K extends Enum<K>, V>
this.keyType = keyType;
}
- // Overriding these 3 methods to show that values may be null (but not keys)
-
- @Override
- K checkKey(K key) {
- return checkNotNull(key);
- }
+ // Overriding these two methods to show that values may be null (but not keys)
@Override public V put(K key, @Nullable V value) {
return super.put(key, value);
diff --git a/guava/src/com/google/common/collect/EnumMultiset.java b/guava/src/com/google/common/collect/EnumMultiset.java
index 2bb121c..560bf7c 100644
--- a/guava/src/com/google/common/collect/EnumMultiset.java
+++ b/guava/src/com/google/common/collect/EnumMultiset.java
@@ -27,10 +27,6 @@ import java.util.Iterator;
/**
* Multiset implementation backed by an {@link EnumMap}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset">
- * {@code Multiset}</a>.
*
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
@@ -58,19 +54,6 @@ public final class EnumMultiset<E extends Enum<E>> extends AbstractMapBasedMulti
Iterables.addAll(multiset, elements);
return multiset;
}
-
- /**
- * Returns a new {@code EnumMultiset} instance containing the given elements. Unlike
- * {@link EnumMultiset#create(Iterable)}, this method does not produce an exception on an empty
- * iterable.
- *
- * @since 14.0
- */
- public static <E extends Enum<E>> EnumMultiset<E> create(Iterable<E> elements, Class<E> type) {
- EnumMultiset<E> result = create(type);
- Iterables.addAll(result, elements);
- return result;
- }
private transient Class<E> type;
diff --git a/guava/src/com/google/common/collect/FilteredEntryMultimap.java b/guava/src/com/google/common/collect/FilteredEntryMultimap.java
deleted file mode 100644
index 9120893..0000000
--- a/guava/src/com/google/common/collect/FilteredEntryMultimap.java
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Predicates.compose;
-import static com.google.common.base.Predicates.in;
-import static com.google.common.base.Predicates.not;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Objects;
-import com.google.common.base.Predicate;
-
-import java.util.AbstractMap;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-/**
- * Implementation of {@link Multimaps#filterEntries(Multimap, Predicate)}.
- *
- * @author Jared Levy
- * @author Louis Wasserman
- */
-@GwtCompatible
-class FilteredEntryMultimap<K, V> extends FilteredMultimap<K, V> {
- final Predicate<? super Entry<K, V>> predicate;
-
- FilteredEntryMultimap(Multimap<K, V> unfiltered, Predicate<? super Entry<K, V>> predicate) {
- super(unfiltered);
- this.predicate = checkNotNull(predicate);
- }
-
- @Override
- Predicate<? super Entry<K, V>> entryPredicate() {
- return predicate;
- }
-
- @Override
- public int size() {
- return entries().size();
- }
-
- private boolean satisfies(K key, V value) {
- return predicate.apply(Maps.immutableEntry(key, value));
- }
-
-
- final class ValuePredicate implements Predicate<V> {
- private final K key;
-
- ValuePredicate(K key) {
- this.key = key;
- }
-
- @Override
- public boolean apply(@Nullable V value) {
- return satisfies(key, value);
- }
- }
-
- static <E> Collection<E> filterCollection(
- Collection<E> collection, Predicate<? super E> predicate) {
- if (collection instanceof Set) {
- return Sets.filter((Set<E>) collection, predicate);
- } else {
- return Collections2.filter(collection, predicate);
- }
- }
-
- @Override
- public boolean containsKey(@Nullable Object key) {
- return asMap().get(key) != null;
- }
-
- @Override
- public Collection<V> removeAll(@Nullable Object key) {
- return Objects.firstNonNull(asMap().remove(key), unmodifiableEmptyCollection());
- }
-
- Collection<V> unmodifiableEmptyCollection() {
- // These return false, rather than throwing a UOE, on remove calls.
- return (unfiltered instanceof SetMultimap)
- ? Collections.<V>emptySet()
- : Collections.<V>emptyList();
- }
-
- @Override
- public void clear() {
- entries().clear();
- }
-
- @Override
- public Collection<V> get(final K key) {
- return filterCollection(unfiltered.get(key), new ValuePredicate(key));
- }
-
- @Override
- Collection<Entry<K, V>> createEntries() {
- return filterCollection(unfiltered.entries(), predicate);
- }
-
- @Override
- Iterator<Entry<K, V>> entryIterator() {
- throw new AssertionError("should never be called");
- }
-
- @Override
- Map<K, Collection<V>> createAsMap() {
- return new AsMap();
- }
-
- @Override
- public Set<K> keySet() {
- return asMap().keySet();
- }
-
- boolean removeIf(Predicate<? super Entry<K, Collection<V>>> predicate) {
- Iterator<Entry<K, Collection<V>>> entryIterator = unfiltered.asMap().entrySet().iterator();
- boolean changed = false;
- while (entryIterator.hasNext()) {
- Entry<K, Collection<V>> entry = entryIterator.next();
- K key = entry.getKey();
- Collection<V> collection = filterCollection(entry.getValue(), new ValuePredicate(key));
- if (!collection.isEmpty() && predicate.apply(Maps.immutableEntry(key, collection))) {
- if (collection.size() == entry.getValue().size()) {
- entryIterator.remove();
- } else {
- collection.clear();
- }
- changed = true;
- }
- }
- return changed;
- }
-
- class AsMap extends AbstractMap<K, Collection<V>> {
- @Override
- public boolean containsKey(@Nullable Object key) {
- return get(key) != null;
- }
-
- @Override
- public void clear() {
- FilteredEntryMultimap.this.clear();
- }
-
- @Override
- public Collection<V> get(@Nullable Object key) {
- Collection<V> result = unfiltered.asMap().get(key);
- if (result == null) {
- return null;
- }
- @SuppressWarnings("unchecked") // key is equal to a K, if not a K itself
- K k = (K) key;
- result = filterCollection(result, new ValuePredicate(k));
- return result.isEmpty() ? null : result;
- }
-
- @Override
- public Collection<V> remove(@Nullable Object key) {
- Collection<V> collection = unfiltered.asMap().get(key);
- if (collection == null) {
- return null;
- }
- @SuppressWarnings("unchecked") // it's definitely equal to a K
- K k = (K) key;
- List<V> result = Lists.newArrayList();
- Iterator<V> itr = collection.iterator();
- while (itr.hasNext()) {
- V v = itr.next();
- if (satisfies(k, v)) {
- itr.remove();
- result.add(v);
- }
- }
- if (result.isEmpty()) {
- return null;
- } else if (unfiltered instanceof SetMultimap) {
- return Collections.unmodifiableSet(Sets.newLinkedHashSet(result));
- } else {
- return Collections.unmodifiableList(result);
- }
- }
-
- private Set<K> keySet;
-
- @Override
- public Set<K> keySet() {
- Set<K> result = keySet;
- if (result == null) {
- return keySet = new Maps.KeySet<K, Collection<V>>() {
- @Override
- Map<K, Collection<V>> map() {
- return AsMap.this;
- }
-
- @Override
- public boolean removeAll(Collection<?> c) {
- return removeIf(compose(in(c), Maps.<K>keyFunction()));
- }
-
- @Override
- public boolean retainAll(Collection<?> c) {
- return removeIf(compose(not(in(c)), Maps.<K>keyFunction()));
- }
-
- @Override
- public boolean remove(@Nullable Object o) {
- return AsMap.this.remove(o) != null;
- }
- };
- }
- return result;
- }
-
- @Override
- public Set<Entry<K, Collection<V>>> entrySet() {
- return new Maps.EntrySet<K, Collection<V>>() {
- @Override
- Map<K, Collection<V>> map() {
- return AsMap.this;
- }
-
- @Override
- public Iterator<Entry<K, Collection<V>>> iterator() {
- return new AbstractIterator<Entry<K, Collection<V>>>() {
- final Iterator<Entry<K, Collection<V>>> backingIterator
- = unfiltered.asMap().entrySet().iterator();
-
- @Override
- protected Entry<K, Collection<V>> computeNext() {
- while (backingIterator.hasNext()) {
- Entry<K, Collection<V>> entry = backingIterator.next();
- K key = entry.getKey();
- Collection<V> collection
- = filterCollection(entry.getValue(), new ValuePredicate(key));
- if (!collection.isEmpty()) {
- return Maps.immutableEntry(key, collection);
- }
- }
- return endOfData();
- }
- };
- }
-
- @Override
- public boolean removeAll(Collection<?> c) {
- return removeIf(in(c));
- }
-
- @Override
- public boolean retainAll(Collection<?> c) {
- return removeIf(not(in(c)));
- }
-
- @Override
- public int size() {
- return Iterators.size(iterator());
- }
- };
- }
-
- @Override
- public Collection<Collection<V>> values() {
- return new Maps.Values<K, Collection<V>>() {
- @Override
- Map<K, Collection<V>> map() {
- return AsMap.this;
- }
-
- @Override
- public boolean remove(@Nullable Object o) {
- if (o instanceof Collection) {
- Collection<?> c = (Collection<?>) o;
- Iterator<Entry<K, Collection<V>>> entryIterator
- = unfiltered.asMap().entrySet().iterator();
- while (entryIterator.hasNext()) {
- Entry<K, Collection<V>> entry = entryIterator.next();
- K key = entry.getKey();
- Collection<V> collection
- = filterCollection(entry.getValue(), new ValuePredicate(key));
- if (!collection.isEmpty() && c.equals(collection)) {
- if (collection.size() == entry.getValue().size()) {
- entryIterator.remove();
- } else {
- collection.clear();
- }
- return true;
- }
- }
- }
- return false;
- }
-
- @Override
- public boolean removeAll(Collection<?> c) {
- return removeIf(compose(in(c), Maps.<Collection<V>>valueFunction()));
- }
-
- @Override
- public boolean retainAll(Collection<?> c) {
- return removeIf(compose(not(in(c)), Maps.<Collection<V>>valueFunction()));
- }
- };
- }
- }
-
- @Override
- Multiset<K> createKeys() {
- return new Keys();
- }
-
- class Keys extends Multimaps.Keys<K, V> {
- Keys() {
- super(FilteredEntryMultimap.this);
- }
-
- @Override
- public int remove(@Nullable Object key, int occurrences) {
- Multisets.checkNonnegative(occurrences, "occurrences");
- if (occurrences == 0) {
- return count(key);
- }
- Collection<V> collection = unfiltered.asMap().get(key);
- if (collection == null) {
- return 0;
- }
- @SuppressWarnings("unchecked") // key is equal to a K, if not a K itself
- K k = (K) key;
- int oldCount = 0;
- Iterator<V> itr = collection.iterator();
- while (itr.hasNext()) {
- V v = itr.next();
- if (satisfies(k, v)) {
- oldCount++;
- if (oldCount <= occurrences) {
- itr.remove();
- }
- }
- }
- return oldCount;
- }
-
- @Override
- public Set<Multiset.Entry<K>> entrySet() {
- return new Multisets.EntrySet<K>() {
-
- @Override
- Multiset<K> multiset() {
- return Keys.this;
- }
-
- @Override
- public Iterator<Multiset.Entry<K>> iterator() {
- return Keys.this.entryIterator();
- }
-
- @Override
- public int size() {
- return FilteredEntryMultimap.this.keySet().size();
- }
-
- private boolean removeIf(final Predicate<? super Multiset.Entry<K>> predicate) {
- return FilteredEntryMultimap.this.removeIf(new Predicate<Map.Entry<K, Collection<V>>>() {
- @Override
- public boolean apply(Map.Entry<K, Collection<V>> entry) {
- return predicate.apply(
- Multisets.immutableEntry(entry.getKey(), entry.getValue().size()));
- }
- });
- }
-
- @Override
- public boolean removeAll(Collection<?> c) {
- return removeIf(in(c));
- }
-
- @Override
- public boolean retainAll(Collection<?> c) {
- return removeIf(not(in(c)));
- }
- };
- }
- }
-}
diff --git a/guava/src/com/google/common/collect/FilteredKeyMultimap.java b/guava/src/com/google/common/collect/FilteredKeyMultimap.java
deleted file mode 100644
index 0a07333..0000000
--- a/guava/src/com/google/common/collect/FilteredKeyMultimap.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkPositionIndex;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-/**
- * Implementation of {@link Multimaps#filterKeys(Multimap, Predicate)}.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible
-class FilteredKeyMultimap<K, V> extends FilteredMultimap<K, V> {
- final Predicate<? super K> keyPredicate;
-
- FilteredKeyMultimap(Multimap<K, V> unfiltered, Predicate<? super K> keyPredicate) {
- super(unfiltered);
- this.keyPredicate = checkNotNull(keyPredicate);
- }
-
- @Override
- Predicate<? super Entry<K, V>> entryPredicate() {
- return Predicates.compose(keyPredicate, Maps.<K>keyFunction());
- }
-
- @Override
- public int size() {
- int size = 0;
- for (Collection<V> collection : asMap().values()) {
- size += collection.size();
- }
- return size;
- }
-
- @Override
- public boolean containsKey(@Nullable Object key) {
- if (unfiltered.containsKey(key)) {
- @SuppressWarnings("unchecked") // k is equal to a K, if not one itself
- K k = (K) key;
- return keyPredicate.apply(k);
- }
- return false;
- }
-
- @Override
- public Collection<V> removeAll(Object key) {
- return containsKey(key) ? unfiltered.removeAll(key) : unmodifiableEmptyCollection();
- }
-
- Collection<V> unmodifiableEmptyCollection() {
- if (unfiltered instanceof SetMultimap) {
- return ImmutableSet.of();
- } else {
- return ImmutableList.of();
- }
- }
-
- @Override
- public void clear() {
- keySet().clear();
- }
-
- @Override
- Set<K> createKeySet() {
- return Sets.filter(unfiltered.keySet(), keyPredicate);
- }
-
- @Override
- public Collection<V> get(K key) {
- if (keyPredicate.apply(key)) {
- return unfiltered.get(key);
- } else if (unfiltered instanceof SetMultimap) {
- return new AddRejectingSet<K, V>(key);
- } else {
- return new AddRejectingList<K, V>(key);
- }
- }
-
- static class AddRejectingSet<K, V> extends ForwardingSet<V> {
- final K key;
-
- AddRejectingSet(K key) {
- this.key = key;
- }
-
- @Override
- public boolean add(V element) {
- throw new IllegalArgumentException("Key does not satisfy predicate: " + key);
- }
-
- @Override
- public boolean addAll(Collection<? extends V> collection) {
- checkNotNull(collection);
- throw new IllegalArgumentException("Key does not satisfy predicate: " + key);
- }
-
- @Override
- protected Set<V> delegate() {
- return Collections.emptySet();
- }
- }
-
- static class AddRejectingList<K, V> extends ForwardingList<V> {
- final K key;
-
- AddRejectingList(K key) {
- this.key = key;
- }
-
- @Override
- public boolean add(V v) {
- add(0, v);
- return true;
- }
-
- @Override
- public boolean addAll(Collection<? extends V> collection) {
- addAll(0, collection);
- return true;
- }
-
- @Override
- public void add(int index, V element) {
- checkPositionIndex(index, 0);
- throw new IllegalArgumentException("Key does not satisfy predicate: " + key);
- }
-
- @Override
- public boolean addAll(int index, Collection<? extends V> elements) {
- checkNotNull(elements);
- checkPositionIndex(index, 0);
- throw new IllegalArgumentException("Key does not satisfy predicate: " + key);
- }
-
- @Override
- protected List<V> delegate() {
- return Collections.emptyList();
- }
- }
-
- @Override
- Iterator<Entry<K, V>> entryIterator() {
- return Iterators.filter(
- unfiltered.entries().iterator(), Predicates.compose(keyPredicate, Maps.<K>keyFunction()));
- }
-
- @Override
- Collection<Entry<K, V>> createEntries() {
- return new Multimaps.Entries<K, V>() {
- @Override
- Multimap<K, V> multimap() {
- return FilteredKeyMultimap.this;
- }
-
- @Override
- public Iterator<Entry<K, V>> iterator() {
- return entryIterator();
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public boolean remove(@Nullable Object o) {
- if (o instanceof Entry) {
- Entry<?, ?> entry = (Entry<?, ?>) o;
- if (unfiltered.containsEntry(entry.getKey(), entry.getValue())
- && keyPredicate.apply((K) entry.getKey())) {
- return unfiltered.remove(entry.getKey(), entry.getValue());
- }
- }
- return false;
- }
-
- @Override
- public boolean removeAll(Collection<?> c) {
- Predicate<Entry<K, ?>> combinedPredicate = Predicates.and(
- Predicates.compose(keyPredicate, Maps.<K>keyFunction()), Predicates.in(c));
- return Iterators.removeIf(unfiltered.entries().iterator(), combinedPredicate);
- }
-
- @Override
- public boolean retainAll(Collection<?> c) {
- Predicate<Entry<K, ?>> combinedPredicate = Predicates.and(
- Predicates.compose(keyPredicate, Maps.<K>keyFunction()),
- Predicates.not(Predicates.in(c)));
- return Iterators.removeIf(unfiltered.entries().iterator(), combinedPredicate);
- }
- };
- }
-
- @Override
- Map<K, Collection<V>> createAsMap() {
- return Maps.filterKeys(unfiltered.asMap(), keyPredicate);
- }
-
- @Override
- Multiset<K> createKeys() {
- return Multisets.filter(unfiltered.keys(), keyPredicate);
- }
-}
diff --git a/guava/src/com/google/common/collect/FilteredMultimap.java b/guava/src/com/google/common/collect/FilteredMultimap.java
deleted file mode 100644
index d7d2b3b..0000000
--- a/guava/src/com/google/common/collect/FilteredMultimap.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Predicate;
-
-import java.util.Map.Entry;
-
-/**
- * A superclass of all filtered multimap types.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible
-abstract class FilteredMultimap<K, V> extends AbstractMultimap<K, V> {
- final Multimap<K, V> unfiltered;
-
- FilteredMultimap(Multimap<K, V> unfiltered) {
- this.unfiltered = checkNotNull(unfiltered);
- }
-
- abstract Predicate<? super Entry<K, V>> entryPredicate();
-}
diff --git a/guava/src/com/google/common/collect/FluentIterable.java b/guava/src/com/google/common/collect/FluentIterable.java
deleted file mode 100644
index 2469180..0000000
--- a/guava/src/com/google/common/collect/FluentIterable.java
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
-
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-import java.util.SortedSet;
-
-import javax.annotation.Nullable;
-
-/**
- * {@code FluentIterable} provides a rich interface for manipulating {@code Iterable} instances in a
- * chained fashion. A {@code FluentIterable} can be created from an {@code Iterable}, or from a set
- * of elements. The following types of methods are provided on {@code FluentIterable}:
- * <ul>
- * <li>chained methods which return a new {@code FluentIterable} based in some way on the contents
- * of the current one (for example {@link #transform})
- * <li>conversion methods which copy the {@code FluentIterable}'s contents into a new collection or
- * array (for example {@link #toList})
- * <li>element extraction methods which facilitate the retrieval of certain elements (for example
- * {@link #last})
- * <li>query methods which answer questions about the {@code FluentIterable}'s contents (for example
- * {@link #anyMatch})
- * </ul>
- *
- * <p>Here is an example that merges the lists returned by two separate database calls, transforms
- * it by invoking {@code toString()} on each element, and returns the first 10 elements as an
- * {@code ImmutableList}: <pre> {@code
- *
- * FluentIterable
- * .from(database.getClientList())
- * .filter(activeInLastMonth())
- * .transform(Functions.toStringFunction())
- * .limit(10)
- * .toList();}</pre>
- *
- * Anything which can be done using {@code FluentIterable} could be done in a different fashion
- * (often with {@link Iterables}), however the use of {@code FluentIterable} makes many sets of
- * operations significantly more concise.
- *
- * @author Marcin Mikosik
- * @since 12.0
- */
-@GwtCompatible(emulated = true)
-public abstract class FluentIterable<E> implements Iterable<E> {
- // We store 'iterable' and use it instead of 'this' to allow Iterables to perform instanceof
- // checks on the _original_ iterable when FluentIterable.from is used.
- private final Iterable<E> iterable;
-
- /** Constructor for use by subclasses. */
- protected FluentIterable() {
- this.iterable = this;
- }
-
- FluentIterable(Iterable<E> iterable) {
- this.iterable = checkNotNull(iterable);
- }
-
- /**
- * Returns a fluent iterable that wraps {@code iterable}, or {@code iterable} itself if it
- * is already a {@code FluentIterable}.
- */
- public static <E> FluentIterable<E> from(final Iterable<E> iterable) {
- return (iterable instanceof FluentIterable) ? (FluentIterable<E>) iterable
- : new FluentIterable<E>(iterable) {
- @Override
- public Iterator<E> iterator() {
- return iterable.iterator();
- }
- };
- }
-
- /**
- * Construct a fluent iterable from another fluent iterable. This is obviously never necessary,
- * but is intended to help call out cases where one migration from {@code Iterable} to
- * {@code FluentIterable} has obviated the need to explicitly convert to a {@code FluentIterable}.
- *
- * @deprecated instances of {@code FluentIterable} don't need to be converted to
- * {@code FluentIterable}
- */
- @Deprecated
- public static <E> FluentIterable<E> from(FluentIterable<E> iterable) {
- return checkNotNull(iterable);
- }
-
- /**
- * Returns a string representation of this fluent iterable, with the format
- * {@code [e1, e2, ..., en]}.
- */
- @Override
- public String toString() {
- return Iterables.toString(iterable);
- }
-
- /**
- * Returns the number of elements in this fluent iterable.
- */
- public final int size() {
- return Iterables.size(iterable);
- }
-
- /**
- * Returns {@code true} if this fluent iterable contains any object for which
- * {@code equals(element)} is true.
- */
- public final boolean contains(@Nullable Object element) {
- return Iterables.contains(iterable, element);
- }
-
- /**
- * Returns a fluent iterable whose {@code Iterator} cycles indefinitely over the elements of
- * this fluent iterable.
- *
- * <p>That iterator supports {@code remove()} if {@code iterable.iterator()} does. After
- * {@code remove()} is called, subsequent cycles omit the removed element, which is no longer in
- * this fluent iterable. The iterator's {@code hasNext()} method returns {@code true} until
- * this fluent iterable is empty.
- *
- * <p><b>Warning:</b> Typical uses of the resulting iterator may produce an infinite loop. You
- * should use an explicit {@code break} or be certain that you will eventually remove all the
- * elements.
- */
- public final FluentIterable<E> cycle() {
- return from(Iterables.cycle(iterable));
- }
-
- /**
- * Returns the elements from this fluent iterable that satisfy a predicate. The
- * resulting fluent iterable's iterator does not support {@code remove()}.
- */
- public final FluentIterable<E> filter(Predicate<? super E> predicate) {
- return from(Iterables.filter(iterable, predicate));
- }
-
- /**
- * Returns the elements from this fluent iterable that are instances of class {@code type}.
- *
- * @param type the type of elements desired
- */
- @GwtIncompatible("Class.isInstance")
- public final <T> FluentIterable<T> filter(Class<T> type) {
- return from(Iterables.filter(iterable, type));
- }
-
- /**
- * Returns {@code true} if any element in this fluent iterable satisfies the predicate.
- */
- public final boolean anyMatch(Predicate<? super E> predicate) {
- return Iterables.any(iterable, predicate);
- }
-
- /**
- * Returns {@code true} if every element in this fluent iterable satisfies the predicate.
- * If this fluent iterable is empty, {@code true} is returned.
- */
- public final boolean allMatch(Predicate<? super E> predicate) {
- return Iterables.all(iterable, predicate);
- }
-
- /**
- * Returns an {@link Optional} containing the first element in this fluent iterable that
- * satisfies the given predicate, if such an element exists.
- *
- * <p><b>Warning:</b> avoid using a {@code predicate} that matches {@code null}. If {@code null}
- * is matched in this fluent iterable, a {@link NullPointerException} will be thrown.
- */
- public final Optional<E> firstMatch(Predicate<? super E> predicate) {
- return Iterables.tryFind(iterable, predicate);
- }
-
- /**
- * Returns a fluent iterable that applies {@code function} to each element of this
- * fluent iterable.
- *
- * <p>The returned fluent iterable's iterator supports {@code remove()} if this iterable's
- * iterator does. After a successful {@code remove()} call, this fluent iterable no longer
- * contains the corresponding element.
- */
- public final <T> FluentIterable<T> transform(Function<? super E, T> function) {
- return from(Iterables.transform(iterable, function));
- }
-
- /**
- * Applies {@code function} to each element of this fluent iterable and returns
- * a fluent iterable with the concatenated combination of results. {@code function}
- * returns an Iterable of results.
- *
- * <p>The returned fluent iterable's iterator supports {@code remove()} if this
- * function-returned iterables' iterator does. After a successful {@code remove()} call,
- * the returned fluent iterable no longer contains the corresponding element.
- *
- * @since 13.0 (required {@code Function<E, Iterable<T>>} until 14.0)
- */
- public <T> FluentIterable<T> transformAndConcat(
- Function<? super E, ? extends Iterable<? extends T>> function) {
- return from(Iterables.concat(transform(function)));
- }
-
- /**
- * Returns an {@link Optional} containing the first element in this fluent iterable.
- * If the iterable is empty, {@code Optional.absent()} is returned.
- *
- * @throws NullPointerException if the first element is null; if this is a possibility, use
- * {@code iterator().next()} or {@link Iterables#getFirst} instead.
- */
- public final Optional<E> first() {
- Iterator<E> iterator = iterable.iterator();
- return iterator.hasNext()
- ? Optional.of(iterator.next())
- : Optional.<E>absent();
- }
-
- /**
- * Returns an {@link Optional} containing the last element in this fluent iterable.
- * If the iterable is empty, {@code Optional.absent()} is returned.
- *
- * @throws NullPointerException if the last element is null; if this is a possibility, use
- * {@link Iterables#getLast} instead.
- */
- public final Optional<E> last() {
- // Iterables#getLast was inlined here so we don't have to throw/catch a NSEE
-
- // TODO(kevinb): Support a concurrently modified collection?
- if (iterable instanceof List) {
- List<E> list = (List<E>) iterable;
- if (list.isEmpty()) {
- return Optional.absent();
- }
- return Optional.of(list.get(list.size() - 1));
- }
- Iterator<E> iterator = iterable.iterator();
- if (!iterator.hasNext()) {
- return Optional.absent();
- }
-
- /*
- * TODO(kevinb): consider whether this "optimization" is worthwhile. Users
- * with SortedSets tend to know they are SortedSets and probably would not
- * call this method.
- */
- if (iterable instanceof SortedSet) {
- SortedSet<E> sortedSet = (SortedSet<E>) iterable;
- return Optional.of(sortedSet.last());
- }
-
- while (true) {
- E current = iterator.next();
- if (!iterator.hasNext()) {
- return Optional.of(current);
- }
- }
- }
-
- /**
- * Returns a view of this fluent iterable that skips its first {@code numberToSkip}
- * elements. If this fluent iterable contains fewer than {@code numberToSkip} elements,
- * the returned fluent iterable skips all of its elements.
- *
- * <p>Modifications to this fluent iterable before a call to {@code iterator()} are
- * reflected in the returned fluent iterable. That is, the its iterator skips the first
- * {@code numberToSkip} elements that exist when the iterator is created, not when {@code skip()}
- * is called.
- *
- * <p>The returned fluent iterable's iterator supports {@code remove()} if the
- * {@code Iterator} of this fluent iterable supports it. Note that it is <i>not</i>
- * possible to delete the last skipped element by immediately calling {@code remove()} on the
- * returned fluent iterable's iterator, as the {@code Iterator} contract states that a call
- * to {@code * remove()} before a call to {@code next()} will throw an
- * {@link IllegalStateException}.
- */
- public final FluentIterable<E> skip(int numberToSkip) {
- return from(Iterables.skip(iterable, numberToSkip));
- }
-
- /**
- * Creates a fluent iterable with the first {@code size} elements of this
- * fluent iterable. If this fluent iterable does not contain that many elements,
- * the returned fluent iterable will have the same behavior as this fluent iterable.
- * The returned fluent iterable's iterator supports {@code remove()} if this
- * fluent iterable's iterator does.
- *
- * @param size the maximum number of elements in the returned fluent iterable
- * @throws IllegalArgumentException if {@code size} is negative
- */
- public final FluentIterable<E> limit(int size) {
- return from(Iterables.limit(iterable, size));
- }
-
- /**
- * Determines whether this fluent iterable is empty.
- */
- public final boolean isEmpty() {
- return !iterable.iterator().hasNext();
- }
-
- /**
- * Returns an {@code ImmutableList} containing all of the elements from this fluent iterable in
- * proper sequence.
- *
- * @since 14.0 (since 12.0 as {@code toImmutableList()}).
- */
- public final ImmutableList<E> toList() {
- return ImmutableList.copyOf(iterable);
- }
-
- /**
- * Returns an {@code ImmutableList} containing all of the elements from this {@code
- * FluentIterable} in the order specified by {@code comparator}. To produce an {@code
- * ImmutableList} sorted by its natural ordering, use {@code toSortedList(Ordering.natural())}.
- *
- * @param comparator the function by which to sort list elements
- * @throws NullPointerException if any element is null
- * @since 14.0 (since 13.0 as {@code toSortedImmutableList()}).
- */
- @Beta
- public final ImmutableList<E> toSortedList(Comparator<? super E> comparator) {
- return Ordering.from(comparator).immutableSortedCopy(iterable);
- }
-
- /**
- * Returns an {@code ImmutableSet} containing all of the elements from this fluent iterable with
- * duplicates removed.
- *
- * @since 14.0 (since 12.0 as {@code toImmutableSet()}).
- */
- public final ImmutableSet<E> toSet() {
- return ImmutableSet.copyOf(iterable);
- }
-
- /**
- * Returns an {@code ImmutableSortedSet} containing all of the elements from this {@code
- * FluentIterable} in the order specified by {@code comparator}, with duplicates (determined by
- * {@code comparator.compare(x, y) == 0}) removed. To produce an {@code ImmutableSortedSet} sorted
- * by its natural ordering, use {@code toSortedSet(Ordering.natural())}.
- *
- * @param comparator the function by which to sort set elements
- * @throws NullPointerException if any element is null
- * @since 14.0 (since 12.0 as {@code toImmutableSortedSet()}).
- */
- public final ImmutableSortedSet<E> toSortedSet(Comparator<? super E> comparator) {
- return ImmutableSortedSet.copyOf(comparator, iterable);
- }
-
- /**
- * Returns an immutable map for which the elements of this {@code FluentIterable} are the keys in
- * the same order, mapped to values by the given function. If this iterable contains duplicate
- * elements, the returned map will contain each distinct element once in the order it first
- * appears.
- *
- * @throws NullPointerException if any element of this iterable is {@code null}, or if {@code
- * valueFunction} produces {@code null} for any key
- * @since 14.0
- */
- public final <V> ImmutableMap<E, V> toMap(Function<? super E, V> valueFunction) {
- return Maps.toMap(iterable, valueFunction);
- }
-
- /**
- * Creates an index {@code ImmutableListMultimap} that contains the results of applying a
- * specified function to each item in this {@code FluentIterable} of values. Each element of this
- * iterable will be stored as a value in the resulting multimap, yielding a multimap with the same
- * size as this iterable. The key used to store that value in the multimap will be the result of
- * calling the function on that value. The resulting multimap is created as an immutable snapshot.
- * In the returned multimap, keys appear in the order they are first encountered, and the values
- * corresponding to each key appear in the same order as they are encountered.
- *
- * @param keyFunction the function used to produce the key for each value
- * @throws NullPointerException if any of the following cases is true:
- * <ul>
- * <li>{@code keyFunction} is null
- * <li>An element in this fluent iterable is null
- * <li>{@code keyFunction} returns {@code null} for any element of this iterable
- * </ul>
- * @since 14.0
- */
- public final <K> ImmutableListMultimap<K, E> index(Function<? super E, K> keyFunction) {
- return Multimaps.index(iterable, keyFunction);
- }
-
- /**
- * Returns an immutable map for which the {@link java.util.Map#values} are the elements of this
- * {@code FluentIterable} in the given order, and each key is the product of invoking a supplied
- * function on its corresponding value.
- *
- * @param keyFunction the function used to produce the key for each value
- * @throws IllegalArgumentException if {@code keyFunction} produces the same key for more than one
- * value in this fluent iterable
- * @throws NullPointerException if any element of this fluent iterable is null, or if
- * {@code keyFunction} produces {@code null} for any value
- * @since 14.0
- */
- public final <K> ImmutableMap<K, E> uniqueIndex(Function<? super E, K> keyFunction) {
- return Maps.uniqueIndex(iterable, keyFunction);
- }
-
- /**
- * Returns an {@code ImmutableList} containing all of the elements from this
- * fluent iterable in proper sequence.
- *
- * @deprecated Use {@link #toList()} instead. This method is scheduled for removal in Guava 15.0.
- */
- @Deprecated
- public final ImmutableList<E> toImmutableList() {
- return toList();
- }
-
- /**
- * Returns an {@code ImmutableList} containing all of the elements from this
- * {@code FluentIterable} in the order specified by {@code comparator}. To produce an
- * {@code ImmutableList} sorted by its natural ordering, use
- * {@code toSortedImmutableList(Ordering.natural())}.
- *
- * @param comparator the function by which to sort list elements
- * @throws NullPointerException if any element is null
- * @since 13.0
- * @deprecated Use {@link #toSortedList(Comparator)} instead. This method is scheduled for removal
- * in Guava 15.0.
- */
- @Deprecated
- public final ImmutableList<E> toSortedImmutableList(Comparator<? super E> comparator) {
- return toSortedList(comparator);
- }
-
- /**
- * Returns an {@code ImmutableSet} containing all of the elements from this
- * fluent iterable with duplicates removed.
- *
- * @deprecated Use {@link #toSet()} instead. This method is scheduled for removal in Guava 15.0.
- */
- @Deprecated
- public final ImmutableSet<E> toImmutableSet() {
- return toSet();
- }
-
- /**
- * Returns an {@code ImmutableSortedSet} containing all of the elements from this
- * {@code FluentIterable} in the order specified by {@code comparator}, with duplicates
- * (determined by {@code comparator.compare(x, y) == 0}) removed. To produce an
- * {@code ImmutableSortedSet} sorted by its natural ordering, use
- * {@code toImmutableSortedSet(Ordering.natural())}.
- *
- * @param comparator the function by which to sort set elements
- * @throws NullPointerException if any element is null
- * @deprecated Use {@link #toSortedSet(Comparator)} instead. This method is scheduled for removal
- * in Guava 15.0.
- */
- @Deprecated
- public final ImmutableSortedSet<E> toImmutableSortedSet(Comparator<? super E> comparator) {
- return toSortedSet(comparator);
- }
-
- /**
- * Returns an array containing all of the elements from this fluent iterable in iteration order.
- *
- * @param type the type of the elements
- * @return a newly-allocated array into which all the elements of this fluent iterable have
- * been copied
- */
- @GwtIncompatible("Array.newArray(Class, int)")
- public final E[] toArray(Class<E> type) {
- return Iterables.toArray(iterable, type);
- }
-
- /**
- * Copies all the elements from this fluent iterable to {@code collection}. This is equivalent to
- * calling {@code Iterables.addAll(collection, this)}.
- *
- * @param collection the collection to copy elements to
- * @return {@code collection}, for convenience
- * @since 14.0
- */
- public final <C extends Collection<? super E>> C copyInto(C collection) {
- checkNotNull(collection);
- if (iterable instanceof Collection) {
- collection.addAll(Collections2.cast(iterable));
- } else {
- for (E item : iterable) {
- collection.add(item);
- }
- }
- return collection;
- }
-
- /**
- * Returns the element at the specified position in this fluent iterable.
- *
- * @param position position of the element to return
- * @return the element at the specified position in this fluent iterable
- * @throws IndexOutOfBoundsException if {@code position} is negative or greater than or equal to
- * the size of this fluent iterable
- */
- public final E get(int position) {
- return Iterables.get(iterable, position);
- }
-
- /**
- * Function that transforms {@code Iterable<E>} into a fluent iterable.
- */
- private static class FromIterableFunction<E>
- implements Function<Iterable<E>, FluentIterable<E>> {
- @Override
- public FluentIterable<E> apply(Iterable<E> fromObject) {
- return FluentIterable.from(fromObject);
- }
- }
-}
diff --git a/guava/src/com/google/common/collect/ForwardingBlockingDeque.java b/guava/src/com/google/common/collect/ForwardingBlockingDeque.java
deleted file mode 100644
index a6fb43d..0000000
--- a/guava/src/com/google/common/collect/ForwardingBlockingDeque.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import java.util.Collection;
-import java.util.concurrent.BlockingDeque;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A {@link BlockingDeque} which forwards all its method calls to another {@code BlockingDeque}.
- * Subclasses should override one or more methods to modify the behavior of the backing deque as
- * desired per the <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
- *
- * <p><b>Warning:</b> The methods of {@code ForwardingBlockingDeque} forward
- * <b>indiscriminately</b> to the methods of the delegate. For example, overriding {@link #add}
- * alone <b>will not</b> change the behaviour of {@link #offer} which can lead to unexpected
- * behaviour. In this case, you should override {@code offer} as well, either providing your own
- * implementation, or delegating to the provided {@code standardOffer} method.
- *
- * <p>
- * The {@code standard} methods are not guaranteed to be thread-safe, even when all of the methods
- * that they depend on are thread-safe.
- *
- * @author Emily Soldal
- * @since 14.0
- */
-public abstract class ForwardingBlockingDeque<E>
- extends ForwardingDeque<E> implements BlockingDeque<E> {
-
- /** Constructor for use by subclasses. */
- protected ForwardingBlockingDeque() {}
-
- @Override protected abstract BlockingDeque<E> delegate();
-
- @Override
- public int remainingCapacity() {
- return delegate().remainingCapacity();
- }
-
- @Override
- public void putFirst(E e) throws InterruptedException {
- delegate().putFirst(e);
- }
-
- @Override
- public void putLast(E e) throws InterruptedException {
- delegate().putLast(e);
- }
-
- @Override
- public boolean offerFirst(E e, long timeout, TimeUnit unit) throws InterruptedException {
- return delegate().offerFirst(e, timeout, unit);
- }
-
- @Override
- public boolean offerLast(E e, long timeout, TimeUnit unit) throws InterruptedException {
- return delegate().offerLast(e, timeout, unit);
- }
-
- @Override
- public E takeFirst() throws InterruptedException {
- return delegate().takeFirst();
- }
-
- @Override
- public E takeLast() throws InterruptedException {
- return delegate().takeLast();
- }
-
- @Override
- public E pollFirst(long timeout, TimeUnit unit) throws InterruptedException {
- return delegate().pollFirst(timeout, unit);
- }
-
- @Override
- public E pollLast(long timeout, TimeUnit unit) throws InterruptedException {
- return delegate().pollLast(timeout, unit);
- }
-
- @Override
- public void put(E e) throws InterruptedException {
- delegate().put(e);
- }
-
- @Override
- public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
- return delegate().offer(e, timeout, unit);
- }
-
- @Override
- public E take() throws InterruptedException {
- return delegate().take();
- }
-
- @Override
- public E poll(long timeout, TimeUnit unit) throws InterruptedException {
- return delegate().poll(timeout, unit);
- }
-
- @Override
- public int drainTo(Collection<? super E> c) {
- return delegate().drainTo(c);
- }
-
- @Override
- public int drainTo(Collection<? super E> c, int maxElements) {
- return delegate().drainTo(c, maxElements);
- }
-}
diff --git a/guava/src/com/google/common/collect/ForwardingCollection.java b/guava/src/com/google/common/collect/ForwardingCollection.java
index 79d7860..a6a46f0 100644
--- a/guava/src/com/google/common/collect/ForwardingCollection.java
+++ b/guava/src/com/google/common/collect/ForwardingCollection.java
@@ -16,6 +16,7 @@
package com.google.common.collect;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Objects;
@@ -126,7 +127,7 @@ public abstract class ForwardingCollection<E> extends ForwardingObject
*
* @since 7.0
*/
- protected boolean standardContains(@Nullable Object object) {
+ @Beta protected boolean standardContains(@Nullable Object object) {
return Iterators.contains(iterator(), object);
}
@@ -137,7 +138,7 @@ public abstract class ForwardingCollection<E> extends ForwardingObject
*
* @since 7.0
*/
- protected boolean standardContainsAll(Collection<?> collection) {
+ @Beta protected boolean standardContainsAll(Collection<?> collection) {
for (Object o : collection) {
if (!contains(o)) {
return false;
@@ -153,7 +154,7 @@ public abstract class ForwardingCollection<E> extends ForwardingObject
*
* @since 7.0
*/
- protected boolean standardAddAll(Collection<? extends E> collection) {
+ @Beta protected boolean standardAddAll(Collection<? extends E> collection) {
return Iterators.addAll(this, collection.iterator());
}
@@ -165,7 +166,7 @@ public abstract class ForwardingCollection<E> extends ForwardingObject
*
* @since 7.0
*/
- protected boolean standardRemove(@Nullable Object object) {
+ @Beta protected boolean standardRemove(@Nullable Object object) {
Iterator<E> iterator = iterator();
while (iterator.hasNext()) {
if (Objects.equal(iterator.next(), object)) {
@@ -184,7 +185,7 @@ public abstract class ForwardingCollection<E> extends ForwardingObject
*
* @since 7.0
*/
- protected boolean standardRemoveAll(Collection<?> collection) {
+ @Beta protected boolean standardRemoveAll(Collection<?> collection) {
return Iterators.removeAll(iterator(), collection);
}
@@ -196,7 +197,7 @@ public abstract class ForwardingCollection<E> extends ForwardingObject
*
* @since 7.0
*/
- protected boolean standardRetainAll(Collection<?> collection) {
+ @Beta protected boolean standardRetainAll(Collection<?> collection) {
return Iterators.retainAll(iterator(), collection);
}
@@ -208,8 +209,12 @@ public abstract class ForwardingCollection<E> extends ForwardingObject
*
* @since 7.0
*/
- protected void standardClear() {
- Iterators.clear(iterator());
+ @Beta protected void standardClear() {
+ Iterator<E> iterator = iterator();
+ while (iterator.hasNext()) {
+ iterator.next();
+ iterator.remove();
+ }
}
/**
@@ -220,7 +225,7 @@ public abstract class ForwardingCollection<E> extends ForwardingObject
*
* @since 7.0
*/
- protected boolean standardIsEmpty() {
+ @Beta protected boolean standardIsEmpty() {
return !iterator().hasNext();
}
@@ -231,7 +236,7 @@ public abstract class ForwardingCollection<E> extends ForwardingObject
*
* @since 7.0
*/
- protected String standardToString() {
+ @Beta protected String standardToString() {
return Collections2.toStringImpl(this);
}
@@ -242,7 +247,7 @@ public abstract class ForwardingCollection<E> extends ForwardingObject
*
* @since 7.0
*/
- protected Object[] standardToArray() {
+ @Beta protected Object[] standardToArray() {
Object[] newArray = new Object[size()];
return toArray(newArray);
}
@@ -254,7 +259,7 @@ public abstract class ForwardingCollection<E> extends ForwardingObject
*
* @since 7.0
*/
- protected <T> T[] standardToArray(T[] array) {
+ @Beta protected <T> T[] standardToArray(T[] array) {
return ObjectArrays.toArrayImpl(this, array);
}
}
diff --git a/guava/src/com/google/common/collect/ForwardingDeque.java b/guava/src/com/google/common/collect/ForwardingDeque.java
deleted file mode 100644
index 070f622..0000000
--- a/guava/src/com/google/common/collect/ForwardingDeque.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import java.util.Deque;
-import java.util.Iterator;
-
-/**
- * A deque which forwards all its method calls to another deque. Subclasses
- * should override one or more methods to modify the behavior of the backing
- * deque as desired per the <a
- * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
- *
- * <p><b>Warning:</b> The methods of {@code ForwardingDeque} forward
- * <b>indiscriminately</b> to the methods of the delegate. For example,
- * overriding {@link #add} alone <b>will not</b> change the behavior of {@link
- * #offer} which can lead to unexpected behavior. In this case, you should
- * override {@code offer} as well.
- *
- * @author Kurt Alfred Kluever
- * @since 12.0
- */
-public abstract class ForwardingDeque<E> extends ForwardingQueue<E>
- implements Deque<E> {
-
- /** Constructor for use by subclasses. */
- protected ForwardingDeque() {}
-
- @Override protected abstract Deque<E> delegate();
-
- @Override
- public void addFirst(E e) {
- delegate().addFirst(e);
- }
-
- @Override
- public void addLast(E e) {
- delegate().addLast(e);
- }
-
- @Override
- public Iterator<E> descendingIterator() {
- return delegate().descendingIterator();
- }
-
- @Override
- public E getFirst() {
- return delegate().getFirst();
- }
-
- @Override
- public E getLast() {
- return delegate().getLast();
- }
-
- @Override
- public boolean offerFirst(E e) {
- return delegate().offerFirst(e);
- }
-
- @Override
- public boolean offerLast(E e) {
- return delegate().offerLast(e);
- }
-
- @Override
- public E peekFirst() {
- return delegate().peekFirst();
- }
-
- @Override
- public E peekLast() {
- return delegate().peekLast();
- }
-
- @Override
- public E pollFirst() {
- return delegate().pollFirst();
- }
-
- @Override
- public E pollLast() {
- return delegate().pollLast();
- }
-
- @Override
- public E pop() {
- return delegate().pop();
- }
-
- @Override
- public void push(E e) {
- delegate().push(e);
- }
-
- @Override
- public E removeFirst() {
- return delegate().removeFirst();
- }
-
- @Override
- public E removeLast() {
- return delegate().removeLast();
- }
-
- @Override
- public boolean removeFirstOccurrence(Object o) {
- return delegate().removeFirstOccurrence(o);
- }
-
- @Override
- public boolean removeLastOccurrence(Object o) {
- return delegate().removeLastOccurrence(o);
- }
-}
diff --git a/guava/src/com/google/common/collect/ForwardingImmutableCollection.java b/guava/src/com/google/common/collect/ForwardingImmutableCollection.java
deleted file mode 100644
index 90489a4..0000000
--- a/guava/src/com/google/common/collect/ForwardingImmutableCollection.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2010 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-/**
- * Dummy class that makes the GWT serialization policy happy. It isn't used
- * on the server-side.
- *
- * @author Hayward Chan
- */
-@GwtCompatible(emulated = true)
-class ForwardingImmutableCollection {
- private ForwardingImmutableCollection() {}
-}
diff --git a/guava/src/com/google/common/collect/ForwardingImmutableList.java b/guava/src/com/google/common/collect/ForwardingImmutableList.java
deleted file mode 100644
index 2b9092e..0000000
--- a/guava/src/com/google/common/collect/ForwardingImmutableList.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-/**
- * Unused stub class, unreferenced under Java and manually emulated under GWT.
- *
- * @author Chris Povirk
- */
-@GwtCompatible(emulated = true)
-abstract class ForwardingImmutableList<E> {
- private ForwardingImmutableList() {}
-}
diff --git a/guava/src/com/google/common/collect/ForwardingImmutableMap.java b/guava/src/com/google/common/collect/ForwardingImmutableMap.java
deleted file mode 100644
index a367157..0000000
--- a/guava/src/com/google/common/collect/ForwardingImmutableMap.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-/**
- * Unused stub class, unreferenced under Java and manually emulated under GWT.
- *
- * @author Chris Povirk
- */
-@GwtCompatible(emulated = true)
-abstract class ForwardingImmutableMap<K, V> {
- private ForwardingImmutableMap() {}
-}
diff --git a/guava/src/com/google/common/collect/ForwardingImmutableSet.java b/guava/src/com/google/common/collect/ForwardingImmutableSet.java
deleted file mode 100644
index c7d7bf6..0000000
--- a/guava/src/com/google/common/collect/ForwardingImmutableSet.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-/**
- * Unused stub class, unreferenced under Java and manually emulated under GWT.
- *
- * @author Chris Povirk
- */
-@GwtCompatible(emulated = true)
-abstract class ForwardingImmutableSet<E> {
- private ForwardingImmutableSet() {}
-}
diff --git a/guava/src/com/google/common/collect/ForwardingList.java b/guava/src/com/google/common/collect/ForwardingList.java
index 9f3cf1c..e59e662 100644
--- a/guava/src/com/google/common/collect/ForwardingList.java
+++ b/guava/src/com/google/common/collect/ForwardingList.java
@@ -127,7 +127,7 @@ public abstract class ForwardingList<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected boolean standardAdd(E element){
+ @Beta protected boolean standardAdd(E element){
add(size(), element);
return true;
}
@@ -140,7 +140,7 @@ public abstract class ForwardingList<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected boolean standardAddAll(
+ @Beta protected boolean standardAddAll(
int index, Iterable<? extends E> elements) {
return Lists.addAllImpl(this, index, elements);
}
@@ -152,7 +152,7 @@ public abstract class ForwardingList<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected int standardIndexOf(@Nullable Object element) {
+ @Beta protected int standardIndexOf(@Nullable Object element) {
return Lists.indexOfImpl(this, element);
}
@@ -164,7 +164,7 @@ public abstract class ForwardingList<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected int standardLastIndexOf(@Nullable Object element) {
+ @Beta protected int standardLastIndexOf(@Nullable Object element) {
return Lists.lastIndexOfImpl(this, element);
}
@@ -175,7 +175,7 @@ public abstract class ForwardingList<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected Iterator<E> standardIterator() {
+ @Beta protected Iterator<E> standardIterator() {
return listIterator();
}
@@ -187,15 +187,14 @@ public abstract class ForwardingList<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected ListIterator<E> standardListIterator() {
+ @Beta protected ListIterator<E> standardListIterator(){
return listIterator(0);
}
/**
* A sensible default implementation of {@link #listIterator(int)}, in terms
- * of {@link #size}, {@link #get(int)}, {@link #set(int, Object)}, {@link
- * #add(int, Object)}, and {@link #remove(int)}. If you override any of these
- * methods, you may wish to override {@link #listIterator(int)} to forward to
+ * of {@link #size} and {@link #get(int)}. If you override either of these
+ * methods you may wish to override {@link #listIterator(int)} to forward to
* this implementation.
*
* @since 7.0
diff --git a/guava/src/com/google/common/collect/ForwardingMap.java b/guava/src/com/google/common/collect/ForwardingMap.java
index be22230..9b3a489 100644
--- a/guava/src/com/google/common/collect/ForwardingMap.java
+++ b/guava/src/com/google/common/collect/ForwardingMap.java
@@ -86,17 +86,17 @@ public abstract class ForwardingMap<K, V> extends ForwardingObject
}
@Override
- public boolean containsKey(@Nullable Object key) {
+ public boolean containsKey(Object key) {
return delegate().containsKey(key);
}
@Override
- public boolean containsValue(@Nullable Object value) {
+ public boolean containsValue(Object value) {
return delegate().containsValue(value);
}
@Override
- public V get(@Nullable Object key) {
+ public V get(Object key) {
return delegate().get(key);
}
@@ -141,7 +141,7 @@ public abstract class ForwardingMap<K, V> extends ForwardingObject
*
* @since 7.0
*/
- protected void standardPutAll(Map<? extends K, ? extends V> map) {
+ @Beta protected void standardPutAll(Map<? extends K, ? extends V> map) {
Maps.putAllImpl(this, map);
}
@@ -177,8 +177,12 @@ public abstract class ForwardingMap<K, V> extends ForwardingObject
*
* @since 7.0
*/
- protected void standardClear() {
- Iterators.clear(entrySet().iterator());
+ @Beta protected void standardClear() {
+ Iterator<Entry<K, V>> entryIterator = entrySet().iterator();
+ while (entryIterator.hasNext()) {
+ entryIterator.next();
+ entryIterator.remove();
+ }
}
/**
@@ -194,7 +198,6 @@ public abstract class ForwardingMap<K, V> extends ForwardingObject
*/
@Beta
protected class StandardKeySet extends Maps.KeySet<K, V> {
- /** Constructor for use by subclasses. */
public StandardKeySet() {}
@Override
@@ -227,7 +230,6 @@ public abstract class ForwardingMap<K, V> extends ForwardingObject
*/
@Beta
protected class StandardValues extends Maps.Values<K, V> {
- /** Constructor for use by subclasses. */
public StandardValues() {}
@Override
@@ -244,7 +246,7 @@ public abstract class ForwardingMap<K, V> extends ForwardingObject
*
* @since 7.0
*/
- protected boolean standardContainsValue(@Nullable Object value) {
+ @Beta protected boolean standardContainsValue(@Nullable Object value) {
return Maps.containsValueImpl(this, value);
}
@@ -260,7 +262,6 @@ public abstract class ForwardingMap<K, V> extends ForwardingObject
*/
@Beta
protected abstract class StandardEntrySet extends Maps.EntrySet<K, V> {
- /** Constructor for use by subclasses. */
public StandardEntrySet() {}
@Override
@@ -276,7 +277,7 @@ public abstract class ForwardingMap<K, V> extends ForwardingObject
*
* @since 7.0
*/
- protected boolean standardIsEmpty() {
+ @Beta protected boolean standardIsEmpty() {
return !entrySet().iterator().hasNext();
}
@@ -287,7 +288,7 @@ public abstract class ForwardingMap<K, V> extends ForwardingObject
*
* @since 7.0
*/
- protected boolean standardEquals(@Nullable Object object) {
+ @Beta protected boolean standardEquals(@Nullable Object object) {
return Maps.equalsImpl(this, object);
}
@@ -298,7 +299,7 @@ public abstract class ForwardingMap<K, V> extends ForwardingObject
*
* @since 7.0
*/
- protected int standardHashCode() {
+ @Beta protected int standardHashCode() {
return Sets.hashCodeImpl(entrySet());
}
@@ -309,7 +310,7 @@ public abstract class ForwardingMap<K, V> extends ForwardingObject
*
* @since 7.0
*/
- protected String standardToString() {
+ @Beta protected String standardToString() {
return Maps.toStringImpl(this);
}
}
diff --git a/guava/src/com/google/common/collect/ForwardingMapEntry.java b/guava/src/com/google/common/collect/ForwardingMapEntry.java
index 4d63757..ff201a5 100644
--- a/guava/src/com/google/common/collect/ForwardingMapEntry.java
+++ b/guava/src/com/google/common/collect/ForwardingMapEntry.java
@@ -92,7 +92,7 @@ public abstract class ForwardingMapEntry<K, V>
*
* @since 7.0
*/
- protected boolean standardEquals(@Nullable Object object) {
+ @Beta protected boolean standardEquals(@Nullable Object object) {
if (object instanceof Entry) {
Entry<?, ?> that = (Entry<?, ?>) object;
return Objects.equal(this.getKey(), that.getKey())
@@ -108,7 +108,7 @@ public abstract class ForwardingMapEntry<K, V>
*
* @since 7.0
*/
- protected int standardHashCode() {
+ @Beta protected int standardHashCode() {
K k = getKey();
V v = getValue();
return ((k == null) ? 0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode());
diff --git a/guava/src/com/google/common/collect/ForwardingMultiset.java b/guava/src/com/google/common/collect/ForwardingMultiset.java
index 9834751..4e1ceed 100644
--- a/guava/src/com/google/common/collect/ForwardingMultiset.java
+++ b/guava/src/com/google/common/collect/ForwardingMultiset.java
@@ -107,7 +107,7 @@ public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- @Override protected boolean standardContains(@Nullable Object object) {
+ @Override @Beta protected boolean standardContains(@Nullable Object object) {
return count(object) > 0;
}
@@ -118,8 +118,12 @@ public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- @Override protected void standardClear() {
- Iterators.clear(entrySet().iterator());
+ @Override @Beta protected void standardClear() {
+ Iterator<Entry<E>> entryIterator = entrySet().iterator();
+ while (entryIterator.hasNext()) {
+ entryIterator.next();
+ entryIterator.remove();
+ }
}
/**
@@ -145,7 +149,7 @@ public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected boolean standardAdd(E element) {
+ @Beta protected boolean standardAdd(E element) {
add(element, 1);
return true;
}
@@ -171,7 +175,7 @@ public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- @Override protected boolean standardRemove(Object element) {
+ @Beta @Override protected boolean standardRemove(Object element) {
return remove(element, 1) > 0;
}
@@ -183,7 +187,7 @@ public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- @Override protected boolean standardRemoveAll(
+ @Beta @Override protected boolean standardRemoveAll(
Collection<?> elementsToRemove) {
return Multisets.removeAllImpl(this, elementsToRemove);
}
@@ -196,7 +200,7 @@ public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- @Override protected boolean standardRetainAll(
+ @Beta @Override protected boolean standardRetainAll(
Collection<?> elementsToRetain) {
return Multisets.retainAllImpl(this, elementsToRetain);
}
@@ -210,7 +214,7 @@ public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected int standardSetCount(E element, int count) {
+ @Beta protected int standardSetCount(E element, int count) {
return Multisets.setCountImpl(this, element, count);
}
@@ -222,7 +226,8 @@ public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected boolean standardSetCount(E element, int oldCount, int newCount) {
+ @Beta protected boolean standardSetCount(
+ E element, int oldCount, int newCount) {
return Multisets.setCountImpl(this, element, oldCount, newCount);
}
@@ -241,7 +246,6 @@ public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
*/
@Beta
protected class StandardElementSet extends Multisets.ElementSet<E> {
- /** Constructor for use by subclasses. */
public StandardElementSet() {}
@Override
@@ -257,7 +261,7 @@ public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected Iterator<E> standardIterator() {
+ @Beta protected Iterator<E> standardIterator() {
return Multisets.iteratorImpl(this);
}
@@ -268,7 +272,7 @@ public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected int standardSize() {
+ @Beta protected int standardSize() {
return Multisets.sizeImpl(this);
}
@@ -280,7 +284,7 @@ public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected boolean standardEquals(@Nullable Object object) {
+ @Beta protected boolean standardEquals(@Nullable Object object) {
return Multisets.equalsImpl(this, object);
}
@@ -291,7 +295,7 @@ public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected int standardHashCode() {
+ @Beta protected int standardHashCode() {
return entrySet().hashCode();
}
@@ -302,7 +306,7 @@ public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- @Override protected String standardToString() {
+ @Beta @Override protected String standardToString() {
return entrySet().toString();
}
}
diff --git a/guava/src/com/google/common/collect/ForwardingNavigableMap.java b/guava/src/com/google/common/collect/ForwardingNavigableMap.java
deleted file mode 100644
index 8f371ff..0000000
--- a/guava/src/com/google/common/collect/ForwardingNavigableMap.java
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.collect.Maps.keyOrNull;
-
-import com.google.common.annotations.Beta;
-
-import java.util.Iterator;
-import java.util.NavigableMap;
-import java.util.NavigableSet;
-import java.util.NoSuchElementException;
-import java.util.SortedMap;
-
-/**
- * A navigable map which forwards all its method calls to another navigable map. Subclasses should
- * override one or more methods to modify the behavior of the backing map as desired per the <a
- * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
- *
- * <p><i>Warning:</i> The methods of {@code ForwardingNavigableMap} forward <i>indiscriminately</i>
- * to the methods of the delegate. For example, overriding {@link #put} alone <i>will not</i>
- * change the behavior of {@link #putAll}, which can lead to unexpected behavior. In this case, you
- * should override {@code putAll} as well, either providing your own implementation, or delegating
- * to the provided {@code standardPutAll} method.
- *
- * <p>Each of the {@code standard} methods uses the map's comparator (or the natural ordering of
- * the elements, if there is no comparator) to test element equality. As a result, if the comparator
- * is not consistent with equals, some of the standard implementations may violate the {@code Map}
- * contract.
- *
- * <p>The {@code standard} methods and the collection views they return are not guaranteed to be
- * thread-safe, even when all of the methods that they depend on are thread-safe.
- *
- * @author Louis Wasserman
- * @since 12.0
- */
-public abstract class ForwardingNavigableMap<K, V>
- extends ForwardingSortedMap<K, V> implements NavigableMap<K, V> {
-
- /** Constructor for use by subclasses. */
- protected ForwardingNavigableMap() {}
-
- @Override
- protected abstract NavigableMap<K, V> delegate();
-
- @Override
- public Entry<K, V> lowerEntry(K key) {
- return delegate().lowerEntry(key);
- }
-
- /**
- * A sensible definition of {@link #lowerEntry} in terms of the {@code lastEntry()} of
- * {@link #headMap(Object, boolean)}. If you override {@code headMap}, you may wish to override
- * {@code lowerEntry} to forward to this implementation.
- */
- protected Entry<K, V> standardLowerEntry(K key) {
- return headMap(key, false).lastEntry();
- }
-
- @Override
- public K lowerKey(K key) {
- return delegate().lowerKey(key);
- }
-
- /**
- * A sensible definition of {@link #lowerKey} in terms of {@code lowerEntry}. If you override
- * {@link #lowerEntry}, you may wish to override {@code lowerKey} to forward to this
- * implementation.
- */
- protected K standardLowerKey(K key) {
- return keyOrNull(lowerEntry(key));
- }
-
- @Override
- public Entry<K, V> floorEntry(K key) {
- return delegate().floorEntry(key);
- }
-
- /**
- * A sensible definition of {@link #floorEntry} in terms of the {@code lastEntry()} of
- * {@link #headMap(Object, boolean)}. If you override {@code headMap}, you may wish to override
- * {@code floorEntry} to forward to this implementation.
- */
- protected Entry<K, V> standardFloorEntry(K key) {
- return headMap(key, true).lastEntry();
- }
-
- @Override
- public K floorKey(K key) {
- return delegate().floorKey(key);
- }
-
- /**
- * A sensible definition of {@link #floorKey} in terms of {@code floorEntry}. If you override
- * {@code floorEntry}, you may wish to override {@code floorKey} to forward to this
- * implementation.
- */
- protected K standardFloorKey(K key) {
- return keyOrNull(floorEntry(key));
- }
-
- @Override
- public Entry<K, V> ceilingEntry(K key) {
- return delegate().ceilingEntry(key);
- }
-
- /**
- * A sensible definition of {@link #ceilingEntry} in terms of the {@code firstEntry()} of
- * {@link #tailMap(Object, boolean)}. If you override {@code tailMap}, you may wish to override
- * {@code ceilingEntry} to forward to this implementation.
- */
- protected Entry<K, V> standardCeilingEntry(K key) {
- return tailMap(key, true).firstEntry();
- }
-
- @Override
- public K ceilingKey(K key) {
- return delegate().ceilingKey(key);
- }
-
- /**
- * A sensible definition of {@link #ceilingKey} in terms of {@code ceilingEntry}. If you override
- * {@code ceilingEntry}, you may wish to override {@code ceilingKey} to forward to this
- * implementation.
- */
- protected K standardCeilingKey(K key) {
- return keyOrNull(ceilingEntry(key));
- }
-
- @Override
- public Entry<K, V> higherEntry(K key) {
- return delegate().higherEntry(key);
- }
-
- /**
- * A sensible definition of {@link #higherEntry} in terms of the {@code firstEntry()} of
- * {@link #tailMap(Object, boolean)}. If you override {@code tailMap}, you may wish to override
- * {@code higherEntry} to forward to this implementation.
- */
- protected Entry<K, V> standardHigherEntry(K key) {
- return tailMap(key, false).firstEntry();
- }
-
- @Override
- public K higherKey(K key) {
- return delegate().higherKey(key);
- }
-
- /**
- * A sensible definition of {@link #higherKey} in terms of {@code higherEntry}. If you override
- * {@code higherEntry}, you may wish to override {@code higherKey} to forward to this
- * implementation.
- */
- protected K standardHigherKey(K key) {
- return keyOrNull(higherEntry(key));
- }
-
- @Override
- public Entry<K, V> firstEntry() {
- return delegate().firstEntry();
- }
-
- /**
- * A sensible definition of {@link #firstEntry} in terms of the {@code iterator()} of
- * {@link #entrySet}. If you override {@code entrySet}, you may wish to override
- * {@code firstEntry} to forward to this implementation.
- */
- protected Entry<K, V> standardFirstEntry() {
- return Iterables.getFirst(entrySet(), null);
- }
-
- /**
- * A sensible definition of {@link #firstKey} in terms of {@code firstEntry}. If you override
- * {@code firstEntry}, you may wish to override {@code firstKey} to forward to this
- * implementation.
- */
- protected K standardFirstKey() {
- Entry<K, V> entry = firstEntry();
- if (entry == null) {
- throw new NoSuchElementException();
- } else {
- return entry.getKey();
- }
- }
-
- @Override
- public Entry<K, V> lastEntry() {
- return delegate().lastEntry();
- }
-
- /**
- * A sensible definition of {@link #lastEntry} in terms of the {@code iterator()} of the
- * {@link #entrySet} of {@link #descendingMap}. If you override {@code descendingMap}, you may
- * wish to override {@code lastEntry} to forward to this implementation.
- */
- protected Entry<K, V> standardLastEntry() {
- return Iterables.getFirst(descendingMap().entrySet(), null);
- }
-
- /**
- * A sensible definition of {@link #lastKey} in terms of {@code lastEntry}. If you override
- * {@code lastEntry}, you may wish to override {@code lastKey} to forward to this implementation.
- */
- protected K standardLastKey() {
- Entry<K, V> entry = lastEntry();
- if (entry == null) {
- throw new NoSuchElementException();
- } else {
- return entry.getKey();
- }
- }
-
- @Override
- public Entry<K, V> pollFirstEntry() {
- return delegate().pollFirstEntry();
- }
-
- /**
- * A sensible definition of {@link #pollFirstEntry} in terms of the {@code iterator} of
- * {@code entrySet}. If you override {@code entrySet}, you may wish to override
- * {@code pollFirstEntry} to forward to this implementation.
- */
- protected Entry<K, V> standardPollFirstEntry() {
- return Iterators.pollNext(entrySet().iterator());
- }
-
- @Override
- public Entry<K, V> pollLastEntry() {
- return delegate().pollLastEntry();
- }
-
- /**
- * A sensible definition of {@link #pollFirstEntry} in terms of the {@code iterator} of the
- * {@code entrySet} of {@code descendingMap}. If you override {@code descendingMap}, you may wish
- * to override {@code pollFirstEntry} to forward to this implementation.
- */
- protected Entry<K, V> standardPollLastEntry() {
- return Iterators.pollNext(descendingMap().entrySet().iterator());
- }
-
- @Override
- public NavigableMap<K, V> descendingMap() {
- return delegate().descendingMap();
- }
-
- /**
- * A sensible implementation of {@link NavigableMap#descendingMap} in terms of the methods of
- * this {@code NavigableMap}. In many cases, you may wish to override
- * {@link ForwardingNavigableMap#descendingMap} to forward to this implementation or a subclass
- * thereof.
- *
- * <p>In particular, this map iterates over entries with repeated calls to
- * {@link NavigableMap#lowerEntry}. If a more efficient means of iteration is available, you may
- * wish to override the {@code entryIterator()} method of this class.
- *
- * @since 12.0
- */
- @Beta
- protected class StandardDescendingMap extends Maps.DescendingMap<K, V> {
- /** Constructor for use by subclasses. */
- public StandardDescendingMap() {}
-
- @Override
- NavigableMap<K, V> forward() {
- return ForwardingNavigableMap.this;
- }
-
- @Override
- protected Iterator<Entry<K, V>> entryIterator() {
- return new Iterator<Entry<K, V>>() {
- private Entry<K, V> toRemove = null;
- private Entry<K, V> nextOrNull = forward().lastEntry();
-
- @Override
- public boolean hasNext() {
- return nextOrNull != null;
- }
-
- @Override
- public java.util.Map.Entry<K, V> next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- try {
- return nextOrNull;
- } finally {
- toRemove = nextOrNull;
- nextOrNull = forward().lowerEntry(nextOrNull.getKey());
- }
- }
-
- @Override
- public void remove() {
- Iterators.checkRemove(toRemove != null);
- forward().remove(toRemove.getKey());
- toRemove = null;
- }
- };
- }
- }
-
- @Override
- public NavigableSet<K> navigableKeySet() {
- return delegate().navigableKeySet();
- }
-
- /**
- * A sensible implementation of {@link NavigableMap#navigableKeySet} in terms of the methods of
- * this {@code NavigableMap}. In many cases, you may wish to override
- * {@link ForwardingNavigableMap#navigableKeySet} to forward to this implementation or a subclass
- * thereof.
- *
- * @since 12.0
- */
- @Beta
- protected class StandardNavigableKeySet extends Maps.NavigableKeySet<K, V> {
- /** Constructor for use by subclasses. */
- public StandardNavigableKeySet() {
- super(ForwardingNavigableMap.this);
- }
- }
-
- @Override
- public NavigableSet<K> descendingKeySet() {
- return delegate().descendingKeySet();
- }
-
- /**
- * A sensible definition of {@link #descendingKeySet} as the {@code navigableKeySet} of
- * {@link #descendingMap}. (The {@link StandardDescendingMap} implementation implements
- * {@code navigableKeySet} on its own, so as not to cause an infinite loop.) If you override
- * {@code descendingMap}, you may wish to override {@code descendingKeySet} to forward to this
- * implementation.
- */
- @Beta
- protected NavigableSet<K> standardDescendingKeySet() {
- return descendingMap().navigableKeySet();
- }
-
- /**
- * A sensible definition of {@link #subMap(Object, Object)} in terms of
- * {@link #subMap(Object, boolean, Object, boolean)}. If you override
- * {@code subMap(K, boolean, K, boolean)}, you may wish to override {@code subMap} to forward to
- * this implementation.
- */
- @Override
- protected SortedMap<K, V> standardSubMap(K fromKey, K toKey) {
- return subMap(fromKey, true, toKey, false);
- }
-
- @Override
- public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
- return delegate().subMap(fromKey, fromInclusive, toKey, toInclusive);
- }
-
- @Override
- public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
- return delegate().headMap(toKey, inclusive);
- }
-
- @Override
- public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
- return delegate().tailMap(fromKey, inclusive);
- }
-
- /**
- * A sensible definition of {@link #headMap(Object)} in terms of
- * {@link #headMap(Object, boolean)}. If you override {@code headMap(K, boolean)}, you may wish
- * to override {@code headMap} to forward to this implementation.
- */
- protected SortedMap<K, V> standardHeadMap(K toKey) {
- return headMap(toKey, false);
- }
-
- /**
- * A sensible definition of {@link #tailMap(Object)} in terms of
- * {@link #tailMap(Object, boolean)}. If you override {@code tailMap(K, boolean)}, you may wish
- * to override {@code tailMap} to forward to this implementation.
- */
- protected SortedMap<K, V> standardTailMap(K fromKey) {
- return tailMap(fromKey, true);
- }
-}
diff --git a/guava/src/com/google/common/collect/ForwardingNavigableSet.java b/guava/src/com/google/common/collect/ForwardingNavigableSet.java
deleted file mode 100644
index dff5ea0..0000000
--- a/guava/src/com/google/common/collect/ForwardingNavigableSet.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.Beta;
-
-import java.util.Iterator;
-import java.util.NavigableSet;
-import java.util.SortedSet;
-
-/**
- * A navigable set which forwards all its method calls to another navigable set. Subclasses should
- * override one or more methods to modify the behavior of the backing set as desired per the <a
- * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
- *
- * <p><i>Warning:</i> The methods of {@code ForwardingNavigableSet} forward <i>indiscriminately</i>
- * to the methods of the delegate. For example, overriding {@link #add} alone <i>will not</i>
- * change the behavior of {@link #addAll}, which can lead to unexpected behavior. In this case, you
- * should override {@code addAll} as well, either providing your own implementation, or delegating
- * to the provided {@code standardAddAll} method.
- *
- * <p>Each of the {@code standard} methods uses the set's comparator (or the natural ordering of
- * the elements, if there is no comparator) to test element equality. As a result, if the
- * comparator is not consistent with equals, some of the standard implementations may violate the
- * {@code Set} contract.
- *
- * <p>The {@code standard} methods and the collection views they return are not guaranteed to be
- * thread-safe, even when all of the methods that they depend on are thread-safe.
- *
- * @author Louis Wasserman
- * @since 12.0
- */
-public abstract class ForwardingNavigableSet<E>
- extends ForwardingSortedSet<E> implements NavigableSet<E> {
-
- /** Constructor for use by subclasses. */
- protected ForwardingNavigableSet() {}
-
- @Override
- protected abstract NavigableSet<E> delegate();
-
- @Override
- public E lower(E e) {
- return delegate().lower(e);
- }
-
- /**
- * A sensible definition of {@link #lower} in terms of the {@code descendingIterator} method of
- * {@link #headSet(Object, boolean)}. If you override {@link #headSet(Object, boolean)}, you may
- * wish to override {@link #lower} to forward to this implementation.
- */
- protected E standardLower(E e) {
- return Iterators.getNext(headSet(e, false).descendingIterator(), null);
- }
-
- @Override
- public E floor(E e) {
- return delegate().floor(e);
- }
-
- /**
- * A sensible definition of {@link #floor} in terms of the {@code descendingIterator} method of
- * {@link #headSet(Object, boolean)}. If you override {@link #headSet(Object, boolean)}, you may
- * wish to override {@link #floor} to forward to this implementation.
- */
- protected E standardFloor(E e) {
- return Iterators.getNext(headSet(e, true).descendingIterator(), null);
- }
-
- @Override
- public E ceiling(E e) {
- return delegate().ceiling(e);
- }
-
- /**
- * A sensible definition of {@link #ceiling} in terms of the {@code iterator} method of
- * {@link #tailSet(Object, boolean)}. If you override {@link #tailSet(Object, boolean)}, you may
- * wish to override {@link #ceiling} to forward to this implementation.
- */
- protected E standardCeiling(E e) {
- return Iterators.getNext(tailSet(e, true).iterator(), null);
- }
-
- @Override
- public E higher(E e) {
- return delegate().higher(e);
- }
-
- /**
- * A sensible definition of {@link #higher} in terms of the {@code iterator} method of
- * {@link #tailSet(Object, boolean)}. If you override {@link #tailSet(Object, boolean)}, you may
- * wish to override {@link #higher} to forward to this implementation.
- */
- protected E standardHigher(E e) {
- return Iterators.getNext(tailSet(e, false).iterator(), null);
- }
-
- @Override
- public E pollFirst() {
- return delegate().pollFirst();
- }
-
- /**
- * A sensible definition of {@link #pollFirst} in terms of the {@code iterator} method. If you
- * override {@link #iterator} you may wish to override {@link #pollFirst} to forward to this
- * implementation.
- */
- protected E standardPollFirst() {
- return Iterators.pollNext(iterator());
- }
-
- @Override
- public E pollLast() {
- return delegate().pollLast();
- }
-
- /**
- * A sensible definition of {@link #pollLast} in terms of the {@code descendingIterator} method.
- * If you override {@link #descendingIterator} you may wish to override {@link #pollLast} to
- * forward to this implementation.
- */
- protected E standardPollLast() {
- return Iterators.pollNext(descendingIterator());
- }
-
- protected E standardFirst() {
- return iterator().next();
- }
-
- protected E standardLast() {
- return descendingIterator().next();
- }
-
- @Override
- public NavigableSet<E> descendingSet() {
- return delegate().descendingSet();
- }
-
- /**
- * A sensible implementation of {@link NavigableSet#descendingSet} in terms of the other methods
- * of {@link NavigableSet}, notably including {@link NavigableSet#descendingIterator}.
- *
- * <p>In many cases, you may wish to override {@link ForwardingNavigableSet#descendingSet} to
- * forward to this implementation or a subclass thereof.
- *
- * @since 12.0
- */
- @Beta
- protected class StandardDescendingSet extends Sets.DescendingSet<E> {
- /** Constructor for use by subclasses. */
- public StandardDescendingSet() {
- super(ForwardingNavigableSet.this);
- }
- }
-
- @Override
- public Iterator<E> descendingIterator() {
- return delegate().descendingIterator();
- }
-
- @Override
- public NavigableSet<E> subSet(
- E fromElement,
- boolean fromInclusive,
- E toElement,
- boolean toInclusive) {
- return delegate().subSet(fromElement, fromInclusive, toElement, toInclusive);
- }
-
- /**
- * A sensible definition of {@link #subSet(Object, boolean, Object, boolean)} in terms of the
- * {@code headSet} and {@code tailSet} methods. In many cases, you may wish to override
- * {@link #subSet(Object, boolean, Object, boolean)} to forward to this implementation.
- */
- @Beta
- protected NavigableSet<E> standardSubSet(
- E fromElement,
- boolean fromInclusive,
- E toElement,
- boolean toInclusive) {
- return tailSet(fromElement, fromInclusive).headSet(toElement, toInclusive);
- }
-
- /**
- * A sensible definition of {@link #subSet(Object, Object)} in terms of the
- * {@link #subSet(Object, boolean, Object, boolean)} method. If you override
- * {@link #subSet(Object, boolean, Object, boolean)}, you may wish to override
- * {@link #subSet(Object, Object)} to forward to this implementation.
- */
- @Override
- protected SortedSet<E> standardSubSet(E fromElement, E toElement) {
- return subSet(fromElement, true, toElement, false);
- }
-
- @Override
- public NavigableSet<E> headSet(E toElement, boolean inclusive) {
- return delegate().headSet(toElement, inclusive);
- }
-
- /**
- * A sensible definition of {@link #headSet(Object)} in terms of the
- * {@link #headSet(Object, boolean)} method. If you override
- * {@link #headSet(Object, boolean)}, you may wish to override
- * {@link #headSet(Object)} to forward to this implementation.
- */
- protected SortedSet<E> standardHeadSet(E toElement) {
- return headSet(toElement, false);
- }
-
- @Override
- public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
- return delegate().tailSet(fromElement, inclusive);
- }
-
- /**
- * A sensible definition of {@link #tailSet(Object)} in terms of the
- * {@link #tailSet(Object, boolean)} method. If you override
- * {@link #tailSet(Object, boolean)}, you may wish to override
- * {@link #tailSet(Object)} to forward to this implementation.
- */
- protected SortedSet<E> standardTailSet(E fromElement) {
- return tailSet(fromElement, true);
- }
-}
diff --git a/guava/src/com/google/common/collect/ForwardingQueue.java b/guava/src/com/google/common/collect/ForwardingQueue.java
index 569880a..3d30aaf 100644
--- a/guava/src/com/google/common/collect/ForwardingQueue.java
+++ b/guava/src/com/google/common/collect/ForwardingQueue.java
@@ -16,6 +16,7 @@
package com.google.common.collect;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import java.util.NoSuchElementException;
@@ -82,7 +83,7 @@ public abstract class ForwardingQueue<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected boolean standardOffer(E e) {
+ @Beta protected boolean standardOffer(E e) {
try {
return add(e);
} catch (IllegalStateException caught) {
@@ -97,7 +98,7 @@ public abstract class ForwardingQueue<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected E standardPeek() {
+ @Beta protected E standardPeek() {
try {
return element();
} catch (NoSuchElementException caught) {
@@ -112,7 +113,7 @@ public abstract class ForwardingQueue<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected E standardPoll() {
+ @Beta protected E standardPoll() {
try {
return remove();
} catch (NoSuchElementException caught) {
diff --git a/guava/src/com/google/common/collect/ForwardingSet.java b/guava/src/com/google/common/collect/ForwardingSet.java
index e1a4485..4c3dccd 100644
--- a/guava/src/com/google/common/collect/ForwardingSet.java
+++ b/guava/src/com/google/common/collect/ForwardingSet.java
@@ -16,11 +16,9 @@
package com.google.common.collect;
-import static com.google.common.base.Preconditions.checkNotNull;
-
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
-import java.util.Collection;
import java.util.Set;
import javax.annotation.Nullable;
@@ -64,26 +62,13 @@ public abstract class ForwardingSet<E> extends ForwardingCollection<E>
}
/**
- * A sensible definition of {@link #removeAll} in terms of {@link #iterator}
- * and {@link #remove}. If you override {@code iterator} or {@code remove},
- * you may wish to override {@link #removeAll} to forward to this
- * implementation.
- *
- * @since 7.0 (this version overrides the {@code ForwardingCollection} version as of 12.0)
- */
- @Override
- protected boolean standardRemoveAll(Collection<?> collection) {
- return Sets.removeAllImpl(this, checkNotNull(collection)); // for GWT
- }
-
- /**
* A sensible definition of {@link #equals} in terms of {@link #size} and
* {@link #containsAll}. If you override either of those methods, you may wish
* to override {@link #equals} to forward to this implementation.
*
* @since 7.0
*/
- protected boolean standardEquals(@Nullable Object object) {
+ @Beta protected boolean standardEquals(@Nullable Object object) {
return Sets.equalsImpl(this, object);
}
@@ -94,7 +79,7 @@ public abstract class ForwardingSet<E> extends ForwardingCollection<E>
*
* @since 7.0
*/
- protected int standardHashCode() {
+ @Beta protected int standardHashCode() {
return Sets.hashCodeImpl(this);
}
}
diff --git a/guava/src/com/google/common/collect/ForwardingTable.java b/guava/src/com/google/common/collect/ForwardingTable.java
index 92cc876..2c59705 100644
--- a/guava/src/com/google/common/collect/ForwardingTable.java
+++ b/guava/src/com/google/common/collect/ForwardingTable.java
@@ -16,6 +16,7 @@
package com.google.common.collect;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import java.util.Collection;
@@ -31,6 +32,7 @@ import java.util.Set;
* @author Gregory Kick
* @since 7.0
*/
+@Beta
@GwtCompatible
public abstract class ForwardingTable<R, C, V> extends ForwardingObject
implements Table<R, C, V> {
diff --git a/guava/src/com/google/common/collect/GeneralRange.java b/guava/src/com/google/common/collect/GeneralRange.java
index cb3b2c8..5a3980f 100644
--- a/guava/src/com/google/common/collect/GeneralRange.java
+++ b/guava/src/com/google/common/collect/GeneralRange.java
@@ -1,11 +1,11 @@
/*
* Copyright (C) 2011 The Guava Authors
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
@@ -19,21 +19,21 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.BoundType.CLOSED;
import static com.google.common.collect.BoundType.OPEN;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Objects;
-
import java.io.Serializable;
import java.util.Comparator;
import javax.annotation.Nullable;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Objects;
+
/**
* A generalized interval on any ordering, for internal use. Supports {@code null}. Unlike
* {@link Range}, this allows the use of an arbitrary comparator. This is designed for use in the
* implementation of subcollections of sorted collection types.
- *
+ *
* <p>Whenever possible, use {@code Range} instead, which is better supported.
- *
+ *
* @author Louis Wasserman
*/
@GwtCompatible(serializable = true)
@@ -138,26 +138,26 @@ final class GeneralRange<T> implements Serializable {
}
boolean isEmpty() {
- return (hasUpperBound() && tooLow(getUpperEndpoint()))
- || (hasLowerBound() && tooHigh(getLowerEndpoint()));
+ return (hasUpperBound() && tooLow(upperEndpoint))
+ || (hasLowerBound() && tooHigh(lowerEndpoint));
}
boolean tooLow(@Nullable T t) {
if (!hasLowerBound()) {
return false;
}
- T lbound = getLowerEndpoint();
+ T lbound = lowerEndpoint;
int cmp = comparator.compare(t, lbound);
- return cmp < 0 | (cmp == 0 & getLowerBoundType() == OPEN);
+ return cmp < 0 | (cmp == 0 & lowerBoundType == OPEN);
}
boolean tooHigh(@Nullable T t) {
if (!hasUpperBound()) {
return false;
}
- T ubound = getUpperEndpoint();
+ T ubound = upperEndpoint;
int cmp = comparator.compare(t, ubound);
- return cmp > 0 | (cmp == 0 & getUpperBoundType() == OPEN);
+ return cmp > 0 | (cmp == 0 & upperBoundType == OPEN);
}
boolean contains(@Nullable T t) {
@@ -173,33 +173,33 @@ final class GeneralRange<T> implements Serializable {
boolean hasLowBound = this.hasLowerBound;
@Nullable
- T lowEnd = getLowerEndpoint();
- BoundType lowType = getLowerBoundType();
+ T lowEnd = lowerEndpoint;
+ BoundType lowType = lowerBoundType;
if (!hasLowerBound()) {
hasLowBound = other.hasLowerBound;
- lowEnd = other.getLowerEndpoint();
- lowType = other.getLowerBoundType();
+ lowEnd = other.lowerEndpoint;
+ lowType = other.lowerBoundType;
} else if (other.hasLowerBound()) {
- int cmp = comparator.compare(getLowerEndpoint(), other.getLowerEndpoint());
- if (cmp < 0 || (cmp == 0 && other.getLowerBoundType() == OPEN)) {
- lowEnd = other.getLowerEndpoint();
- lowType = other.getLowerBoundType();
+ int cmp = comparator.compare(lowerEndpoint, other.lowerEndpoint);
+ if (cmp < 0 || (cmp == 0 && other.lowerBoundType == OPEN)) {
+ lowEnd = other.lowerEndpoint;
+ lowType = other.lowerBoundType;
}
}
boolean hasUpBound = this.hasUpperBound;
@Nullable
- T upEnd = getUpperEndpoint();
- BoundType upType = getUpperBoundType();
+ T upEnd = upperEndpoint;
+ BoundType upType = upperBoundType;
if (!hasUpperBound()) {
hasUpBound = other.hasUpperBound;
- upEnd = other.getUpperEndpoint();
- upType = other.getUpperBoundType();
+ upEnd = other.upperEndpoint;
+ upType = other.upperBoundType;
} else if (other.hasUpperBound()) {
- int cmp = comparator.compare(getUpperEndpoint(), other.getUpperEndpoint());
- if (cmp > 0 || (cmp == 0 && other.getUpperBoundType() == OPEN)) {
- upEnd = other.getUpperEndpoint();
- upType = other.getUpperBoundType();
+ int cmp = comparator.compare(upperEndpoint, other.upperEndpoint);
+ if (cmp > 0 || (cmp == 0 && other.upperBoundType == OPEN)) {
+ upEnd = other.upperEndpoint;
+ upType = other.upperBoundType;
}
}
@@ -221,18 +221,18 @@ final class GeneralRange<T> implements Serializable {
if (obj instanceof GeneralRange) {
GeneralRange<?> r = (GeneralRange<?>) obj;
return comparator.equals(r.comparator) && hasLowerBound == r.hasLowerBound
- && hasUpperBound == r.hasUpperBound && getLowerBoundType().equals(r.getLowerBoundType())
- && getUpperBoundType().equals(r.getUpperBoundType())
- && Objects.equal(getLowerEndpoint(), r.getLowerEndpoint())
- && Objects.equal(getUpperEndpoint(), r.getUpperEndpoint());
+ && hasUpperBound == r.hasUpperBound && lowerBoundType.equals(r.lowerBoundType)
+ && upperBoundType.equals(r.upperBoundType)
+ && Objects.equal(lowerEndpoint, r.lowerEndpoint)
+ && Objects.equal(upperEndpoint, r.upperEndpoint);
}
return false;
}
@Override
public int hashCode() {
- return Objects.hashCode(comparator, getLowerEndpoint(), getLowerBoundType(), getUpperEndpoint(),
- getUpperBoundType());
+ return Objects.hashCode(comparator, lowerEndpoint, lowerBoundType, upperEndpoint,
+ upperBoundType);
}
private transient GeneralRange<T> reverse;
@@ -240,12 +240,12 @@ final class GeneralRange<T> implements Serializable {
/**
* Returns the same range relative to the reversed comparator.
*/
- GeneralRange<T> reverse() {
+ public GeneralRange<T> reverse() {
GeneralRange<T> result = reverse;
if (result == null) {
- result = new GeneralRange<T>(
- Ordering.from(comparator).reverse(), hasUpperBound, getUpperEndpoint(),
- getUpperBoundType(), hasLowerBound, getLowerEndpoint(), getLowerBoundType());
+ result =
+ new GeneralRange<T>(Ordering.from(comparator).reverse(), hasUpperBound, upperEndpoint,
+ upperBoundType, hasLowerBound, lowerEndpoint, lowerBoundType);
result.reverse = this;
return this.reverse = result;
}
@@ -254,30 +254,35 @@ final class GeneralRange<T> implements Serializable {
@Override
public String toString() {
- return new StringBuilder()
- .append(comparator)
- .append(":")
- .append(lowerBoundType == CLOSED ? '[' : '(')
- .append(hasLowerBound ? lowerEndpoint : "-\u221e")
- .append(',')
- .append(hasUpperBound ? upperEndpoint : "\u221e")
- .append(upperBoundType == CLOSED ? ']' : ')')
- .toString();
- }
-
- T getLowerEndpoint() {
- return lowerEndpoint;
- }
-
- BoundType getLowerBoundType() {
- return lowerBoundType;
- }
-
- T getUpperEndpoint() {
- return upperEndpoint;
- }
-
- BoundType getUpperBoundType() {
- return upperBoundType;
+ StringBuilder builder = new StringBuilder();
+ builder.append(comparator).append(":");
+ switch (lowerBoundType) {
+ case CLOSED:
+ builder.append('[');
+ break;
+ case OPEN:
+ builder.append('(');
+ break;
+ }
+ if (hasLowerBound()) {
+ builder.append(lowerEndpoint);
+ } else {
+ builder.append("-\u221e");
+ }
+ builder.append(',');
+ if (hasUpperBound()) {
+ builder.append(upperEndpoint);
+ } else {
+ builder.append("\u221e");
+ }
+ switch (upperBoundType) {
+ case CLOSED:
+ builder.append(']');
+ break;
+ case OPEN:
+ builder.append(')');
+ break;
+ }
+ return builder.toString();
}
}
diff --git a/guava/src/com/google/common/collect/GenericMapMaker.java b/guava/src/com/google/common/collect/GenericMapMaker.java
index 0b0a290..8c5bbeb 100644
--- a/guava/src/com/google/common/collect/GenericMapMaker.java
+++ b/guava/src/com/google/common/collect/GenericMapMaker.java
@@ -62,6 +62,12 @@ public abstract class GenericMapMaker<K0, V0> {
abstract GenericMapMaker<K0, V0> keyEquivalence(Equivalence<Object> equivalence);
/**
+ * See {@link MapMaker#valueEquivalence}.
+ */
+ @GwtIncompatible("To be supported")
+ abstract GenericMapMaker<K0, V0> valueEquivalence(Equivalence<Object> equivalence);
+
+ /**
* See {@link MapMaker#initialCapacity}.
*/
public abstract GenericMapMaker<K0, V0> initialCapacity(int initialCapacity);
@@ -72,6 +78,11 @@ public abstract class GenericMapMaker<K0, V0> {
abstract GenericMapMaker<K0, V0> maximumSize(int maximumSize);
/**
+ * See {@link MapMaker#strongKeys}.
+ */
+ abstract GenericMapMaker<K0, V0> strongKeys();
+
+ /**
* See {@link MapMaker#concurrencyLevel}.
*/
public abstract GenericMapMaker<K0, V0> concurrencyLevel(int concurrencyLevel);
@@ -83,6 +94,18 @@ public abstract class GenericMapMaker<K0, V0> {
public abstract GenericMapMaker<K0, V0> weakKeys();
/**
+ * See {@link MapMaker#strongValues}.
+ */
+ abstract GenericMapMaker<K0, V0> strongValues();
+
+ /**
+ * See {@link MapMaker#softKeys}.
+ */
+ @Deprecated
+ @GwtIncompatible("java.lang.ref.SoftReference")
+ public abstract GenericMapMaker<K0, V0> softKeys();
+
+ /**
* See {@link MapMaker#weakValues}.
*/
@GwtIncompatible("java.lang.ref.WeakReference")
@@ -95,6 +118,13 @@ public abstract class GenericMapMaker<K0, V0> {
public abstract GenericMapMaker<K0, V0> softValues();
/**
+ * See {@link MapMaker#expiration}.
+ */
+ @Deprecated
+ public
+ abstract GenericMapMaker<K0, V0> expiration(long duration, TimeUnit unit);
+
+ /**
* See {@link MapMaker#expireAfterWrite}.
*/
abstract GenericMapMaker<K0, V0> expireAfterWrite(long duration, TimeUnit unit);
diff --git a/guava/src/com/google/common/collect/HashBasedTable.java b/guava/src/com/google/common/collect/HashBasedTable.java
index 4944174..8c92ec1 100644
--- a/guava/src/com/google/common/collect/HashBasedTable.java
+++ b/guava/src/com/google/common/collect/HashBasedTable.java
@@ -18,6 +18,7 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Supplier;
@@ -44,15 +45,12 @@ import javax.annotation.Nullable;
* <p>Note that this implementation is not synchronized. If multiple threads
* access this table concurrently and one of the threads modifies the table, it
* must be synchronized externally.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table">
- * {@code Table}</a>.
*
* @author Jared Levy
* @since 7.0
*/
@GwtCompatible(serializable = true)
+@Beta
public class HashBasedTable<R, C, V> extends StandardTable<R, C, V> {
private static class Factory<C, V>
implements Supplier<Map<C, V>>, Serializable {
diff --git a/guava/src/com/google/common/collect/HashBiMap.java b/guava/src/com/google/common/collect/HashBiMap.java
index 0620f45..26d11e1 100644
--- a/guava/src/com/google/common/collect/HashBiMap.java
+++ b/guava/src/com/google/common/collect/HashBiMap.java
@@ -1,657 +1,97 @@
/*
* Copyright (C) 2007 The Guava Authors
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package com.google.common.collect;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
-import com.google.common.base.Objects;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.util.AbstractMap;
-import java.util.Arrays;
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
+import java.util.HashMap;
import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
import javax.annotation.Nullable;
/**
- * A {@link BiMap} backed by two hash tables. This implementation allows null keys and values. A
- * {@code HashBiMap} and its inverse are both serializable.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap"> {@code BiMap}
- * </a>.
+ * A {@link BiMap} backed by two {@link HashMap} instances. This implementation
+ * allows null keys and values. A {@code HashBiMap} and its inverse are both
+ * serializable.
*
- * @author Louis Wasserman
* @author Mike Bostock
* @since 2.0 (imported from Google Collections Library)
*/
@GwtCompatible(emulated = true)
-public final class HashBiMap<K, V> extends AbstractMap<K, V> implements BiMap<K, V>, Serializable {
+public final class HashBiMap<K, V> extends AbstractBiMap<K, V> {
/**
- * Returns a new, empty {@code HashBiMap} with the default initial capacity (16).
+ * Returns a new, empty {@code HashBiMap} with the default initial capacity
+ * (16).
*/
public static <K, V> HashBiMap<K, V> create() {
- return create(16);
+ return new HashBiMap<K, V>();
}
/**
* Constructs a new, empty bimap with the specified expected size.
*
* @param expectedSize the expected number of entries
- * @throws IllegalArgumentException if the specified expected size is negative
+ * @throws IllegalArgumentException if the specified expected size is
+ * negative
*/
public static <K, V> HashBiMap<K, V> create(int expectedSize) {
return new HashBiMap<K, V>(expectedSize);
}
/**
- * Constructs a new bimap containing initial values from {@code map}. The bimap is created with an
- * initial capacity sufficient to hold the mappings in the specified map.
+ * Constructs a new bimap containing initial values from {@code map}. The
+ * bimap is created with an initial capacity sufficient to hold the mappings
+ * in the specified map.
*/
- public static <K, V> HashBiMap<K, V> create(Map<? extends K, ? extends V> map) {
+ public static <K, V> HashBiMap<K, V> create(
+ Map<? extends K, ? extends V> map) {
HashBiMap<K, V> bimap = create(map.size());
bimap.putAll(map);
return bimap;
}
- private static final class BiEntry<K, V> {
- final K key;
- final int keyHash;
-
- final V value;
- final int valueHash;
-
- @Nullable
- BiEntry<K, V> nextInKToVBucket;
-
- @Nullable
- BiEntry<K, V> nextInVToKBucket;
-
- BiEntry(K key, int keyHash, V value, int valueHash) {
- this.key = key;
- this.keyHash = keyHash;
- this.value = value;
- this.valueHash = valueHash;
- }
+ private HashBiMap() {
+ super(new HashMap<K, V>(), new HashMap<V, K>());
}
- private static final double LOAD_FACTOR = 1.0;
-
- private transient BiEntry<K, V>[] hashTableKToV;
- private transient BiEntry<K, V>[] hashTableVToK;
- private transient int size;
- private transient int mask;
- private transient int modCount;
-
private HashBiMap(int expectedSize) {
- init(expectedSize);
- }
-
- private void init(int expectedSize) {
- checkArgument(expectedSize >= 0, "expectedSize must be >= 0 but was %s", expectedSize);
- int tableSize = Hashing.closedTableSize(expectedSize, LOAD_FACTOR);
- this.hashTableKToV = createTable(tableSize);
- this.hashTableVToK = createTable(tableSize);
- this.mask = tableSize - 1;
- this.modCount = 0;
- this.size = 0;
- }
-
- /**
- * Finds and removes {@code entry} from the bucket linked lists in both the
- * key-to-value direction and the value-to-key direction.
- */
- private void delete(BiEntry<K, V> entry) {
- int keyBucket = entry.keyHash & mask;
- BiEntry<K, V> prevBucketEntry = null;
- for (BiEntry<K, V> bucketEntry = hashTableKToV[keyBucket]; true;
- bucketEntry = bucketEntry.nextInKToVBucket) {
- if (bucketEntry == entry) {
- if (prevBucketEntry == null) {
- hashTableKToV[keyBucket] = entry.nextInKToVBucket;
- } else {
- prevBucketEntry.nextInKToVBucket = entry.nextInKToVBucket;
- }
- break;
- }
- prevBucketEntry = bucketEntry;
- }
-
- int valueBucket = entry.valueHash & mask;
- prevBucketEntry = null;
- for (BiEntry<K, V> bucketEntry = hashTableVToK[valueBucket];;
- bucketEntry = bucketEntry.nextInVToKBucket) {
- if (bucketEntry == entry) {
- if (prevBucketEntry == null) {
- hashTableVToK[valueBucket] = entry.nextInVToKBucket;
- } else {
- prevBucketEntry.nextInVToKBucket = entry.nextInVToKBucket;
- }
- break;
- }
- prevBucketEntry = bucketEntry;
- }
-
- size--;
- modCount++;
- }
-
- private void insert(BiEntry<K, V> entry) {
- int keyBucket = entry.keyHash & mask;
- entry.nextInKToVBucket = hashTableKToV[keyBucket];
- hashTableKToV[keyBucket] = entry;
-
- int valueBucket = entry.valueHash & mask;
- entry.nextInVToKBucket = hashTableVToK[valueBucket];
- hashTableVToK[valueBucket] = entry;
-
- size++;
- modCount++;
- }
-
- private static int hash(@Nullable Object o) {
- return Hashing.smear((o == null) ? 0 : o.hashCode());
+ super(
+ Maps.<K, V>newHashMapWithExpectedSize(expectedSize),
+ Maps.<V, K>newHashMapWithExpectedSize(expectedSize));
}
- private BiEntry<K, V> seekByKey(@Nullable Object key, int keyHash) {
- for (BiEntry<K, V> entry = hashTableKToV[keyHash & mask]; entry != null;
- entry = entry.nextInKToVBucket) {
- if (keyHash == entry.keyHash && Objects.equal(key, entry.key)) {
- return entry;
- }
- }
- return null;
- }
-
- private BiEntry<K, V> seekByValue(@Nullable Object value, int valueHash) {
- for (BiEntry<K, V> entry = hashTableVToK[valueHash & mask]; entry != null;
- entry = entry.nextInVToKBucket) {
- if (valueHash == entry.valueHash && Objects.equal(value, entry.value)) {
- return entry;
- }
- }
- return null;
- }
-
- @Override
- public boolean containsKey(@Nullable Object key) {
- return seekByKey(key, hash(key)) != null;
- }
-
- @Override
- public boolean containsValue(@Nullable Object value) {
- return seekByValue(value, hash(value)) != null;
- }
+ // Override these two methods to show that keys and values may be null
- @Nullable
- @Override
- public V get(@Nullable Object key) {
- BiEntry<K, V> entry = seekByKey(key, hash(key));
- return (entry == null) ? null : entry.value;
+ @Override public V put(@Nullable K key, @Nullable V value) {
+ return super.put(key, value);
}
- @Override
- public V put(@Nullable K key, @Nullable V value) {
- return put(key, value, false);
- }
-
- @Override
- public V forcePut(@Nullable K key, @Nullable V value) {
- return put(key, value, true);
- }
-
- private V put(@Nullable K key, @Nullable V value, boolean force) {
- int keyHash = hash(key);
- int valueHash = hash(value);
-
- BiEntry<K, V> oldEntryForKey = seekByKey(key, keyHash);
- if (oldEntryForKey != null && valueHash == oldEntryForKey.valueHash
- && Objects.equal(value, oldEntryForKey.value)) {
- return value;
- }
-
- BiEntry<K, V> oldEntryForValue = seekByValue(value, valueHash);
- if (oldEntryForValue != null) {
- if (force) {
- delete(oldEntryForValue);
- } else {
- throw new IllegalArgumentException("value already present: " + value);
- }
- }
-
- if (oldEntryForKey != null) {
- delete(oldEntryForKey);
- }
- BiEntry<K, V> newEntry = new BiEntry<K, V>(key, keyHash, value, valueHash);
- insert(newEntry);
- rehashIfNecessary();
- return (oldEntryForKey == null) ? null : oldEntryForKey.value;
- }
-
- @Nullable
- private K putInverse(@Nullable V value, @Nullable K key, boolean force) {
- int valueHash = hash(value);
- int keyHash = hash(key);
-
- BiEntry<K, V> oldEntryForValue = seekByValue(value, valueHash);
- if (oldEntryForValue != null && keyHash == oldEntryForValue.keyHash
- && Objects.equal(key, oldEntryForValue.key)) {
- return key;
- }
-
- BiEntry<K, V> oldEntryForKey = seekByKey(key, keyHash);
- if (oldEntryForKey != null) {
- if (force) {
- delete(oldEntryForKey);
- } else {
- throw new IllegalArgumentException("value already present: " + key);
- }
- }
-
- if (oldEntryForValue != null) {
- delete(oldEntryForValue);
- }
- BiEntry<K, V> newEntry = new BiEntry<K, V>(key, keyHash, value, valueHash);
- insert(newEntry);
- rehashIfNecessary();
- return (oldEntryForValue == null) ? null : oldEntryForValue.key;
- }
-
- private void rehashIfNecessary() {
- BiEntry<K, V>[] oldKToV = hashTableKToV;
- if (Hashing.needsResizing(size, oldKToV.length, LOAD_FACTOR)) {
- int newTableSize = oldKToV.length * 2;
-
- this.hashTableKToV = createTable(newTableSize);
- this.hashTableVToK = createTable(newTableSize);
- this.mask = newTableSize - 1;
- this.size = 0;
-
- for (int bucket = 0; bucket < oldKToV.length; bucket++) {
- BiEntry<K, V> entry = oldKToV[bucket];
- while (entry != null) {
- BiEntry<K, V> nextEntry = entry.nextInKToVBucket;
- insert(entry);
- entry = nextEntry;
- }
- }
- this.modCount++;
- }
- }
-
- @SuppressWarnings("unchecked")
- private BiEntry<K, V>[] createTable(int length) {
- return new BiEntry[length];
- }
-
- @Override
- public V remove(@Nullable Object key) {
- BiEntry<K, V> entry = seekByKey(key, hash(key));
- if (entry == null) {
- return null;
- } else {
- delete(entry);
- return entry.value;
- }
- }
-
- @Override
- public void clear() {
- size = 0;
- Arrays.fill(hashTableKToV, null);
- Arrays.fill(hashTableVToK, null);
- modCount++;
- }
-
- @Override
- public int size() {
- return size;
- }
-
- abstract class Itr<T> implements Iterator<T> {
- int nextBucket = 0;
- BiEntry<K, V> next = null;
- BiEntry<K, V> toRemove = null;
- int expectedModCount = modCount;
-
- private void checkForConcurrentModification() {
- if (modCount != expectedModCount) {
- throw new ConcurrentModificationException();
- }
- }
-
- @Override
- public boolean hasNext() {
- checkForConcurrentModification();
- if (next != null) {
- return true;
- }
- while (nextBucket < hashTableKToV.length) {
- if (hashTableKToV[nextBucket] != null) {
- next = hashTableKToV[nextBucket++];
- return true;
- }
- nextBucket++;
- }
- return false;
- }
-
- @Override
- public T next() {
- checkForConcurrentModification();
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
-
- BiEntry<K, V> entry = next;
- next = entry.nextInKToVBucket;
- toRemove = entry;
- return output(entry);
- }
-
- @Override
- public void remove() {
- checkForConcurrentModification();
- checkState(toRemove != null, "Only one remove() call allowed per call to next");
- delete(toRemove);
- expectedModCount = modCount;
- toRemove = null;
- }
-
- abstract T output(BiEntry<K, V> entry);
- }
-
- @Override
- public Set<K> keySet() {
- return new KeySet();
- }
-
- private final class KeySet extends Maps.KeySet<K, V> {
- @Override
- Map<K, V> map() {
- return HashBiMap.this;
- }
-
- @Override
- public Iterator<K> iterator() {
- return new Itr<K>() {
- @Override
- K output(BiEntry<K, V> entry) {
- return entry.key;
- }
- };
- }
-
- @Override
- public boolean remove(@Nullable Object o) {
- BiEntry<K, V> entry = seekByKey(o, hash(o));
- if (entry == null) {
- return false;
- } else {
- delete(entry);
- return true;
- }
- }
- }
-
- @Override
- public Set<V> values() {
- return inverse().keySet();
- }
-
- @Override
- public Set<Entry<K, V>> entrySet() {
- return new EntrySet();
- }
-
- private final class EntrySet extends Maps.EntrySet<K, V> {
- @Override
- Map<K, V> map() {
- return HashBiMap.this;
- }
-
- @Override
- public Iterator<Entry<K, V>> iterator() {
- return new Itr<Entry<K, V>>() {
- @Override
- Entry<K, V> output(BiEntry<K, V> entry) {
- return new MapEntry(entry);
- }
-
- class MapEntry extends AbstractMapEntry<K, V> {
- BiEntry<K, V> delegate;
-
- MapEntry(BiEntry<K, V> entry) {
- this.delegate = entry;
- }
-
- @Override public K getKey() {
- return delegate.key;
- }
-
- @Override public V getValue() {
- return delegate.value;
- }
-
- @Override public V setValue(V value) {
- V oldValue = delegate.value;
- int valueHash = hash(value);
- if (valueHash == delegate.valueHash && Objects.equal(value, oldValue)) {
- return value;
- }
- checkArgument(
- seekByValue(value, valueHash) == null, "value already present: %s", value);
- delete(delegate);
- BiEntry<K, V> newEntry =
- new BiEntry<K, V>(delegate.key, delegate.keyHash, value, valueHash);
- insert(newEntry);
- expectedModCount = modCount;
- if (toRemove == delegate) {
- toRemove = newEntry;
- }
- delegate = newEntry;
- return oldValue;
- }
- }
- };
- }
- }
-
- private transient BiMap<V, K> inverse;
-
- @Override
- public BiMap<V, K> inverse() {
- return (inverse == null) ? inverse = new Inverse() : inverse;
- }
-
- private final class Inverse extends AbstractMap<V, K> implements BiMap<V, K>, Serializable {
- BiMap<K, V> forward() {
- return HashBiMap.this;
- }
-
- @Override
- public int size() {
- return size;
- }
-
- @Override
- public void clear() {
- forward().clear();
- }
-
- @Override
- public boolean containsKey(@Nullable Object value) {
- return forward().containsValue(value);
- }
-
- @Override
- public K get(@Nullable Object value) {
- BiEntry<K, V> entry = seekByValue(value, hash(value));
- return (entry == null) ? null : entry.key;
- }
-
- @Override
- public K put(@Nullable V value, @Nullable K key) {
- return putInverse(value, key, false);
- }
-
- @Override
- public K forcePut(@Nullable V value, @Nullable K key) {
- return putInverse(value, key, true);
- }
-
- @Override
- public K remove(@Nullable Object value) {
- BiEntry<K, V> entry = seekByValue(value, hash(value));
- if (entry == null) {
- return null;
- } else {
- delete(entry);
- return entry.key;
- }
- }
-
- @Override
- public BiMap<K, V> inverse() {
- return forward();
- }
-
- @Override
- public Set<V> keySet() {
- return new InverseKeySet();
- }
-
- private final class InverseKeySet extends Maps.KeySet<V, K> {
- @Override
- Map<V, K> map() {
- return Inverse.this;
- }
-
- @Override
- public boolean remove(@Nullable Object o) {
- BiEntry<K, V> entry = seekByValue(o, hash(o));
- if (entry == null) {
- return false;
- } else {
- delete(entry);
- return true;
- }
- }
-
- @Override
- public Iterator<V> iterator() {
- return new Itr<V>() {
- @Override V output(BiEntry<K, V> entry) {
- return entry.value;
- }
- };
- }
- }
-
- @Override
- public Set<K> values() {
- return forward().keySet();
- }
-
- @Override
- public Set<Entry<V, K>> entrySet() {
- return new Maps.EntrySet<V, K>() {
-
- @Override
- Map<V, K> map() {
- return Inverse.this;
- }
-
- @Override
- public Iterator<Entry<V, K>> iterator() {
- return new Itr<Entry<V, K>>() {
- @Override
- Entry<V, K> output(BiEntry<K, V> entry) {
- return new InverseEntry(entry);
- }
-
- class InverseEntry extends AbstractMapEntry<V, K> {
- BiEntry<K, V> delegate;
-
- InverseEntry(BiEntry<K, V> entry) {
- this.delegate = entry;
- }
-
- @Override
- public V getKey() {
- return delegate.value;
- }
-
- @Override
- public K getValue() {
- return delegate.key;
- }
-
- @Override
- public K setValue(K key) {
- K oldKey = delegate.key;
- int keyHash = hash(key);
- if (keyHash == delegate.keyHash && Objects.equal(key, oldKey)) {
- return key;
- }
- checkArgument(seekByKey(key, keyHash) == null, "value already present: %s", key);
- delete(delegate);
- BiEntry<K, V> newEntry =
- new BiEntry<K, V>(key, keyHash, delegate.value, delegate.valueHash);
- insert(newEntry);
- expectedModCount = modCount;
- // This is safe because entries can only get bumped up to earlier in the iteration,
- // so they can't get revisited.
- return oldKey;
- }
- }
- };
- }
- };
- }
-
- Object writeReplace() {
- return new InverseSerializedForm<K, V>(HashBiMap.this);
- }
- }
-
- private static final class InverseSerializedForm<K, V> implements Serializable {
- private final HashBiMap<K, V> bimap;
-
- InverseSerializedForm(HashBiMap<K, V> bimap) {
- this.bimap = bimap;
- }
-
- Object readResolve() {
- return bimap.inverse();
- }
+ @Override public V forcePut(@Nullable K key, @Nullable V value) {
+ return super.forcePut(key, value);
}
/**
- * @serialData the number of entries, first key, first value, second key, second value, and so on.
+ * @serialData the number of entries, first key, first value, second key,
+ * second value, and so on.
*/
@GwtIncompatible("java.io.ObjectOutputStream")
private void writeObject(ObjectOutputStream stream) throws IOException {
@@ -660,10 +100,12 @@ public final class HashBiMap<K, V> extends AbstractMap<K, V> implements BiMap<K,
}
@GwtIncompatible("java.io.ObjectInputStream")
- private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
stream.defaultReadObject();
int size = Serialization.readCount(stream);
- init(size);
+ setDelegates(Maps.<K, V>newHashMapWithExpectedSize(size),
+ Maps.<V, K>newHashMapWithExpectedSize(size));
Serialization.populateMap(this, stream, size);
}
diff --git a/guava/src/com/google/common/collect/HashMultimap.java b/guava/src/com/google/common/collect/HashMultimap.java
index bab2a05..d347ff1 100644
--- a/guava/src/com/google/common/collect/HashMultimap.java
+++ b/guava/src/com/google/common/collect/HashMultimap.java
@@ -48,7 +48,7 @@ import java.util.Set;
*/
@GwtCompatible(serializable = true, emulated = true)
public final class HashMultimap<K, V> extends AbstractSetMultimap<K, V> {
- private static final int DEFAULT_VALUES_PER_KEY = 2;
+ private static final int DEFAULT_VALUES_PER_KEY = 8;
@VisibleForTesting
transient int expectedValuesPerKey = DEFAULT_VALUES_PER_KEY;
diff --git a/guava/src/com/google/common/collect/Hashing.java b/guava/src/com/google/common/collect/Hashing.java
index b13eb7c..9c5f6bc 100644
--- a/guava/src/com/google/common/collect/Hashing.java
+++ b/guava/src/com/google/common/collect/Hashing.java
@@ -17,50 +17,27 @@
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.primitives.Ints;
/**
* Static methods for implementing hash-based collections.
*
* @author Kevin Bourrillion
* @author Jesse Wilson
- * @author Austin Appleby
*/
@GwtCompatible
final class Hashing {
private Hashing() {}
- private static final int C1 = 0xcc9e2d51;
- private static final int C2 = 0x1b873593;
-
/*
- * This method was rewritten in Java from an intermediate step of the Murmur hash function in
- * http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp, which contained the
- * following header:
- *
- * MurmurHash3 was written by Austin Appleby, and is placed in the public domain. The author
- * hereby disclaims copyright to this source code.
+ * This method was written by Doug Lea with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/licenses/publicdomain
+ *
+ * As of 2010/06/11, this method is identical to the (package private) hash
+ * method in OpenJDK 7's java.util.HashMap class.
*/
static int smear(int hashCode) {
- return C2 * Integer.rotateLeft(hashCode * C1, 15);
- }
-
- static int MAX_TABLE_SIZE = Ints.MAX_POWER_OF_TWO;
-
- static int closedTableSize(int expectedEntries, double loadFactor) {
- // Get the recommended table size.
- // Round down to the nearest power of 2.
- expectedEntries = Math.max(expectedEntries, 2);
- int tableSize = Integer.highestOneBit(expectedEntries);
- // Check to make sure that we will not exceed the maximum load factor.
- if ((double) expectedEntries / tableSize > loadFactor) {
- tableSize <<= 1;
- return (tableSize > 0) ? tableSize : MAX_TABLE_SIZE;
- }
- return tableSize;
- }
-
- static boolean needsResizing(int size, int tableSize, double loadFactor) {
- return size > loadFactor * tableSize && tableSize < MAX_TABLE_SIZE;
+ hashCode ^= (hashCode >>> 20) ^ (hashCode >>> 12);
+ return hashCode ^ (hashCode >>> 7) ^ (hashCode >>> 4);
}
}
diff --git a/guava/src/com/google/common/collect/ImmutableAsList.java b/guava/src/com/google/common/collect/ImmutableAsList.java
index 249abee..9eb87de 100644
--- a/guava/src/com/google/common/collect/ImmutableAsList.java
+++ b/guava/src/com/google/common/collect/ImmutableAsList.java
@@ -17,49 +17,36 @@
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable;
/**
- * List returned by {@link ImmutableCollection#asList} that delegates {@code contains} checks
- * to the backing collection.
+ * List returned by {@link ImmutableCollection#asList} when the collection isn't
+ * an {@link ImmutableList} or an {@link ImmutableSortedSet}.
*
* @author Jared Levy
- * @author Louis Wasserman
*/
@GwtCompatible(serializable = true, emulated = true)
@SuppressWarnings("serial")
-abstract class ImmutableAsList<E> extends ImmutableList<E> {
- abstract ImmutableCollection<E> delegateCollection();
+final class ImmutableAsList<E> extends RegularImmutableList<E> {
+ private final transient ImmutableCollection<E> collection;
- @Override public boolean contains(Object target) {
- // The collection's contains() is at least as fast as ImmutableList's
- // and is often faster.
- return delegateCollection().contains(target);
- }
-
- @Override
- public int size() {
- return delegateCollection().size();
+ ImmutableAsList(Object[] array, ImmutableCollection<E> collection) {
+ super(array, 0, array.length);
+ this.collection = collection;
}
- @Override
- public boolean isEmpty() {
- return delegateCollection().isEmpty();
- }
-
- @Override
- boolean isPartialView() {
- return delegateCollection().isPartialView();
+ @Override public boolean contains(Object target) {
+ // The collection's contains() is at least as fast as RegularImmutableList's
+ // and is often faster.
+ return collection.contains(target);
}
/**
* Serialized form that leads to the same performance as the original list.
*/
- @GwtIncompatible("serialization")
static class SerializedForm implements Serializable {
final ImmutableCollection<?> collection;
SerializedForm(ImmutableCollection<?> collection) {
@@ -71,14 +58,12 @@ abstract class ImmutableAsList<E> extends ImmutableList<E> {
private static final long serialVersionUID = 0;
}
- @GwtIncompatible("serialization")
private void readObject(ObjectInputStream stream)
throws InvalidObjectException {
throw new InvalidObjectException("Use SerializedForm");
}
- @GwtIncompatible("serialization")
@Override Object writeReplace() {
- return new SerializedForm(delegateCollection());
+ return new SerializedForm(collection);
}
}
diff --git a/guava/src/com/google/common/collect/ImmutableBiMap.java b/guava/src/com/google/common/collect/ImmutableBiMap.java
index d7968b2..9d8e144 100644
--- a/guava/src/com/google/common/collect/ImmutableBiMap.java
+++ b/guava/src/com/google/common/collect/ImmutableBiMap.java
@@ -16,13 +16,12 @@
package com.google.common.collect;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.annotations.GwtCompatible;
-import java.util.Collection;
import java.util.Map;
+import javax.annotation.Nullable;
+
/**
* An immutable {@link BiMap} with reliable user-specified iteration order. Does
* not permit null keys or values. An {@code ImmutableBiMap} and its inverse
@@ -44,22 +43,23 @@ import java.util.Map;
public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V>
implements BiMap<K, V> {
+ private static final ImmutableBiMap<Object, Object> EMPTY_IMMUTABLE_BIMAP
+ = new EmptyBiMap();
+
/**
* Returns the empty bimap.
*/
// Casting to any type is safe because the set will never hold any elements.
@SuppressWarnings("unchecked")
public static <K, V> ImmutableBiMap<K, V> of() {
- return (ImmutableBiMap<K, V>) EmptyImmutableBiMap.INSTANCE;
+ return (ImmutableBiMap<K, V>) EMPTY_IMMUTABLE_BIMAP;
}
/**
* Returns an immutable bimap containing a single entry.
*/
public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) {
- checkNotNull(k1, "null key in entry: null=%s", v1);
- checkNotNull(v1, "null value in entry: %s=null", k1);
- return new SingletonImmutableBiMap<K, V>(k1, v1);
+ return new RegularImmutableBiMap<K, V>(ImmutableMap.of(k1, v1));
}
/**
@@ -68,10 +68,7 @@ public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V>
* @throws IllegalArgumentException if duplicate keys or values are added
*/
public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2) {
- return new Builder<K, V>()
- .put(k1, v1)
- .put(k2, v2)
- .build();
+ return new RegularImmutableBiMap<K, V>(ImmutableMap.of(k1, v1, k2, v2));
}
/**
@@ -81,11 +78,8 @@ public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V>
*/
public static <K, V> ImmutableBiMap<K, V> of(
K k1, V v1, K k2, V v2, K k3, V v3) {
- return new Builder<K, V>()
- .put(k1, v1)
- .put(k2, v2)
- .put(k3, v3)
- .build();
+ return new RegularImmutableBiMap<K, V>(ImmutableMap.of(
+ k1, v1, k2, v2, k3, v3));
}
/**
@@ -95,12 +89,8 @@ public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V>
*/
public static <K, V> ImmutableBiMap<K, V> of(
K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
- return new Builder<K, V>()
- .put(k1, v1)
- .put(k2, v2)
- .put(k3, v3)
- .put(k4, v4)
- .build();
+ return new RegularImmutableBiMap<K, V>(ImmutableMap.of(
+ k1, v1, k2, v2, k3, v3, k4, v4));
}
/**
@@ -110,13 +100,8 @@ public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V>
*/
public static <K, V> ImmutableBiMap<K, V> of(
K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
- return new Builder<K, V>()
- .put(k1, v1)
- .put(k2, v2)
- .put(k3, v3)
- .put(k4, v4)
- .put(k5, v5)
- .build();
+ return new RegularImmutableBiMap<K, V>(ImmutableMap.of(
+ k1, v1, k2, v2, k3, v3, k4, v4, k5, v5));
}
// looking for of() with > 5 entries? Use the builder instead.
@@ -184,7 +169,11 @@ public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V>
* @throws IllegalArgumentException if duplicate keys or values were added
*/
@Override public ImmutableBiMap<K, V> build() {
- return fromEntries(entries);
+ ImmutableMap<K, V> map = super.build();
+ if (map.isEmpty()) {
+ return of();
+ }
+ return new RegularImmutableBiMap<K, V>(map);
}
}
@@ -213,25 +202,18 @@ public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V>
}
}
- return fromEntries(ImmutableList.copyOf(map.entrySet()));
- }
-
- static <K, V> ImmutableBiMap<K, V> fromEntries(
- Collection<? extends Entry<? extends K, ? extends V>> entries) {
- switch (entries.size()) {
- case 0:
- return of();
- case 1: {
- Entry<? extends K, ? extends V> entry = Iterables.getOnlyElement(entries);
- return new SingletonImmutableBiMap<K, V>(entry.getKey(), entry.getValue());
- }
- default:
- return new RegularImmutableBiMap<K, V>(entries);
+ if (map.isEmpty()) {
+ return of();
}
+
+ ImmutableMap<K, V> immutableMap = ImmutableMap.copyOf(map);
+ return new RegularImmutableBiMap<K, V>(immutableMap);
}
ImmutableBiMap() {}
+ abstract ImmutableMap<K, V> delegate();
+
/**
* {@inheritDoc}
*
@@ -241,6 +223,26 @@ public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V>
@Override
public abstract ImmutableBiMap<V, K> inverse();
+ @Override public boolean containsKey(@Nullable Object key) {
+ return delegate().containsKey(key);
+ }
+
+ @Override public boolean containsValue(@Nullable Object value) {
+ return inverse().containsKey(value);
+ }
+
+ @Override public ImmutableSet<Entry<K, V>> entrySet() {
+ return delegate().entrySet();
+ }
+
+ @Override public V get(@Nullable Object key) {
+ return delegate().get(key);
+ }
+
+ @Override public ImmutableSet<K> keySet() {
+ return delegate().keySet();
+ }
+
/**
* Returns an immutable set of the values in this map. The values are in the
* same order as the parameters used to build this map.
@@ -253,14 +255,50 @@ public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V>
* Guaranteed to throw an exception and leave the bimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public V forcePut(K key, V value) {
throw new UnsupportedOperationException();
}
+ @Override public boolean isEmpty() {
+ return delegate().isEmpty();
+ }
+
+ @Override
+ public int size() {
+ return delegate().size();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ return object == this || delegate().equals(object);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+
+ @Override public String toString() {
+ return delegate().toString();
+ }
+
+ /** Bimap with no mappings. */
+ @SuppressWarnings("serial") // uses writeReplace(), not default serialization
+ static class EmptyBiMap extends ImmutableBiMap<Object, Object> {
+ @Override ImmutableMap<Object, Object> delegate() {
+ return ImmutableMap.of();
+ }
+ @Override public ImmutableBiMap<Object, Object> inverse() {
+ return this;
+ }
+ @Override boolean isPartialView() {
+ return false;
+ }
+ Object readResolve() {
+ return EMPTY_IMMUTABLE_BIMAP; // preserve singleton property
+ }
+ }
+
/**
* Serialized type for all ImmutableBiMap instances. It captures the logical
* contents and they are reconstructed using public factory methods. This
diff --git a/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java b/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java
index 50f93c3..1c596e2 100644
--- a/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java
+++ b/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java
@@ -16,14 +16,10 @@
package com.google.common.collect;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.primitives.Primitives;
import java.util.Map;
-import javax.annotation.Nullable;
-
/**
* A class-to-instance map backed by an {@link ImmutableMap}. See also {@link
* MutableClassToInstanceMap}.
@@ -142,18 +138,15 @@ public final class ImmutableClassToInstanceMap<B> extends
@Override
@SuppressWarnings("unchecked") // value could not get in if not a T
- @Nullable
public <T extends B> T getInstance(Class<T> type) {
- return (T) delegate.get(checkNotNull(type));
+ return (T) delegate.get(type);
}
/**
* Guaranteed to throw an exception and leave the map unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public <T extends B> T putInstance(Class<T> type, T value) {
throw new UnsupportedOperationException();
diff --git a/guava/src/com/google/common/collect/ImmutableCollection.java b/guava/src/com/google/common/collect/ImmutableCollection.java
index 2aeca97..5fca2aa 100644
--- a/guava/src/com/google/common/collect/ImmutableCollection.java
+++ b/guava/src/com/google/common/collect/ImmutableCollection.java
@@ -17,7 +17,6 @@
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.VisibleForTesting;
import java.io.Serializable;
import java.util.Collection;
@@ -86,9 +85,7 @@ public abstract class ImmutableCollection<E>
* Guaranteed to throw an exception and leave the collection unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final boolean add(E e) {
throw new UnsupportedOperationException();
@@ -98,9 +95,7 @@ public abstract class ImmutableCollection<E>
* Guaranteed to throw an exception and leave the collection unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final boolean remove(Object object) {
throw new UnsupportedOperationException();
@@ -110,9 +105,7 @@ public abstract class ImmutableCollection<E>
* Guaranteed to throw an exception and leave the collection unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final boolean addAll(Collection<? extends E> newElements) {
throw new UnsupportedOperationException();
@@ -122,9 +115,7 @@ public abstract class ImmutableCollection<E>
* Guaranteed to throw an exception and leave the collection unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final boolean removeAll(Collection<?> oldElements) {
throw new UnsupportedOperationException();
@@ -134,9 +125,7 @@ public abstract class ImmutableCollection<E>
* Guaranteed to throw an exception and leave the collection unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final boolean retainAll(Collection<?> elementsToKeep) {
throw new UnsupportedOperationException();
@@ -146,9 +135,7 @@ public abstract class ImmutableCollection<E>
* Guaranteed to throw an exception and leave the collection unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final void clear() {
throw new UnsupportedOperationException();
@@ -177,7 +164,7 @@ public abstract class ImmutableCollection<E>
case 1:
return ImmutableList.of(iterator().next());
default:
- return new RegularImmutableAsList<E>(this, toArray());
+ return new ImmutableAsList<E>(toArray(), this);
}
}
@@ -199,7 +186,7 @@ public abstract class ImmutableCollection<E>
}
@Override public UnmodifiableIterator<Object> iterator() {
- return Iterators.EMPTY_LIST_ITERATOR;
+ return Iterators.EMPTY_ITERATOR;
}
private static final Object[] EMPTY_ARRAY = new Object[0];
@@ -285,24 +272,6 @@ public abstract class ImmutableCollection<E>
* @since 10.0
*/
public abstract static class Builder<E> {
- static final int DEFAULT_INITIAL_CAPACITY = 4;
-
- @VisibleForTesting
- static int expandedCapacity(int oldCapacity, int minCapacity) {
- if (minCapacity < 0) {
- throw new AssertionError("cannot store more than MAX_VALUE elements");
- }
- // careful of overflow!
- int newCapacity = oldCapacity + (oldCapacity >> 1) + 1;
- if (newCapacity < minCapacity) {
- newCapacity = Integer.highestOneBit(minCapacity - 1) << 1;
- }
- if (newCapacity < 0) {
- newCapacity = Integer.MAX_VALUE;
- // guaranteed to be >= newCapacity
- }
- return newCapacity;
- }
Builder() {
}
diff --git a/guava/src/com/google/common/collect/ImmutableEnumMap.java b/guava/src/com/google/common/collect/ImmutableEnumMap.java
deleted file mode 100644
index 6738685..0000000
--- a/guava/src/com/google/common/collect/ImmutableEnumMap.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.io.Serializable;
-import java.util.EnumMap;
-import java.util.Iterator;
-
-import javax.annotation.Nullable;
-
-/**
- * Implementation of {@link ImmutableMap} backed by a non-empty {@link
- * java.util.EnumMap}.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible(serializable = true, emulated = true)
-@SuppressWarnings("serial") // we're overriding default serialization
-final class ImmutableEnumMap<K extends Enum<K>, V> extends ImmutableMap<K, V> {
- static <K extends Enum<K>, V> ImmutableMap<K, V> asImmutable(EnumMap<K, V> map) {
- switch (map.size()) {
- case 0:
- return ImmutableMap.of();
- case 1: {
- Entry<K, V> entry = Iterables.getOnlyElement(map.entrySet());
- return ImmutableMap.of(entry.getKey(), entry.getValue());
- }
- default:
- return new ImmutableEnumMap<K, V>(map);
- }
- }
-
- private transient final EnumMap<K, V> delegate;
-
- private ImmutableEnumMap(EnumMap<K, V> delegate) {
- this.delegate = delegate;
- checkArgument(!delegate.isEmpty());
- }
-
- @Override
- ImmutableSet<K> createKeySet() {
- return new ImmutableSet<K>() {
-
- @Override
- public boolean contains(Object object) {
- return delegate.containsKey(object);
- }
-
- @Override
- public int size() {
- return ImmutableEnumMap.this.size();
- }
-
- @Override
- public UnmodifiableIterator<K> iterator() {
- return Iterators.unmodifiableIterator(delegate.keySet().iterator());
- }
-
- @Override
- boolean isPartialView() {
- return true;
- }
- };
- }
-
- @Override
- public int size() {
- return delegate.size();
- }
-
- @Override
- public boolean containsKey(@Nullable Object key) {
- return delegate.containsKey(key);
- }
-
- @Override
- public V get(Object key) {
- return delegate.get(key);
- }
-
- @Override
- ImmutableSet<Entry<K, V>> createEntrySet() {
- return new ImmutableMapEntrySet<K, V>() {
-
- @Override
- ImmutableMap<K, V> map() {
- return ImmutableEnumMap.this;
- }
-
- @Override
- public UnmodifiableIterator<Entry<K, V>> iterator() {
- return new UnmodifiableIterator<Entry<K, V>>() {
- private final Iterator<Entry<K, V>> backingIterator = delegate.entrySet().iterator();
-
- @Override
- public boolean hasNext() {
- return backingIterator.hasNext();
- }
-
- @Override
- public Entry<K, V> next() {
- Entry<K, V> entry = backingIterator.next();
- return Maps.immutableEntry(entry.getKey(), entry.getValue());
- }
- };
- }
- };
- }
-
- @Override
- boolean isPartialView() {
- return false;
- }
-
- // All callers of the constructor are restricted to <K extends Enum<K>>.
- @Override Object writeReplace() {
- return new EnumSerializedForm<K, V>(delegate);
- }
-
- /*
- * This class is used to serialize ImmutableEnumSet instances.
- */
- private static class EnumSerializedForm<K extends Enum<K>, V>
- implements Serializable {
- final EnumMap<K, V> delegate;
- EnumSerializedForm(EnumMap<K, V> delegate) {
- this.delegate = delegate;
- }
- Object readResolve() {
- return new ImmutableEnumMap<K, V>(delegate);
- }
- private static final long serialVersionUID = 0;
- }
-}
diff --git a/guava/src/com/google/common/collect/ImmutableEnumSet.java b/guava/src/com/google/common/collect/ImmutableEnumSet.java
index d187b5c..ac6dd0e 100644
--- a/guava/src/com/google/common/collect/ImmutableEnumSet.java
+++ b/guava/src/com/google/common/collect/ImmutableEnumSet.java
@@ -31,17 +31,6 @@ import java.util.EnumSet;
@GwtCompatible(serializable = true, emulated = true)
@SuppressWarnings("serial") // we're overriding default serialization
final class ImmutableEnumSet<E extends Enum<E>> extends ImmutableSet<E> {
- static <E extends Enum<E>> ImmutableSet<E> asImmutable(EnumSet<E> set) {
- switch (set.size()) {
- case 0:
- return ImmutableSet.of();
- case 1:
- return ImmutableSet.of(Iterables.getOnlyElement(set));
- default:
- return new ImmutableEnumSet<E>(set);
- }
- }
-
/*
* Notes on EnumSet and <E extends Enum<E>>:
*
@@ -52,7 +41,7 @@ final class ImmutableEnumSet<E extends Enum<E>> extends ImmutableSet<E> {
*/
private final transient EnumSet<E> delegate;
- private ImmutableEnumSet(EnumSet<E> delegate) {
+ ImmutableEnumSet(EnumSet<E> delegate) {
this.delegate = delegate;
}
diff --git a/guava/src/com/google/common/collect/ImmutableList.java b/guava/src/com/google/common/collect/ImmutableList.java
index a01f4bc..cd8235a 100644
--- a/guava/src/com/google/common/collect/ImmutableList.java
+++ b/guava/src/com/google/common/collect/ImmutableList.java
@@ -16,17 +16,15 @@
package com.google.common.collect;
-import static com.google.common.base.Preconditions.checkElementIndex;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkPositionIndex;
-import static com.google.common.base.Preconditions.checkPositionIndexes;
-import static com.google.common.collect.ObjectArrays.checkElementNotNull;
import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Preconditions;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
@@ -50,10 +48,6 @@ import javax.annotation.Nullable;
* it has no public or protected constructors. Thus, instances of this type are
* guaranteed to be immutable.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
- * immutable collections</a>.
- *
* @see ImmutableMap
* @see ImmutableSet
* @author Kevin Bourrillion
@@ -259,19 +253,7 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
* @throws NullPointerException if any of {@code elements} is null
*/
public static <E> ImmutableList<E> copyOf(Iterator<? extends E> elements) {
- // We special-case for 0 or 1 elements, but going further is madness.
- if (!elements.hasNext()) {
- return of();
- }
- E first = elements.next();
- if (!elements.hasNext()) {
- return of(first);
- } else {
- return new ImmutableList.Builder<E>()
- .add(first)
- .addAll(elements)
- .build();
- }
+ return copyFromCollection(Lists.newArrayList(elements));
}
/**
@@ -291,12 +273,9 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
}
}
- /**
- * Views the array as an immutable list. The array must have only non-null {@code E} elements.
- *
- * <p>The array must be internally created.
- */
- static <E> ImmutableList<E> asImmutableList(Object[] elements) {
+ private static <E> ImmutableList<E> copyFromCollection(
+ Collection<? extends E> collection) {
+ Object[] elements = collection.toArray();
switch (elements.length) {
case 0:
return of();
@@ -305,23 +284,29 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
ImmutableList<E> list = new SingletonImmutableList<E>((E) elements[0]);
return list;
default:
+ // safe to use the array without copying it
+ // as specified by Collection.toArray().
return construct(elements);
}
}
-
- private static <E> ImmutableList<E> copyFromCollection(
- Collection<? extends E> collection) {
- return asImmutableList(collection.toArray());
- }
-
+
/** {@code elements} has to be internally created array. */
private static <E> ImmutableList<E> construct(Object... elements) {
for (int i = 0; i < elements.length; i++) {
- ObjectArrays.checkElementNotNull(elements[i], i);
+ checkElementNotNull(elements[i], i);
}
return new RegularImmutableList<E>(elements);
}
+ // We do this instead of Preconditions.checkNotNull to save boxing and array
+ // creation cost.
+ private static Object checkElementNotNull(Object element, int index) {
+ if (element == null) {
+ throw new NullPointerException("at index " + index);
+ }
+ return element;
+ }
+
ImmutableList() {}
// This declaration is needed to make List.iterator() and
@@ -334,29 +319,15 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
return listIterator(0);
}
- @Override public UnmodifiableListIterator<E> listIterator(int index) {
- return new AbstractIndexedListIterator<E>(size(), index) {
- @Override
- protected E get(int index) {
- return ImmutableList.this.get(index);
- }
- };
- }
+ @Override public abstract UnmodifiableListIterator<E> listIterator(int index);
- @Override
- public int indexOf(@Nullable Object object) {
- return (object == null) ? -1 : Lists.indexOfImpl(this, object);
- }
+ // Mark these two methods with @Nullable
@Override
- public int lastIndexOf(@Nullable Object object) {
- return (object == null) ? -1 : Lists.lastIndexOfImpl(this, object);
- }
+ public abstract int indexOf(@Nullable Object object);
@Override
- public boolean contains(@Nullable Object object) {
- return indexOf(object) >= 0;
- }
+ public abstract int lastIndexOf(@Nullable Object object);
// constrain the return type to ImmutableList<E>
@@ -367,67 +338,13 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
* returned.)
*/
@Override
- public ImmutableList<E> subList(int fromIndex, int toIndex) {
- checkPositionIndexes(fromIndex, toIndex, size());
- int length = toIndex - fromIndex;
- switch (length) {
- case 0:
- return of();
- case 1:
- return of(get(fromIndex));
- default:
- return subListUnchecked(fromIndex, toIndex);
- }
- }
-
- /**
- * Called by the default implementation of {@link #subList} when {@code
- * toIndex - fromIndex > 1}, after index validation has already been
- * performed.
- */
- ImmutableList<E> subListUnchecked(int fromIndex, int toIndex) {
- return new SubList(fromIndex, toIndex - fromIndex);
- }
-
- class SubList extends ImmutableList<E> {
- transient final int offset;
- transient final int length;
-
- SubList(int offset, int length) {
- this.offset = offset;
- this.length = length;
- }
-
- @Override
- public int size() {
- return length;
- }
-
- @Override
- public E get(int index) {
- checkElementIndex(index, length);
- return ImmutableList.this.get(index + offset);
- }
-
- @Override
- public ImmutableList<E> subList(int fromIndex, int toIndex) {
- checkPositionIndexes(fromIndex, toIndex, length);
- return ImmutableList.this.subList(fromIndex + offset, toIndex + offset);
- }
-
- @Override
- boolean isPartialView() {
- return true;
- }
- }
+ public abstract ImmutableList<E> subList(int fromIndex, int toIndex);
/**
* Guaranteed to throw an exception and leave the list unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final boolean addAll(int index, Collection<? extends E> newElements) {
throw new UnsupportedOperationException();
@@ -437,9 +354,7 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
* Guaranteed to throw an exception and leave the list unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final E set(int index, E element) {
throw new UnsupportedOperationException();
@@ -449,9 +364,7 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
* Guaranteed to throw an exception and leave the list unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final void add(int index, E element) {
throw new UnsupportedOperationException();
@@ -461,9 +374,7 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
* Guaranteed to throw an exception and leave the list unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final E remove(int index) {
throw new UnsupportedOperationException();
@@ -491,8 +402,8 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
}
private static class ReverseImmutableList<E> extends ImmutableList<E> {
- private final transient ImmutableList<E> forwardList;
- private final transient int size;
+ private transient final ImmutableList<E> forwardList;
+ private transient final int size;
ReverseImmutableList(ImmutableList<E> backingList) {
this.forwardList = backingList;
@@ -530,18 +441,18 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
}
@Override public ImmutableList<E> subList(int fromIndex, int toIndex) {
- checkPositionIndexes(fromIndex, toIndex, size);
+ Preconditions.checkPositionIndexes(fromIndex, toIndex, size);
return forwardList.subList(
reversePosition(toIndex), reversePosition(fromIndex)).reverse();
}
@Override public E get(int index) {
- checkElementIndex(index, size);
+ Preconditions.checkElementIndex(index, size);
return forwardList.get(reverseIndex(index));
}
@Override public UnmodifiableListIterator<E> listIterator(int index) {
- checkPositionIndex(index, size);
+ Preconditions.checkPositionIndex(index, size);
final UnmodifiableListIterator<E> forward =
forwardList.listIterator(reversePosition(index));
return new UnmodifiableListIterator<E>() {
@@ -583,7 +494,7 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
return forwardList.isPartialView();
}
}
-
+
@Override public boolean equals(Object obj) {
return Lists.equalsImpl(this, obj);
}
@@ -641,34 +552,13 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
* @since 2.0 (imported from Google Collections Library)
*/
public static final class Builder<E> extends ImmutableCollection.Builder<E> {
- private Object[] contents;
- private int size;
+ private final ArrayList<E> contents = Lists.newArrayList();
/**
* Creates a new builder. The returned builder is equivalent to the builder
* generated by {@link ImmutableList#builder}.
*/
- public Builder() {
- this(DEFAULT_INITIAL_CAPACITY);
- }
-
- // TODO(user): consider exposing this
- Builder(int capacity) {
- this.contents = new Object[capacity];
- this.size = 0;
- }
-
- /**
- * Expand the absolute capacity of the builder so it can accept at least
- * the specified number of elements without being resized.
- */
- Builder<E> ensureCapacity(int minCapacity) {
- if (contents.length < minCapacity) {
- this.contents = ObjectArrays.arraysCopyOf(
- this.contents, expandedCapacity(contents.length, minCapacity));
- }
- return this;
- }
+ public Builder() {}
/**
* Adds {@code element} to the {@code ImmutableList}.
@@ -678,9 +568,7 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
* @throws NullPointerException if {@code element} is null
*/
@Override public Builder<E> add(E element) {
- checkNotNull(element);
- ensureCapacity(size + 1);
- contents[size++] = element;
+ contents.add(checkNotNull(element));
return this;
}
@@ -695,7 +583,7 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
@Override public Builder<E> addAll(Iterable<? extends E> elements) {
if (elements instanceof Collection) {
Collection<?> collection = (Collection<?>) elements;
- ensureCapacity(size + collection.size());
+ contents.ensureCapacity(contents.size() + collection.size());
}
super.addAll(elements);
return this;
@@ -710,12 +598,8 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
* null element
*/
@Override public Builder<E> add(E... elements) {
- for (int i = 0; i < elements.length; i++) {
- checkElementNotNull(elements[i], i);
- }
- ensureCapacity(size + elements.length);
- System.arraycopy(elements, 0, contents, size, elements.length);
- size += elements.length;
+ contents.ensureCapacity(contents.size() + elements.length);
+ super.add(elements);
return this;
}
@@ -737,21 +621,7 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
* the {@code Builder}.
*/
@Override public ImmutableList<E> build() {
- switch (size) {
- case 0:
- return of();
- case 1:
- @SuppressWarnings("unchecked") // guaranteed to be an E
- E singleElement = (E) contents[0];
- return of(singleElement);
- default:
- if (size == contents.length) {
- // no need to copy; any further add operations on the builder will copy the buffer
- return new RegularImmutableList<E>(contents);
- } else {
- return new RegularImmutableList<E>(ObjectArrays.arraysCopyOf(contents, size));
- }
- }
+ return copyOf(contents);
}
}
}
diff --git a/guava/src/com/google/common/collect/ImmutableListMultimap.java b/guava/src/com/google/common/collect/ImmutableListMultimap.java
index 865fa6f..3071075 100644
--- a/guava/src/com/google/common/collect/ImmutableListMultimap.java
+++ b/guava/src/com/google/common/collect/ImmutableListMultimap.java
@@ -16,6 +16,7 @@
package com.google.common.collect;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
@@ -45,10 +46,6 @@ import javax.annotation.Nullable;
* it has no public or protected constructors. Thus, instances of this class
* are guaranteed to be immutable.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
- * immutable collections</a>.
- *
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
*/
@@ -200,7 +197,7 @@ public class ImmutableListMultimap<K, V>
*
* @since 8.0
*/
- @Override
+ @Beta @Override
public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
super.orderKeysBy(keyComparator);
return this;
@@ -211,7 +208,7 @@ public class ImmutableListMultimap<K, V>
*
* @since 8.0
*/
- @Override
+ @Beta @Override
public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
super.orderValuesBy(valueComparator);
return this;
@@ -291,14 +288,13 @@ public class ImmutableListMultimap<K, V>
/**
* {@inheritDoc}
*
- * <p>Because an inverse of a list multimap can contain multiple pairs with
- * the same key and value, this method returns an {@code
- * ImmutableListMultimap} rather than the {@code ImmutableMultimap} specified
- * in the {@code ImmutableMultimap} class.
+ * <p>Because an inverse of a list multimap can contain multiple pairs with the same key and
+ * value, this method returns an {@code ImmutableListMultimap} rather than the
+ * {@code ImmutableMultimap} specified in the {@code ImmutableMultimap} class.
*
- * @since 11.0
+ * @since 11
*/
- @Override
+ @Beta
public ImmutableListMultimap<V, K> inverse() {
ImmutableListMultimap<V, K> result = inverse;
return (result == null) ? (inverse = invert()) : result;
@@ -318,9 +314,8 @@ public class ImmutableListMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated @Override public ImmutableList<V> removeAll(Object key) {
+ @Override public ImmutableList<V> removeAll(Object key) {
throw new UnsupportedOperationException();
}
@@ -328,9 +323,8 @@ public class ImmutableListMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated @Override public ImmutableList<V> replaceValues(
+ @Override public ImmutableList<V> replaceValues(
K key, Iterable<? extends V> values) {
throw new UnsupportedOperationException();
}
diff --git a/guava/src/com/google/common/collect/ImmutableMap.java b/guava/src/com/google/common/collect/ImmutableMap.java
index c1d7933..0a2ef77 100644
--- a/guava/src/com/google/common/collect/ImmutableMap.java
+++ b/guava/src/com/google/common/collect/ImmutableMap.java
@@ -19,15 +19,12 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.getOnlyElement;
-import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.EnumMap;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -50,10 +47,6 @@ import javax.annotation.Nullable;
* having your element type cache its own hash codes, and by making use of the
* cached values to short-circuit a slow {@code equals} algorithm.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
- * immutable collections</a>.
- *
* @author Jesse Wilson
* @author Kevin Bourrillion
* @since 2.0 (imported from Google Collections Library)
@@ -66,8 +59,10 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
* {@link Collections#emptyMap}, and is preferable mainly for consistency
* and maintainability of your code.
*/
+ // Casting to any type is safe because the set will never hold any elements.
+ @SuppressWarnings("unchecked")
public static <K, V> ImmutableMap<K, V> of() {
- return ImmutableBiMap.of();
+ return (ImmutableMap<K, V>) EmptyImmutableMap.INSTANCE;
}
/**
@@ -77,7 +72,8 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
* maintainability of your code.
*/
public static <K, V> ImmutableMap<K, V> of(K k1, V v1) {
- return ImmutableBiMap.of(k1, v1);
+ return new SingletonImmutableMap<K, V>(
+ checkNotNull(k1), checkNotNull(v1));
}
/**
@@ -140,9 +136,9 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
* throw {@link UnsupportedOperationException}.
*/
static <K, V> Entry<K, V> entryOf(K key, V value) {
- checkNotNull(key, "null key in entry: null=%s", value);
- checkNotNull(value, "null value in entry: %s=null", key);
- return Maps.immutableEntry(key, value);
+ return Maps.immutableEntry(
+ checkNotNull(key, "null key"),
+ checkNotNull(value, "null value"));
}
/**
@@ -193,7 +189,7 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
K key = entry.getKey();
V value = entry.getValue();
- if (entry instanceof ImmutableEntry) {
+ if (entry instanceof ImmutableEntry<?, ?>) {
checkNotNull(key);
checkNotNull(value);
@SuppressWarnings("unchecked") // all supported methods are covariant
@@ -242,7 +238,7 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
case 0:
return of();
case 1:
- return new SingletonImmutableBiMap<K, V>(getOnlyElement(entries));
+ return new SingletonImmutableMap<K, V>(getOnlyElement(entries));
default:
Entry<?, ?>[] entryArray
= entries.toArray(new Entry<?, ?>[entries.size()]);
@@ -274,16 +270,6 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
if (!kvMap.isPartialView()) {
return kvMap;
}
- } else if (map instanceof EnumMap) {
- EnumMap<?, ?> enumMap = (EnumMap<?, ?>) map;
- for (Map.Entry<?, ?> entry : enumMap.entrySet()) {
- checkNotNull(entry.getKey());
- checkNotNull(entry.getValue());
- }
- @SuppressWarnings("unchecked")
- // immutable collections are safe for covariant casts
- ImmutableMap<K, V> result = ImmutableEnumMap.asImmutable(new EnumMap(enumMap));
- return result;
}
@SuppressWarnings("unchecked") // we won't write to this array
@@ -292,7 +278,7 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
case 0:
return of();
case 1:
- return new SingletonImmutableBiMap<K, V>(entryOf(
+ return new SingletonImmutableMap<K, V>(entryOf(
entries[0].getKey(), entries[0].getValue()));
default:
for (int i = 0; i < entries.length; i++) {
@@ -310,9 +296,7 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
* Guaranteed to throw an exception and leave the map unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final V put(K k, V v) {
throw new UnsupportedOperationException();
@@ -322,9 +306,7 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
* Guaranteed to throw an exception and leave the map unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final V remove(Object o) {
throw new UnsupportedOperationException();
@@ -334,9 +316,7 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
* Guaranteed to throw an exception and leave the map unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final void putAll(Map<? extends K, ? extends V> map) {
throw new UnsupportedOperationException();
@@ -346,9 +326,7 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
* Guaranteed to throw an exception and leave the map unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final void clear() {
throw new UnsupportedOperationException();
@@ -364,132 +342,44 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
return get(key) != null;
}
+ // Overriding to mark it Nullable
@Override
- public boolean containsValue(@Nullable Object value) {
- return value != null && Maps.containsValueImpl(this, value);
- }
+ public abstract boolean containsValue(@Nullable Object value);
// Overriding to mark it Nullable
@Override
public abstract V get(@Nullable Object key);
- private transient ImmutableSet<Entry<K, V>> entrySet;
-
/**
* Returns an immutable set of the mappings in this map. The entries are in
* the same order as the parameters used to build this map.
*/
@Override
- public ImmutableSet<Entry<K, V>> entrySet() {
- ImmutableSet<Entry<K, V>> result = entrySet;
- return (result == null) ? entrySet = createEntrySet() : result;
- }
-
- abstract ImmutableSet<Entry<K, V>> createEntrySet();
-
- private transient ImmutableSet<K> keySet;
+ public abstract ImmutableSet<Entry<K, V>> entrySet();
/**
* Returns an immutable set of the keys in this map. These keys are in
* the same order as the parameters used to build this map.
*/
@Override
- public ImmutableSet<K> keySet() {
- ImmutableSet<K> result = keySet;
- return (result == null) ? keySet = createKeySet() : result;
- }
-
- ImmutableSet<K> createKeySet() {
- return new ImmutableMapKeySet<K, V>(this);
- }
-
- private transient ImmutableCollection<V> values;
+ public abstract ImmutableSet<K> keySet();
/**
* Returns an immutable collection of the values in this map. The values are
* in the same order as the parameters used to build this map.
*/
@Override
- public ImmutableCollection<V> values() {
- ImmutableCollection<V> result = values;
- return (result == null) ? values = new ImmutableMapValues<K, V>(this) : result;
- }
-
- // cached so that this.multimapView().inverse() only computes inverse once
- private transient ImmutableSetMultimap<K, V> multimapView;
-
- /**
- * Returns a multimap view of the map.
- *
- * @since 14.0
- */
- @Beta
- public ImmutableSetMultimap<K, V> asMultimap() {
- ImmutableSetMultimap<K, V> result = multimapView;
- return (result == null) ? (multimapView = createMultimapView()) : result;
- }
-
- private ImmutableSetMultimap<K, V> createMultimapView() {
- ImmutableMap<K, ImmutableSet<V>> map = viewMapValuesAsSingletonSets();
- return new ImmutableSetMultimap<K, V>(map, map.size(), null);
- }
-
- private ImmutableMap<K, ImmutableSet<V>> viewMapValuesAsSingletonSets() {
- class MapViewOfValuesAsSingletonSets extends ImmutableMap<K, ImmutableSet<V>> {
- @Override public int size() {
- return ImmutableMap.this.size();
- }
-
- @Override public boolean containsKey(@Nullable Object key) {
- return ImmutableMap.this.containsKey(key);
- }
-
- @Override public ImmutableSet<V> get(@Nullable Object key) {
- V outerValue = ImmutableMap.this.get(key);
- return (outerValue == null) ? null : ImmutableSet.of(outerValue);
- }
-
- @Override boolean isPartialView() {
- return false;
- }
-
- @Override ImmutableSet<Entry<K, ImmutableSet<V>>> createEntrySet() {
- return new ImmutableMapEntrySet<K, ImmutableSet<V>>() {
- @Override ImmutableMap<K, ImmutableSet<V>> map() {
- return MapViewOfValuesAsSingletonSets.this;
- }
-
- @Override
- public UnmodifiableIterator<Entry<K, ImmutableSet<V>>> iterator() {
- final Iterator<Entry<K,V>> backingIterator = ImmutableMap.this
- .entrySet().iterator();
- return new UnmodifiableIterator<Entry<K, ImmutableSet<V>>>() {
- @Override public boolean hasNext() {
- return backingIterator.hasNext();
- }
-
- @Override public Entry<K, ImmutableSet<V>> next() {
- final Entry<K, V> backingEntry = backingIterator.next();
- return new AbstractMapEntry<K, ImmutableSet<V>>() {
- @Override public K getKey() {
- return backingEntry.getKey();
- }
-
- @Override public ImmutableSet<V> getValue() {
- return ImmutableSet.of(backingEntry.getValue());
- }
- };
- }
- };
- }
- };
- }
- }
- return new MapViewOfValuesAsSingletonSets();
- }
+ public abstract ImmutableCollection<V> values();
@Override public boolean equals(@Nullable Object object) {
- return Maps.equalsImpl(this, object);
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof Map) {
+ Map<?, ?> that = (Map<?, ?>) object;
+ return this.entrySet().equals(that.entrySet());
+ }
+ return false;
}
abstract boolean isPartialView();
diff --git a/guava/src/com/google/common/collect/ImmutableMapEntrySet.java b/guava/src/com/google/common/collect/ImmutableMapEntrySet.java
deleted file mode 100644
index a6aa6e0..0000000
--- a/guava/src/com/google/common/collect/ImmutableMapEntrySet.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
-
-import java.io.Serializable;
-import java.util.Map.Entry;
-
-import javax.annotation.Nullable;
-
-/**
- * {@code entrySet()} implementation for {@link ImmutableMap}.
- *
- * @author Jesse Wilson
- * @author Kevin Bourrillion
- */
-@GwtCompatible(emulated = true)
-abstract class ImmutableMapEntrySet<K, V> extends ImmutableSet<Entry<K, V>> {
- ImmutableMapEntrySet() {}
-
- abstract ImmutableMap<K, V> map();
-
- @Override
- public int size() {
- return map().size();
- }
-
- @Override
- public boolean contains(@Nullable Object object) {
- if (object instanceof Entry) {
- Entry<?, ?> entry = (Entry<?, ?>) object;
- V value = map().get(entry.getKey());
- return value != null && value.equals(entry.getValue());
- }
- return false;
- }
-
- @Override
- boolean isPartialView() {
- return map().isPartialView();
- }
-
- @GwtIncompatible("serialization")
- @Override
- Object writeReplace() {
- return new EntrySetSerializedForm<K, V>(map());
- }
-
- @GwtIncompatible("serialization")
- private static class EntrySetSerializedForm<K, V> implements Serializable {
- final ImmutableMap<K, V> map;
- EntrySetSerializedForm(ImmutableMap<K, V> map) {
- this.map = map;
- }
- Object readResolve() {
- return map.entrySet();
- }
- private static final long serialVersionUID = 0;
- }
-}
diff --git a/guava/src/com/google/common/collect/ImmutableMapKeySet.java b/guava/src/com/google/common/collect/ImmutableMapKeySet.java
deleted file mode 100644
index fbb59d8..0000000
--- a/guava/src/com/google/common/collect/ImmutableMapKeySet.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
-
-import java.io.Serializable;
-import java.util.Map.Entry;
-
-import javax.annotation.Nullable;
-
-/**
- * {@code keySet()} implementation for {@link ImmutableMap}.
- *
- * @author Jesse Wilson
- * @author Kevin Bourrillion
- */
-@GwtCompatible(emulated = true)
-final class ImmutableMapKeySet<K, V> extends ImmutableSet<K> {
- private final ImmutableMap<K, V> map;
-
- ImmutableMapKeySet(ImmutableMap<K, V> map) {
- this.map = map;
- }
-
- @Override
- public int size() {
- return map.size();
- }
-
- @Override
- public UnmodifiableIterator<K> iterator() {
- return asList().iterator();
- }
-
- @Override
- public boolean contains(@Nullable Object object) {
- return map.containsKey(object);
- }
-
- @Override
- ImmutableList<K> createAsList() {
- final ImmutableList<Entry<K, V>> entryList = map.entrySet().asList();
- return new ImmutableAsList<K>() {
-
- @Override
- public K get(int index) {
- return entryList.get(index).getKey();
- }
-
- @Override
- ImmutableCollection<K> delegateCollection() {
- return ImmutableMapKeySet.this;
- }
-
- };
- }
-
- @Override
- boolean isPartialView() {
- return true;
- }
-
- @GwtIncompatible("serialization")
- @Override Object writeReplace() {
- return new KeySetSerializedForm<K>(map);
- }
-
- @GwtIncompatible("serialization")
- private static class KeySetSerializedForm<K> implements Serializable {
- final ImmutableMap<K, ?> map;
- KeySetSerializedForm(ImmutableMap<K, ?> map) {
- this.map = map;
- }
- Object readResolve() {
- return map.keySet();
- }
- private static final long serialVersionUID = 0;
- }
-}
diff --git a/guava/src/com/google/common/collect/ImmutableMapValues.java b/guava/src/com/google/common/collect/ImmutableMapValues.java
deleted file mode 100644
index 6ec7464..0000000
--- a/guava/src/com/google/common/collect/ImmutableMapValues.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
-
-import java.io.Serializable;
-import java.util.Map.Entry;
-
-/**
- * {@code values()} implementation for {@link ImmutableMap}.
- *
- * @author Jesse Wilson
- * @author Kevin Bourrillion
- */
-@GwtCompatible(emulated = true)
-final class ImmutableMapValues<K, V> extends ImmutableCollection<V> {
- private final ImmutableMap<K, V> map;
-
- ImmutableMapValues(ImmutableMap<K, V> map) {
- this.map = map;
- }
-
- @Override
- public int size() {
- return map.size();
- }
-
- @Override
- public UnmodifiableIterator<V> iterator() {
- return Maps.valueIterator(map.entrySet().iterator());
- }
-
- @Override
- public boolean contains(Object object) {
- return map.containsValue(object);
- }
-
- @Override
- boolean isPartialView() {
- return true;
- }
-
- @Override
- ImmutableList<V> createAsList() {
- final ImmutableList<Entry<K, V>> entryList = map.entrySet().asList();
- return new ImmutableAsList<V>() {
- @Override
- public V get(int index) {
- return entryList.get(index).getValue();
- }
-
- @Override
- ImmutableCollection<V> delegateCollection() {
- return ImmutableMapValues.this;
- }
- };
- }
-
- @GwtIncompatible("serialization")
- @Override Object writeReplace() {
- return new SerializedForm<V>(map);
- }
-
- @GwtIncompatible("serialization")
- private static class SerializedForm<V> implements Serializable {
- final ImmutableMap<?, V> map;
- SerializedForm(ImmutableMap<?, V> map) {
- this.map = map;
- }
- Object readResolve() {
- return map.values();
- }
- private static final long serialVersionUID = 0;
- }
-}
diff --git a/guava/src/com/google/common/collect/ImmutableMultimap.java b/guava/src/com/google/common/collect/ImmutableMultimap.java
index e29dbc1..13e213e 100644
--- a/guava/src/com/google/common/collect/ImmutableMultimap.java
+++ b/guava/src/com/google/common/collect/ImmutableMultimap.java
@@ -18,9 +18,9 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
-import com.google.common.base.Function;
import java.io.Serializable;
import java.util.Arrays;
@@ -30,9 +30,8 @@ import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
import java.util.Map.Entry;
-import java.util.Set;
+import java.util.TreeMap;
import javax.annotation.Nullable;
@@ -54,16 +53,13 @@ import javax.annotation.Nullable;
* <p>In addition to methods defined by {@link Multimap}, an {@link #inverse}
* method is also supported.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
- * immutable collections</a>.
- *
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
*/
@GwtCompatible(emulated = true)
-public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
- implements Serializable {
+// TODO(user): If BiMultimap graduates from labs, this class should implement it.
+public abstract class ImmutableMultimap<K, V>
+ implements Multimap<K, V>, Serializable {
/** Returns an empty multimap. */
public static <K, V> ImmutableMultimap<K, V> of() {
@@ -123,7 +119,7 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* value orderings, allows duplicate values, and performs better than
* {@link LinkedListMultimap}.
*/
- private static class BuilderMultimap<K, V> extends AbstractMapBasedMultimap<K, V> {
+ private static class BuilderMultimap<K, V> extends AbstractMultimap<K, V> {
BuilderMultimap() {
super(new LinkedHashMap<K, Collection<V>>());
}
@@ -134,6 +130,23 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
}
/**
+ * Multimap for {@link ImmutableMultimap.Builder} that sorts key and allows
+ * duplicate values,
+ */
+ private static class SortedKeyBuilderMultimap<K, V>
+ extends AbstractMultimap<K, V> {
+ SortedKeyBuilderMultimap(
+ Comparator<? super K> keyComparator, Multimap<K, V> multimap) {
+ super(new TreeMap<K, Collection<V>>(keyComparator));
+ putAll(multimap);
+ }
+ @Override Collection<V> createCollection() {
+ return Lists.newArrayList();
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
* A builder for creating immutable multimap instances, especially
* {@code public static final} multimaps ("constant multimaps"). Example:
* <pre> {@code
@@ -153,7 +166,6 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
*/
public static class Builder<K, V> {
Multimap<K, V> builderMultimap = new BuilderMultimap<K, V>();
- Comparator<? super K> keyComparator;
Comparator<? super V> valueComparator;
/**
@@ -228,8 +240,10 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
*
* @since 8.0
*/
+ @Beta
public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
- this.keyComparator = checkNotNull(keyComparator);
+ builderMultimap = new SortedKeyBuilderMultimap<K, V>(
+ checkNotNull(keyComparator), builderMultimap);
return this;
}
@@ -238,6 +252,7 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
*
* @since 8.0
*/
+ @Beta
public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
this.valueComparator = checkNotNull(valueComparator);
return this;
@@ -253,23 +268,6 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
Collections.sort(list, valueComparator);
}
}
- if (keyComparator != null) {
- Multimap<K, V> sortedCopy = new BuilderMultimap<K, V>();
- List<Map.Entry<K, Collection<V>>> entries = Lists.newArrayList(
- builderMultimap.asMap().entrySet());
- Collections.sort(
- entries,
- Ordering.from(keyComparator).onResultOf(new Function<Entry<K, Collection<V>>, K>() {
- @Override
- public K apply(Entry<K, Collection<V>> entry) {
- return entry.getKey();
- }
- }));
- for (Map.Entry<K, Collection<V>> entry : entries) {
- sortedCopy.putAll(entry.getKey(), entry.getValue());
- }
- builderMultimap = sortedCopy;
- }
return copyOf(builderMultimap);
}
}
@@ -327,9 +325,7 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public ImmutableCollection<V> removeAll(Object key) {
throw new UnsupportedOperationException();
@@ -339,9 +335,7 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public ImmutableCollection<V> replaceValues(K key,
Iterable<? extends V> values) {
@@ -352,9 +346,7 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public void clear() {
throw new UnsupportedOperationException();
@@ -374,17 +366,16 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* key-value mapping in the original, the result will have a mapping with
* key and value reversed.
*
- * @since 11.0
+ * @since 11
*/
+ @Beta
public abstract ImmutableMultimap<V, K> inverse();
/**
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public boolean put(K key, V value) {
throw new UnsupportedOperationException();
@@ -394,9 +385,7 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public boolean putAll(K key, Iterable<? extends V> values) {
throw new UnsupportedOperationException();
@@ -406,9 +395,7 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
throw new UnsupportedOperationException();
@@ -418,30 +405,65 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public boolean remove(Object key, Object value) {
throw new UnsupportedOperationException();
}
- boolean isPartialView() {
+ boolean isPartialView(){
return map.isPartialView();
}
// accessors
@Override
+ public boolean containsEntry(@Nullable Object key, @Nullable Object value) {
+ Collection<V> values = map.get(key);
+ return values != null && values.contains(value);
+ }
+
+ @Override
public boolean containsKey(@Nullable Object key) {
return map.containsKey(key);
}
@Override
+ public boolean containsValue(@Nullable Object value) {
+ for (Collection<V> valueCollection : map.values()) {
+ if (valueCollection.contains(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
+ @Override
public int size() {
return size;
}
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof Multimap) {
+ Multimap<?, ?> that = (Multimap<?, ?>) object;
+ return this.map.equals(that.asMap());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return map.hashCode();
+ }
+
+ @Override public String toString() {
+ return map.toString();
+ }
+
// views
/**
@@ -463,11 +485,8 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
public ImmutableMap<K, Collection<V>> asMap() {
return (ImmutableMap) map;
}
-
- @Override
- Map<K, Collection<V>> createAsMap() {
- throw new AssertionError("should never be called");
- }
+
+ private transient ImmutableCollection<Entry<K, V>> entries;
/**
* Returns an immutable collection of all key-value pairs in the multimap. Its
@@ -476,12 +495,9 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
*/
@Override
public ImmutableCollection<Entry<K, V>> entries() {
- return (ImmutableCollection<Entry<K, V>>) super.entries();
- }
-
- @Override
- ImmutableCollection<Entry<K, V>> createEntries() {
- return new EntryCollection<K, V>(this);
+ ImmutableCollection<Entry<K, V>> result = entries;
+ return (result == null)
+ ? (entries = new EntryCollection<K, V>(this)) : result;
}
private static class EntryCollection<K, V>
@@ -493,7 +509,30 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
}
@Override public UnmodifiableIterator<Entry<K, V>> iterator() {
- return multimap.entryIterator();
+ final Iterator<? extends Entry<K, ? extends ImmutableCollection<V>>>
+ mapIterator = this.multimap.map.entrySet().iterator();
+
+ return new UnmodifiableIterator<Entry<K, V>>() {
+ K key;
+ Iterator<V> valueIterator;
+
+ @Override
+ public boolean hasNext() {
+ return (key != null && valueIterator.hasNext())
+ || mapIterator.hasNext();
+ }
+
+ @Override
+ public Entry<K, V> next() {
+ if (key == null || !valueIterator.hasNext()) {
+ Entry<K, ? extends ImmutableCollection<V>> entry
+ = mapIterator.next();
+ key = entry.getKey();
+ valueIterator = entry.getValue().iterator();
+ }
+ return Maps.immutableEntry(key, valueIterator.next());
+ }
+ };
}
@Override boolean isPartialView() {
@@ -515,34 +554,8 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
private static final long serialVersionUID = 0;
}
-
- @Override
- UnmodifiableIterator<Entry<K, V>> entryIterator() {
- final Iterator<? extends Entry<K, ? extends ImmutableCollection<V>>>
- mapIterator = map.entrySet().iterator();
-
- return new UnmodifiableIterator<Entry<K, V>>() {
- K key;
- Iterator<V> valueIterator;
-
- @Override
- public boolean hasNext() {
- return (key != null && valueIterator.hasNext())
- || mapIterator.hasNext();
- }
- @Override
- public Entry<K, V> next() {
- if (key == null || !valueIterator.hasNext()) {
- Entry<K, ? extends ImmutableCollection<V>> entry
- = mapIterator.next();
- key = entry.getKey();
- valueIterator = entry.getValue().iterator();
- }
- return Maps.immutableEntry(key, valueIterator.next());
- }
- };
- }
+ private transient ImmutableMultiset<K> keys;
/**
* Returns a collection, which may contain duplicates, of all keys. The number
@@ -552,78 +565,21 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
*/
@Override
public ImmutableMultiset<K> keys() {
- return (ImmutableMultiset<K>) super.keys();
+ ImmutableMultiset<K> result = keys;
+ return (result == null) ? (keys = createKeys()) : result;
}
- @Override
- ImmutableMultiset<K> createKeys() {
- return new Keys();
- }
-
- @SuppressWarnings("serial") // Uses writeReplace, not default serialization
- class Keys extends ImmutableMultiset<K> {
- @Override
- public boolean contains(@Nullable Object object) {
- return containsKey(object);
- }
-
- @Override
- public int count(@Nullable Object element) {
- Collection<V> values = map.get(element);
- return (values == null) ? 0 : values.size();
- }
-
- @Override
- public Set<K> elementSet() {
- return keySet();
- }
-
- @Override
- public int size() {
- return ImmutableMultimap.this.size();
- }
-
- @Override
- ImmutableSet<Entry<K>> createEntrySet() {
- return new KeysEntrySet();
- }
-
- private class KeysEntrySet extends ImmutableMultiset<K>.EntrySet {
- @Override
- public int size() {
- return keySet().size();
- }
-
- @Override
- public UnmodifiableIterator<Entry<K>> iterator() {
- return asList().iterator();
- }
-
- @Override
- ImmutableList<Entry<K>> createAsList() {
- final ImmutableList<? extends Map.Entry<K, ? extends Collection<V>>> mapEntries =
- map.entrySet().asList();
- return new ImmutableAsList<Entry<K>>() {
- @Override
- public Entry<K> get(int index) {
- Map.Entry<K, ? extends Collection<V>> entry = mapEntries.get(index);
- return Multisets.immutableEntry(entry.getKey(), entry.getValue().size());
- }
-
- @Override
- ImmutableCollection<Entry<K>> delegateCollection() {
- return KeysEntrySet.this;
- }
- };
- }
- }
-
- @Override
- boolean isPartialView() {
- return true;
+ private ImmutableMultiset<K> createKeys() {
+ ImmutableMultiset.Builder<K> builder = ImmutableMultiset.builder();
+ for (Entry<K, ? extends ImmutableCollection<V>> entry
+ : map.entrySet()) {
+ builder.addCopies(entry.getKey(), entry.getValue().size());
}
+ return builder.build();
}
+ private transient ImmutableCollection<V> values;
+
/**
* Returns an immutable collection of the values in this multimap. Its
* iterator traverses the values for the first key, the values for the second
@@ -631,12 +587,8 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
*/
@Override
public ImmutableCollection<V> values() {
- return (ImmutableCollection<V>) super.values();
- }
-
- @Override
- ImmutableCollection<V> createValues() {
- return new Values<V>(this);
+ ImmutableCollection<V> result = values;
+ return (result == null) ? (values = new Values<V>(this)) : result;
}
private static class Values<V> extends ImmutableCollection<V> {
@@ -647,7 +599,18 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
}
@Override public UnmodifiableIterator<V> iterator() {
- return Maps.valueIterator(multimap.entries().iterator());
+ final Iterator<? extends Entry<?, V>> entryIterator
+ = multimap.entries().iterator();
+ return new UnmodifiableIterator<V>() {
+ @Override
+ public boolean hasNext() {
+ return entryIterator.hasNext();
+ }
+ @Override
+ public V next() {
+ return entryIterator.next().getValue();
+ }
+ };
}
@Override
diff --git a/guava/src/com/google/common/collect/ImmutableMultiset.java b/guava/src/com/google/common/collect/ImmutableMultiset.java
index 6680a2d..bd07423 100644
--- a/guava/src/com/google/common/collect/ImmutableMultiset.java
+++ b/guava/src/com/google/common/collect/ImmutableMultiset.java
@@ -19,6 +19,7 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
+import com.google.common.collect.Multiset.Entry;
import com.google.common.primitives.Ints;
import java.io.Serializable;
@@ -28,6 +29,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import javax.annotation.Nullable;
@@ -39,10 +41,6 @@ import javax.annotation.Nullable;
* multiset contains multiple instances of an element, those instances are
* consecutive in the iteration order.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
- * immutable collections</a>.
- *
* @author Jared Levy
* @author Louis Wasserman
* @since 2.0 (imported from Google Collections Library)
@@ -136,6 +134,23 @@ public abstract class ImmutableMultiset<E> extends ImmutableCollection<E>
* Returns an immutable multiset containing the given elements.
*
* <p>The multiset is ordered by the first occurrence of each element. For
+ * example, {@code ImmutableMultiset.of(2, 3, 1, 3)} yields a multiset with
+ * elements in the order {@code 2, 3, 3, 1}.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ * @deprecated use {@link #copyOf(Object[])}. <b>This method is scheduled for
+ * deletion in January 2012.</b>
+ * @since 2.0 (changed from varargs in 6.0)
+ */
+ @Deprecated
+ public static <E> ImmutableMultiset<E> of(E[] elements) {
+ return copyOf(Arrays.asList(elements));
+ }
+
+ /**
+ * Returns an immutable multiset containing the given elements.
+ *
+ * <p>The multiset is ordered by the first occurrence of each element. For
* example, {@code ImmutableMultiset.copyOf([2, 3, 1, 3])} yields a multiset
* with elements in the order {@code 2, 3, 3, 1}.
*
@@ -206,8 +221,7 @@ public abstract class ImmutableMultiset<E> extends ImmutableCollection<E>
if (size == 0) {
return of();
}
- return new RegularImmutableMultiset<E>(
- builder.build(), Ints.saturatedCast(size));
+ return new RegularImmutableMultiset<E>(builder.build(), Ints.saturatedCast(size));
}
/**
@@ -230,7 +244,8 @@ public abstract class ImmutableMultiset<E> extends ImmutableCollection<E>
ImmutableMultiset() {}
@Override public UnmodifiableIterator<E> iterator() {
- final Iterator<Entry<E>> entryIterator = entrySet().iterator();
+ final Iterator<Entry<E>> entryIterator = entryIterator();
+
return new UnmodifiableIterator<E>() {
int remaining;
E element;
@@ -267,9 +282,7 @@ public abstract class ImmutableMultiset<E> extends ImmutableCollection<E>
* Guaranteed to throw an exception and leave the collection unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final int add(E element, int occurrences) {
throw new UnsupportedOperationException();
@@ -279,9 +292,7 @@ public abstract class ImmutableMultiset<E> extends ImmutableCollection<E>
* Guaranteed to throw an exception and leave the collection unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final int remove(Object element, int occurrences) {
throw new UnsupportedOperationException();
@@ -291,9 +302,7 @@ public abstract class ImmutableMultiset<E> extends ImmutableCollection<E>
* Guaranteed to throw an exception and leave the collection unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final int setCount(E element, int count) {
throw new UnsupportedOperationException();
@@ -303,9 +312,7 @@ public abstract class ImmutableMultiset<E> extends ImmutableCollection<E>
* Guaranteed to throw an exception and leave the collection unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final boolean setCount(E element, int oldCount, int newCount) {
throw new UnsupportedOperationException();
@@ -341,17 +348,39 @@ public abstract class ImmutableMultiset<E> extends ImmutableCollection<E>
private transient ImmutableSet<Entry<E>> entrySet;
@Override
- public ImmutableSet<Entry<E>> entrySet() {
+ public Set<Entry<E>> entrySet() {
ImmutableSet<Entry<E>> es = entrySet;
return (es == null) ? (entrySet = createEntrySet()) : es;
}
- abstract ImmutableSet<Entry<E>> createEntrySet();
+ abstract UnmodifiableIterator<Entry<E>> entryIterator();
+
+ abstract int distinctElements();
+
+ ImmutableSet<Entry<E>> createEntrySet() {
+ return new EntrySet<E>(this);
+ }
+
+ static class EntrySet<E> extends ImmutableSet<Entry<E>> {
+ transient final ImmutableMultiset<E> multiset;
+
+ public EntrySet(ImmutableMultiset<E> multiset) {
+ this.multiset = multiset;
+ }
+
+ @Override
+ public UnmodifiableIterator<Entry<E>> iterator() {
+ return multiset.entryIterator();
+ }
+
+ @Override
+ public int size() {
+ return multiset.distinctElements();
+ }
- abstract class EntrySet extends ImmutableSet<Entry<E>> {
@Override
boolean isPartialView() {
- return ImmutableMultiset.this.isPartialView();
+ return multiset.isPartialView();
}
@Override
@@ -361,7 +390,7 @@ public abstract class ImmutableMultiset<E> extends ImmutableCollection<E>
if (entry.getCount() <= 0) {
return false;
}
- int count = count(entry.getElement());
+ int count = multiset.count(entry.getElement());
return count == entry.getCount();
}
return false;
@@ -401,29 +430,28 @@ public abstract class ImmutableMultiset<E> extends ImmutableCollection<E>
@Override
public int hashCode() {
- return ImmutableMultiset.this.hashCode();
+ return multiset.hashCode();
}
// We can't label this with @Override, because it doesn't override anything
// in the GWT emulated version.
- // TODO(cpovirk): try making all copies of this method @GwtIncompatible instead
Object writeReplace() {
- return new EntrySetSerializedForm<E>(ImmutableMultiset.this);
+ return new EntrySetSerializedForm<E>(multiset);
}
- private static final long serialVersionUID = 0;
- }
+ static class EntrySetSerializedForm<E> implements Serializable {
+ final ImmutableMultiset<E> multiset;
- static class EntrySetSerializedForm<E> implements Serializable {
- final ImmutableMultiset<E> multiset;
+ EntrySetSerializedForm(ImmutableMultiset<E> multiset) {
+ this.multiset = multiset;
+ }
- EntrySetSerializedForm(ImmutableMultiset<E> multiset) {
- this.multiset = multiset;
+ Object readResolve() {
+ return multiset.entrySet();
+ }
}
- Object readResolve() {
- return multiset.entrySet();
- }
+ private static final long serialVersionUID = 0;
}
private static class SerializedForm implements Serializable {
diff --git a/guava/src/com/google/common/collect/ImmutableRangeMap.java b/guava/src/com/google/common/collect/ImmutableRangeMap.java
deleted file mode 100644
index 9545f1d..0000000
--- a/guava/src/com/google/common/collect/ImmutableRangeMap.java
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkElementIndex;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtIncompatible;
-import com.google.common.collect.SortedLists.KeyAbsentBehavior;
-import com.google.common.collect.SortedLists.KeyPresentBehavior;
-
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.NoSuchElementException;
-
-import javax.annotation.Nullable;
-
-/**
- * An immutable implementation of {@code RangeMap}, supporting all query operations efficiently.
- *
- * <p>Like all {@code RangeMap} implementations, this supports neither null keys nor null values.
- *
- * @author Louis Wasserman
- * @since 14.0
- */
-@Beta
-@GwtIncompatible("NavigableMap")
-public class ImmutableRangeMap<K extends Comparable<?>, V> implements RangeMap<K, V> {
-
- @SuppressWarnings("unchecked")
- private static final ImmutableRangeMap EMPTY =
- new ImmutableRangeMap(ImmutableList.of(), ImmutableList.of());
-
- /**
- * Returns an empty immutable range map.
- */
- @SuppressWarnings("unchecked")
- public static final <K extends Comparable<?>, V> ImmutableRangeMap<K, V> of() {
- return EMPTY;
- }
-
- /**
- * Returns an immutable range map mapping a single range to a single value.
- */
- public static final <K extends Comparable<?>, V> ImmutableRangeMap<K, V> of(
- Range<K> range, V value) {
- return new ImmutableRangeMap<K, V>(ImmutableList.of(range), ImmutableList.of(value));
- }
-
- @SuppressWarnings("unchecked")
- public static final <K extends Comparable<?>, V> ImmutableRangeMap<K, V> copyOf(
- RangeMap<K, ? extends V> rangeMap) {
- if (rangeMap instanceof ImmutableRangeMap) {
- return (ImmutableRangeMap<K, V>) rangeMap;
- }
- Map<Range<K>, ? extends V> map = rangeMap.asMapOfRanges();
- ImmutableList.Builder<Range<K>> rangesBuilder = new ImmutableList.Builder<Range<K>>(map.size());
- ImmutableList.Builder<V> valuesBuilder = new ImmutableList.Builder<V>(map.size());
- for (Entry<Range<K>, ? extends V> entry : map.entrySet()) {
- rangesBuilder.add(entry.getKey());
- valuesBuilder.add(entry.getValue());
- }
- return new ImmutableRangeMap<K, V>(rangesBuilder.build(), valuesBuilder.build());
- }
-
- /**
- * Returns a new builder for an immutable range map.
- */
- public static <K extends Comparable<?>, V> Builder<K, V> builder() {
- return new Builder<K, V>();
- }
-
- /**
- * A builder for immutable range maps. Overlapping ranges are prohibited.
- */
- public static final class Builder<K extends Comparable<?>, V> {
- private final RangeSet<K> keyRanges;
- private final RangeMap<K, V> rangeMap;
-
- public Builder() {
- this.keyRanges = TreeRangeSet.create();
- this.rangeMap = TreeRangeMap.create();
- }
-
- /**
- * Associates the specified range with the specified value.
- *
- * @throws IllegalArgumentException if {@code range} overlaps with any other ranges inserted
- * into this builder, or if {@code range} is empty
- */
- public Builder<K, V> put(Range<K> range, V value) {
- checkNotNull(range);
- checkNotNull(value);
- checkArgument(!range.isEmpty(), "Range must not be empty, but was %s", range);
- if (!keyRanges.complement().encloses(range)) {
- // it's an error case; we can afford an expensive lookup
- for (Entry<Range<K>, V> entry : rangeMap.asMapOfRanges().entrySet()) {
- Range<K> key = entry.getKey();
- if (key.isConnected(range) && !key.intersection(range).isEmpty()) {
- throw new IllegalArgumentException(
- "Overlapping ranges: range " + range + " overlaps with entry " + entry);
- }
- }
- }
- keyRanges.add(range);
- rangeMap.put(range, value);
- return this;
- }
-
- /**
- * Copies all associations from the specified range map into this builder.
- *
- * @throws IllegalArgumentException if any of the ranges in {@code rangeMap} overlap with ranges
- * already in this builder
- */
- public Builder<K, V> putAll(RangeMap<K, ? extends V> rangeMap) {
- for (Entry<Range<K>, ? extends V> entry : rangeMap.asMapOfRanges().entrySet()) {
- put(entry.getKey(), entry.getValue());
- }
- return this;
- }
-
- /**
- * Returns an {@code ImmutableRangeMap} containing the associations previously added to this
- * builder.
- */
- public ImmutableRangeMap<K, V> build() {
- Map<Range<K>, V> map = rangeMap.asMapOfRanges();
- ImmutableList.Builder<Range<K>> rangesBuilder =
- new ImmutableList.Builder<Range<K>>(map.size());
- ImmutableList.Builder<V> valuesBuilder = new ImmutableList.Builder<V>(map.size());
- for (Entry<Range<K>, V> entry : map.entrySet()) {
- rangesBuilder.add(entry.getKey());
- valuesBuilder.add(entry.getValue());
- }
- return new ImmutableRangeMap<K, V>(rangesBuilder.build(), valuesBuilder.build());
- }
- }
-
- private final ImmutableList<Range<K>> ranges;
- private final ImmutableList<V> values;
-
- ImmutableRangeMap(ImmutableList<Range<K>> ranges, ImmutableList<V> values) {
- this.ranges = ranges;
- this.values = values;
- }
-
- @Override
- @Nullable
- public V get(K key) {
- int index = SortedLists.binarySearch(ranges, Range.<K>lowerBoundFn(),
- Cut.belowValue(key), KeyPresentBehavior.ANY_PRESENT, KeyAbsentBehavior.NEXT_LOWER);
- if (index == -1) {
- return null;
- } else {
- Range<K> range = ranges.get(index);
- return range.contains(key) ? values.get(index) : null;
- }
- }
-
- @Override
- @Nullable
- public Map.Entry<Range<K>, V> getEntry(K key) {
- int index = SortedLists.binarySearch(ranges, Range.<K>lowerBoundFn(),
- Cut.belowValue(key), KeyPresentBehavior.ANY_PRESENT, KeyAbsentBehavior.NEXT_LOWER);
- if (index == -1) {
- return null;
- } else {
- Range<K> range = ranges.get(index);
- return range.contains(key) ? Maps.immutableEntry(range, values.get(index)) : null;
- }
- }
-
- @Override
- public Range<K> span() {
- if (ranges.isEmpty()) {
- throw new NoSuchElementException();
- }
- Range<K> firstRange = ranges.get(0);
- Range<K> lastRange = ranges.get(ranges.size() - 1);
- return Range.create(firstRange.lowerBound, lastRange.upperBound);
- }
-
- @Override
- public void put(Range<K> range, V value) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void putAll(RangeMap<K, V> rangeMap) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void clear() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void remove(Range<K> range) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public ImmutableMap<Range<K>, V> asMapOfRanges() {
- if (ranges.isEmpty()) {
- return ImmutableMap.of();
- }
- RegularImmutableSortedSet<Range<K>> rangeSet =
- new RegularImmutableSortedSet<Range<K>>(ranges, Range.RANGE_LEX_ORDERING);
- return new RegularImmutableSortedMap<Range<K>, V>(rangeSet, values);
- }
-
- @Override
- public ImmutableRangeMap<K, V> subRangeMap(final Range<K> range) {
- if (checkNotNull(range).isEmpty()) {
- return ImmutableRangeMap.of();
- } else if (ranges.isEmpty() || range.encloses(span())) {
- return this;
- }
- int lowerIndex = SortedLists.binarySearch(
- ranges, Range.<K>upperBoundFn(), range.lowerBound,
- KeyPresentBehavior.FIRST_AFTER, KeyAbsentBehavior.NEXT_HIGHER);
- int upperIndex = SortedLists.binarySearch(ranges,
- Range.<K>lowerBoundFn(), range.upperBound,
- KeyPresentBehavior.ANY_PRESENT, KeyAbsentBehavior.NEXT_HIGHER);
- if (lowerIndex >= upperIndex) {
- return ImmutableRangeMap.of();
- }
- final int off = lowerIndex;
- final int len = upperIndex - lowerIndex;
- ImmutableList<Range<K>> subRanges = new ImmutableList<Range<K>>() {
- @Override
- public int size() {
- return len;
- }
-
- @Override
- public Range<K> get(int index) {
- checkElementIndex(index, len);
- if (index == 0 || index == len - 1) {
- return ranges.get(index + off).intersection(range);
- } else {
- return ranges.get(index + off);
- }
- }
-
- @Override
- boolean isPartialView() {
- return true;
- }
- };
- final ImmutableRangeMap<K, V> outer = this;
- return new ImmutableRangeMap<K, V>(
- subRanges, values.subList(lowerIndex, upperIndex)) {
- @Override
- public ImmutableRangeMap<K, V> subRangeMap(Range<K> subRange) {
- if (range.isConnected(subRange)) {
- return outer.subRangeMap(subRange.intersection(range));
- } else {
- return ImmutableRangeMap.of();
- }
- }
- };
- }
-
- @Override
- public int hashCode() {
- return asMapOfRanges().hashCode();
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (o instanceof RangeMap) {
- RangeMap<?, ?> rangeMap = (RangeMap<?, ?>) o;
- return asMapOfRanges().equals(rangeMap.asMapOfRanges());
- }
- return false;
- }
-
- @Override
- public String toString() {
- return asMapOfRanges().toString();
- }
-}
diff --git a/guava/src/com/google/common/collect/ImmutableRangeSet.java b/guava/src/com/google/common/collect/ImmutableRangeSet.java
deleted file mode 100644
index bd21bbe..0000000
--- a/guava/src/com/google/common/collect/ImmutableRangeSet.java
+++ /dev/null
@@ -1,608 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkElementIndex;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.SortedLists.KeyAbsentBehavior.NEXT_LOWER;
-import static com.google.common.collect.SortedLists.KeyPresentBehavior.ANY_PRESENT;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtIncompatible;
-import com.google.common.collect.SortedLists.KeyAbsentBehavior;
-import com.google.common.collect.SortedLists.KeyPresentBehavior;
-import com.google.common.primitives.Ints;
-
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-/**
- * An efficient immutable implementation of a {@link RangeSet}.
- *
- * @author Louis Wasserman
- * @since 14.0
- */
-@Beta
-public final class ImmutableRangeSet<C extends Comparable> extends AbstractRangeSet<C>
- implements Serializable {
-
- @SuppressWarnings("unchecked")
- private static final ImmutableRangeSet EMPTY = new ImmutableRangeSet(ImmutableList.of());
-
- @SuppressWarnings("unchecked")
- private static final ImmutableRangeSet ALL = new ImmutableRangeSet(ImmutableList.of(Range.all()));
-
- /**
- * Returns an empty immutable range set.
- */
- @SuppressWarnings("unchecked")
- public static <C extends Comparable> ImmutableRangeSet<C> of() {
- return EMPTY;
- }
-
- /**
- * Returns an immutable range set containing the single range {@link Range#all()}.
- */
- @SuppressWarnings("unchecked")
- static <C extends Comparable> ImmutableRangeSet<C> all() {
- return ALL;
- }
-
- /**
- * Returns an immutable range set containing the specified single range. If {@link Range#isEmpty()
- * range.isEmpty()}, this is equivalent to {@link ImmutableRangeSet#of()}.
- */
- public static <C extends Comparable> ImmutableRangeSet<C> of(Range<C> range) {
- checkNotNull(range);
- if (range.isEmpty()) {
- return of();
- } else if (range.equals(Range.all())) {
- return all();
- } else {
- return new ImmutableRangeSet<C>(ImmutableList.of(range));
- }
- }
-
- /**
- * Returns an immutable copy of the specified {@code RangeSet}.
- */
- public static <C extends Comparable> ImmutableRangeSet<C> copyOf(RangeSet<C> rangeSet) {
- checkNotNull(rangeSet);
- if (rangeSet.isEmpty()) {
- return of();
- } else if (rangeSet.encloses(Range.<C>all())) {
- return all();
- }
-
- if (rangeSet instanceof ImmutableRangeSet) {
- ImmutableRangeSet<C> immutableRangeSet = (ImmutableRangeSet<C>) rangeSet;
- if (!immutableRangeSet.isPartialView()) {
- return immutableRangeSet;
- }
- }
- return new ImmutableRangeSet<C>(ImmutableList.copyOf(rangeSet.asRanges()));
- }
-
- ImmutableRangeSet(ImmutableList<Range<C>> ranges) {
- this.ranges = ranges;
- }
-
- private ImmutableRangeSet(ImmutableList<Range<C>> ranges, ImmutableRangeSet<C> complement) {
- this.ranges = ranges;
- this.complement = complement;
- }
-
- private transient final ImmutableList<Range<C>> ranges;
-
- @Override
- public boolean encloses(Range<C> otherRange) {
- int index = SortedLists.binarySearch(ranges,
- Range.<C>lowerBoundFn(),
- otherRange.lowerBound,
- Ordering.natural(),
- ANY_PRESENT,
- NEXT_LOWER);
- return index != -1 && ranges.get(index).encloses(otherRange);
- }
-
- @Override
- public Range<C> rangeContaining(C value) {
- int index = SortedLists.binarySearch(ranges,
- Range.<C>lowerBoundFn(),
- Cut.belowValue(value),
- Ordering.natural(),
- ANY_PRESENT,
- NEXT_LOWER);
- if (index != -1) {
- Range<C> range = ranges.get(index);
- return range.contains(value) ? range : null;
- }
- return null;
- }
-
- @Override
- public Range<C> span() {
- if (ranges.isEmpty()) {
- throw new NoSuchElementException();
- }
- return Range.create(
- ranges.get(0).lowerBound,
- ranges.get(ranges.size() - 1).upperBound);
- }
-
- @Override
- public boolean isEmpty() {
- return ranges.isEmpty();
- }
-
- @Override
- public void add(Range<C> range) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void addAll(RangeSet<C> other) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void remove(Range<C> range) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void removeAll(RangeSet<C> other) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public ImmutableSet<Range<C>> asRanges() {
- if (ranges.isEmpty()) {
- return ImmutableSet.of();
- }
- return new RegularImmutableSortedSet<Range<C>>(ranges, Range.RANGE_LEX_ORDERING);
- }
-
- private transient ImmutableRangeSet<C> complement;
-
- private final class ComplementRanges extends ImmutableList<Range<C>> {
- // True if the "positive" range set is empty or bounded below.
- private final boolean positiveBoundedBelow;
-
- // True if the "positive" range set is empty or bounded above.
- private final boolean positiveBoundedAbove;
-
- private final int size;
-
- ComplementRanges() {
- this.positiveBoundedBelow = ranges.get(0).hasLowerBound();
- this.positiveBoundedAbove = Iterables.getLast(ranges).hasUpperBound();
-
- int size = ranges.size() - 1;
- if (positiveBoundedBelow) {
- size++;
- }
- if (positiveBoundedAbove) {
- size++;
- }
- this.size = size;
- }
-
- @Override
- public int size() {
- return size;
- }
-
- @Override
- public Range<C> get(int index) {
- checkElementIndex(index, size);
-
- Cut<C> lowerBound;
- if (positiveBoundedBelow) {
- lowerBound = (index == 0) ? Cut.<C>belowAll() : ranges.get(index - 1).upperBound;
- } else {
- lowerBound = ranges.get(index).upperBound;
- }
-
- Cut<C> upperBound;
- if (positiveBoundedAbove && index == size - 1) {
- upperBound = Cut.<C>aboveAll();
- } else {
- upperBound = ranges.get(index + (positiveBoundedBelow ? 0 : 1)).lowerBound;
- }
-
- return Range.create(lowerBound, upperBound);
- }
-
- @Override
- boolean isPartialView() {
- return true;
- }
- }
-
- @Override
- public ImmutableRangeSet<C> complement() {
- ImmutableRangeSet<C> result = complement;
- if (result != null) {
- return result;
- } else if (ranges.isEmpty()) {
- return complement = all();
- } else if (ranges.size() == 1 && ranges.get(0).equals(Range.all())) {
- return complement = of();
- } else {
- ImmutableList<Range<C>> complementRanges = new ComplementRanges();
- result = complement = new ImmutableRangeSet<C>(complementRanges, this);
- }
- return result;
- }
-
- /**
- * Returns a list containing the nonempty intersections of {@code range}
- * with the ranges in this range set.
- */
- private ImmutableList<Range<C>> intersectRanges(final Range<C> range) {
- if (ranges.isEmpty() || range.isEmpty()) {
- return ImmutableList.of();
- } else if (range.encloses(span())) {
- return ranges;
- }
-
- final int fromIndex;
- if (range.hasLowerBound()) {
- fromIndex = SortedLists.binarySearch(
- ranges, Range.<C>upperBoundFn(), range.lowerBound, KeyPresentBehavior.FIRST_AFTER,
- KeyAbsentBehavior.NEXT_HIGHER);
- } else {
- fromIndex = 0;
- }
-
- int toIndex;
- if (range.hasUpperBound()) {
- toIndex = SortedLists.binarySearch(
- ranges, Range.<C>lowerBoundFn(), range.upperBound, KeyPresentBehavior.FIRST_PRESENT,
- KeyAbsentBehavior.NEXT_HIGHER);
- } else {
- toIndex = ranges.size();
- }
- final int length = toIndex - fromIndex;
- if (length == 0) {
- return ImmutableList.of();
- } else {
- return new ImmutableList<Range<C>>() {
- @Override
- public int size() {
- return length;
- }
-
- @Override
- public Range<C> get(int index) {
- checkElementIndex(index, length);
- if (index == 0 || index == length - 1) {
- return ranges.get(index + fromIndex).intersection(range);
- } else {
- return ranges.get(index + fromIndex);
- }
- }
-
- @Override
- boolean isPartialView() {
- return true;
- }
- };
- }
- }
-
- /**
- * Returns a view of the intersection of this range set with the given range.
- */
- @Override
- public ImmutableRangeSet<C> subRangeSet(Range<C> range) {
- if (!isEmpty()) {
- Range<C> span = span();
- if (range.encloses(span)) {
- return this;
- } else if (range.isConnected(span)) {
- return new ImmutableRangeSet<C>(intersectRanges(range));
- }
- }
- return of();
- }
-
- /**
- * Returns an {@link ImmutableSortedSet} containing the same values in the given domain
- * {@linkplain RangeSet#contains contained} by this range set.
- *
- * <p><b>Note:</b> {@code a.asSet(d).equals(b.asSet(d))} does not imply {@code a.equals(b)}! For
- * example, {@code a} and {@code b} could be {@code [2..4]} and {@code (1..5)}, or the empty
- * ranges {@code [3..3)} and {@code [4..4)}.
- *
- * <p><b>Warning:</b> Be extremely careful what you do with the {@code asSet} view of a large
- * range set (such as {@code ImmutableRangeSet.of(Range.greaterThan(0))}). Certain operations on
- * such a set can be performed efficiently, but others (such as {@link Set#hashCode} or
- * {@link Collections#frequency}) can cause major performance problems.
- *
- * <p>The returned set's {@link Object#toString} method returns a short-hand form of the set's
- * contents, such as {@code "[1..100]}"}.
- *
- * @throws IllegalArgumentException if neither this range nor the domain has a lower bound, or if
- * neither has an upper bound
- */
- public ImmutableSortedSet<C> asSet(DiscreteDomain<C> domain) {
- checkNotNull(domain);
- if (isEmpty()) {
- return ImmutableSortedSet.of();
- }
- Range<C> span = span().canonical(domain);
- if (!span.hasLowerBound()) {
- // according to the spec of canonical, neither this ImmutableRangeSet nor
- // the range have a lower bound
- throw new IllegalArgumentException(
- "Neither the DiscreteDomain nor this range set are bounded below");
- } else if (!span.hasUpperBound()) {
- try {
- domain.maxValue();
- } catch (NoSuchElementException e) {
- throw new IllegalArgumentException(
- "Neither the DiscreteDomain nor this range set are bounded above");
- }
- }
-
- return new AsSet(domain);
- }
-
- private final class AsSet extends ImmutableSortedSet<C> {
- private final DiscreteDomain<C> domain;
-
- AsSet(DiscreteDomain<C> domain) {
- super(Ordering.natural());
- this.domain = domain;
- }
-
- private transient Integer size;
-
- @Override
- public int size() {
- // racy single-check idiom
- Integer result = size;
- if (result == null) {
- long total = 0;
- for (Range<C> range : ranges) {
- total += range.asSet(domain).size();
- if (total >= Integer.MAX_VALUE) {
- break;
- }
- }
- result = size = Ints.saturatedCast(total);
- }
- return result.intValue();
- }
-
- @Override
- public UnmodifiableIterator<C> iterator() {
- return new AbstractIterator<C>() {
- final Iterator<Range<C>> rangeItr = ranges.iterator();
- Iterator<C> elemItr = Iterators.emptyIterator();
-
- @Override
- protected C computeNext() {
- while (!elemItr.hasNext()) {
- if (rangeItr.hasNext()) {
- elemItr = rangeItr.next().asSet(domain).iterator();
- } else {
- return endOfData();
- }
- }
- return elemItr.next();
- }
- };
- }
-
- @Override
- @GwtIncompatible("NavigableSet")
- public UnmodifiableIterator<C> descendingIterator() {
- return new AbstractIterator<C>() {
- final Iterator<Range<C>> rangeItr = ranges.reverse().iterator();
- Iterator<C> elemItr = Iterators.emptyIterator();
-
- @Override
- protected C computeNext() {
- while (!elemItr.hasNext()) {
- if (rangeItr.hasNext()) {
- elemItr = rangeItr.next().asSet(domain).descendingIterator();
- } else {
- return endOfData();
- }
- }
- return elemItr.next();
- }
- };
- }
-
- ImmutableSortedSet<C> subSet(Range<C> range) {
- return subRangeSet(range).asSet(domain);
- }
-
- @Override
- ImmutableSortedSet<C> headSetImpl(C toElement, boolean inclusive) {
- return subSet(Range.upTo(toElement, BoundType.forBoolean(inclusive)));
- }
-
- @Override
- ImmutableSortedSet<C> subSetImpl(
- C fromElement, boolean fromInclusive, C toElement, boolean toInclusive) {
- if (!fromInclusive && !toInclusive && Range.compareOrThrow(fromElement, toElement) == 0) {
- return ImmutableSortedSet.of();
- }
- return subSet(Range.range(
- fromElement, BoundType.forBoolean(fromInclusive),
- toElement, BoundType.forBoolean(toInclusive)));
- }
-
- @Override
- ImmutableSortedSet<C> tailSetImpl(C fromElement, boolean inclusive) {
- return subSet(Range.downTo(fromElement, BoundType.forBoolean(inclusive)));
- }
-
- @Override
- public boolean contains(@Nullable Object o) {
- if (o == null) {
- return false;
- }
- try {
- @SuppressWarnings("unchecked") // we catch CCE's
- C c = (C) o;
- return ImmutableRangeSet.this.contains(c);
- } catch (ClassCastException e) {
- return false;
- }
- }
-
- @Override
- int indexOf(Object target) {
- if (contains(target)) {
- @SuppressWarnings("unchecked") // if it's contained, it's definitely a C
- C c = (C) target;
- long total = 0;
- for (Range<C> range : ranges) {
- if (range.contains(c)) {
- return Ints.saturatedCast(total + range.asSet(domain).indexOf(c));
- } else {
- total += range.asSet(domain).size();
- }
- }
- throw new AssertionError("impossible");
- }
- return -1;
- }
-
- @Override
- boolean isPartialView() {
- return ranges.isPartialView();
- }
-
- @Override
- public String toString() {
- return ranges.toString();
- }
-
- @Override
- Object writeReplace() {
- return new AsSetSerializedForm<C>(ranges, domain);
- }
- }
-
- private static class AsSetSerializedForm<C extends Comparable> implements Serializable {
- private final ImmutableList<Range<C>> ranges;
- private final DiscreteDomain<C> domain;
-
- AsSetSerializedForm(ImmutableList<Range<C>> ranges, DiscreteDomain<C> domain) {
- this.ranges = ranges;
- this.domain = domain;
- }
-
- Object readResolve() {
- return new ImmutableRangeSet<C>(ranges).asSet(domain);
- }
- }
-
- boolean isPartialView() {
- return ranges.isPartialView();
- }
-
- /**
- * Returns a new builder for an immutable range set.
- */
- public static <C extends Comparable<?>> Builder<C> builder() {
- return new Builder<C>();
- }
-
- /**
- * A builder for immutable range sets.
- */
- public static class Builder<C extends Comparable<?>> {
- private final RangeSet<C> rangeSet;
-
- public Builder() {
- this.rangeSet = TreeRangeSet.create();
- }
-
- /**
- * Add the specified range to this builder. Adjacent/abutting ranges are permitted, but
- * empty ranges, or ranges with nonempty overlap, are forbidden.
- *
- * @throws IllegalArgumentException if {@code range} is empty or has nonempty intersection with
- * any ranges already added to the builder
- */
- public Builder<C> add(Range<C> range) {
- if (range.isEmpty()) {
- throw new IllegalArgumentException("range must not be empty, but was " + range);
- } else if (!rangeSet.complement().encloses(range)) {
- for (Range<C> currentRange : rangeSet.asRanges()) {
- checkArgument(
- !currentRange.isConnected(range) || currentRange.intersection(range).isEmpty(),
- "Ranges may not overlap, but received %s and %s", currentRange, range);
- }
- throw new AssertionError("should have thrown an IAE above");
- }
- rangeSet.add(range);
- return this;
- }
-
- /**
- * Add all ranges from the specified range set to this builder. Duplicate or connected ranges
- * are permitted, and will be merged in the resulting immutable range set.
- */
- public Builder<C> addAll(RangeSet<C> ranges) {
- for (Range<C> range : ranges.asRanges()) {
- add(range);
- }
- return this;
- }
-
- /**
- * Returns an {@code ImmutableRangeSet} containing the ranges added to this builder.
- */
- public ImmutableRangeSet<C> build() {
- return copyOf(rangeSet);
- }
- }
-
- private static final class SerializedForm<C extends Comparable> implements Serializable {
- private final ImmutableList<Range<C>> ranges;
-
- SerializedForm(ImmutableList<Range<C>> ranges) {
- this.ranges = ranges;
- }
-
- Object readResolve() {
- if (ranges.isEmpty()) {
- return of();
- } else if (ranges.equals(ImmutableList.of(Range.all()))) {
- return all();
- } else {
- return new ImmutableRangeSet<C>(ranges);
- }
- }
- }
-
- Object writeReplace() {
- return new SerializedForm<C>(ranges);
- }
-}
diff --git a/guava/src/com/google/common/collect/ImmutableSet.java b/guava/src/com/google/common/collect/ImmutableSet.java
index b96829c..fb60ce6 100644
--- a/guava/src/com/google/common/collect/ImmutableSet.java
+++ b/guava/src/com/google/common/collect/ImmutableSet.java
@@ -20,14 +20,12 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.primitives.Ints;
import java.io.Serializable;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
@@ -59,10 +57,6 @@ import javax.annotation.Nullable;
* outside its package as it has no public or protected constructors. Thus,
* instances of this type are guaranteed to be immutable.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
- * immutable collections</a>.
- *
* @see ImmutableList
* @see ImmutableMap
* @author Kevin Bourrillion
@@ -102,7 +96,7 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
* @throws NullPointerException if any element is null
*/
public static <E> ImmutableSet<E> of(E e1, E e2) {
- return construct(2, e1, e2);
+ return construct(e1, e2);
}
/**
@@ -113,7 +107,7 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
* @throws NullPointerException if any element is null
*/
public static <E> ImmutableSet<E> of(E e1, E e2, E e3) {
- return construct(3, e1, e2, e3);
+ return construct(e1, e2, e3);
}
/**
@@ -124,7 +118,7 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
* @throws NullPointerException if any element is null
*/
public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4) {
- return construct(4, e1, e2, e3, e4);
+ return construct(e1, e2, e3, e4);
}
/**
@@ -135,7 +129,7 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
* @throws NullPointerException if any element is null
*/
public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5) {
- return construct(5, e1, e2, e3, e4, e5);
+ return construct(e1, e2, e3, e4, e5);
}
/**
@@ -156,72 +150,59 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
elements[3] = e4;
elements[4] = e5;
elements[5] = e6;
- System.arraycopy(others, 0, elements, paramCount, others.length);
- return construct(elements.length, elements);
+ for (int i = paramCount; i < elements.length; i++) {
+ elements[i] = others[i - paramCount];
+ }
+ return construct(elements);
}
- /**
- * Constructs an {@code ImmutableSet} from the first {@code n} elements of the specified array.
- * If {@code k} is the size of the returned {@code ImmutableSet}, then the unique elements of
- * {@code elements} will be in the first {@code k} positions, and {@code elements[i] == null} for
- * {@code k <= i < n}.
- *
- * <p>This may modify {@code elements}. Additionally, if {@code n == elements.length} and
- * {@code elements} contains no duplicates, {@code elements} may be used without copying in the
- * returned {@code ImmutableSet}, in which case it may no longer be modified.
- *
- * <p>{@code elements} may contain only values of type {@code E}.
- *
- * @throws NullPointerException if any of the first {@code n} elements of {@code elements} is
- * null
- */
- private static <E> ImmutableSet<E> construct(int n, Object... elements) {
- switch (n) {
- case 0:
- return of();
- case 1:
- @SuppressWarnings("unchecked") // safe; elements contains only E's
- E elem = (E) elements[0];
- return of(elem);
- default:
- // continue below to handle the general case
- }
- int tableSize = chooseTableSize(n);
+ /** {@code elements} has to be internally created array. */
+ private static <E> ImmutableSet<E> construct(Object... elements) {
+ int tableSize = chooseTableSize(elements.length);
Object[] table = new Object[tableSize];
int mask = tableSize - 1;
+ ArrayList<Object> uniqueElementsList = null;
int hashCode = 0;
- int uniques = 0;
- for (int i = 0; i < n; i++) {
- Object element = ObjectArrays.checkElementNotNull(elements[i], i);
+ for (int i = 0; i < elements.length; i++) {
+ Object element = elements[i];
int hash = element.hashCode();
for (int j = Hashing.smear(hash); ; j++) {
int index = j & mask;
Object value = table[index];
if (value == null) {
+ if (uniqueElementsList != null) {
+ uniqueElementsList.add(element);
+ }
// Came to an empty slot. Put the element here.
- elements[uniques++] = element;
table[index] = element;
hashCode += hash;
break;
} else if (value.equals(element)) {
+ if (uniqueElementsList == null) {
+ // first dup
+ uniqueElementsList = new ArrayList<Object>(elements.length);
+ for (int k = 0; k < i; k++) {
+ Object previous = elements[k];
+ uniqueElementsList.add(previous);
+ }
+ }
break;
}
}
}
- Arrays.fill(elements, uniques, n, null);
- if (uniques == 1) {
+ Object[] uniqueElements = uniqueElementsList == null
+ ? elements
+ : uniqueElementsList.toArray();
+ if (uniqueElements.length == 1) {
// There is only one element or elements are all duplicates
@SuppressWarnings("unchecked") // we are careful to only pass in E
- E element = (E) elements[0];
+ E element = (E) uniqueElements[0];
return new SingletonImmutableSet<E>(element, hashCode);
- } else if (tableSize != chooseTableSize(uniques)) {
+ } else if (tableSize > 2 * chooseTableSize(uniqueElements.length)) {
// Resize the table when the array includes too many duplicates.
// when this happens, we have already made a copy
- return construct(uniques, elements);
+ return construct(uniqueElements);
} else {
- Object[] uniqueElements = (uniques < elements.length)
- ? ObjectArrays.arraysCopyOf(elements, uniques)
- : elements;
return new RegularImmutableSet<E>(uniqueElements, hashCode, table, mask);
}
}
@@ -229,30 +210,18 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
// We use power-of-2 tables, and this is the highest int that's a power of 2
static final int MAX_TABLE_SIZE = Ints.MAX_POWER_OF_TWO;
- // Represents how tightly we can pack things, as a maximum.
- private static final double DESIRED_LOAD_FACTOR = 0.7;
-
// If the set has this many elements, it will "max out" the table size
- private static final int CUTOFF =
- (int) Math.floor(MAX_TABLE_SIZE * DESIRED_LOAD_FACTOR);
+ static final int CUTOFF = 1 << 29;
/**
* Returns an array size suitable for the backing array of a hash table that
- * uses open addressing with linear probing in its implementation. The
- * returned size is the smallest power of two that can hold setSize elements
- * with the desired load factor.
- *
- * <p>Do not call this method with setSize < 2.
+ * uses linear probing in its implementation. The returned size is the
+ * smallest power of two that can hold setSize elements while being at most
+ * 50% full, if possible.
*/
- @VisibleForTesting static int chooseTableSize(int setSize) {
- // Correct the size for open addressing to match desired load factor.
+ static int chooseTableSize(int setSize) {
if (setSize < CUTOFF) {
- // Round up to the next highest power of 2.
- int tableSize = Integer.highestOneBit(setSize - 1) << 1;
- while (tableSize * DESIRED_LOAD_FACTOR < setSize) {
- tableSize <<= 1;
- }
- return tableSize;
+ return Integer.highestOneBit(setSize) << 2;
}
// The table can't be completely full or we'll get infinite reprobes
@@ -277,7 +246,7 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
case 1:
return of(elements[0]);
default:
- return construct(elements.length, elements.clone());
+ return construct(elements.clone());
}
}
@@ -312,19 +281,9 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
* @throws NullPointerException if any of {@code elements} is null
*/
public static <E> ImmutableSet<E> copyOf(Iterator<? extends E> elements) {
- // We special-case for 0 or 1 elements, but anything further is madness.
- if (!elements.hasNext()) {
- return of();
- }
- E first = elements.next();
- if (!elements.hasNext()) {
- return of(first);
- } else {
- return new ImmutableSet.Builder<E>()
- .add(first)
- .addAll(elements)
- .build();
- }
+ // TODO(benyu): here we could avoid toArray() for 0 or 1-element list,
+ // worth it?
+ return copyFromCollection(Lists.newArrayList(elements));
}
/**
@@ -366,12 +325,6 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
if (!set.isPartialView()) {
return set;
}
- } else if (elements instanceof EnumSet) {
- EnumSet<?> enumSet = EnumSet.copyOf((EnumSet<?>) elements);
- @SuppressWarnings("unchecked")
- // immutable collections are safe for covariant casts
- ImmutableSet<E> result = (ImmutableSet<E>) ImmutableEnumSet.asImmutable(enumSet);
- return result;
}
return copyFromCollection(elements);
}
@@ -389,7 +342,7 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
default:
// safe to use the array without copying it
// as specified by Collection.toArray().
- return construct(elements.length, elements);
+ return construct(elements);
}
}
@@ -438,16 +391,30 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
return false;
}
+ /*
+ * The cast is safe because the only way to create an instance is via the
+ * create() method above, which only permits elements of type E.
+ */
+ @SuppressWarnings("unchecked")
@Override public UnmodifiableIterator<E> iterator() {
- return asList().iterator();
+ return (UnmodifiableIterator<E>) Iterators.forArray(elements);
}
@Override public Object[] toArray() {
- return asList().toArray();
+ Object[] array = new Object[size()];
+ System.arraycopy(elements, 0, array, 0, size());
+ return array;
}
@Override public <T> T[] toArray(T[] array) {
- return asList().toArray(array);
+ int size = size();
+ if (array.length < size) {
+ array = ObjectArrays.newArray(array, size);
+ } else if (array.length > size) {
+ array[size] = null;
+ }
+ System.arraycopy(elements, 0, array, 0, size);
+ return array;
}
@Override public boolean containsAll(Collection<?> targets) {
@@ -473,7 +440,65 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
}
@Override ImmutableList<E> createAsList() {
- return new RegularImmutableAsList<E>(this, elements);
+ return new ImmutableAsList<E>(elements, this);
+ }
+ }
+
+ /** such as ImmutableMap.keySet() */
+ abstract static class TransformedImmutableSet<D, E> extends ImmutableSet<E> {
+ final D[] source;
+ final int hashCode;
+
+ TransformedImmutableSet(D[] source, int hashCode) {
+ this.source = source;
+ this.hashCode = hashCode;
+ }
+
+ abstract E transform(D element);
+
+ @Override
+ public int size() {
+ return source.length;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public UnmodifiableIterator<E> iterator() {
+ return new AbstractIndexedListIterator<E>(source.length) {
+ @Override protected E get(int index) {
+ return transform(source[index]);
+ }
+ };
+ }
+
+ @Override public Object[] toArray() {
+ return toArray(new Object[size()]);
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ int size = size();
+ if (array.length < size) {
+ array = ObjectArrays.newArray(array, size);
+ } else if (array.length > size) {
+ array[size] = null;
+ }
+
+ // Writes will produce ArrayStoreException when the toArray() doc requires
+ Object[] objectArray = array;
+ for (int i = 0; i < source.length; i++) {
+ objectArray[i] = transform(source[i]);
+ }
+ return array;
+ }
+
+ @Override public final int hashCode() {
+ return hashCode;
+ }
+
+ @Override boolean isHashCodeFast() {
+ return true;
}
}
@@ -524,34 +549,14 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
* @since 2.0 (imported from Google Collections Library)
*/
public static class Builder<E> extends ImmutableCollection.Builder<E> {
- Object[] contents;
- int size;
+ // accessed directly by ImmutableSortedSet
+ final ArrayList<E> contents = Lists.newArrayList();
/**
* Creates a new builder. The returned builder is equivalent to the builder
* generated by {@link ImmutableSet#builder}.
*/
- public Builder() {
- this(DEFAULT_INITIAL_CAPACITY);
- }
-
- Builder(int capacity) {
- checkArgument(capacity >= 0, "capacity must be >= 0 but was %s", capacity);
- this.contents = new Object[capacity];
- this.size = 0;
- }
-
- /**
- * Expand the absolute capacity of the builder so it can accept at least
- * the specified number of elements without being resized.
- */
- Builder<E> ensureCapacity(int minCapacity) {
- if (contents.length < minCapacity) {
- contents = ObjectArrays.arraysCopyOf(
- contents, expandedCapacity(contents.length, minCapacity));
- }
- return this;
- }
+ public Builder() {}
/**
* Adds {@code element} to the {@code ImmutableSet}. If the {@code
@@ -563,8 +568,7 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
* @throws NullPointerException if {@code element} is null
*/
@Override public Builder<E> add(E element) {
- ensureCapacity(size + 1);
- contents[size++] = checkNotNull(element);
+ contents.add(checkNotNull(element));
return this;
}
@@ -578,12 +582,8 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
* null element
*/
@Override public Builder<E> add(E... elements) {
- for (int i = 0; i < elements.length; i++) {
- ObjectArrays.checkElementNotNull(elements[i], i);
- }
- ensureCapacity(size + elements.length);
- System.arraycopy(elements, 0, contents, size, elements.length);
- size += elements.length;
+ contents.ensureCapacity(contents.size() + elements.length);
+ super.add(elements);
return this;
}
@@ -599,7 +599,7 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
@Override public Builder<E> addAll(Iterable<? extends E> elements) {
if (elements instanceof Collection) {
Collection<?> collection = (Collection<?>) elements;
- ensureCapacity(size + collection.size());
+ contents.ensureCapacity(contents.size() + collection.size());
}
super.addAll(elements);
return this;
@@ -624,11 +624,7 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E>
* the {@code Builder}.
*/
@Override public ImmutableSet<E> build() {
- ImmutableSet<E> result = construct(size, contents);
- // construct has the side effect of deduping contents, so we update size
- // accordingly.
- size = result.size();
- return result;
+ return copyOf(contents);
}
}
}
diff --git a/guava/src/com/google/common/collect/ImmutableSetMultimap.java b/guava/src/com/google/common/collect/ImmutableSetMultimap.java
index 6eedf1a..04a6978 100644
--- a/guava/src/com/google/common/collect/ImmutableSetMultimap.java
+++ b/guava/src/com/google/common/collect/ImmutableSetMultimap.java
@@ -18,9 +18,9 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
-import com.google.common.base.Function;
import java.io.IOException;
import java.io.InvalidObjectException;
@@ -28,12 +28,10 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
import java.util.Map.Entry;
+import java.util.TreeMap;
import javax.annotation.Nullable;
@@ -53,10 +51,6 @@ import javax.annotation.Nullable;
* it has no public or protected constructors. Thus, instances of this class
* are guaranteed to be immutable.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
- * immutable collections</a>.
- *
* @author Mike Ward
* @since 2.0 (imported from Google Collections Library)
*/
@@ -151,7 +145,7 @@ public class ImmutableSetMultimap<K, V>
* Multimap for {@link ImmutableSetMultimap.Builder} that maintains key
* and value orderings and performs better than {@link LinkedHashMultimap}.
*/
- private static class BuilderMultimap<K, V> extends AbstractMapBasedMultimap<K, V> {
+ private static class BuilderMultimap<K, V> extends AbstractMultimap<K, V> {
BuilderMultimap() {
super(new LinkedHashMap<K, Collection<V>>());
}
@@ -162,6 +156,23 @@ public class ImmutableSetMultimap<K, V>
}
/**
+ * Multimap for {@link ImmutableSetMultimap.Builder} that sorts keys and
+ * maintains value orderings.
+ */
+ private static class SortedKeyBuilderMultimap<K, V>
+ extends AbstractMultimap<K, V> {
+ SortedKeyBuilderMultimap(
+ Comparator<? super K> keyComparator, Multimap<K, V> multimap) {
+ super(new TreeMap<K, Collection<V>>(keyComparator));
+ putAll(multimap);
+ }
+ @Override Collection<V> createCollection() {
+ return Sets.newLinkedHashSet();
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
* A builder for creating immutable {@code SetMultimap} instances, especially
* {@code public static final} multimaps ("constant multimaps"). Example:
* <pre> {@code
@@ -186,7 +197,7 @@ public class ImmutableSetMultimap<K, V>
* generated by {@link ImmutableSetMultimap#builder}.
*/
public Builder() {
- builderMultimap = new BuilderMultimap<K, V>();
+ builderMultimap = new BuilderMultimap<K, V>();
}
/**
@@ -235,25 +246,26 @@ public class ImmutableSetMultimap<K, V>
*
* @since 8.0
*/
- @Override
+ @Beta @Override
public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
- this.keyComparator = checkNotNull(keyComparator);
+ builderMultimap = new SortedKeyBuilderMultimap<K, V>(
+ checkNotNull(keyComparator), builderMultimap);
return this;
}
/**
* Specifies the ordering of the generated multimap's values for each key.
- *
- * <p>If this method is called, the sets returned by the {@code get()}
+ *
+ * <p>If this method is called, the sets returned by the {@code get()}
* method of the generated multimap and its {@link Multimap#asMap()} view
* are {@link ImmutableSortedSet} instances. However, serialization does not
* preserve that property, though it does maintain the key and value
* ordering.
- *
+ *
* @since 8.0
*/
// TODO: Make serialization behavior consistent.
- @Override
+ @Beta @Override
public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
super.orderValuesBy(valueComparator);
return this;
@@ -263,23 +275,6 @@ public class ImmutableSetMultimap<K, V>
* Returns a newly-created immutable set multimap.
*/
@Override public ImmutableSetMultimap<K, V> build() {
- if (keyComparator != null) {
- Multimap<K, V> sortedCopy = new BuilderMultimap<K, V>();
- List<Map.Entry<K, Collection<V>>> entries = Lists.newArrayList(
- builderMultimap.asMap().entrySet());
- Collections.sort(
- entries,
- Ordering.from(keyComparator).onResultOf(new Function<Entry<K, Collection<V>>, K>() {
- @Override
- public K apply(Entry<K, Collection<V>> entry) {
- return entry.getKey();
- }
- }));
- for (Map.Entry<K, Collection<V>> entry : entries) {
- sortedCopy.putAll(entry.getKey(), entry.getValue());
- }
- builderMultimap = sortedCopy;
- }
return copyOf(builderMultimap, valueComparator);
}
}
@@ -302,7 +297,7 @@ public class ImmutableSetMultimap<K, V>
Multimap<? extends K, ? extends V> multimap) {
return copyOf(multimap, null);
}
-
+
private static <K, V> ImmutableSetMultimap<K, V> copyOf(
Multimap<? extends K, ? extends V> multimap,
Comparator<? super V> valueComparator) {
@@ -328,7 +323,7 @@ public class ImmutableSetMultimap<K, V>
K key = entry.getKey();
Collection<? extends V> values = entry.getValue();
ImmutableSet<V> set = (valueComparator == null)
- ? ImmutableSet.copyOf(values)
+ ? ImmutableSet.copyOf(values)
: ImmutableSortedSet.copyOf(valueComparator, values);
if (!set.isEmpty()) {
builder.put(key, set);
@@ -343,10 +338,10 @@ public class ImmutableSetMultimap<K, V>
// Returned by get() when values are sorted and a missing key is provided.
private final transient ImmutableSortedSet<V> emptySet;
- ImmutableSetMultimap(ImmutableMap<K, ImmutableSet<V>> map, int size,
+ ImmutableSetMultimap(ImmutableMap<K, ImmutableSet<V>> map, int size,
@Nullable Comparator<? super V> valueComparator) {
super(map, size);
- this.emptySet = (valueComparator == null)
+ this.emptySet = (valueComparator == null)
? null : ImmutableSortedSet.<V>emptySet(valueComparator);
}
@@ -375,13 +370,13 @@ public class ImmutableSetMultimap<K, V>
/**
* {@inheritDoc}
*
- * <p>Because an inverse of a set multimap cannot contain multiple pairs with
- * the same key and value, this method returns an {@code ImmutableSetMultimap}
- * rather than the {@code ImmutableMultimap} specified in the {@code
- * ImmutableMultimap} class.
+ * <p>Because an inverse of a set multimap cannot contain multiple pairs with the same key and
+ * value, this method returns an {@code ImmutableSetMultimap} rather than the
+ * {@code ImmutableMultimap} specified in the {@code ImmutableMultimap} class.
*
- * @since 11.0
+ * @since 11
*/
+ @Beta
public ImmutableSetMultimap<V, K> inverse() {
ImmutableSetMultimap<V, K> result = inverse;
return (result == null) ? (inverse = invert()) : result;
@@ -401,9 +396,8 @@ public class ImmutableSetMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated @Override public ImmutableSet<V> removeAll(Object key) {
+ @Override public ImmutableSet<V> removeAll(Object key) {
throw new UnsupportedOperationException();
}
@@ -411,9 +405,8 @@ public class ImmutableSetMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated @Override public ImmutableSet<V> replaceValues(
+ @Override public ImmutableSet<V> replaceValues(
K key, Iterable<? extends V> values) {
throw new UnsupportedOperationException();
}
diff --git a/guava/src/com/google/common/collect/ImmutableSortedAsList.java b/guava/src/com/google/common/collect/ImmutableSortedAsList.java
index 98aab41..e557570 100644
--- a/guava/src/com/google/common/collect/ImmutableSortedAsList.java
+++ b/guava/src/com/google/common/collect/ImmutableSortedAsList.java
@@ -14,8 +14,7 @@
package com.google.common.collect;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
+import com.google.common.base.Preconditions;
import java.util.Comparator;
@@ -27,60 +26,80 @@ import javax.annotation.Nullable;
* @author Jared Levy
* @author Louis Wasserman
*/
-@GwtCompatible(emulated = true)
@SuppressWarnings("serial")
-final class ImmutableSortedAsList<E> extends RegularImmutableAsList<E>
- implements SortedIterable<E> {
+final class ImmutableSortedAsList<E> extends ImmutableList<E> implements SortedIterable<E> {
+ private final transient ImmutableSortedSet<E> backingSet;
+ private final transient ImmutableList<E> backingList;
+
ImmutableSortedAsList(
ImmutableSortedSet<E> backingSet, ImmutableList<E> backingList) {
- super(backingSet, backingList);
- }
-
- @Override
- ImmutableSortedSet<E> delegateCollection() {
- return (ImmutableSortedSet<E>) super.delegateCollection();
+ this.backingSet = backingSet;
+ this.backingList = backingList;
}
@Override public Comparator<? super E> comparator() {
- return delegateCollection().comparator();
+ return backingSet.comparator();
}
- // Override indexOf() and lastIndexOf() to be O(log N) instead of O(N).
+ // Override contains(), indexOf(), and lastIndexOf() to be O(log N) instead of O(N).
+
+ @Override public boolean contains(@Nullable Object target) {
+ // TODO: why not contains(target)?
+ return backingSet.indexOf(target) >= 0;
+ }
- @GwtIncompatible("ImmutableSortedSet.indexOf")
- // TODO(cpovirk): consider manual binary search under GWT to preserve O(log N) lookup
@Override public int indexOf(@Nullable Object target) {
- int index = delegateCollection().indexOf(target);
+ return backingSet.indexOf(target);
+ }
- // TODO(kevinb): reconsider if it's really worth making feeble attempts at
- // sanity for inconsistent comparators.
+ @Override public int lastIndexOf(@Nullable Object target) {
+ return backingSet.indexOf(target);
+ }
- // The equals() check is needed when the comparator isn't compatible with
- // equals().
- return (index >= 0 && get(index).equals(target)) ? index : -1;
+ // The returned ImmutableSortedAsList maintains the contains(), indexOf(), and
+ // lastIndexOf() performance benefits.
+ @Override public ImmutableList<E> subList(int fromIndex, int toIndex) {
+ Preconditions.checkPositionIndexes(fromIndex, toIndex, size());
+ return (fromIndex == toIndex) ? ImmutableList.<E>of()
+ : new RegularImmutableSortedSet<E>(
+ backingList.subList(fromIndex, toIndex), backingSet.comparator())
+ .asList();
}
- @GwtIncompatible("ImmutableSortedSet.indexOf")
- @Override public int lastIndexOf(@Nullable Object target) {
- return indexOf(target);
+ // The ImmutableAsList serialized form has the correct behavior.
+ @Override Object writeReplace() {
+ return new ImmutableAsList.SerializedForm(backingSet);
+ }
+
+ @Override public UnmodifiableIterator<E> iterator() {
+ return backingList.iterator();
+ }
+
+ @Override public E get(int index) {
+ return backingList.get(index);
+ }
+
+ @Override public UnmodifiableListIterator<E> listIterator() {
+ return backingList.listIterator();
+ }
+
+ @Override public UnmodifiableListIterator<E> listIterator(int index) {
+ return backingList.listIterator(index);
+ }
+
+ @Override public int size() {
+ return backingList.size();
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ return backingList.equals(obj);
}
- @Override
- public boolean contains(Object target) {
- // Necessary for ISS's with comparators inconsistent with equals.
- return indexOf(target) >= 0;
+ @Override public int hashCode() {
+ return backingList.hashCode();
}
- @GwtIncompatible("super.subListUnchecked does not exist; inherited subList is valid if slow")
- /*
- * TODO(cpovirk): if we start to override indexOf/lastIndexOf under GWT, we'll want some way to
- * override subList to return an ImmutableSortedAsList for better performance. Right now, I'm not
- * sure there's any performance hit from our failure to override subListUnchecked under GWT
- */
- @Override
- ImmutableList<E> subListUnchecked(int fromIndex, int toIndex) {
- return new RegularImmutableSortedSet<E>(
- super.subListUnchecked(fromIndex, toIndex), comparator())
- .asList();
+ @Override boolean isPartialView() {
+ return backingList.isPartialView();
}
}
diff --git a/guava/src/com/google/common/collect/ImmutableSortedMap.java b/guava/src/com/google/common/collect/ImmutableSortedMap.java
index d8420fe..c700f7f 100644
--- a/guava/src/com/google/common/collect/ImmutableSortedMap.java
+++ b/guava/src/com/google/common/collect/ImmutableSortedMap.java
@@ -18,17 +18,22 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Maps.keyOrNull;
+import static com.google.common.collect.SortedLists.KeyAbsentBehavior.INVERTED_INSERTION_INDEX;
+import static com.google.common.collect.SortedLists.KeyAbsentBehavior.NEXT_HIGHER;
+import static com.google.common.collect.SortedLists.KeyAbsentBehavior.NEXT_LOWER;
+import static com.google.common.collect.SortedLists.KeyPresentBehavior.ANY_PRESENT;
import com.google.common.annotations.GwtCompatible;
+import com.google.common.collect.SortedLists.KeyAbsentBehavior;
+import com.google.common.collect.SortedLists.KeyPresentBehavior;
+import java.io.Serializable;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
-import java.util.NavigableMap;
+import java.util.NoSuchElementException;
import java.util.SortedMap;
import java.util.TreeMap;
@@ -48,64 +53,28 @@ import javax.annotation.Nullable;
* it has no public or protected constructors. Thus, instances of this class are
* guaranteed to be immutable.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
- * immutable collections</a>.
- *
* @author Jared Levy
* @author Louis Wasserman
- * @since 2.0 (imported from Google Collections Library; implements {@code
- * NavigableMap} since 12.0)
+ * @since 2.0 (imported from Google Collections Library)
*/
@GwtCompatible(serializable = true, emulated = true)
-public abstract class ImmutableSortedMap<K, V>
- extends ImmutableSortedMapFauxverideShim<K, V> implements NavigableMap<K, V> {
+public class ImmutableSortedMap<K, V>
+ extends ImmutableSortedMapFauxverideShim<K, V> implements SortedMap<K, V> {
/*
* TODO(kevinb): Confirm that ImmutableSortedMap is faster to construct and
* uses less memory than TreeMap; then say so in the class Javadoc.
+ *
+ * TODO(kevinb): Create separate subclasses for empty, single-entry, and
+ * multiple-entry instances, if it's deemed beneficial.
*/
- private static final Comparator<Comparable> NATURAL_ORDER = Ordering.natural();
-
- private static final ImmutableSortedMap<Comparable, Object> NATURAL_EMPTY_MAP =
- new EmptyImmutableSortedMap<Comparable, Object>(NATURAL_ORDER);
-
- static <K, V> ImmutableSortedMap<K, V> emptyMap(Comparator<? super K> comparator) {
- if (Ordering.natural().equals(comparator)) {
- return of();
- } else {
- return new EmptyImmutableSortedMap<K, V>(comparator);
- }
- }
-
- static <K, V> ImmutableSortedMap<K, V> fromSortedEntries(
- Comparator<? super K> comparator,
- Collection<? extends Entry<? extends K, ? extends V>> entries) {
- if (entries.isEmpty()) {
- return emptyMap(comparator);
- }
- ImmutableList.Builder<K> keyBuilder = ImmutableList.builder();
- ImmutableList.Builder<V> valueBuilder = ImmutableList.builder();
- for (Entry<? extends K, ? extends V> entry : entries) {
- keyBuilder.add(entry.getKey());
- valueBuilder.add(entry.getValue());
- }
+ private static final Comparator<Comparable> NATURAL_ORDER =
+ Ordering.natural();
- return new RegularImmutableSortedMap<K, V>(
- new RegularImmutableSortedSet<K>(keyBuilder.build(), comparator),
- valueBuilder.build());
- }
-
- static <K, V> ImmutableSortedMap<K, V> from(
- ImmutableSortedSet<K> keySet, ImmutableList<V> valueList) {
- if (keySet.isEmpty()) {
- return emptyMap(keySet.comparator());
- } else {
- return new RegularImmutableSortedMap<K, V>(
- (RegularImmutableSortedSet<K>) keySet,
- valueList);
- }
- }
+ private static final ImmutableSortedMap<Comparable, Object>
+ NATURAL_EMPTY_MAP =
+ new ImmutableSortedMap<Comparable, Object>(
+ ImmutableList.<Entry<Comparable, Object>>of(), NATURAL_ORDER);
/**
* Returns the empty sorted map.
@@ -117,12 +86,24 @@ public abstract class ImmutableSortedMap<K, V>
return (ImmutableSortedMap<K, V>) NATURAL_EMPTY_MAP;
}
+ @SuppressWarnings("unchecked")
+ private static <K, V> ImmutableSortedMap<K, V> emptyMap(
+ Comparator<? super K> comparator) {
+ if (NATURAL_ORDER.equals(comparator)) {
+ return (ImmutableSortedMap<K, V>) NATURAL_EMPTY_MAP;
+ } else {
+ return new ImmutableSortedMap<K, V>(
+ ImmutableList.<Entry<K, V>>of(), comparator);
+ }
+ }
+
/**
* Returns an immutable map containing a single entry.
*/
public static <K extends Comparable<? super K>, V>
ImmutableSortedMap<K, V> of(K k1, V v1) {
- return from(ImmutableSortedSet.of(k1), ImmutableList.of(v1));
+ return new ImmutableSortedMap<K, V>(
+ ImmutableList.of(entryOf(k1, v1)), Ordering.natural());
}
/**
@@ -249,7 +230,7 @@ public abstract class ImmutableSortedMap<K, V>
SortedMap<?, ?> sortedMap = (SortedMap<?, ?>) map;
Comparator<?> comparator2 = sortedMap.comparator();
sameComparator = (comparator2 == null)
- ? comparator == NATURAL_ORDER
+ ? comparator == NATURAL_ORDER
: comparator.equals(comparator2);
}
@@ -264,7 +245,7 @@ public abstract class ImmutableSortedMap<K, V>
}
// "adding" type params to an array of a raw type should be safe as
- // long as no one can ever cast that same array instance back to a
+ // long as no one can ever cast that same array instance back to a
// raw type.
@SuppressWarnings("unchecked")
Entry<K, V>[] entries = map.entrySet().toArray(new Entry[0]);
@@ -281,9 +262,9 @@ public abstract class ImmutableSortedMap<K, V>
validateEntries(list, comparator);
}
- return fromSortedEntries(comparator, list);
+ return new ImmutableSortedMap<K, V>(ImmutableList.copyOf(list), comparator);
}
-
+
private static <K, V> void sortEntries(
List<Entry<K, V>> entries, final Comparator<? super K> comparator) {
Comparator<Entry<K, V>> entryComparator = new Comparator<Entry<K, V>>() {
@@ -292,7 +273,7 @@ public abstract class ImmutableSortedMap<K, V>
return comparator.compare(entry1.getKey(), entry2.getKey());
}
};
-
+
Collections.sort(entries, entryComparator);
}
@@ -312,8 +293,13 @@ public abstract class ImmutableSortedMap<K, V>
* Returns a builder that creates immutable sorted maps whose keys are
* ordered by their natural ordering. The sorted maps use {@link
* Ordering#natural()} as the comparator.
+ *
+ * <p>Note: the type parameter {@code K} extends {@code Comparable<K>} rather
+ * than {@code Comparable<? super K>} as a workaround for javac <a
+ * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug
+ * 6468354</a>.
*/
- public static <K extends Comparable<?>, V> Builder<K, V> naturalOrder() {
+ public static <K extends Comparable<K>, V> Builder<K, V> naturalOrder() {
return new Builder<K, V>(Ordering.natural());
}
@@ -332,8 +318,13 @@ public abstract class ImmutableSortedMap<K, V>
/**
* Returns a builder that creates immutable sorted maps whose keys are
* ordered by the reverse of their natural ordering.
+ *
+ * <p>Note: the type parameter {@code K} extends {@code Comparable<K>} rather
+ * than {@code Comparable<? super K>} as a workaround for javac <a
+ * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug
+ * 6468354</a>.
*/
- public static <K extends Comparable<?>, V> Builder<K, V> reverseOrder() {
+ public static <K extends Comparable<K>, V> Builder<K, V> reverseOrder() {
return new Builder<K, V>(Ordering.natural().reverse());
}
@@ -414,48 +405,209 @@ public abstract class ImmutableSortedMap<K, V>
@Override public ImmutableSortedMap<K, V> build() {
sortEntries(entries, comparator);
validateEntries(entries, comparator);
- return fromSortedEntries(comparator, entries);
+ return new ImmutableSortedMap<K, V>(
+ ImmutableList.copyOf(entries), comparator);
}
}
- ImmutableSortedMap() {
- }
+ final transient ImmutableList<Entry<K, V>> entries;
+ private final transient Comparator<? super K> comparator;
- ImmutableSortedMap(ImmutableSortedMap<K, V> descendingMap) {
- this.descendingMap = descendingMap;
+ ImmutableSortedMap(
+ ImmutableList<Entry<K, V>> entries, Comparator<? super K> comparator) {
+ this.entries = entries;
+ this.comparator = comparator;
}
@Override
public int size() {
- return values().size();
+ return entries.size();
+ }
+
+ // Pretend the comparator can compare anything. If it turns out it can't
+ // compare two elements, it'll throw a CCE. Only methods that are specified to
+ // throw CCE should call this.
+ @SuppressWarnings("unchecked")
+ Comparator<Object> unsafeComparator() {
+ return (Comparator<Object>) comparator;
+ }
+
+ @Override public V get(@Nullable Object key) {
+ if (key == null) {
+ return null;
+ }
+ int i;
+ try {
+ i = index(key, ANY_PRESENT, INVERTED_INSERTION_INDEX);
+ } catch (ClassCastException e) {
+ return null;
+ }
+ return i >= 0 ? entries.get(i).getValue() : null;
}
@Override public boolean containsValue(@Nullable Object value) {
- return values().contains(value);
+ if (value == null) {
+ return false;
+ }
+ return Iterators.contains(valueIterator(), value);
}
@Override boolean isPartialView() {
- return keySet().isPartialView() || values().isPartialView();
+ return entries.isPartialView();
}
+ private transient ImmutableSet<Entry<K, V>> entrySet;
+
/**
* Returns an immutable set of the mappings in this map, sorted by the key
* ordering.
*/
@Override public ImmutableSet<Entry<K, V>> entrySet() {
- return super.entrySet();
+ ImmutableSet<Entry<K, V>> es = entrySet;
+ return (es == null) ? (entrySet = createEntrySet()) : es;
}
+ private ImmutableSet<Entry<K, V>> createEntrySet() {
+ return isEmpty() ? ImmutableSet.<Entry<K, V>>of()
+ : new EntrySet<K, V>(this);
+ }
+
+ @SuppressWarnings("serial") // uses writeReplace(), not default serialization
+ private static class EntrySet<K, V> extends ImmutableSet<Entry<K, V>> {
+ final transient ImmutableSortedMap<K, V> map;
+
+ EntrySet(ImmutableSortedMap<K, V> map) {
+ this.map = map;
+ }
+
+ @Override boolean isPartialView() {
+ return map.isPartialView();
+ }
+
+ @Override
+ public int size() {
+ return map.size();
+ }
+
+ @Override public UnmodifiableIterator<Entry<K, V>> iterator() {
+ return map.entries.iterator();
+ }
+
+ @Override public boolean contains(Object target) {
+ if (target instanceof Entry) {
+ Entry<?, ?> entry = (Entry<?, ?>) target;
+ V mappedValue = map.get(entry.getKey());
+ return mappedValue != null && mappedValue.equals(entry.getValue());
+ }
+ return false;
+ }
+
+ @Override Object writeReplace() {
+ return new EntrySetSerializedForm<K, V>(map);
+ }
+ }
+
+ private static class EntrySetSerializedForm<K, V> implements Serializable {
+ final ImmutableSortedMap<K, V> map;
+ EntrySetSerializedForm(ImmutableSortedMap<K, V> map) {
+ this.map = map;
+ }
+ Object readResolve() {
+ return map.entrySet();
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ private transient ImmutableSortedSet<K> keySet;
+
/**
* Returns an immutable sorted set of the keys in this map.
*/
- @Override public abstract ImmutableSortedSet<K> keySet();
+ @Override public ImmutableSortedSet<K> keySet() {
+ ImmutableSortedSet<K> ks = keySet;
+ return (ks == null) ? (keySet = createKeySet()) : ks;
+ }
+
+ @SuppressWarnings("serial") // does not use default serialization
+ private ImmutableSortedSet<K> createKeySet() {
+ if (isEmpty()) {
+ return ImmutableSortedSet.emptySet(comparator);
+ }
+
+ return new RegularImmutableSortedSet<K>(
+ new TransformedImmutableList<Entry<K, V>, K>(entries) {
+
+ @Override K transform(Entry<K, V> entry) {
+ return entry.getKey();
+ }
+ }, comparator);
+ }
+
+ private transient ImmutableCollection<V> values;
/**
* Returns an immutable collection of the values in this map, sorted by the
* ordering of the corresponding keys.
*/
- @Override public abstract ImmutableCollection<V> values();
+ @Override public ImmutableCollection<V> values() {
+ ImmutableCollection<V> v = values;
+ return (v == null) ? (values = new Values<V>(this)) : v;
+ }
+
+ UnmodifiableIterator<V> valueIterator(){
+ final UnmodifiableIterator<Entry<K, V>> entryIterator = entries.iterator();
+ return new UnmodifiableIterator<V>() {
+
+ @Override public boolean hasNext() {
+ return entryIterator.hasNext();
+ }
+
+ @Override public V next() {
+ return entryIterator.next().getValue();
+ }
+ };
+ }
+
+ @SuppressWarnings("serial") // uses writeReplace(), not default serialization
+ private static class Values<V> extends ImmutableCollection<V> {
+ private final ImmutableSortedMap<?, V> map;
+
+ Values(ImmutableSortedMap<?, V> map) {
+ this.map = map;
+ }
+
+ @Override
+ public int size() {
+ return map.size();
+ }
+
+ @Override public UnmodifiableIterator<V> iterator() {
+ return map.valueIterator();
+ }
+
+ @Override public boolean contains(Object target) {
+ return map.containsValue(target);
+ }
+
+ @Override boolean isPartialView() {
+ return true;
+ }
+
+ @Override Object writeReplace() {
+ return new ValuesSerializedForm<V>(map);
+ }
+ }
+
+ private static class ValuesSerializedForm<V> implements Serializable {
+ final ImmutableSortedMap<?, V> map;
+ ValuesSerializedForm(ImmutableSortedMap<?, V> map) {
+ this.map = map;
+ }
+ Object readResolve() {
+ return map.values();
+ }
+ private static final long serialVersionUID = 0;
+ }
/**
* Returns the comparator that orders the keys, which is
@@ -465,17 +617,23 @@ public abstract class ImmutableSortedMap<K, V>
*/
@Override
public Comparator<? super K> comparator() {
- return keySet().comparator();
+ return comparator;
}
@Override
public K firstKey() {
- return keySet().first();
+ if (isEmpty()) {
+ throw new NoSuchElementException();
+ }
+ return entries.get(0).getKey();
}
@Override
public K lastKey() {
- return keySet().last();
+ if (isEmpty()) {
+ throw new NoSuchElementException();
+ }
+ return entries.get(size() - 1).getKey();
}
/**
@@ -493,20 +651,15 @@ public abstract class ImmutableSortedMap<K, V>
return headMap(toKey, false);
}
- /**
- * This method returns a {@code ImmutableSortedMap}, consisting of the entries
- * whose keys are less than (or equal to, if {@code inclusive}) {@code toKey}.
- *
- * <p>The {@link SortedMap#headMap} documentation states that a submap of a
- * submap throws an {@link IllegalArgumentException} if passed a {@code toKey}
- * greater than an earlier {@code toKey}. However, this method doesn't throw
- * an exception in that situation, but instead keeps the original {@code
- * toKey}.
- *
- * @since 12.0
- */
- @Override
- public abstract ImmutableSortedMap<K, V> headMap(K toKey, boolean inclusive);
+ ImmutableSortedMap<K, V> headMap(K toKey, boolean inclusive){
+ int index;
+ if (inclusive) {
+ index = index(toKey, ANY_PRESENT, NEXT_LOWER) + 1;
+ } else {
+ index = index(toKey, ANY_PRESENT, NEXT_HIGHER);
+ }
+ return createSubmap(0, index);
+ }
/**
* This method returns a {@code ImmutableSortedMap}, consisting of the entries
@@ -526,29 +679,12 @@ public abstract class ImmutableSortedMap<K, V>
return subMap(fromKey, true, toKey, false);
}
- /**
- * This method returns a {@code ImmutableSortedMap}, consisting of the entries
- * whose keys ranges from {@code fromKey} to {@code toKey}, inclusive or
- * exclusive as indicated by the boolean flags.
- *
- * <p>The {@link SortedMap#subMap} documentation states that a submap of a
- * submap throws an {@link IllegalArgumentException} if passed a {@code
- * fromKey} less than an earlier {@code fromKey}. However, this method doesn't
- * throw an exception in that situation, but instead keeps the original {@code
- * fromKey}. Similarly, this method keeps the original {@code toKey}, instead
- * of throwing an exception, if passed a {@code toKey} greater than an earlier
- * {@code toKey}.
- *
- * @since 12.0
- */
- @Override
- public ImmutableSortedMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey,
+ ImmutableSortedMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey,
boolean toInclusive) {
checkNotNull(fromKey);
checkNotNull(toKey);
- checkArgument(comparator().compare(fromKey, toKey) <= 0,
- "expected fromKey <= toKey but %s > %s", fromKey, toKey);
- return headMap(toKey, toInclusive).tailMap(fromKey, fromInclusive);
+ checkArgument(comparator.compare(fromKey, toKey) <= 0);
+ return tailMap(fromKey, fromInclusive).headMap(toKey, toInclusive);
}
/**
@@ -566,117 +702,39 @@ public abstract class ImmutableSortedMap<K, V>
return tailMap(fromKey, true);
}
- /**
- * This method returns a {@code ImmutableSortedMap}, consisting of the entries
- * whose keys are greater than (or equal to, if {@code inclusive})
- * {@code fromKey}.
- *
- * <p>The {@link SortedMap#tailMap} documentation states that a submap of a
- * submap throws an {@link IllegalArgumentException} if passed a {@code
- * fromKey} less than an earlier {@code fromKey}. However, this method doesn't
- * throw an exception in that situation, but instead keeps the original {@code
- * fromKey}.
- *
- * @since 12.0
- */
- @Override
- public abstract ImmutableSortedMap<K, V> tailMap(K fromKey, boolean inclusive);
-
- @Override
- public Entry<K, V> lowerEntry(K key) {
- return headMap(key, false).lastEntry();
- }
-
- @Override
- public K lowerKey(K key) {
- return keyOrNull(lowerEntry(key));
- }
-
- @Override
- public Entry<K, V> floorEntry(K key) {
- return headMap(key, true).lastEntry();
- }
-
- @Override
- public K floorKey(K key) {
- return keyOrNull(floorEntry(key));
- }
-
- @Override
- public Entry<K, V> ceilingEntry(K key) {
- return tailMap(key, true).firstEntry();
- }
-
- @Override
- public K ceilingKey(K key) {
- return keyOrNull(ceilingEntry(key));
- }
-
- @Override
- public Entry<K, V> higherEntry(K key) {
- return tailMap(key, false).firstEntry();
- }
-
- @Override
- public K higherKey(K key) {
- return keyOrNull(higherEntry(key));
- }
-
- @Override
- public Entry<K, V> firstEntry() {
- return isEmpty() ? null : entrySet().asList().get(0);
- }
-
- @Override
- public Entry<K, V> lastEntry() {
- return isEmpty() ? null : entrySet().asList().get(size() - 1);
+ ImmutableSortedMap<K, V> tailMap(K fromKey, boolean inclusive) {
+ int index;
+ if (inclusive) {
+ index = index(fromKey, ANY_PRESENT, NEXT_HIGHER);
+ } else {
+ index = index(fromKey, ANY_PRESENT, NEXT_LOWER) + 1;
+ }
+ return createSubmap(index, size());
}
- /**
- * Guaranteed to throw an exception and leave the map unmodified.
- *
- * @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
- */
- @Deprecated
- @Override
- public final Entry<K, V> pollFirstEntry() {
- throw new UnsupportedOperationException();
+ private ImmutableList<K> keyList() {
+ return new TransformedImmutableList<Entry<K, V>, K>(entries) {
+ @Override
+ K transform(Entry<K, V> entry) {
+ return entry.getKey();
+ }
+ };
}
- /**
- * Guaranteed to throw an exception and leave the map unmodified.
- *
- * @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
- */
- @Deprecated
- @Override
- public final Entry<K, V> pollLastEntry() {
- throw new UnsupportedOperationException();
+ private int index(
+ Object key, KeyPresentBehavior presentBehavior, KeyAbsentBehavior absentBehavior) {
+ return SortedLists.binarySearch(
+ keyList(), checkNotNull(key), unsafeComparator(), presentBehavior, absentBehavior);
}
- private transient ImmutableSortedMap<K, V> descendingMap;
-
- @Override
- public ImmutableSortedMap<K, V> descendingMap() {
- ImmutableSortedMap<K, V> result = descendingMap;
- if (result == null) {
- result = descendingMap = createDescendingMap();
+ private ImmutableSortedMap<K, V> createSubmap(
+ int newFromIndex, int newToIndex) {
+ if (newFromIndex < newToIndex) {
+ return new ImmutableSortedMap<K, V>(
+ entries.subList(newFromIndex, newToIndex), comparator);
+ } else {
+ return emptyMap(comparator);
}
- return result;
- }
-
- abstract ImmutableSortedMap<K, V> createDescendingMap();
-
- @Override
- public ImmutableSortedSet<K> navigableKeySet() {
- return keySet();
- }
-
- @Override
- public ImmutableSortedSet<K> descendingKeySet() {
- return keySet().descendingSet();
}
/**
diff --git a/guava/src/com/google/common/collect/ImmutableSortedMultiset.java b/guava/src/com/google/common/collect/ImmutableSortedMultiset.java
index dadcfb5..82f4abe 100644
--- a/guava/src/com/google/common/collect/ImmutableSortedMultiset.java
+++ b/guava/src/com/google/common/collect/ImmutableSortedMultiset.java
@@ -14,13 +14,12 @@
package com.google.common.collect;
-import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
-import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtIncompatible;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -62,7 +61,7 @@ import java.util.List;
*
* {(x, y) | x.compareTo(y) == 0}}</pre>
*
- * <b>Warning:</b> Like most multisets, an {@code ImmutableSortedMultiset} will not function
+ * <b>Warning:</b> Like most multisets, an {@code ImmutableSortedMultiset} will not function
* correctly if an element is modified after being placed in the multiset. For this reason, and to
* avoid general confusion, it is strongly recommended to place only immutable objects into this
* collection.
@@ -70,16 +69,10 @@ import java.util.List;
* <p><b>Note:</b> Although this class is not final, it cannot be subclassed as it has no public or
* protected constructors. Thus, instances of this type are guaranteed to be immutable.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
- * immutable collections</a>.
- *
* @author Louis Wasserman
- * @since 12.0
*/
-@Beta
@GwtIncompatible("hasn't been tested yet")
-public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultisetFauxverideShim<E>
+abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultisetFauxverideShim<E>
implements SortedMultiset<E> {
// TODO(user): GWT compatibility
@@ -100,11 +93,8 @@ public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultiset
* Returns an immutable sorted multiset containing a single element.
*/
public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E element) {
- RegularImmutableSortedSet<E> elementSet =
- (RegularImmutableSortedSet<E>) ImmutableSortedSet.of(element);
- int[] counts = {1};
- long[] cumulativeCounts = {0, 1};
- return new RegularImmutableSortedMultiset<E>(elementSet, counts, cumulativeCounts, 0, 1);
+ return RegularImmutableSortedMultiset.createFromSorted(
+ NATURAL_ORDER, ImmutableList.of(Multisets.immutableEntry(checkNotNull(element), 1)));
}
/**
@@ -161,9 +151,15 @@ public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultiset
*/
@SuppressWarnings("unchecked")
public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(
- E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) {
+ E e1,
+ E e2,
+ E e3,
+ E e4,
+ E e5,
+ E e6,
+ E... remaining) {
int size = remaining.length + 6;
- List<E> all = Lists.newArrayListWithCapacity(size);
+ List<E> all = new ArrayList<E>(size);
Collections.addAll(all, e1, e2, e3, e4, e5, e6);
Collections.addAll(all, remaining);
return copyOf(Ordering.natural(), all);
@@ -224,7 +220,7 @@ public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultiset
// Unsafe, see ImmutableSortedMultisetFauxverideShim.
@SuppressWarnings("unchecked")
Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural();
- return copyOf(naturalOrder, elements);
+ return copyOfInternal(naturalOrder, elements);
}
/**
@@ -236,7 +232,7 @@ public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultiset
public static <E> ImmutableSortedMultiset<E> copyOf(
Comparator<? super E> comparator, Iterator<? extends E> elements) {
checkNotNull(comparator);
- return new Builder<E>(comparator).addAll(elements).build();
+ return copyOfInternal(comparator, elements);
}
/**
@@ -251,21 +247,8 @@ public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultiset
*/
public static <E> ImmutableSortedMultiset<E> copyOf(
Comparator<? super E> comparator, Iterable<? extends E> elements) {
- if (elements instanceof ImmutableSortedMultiset) {
- @SuppressWarnings("unchecked") // immutable collections are always safe for covariant casts
- ImmutableSortedMultiset<E> multiset = (ImmutableSortedMultiset<E>) elements;
- if (comparator.equals(multiset.comparator())) {
- if (multiset.isPartialView()) {
- return copyOfSortedEntries(comparator, multiset.entrySet().asList());
- } else {
- return multiset;
- }
- }
- }
- elements = Lists.newArrayList(elements); // defensive copy
- TreeMultiset<E> sortedCopy = TreeMultiset.create(checkNotNull(comparator));
- Iterables.addAll(sortedCopy, elements);
- return copyOfSortedEntries(comparator, sortedCopy.entrySet());
+ checkNotNull(comparator);
+ return copyOfInternal(comparator, elements);
}
/**
@@ -282,29 +265,50 @@ public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultiset
*
* @throws NullPointerException if {@code sortedMultiset} or any of its elements is null
*/
+ @SuppressWarnings("unchecked")
public static <E> ImmutableSortedMultiset<E> copyOfSorted(SortedMultiset<E> sortedMultiset) {
- return copyOfSortedEntries(sortedMultiset.comparator(),
- Lists.newArrayList(sortedMultiset.entrySet()));
+ Comparator<? super E> comparator = sortedMultiset.comparator();
+ if (comparator == null) {
+ comparator = (Comparator<? super E>) NATURAL_ORDER;
+ }
+ return copyOfInternal(comparator, sortedMultiset);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <E> ImmutableSortedMultiset<E> copyOfInternal(
+ Comparator<? super E> comparator, Iterable<? extends E> iterable) {
+ if (SortedIterables.hasSameComparator(comparator, iterable)
+ && iterable instanceof ImmutableSortedMultiset<?>) {
+ ImmutableSortedMultiset<E> multiset = (ImmutableSortedMultiset<E>) iterable;
+ if (!multiset.isPartialView()) {
+ return (ImmutableSortedMultiset<E>) iterable;
+ }
+ }
+ ImmutableList<Entry<E>> entries =
+ (ImmutableList) ImmutableList.copyOf(SortedIterables.sortedCounts(comparator, iterable));
+ if (entries.isEmpty()) {
+ return emptyMultiset(comparator);
+ }
+ verifyEntries(entries);
+ return RegularImmutableSortedMultiset.createFromSorted(comparator, entries);
}
- private static <E> ImmutableSortedMultiset<E> copyOfSortedEntries(
- Comparator<? super E> comparator, Collection<Entry<E>> entries) {
+ private static <E> ImmutableSortedMultiset<E> copyOfInternal(
+ Comparator<? super E> comparator, Iterator<? extends E> iterator) {
+ @SuppressWarnings("unchecked") // We can safely cast from IL<Entry<? extends E>> to IL<Entry<E>>
+ ImmutableList<Entry<E>> entries =
+ (ImmutableList) ImmutableList.copyOf(SortedIterables.sortedCounts(comparator, iterator));
if (entries.isEmpty()) {
return emptyMultiset(comparator);
}
- ImmutableList.Builder<E> elementsBuilder = new ImmutableList.Builder<E>(entries.size());
- int[] counts = new int[entries.size()];
- long[] cumulativeCounts = new long[entries.size() + 1];
- int i = 0;
+ verifyEntries(entries);
+ return RegularImmutableSortedMultiset.createFromSorted(comparator, entries);
+ }
+
+ private static <E> void verifyEntries(Collection<Entry<E>> entries) {
for (Entry<E> entry : entries) {
- elementsBuilder.add(entry.getElement());
- counts[i] = entry.getCount();
- cumulativeCounts[i + 1] = cumulativeCounts[i] + counts[i];
- i++;
+ checkNotNull(entry.getElement());
}
- return new RegularImmutableSortedMultiset<E>(
- new RegularImmutableSortedSet<E>(elementsBuilder.build(), comparator),
- counts, cumulativeCounts, 0, entries.size());
}
@SuppressWarnings("unchecked")
@@ -315,15 +319,49 @@ public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultiset
return new EmptyImmutableSortedMultiset<E>(comparator);
}
- ImmutableSortedMultiset() {}
+ private final transient Comparator<? super E> comparator;
+
+ ImmutableSortedMultiset(Comparator<? super E> comparator) {
+ this.comparator = checkNotNull(comparator);
+ }
@Override
- public final Comparator<? super E> comparator() {
- return elementSet().comparator();
+ public Comparator<? super E> comparator() {
+ return comparator;
}
+ // Pretend the comparator can compare anything. If it turns out it can't
+ // compare two elements, it'll throw a CCE. Only methods that are specified to
+ // throw CCE should call this.
+ @SuppressWarnings("unchecked")
+ Comparator<Object> unsafeComparator() {
+ return (Comparator<Object>) comparator;
+ }
+
+ private transient Comparator<? super E> reverseComparator;
+
+ Comparator<? super E> reverseComparator() {
+ Comparator<? super E> result = reverseComparator;
+ if (result == null) {
+ return reverseComparator = Ordering.from(comparator).<E>reverse();
+ }
+ return result;
+ }
+
+ private transient ImmutableSortedSet<E> elementSet;
+
@Override
- public abstract ImmutableSortedSet<E> elementSet();
+ public ImmutableSortedSet<E> elementSet() {
+ ImmutableSortedSet<E> result = elementSet;
+ if (result == null) {
+ return elementSet = createElementSet();
+ }
+ return result;
+ }
+
+ abstract ImmutableSortedSet<E> createElementSet();
+
+ abstract ImmutableSortedSet<E> createDescendingElementSet();
transient ImmutableSortedMultiset<E> descendingMultiset;
@@ -336,15 +374,13 @@ public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultiset
return result;
}
+ abstract UnmodifiableIterator<Entry<E>> descendingEntryIterator();
+
/**
* {@inheritDoc}
*
* <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}.
- *
- * @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final Entry<E> pollFirstEntry() {
throw new UnsupportedOperationException();
@@ -354,13 +390,9 @@ public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultiset
* {@inheritDoc}
*
* <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}.
- *
- * @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
- public final Entry<E> pollLastEntry() {
+ public Entry<E> pollLastEntry() {
throw new UnsupportedOperationException();
}
@@ -370,8 +402,6 @@ public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultiset
@Override
public ImmutableSortedMultiset<E> subMultiset(
E lowerBound, BoundType lowerBoundType, E upperBound, BoundType upperBoundType) {
- checkArgument(comparator().compare(lowerBound, upperBound) <= 0,
- "Expected lowerBound <= upperBound but %s > %s", lowerBound, upperBound);
return tailMultiset(lowerBound, lowerBoundType).headMultiset(upperBound, upperBoundType);
}
@@ -432,8 +462,6 @@ public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultiset
*
* Builder instances can be reused; it is safe to call {@link #build} multiple times to build
* multiple multisets in series.
- *
- * @since 12.0
*/
public static class Builder<E> extends ImmutableMultiset.Builder<E> {
private final Comparator<? super E> comparator;
@@ -538,7 +566,7 @@ public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultiset
*/
@Override
public ImmutableSortedMultiset<E> build() {
- return copyOfSorted((SortedMultiset<E>) contents);
+ return copyOf(comparator, contents);
}
}
diff --git a/guava/src/com/google/common/collect/ImmutableSortedSet.java b/guava/src/com/google/common/collect/ImmutableSortedSet.java
index cfeb8a5..b2d871f 100644
--- a/guava/src/com/google/common/collect/ImmutableSortedSet.java
+++ b/guava/src/com/google/common/collect/ImmutableSortedSet.java
@@ -20,7 +20,6 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
@@ -32,7 +31,6 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
-import java.util.NavigableSet;
import java.util.SortedSet;
import javax.annotation.Nullable;
@@ -80,20 +78,16 @@ import javax.annotation.Nullable;
* it has no public or protected constructors. Thus, instances of this type are
* guaranteed to be immutable.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
- * immutable collections</a>.
- *
* @see ImmutableSet
* @author Jared Levy
* @author Louis Wasserman
- * @since 2.0 (imported from Google Collections Library; implements {@code NavigableSet} since 12.0)
+ * @since 2.0 (imported from Google Collections Library)
*/
// TODO(benyu): benchmark and optimize all creation paths, which are a mess now
@GwtCompatible(serializable = true, emulated = true)
@SuppressWarnings("serial") // we're overriding default serialization
public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxverideShim<E>
- implements NavigableSet<E>, SortedIterable<E> {
+ implements SortedSet<E>, SortedIterable<E> {
private static final Comparator<Comparable> NATURAL_ORDER =
Ordering.natural();
@@ -182,7 +176,7 @@ public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxveride
E e1, E e2, E e3, E e4, E e5) {
return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3, e4, e5));
}
-
+
/**
* Returns an immutable sorted set containing the given elements sorted by
* their natural ordering. When multiple elements are equivalent according to
@@ -306,7 +300,7 @@ public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxveride
// Unsafe, see ImmutableSortedSetFauxverideShim.
@SuppressWarnings("unchecked")
Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural();
- return copyOf(naturalOrder, elements);
+ return copyOfInternal(naturalOrder, elements);
}
/**
@@ -320,7 +314,8 @@ public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxveride
*/
public static <E> ImmutableSortedSet<E> copyOf(
Comparator<? super E> comparator, Iterator<? extends E> elements) {
- return copyOf(comparator, Lists.newArrayList(elements));
+ checkNotNull(comparator);
+ return copyOfInternal(comparator, elements);
}
/**
@@ -339,19 +334,7 @@ public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxveride
public static <E> ImmutableSortedSet<E> copyOf(
Comparator<? super E> comparator, Iterable<? extends E> elements) {
checkNotNull(comparator);
- boolean hasSameComparator =
- SortedIterables.hasSameComparator(comparator, elements);
-
- if (hasSameComparator && (elements instanceof ImmutableSortedSet)) {
- @SuppressWarnings("unchecked")
- ImmutableSortedSet<E> original = (ImmutableSortedSet<E>) elements;
- if (!original.isPartialView()) {
- return original;
- }
- }
- @SuppressWarnings("unchecked") // elements only contains E's; it's safe.
- E[] array = (E[]) Iterables.toArray(elements);
- return construct(comparator, array.length, array);
+ return copyOfInternal(comparator, elements);
}
/**
@@ -374,7 +357,8 @@ public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxveride
*/
public static <E> ImmutableSortedSet<E> copyOf(
Comparator<? super E> comparator, Collection<? extends E> elements) {
- return copyOf(comparator, (Iterable<? extends E>) elements);
+ checkNotNull(comparator);
+ return copyOfInternal(comparator, elements);
}
/**
@@ -394,69 +378,41 @@ public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxveride
* @throws NullPointerException if {@code sortedSet} or any of its elements
* is null
*/
+ @SuppressWarnings("unchecked")
public static <E> ImmutableSortedSet<E> copyOfSorted(SortedSet<E> sortedSet) {
- Comparator<? super E> comparator = SortedIterables.comparator(sortedSet);
- Object[] elements = sortedSet.toArray();
- if (elements.length == 0) {
- return emptySet(comparator);
- } else {
- return new RegularImmutableSortedSet<E>(
- ImmutableList.<E>asImmutableList(elements), comparator);
+ Comparator<? super E> comparator = sortedSet.comparator();
+ if (comparator == null) {
+ comparator = (Comparator<? super E>) NATURAL_ORDER;
}
+ return copyOfInternal(comparator, sortedSet);
}
- /**
- * Sorts and eliminates duplicates from the first {@code n} positions in {@code contents}.
- * Returns the number of unique elements. If this returns {@code k}, then the first {@code k}
- * elements of {@code contents} will be the sorted, unique elements, and {@code
- * contents[i] == null} for {@code k <= i < n}.
- *
- * @throws NullPointerException if any of the first {@code n} elements of {@code contents} is
- * null
- */
- static <E> int sortAndUnique(
- Comparator<? super E> comparator, int n, E... contents) {
- if (n == 0) {
- return 0;
- }
- for (int i = 0; i < n; i++) {
- ObjectArrays.checkElementNotNull(contents[i], i);
- }
- Arrays.sort(contents, 0, n, comparator);
- int uniques = 1;
- for (int i = 1; i < n; i++) {
- E cur = contents[i];
- E prev = contents[uniques - 1];
- if (comparator.compare(cur, prev) != 0) {
- contents[uniques++] = cur;
+ private static <E> ImmutableSortedSet<E> copyOfInternal(
+ Comparator<? super E> comparator, Iterable<? extends E> elements) {
+ boolean hasSameComparator =
+ SortedIterables.hasSameComparator(comparator, elements);
+
+ if (hasSameComparator && (elements instanceof ImmutableSortedSet)) {
+ @SuppressWarnings("unchecked")
+ ImmutableSortedSet<E> original = (ImmutableSortedSet<E>) elements;
+ if (!original.isPartialView()) {
+ return original;
}
}
- Arrays.fill(contents, uniques, n, null);
- return uniques;
+ ImmutableList<E> list = ImmutableList.copyOf(
+ SortedIterables.sortedUnique(comparator, elements));
+ return list.isEmpty()
+ ? ImmutableSortedSet.<E>emptySet(comparator)
+ : new RegularImmutableSortedSet<E>(list, comparator);
}
- /**
- * Constructs an {@code ImmutableSortedSet} from the first {@code n} elements of
- * {@code contents}. If {@code k} is the size of the returned {@code ImmutableSortedSet}, then
- * the sorted unique elements are in the first {@code k} positions of {@code contents}, and
- * {@code contents[i] == null} for {@code k <= i < n}.
- *
- * <p>If {@code k == contents.length}, then {@code contents} may no longer be safe for
- * modification.
- *
- * @throws NullPointerException if any of the first {@code n} elements of {@code contents} is
- * null
- */
- static <E> ImmutableSortedSet<E> construct(
- Comparator<? super E> comparator, int n, E... contents) {
- int uniques = sortAndUnique(comparator, n, contents);
- if (uniques == 0) {
- return emptySet(comparator);
- } else if (uniques < contents.length) {
- contents = ObjectArrays.arraysCopyOf(contents, uniques);
- }
- return new RegularImmutableSortedSet<E>(
- ImmutableList.<E>asImmutableList(contents), comparator);
+ private static <E> ImmutableSortedSet<E> copyOfInternal(
+ Comparator<? super E> comparator, Iterator<? extends E> elements) {
+ ImmutableList<E> list =
+ ImmutableList.copyOf(SortedIterables.sortedUnique(comparator, elements));
+ return list.isEmpty()
+ ? ImmutableSortedSet.<E>emptySet(comparator)
+ : new RegularImmutableSortedSet<E>(list, comparator);
}
/**
@@ -474,8 +430,13 @@ public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxveride
/**
* Returns a builder that creates immutable sorted sets whose elements are
* ordered by the reverse of their natural ordering.
+ *
+ * <p>Note: the type parameter {@code E} extends {@code Comparable<E>} rather
+ * than {@code Comparable<? super E>} as a workaround for javac <a
+ * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug
+ * 6468354</a>.
*/
- public static <E extends Comparable<?>> Builder<E> reverseOrder() {
+ public static <E extends Comparable<E>> Builder<E> reverseOrder() {
return new Builder<E>(Ordering.natural().reverse());
}
@@ -485,8 +446,13 @@ public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxveride
* Ordering#natural()} as the comparator. This method provides more
* type-safety than {@link #builder}, as it can be called only for classes
* that implement {@link Comparable}.
+ *
+ * <p>Note: the type parameter {@code E} extends {@code Comparable<E>} rather
+ * than {@code Comparable<? super E>} as a workaround for javac <a
+ * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug
+ * 6468354</a>.
*/
- public static <E extends Comparable<?>> Builder<E> naturalOrder() {
+ public static <E extends Comparable<E>> Builder<E> naturalOrder() {
return new Builder<E>(Ordering.natural());
}
@@ -577,11 +543,7 @@ public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxveride
* of the {@code Builder} and its comparator.
*/
@Override public ImmutableSortedSet<E> build() {
- @SuppressWarnings("unchecked") // we're careful to put only E's in here
- E[] contentsArray = (E[]) contents;
- ImmutableSortedSet<E> result = construct(comparator, size, contentsArray);
- this.size = result.size(); // we eliminated duplicates in-place in contentsArray
- return result;
+ return copyOfInternal(comparator, contents.iterator());
}
}
@@ -636,12 +598,7 @@ public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxveride
return headSet(toElement, false);
}
- /**
- * @since 12.0
- */
- @GwtIncompatible("NavigableSet")
- @Override
- public ImmutableSortedSet<E> headSet(E toElement, boolean inclusive) {
+ ImmutableSortedSet<E> headSet(E toElement, boolean inclusive) {
return headSetImpl(checkNotNull(toElement), inclusive);
}
@@ -663,12 +620,7 @@ public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxveride
return subSet(fromElement, true, toElement, false);
}
- /**
- * @since 12.0
- */
- @GwtIncompatible("NavigableSet")
- @Override
- public ImmutableSortedSet<E> subSet(
+ ImmutableSortedSet<E> subSet(
E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
checkNotNull(fromElement);
checkNotNull(toElement);
@@ -692,12 +644,7 @@ public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxveride
return tailSet(fromElement, true);
}
- /**
- * @since 12.0
- */
- @GwtIncompatible("NavigableSet")
- @Override
- public ImmutableSortedSet<E> tailSet(E fromElement, boolean inclusive) {
+ ImmutableSortedSet<E> tailSet(E fromElement, boolean inclusive) {
return tailSetImpl(checkNotNull(fromElement), inclusive);
}
@@ -713,110 +660,6 @@ public abstract class ImmutableSortedSet<E> extends ImmutableSortedSetFauxveride
abstract ImmutableSortedSet<E> tailSetImpl(E fromElement, boolean inclusive);
/**
- * @since 12.0
- */
- @GwtIncompatible("NavigableSet")
- @Override
- public E lower(E e) {
- return Iterators.getNext(headSet(e, false).descendingIterator(), null);
- }
-
- /**
- * @since 12.0
- */
- @GwtIncompatible("NavigableSet")
- @Override
- public E floor(E e) {
- return Iterators.getNext(headSet(e, true).descendingIterator(), null);
- }
-
- /**
- * @since 12.0
- */
- @GwtIncompatible("NavigableSet")
- @Override
- public E ceiling(E e) {
- return Iterables.getFirst(tailSet(e, true), null);
- }
-
- /**
- * @since 12.0
- */
- @GwtIncompatible("NavigableSet")
- @Override
- public E higher(E e) {
- return Iterables.getFirst(tailSet(e, false), null);
- }
-
- @Override
- public E first() {
- return iterator().next();
- }
-
- @Override
- public E last() {
- return descendingIterator().next();
- }
-
- /**
- * Guaranteed to throw an exception and leave the set unmodified.
- *
- * @since 12.0
- * @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
- */
- @Deprecated
- @GwtIncompatible("NavigableSet")
- @Override
- public final E pollFirst() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Guaranteed to throw an exception and leave the set unmodified.
- *
- * @since 12.0
- * @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
- */
- @Deprecated
- @GwtIncompatible("NavigableSet")
- @Override
- public final E pollLast() {
- throw new UnsupportedOperationException();
- }
-
- @GwtIncompatible("NavigableSet")
- transient ImmutableSortedSet<E> descendingSet;
-
- /**
- * @since 12.0
- */
- @GwtIncompatible("NavigableSet")
- @Override
- public ImmutableSortedSet<E> descendingSet() {
- // racy single-check idiom
- ImmutableSortedSet<E> result = descendingSet;
- if (result == null) {
- result = descendingSet = createDescendingSet();
- result.descendingSet = this;
- }
- return result;
- }
-
- @GwtIncompatible("NavigableSet")
- ImmutableSortedSet<E> createDescendingSet() {
- return new DescendingImmutableSortedSet<E>(this);
- }
-
- /**
- * @since 12.0
- */
- @GwtIncompatible("NavigableSet")
- @Override
- public abstract UnmodifiableIterator<E> descendingIterator();
-
- /**
* Returns the position of an element within the set, or -1 if not present.
*/
abstract int indexOf(@Nullable Object target);
diff --git a/guava/src/com/google/common/collect/ImmutableTable.java b/guava/src/com/google/common/collect/ImmutableTable.java
index 8296a83..debd49b 100644
--- a/guava/src/com/google/common/collect/ImmutableTable.java
+++ b/guava/src/com/google/common/collect/ImmutableTable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Guava Authors
+ * Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import java.util.Comparator;
@@ -34,13 +35,10 @@ import javax.annotation.Nullable;
* it has no public or protected constructors. Thus, instances of this class are
* guaranteed to be immutable.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
- * immutable collections</a>.
- *
- * @author Gregory Kick
+ * @author gak@google.com (Gregory Kick)
* @since 11.0
*/
+@Beta
@GwtCompatible
// TODO(gak): make serializable
public abstract class ImmutableTable<R, C, V> implements Table<R, C, V> {
@@ -72,7 +70,7 @@ public abstract class ImmutableTable<R, C, V> implements Table<R, C, V> {
*/
public static final <R, C, V> ImmutableTable<R, C, V> copyOf(
Table<? extends R, ? extends C, ? extends V> table) {
- if (table instanceof ImmutableTable) {
+ if (table instanceof ImmutableTable<?, ?, ?>) {
@SuppressWarnings("unchecked")
ImmutableTable<R, C, V> parameterizedTable
= (ImmutableTable<R, C, V>) table;
@@ -106,7 +104,7 @@ public abstract class ImmutableTable<R, C, V> implements Table<R, C, V> {
/**
* Returns a new builder. The generated builder is equivalent to the builder
- * created by the {@link Builder#ImmutableTable.Builder()} constructor.
+ * created by the {@link Builder#Builder()} constructor.
*/
public static final <R, C, V> Builder<R, C, V> builder() {
return new Builder<R, C, V>();
@@ -256,8 +254,8 @@ public abstract class ImmutableTable<R, C, V> implements Table<R, C, V> {
/**
* {@inheritDoc}
*
- * <p>The value {@code Map<R, V>} instances in the returned map are
- * {@link ImmutableMap} instances as well.
+ * <p>The value {@code Map<R, V>}s in the returned map are
+ * {@link ImmutableMap}s as well.
*/
@Override public abstract ImmutableMap<C, Map<R, V>> columnMap();
@@ -273,8 +271,8 @@ public abstract class ImmutableTable<R, C, V> implements Table<R, C, V> {
/**
* {@inheritDoc}
*
- * <p>The value {@code Map<C, V>} instances in the returned map are
- * {@link ImmutableMap} instances as well.
+ * <p>The value {@code Map<C, V>}s in the returned map are
+ * {@link ImmutableMap}s as well.
*/
@Override public abstract ImmutableMap<R, Map<C, V>> rowMap();
@@ -282,9 +280,8 @@ public abstract class ImmutableTable<R, C, V> implements Table<R, C, V> {
* Guaranteed to throw an exception and leave the table unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated @Override public final void clear() {
+ @Override public final void clear() {
throw new UnsupportedOperationException();
}
@@ -292,9 +289,8 @@ public abstract class ImmutableTable<R, C, V> implements Table<R, C, V> {
* Guaranteed to throw an exception and leave the table unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated @Override public final V put(R rowKey, C columnKey, V value) {
+ @Override public final V put(R rowKey, C columnKey, V value) {
throw new UnsupportedOperationException();
}
@@ -302,9 +298,8 @@ public abstract class ImmutableTable<R, C, V> implements Table<R, C, V> {
* Guaranteed to throw an exception and leave the table unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated @Override public final void putAll(
+ @Override public final void putAll(
Table<? extends R, ? extends C, ? extends V> table) {
throw new UnsupportedOperationException();
}
@@ -313,16 +308,15 @@ public abstract class ImmutableTable<R, C, V> implements Table<R, C, V> {
* Guaranteed to throw an exception and leave the table unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated @Override public final V remove(Object rowKey, Object columnKey) {
+ @Override public final V remove(Object rowKey, Object columnKey) {
throw new UnsupportedOperationException();
}
@Override public boolean equals(@Nullable Object obj) {
if (obj == this) {
return true;
- } else if (obj instanceof Table) {
+ } else if (obj instanceof Table<?, ?, ?>) {
Table<?, ?, ?> that = (Table<?, ?, ?>) obj;
return this.cellSet().equals(that.cellSet());
} else {
diff --git a/guava/src/com/google/common/collect/Interners.java b/guava/src/com/google/common/collect/Interners.java
index bd592d6..f5a6c85 100644
--- a/guava/src/com/google/common/collect/Interners.java
+++ b/guava/src/com/google/common/collect/Interners.java
@@ -18,7 +18,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtIncompatible;
-import com.google.common.base.Equivalence;
+import com.google.common.base.Equivalences;
import com.google.common.base.Function;
import com.google.common.collect.MapMakerInternalMap.ReferenceEntry;
@@ -51,24 +51,16 @@ public final class Interners {
};
}
- /**
- * Returns a new thread-safe interner which retains a weak reference to each instance it has
- * interned, and so does not prevent these instances from being garbage-collected. This most
- * likely does not perform as well as {@link #newStrongInterner}, but is the best alternative
- * when the memory usage of that implementation is unacceptable. Note that unlike {@link
- * String#intern}, using this interner does not consume memory in the permanent generation.
- */
- @GwtIncompatible("java.lang.ref.WeakReference")
- public static <E> Interner<E> newWeakInterner() {
- return new WeakInterner<E>();
- }
-
- private static class WeakInterner<E> implements Interner<E> {
+ private static class CustomInterner<E> implements Interner<E> {
// MapMaker is our friend, we know about this type
- private final MapMakerInternalMap<E, Dummy> map = new MapMaker()
- .weakKeys()
- .keyEquivalence(Equivalence.equals())
+ private final MapMakerInternalMap<E, Dummy> map;
+
+ CustomInterner(GenericMapMaker<? super E, Object> mm) {
+ this.map = mm
+ .strongValues()
+ .keyEquivalence(Equivalences.equals())
.makeCustomMap();
+ }
@Override public E intern(E sample) {
while (true) {
@@ -100,6 +92,18 @@ public final class Interners {
}
/**
+ * Returns a new thread-safe interner which retains a weak reference to each instance it has
+ * interned, and so does not prevent these instances from being garbage-collected. This most
+ * likely does not perform as well as {@link #newStrongInterner}, but is the best alternative
+ * when the memory usage of that implementation is unacceptable. Note that unlike {@link
+ * String#intern}, using this interner does not consume memory in the permanent generation.
+ */
+ @GwtIncompatible("java.lang.ref.WeakReference")
+ public static <E> Interner<E> newWeakInterner() {
+ return new CustomInterner<E>(new MapMaker().weakKeys());
+ }
+
+ /**
* Returns a function that delegates to the {@link Interner#intern} method of the given interner.
*
* @since 8.0
@@ -125,7 +129,7 @@ public final class Interners {
}
@Override public boolean equals(Object other) {
- if (other instanceof InternerFunction) {
+ if (other instanceof InternerFunction<?>) {
InternerFunction<?> that = (InternerFunction<?>) other;
return interner.equals(that.interner);
}
diff --git a/guava/src/com/google/common/collect/Iterables.java b/guava/src/com/google/common/collect/Iterables.java
index 39ad2f2..a92c2b2 100644
--- a/guava/src/com/google/common/collect/Iterables.java
+++ b/guava/src/com/google/common/collect/Iterables.java
@@ -23,6 +23,7 @@ import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Function;
+import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
@@ -31,6 +32,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
@@ -50,10 +52,6 @@ import javax.annotation.Nullable;
* produced in this class are <i>lazy</i>, which means that their iterators
* only advance the backing iteration when absolutely necessary.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Iterables">
- * {@code Iterables}</a>.
- *
* @author Kevin Bourrillion
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
@@ -84,7 +82,7 @@ public final class Iterables {
return checkNotNull(iterable);
}
- private static final class UnmodifiableIterable<T> extends FluentIterable<T> {
+ private static final class UnmodifiableIterable<T> implements Iterable<T> {
private final Iterable<T> iterable;
private UnmodifiableIterable(Iterable<T> iterable) {
@@ -113,14 +111,20 @@ public final class Iterables {
}
/**
- * Returns {@code true} if {@code iterable} contains any object for which {@code equals(element)}
- * is true.
+ * Returns {@code true} if {@code iterable} contains {@code element}; that is,
+ * any object for which {@code equals(element)} is true.
*/
public static boolean contains(Iterable<?> iterable, @Nullable Object element)
{
if (iterable instanceof Collection) {
Collection<?> collection = (Collection<?>) iterable;
- return Collections2.safeContains(collection, element);
+ try {
+ return collection.contains(element);
+ } catch (NullPointerException e) {
+ return false;
+ } catch (ClassCastException e) {
+ return false;
+ }
}
return Iterators.contains(iterable.iterator(), element);
}
@@ -242,13 +246,6 @@ public final class Iterables {
*/
public static boolean elementsEqual(
Iterable<?> iterable1, Iterable<?> iterable2) {
- if (iterable1 instanceof Collection && iterable2 instanceof Collection) {
- Collection<?> collection1 = (Collection<?>) iterable1;
- Collection<?> collection2 = (Collection<?>) iterable2;
- if (collection1.size() != collection2.size()) {
- return false;
- }
- }
return Iterators.elementsEqual(iterable1.iterator(), iterable2.iterator());
}
@@ -278,9 +275,8 @@ public final class Iterables {
* @throws IllegalArgumentException if the iterator contains multiple
* elements
*/
- @Nullable
public static <T> T getOnlyElement(
- Iterable<? extends T> iterable, @Nullable T defaultValue) {
+ Iterable<T> iterable, @Nullable T defaultValue) {
return Iterators.getOnlyElement(iterable.iterator(), defaultValue);
}
@@ -372,7 +368,7 @@ public final class Iterables {
*/
public static <T> Iterable<T> cycle(final Iterable<T> iterable) {
checkNotNull(iterable);
- return new FluentIterable<T>() {
+ return new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.cycle(iterable);
@@ -487,7 +483,7 @@ public final class Iterables {
public static <T> Iterable<T> concat(
final Iterable<? extends Iterable<? extends T>> inputs) {
checkNotNull(inputs);
- return new FluentIterable<T>() {
+ return new IterableWithToString<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.concat(iterators(inputs));
@@ -538,7 +534,7 @@ public final class Iterables {
final Iterable<T> iterable, final int size) {
checkNotNull(iterable);
checkArgument(size > 0);
- return new FluentIterable<List<T>>() {
+ return new IterableWithToString<List<T>>() {
@Override
public Iterator<List<T>> iterator() {
return Iterators.partition(iterable.iterator(), size);
@@ -567,7 +563,7 @@ public final class Iterables {
final Iterable<T> iterable, final int size) {
checkNotNull(iterable);
checkArgument(size > 0);
- return new FluentIterable<List<T>>() {
+ return new IterableWithToString<List<T>>() {
@Override
public Iterator<List<T>> iterator() {
return Iterators.paddedPartition(iterable.iterator(), size);
@@ -583,7 +579,7 @@ public final class Iterables {
final Iterable<T> unfiltered, final Predicate<? super T> predicate) {
checkNotNull(unfiltered);
checkNotNull(predicate);
- return new FluentIterable<T>() {
+ return new IterableWithToString<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.filter(unfiltered.iterator(), predicate);
@@ -607,7 +603,7 @@ public final class Iterables {
final Iterable<?> unfiltered, final Class<T> type) {
checkNotNull(unfiltered);
checkNotNull(type);
- return new FluentIterable<T>() {
+ return new IterableWithToString<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.filter(unfiltered.iterator(), type);
@@ -616,7 +612,8 @@ public final class Iterables {
}
/**
- * Returns {@code true} if any element in {@code iterable} satisfies the predicate.
+ * Returns {@code true} if one or more elements in {@code iterable} satisfy
+ * the predicate.
*/
public static <T> boolean any(
Iterable<T> iterable, Predicate<? super T> predicate) {
@@ -635,8 +632,8 @@ public final class Iterables {
/**
* Returns the first element in {@code iterable} that satisfies the given
* predicate; use this method only when such an element is known to exist. If
- * it is possible that <i>no</i> element will match, use {@link #tryFind} or
- * {@link #find(Iterable, Predicate, Object)} instead.
+ * it is possible that <i>no</i> element will match, use {@link
+ * #tryFind)} or {@link #find(Iterable, Predicate, T)} instead.
*
* @throws NoSuchElementException if no element in {@code iterable} matches
* the given predicate
@@ -654,8 +651,7 @@ public final class Iterables {
*
* @since 7.0
*/
- @Nullable
- public static <T> T find(Iterable<? extends T> iterable,
+ public static <T> T find(Iterable<T> iterable,
Predicate<? super T> predicate, @Nullable T defaultValue) {
return Iterators.find(iterable.iterator(), predicate, defaultValue);
}
@@ -707,7 +703,7 @@ public final class Iterables {
final Function<? super F, ? extends T> function) {
checkNotNull(fromIterable);
checkNotNull(function);
- return new FluentIterable<T>() {
+ return new IterableWithToString<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.transform(fromIterable.iterator(), function);
@@ -760,8 +756,8 @@ public final class Iterables {
* @throws IndexOutOfBoundsException if {@code position} is negative
* @since 4.0
*/
- @Nullable
- public static <T> T get(Iterable<? extends T> iterable, int position, @Nullable T defaultValue) {
+ public static <T> T get(Iterable<T> iterable, int position,
+ @Nullable T defaultValue) {
checkNotNull(iterable);
checkNonnegativeIndex(position);
@@ -777,16 +773,11 @@ public final class Iterables {
* the iterable is empty. The {@link Iterators} analog to this method is
* {@link Iterators#getNext}.
*
- * <p>If no default value is desired (and the caller instead wants a
- * {@link NoSuchElementException} to be thrown), it is recommended that
- * {@code iterable.iterator().next()} is used instead.
- *
* @param defaultValue the default value to return if the iterable is empty
* @return the first element of {@code iterable} or the default value
* @since 7.0
*/
- @Nullable
- public static <T> T getFirst(Iterable<? extends T> iterable, @Nullable T defaultValue) {
+ public static <T> T getFirst(Iterable<T> iterable, @Nullable T defaultValue) {
return Iterators.getNext(iterable.iterator(), defaultValue);
}
@@ -827,17 +818,16 @@ public final class Iterables {
* @return the last element of {@code iterable} or the default value
* @since 3.0
*/
- @Nullable
- public static <T> T getLast(Iterable<? extends T> iterable, @Nullable T defaultValue) {
+ public static <T> T getLast(Iterable<T> iterable, @Nullable T defaultValue) {
if (iterable instanceof Collection) {
- Collection<? extends T> collection = Collections2.cast(iterable);
+ Collection<T> collection = (Collection<T>) iterable;
if (collection.isEmpty()) {
return defaultValue;
}
}
if (iterable instanceof List) {
- List<? extends T> list = Lists.cast(iterable);
+ List<T> list = (List<T>) iterable;
return getLastInNonemptyList(list);
}
@@ -847,7 +837,7 @@ public final class Iterables {
* call this method.
*/
if (iterable instanceof SortedSet) {
- SortedSet<? extends T> sortedSet = Sets.cast(iterable);
+ SortedSet<T> sortedSet = (SortedSet<T>) iterable;
return sortedSet.last();
}
@@ -885,7 +875,7 @@ public final class Iterables {
if (iterable instanceof List) {
final List<T> list = (List<T>) iterable;
- return new FluentIterable<T>() {
+ return new IterableWithToString<T>() {
@Override
public Iterator<T> iterator() {
// TODO(kevinb): Support a concurrently modified collection?
@@ -896,12 +886,12 @@ public final class Iterables {
};
}
- return new FluentIterable<T>() {
+ return new IterableWithToString<T>() {
@Override
public Iterator<T> iterator() {
final Iterator<T> iterator = iterable.iterator();
- Iterators.advance(iterator, numberToSkip);
+ Iterators.skip(iterator, numberToSkip);
/*
* We can't just return the iterator because an immediate call to its
@@ -957,7 +947,7 @@ public final class Iterables {
final Iterable<T> iterable, final int limitSize) {
checkNotNull(iterable);
checkArgument(limitSize >= 0, "limit is negative");
- return new FluentIterable<T>() {
+ return new IterableWithToString<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.limit(iterable.iterator(), limitSize);
@@ -986,7 +976,7 @@ public final class Iterables {
*/
public static <T> Iterable<T> consumingIterable(final Iterable<T> iterable) {
if (iterable instanceof Queue) {
- return new FluentIterable<T>() {
+ return new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return new ConsumingQueueIterator<T>((Queue<T>) iterable);
@@ -996,7 +986,7 @@ public final class Iterables {
checkNotNull(iterable);
- return new FluentIterable<T>() {
+ return new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.consumingIterator(iterable.iterator());
@@ -1023,6 +1013,30 @@ public final class Iterables {
// Methods only in Iterables, not in Iterators
/**
+ * Adapts a list to an iterable with reversed iteration order. It is
+ * especially useful in foreach-style loops: <pre> {@code
+ *
+ * List<String> mylist = ...
+ * for (String str : Iterables.reverse(mylist)) {
+ * ...
+ * }}</pre>
+ *
+ * There is no corresponding method in {@link Iterators}, since {@link
+ * Iterable#iterator} can simply be invoked on the result of calling this
+ * method.
+ *
+ * @return an iterable with the same elements as the list, in reverse
+ *
+ * @deprecated use {@link Lists#reverse(List)} or {@link
+ * ImmutableList#reverse()}. <b>This method is scheduled for deletion in
+ * July 2012.</b>
+ */
+ @Deprecated
+ public static <T> Iterable<T> reverse(final List<T> list) {
+ return Lists.reverse(list);
+ }
+
+ /**
* Determines if the given iterable contains no elements.
*
* <p>There is no precise {@link Iterator} equivalent to this method, since
@@ -1038,6 +1052,43 @@ public final class Iterables {
return !iterable.iterator().hasNext();
}
+ // Non-public
+
+ /**
+ * Removes the specified element from the specified iterable.
+ *
+ * <p>This method iterates over the iterable, checking each element returned
+ * by the iterator in turn to see if it equals the object {@code o}. If they
+ * are equal, it is removed from the iterable with the iterator's
+ * {@code remove} method. At most one element is removed, even if the iterable
+ * contains multiple members that equal {@code o}.
+ *
+ * <p><b>Warning:</b> Do not use this method for a collection, such as a
+ * {@link HashSet}, that has a fast {@code remove} method.
+ *
+ * @param iterable the iterable from which to remove
+ * @param o an element to remove from the collection
+ * @return {@code true} if the iterable changed as a result
+ * @throws UnsupportedOperationException if the iterator does not support the
+ * {@code remove} method and the iterable contains the object
+ */
+ static boolean remove(Iterable<?> iterable, @Nullable Object o) {
+ Iterator<?> i = iterable.iterator();
+ while (i.hasNext()) {
+ if (Objects.equal(i.next(), o)) {
+ i.remove();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ abstract static class IterableWithToString<E> implements Iterable<E> {
+ @Override public String toString() {
+ return Iterables.toString(this);
+ }
+ }
+
/**
* Returns an iterable over the merged contents of all given
* {@code iterables}. Equivalent entries will not be de-duplicated.
@@ -1056,7 +1107,7 @@ public final class Iterables {
final Comparator<? super T> comparator) {
checkNotNull(iterables, "iterables");
checkNotNull(comparator, "comparator");
- Iterable<T> iterable = new FluentIterable<T>() {
+ Iterable<T> iterable = new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.mergeSorted(
diff --git a/guava/src/com/google/common/collect/Iterators.java b/guava/src/com/google/common/collect/Iterators.java
index 39e13c3..847d1dd 100644
--- a/guava/src/com/google/common/collect/Iterators.java
+++ b/guava/src/com/google/common/collect/Iterators.java
@@ -24,7 +24,6 @@ import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Function;
-import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
@@ -38,7 +37,6 @@ import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
-import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.PriorityQueue;
import java.util.Queue;
@@ -54,10 +52,6 @@ import javax.annotation.Nullable;
* produced in this class are <i>lazy</i>, which means that they only advance
* the backing iteration when absolutely necessary.
*
- * <p>See the Guava User Guide section on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Iterables">
- * {@code Iterators}</a>.
- *
* @author Kevin Bourrillion
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
@@ -66,8 +60,8 @@ import javax.annotation.Nullable;
public final class Iterators {
private Iterators() {}
- static final UnmodifiableListIterator<Object> EMPTY_LIST_ITERATOR
- = new UnmodifiableListIterator<Object>() {
+ static final UnmodifiableIterator<Object> EMPTY_ITERATOR
+ = new UnmodifiableIterator<Object>() {
@Override
public boolean hasNext() {
return false;
@@ -76,22 +70,6 @@ public final class Iterators {
public Object next() {
throw new NoSuchElementException();
}
- @Override
- public boolean hasPrevious() {
- return false;
- }
- @Override
- public Object previous() {
- throw new NoSuchElementException();
- }
- @Override
- public int nextIndex() {
- return 0;
- }
- @Override
- public int previousIndex() {
- return -1;
- }
};
/**
@@ -100,20 +78,10 @@ public final class Iterators {
* <p>The {@link Iterable} equivalent of this method is {@link
* ImmutableSet#of()}.
*/
- public static <T> UnmodifiableIterator<T> emptyIterator() {
- return emptyListIterator();
- }
-
- /**
- * Returns the empty iterator.
- *
- * <p>The {@link Iterable} equivalent of this method is {@link
- * ImmutableSet#of()}.
- */
// Casting to any type is safe since there are no actual elements.
@SuppressWarnings("unchecked")
- static <T> UnmodifiableListIterator<T> emptyListIterator() {
- return (UnmodifiableListIterator<T>) EMPTY_LIST_ITERATOR;
+ public static <T> UnmodifiableIterator<T> emptyIterator() {
+ return (UnmodifiableIterator<T>) EMPTY_ITERATOR;
}
private static final Iterator<Object> EMPTY_MODIFIABLE_ITERATOR =
@@ -307,11 +275,15 @@ public final class Iterators {
* {@code hasNext()} method will return {@code false}.
*/
public static String toString(Iterator<?> iterator) {
- return Joiner.on(", ")
- .useForNull("null")
- .appendTo(new StringBuilder().append('['), iterator)
- .append(']')
- .toString();
+ if (!iterator.hasNext()) {
+ return "[]";
+ }
+ StringBuilder builder = new StringBuilder();
+ builder.append('[').append(iterator.next());
+ while (iterator.hasNext()) {
+ builder.append(", ").append(iterator.next());
+ }
+ return builder.append(']').toString();
}
/**
@@ -347,8 +319,8 @@ public final class Iterators {
* @throws IllegalArgumentException if the iterator contains multiple
* elements. The state of the iterator is unspecified.
*/
- @Nullable
- public static <T> T getOnlyElement(Iterator<? extends T> iterator, @Nullable T defaultValue) {
+ public static <T> T getOnlyElement(
+ Iterator<T> iterator, @Nullable T defaultValue) {
return iterator.hasNext() ? getOnlyElement(iterator) : defaultValue;
}
@@ -459,8 +431,8 @@ public final class Iterators {
/**
* Returns an iterator that cycles indefinitely over the provided elements.
*
- * <p>The returned iterator supports {@code remove()}. After {@code remove()}
- * is called, subsequent cycles omit the removed
+ * <p>The returned iterator supports {@code remove()} if the provided iterator
+ * does. After {@code remove()} is called, subsequent cycles omit the removed
* element, but {@code elements} does not change. The iterator's
* {@code hasNext()} method returns {@code true} until all of the original
* elements have been removed.
@@ -480,11 +452,6 @@ public final class Iterators {
*
* <p>The returned iterator supports {@code remove()} when the corresponding
* input iterator supports it.
- *
- * <p><b>Note:</b> the current implementation is not suitable for nested
- * concatenated iterators, i.e. the following should be avoided when in a loop:
- * {@code iterator = Iterators.concat(iterator, suffix);}, since iteration over the
- * resulting iterator has a cubic complexity to the depth of the nesting.
*/
@SuppressWarnings("unchecked")
public static <T> Iterator<T> concat(Iterator<? extends T> a,
@@ -502,11 +469,6 @@ public final class Iterators {
*
* <p>The returned iterator supports {@code remove()} when the corresponding
* input iterator supports it.
- *
- * <p><b>Note:</b> the current implementation is not suitable for nested
- * concatenated iterators, i.e. the following should be avoided when in a loop:
- * {@code iterator = Iterators.concat(iterator, suffix);}, since iteration over the
- * resulting iterator has a cubic complexity to the depth of the nesting.
*/
@SuppressWarnings("unchecked")
public static <T> Iterator<T> concat(Iterator<? extends T> a,
@@ -525,11 +487,6 @@ public final class Iterators {
*
* <p>The returned iterator supports {@code remove()} when the corresponding
* input iterator supports it.
- *
- * <p><b>Note:</b> the current implementation is not suitable for nested
- * concatenated iterators, i.e. the following should be avoided when in a loop:
- * {@code iterator = Iterators.concat(iterator, suffix);}, since iteration over the
- * resulting iterator has a cubic complexity to the depth of the nesting.
*/
@SuppressWarnings("unchecked")
public static <T> Iterator<T> concat(Iterator<? extends T> a,
@@ -550,11 +507,6 @@ public final class Iterators {
* <p>The returned iterator supports {@code remove()} when the corresponding
* input iterator supports it.
*
- * <p><b>Note:</b> the current implementation is not suitable for nested
- * concatenated iterators, i.e. the following should be avoided when in a loop:
- * {@code iterator = Iterators.concat(iterator, suffix);}, since iteration over the
- * resulting iterator has a cubic complexity to the depth of the nesting.
- *
* @throws NullPointerException if any of the provided iterators is null
*/
public static <T> Iterator<T> concat(Iterator<? extends T>... inputs) {
@@ -569,11 +521,6 @@ public final class Iterators {
* <p>The returned iterator supports {@code remove()} when the corresponding
* input iterator supports it. The methods of the returned iterator may throw
* {@code NullPointerException} if any of the input iterators is null.
- *
- * <p><b>Note:</b> the current implementation is not suitable for nested
- * concatenated iterators, i.e. the following should be avoided when in a loop:
- * {@code iterator = Iterators.concat(iterator, suffix);}, since iteration over the
- * resulting iterator has a cubic complexity to the depth of the nesting.
*/
public static <T> Iterator<T> concat(
final Iterator<? extends Iterator<? extends T>> inputs) {
@@ -764,8 +711,8 @@ public final class Iterators {
* predicate; use this method only when such an element is known to exist. If
* no such element is found, the iterator will be left exhausted: its {@code
* hasNext()} method will return {@code false}. If it is possible that
- * <i>no</i> element will match, use {@link #tryFind} or {@link
- * #find(Iterator, Predicate, Object)} instead.
+ * <i>no</i> element will match, use {@link #tryFind)} or {@link
+ * #find(Iterator, Predicate, T)} instead.
*
* @throws NoSuchElementException if no element in {@code iterator} matches
* the given predicate
@@ -785,10 +732,9 @@ public final class Iterators {
*
* @since 7.0
*/
- @Nullable
- public static <T> T find(Iterator<? extends T> iterator, Predicate<? super T> predicate,
+ public static <T> T find(Iterator<T> iterator, Predicate<? super T> predicate,
@Nullable T defaultValue) {
- UnmodifiableIterator<? extends T> filteredIterator = filter(iterator, predicate);
+ UnmodifiableIterator<T> filteredIterator = filter(iterator, predicate);
return filteredIterator.hasNext() ? filteredIterator.next() : defaultValue;
}
@@ -853,12 +799,22 @@ public final class Iterators {
*/
public static <F, T> Iterator<T> transform(final Iterator<F> fromIterator,
final Function<? super F, ? extends T> function) {
+ checkNotNull(fromIterator);
checkNotNull(function);
- return new TransformedIterator<F, T>(fromIterator) {
+ return new Iterator<T>() {
+ @Override
+ public boolean hasNext() {
+ return fromIterator.hasNext();
+ }
@Override
- T transform(F from) {
+ public T next() {
+ F from = fromIterator.next();
return function.apply(from);
}
+ @Override
+ public void remove() {
+ fromIterator.remove();
+ }
};
}
@@ -910,8 +866,8 @@ public final class Iterators {
* @throws IndexOutOfBoundsException if {@code position} is negative
* @since 4.0
*/
- @Nullable
- public static <T> T get(Iterator<? extends T> iterator, int position, @Nullable T defaultValue) {
+ public static <T> T get(Iterator<T> iterator, int position,
+ @Nullable T defaultValue) {
checkNonnegative(position);
try {
@@ -930,8 +886,7 @@ public final class Iterators {
* @return the next element of {@code iterator} or the default value
* @since 7.0
*/
- @Nullable
- public static <T> T getNext(Iterator<? extends T> iterator, @Nullable T defaultValue) {
+ public static <T> T getNext(Iterator<T> iterator, @Nullable T defaultValue) {
return iterator.hasNext() ? iterator.next() : defaultValue;
}
@@ -958,24 +913,24 @@ public final class Iterators {
* @return the last element of {@code iterator}
* @since 3.0
*/
- @Nullable
- public static <T> T getLast(Iterator<? extends T> iterator, @Nullable T defaultValue) {
+ public static <T> T getLast(Iterator<T> iterator, @Nullable T defaultValue) {
return iterator.hasNext() ? getLast(iterator) : defaultValue;
}
/**
- * Calls {@code next()} on {@code iterator}, either {@code numberToAdvance} times
+ * Calls {@code next()} on {@code iterator}, either {@code numberToSkip} times
* or until {@code hasNext()} returns {@code false}, whichever comes first.
*
- * @return the number of elements the iterator was advanced
- * @since 13.0 (since 3.0 as {@code Iterators.skip})
+ * @return the number of elements skipped
+ * @since 3.0
*/
- public static int advance(Iterator<?> iterator, int numberToAdvance) {
+ @Beta
+ public static <T> int skip(Iterator<T> iterator, int numberToSkip) {
checkNotNull(iterator);
- checkArgument(numberToAdvance >= 0, "number to advance cannot be negative");
+ checkArgument(numberToSkip >= 0, "number to skip cannot be negative");
int i;
- for (i = 0; i < numberToAdvance && iterator.hasNext(); i++) {
+ for (i = 0; i < numberToSkip && iterator.hasNext(); i++) {
iterator.next();
}
return i;
@@ -1051,21 +1006,6 @@ public final class Iterators {
};
}
- /**
- * Deletes and returns the next value from the iterator, or returns
- * {@code defaultValue} if there is no such value.
- */
- @Nullable
- static <T> T pollNext(Iterator<T> iterator) {
- if (iterator.hasNext()) {
- T result = iterator.next();
- iterator.remove();
- return result;
- } else {
- return null;
- }
- }
-
// Methods only in Iterators, not in Iterables
/**
@@ -1103,14 +1043,21 @@ public final class Iterators {
}
/**
- * Returns a list iterator containing the elements in the specified range of
- * {@code array} in order, starting at the specified index.
+ * Returns an iterator containing the elements in the specified range of
+ * {@code array} in order. The returned iterator is a view of the array;
+ * subsequent changes to the array will be reflected in the iterator.
*
* <p>The {@code Iterable} equivalent of this method is {@code
- * Arrays.asList(array).subList(offset, offset + length).listIterator(index)}.
+ * Arrays.asList(array).subList(offset, offset + length)}.
+ *
+ * @param array array to read elements out of
+ * @param offset index of first array element to retrieve
+ * @param length number of elements in iteration
+ * @throws IndexOutOfBoundsException if {@code offset} is negative, {@code
+ * length} is negative, or {@code offset + length > array.length}
*/
- static <T> UnmodifiableListIterator<T> forArray(
- final T[] array, final int offset, int length, int index) {
+ static <T> UnmodifiableIterator<T> forArray(
+ final T[] array, final int offset, int length) {
checkArgument(length >= 0);
int end = offset + length;
@@ -1122,7 +1069,7 @@ public final class Iterators {
* because the returned Iterator is a ListIterator that may be moved back
* past the beginning of the iteration.
*/
- return new AbstractIndexedListIterator<T>(length, index) {
+ return new AbstractIndexedListIterator<T>(length) {
@Override protected T get(int index) {
return array[offset + index];
}
@@ -1379,19 +1326,4 @@ public final class Iterators {
return next;
}
}
-
- /**
- * Precondition tester for {@code Iterator.remove()} that throws an exception with a consistent
- * error message.
- */
- static void checkRemove(boolean canRemove) {
- checkState(canRemove, "no calls to next() since the last call to remove()");
- }
-
- /**
- * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
- */
- static <T> ListIterator<T> cast(Iterator<T> iterator) {
- return (ListIterator<T>) iterator;
- }
}
diff --git a/guava/src/com/google/common/collect/LinkedHashMultimap.java b/guava/src/com/google/common/collect/LinkedHashMultimap.java
index 47bbe6f..39c0bfb 100644
--- a/guava/src/com/google/common/collect/LinkedHashMultimap.java
+++ b/guava/src/com/google/common/collect/LinkedHashMultimap.java
@@ -16,24 +16,20 @@
package com.google.common.collect;
-import static com.google.common.base.Preconditions.checkArgument;
-
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.Ints;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.util.Arrays;
import java.util.Collection;
-import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
-import java.util.NoSuchElementException;
import java.util.Set;
import javax.annotation.Nullable;
@@ -69,23 +65,29 @@ import javax.annotation.Nullable;
* update operations, wrap your multimap with a call to {@link
* Multimaps#synchronizedSetMultimap}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap">
- * {@code Multimap}</a>.
- *
* @author Jared Levy
- * @author Louis Wasserman
* @since 2.0 (imported from Google Collections Library)
*/
@GwtCompatible(serializable = true, emulated = true)
public final class LinkedHashMultimap<K, V> extends AbstractSetMultimap<K, V> {
+ private static final int DEFAULT_VALUES_PER_KEY = 8;
+
+ @VisibleForTesting
+ transient int expectedValuesPerKey = DEFAULT_VALUES_PER_KEY;
+
+ /**
+ * Map entries with an iteration order corresponding to the order in which the
+ * key-value pairs were added to the multimap.
+ */
+ // package-private for GWT deserialization
+ transient Collection<Map.Entry<K, V>> linkedEntries;
/**
* Creates a new, empty {@code LinkedHashMultimap} with the default initial
* capacities.
*/
public static <K, V> LinkedHashMultimap<K, V> create() {
- return new LinkedHashMultimap<K, V>(DEFAULT_KEY_CAPACITY, DEFAULT_VALUE_SET_CAPACITY);
+ return new LinkedHashMultimap<K, V>();
}
/**
@@ -99,9 +101,7 @@ public final class LinkedHashMultimap<K, V> extends AbstractSetMultimap<K, V> {
*/
public static <K, V> LinkedHashMultimap<K, V> create(
int expectedKeys, int expectedValuesPerKey) {
- return new LinkedHashMultimap<K, V>(
- Maps.capacity(expectedKeys),
- Maps.capacity(expectedValuesPerKey));
+ return new LinkedHashMultimap<K, V>(expectedKeys, expectedValuesPerKey);
}
/**
@@ -115,158 +115,201 @@ public final class LinkedHashMultimap<K, V> extends AbstractSetMultimap<K, V> {
*/
public static <K, V> LinkedHashMultimap<K, V> create(
Multimap<? extends K, ? extends V> multimap) {
- LinkedHashMultimap<K, V> result = create(multimap.keySet().size(), DEFAULT_VALUE_SET_CAPACITY);
- result.putAll(multimap);
- return result;
- }
-
- private interface ValueSetLink<K, V> {
- ValueSetLink<K, V> getPredecessorInValueSet();
- ValueSetLink<K, V> getSuccessorInValueSet();
-
- void setPredecessorInValueSet(ValueSetLink<K, V> entry);
- void setSuccessorInValueSet(ValueSetLink<K, V> entry);
+ return new LinkedHashMultimap<K, V>(multimap);
}
- private static <K, V> void succeedsInValueSet(ValueSetLink<K, V> pred, ValueSetLink<K, V> succ) {
- pred.setSuccessorInValueSet(succ);
- succ.setPredecessorInValueSet(pred);
+ private LinkedHashMultimap() {
+ super(new LinkedHashMap<K, Collection<V>>());
+ linkedEntries = Sets.newLinkedHashSet();
}
- private static <K, V> void succeedsInMultimap(
- ValueEntry<K, V> pred, ValueEntry<K, V> succ) {
- pred.setSuccessorInMultimap(succ);
- succ.setPredecessorInMultimap(pred);
+ private LinkedHashMultimap(int expectedKeys, int expectedValuesPerKey) {
+ super(new LinkedHashMap<K, Collection<V>>(expectedKeys));
+ Preconditions.checkArgument(expectedValuesPerKey >= 0);
+ this.expectedValuesPerKey = expectedValuesPerKey;
+ linkedEntries = new LinkedHashSet<Map.Entry<K, V>>(
+ (int) Math.min(Ints.MAX_POWER_OF_TWO,
+ ((long) expectedKeys) * expectedValuesPerKey));
}
- private static <K, V> void deleteFromValueSet(ValueSetLink<K, V> entry) {
- succeedsInValueSet(entry.getPredecessorInValueSet(), entry.getSuccessorInValueSet());
+ private LinkedHashMultimap(Multimap<? extends K, ? extends V> multimap) {
+ super(new LinkedHashMap<K, Collection<V>>(
+ Maps.capacity(multimap.keySet().size())));
+ linkedEntries
+ = new LinkedHashSet<Map.Entry<K, V>>(Maps.capacity(multimap.size()));
+ putAll(multimap);
}
- private static <K, V> void deleteFromMultimap(ValueEntry<K, V> entry) {
- succeedsInMultimap(entry.getPredecessorInMultimap(), entry.getSuccessorInMultimap());
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Creates an empty {@code LinkedHashSet} for a collection of values for
+ * one key.
+ *
+ * @return a new {@code LinkedHashSet} containing a collection of values for
+ * one key
+ */
+ @Override Set<V> createCollection() {
+ return new LinkedHashSet<V>(Maps.capacity(expectedValuesPerKey));
}
/**
- * LinkedHashMultimap entries are in no less than three coexisting linked lists:
- * a row in the hash table for a Set<V> associated with a key, the linked list
- * of insertion-ordered entries in that Set<V>, and the linked list of entries
- * in the LinkedHashMultimap as a whole.
+ * {@inheritDoc}
+ *
+ * <p>Creates a decorated {@code LinkedHashSet} that also keeps track of the
+ * order in which key-value pairs are added to the multimap.
+ *
+ * @param key key to associate with values in the collection
+ * @return a new decorated {@code LinkedHashSet} containing a collection of
+ * values for one key
*/
- @VisibleForTesting
- static final class ValueEntry<K, V> extends AbstractMapEntry<K, V>
- implements ValueSetLink<K, V> {
- final K key;
- final V value;
- final int valueHash;
-
- @Nullable ValueEntry<K, V> nextInValueSetHashRow;
-
- ValueSetLink<K, V> predecessorInValueSet;
- ValueSetLink<K, V> successorInValueSet;
+ @Override Collection<V> createCollection(@Nullable K key) {
+ return new SetDecorator(key, createCollection());
+ }
- ValueEntry<K, V> predecessorInMultimap;
- ValueEntry<K, V> successorInMultimap;
+ private class SetDecorator extends ForwardingSet<V> {
+ final Set<V> delegate;
+ final K key;
- ValueEntry(@Nullable K key, @Nullable V value, int valueHash,
- @Nullable ValueEntry<K, V> nextInValueSetHashRow) {
+ SetDecorator(@Nullable K key, Set<V> delegate) {
+ this.delegate = delegate;
this.key = key;
- this.value = value;
- this.valueHash = valueHash;
- this.nextInValueSetHashRow = nextInValueSetHashRow;
}
- @Override
- public K getKey() {
- return key;
+ @Override protected Set<V> delegate() {
+ return delegate;
}
- @Override
- public V getValue() {
- return value;
+ <E> Map.Entry<K, E> createEntry(@Nullable E value) {
+ return Maps.immutableEntry(key, value);
}
- @Override
- public ValueSetLink<K, V> getPredecessorInValueSet() {
- return predecessorInValueSet;
+ <E> Collection<Map.Entry<K, E>> createEntries(Collection<E> values) {
+ // converts a collection of values into a list of key/value map entries
+ Collection<Map.Entry<K, E>> entries
+ = Lists.newArrayListWithExpectedSize(values.size());
+ for (E value : values) {
+ entries.add(createEntry(value));
+ }
+ return entries;
}
- @Override
- public ValueSetLink<K, V> getSuccessorInValueSet() {
- return successorInValueSet;
+ @Override public boolean add(@Nullable V value) {
+ boolean changed = delegate.add(value);
+ if (changed) {
+ linkedEntries.add(createEntry(value));
+ }
+ return changed;
}
- @Override
- public void setPredecessorInValueSet(ValueSetLink<K, V> entry) {
- predecessorInValueSet = entry;
+ @Override public boolean addAll(Collection<? extends V> values) {
+ boolean changed = delegate.addAll(values);
+ if (changed) {
+ linkedEntries.addAll(createEntries(delegate()));
+ }
+ return changed;
}
- @Override
- public void setSuccessorInValueSet(ValueSetLink<K, V> entry) {
- successorInValueSet = entry;
+ @Override public void clear() {
+ for (V value : delegate) {
+ linkedEntries.remove(createEntry(value));
+ }
+ delegate.clear();
}
- public ValueEntry<K, V> getPredecessorInMultimap() {
- return predecessorInMultimap;
- }
+ @Override public Iterator<V> iterator() {
+ final Iterator<V> delegateIterator = delegate.iterator();
+ return new Iterator<V>() {
+ V value;
- public ValueEntry<K, V> getSuccessorInMultimap() {
- return successorInMultimap;
+ @Override
+ public boolean hasNext() {
+ return delegateIterator.hasNext();
+ }
+ @Override
+ public V next() {
+ value = delegateIterator.next();
+ return value;
+ }
+ @Override
+ public void remove() {
+ delegateIterator.remove();
+ linkedEntries.remove(createEntry(value));
+ }
+ };
}
- public void setSuccessorInMultimap(ValueEntry<K, V> multimapSuccessor) {
- this.successorInMultimap = multimapSuccessor;
+ @Override public boolean remove(@Nullable Object value) {
+ boolean changed = delegate.remove(value);
+ if (changed) {
+ /*
+ * linkedEntries.remove() will return false when this method is called
+ * by entries().iterator().remove()
+ */
+ linkedEntries.remove(createEntry(value));
+ }
+ return changed;
}
- public void setPredecessorInMultimap(ValueEntry<K, V> multimapPredecessor) {
- this.predecessorInMultimap = multimapPredecessor;
+ @Override public boolean removeAll(Collection<?> values) {
+ boolean changed = delegate.removeAll(values);
+ if (changed) {
+ linkedEntries.removeAll(createEntries(values));
+ }
+ return changed;
}
- }
-
- private static final int DEFAULT_KEY_CAPACITY = 16;
- private static final int DEFAULT_VALUE_SET_CAPACITY = 2;
- @VisibleForTesting static final double VALUE_SET_LOAD_FACTOR = 1.0;
- @VisibleForTesting transient int valueSetCapacity = DEFAULT_VALUE_SET_CAPACITY;
- private transient ValueEntry<K, V> multimapHeaderEntry;
-
- private LinkedHashMultimap(int keyCapacity, int valueSetCapacity) {
- super(new LinkedHashMap<K, Collection<V>>(keyCapacity));
-
- checkArgument(valueSetCapacity >= 0,
- "expectedValuesPerKey must be >= 0 but was %s", valueSetCapacity);
-
- this.valueSetCapacity = valueSetCapacity;
- this.multimapHeaderEntry = new ValueEntry<K, V>(null, null, 0, null);
- succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry);
+ @Override public boolean retainAll(Collection<?> values) {
+ /*
+ * Calling linkedEntries.retainAll() would incorrectly remove values
+ * with other keys.
+ */
+ boolean changed = false;
+ Iterator<V> iterator = delegate.iterator();
+ while (iterator.hasNext()) {
+ V value = iterator.next();
+ if (!values.contains(value)) {
+ iterator.remove();
+ linkedEntries.remove(Maps.immutableEntry(key, value));
+ changed = true;
+ }
+ }
+ return changed;
+ }
}
/**
* {@inheritDoc}
*
- * <p>Creates an empty {@code LinkedHashSet} for a collection of values for
- * one key.
+ * <p>Generates an iterator across map entries that follows the ordering in
+ * which the key-value pairs were added to the multimap.
*
- * @return a new {@code LinkedHashSet} containing a collection of values for
- * one key
+ * @return a key-value iterator with the correct ordering
*/
- @Override
- Set<V> createCollection() {
- return new LinkedHashSet<V>(valueSetCapacity);
- }
+ @Override Iterator<Map.Entry<K, V>> createEntryIterator() {
+ final Iterator<Map.Entry<K, V>> delegateIterator = linkedEntries.iterator();
- /**
- * {@inheritDoc}
- *
- * <p>Creates a decorated insertion-ordered set that also keeps track of the
- * order in which key-value pairs are added to the multimap.
- *
- * @param key key to associate with values in the collection
- * @return a new decorated set containing a collection of values for one key
- */
- @Override
- Collection<V> createCollection(K key) {
- return new ValueSet(key, valueSetCapacity);
+ return new Iterator<Map.Entry<K, V>>() {
+ Map.Entry<K, V> entry;
+
+ @Override
+ public boolean hasNext() {
+ return delegateIterator.hasNext();
+ }
+
+ @Override
+ public Map.Entry<K, V> next() {
+ entry = delegateIterator.next();
+ return entry;
+ }
+
+ @Override
+ public void remove() {
+ // Remove from iterator first to keep iterator valid.
+ delegateIterator.remove();
+ LinkedHashMultimap.this.remove(entry.getKey(), entry.getValue());
+ }
+ };
}
/**
@@ -277,8 +320,8 @@ public final class LinkedHashMultimap<K, V> extends AbstractSetMultimap<K, V> {
* However, the provided values always come last in the {@link #entries()} and
* {@link #values()} iteration orderings.
*/
- @Override
- public Set<V> replaceValues(@Nullable K key, Iterable<? extends V> values) {
+ @Override public Set<V> replaceValues(
+ @Nullable K key, Iterable<? extends V> values) {
return super.replaceValues(key, values);
}
@@ -309,265 +352,20 @@ public final class LinkedHashMultimap<K, V> extends AbstractSetMultimap<K, V> {
return super.values();
}
- @VisibleForTesting
- final class ValueSet extends Sets.ImprovedAbstractSet<V> implements ValueSetLink<K, V> {
- /*
- * We currently use a fixed load factor of 1.0, a bit higher than normal to reduce memory
- * consumption.
- */
-
- private final K key;
- @VisibleForTesting ValueEntry<K, V>[] hashTable;
- private int size = 0;
- private int modCount = 0;
-
- // We use the set object itself as the end of the linked list, avoiding an unnecessary
- // entry object per key.
- private ValueSetLink<K, V> firstEntry;
- private ValueSetLink<K, V> lastEntry;
-
- ValueSet(K key, int expectedValues) {
- this.key = key;
- this.firstEntry = this;
- this.lastEntry = this;
- // Round expected values up to a power of 2 to get the table size.
- int tableSize = Hashing.closedTableSize(expectedValues, VALUE_SET_LOAD_FACTOR);
-
- @SuppressWarnings("unchecked")
- ValueEntry<K, V>[] hashTable = new ValueEntry[tableSize];
- this.hashTable = hashTable;
- }
-
- @Override
- public ValueSetLink<K, V> getPredecessorInValueSet() {
- return lastEntry;
- }
-
- @Override
- public ValueSetLink<K, V> getSuccessorInValueSet() {
- return firstEntry;
- }
-
- @Override
- public void setPredecessorInValueSet(ValueSetLink<K, V> entry) {
- lastEntry = entry;
- }
-
- @Override
- public void setSuccessorInValueSet(ValueSetLink<K, V> entry) {
- firstEntry = entry;
- }
-
- @Override
- public Iterator<V> iterator() {
- return new Iterator<V>() {
- ValueSetLink<K, V> nextEntry = firstEntry;
- ValueEntry<K, V> toRemove;
- int expectedModCount = modCount;
-
- private void checkForComodification() {
- if (modCount != expectedModCount) {
- throw new ConcurrentModificationException();
- }
- }
-
- @Override
- public boolean hasNext() {
- checkForComodification();
- return nextEntry != ValueSet.this;
- }
-
- @Override
- public V next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- ValueEntry<K, V> entry = (ValueEntry<K, V>) nextEntry;
- V result = entry.getValue();
- toRemove = entry;
- nextEntry = entry.getSuccessorInValueSet();
- return result;
- }
-
- @Override
- public void remove() {
- checkForComodification();
- Iterators.checkRemove(toRemove != null);
- Object o = toRemove.getValue();
- int hash = (o == null) ? 0 : o.hashCode();
- int row = Hashing.smear(hash) & (hashTable.length - 1);
- ValueEntry<K, V> prev = null;
- for (ValueEntry<K, V> entry = hashTable[row]; entry != null;
- prev = entry, entry = entry.nextInValueSetHashRow) {
- if (entry == toRemove) {
- if (prev == null) {
- // first entry in row
- hashTable[row] = entry.nextInValueSetHashRow;
- } else {
- prev.nextInValueSetHashRow = entry.nextInValueSetHashRow;
- }
- deleteFromValueSet(toRemove);
- deleteFromMultimap(toRemove);
- size--;
- expectedModCount = ++modCount;
- break;
- }
- }
- toRemove = null;
- }
- };
- }
-
- @Override
- public int size() {
- return size;
- }
-
- @Override
- public boolean contains(@Nullable Object o) {
- int hash = (o == null) ? 0 : o.hashCode();
- int row = Hashing.smear(hash) & (hashTable.length - 1);
-
- for (ValueEntry<K, V> entry = hashTable[row]; entry != null;
- entry = entry.nextInValueSetHashRow) {
- if (hash == entry.valueHash && Objects.equal(o, entry.getValue())) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean add(@Nullable V value) {
- int hash = (value == null) ? 0 : value.hashCode();
- int row = Hashing.smear(hash) & (hashTable.length - 1);
-
- ValueEntry<K, V> rowHead = hashTable[row];
- for (ValueEntry<K, V> entry = rowHead; entry != null;
- entry = entry.nextInValueSetHashRow) {
- if (hash == entry.valueHash && Objects.equal(value, entry.getValue())) {
- return false;
- }
- }
-
- ValueEntry<K, V> newEntry = new ValueEntry<K, V>(key, value, hash, rowHead);
- succeedsInValueSet(lastEntry, newEntry);
- succeedsInValueSet(newEntry, this);
- succeedsInMultimap(multimapHeaderEntry.getPredecessorInMultimap(), newEntry);
- succeedsInMultimap(newEntry, multimapHeaderEntry);
- hashTable[row] = newEntry;
- size++;
- modCount++;
- rehashIfNecessary();
- return true;
- }
-
- private void rehashIfNecessary() {
- if (Hashing.needsResizing(size, hashTable.length, VALUE_SET_LOAD_FACTOR)) {
- @SuppressWarnings("unchecked")
- ValueEntry<K, V>[] hashTable = new ValueEntry[this.hashTable.length * 2];
- this.hashTable = hashTable;
- int mask = hashTable.length - 1;
- for (ValueSetLink<K, V> entry = firstEntry;
- entry != this; entry = entry.getSuccessorInValueSet()) {
- ValueEntry<K, V> valueEntry = (ValueEntry<K, V>) entry;
- int row = Hashing.smear(valueEntry.valueHash) & mask;
- valueEntry.nextInValueSetHashRow = hashTable[row];
- hashTable[row] = valueEntry;
- }
- }
- }
-
- @Override
- public boolean remove(@Nullable Object o) {
- int hash = (o == null) ? 0 : o.hashCode();
- int row = Hashing.smear(hash) & (hashTable.length - 1);
-
- ValueEntry<K, V> prev = null;
- for (ValueEntry<K, V> entry = hashTable[row]; entry != null;
- prev = entry, entry = entry.nextInValueSetHashRow) {
- if (hash == entry.valueHash && Objects.equal(o, entry.getValue())) {
- if (prev == null) {
- // first entry in the row
- hashTable[row] = entry.nextInValueSetHashRow;
- } else {
- prev.nextInValueSetHashRow = entry.nextInValueSetHashRow;
- }
- deleteFromValueSet(entry);
- deleteFromMultimap(entry);
- size--;
- modCount++;
- return true;
- }
- }
- return false;
- }
-
- @Override
- public void clear() {
- Arrays.fill(hashTable, null);
- size = 0;
- for (ValueSetLink<K, V> entry = firstEntry;
- entry != this; entry = entry.getSuccessorInValueSet()) {
- ValueEntry<K, V> valueEntry = (ValueEntry<K, V>) entry;
- deleteFromMultimap(valueEntry);
- }
- succeedsInValueSet(this, this);
- modCount++;
- }
- }
-
- @Override
- Iterator<Map.Entry<K, V>> entryIterator() {
- return new Iterator<Map.Entry<K, V>>() {
- ValueEntry<K, V> nextEntry = multimapHeaderEntry.successorInMultimap;
- ValueEntry<K, V> toRemove;
-
- @Override
- public boolean hasNext() {
- return nextEntry != multimapHeaderEntry;
- }
-
- @Override
- public Map.Entry<K, V> next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- ValueEntry<K, V> result = nextEntry;
- toRemove = result;
- nextEntry = nextEntry.successorInMultimap;
- return result;
- }
-
- @Override
- public void remove() {
- Iterators.checkRemove(toRemove != null);
- LinkedHashMultimap.this.remove(toRemove.getKey(), toRemove.getValue());
- toRemove = null;
- }
- };
- }
-
- @Override
- public void clear() {
- super.clear();
- succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry);
- }
+ // Unfortunately, the entries() ordering does not determine the key ordering;
+ // see the example in the LinkedListMultimap class Javadoc.
/**
- * @serialData the expected values per key, the number of distinct keys,
- * the number of entries, and the entries in order
+ * @serialData the number of distinct keys, and then for each distinct key:
+ * the first key, the number of values for that key, and the key's values,
+ * followed by successive keys and values from the entries() ordering
*/
@GwtIncompatible("java.io.ObjectOutputStream")
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.defaultWriteObject();
- stream.writeInt(valueSetCapacity);
- stream.writeInt(keySet().size());
- for (K key : keySet()) {
- stream.writeObject(key);
- }
- stream.writeInt(size());
- for (Map.Entry<K, V> entry : entries()) {
+ stream.writeInt(expectedValuesPerKey);
+ Serialization.writeMultimap(this, stream);
+ for (Map.Entry<K, V> entry : linkedEntries) {
stream.writeObject(entry.getKey());
stream.writeObject(entry.getValue());
}
@@ -577,28 +375,22 @@ public final class LinkedHashMultimap<K, V> extends AbstractSetMultimap<K, V> {
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
- multimapHeaderEntry = new ValueEntry<K, V>(null, null, 0, null);
- succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry);
- valueSetCapacity = stream.readInt();
- int distinctKeys = stream.readInt();
- Map<K, Collection<V>> map =
- new LinkedHashMap<K, Collection<V>>(Maps.capacity(distinctKeys));
- for (int i = 0; i < distinctKeys; i++) {
- @SuppressWarnings("unchecked")
- K key = (K) stream.readObject();
- map.put(key, createCollection(key));
- }
- int entries = stream.readInt();
- for (int i = 0; i < entries; i++) {
- @SuppressWarnings("unchecked")
+ expectedValuesPerKey = stream.readInt();
+ int distinctKeys = Serialization.readCount(stream);
+ setMap(new LinkedHashMap<K, Collection<V>>(Maps.capacity(distinctKeys)));
+ linkedEntries = new LinkedHashSet<Map.Entry<K, V>>(
+ distinctKeys * expectedValuesPerKey);
+ Serialization.populateMultimap(this, stream, distinctKeys);
+ linkedEntries.clear(); // will clear and repopulate entries
+ for (int i = 0; i < size(); i++) {
+ @SuppressWarnings("unchecked") // reading data stored by writeObject
K key = (K) stream.readObject();
- @SuppressWarnings("unchecked")
+ @SuppressWarnings("unchecked") // reading data stored by writeObject
V value = (V) stream.readObject();
- map.get(key).add(value);
+ linkedEntries.add(Maps.immutableEntry(key, value));
}
- setMap(map);
}
@GwtIncompatible("java serialization not supported")
- private static final long serialVersionUID = 1;
+ private static final long serialVersionUID = 0;
}
diff --git a/guava/src/com/google/common/collect/LinkedHashMultiset.java b/guava/src/com/google/common/collect/LinkedHashMultiset.java
index 9b8c45b..c8db8e2 100644
--- a/guava/src/com/google/common/collect/LinkedHashMultiset.java
+++ b/guava/src/com/google/common/collect/LinkedHashMultiset.java
@@ -31,10 +31,6 @@ import java.util.LinkedHashMap;
* element, those instances are consecutive in the iteration order. If all
* occurrences of an element are removed, after which that element is added to
* the multiset, the element will appear at the end of the iteration.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset">
- * {@code Multiset}</a>.
*
* @author Kevin Bourrillion
* @author Jared Levy
diff --git a/guava/src/com/google/common/collect/LinkedListMultimap.java b/guava/src/com/google/common/collect/LinkedListMultimap.java
index 0a7b100..336ca72 100644
--- a/guava/src/com/google/common/collect/LinkedListMultimap.java
+++ b/guava/src/com/google/common/collect/LinkedListMultimap.java
@@ -17,7 +17,9 @@
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Multisets.setCountImpl;
import static java.util.Collections.unmodifiableList;
import com.google.common.annotations.GwtCompatible;
@@ -29,10 +31,11 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import java.util.AbstractCollection;
+import java.util.AbstractMap;
import java.util.AbstractSequentialList;
+import java.util.AbstractSet;
import java.util.Collection;
-import java.util.ConcurrentModificationException;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
@@ -92,10 +95,6 @@ import javax.annotation.Nullable;
* update operations, wrap your multimap with a call to {@link
* Multimaps#synchronizedListMultimap}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap">
- * {@code Multimap}</a>.
- *
* @author Mike Bostock
* @since 2.0 (imported from Google Collections Library)
*/
@@ -126,32 +125,12 @@ public class LinkedListMultimap<K, V>
return key + "=" + value;
}
}
-
- private static class KeyList<K, V> {
- Node<K, V> head;
- Node<K, V> tail;
- int count;
-
- KeyList(Node<K, V> firstNode) {
- this.head = firstNode;
- this.tail = firstNode;
- firstNode.previousSibling = null;
- firstNode.nextSibling = null;
- this.count = 1;
- }
- }
private transient Node<K, V> head; // the head for all keys
private transient Node<K, V> tail; // the tail for all keys
- private transient Map<K, KeyList<K, V>> keyToKeyList;
- private transient int size;
-
- /*
- * Tracks modifications to keyToKeyList so that addition or removal of keys invalidates
- * preexisting iterators. This does *not* track simple additions and removals of values
- * that are not the first to be added or last to be removed for their key.
- */
- private transient int modCount;
+ private transient Multiset<K> keyCount; // the number of values for each key
+ private transient Map<K, Node<K, V>> keyToKeyHead; // the head for a given key
+ private transient Map<K, Node<K, V>> keyToKeyTail; // the tail for a given key
/**
* Creates a new, empty {@code LinkedListMultimap} with the default initial
@@ -185,11 +164,15 @@ public class LinkedListMultimap<K, V>
}
LinkedListMultimap() {
- keyToKeyList = Maps.newHashMap();
+ keyCount = LinkedHashMultiset.create();
+ keyToKeyHead = Maps.newHashMap();
+ keyToKeyTail = Maps.newHashMap();
}
private LinkedListMultimap(int expectedKeys) {
- keyToKeyList = new HashMap<K, KeyList<K, V>>(expectedKeys);
+ keyCount = LinkedHashMultiset.create(expectedKeys);
+ keyToKeyHead = Maps.newHashMapWithExpectedSize(expectedKeys);
+ keyToKeyTail = Maps.newHashMapWithExpectedSize(expectedKeys);
}
private LinkedListMultimap(Multimap<? extends K, ? extends V> multimap) {
@@ -208,32 +191,27 @@ public class LinkedListMultimap<K, V>
Node<K, V> node = new Node<K, V>(key, value);
if (head == null) { // empty list
head = tail = node;
- keyToKeyList.put(key, new KeyList<K, V>(node));
- modCount++;
+ keyToKeyHead.put(key, node);
+ keyToKeyTail.put(key, node);
} else if (nextSibling == null) { // non-empty list, add to tail
tail.next = node;
node.previous = tail;
- tail = node;
- KeyList<K, V> keyList = keyToKeyList.get(key);
- if (keyList == null) {
- keyToKeyList.put(key, keyList = new KeyList<K, V>(node));
- modCount++;
+ Node<K, V> keyTail = keyToKeyTail.get(key);
+ if (keyTail == null) { // first for this key
+ keyToKeyHead.put(key, node);
} else {
- keyList.count++;
- Node<K, V> keyTail = keyList.tail;
keyTail.nextSibling = node;
node.previousSibling = keyTail;
- keyList.tail = node;
}
+ keyToKeyTail.put(key, node);
+ tail = node;
} else { // non-empty list, insert before nextSibling
- KeyList<K, V> keyList = keyToKeyList.get(key);
- keyList.count++;
node.previous = nextSibling.previous;
node.previousSibling = nextSibling.previousSibling;
node.next = nextSibling;
node.nextSibling = nextSibling;
if (nextSibling.previousSibling == null) { // nextSibling was key head
- keyToKeyList.get(key).head = node;
+ keyToKeyHead.put(key, node);
} else {
nextSibling.previousSibling.nextSibling = node;
}
@@ -245,7 +223,7 @@ public class LinkedListMultimap<K, V>
nextSibling.previous = node;
nextSibling.previousSibling = node;
}
- size++;
+ keyCount.add(key);
return node;
}
@@ -265,27 +243,21 @@ public class LinkedListMultimap<K, V>
} else { // node was tail
tail = node.previous;
}
- if (node.previousSibling == null && node.nextSibling == null) {
- KeyList<K, V> keyList = keyToKeyList.remove(node.key);
- keyList.count = 0;
- modCount++;
+ if (node.previousSibling != null) {
+ node.previousSibling.nextSibling = node.nextSibling;
+ } else if (node.nextSibling != null) { // node was key head
+ keyToKeyHead.put(node.key, node.nextSibling);
} else {
- KeyList<K, V> keyList = keyToKeyList.get(node.key);
- keyList.count--;
-
- if (node.previousSibling == null) {
- keyList.head = node.nextSibling;
- } else {
- node.previousSibling.nextSibling = node.nextSibling;
- }
-
- if (node.nextSibling == null) {
- keyList.tail = node.previousSibling;
- } else {
- node.nextSibling.previousSibling = node.previousSibling;
- }
+ keyToKeyHead.remove(node.key); // don't leak a key-null entry
}
- size--;
+ if (node.nextSibling != null) {
+ node.nextSibling.previousSibling = node.previousSibling;
+ } else if (node.previousSibling != null) { // node was key tail
+ keyToKeyTail.put(node.key, node.previousSibling);
+ } else {
+ keyToKeyTail.remove(node.key); // don't leak a key-null entry
+ }
+ keyCount.remove(node.key);
}
/** Removes all nodes for the specified key. */
@@ -309,7 +281,6 @@ public class LinkedListMultimap<K, V>
Node<K, V> next;
Node<K, V> current;
Node<K, V> previous;
- int expectedModCount = modCount;
NodeIterator() {
next = head;
@@ -331,19 +302,12 @@ public class LinkedListMultimap<K, V>
}
current = null;
}
- private void checkForConcurrentModification() {
- if (modCount != expectedModCount) {
- throw new ConcurrentModificationException();
- }
- }
@Override
public boolean hasNext() {
- checkForConcurrentModification();
return next != null;
}
@Override
public Node<K, V> next() {
- checkForConcurrentModification();
checkElement(next);
previous = current = next;
next = next.next;
@@ -352,7 +316,6 @@ public class LinkedListMultimap<K, V>
}
@Override
public void remove() {
- checkForConcurrentModification();
checkState(current != null);
if (current != next) { // after call to next()
previous = current.previous;
@@ -362,16 +325,13 @@ public class LinkedListMultimap<K, V>
}
removeNode(current);
current = null;
- expectedModCount = modCount;
}
@Override
public boolean hasPrevious() {
- checkForConcurrentModification();
return previous != null;
}
@Override
public Node<K, V> previous() {
- checkForConcurrentModification();
checkElement(previous);
next = current = previous;
previous = previous.previous;
@@ -405,21 +365,13 @@ public class LinkedListMultimap<K, V>
final Set<K> seenKeys = Sets.<K>newHashSetWithExpectedSize(keySet().size());
Node<K, V> next = head;
Node<K, V> current;
- int expectedModCount = modCount;
-
- private void checkForConcurrentModification() {
- if (modCount != expectedModCount) {
- throw new ConcurrentModificationException();
- }
- }
+
@Override
public boolean hasNext() {
- checkForConcurrentModification();
return next != null;
}
@Override
public K next() {
- checkForConcurrentModification();
checkElement(next);
current = next;
seenKeys.add(current.key);
@@ -430,11 +382,9 @@ public class LinkedListMultimap<K, V>
}
@Override
public void remove() {
- checkForConcurrentModification();
checkState(current != null);
removeAllNodes(current.key);
current = null;
- expectedModCount = modCount;
}
}
@@ -449,8 +399,7 @@ public class LinkedListMultimap<K, V>
/** Constructs a new iterator over all values for the specified key. */
ValueForKeyIterator(@Nullable Object key) {
this.key = key;
- KeyList<K, V> keyList = keyToKeyList.get(key);
- next = (keyList == null) ? null : keyList.head;
+ next = keyToKeyHead.get(key);
}
/**
@@ -463,17 +412,16 @@ public class LinkedListMultimap<K, V>
* @throws IndexOutOfBoundsException if index is invalid
*/
public ValueForKeyIterator(@Nullable Object key, int index) {
- KeyList<K, V> keyList = keyToKeyList.get(key);
- int size = (keyList == null) ? 0 : keyList.count;
+ int size = keyCount.count(key);
Preconditions.checkPositionIndex(index, size);
if (index >= (size / 2)) {
- previous = (keyList == null) ? null : keyList.tail;
+ previous = keyToKeyTail.get(key);
nextIndex = size;
while (index++ < size) {
previous();
}
} else {
- next = (keyList == null) ? null : keyList.head;
+ next = keyToKeyHead.get(key);
while (index-- > 0) {
next();
}
@@ -552,7 +500,7 @@ public class LinkedListMultimap<K, V>
@Override
public int size() {
- return size;
+ return keyCount.size();
}
@Override
@@ -562,7 +510,7 @@ public class LinkedListMultimap<K, V>
@Override
public boolean containsKey(@Nullable Object key) {
- return keyToKeyList.containsKey(key);
+ return keyToKeyHead.containsKey(key);
}
@Override
@@ -689,9 +637,9 @@ public class LinkedListMultimap<K, V>
public void clear() {
head = null;
tail = null;
- keyToKeyList.clear();
- size = 0;
- modCount++;
+ keyCount.clear();
+ keyToKeyHead.clear();
+ keyToKeyTail.clear();
}
// Views
@@ -709,8 +657,7 @@ public class LinkedListMultimap<K, V>
public List<V> get(final @Nullable K key) {
return new AbstractSequentialList<V>() {
@Override public int size() {
- KeyList<K, V> keyList = keyToKeyList.get(key);
- return (keyList == null) ? 0 : keyList.count;
+ return keyCount.count(key);
}
@Override public ListIterator<V> listIterator(int index) {
return new ValueForKeyIterator(key, index);
@@ -730,19 +677,19 @@ public class LinkedListMultimap<K, V>
public Set<K> keySet() {
Set<K> result = keySet;
if (result == null) {
- keySet = result = new Sets.ImprovedAbstractSet<K>() {
+ keySet = result = new AbstractSet<K>() {
@Override public int size() {
- return keyToKeyList.size();
+ return keyCount.elementSet().size();
}
@Override public Iterator<K> iterator() {
return new DistinctKeyIterator();
}
@Override public boolean contains(Object key) { // for performance
- return containsKey(key);
+ return keyCount.contains(key);
}
- @Override
- public boolean remove(Object o) { // for performance
- return !LinkedListMultimap.this.removeAll(o).isEmpty();
+ @Override public boolean removeAll(Collection<?> c) {
+ checkNotNull(c); // eager for GWT
+ return super.removeAll(c);
}
};
}
@@ -760,50 +707,39 @@ public class LinkedListMultimap<K, V>
return result;
}
- private class MultisetView extends AbstractMultiset<K> {
- @Override
- public int size() {
- return size;
- }
+ private class MultisetView extends AbstractCollection<K>
+ implements Multiset<K> {
- @Override
- public int count(Object element) {
- KeyList<K, V> keyList = keyToKeyList.get(element);
- return (keyList == null) ? 0 : keyList.count;
+ @Override public int size() {
+ return keyCount.size();
}
- @Override
- Iterator<Entry<K>> entryIterator() {
- return new TransformedIterator<K, Entry<K>>(new DistinctKeyIterator()) {
+ @Override public Iterator<K> iterator() {
+ final Iterator<Node<K, V>> nodes = new NodeIterator();
+ return new Iterator<K>() {
@Override
- Entry<K> transform(final K key) {
- return new Multisets.AbstractEntry<K>() {
- @Override
- public K getElement() {
- return key;
- }
-
- @Override
- public int getCount() {
- return keyToKeyList.get(key).count;
- }
- };
+ public boolean hasNext() {
+ return nodes.hasNext();
+ }
+ @Override
+ public K next() {
+ return nodes.next().key;
+ }
+ @Override
+ public void remove() {
+ nodes.remove();
}
};
}
@Override
- int distinctElements() {
- return elementSet().size();
+ public int count(@Nullable Object key) {
+ return keyCount.count(key);
}
- @Override public Iterator<K> iterator() {
- return new TransformedIterator<Node<K, V>, K>(new NodeIterator()) {
- @Override
- K transform(Node<K, V> node) {
- return node.key;
- }
- };
+ @Override
+ public int add(@Nullable K key, int occurrences) {
+ throw new UnsupportedOperationException();
}
@Override
@@ -819,9 +755,77 @@ public class LinkedListMultimap<K, V>
}
@Override
+ public int setCount(K element, int count) {
+ return setCountImpl(this, element, count);
+ }
+
+ @Override
+ public boolean setCount(K element, int oldCount, int newCount) {
+ return setCountImpl(this, element, oldCount, newCount);
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ return Iterators.removeAll(iterator(), c);
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ return Iterators.retainAll(iterator(), c);
+ }
+
+ @Override
public Set<K> elementSet() {
return keySet();
}
+
+ @Override
+ public Set<Entry<K>> entrySet() {
+ // TODO(jlevy): lazy init?
+ return new AbstractSet<Entry<K>>() {
+ @Override public int size() {
+ return keyCount.elementSet().size();
+ }
+
+ @Override public Iterator<Entry<K>> iterator() {
+ final Iterator<K> keyIterator = new DistinctKeyIterator();
+ return new Iterator<Entry<K>>() {
+ @Override
+ public boolean hasNext() {
+ return keyIterator.hasNext();
+ }
+ @Override
+ public Entry<K> next() {
+ final K key = keyIterator.next();
+ return new Multisets.AbstractEntry<K>() {
+ @Override
+ public K getElement() {
+ return key;
+ }
+ @Override
+ public int getCount() {
+ return keyCount.count(key);
+ }
+ };
+ }
+ @Override
+ public void remove() {
+ keyIterator.remove();
+ }
+ };
+ }
+ };
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ return keyCount.equals(object);
+ }
+
+ @Override public int hashCode() {
+ return keyCount.hashCode();
+ }
+
+ @Override public String toString() {
+ return keyCount.toString(); // XXX observe order?
+ }
}
private transient List<V> valuesList;
@@ -841,20 +845,47 @@ public class LinkedListMultimap<K, V>
if (result == null) {
valuesList = result = new AbstractSequentialList<V>() {
@Override public int size() {
- return size;
+ return keyCount.size();
}
@Override
public ListIterator<V> listIterator(int index) {
final NodeIterator nodes = new NodeIterator(index);
- return new TransformedListIterator<Node<K, V>, V>(nodes) {
+ return new ListIterator<V>() {
@Override
- V transform(Node<K, V> node) {
- return node.value;
+ public boolean hasNext() {
+ return nodes.hasNext();
+ }
+ @Override
+ public V next() {
+ return nodes.next().value;
+ }
+ @Override
+ public boolean hasPrevious() {
+ return nodes.hasPrevious();
+ }
+ @Override
+ public V previous() {
+ return nodes.previous().value;
}
-
@Override
- public void set(V value) {
- nodes.setValue(value);
+ public int nextIndex() {
+ return nodes.nextIndex();
+ }
+ @Override
+ public int previousIndex() {
+ return nodes.previousIndex();
+ }
+ @Override
+ public void remove() {
+ nodes.remove();
+ }
+ @Override
+ public void set(V e) {
+ nodes.setValue(e);
+ }
+ @Override
+ public void add(V e) {
+ throw new UnsupportedOperationException();
}
};
}
@@ -905,14 +936,55 @@ public class LinkedListMultimap<K, V>
if (result == null) {
entries = result = new AbstractSequentialList<Entry<K, V>>() {
@Override public int size() {
- return size;
+ return keyCount.size();
}
@Override public ListIterator<Entry<K, V>> listIterator(int index) {
- return new TransformedListIterator<Node<K, V>, Entry<K, V>>(new NodeIterator(index)) {
+ final ListIterator<Node<K, V>> nodes = new NodeIterator(index);
+ return new ListIterator<Entry<K, V>>() {
+ @Override
+ public boolean hasNext() {
+ return nodes.hasNext();
+ }
+
+ @Override
+ public Entry<K, V> next() {
+ return createEntry(nodes.next());
+ }
+
+ @Override
+ public void remove() {
+ nodes.remove();
+ }
+
+ @Override
+ public boolean hasPrevious() {
+ return nodes.hasPrevious();
+ }
+
+ @Override
+ public Map.Entry<K, V> previous() {
+ return createEntry(nodes.previous());
+ }
+
+ @Override
+ public int nextIndex() {
+ return nodes.nextIndex();
+ }
+
+ @Override
+ public int previousIndex() {
+ return nodes.previousIndex();
+ }
+
+ @Override
+ public void set(Map.Entry<K, V> e) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
- Entry<K, V> transform(Node<K, V> node) {
- return createEntry(node);
+ public void add(Map.Entry<K, V> e) {
+ throw new UnsupportedOperationException();
}
};
}
@@ -921,39 +993,75 @@ public class LinkedListMultimap<K, V>
return result;
}
+ private class AsMapEntries extends AbstractSet<Entry<K, Collection<V>>> {
+ @Override public int size() {
+ return keyCount.elementSet().size();
+ }
+
+ @Override public Iterator<Entry<K, Collection<V>>> iterator() {
+ final Iterator<K> keyIterator = new DistinctKeyIterator();
+ return new Iterator<Entry<K, Collection<V>>>() {
+ @Override
+ public boolean hasNext() {
+ return keyIterator.hasNext();
+ }
+
+ @Override
+ public Entry<K, Collection<V>> next() {
+ final K key = keyIterator.next();
+ return new AbstractMapEntry<K, Collection<V>>() {
+ @Override public K getKey() {
+ return key;
+ }
+
+ @Override public Collection<V> getValue() {
+ return LinkedListMultimap.this.get(key);
+ }
+ };
+ }
+
+ @Override
+ public void remove() {
+ keyIterator.remove();
+ }
+ };
+ }
+
+ // TODO(jlevy): Override contains() and remove() for better performance.
+ }
+
private transient Map<K, Collection<V>> map;
@Override
public Map<K, Collection<V>> asMap() {
Map<K, Collection<V>> result = map;
if (result == null) {
- map = result = new Multimaps.AsMap<K, V>() {
- @Override
- public int size() {
- return keyToKeyList.size();
+ map = result = new AbstractMap<K, Collection<V>>() {
+ Set<Entry<K, Collection<V>>> entrySet;
+
+ @Override public Set<Entry<K, Collection<V>>> entrySet() {
+ Set<Entry<K, Collection<V>>> result = entrySet;
+ if (result == null) {
+ entrySet = result = new AsMapEntries();
+ }
+ return result;
}
- @Override
- Multimap<K, V> multimap() {
- return LinkedListMultimap.this;
+ // The following methods are included for performance.
+
+ @Override public boolean containsKey(@Nullable Object key) {
+ return LinkedListMultimap.this.containsKey(key);
}
- @Override
- Iterator<Entry<K, Collection<V>>> entryIterator() {
- return new TransformedIterator<K, Entry<K, Collection<V>>>(new DistinctKeyIterator()) {
- @Override
- Entry<K, Collection<V>> transform(final K key) {
- return new AbstractMapEntry<K, Collection<V>>() {
- @Override public K getKey() {
- return key;
- }
+ @SuppressWarnings("unchecked")
+ @Override public Collection<V> get(@Nullable Object key) {
+ Collection<V> collection = LinkedListMultimap.this.get((K) key);
+ return collection.isEmpty() ? null : collection;
+ }
- @Override public Collection<V> getValue() {
- return LinkedListMultimap.this.get(key);
- }
- };
- }
- };
+ @Override public Collection<V> remove(@Nullable Object key) {
+ Collection<V> collection = removeAll(key);
+ return collection.isEmpty() ? null : collection;
}
};
}
@@ -1020,7 +1128,9 @@ public class LinkedListMultimap<K, V>
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
- keyToKeyList = Maps.newLinkedHashMap();
+ keyCount = LinkedHashMultiset.create();
+ keyToKeyHead = Maps.newHashMap();
+ keyToKeyTail = Maps.newHashMap();
int size = stream.readInt();
for (int i = 0; i < size; i++) {
@SuppressWarnings("unchecked") // reading data stored by writeObject
diff --git a/guava/src/com/google/common/collect/ListMultimap.java b/guava/src/com/google/common/collect/ListMultimap.java
index a83b81a..cf4cbaa 100644
--- a/guava/src/com/google/common/collect/ListMultimap.java
+++ b/guava/src/com/google/common/collect/ListMultimap.java
@@ -26,16 +26,11 @@ import javax.annotation.Nullable;
/**
* A {@code Multimap} that can hold duplicate key-value pairs and that maintains
- * the insertion ordering of values for a given key. See the {@link Multimap}
- * documentation for information common to all multimaps.
+ * the insertion ordering of values for a given key.
*
* <p>The {@link #get}, {@link #removeAll}, and {@link #replaceValues} methods
* each return a {@link List} of values. Though the method signature doesn't say
* so explicitly, the map returned by {@link #asMap} has {@code List} values.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap">
- * {@code Multimap}</a>.
*
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
diff --git a/guava/src/com/google/common/collect/Lists.java b/guava/src/com/google/common/collect/Lists.java
index 271da37..850d87e 100644
--- a/guava/src/com/google/common/collect/Lists.java
+++ b/guava/src/com/google/common/collect/Lists.java
@@ -25,7 +25,6 @@ import static com.google.common.base.Preconditions.checkState;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Objects;
@@ -44,24 +43,19 @@ import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.RandomAccess;
-import java.util.concurrent.CopyOnWriteArrayList;
import javax.annotation.Nullable;
/**
* Static utility methods pertaining to {@link List} instances. Also see this
- * class's counterparts {@link Sets}, {@link Maps} and {@link Queues}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Lists">
- * {@code Lists}</a>.
+ * class's counterparts {@link Sets} and {@link Maps}.
*
* @author Kevin Bourrillion
* @author Mike Bostock
* @author Louis Wasserman
* @since 2.0 (imported from Google Collections Library)
*/
-@GwtCompatible(emulated = true)
+@GwtCompatible
public final class Lists {
private Lists() {}
@@ -227,38 +221,6 @@ public final class Lists {
}
/**
- * Creates an empty {@code CopyOnWriteArrayList} instance.
- *
- * <p><b>Note:</b> if you need an immutable empty {@link List}, use
- * {@link Collections#emptyList} instead.
- *
- * @return a new, empty {@code CopyOnWriteArrayList}
- * @since 12.0
- */
- @GwtIncompatible("CopyOnWriteArrayList")
- public static <E> CopyOnWriteArrayList<E> newCopyOnWriteArrayList() {
- return new CopyOnWriteArrayList<E>();
- }
-
- /**
- * Creates a {@code CopyOnWriteArrayList} instance containing the given elements.
- *
- * @param elements the elements that the list should contain, in order
- * @return a new {@code CopyOnWriteArrayList} containing those elements
- * @since 12.0
- */
- @GwtIncompatible("CopyOnWriteArrayList")
- public static <E> CopyOnWriteArrayList<E> newCopyOnWriteArrayList(
- Iterable<? extends E> elements) {
- // We copy elements to an ArrayList first, rather than incurring the
- // quadratic cost of adding them to the COWAL directly.
- Collection<? extends E> elementsCollection = (elements instanceof Collection)
- ? Collections2.cast(elements)
- : newArrayList(elements);
- return new CopyOnWriteArrayList<E>(elementsCollection);
- }
-
- /**
* Returns an unmodifiable list containing the specified first element and
* backed by the specified array of additional elements. Changes to the {@code
* rest} array will be reflected in the returned list. Unlike {@link
@@ -352,127 +314,6 @@ public final class Lists {
}
/**
- * Returns every possible list that can be formed by choosing one element
- * from each of the given lists in order; the "n-ary
- * <a href="http://en.wikipedia.org/wiki/Cartesian_product">Cartesian
- * product</a>" of the lists. For example: <pre> {@code
- *
- * Lists.cartesianProduct(ImmutableList.of(
- * ImmutableList.of(1, 2),
- * ImmutableList.of("A", "B", "C")))}</pre>
- *
- * returns a list containing six lists in the following order:
- *
- * <ul>
- * <li>{@code ImmutableList.of(1, "A")}
- * <li>{@code ImmutableList.of(1, "B")}
- * <li>{@code ImmutableList.of(1, "C")}
- * <li>{@code ImmutableList.of(2, "A")}
- * <li>{@code ImmutableList.of(2, "B")}
- * <li>{@code ImmutableList.of(2, "C")}
- * </ul>
- *
- * The result is guaranteed to be in the "traditional", lexicographical
- * order for Cartesian products that you would get from nesting for loops:
- * <pre> {@code
- *
- * for (B b0 : lists.get(0)) {
- * for (B b1 : lists.get(1)) {
- * ...
- * ImmutableList<B> tuple = ImmutableList.of(b0, b1, ...);
- * // operate on tuple
- * }
- * }}</pre>
- *
- * Note that if any input list is empty, the Cartesian product will also be
- * empty. If no lists at all are provided (an empty list), the resulting
- * Cartesian product has one element, an empty list (counter-intuitive, but
- * mathematically consistent).
- *
- * <p><i>Performance notes:</i> while the cartesian product of lists of size
- * {@code m, n, p} is a list of size {@code m x n x p}, its actual memory
- * consumption is much smaller. When the cartesian product is constructed, the
- * input lists are merely copied. Only as the resulting list is iterated are
- * the individual lists created, and these are not retained after iteration.
- *
- * @param lists the lists to choose elements from, in the order that
- * the elements chosen from those lists should appear in the resulting
- * lists
- * @param <B> any common base class shared by all axes (often just {@link
- * Object})
- * @return the Cartesian product, as an immutable list containing immutable
- * lists
- * @throws IllegalArgumentException if the size of the cartesian product would
- * be greater than {@link Integer#MAX_VALUE}
- * @throws NullPointerException if {@code lists}, any one of the {@code lists},
- * or any element of a provided list is null
- */
- static <B> List<List<B>> cartesianProduct(
- List<? extends List<? extends B>> lists) {
- return CartesianList.create(lists);
- }
-
- /**
- * Returns every possible list that can be formed by choosing one element
- * from each of the given lists in order; the "n-ary
- * <a href="http://en.wikipedia.org/wiki/Cartesian_product">Cartesian
- * product</a>" of the lists. For example: <pre> {@code
- *
- * Lists.cartesianProduct(ImmutableList.of(
- * ImmutableList.of(1, 2),
- * ImmutableList.of("A", "B", "C")))}</pre>
- *
- * returns a list containing six lists in the following order:
- *
- * <ul>
- * <li>{@code ImmutableList.of(1, "A")}
- * <li>{@code ImmutableList.of(1, "B")}
- * <li>{@code ImmutableList.of(1, "C")}
- * <li>{@code ImmutableList.of(2, "A")}
- * <li>{@code ImmutableList.of(2, "B")}
- * <li>{@code ImmutableList.of(2, "C")}
- * </ul>
- *
- * The result is guaranteed to be in the "traditional", lexicographical
- * order for Cartesian products that you would get from nesting for loops:
- * <pre> {@code
- *
- * for (B b0 : lists.get(0)) {
- * for (B b1 : lists.get(1)) {
- * ...
- * ImmutableList<B> tuple = ImmutableList.of(b0, b1, ...);
- * // operate on tuple
- * }
- * }}</pre>
- *
- * Note that if any input list is empty, the Cartesian product will also be
- * empty. If no lists at all are provided (an empty list), the resulting
- * Cartesian product has one element, an empty list (counter-intuitive, but
- * mathematically consistent).
- *
- * <p><i>Performance notes:</i> while the cartesian product of lists of size
- * {@code m, n, p} is a list of size {@code m x n x p}, its actual memory
- * consumption is much smaller. When the cartesian product is constructed, the
- * input lists are merely copied. Only as the resulting list is iterated are
- * the individual lists created, and these are not retained after iteration.
- *
- * @param lists the lists to choose elements from, in the order that
- * the elements chosen from those lists should appear in the resulting
- * lists
- * @param <B> any common base class shared by all axes (often just {@link
- * Object})
- * @return the Cartesian product, as an immutable list containing immutable
- * lists
- * @throws IllegalArgumentException if the size of the cartesian product would
- * be greater than {@link Integer#MAX_VALUE}
- * @throws NullPointerException if {@code lists}, any one of the
- * {@code lists}, or any element of a provided list is null
- */
- static <B> List<List<B>> cartesianProduct(List<? extends B>... lists) {
- return cartesianProduct(Arrays.asList(lists));
- }
-
- /**
* Returns a list that applies {@code function} to each element of {@code
* fromList}. The returned list is a transformed view of {@code fromList};
* changes to {@code fromList} will be reflected in the returned list and vice
@@ -491,19 +332,13 @@ public final class Lists {
* view, copy the returned list into a new list of your choosing.
*
* <p>If {@code fromList} implements {@link RandomAccess}, so will the
- * returned list. The returned list is threadsafe if the supplied list and
- * function are.
+ * returned list. The returned list always implements {@link Serializable},
+ * but serialization will succeed only when {@code fromList} and
+ * {@code function} are serializable. The returned list is threadsafe if the
+ * supplied list and function are.
*
* <p>If only a {@code Collection} or {@code Iterable} input is available, use
* {@link Collections2#transform} or {@link Iterables#transform}.
- *
- * <p><b>Note:</b> serializing the returned list is implemented by serializing
- * {@code fromList}, its contents, and {@code function} -- <i>not</i> by
- * serializing the transformed values. This can lead to surprising behavior,
- * so serializing the returned list is <b>not recommended</b>. Instead,
- * copy the list using {@link ImmutableList#copyOf(Collection)} (for example),
- * then serialize the copy. Other methods similar to this do not implement
- * serialization at all for this reason.
*/
public static <F, T> List<T> transform(
List<F> fromList, Function<? super F, ? extends T> function) {
@@ -539,10 +374,51 @@ public final class Lists {
return fromList.size();
}
@Override public ListIterator<T> listIterator(final int index) {
- return new TransformedListIterator<F, T>(fromList.listIterator(index)) {
+ final ListIterator<F> delegate = fromList.listIterator(index);
+ return new ListIterator<T>() {
+ @Override
+ public void add(T e) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return delegate.hasNext();
+ }
+
+ @Override
+ public boolean hasPrevious() {
+ return delegate.hasPrevious();
+ }
+
+ @Override
+ public T next() {
+ return function.apply(delegate.next());
+ }
+
+ @Override
+ public int nextIndex() {
+ return delegate.nextIndex();
+ }
+
+ @Override
+ public T previous() {
+ return function.apply(delegate.previous());
+ }
+
+ @Override
+ public int previousIndex() {
+ return delegate.previousIndex();
+ }
+
@Override
- T transform(F from) {
- return function.apply(from);
+ public void remove() {
+ delegate.remove();
+ }
+
+ @Override
+ public void set(T e) {
+ throw new UnsupportedOperationException("not supported");
}
};
}
@@ -670,6 +546,10 @@ public final class Lists {
this.string = string;
}
+ @Override public boolean contains(@Nullable Object object) {
+ return indexOf(object) >= 0;
+ }
+
@Override public int indexOf(@Nullable Object object) {
return (object instanceof Character)
? string.indexOf((Character) object) : -1;
@@ -680,9 +560,17 @@ public final class Lists {
? string.lastIndexOf((Character) object) : -1;
}
+ @Override public UnmodifiableListIterator<Character> listIterator(
+ int index) {
+ return new AbstractIndexedListIterator<Character>(size(), index) {
+ @Override protected Character get(int index) {
+ return string.charAt(index);
+ }
+ };
+ }
+
@Override public ImmutableList<Character> subList(
int fromIndex, int toIndex) {
- checkPositionIndexes(fromIndex, toIndex, size()); // for GWT
return charactersOf(string.substring(fromIndex, toIndex));
}
@@ -691,7 +579,6 @@ public final class Lists {
}
@Override public Character get(int index) {
- checkElementIndex(index, size()); // for GWT
return string.charAt(index);
}
@@ -758,7 +645,6 @@ public final class Lists {
}
@Override public Character get(int index) {
- checkElementIndex(index, size()); // for GWT
return sequence.charAt(index);
}
@@ -795,7 +681,6 @@ public final class Lists {
}
@Override public List<Character> subList(int fromIndex, int toIndex) {
- checkPositionIndexes(fromIndex, toIndex, size()); // for GWT
return charactersOf(sequence.subSequence(fromIndex, toIndex));
}
@@ -1003,13 +888,10 @@ public final class Lists {
/**
* An implementation of {@link List#hashCode()}.
*/
- static int hashCodeImpl(List<?> list) {
+ static int hashCodeImpl(List<?> list){
int hashCode = 1;
for (Object o : list) {
hashCode = 31 * hashCode + (o == null ? 0 : o.hashCode());
-
- hashCode = ~~hashCode;
- // needed to deal with GWT integer overflow
}
return hashCode;
}
@@ -1146,11 +1028,4 @@ public final class Lists {
super(backingList);
}
}
-
- /**
- * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
- */
- static <T> List<T> cast(Iterable<T> iterable) {
- return (List<T>) iterable;
- }
}
diff --git a/guava/src/com/google/common/collect/MapConstraints.java b/guava/src/com/google/common/collect/MapConstraints.java
index 090625d..11351bb 100644
--- a/guava/src/com/google/common/collect/MapConstraints.java
+++ b/guava/src/com/google/common/collect/MapConstraints.java
@@ -21,7 +21,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
-import java.io.Serializable;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
@@ -396,7 +395,7 @@ public final class MapConstraints {
/** @see MapConstraints#constrainedMultimap */
private static class ConstrainedMultimap<K, V>
- extends ForwardingMultimap<K, V> implements Serializable {
+ extends ForwardingMultimap<K, V> {
final MapConstraint<? super K, ? super V> constraint;
final Multimap<K, V> delegate;
transient Collection<Entry<K, V>> entries;
diff --git a/guava/src/com/google/common/collect/MapMaker.java b/guava/src/com/google/common/collect/MapMaker.java
index a5a035e..330018e 100644
--- a/guava/src/com/google/common/collect/MapMaker.java
+++ b/guava/src/com/google/common/collect/MapMaker.java
@@ -18,12 +18,12 @@ import static com.google.common.base.Objects.firstNonNull;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.MapMakerInternalMap.Strength.SOFT;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Ascii;
import com.google.common.base.Equivalence;
+import com.google.common.base.Equivalences;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Throwables;
@@ -51,6 +51,8 @@ import javax.annotation.Nullable;
* <ul>
* <li>keys or values automatically wrapped in {@linkplain WeakReference weak} or {@linkplain
* SoftReference soft} references
+ * <li>least-recently-used eviction when a maximum size is exceeded
+ * <li>time-based expiration of entries, measured since last access or last write
* <li>notification of evicted (or otherwise removed) entries
* <li>on-demand computation of values for keys not already present
* </ul>
@@ -60,6 +62,8 @@ import javax.annotation.Nullable;
* ConcurrentMap<Key, Graph> graphs = new MapMaker()
* .concurrencyLevel(4)
* .weakKeys()
+ * .maximumSize(10000)
+ * .expireAfterWrite(10, TimeUnit.MINUTES)
* .makeComputingMap(
* new Function<Key, Graph>() {
* public Graph apply(Key key) {
@@ -75,9 +79,10 @@ import javax.annotation.Nullable;
* interface. It does not permit null keys or values.
*
* <p><b>Note:</b> by default, the returned map uses equality comparisons (the {@link Object#equals
- * equals} method) to determine equality for keys or values. However, if {@link #weakKeys} was
- * specified, the map uses identity ({@code ==}) comparisons instead for keys. Likewise, if {@link
- * #weakValues} or {@link #softValues} was specified, the map uses identity comparisons for values.
+ * equals} method) to determine equality for keys or values. However, if {@link #weakKeys} or {@link
+ * #softKeys} was specified, the map uses identity ({@code ==}) comparisons instead for keys.
+ * Likewise, if {@link #weakValues} or {@link #softValues} was specified, the map uses identity
+ * comparisons for values.
*
* <p>The view collections of the returned map have <i>weakly consistent iterators</i>. This means
* that they are safe for concurrent use, but if other threads modify the map after the iterator is
@@ -129,6 +134,7 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
RemovalCause nullRemovalCause;
Equivalence<Object> keyEquivalence;
+ Equivalence<Object> valueEquivalence;
Ticker ticker;
@@ -138,12 +144,16 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
*/
public MapMaker() {}
+ private boolean useNullMap() {
+ return (nullRemovalCause == null);
+ }
+
/**
* Sets a custom {@code Equivalence} strategy for comparing keys.
*
- * <p>By default, the map uses {@link Equivalence#identity} to determine key equality when {@link
- * #weakKeys} is specified, and {@link Equivalence#equals()} otherwise. The only place this is
- * used is in {@link Interners.WeakInterner}.
+ * <p>By default, the map uses {@link Equivalences#identity} to determine key equality when
+ * {@link #weakKeys} or {@link #softKeys} is specified, and {@link Equivalences#equals()}
+ * otherwise.
*/
@GwtIncompatible("To be supported")
@Override
@@ -159,6 +169,27 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
}
/**
+ * Sets a custom {@code Equivalence} strategy for comparing values.
+ *
+ * <p>By default, the map uses {@link Equivalences#identity} to determine value equality when
+ * {@link #weakValues} or {@link #softValues} is specified, and {@link Equivalences#equals()}
+ * otherwise.
+ */
+ @GwtIncompatible("To be supported")
+ @Override
+ MapMaker valueEquivalence(Equivalence<Object> equivalence) {
+ checkState(valueEquivalence == null,
+ "value equivalence was already set to %s", valueEquivalence);
+ this.valueEquivalence = checkNotNull(equivalence);
+ this.useCustomMap = true;
+ return this;
+ }
+
+ Equivalence<Object> getValueEquivalence() {
+ return firstNonNull(valueEquivalence, getValueStrength().defaultEquivalence());
+ }
+
+ /**
* Sets the minimum total size for the internal hash tables. For example, if the initial capacity
* is {@code 60}, and the concurrency level is {@code 8}, then eight segments are created, each
* having a hash table of size eight. Providing a large enough estimate at construction time
@@ -200,9 +231,7 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
* @throws IllegalStateException if a maximum size was already set
* @deprecated Caching functionality in {@code MapMaker} is being moved to
* {@link com.google.common.cache.CacheBuilder}, with {@link #maximumSize} being
- * replaced by {@link com.google.common.cache.CacheBuilder#maximumSize}. Note that {@code
- * CacheBuilder} is simply an enhanced API for an implementation which was branched from
- * {@code MapMaker}.
+ * replaced by {@link com.google.common.cache.CacheBuilder#maximumSize}.
*/
@Deprecated
@Override
@@ -252,6 +281,16 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
}
/**
+ * Specifies that each key (not value) stored in the map should be strongly referenced.
+ *
+ * @throws IllegalStateException if the key strength was already set
+ */
+ @Override
+ MapMaker strongKeys() {
+ return setKeyStrength(Strength.STRONG);
+ }
+
+ /**
* Specifies that each key (not value) stored in the map should be wrapped in a {@link
* WeakReference} (by default, strong references are used).
*
@@ -268,10 +307,36 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
return setKeyStrength(Strength.WEAK);
}
+ /**
+ * <b>This method is broken.</b> Maps with soft keys offer no functional advantage over maps with
+ * weak keys, and they waste memory by keeping unreachable elements in the map. If your goal is to
+ * create a memory-sensitive map, then consider using soft values instead.
+ *
+ * <p>Specifies that each key (not value) stored in the map should be wrapped in a
+ * {@link SoftReference} (by default, strong references are used). Softly-referenced objects will
+ * be garbage-collected in a <i>globally</i> least-recently-used manner, in response to memory
+ * demand.
+ *
+ * <p><b>Warning:</b> when this method is used, the resulting map will use identity ({@code ==})
+ * comparison to determine equality of keys, which is a technical violation of the {@link Map}
+ * specification, and may not be what you expect.
+ *
+ * @throws IllegalStateException if the key strength was already set
+ * @see SoftReference
+ * @deprecated use {@link #softValues} to create a memory-sensitive map, or {@link #weakKeys} to
+ * create a map that doesn't hold strong references to the keys.
+ * <b>This method is scheduled for deletion in January 2013.</b>
+ */
+ @Deprecated
+ @GwtIncompatible("java.lang.ref.SoftReference")
+ @Override
+ public MapMaker softKeys() {
+ return setKeyStrength(Strength.SOFT);
+ }
+
MapMaker setKeyStrength(Strength strength) {
checkState(keyStrength == null, "Key strength was already set to %s", keyStrength);
keyStrength = checkNotNull(strength);
- checkArgument(keyStrength != SOFT, "Soft keys are not supported");
if (strength != Strength.STRONG) {
// STRONG could be used during deserialization.
useCustomMap = true;
@@ -284,6 +349,16 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
}
/**
+ * Specifies that each value (not key) stored in the map should be strongly referenced.
+ *
+ * @throws IllegalStateException if the value strength was already set
+ */
+ @Override
+ MapMaker strongValues() {
+ return setValueStrength(Strength.STRONG);
+ }
+
+ /**
* Specifies that each value (not key) stored in the map should be wrapped in a
* {@link WeakReference} (by default, strong references are used).
*
@@ -347,6 +422,22 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
}
/**
+ * Old name of {@link #expireAfterWrite}.
+ *
+ * @deprecated Caching functionality in {@code MapMaker} is being moved to
+ * {@link com.google.common.cache.CacheBuilder}. Functionality equivalent to
+ * {@link MapMaker#expiration} is provided by
+ * {@link com.google.common.cache.CacheBuilder#expireAfterWrite}.
+ * <b>This method is scheduled for deletion in July 2012.</b>
+ */
+ @Deprecated
+ @Override
+ public
+ MapMaker expiration(long duration, TimeUnit unit) {
+ return expireAfterWrite(duration, unit);
+ }
+
+ /**
* Specifies that each entry should be automatically removed from the map once a fixed duration
* has elapsed after the entry's creation, or the most recent replacement of its value.
*
@@ -367,9 +458,7 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
* @throws IllegalStateException if the time to live or time to idle was already set
* @deprecated Caching functionality in {@code MapMaker} is being moved to
* {@link com.google.common.cache.CacheBuilder}, with {@link #expireAfterWrite} being
- * replaced by {@link com.google.common.cache.CacheBuilder#expireAfterWrite}. Note that {@code
- * CacheBuilder} is simply an enhanced API for an implementation which was branched from
- * {@code MapMaker}.
+ * replaced by {@link com.google.common.cache.CacheBuilder#expireAfterWrite}.
*/
@Deprecated
@Override
@@ -417,9 +506,7 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
* @throws IllegalStateException if the time to idle or time to live was already set
* @deprecated Caching functionality in {@code MapMaker} is being moved to
* {@link com.google.common.cache.CacheBuilder}, with {@link #expireAfterAccess} being
- * replaced by {@link com.google.common.cache.CacheBuilder#expireAfterAccess}. Note that
- * {@code CacheBuilder} is simply an enhanced API for an implementation which was branched
- * from {@code MapMaker}.
+ * replaced by {@link com.google.common.cache.CacheBuilder#expireAfterAccess}.
*/
@Deprecated
@GwtIncompatible("To be supported")
@@ -469,9 +556,7 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
* @throws IllegalStateException if a removal listener was already set
* @deprecated Caching functionality in {@code MapMaker} is being moved to
* {@link com.google.common.cache.CacheBuilder}, with {@link #removalListener} being
- * replaced by {@link com.google.common.cache.CacheBuilder#removalListener}. Note that {@code
- * CacheBuilder} is simply an enhanced API for an implementation which was branched from
- * {@code MapMaker}.
+ * replaced by {@link com.google.common.cache.CacheBuilder#removalListener}.
*/
@Deprecated
@GwtIncompatible("To be supported")
@@ -571,16 +656,17 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
* @return a serializable concurrent map having the requested features
* @deprecated Caching functionality in {@code MapMaker} is being moved to
* {@link com.google.common.cache.CacheBuilder}, with {@link #makeComputingMap} being replaced
- * by {@link com.google.common.cache.CacheBuilder#build}. See the
- * <a href="http://code.google.com/p/guava-libraries/wiki/MapMakerMigration">MapMaker
- * Migration Guide</a> for more details.
+ * by {@link com.google.common.cache.CacheBuilder#build}. Note that uses of
+ * {@link #makeComputingMap} with {@code AtomicLong} values can often be migrated to
+ * {@link AtomicLongMap}.
* <b>This method is scheduled for deletion in February 2013.</b>
+ *
*/
@Deprecated
@Override
public <K, V> ConcurrentMap<K, V> makeComputingMap(
Function<? super K, ? extends V> computingFunction) {
- return (nullRemovalCause == null)
+ return useNullMap()
? new MapMaker.ComputingMapAdapter<K, V>(this, computingFunction)
: new NullComputingConcurrentMap<K, V>(this, computingFunction);
}
@@ -616,6 +702,9 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
if (keyEquivalence != null) {
s.addValue("keyEquivalence");
}
+ if (valueEquivalence != null) {
+ s.addValue("valueEquivalence");
+ }
if (removalListener != null) {
s.addValue("removalListener");
}
@@ -706,8 +795,9 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
},
/**
- * The entry was removed automatically because its key or value was garbage-collected. This can
- * occur when using {@link #softValues}, {@link #weakKeys}, or {@link #weakValues}.
+ * The entry was removed automatically because its key or value was garbage-collected. This
+ * can occur when using {@link #softKeys}, {@link #softValues}, {@link #weakKeys}, or {@link
+ * #weakValues}.
*/
COLLECTED {
@Override
@@ -862,10 +952,6 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
* Overrides get() to compute on demand. Also throws an exception when {@code null} is returned
* from a computation.
*/
- /*
- * This might make more sense in ComputingConcurrentHashMap, but it causes a javac crash in some
- * cases there: http://code.google.com/p/guava-libraries/issues/detail?id=950
- */
static final class ComputingMapAdapter<K, V>
extends ComputingConcurrentHashMap<K, V> implements Serializable {
private static final long serialVersionUID = 0;
@@ -893,4 +979,5 @@ public final class MapMaker extends GenericMapMaker<Object, Object> {
return value;
}
}
+
}
diff --git a/guava/src/com/google/common/collect/MapMakerInternalMap.java b/guava/src/com/google/common/collect/MapMakerInternalMap.java
index b2d05bd..a5a6be8 100644
--- a/guava/src/com/google/common/collect/MapMakerInternalMap.java
+++ b/guava/src/com/google/common/collect/MapMakerInternalMap.java
@@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkState;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Equivalence;
+import com.google.common.base.Equivalences;
import com.google.common.base.Ticker;
import com.google.common.collect.GenericMapMaker.NullListener;
import com.google.common.collect.MapMaker.RemovalCause;
@@ -199,7 +200,7 @@ class MapMakerInternalMap<K, V>
valueStrength = builder.getValueStrength();
keyEquivalence = builder.getKeyEquivalence();
- valueEquivalence = valueStrength.defaultEquivalence();
+ valueEquivalence = builder.getValueEquivalence();
maximumSize = builder.maximumSize;
expireAfterAccessNanos = builder.getExpireAfterAccessNanos();
@@ -301,7 +302,7 @@ class MapMakerInternalMap<K, V>
@Override
Equivalence<Object> defaultEquivalence() {
- return Equivalence.equals();
+ return Equivalences.equals();
}
},
@@ -314,7 +315,7 @@ class MapMakerInternalMap<K, V>
@Override
Equivalence<Object> defaultEquivalence() {
- return Equivalence.identity();
+ return Equivalences.identity();
}
},
@@ -327,7 +328,7 @@ class MapMakerInternalMap<K, V>
@Override
Equivalence<Object> defaultEquivalence() {
- return Equivalence.identity();
+ return Equivalences.identity();
}
};
@@ -403,6 +404,60 @@ class MapMakerInternalMap<K, V>
}
},
+ SOFT {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new SoftEntry<K, V>(segment.keyReferenceQueue, key, hash, next);
+ }
+ },
+ SOFT_EXPIRABLE {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new SoftExpirableEntry<K, V>(segment.keyReferenceQueue, key, hash, next);
+ }
+
+ @Override
+ <K, V> ReferenceEntry<K, V> copyEntry(
+ Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
+ ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext);
+ copyExpirableEntry(original, newEntry);
+ return newEntry;
+ }
+ },
+ SOFT_EVICTABLE {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new SoftEvictableEntry<K, V>(segment.keyReferenceQueue, key, hash, next);
+ }
+
+ @Override
+ <K, V> ReferenceEntry<K, V> copyEntry(
+ Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
+ ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext);
+ copyEvictableEntry(original, newEntry);
+ return newEntry;
+ }
+ },
+ SOFT_EXPIRABLE_EVICTABLE {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new SoftExpirableEvictableEntry<K, V>(segment.keyReferenceQueue, key, hash, next);
+ }
+
+ @Override
+ <K, V> ReferenceEntry<K, V> copyEntry(
+ Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
+ ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext);
+ copyExpirableEntry(original, newEntry);
+ copyEvictableEntry(original, newEntry);
+ return newEntry;
+ }
+ },
+
WEAK {
@Override
<K, V> ReferenceEntry<K, V> newEntry(
@@ -469,7 +524,7 @@ class MapMakerInternalMap<K, V>
*/
static final EntryFactory[][] factories = {
{ STRONG, STRONG_EXPIRABLE, STRONG_EVICTABLE, STRONG_EXPIRABLE_EVICTABLE },
- {}, // no support for SOFT keys
+ { SOFT, SOFT_EXPIRABLE, SOFT_EVICTABLE, SOFT_EXPIRABLE_EVICTABLE },
{ WEAK, WEAK_EXPIRABLE, WEAK_EVICTABLE, WEAK_EXPIRABLE_EVICTABLE }
};
@@ -550,11 +605,8 @@ class MapMakerInternalMap<K, V>
/**
* Creates a copy of this reference for the given entry.
- *
- * <p>{@code value} may be null only for a loading reference.
*/
- ValueReference<K, V> copyFor(
- ReferenceQueue<V> queue, @Nullable V value, ReferenceEntry<K, V> entry);
+ ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry);
/**
* Clears this reference object.
@@ -587,8 +639,8 @@ class MapMakerInternalMap<K, V>
}
@Override
- public ValueReference<Object, Object> copyFor(ReferenceQueue<Object> queue,
- @Nullable Object value, ReferenceEntry<Object, Object> entry) {
+ public ValueReference<Object, Object> copyFor(
+ ReferenceQueue<Object> queue, ReferenceEntry<Object, Object> entry) {
return this;
}
@@ -783,7 +835,7 @@ class MapMakerInternalMap<K, V>
public void setPreviousEvictable(ReferenceEntry<Object, Object> previous) {}
}
- abstract static class AbstractReferenceEntry<K, V> implements ReferenceEntry<K, V> {
+ static abstract class AbstractReferenceEntry<K, V> implements ReferenceEntry<K, V> {
@Override
public ValueReference<K, V> getValueReference() {
throw new UnsupportedOperationException();
@@ -1704,8 +1756,8 @@ class MapMakerInternalMap<K, V>
@Override
public ValueReference<K, V> copyFor(
- ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
- return new WeakValueReference<K, V>(queue, value, entry);
+ ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) {
+ return new WeakValueReference<K, V>(queue, get(), entry);
}
@Override
@@ -1742,9 +1794,8 @@ class MapMakerInternalMap<K, V>
}
@Override
- public ValueReference<K, V> copyFor(
- ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
- return new SoftValueReference<K, V>(queue, value, entry);
+ public ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) {
+ return new SoftValueReference<K, V>(queue, get(), entry);
}
@Override
@@ -1779,8 +1830,7 @@ class MapMakerInternalMap<K, V>
}
@Override
- public ValueReference<K, V> copyFor(
- ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
+ public ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) {
return this;
}
@@ -2129,26 +2179,11 @@ class MapMakerInternalMap<K, V>
return map.entryFactory.newEntry(this, key, hash, next);
}
- /**
- * Copies {@code original} into a new entry chained to {@code newNext}. Returns the new entry,
- * or {@code null} if {@code original} was already garbage collected.
- */
@GuardedBy("Segment.this")
ReferenceEntry<K, V> copyEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
- if (original.getKey() == null) {
- // key collected
- return null;
- }
-
ValueReference<K, V> valueReference = original.getValueReference();
- V value = valueReference.get();
- if ((value == null) && !valueReference.isComputingReference()) {
- // value collected
- return null;
- }
-
ReferenceEntry<K, V> newEntry = map.entryFactory.copyEntry(this, original, newNext);
- newEntry.setValueReference(valueReference.copyFor(this.valueReferenceQueue, value, newEntry));
+ newEntry.setValueReference(valueReference.copyFor(this.valueReferenceQueue, newEntry));
return newEntry;
}
@@ -2617,14 +2652,14 @@ class MapMakerInternalMap<K, V>
// Clone nodes leading up to the tail.
for (ReferenceEntry<K, V> e = head; e != tail; e = e.getNext()) {
- int newIndex = e.getHash() & newMask;
- ReferenceEntry<K, V> newNext = newTable.get(newIndex);
- ReferenceEntry<K, V> newFirst = copyEntry(e, newNext);
- if (newFirst != null) {
- newTable.set(newIndex, newFirst);
- } else {
+ if (isCollected(e)) {
removeCollectedEntry(e);
newCount--;
+ } else {
+ int newIndex = e.getHash() & newMask;
+ ReferenceEntry<K, V> newNext = newTable.get(newIndex);
+ ReferenceEntry<K, V> newFirst = copyEntry(e, newNext);
+ newTable.set(newIndex, newFirst);
}
}
}
@@ -2867,12 +2902,11 @@ class MapMakerInternalMap<K, V>
int newCount = count;
ReferenceEntry<K, V> newFirst = entry.getNext();
for (ReferenceEntry<K, V> e = first; e != entry; e = e.getNext()) {
- ReferenceEntry<K, V> next = copyEntry(e, newFirst);
- if (next != null) {
- newFirst = next;
- } else {
+ if (isCollected(e)) {
removeCollectedEntry(e);
newCount--;
+ } else {
+ newFirst = copyEntry(e, newFirst);
}
}
this.count = newCount;
@@ -3008,6 +3042,17 @@ class MapMakerInternalMap<K, V>
}
/**
+ * Returns {@code true} if the entry has been partially collected, meaning that either the key
+ * is null, or the value is null and it is not computing.
+ */
+ boolean isCollected(ReferenceEntry<K, V> entry) {
+ if (entry.getKey() == null) {
+ return true;
+ }
+ return isCollected(entry.getValueReference());
+ }
+
+ /**
* Returns {@code true} if the value has been partially collected, meaning that the value is
* null and it is not computing.
*/
@@ -3215,7 +3260,7 @@ class MapMakerInternalMap<K, V>
@Override
public Iterator<ReferenceEntry<K, V>> iterator() {
- return new AbstractSequentialIterator<ReferenceEntry<K, V>>(peek()) {
+ return new AbstractLinkedIterator<ReferenceEntry<K, V>>(peek()) {
@Override
protected ReferenceEntry<K, V> computeNext(ReferenceEntry<K, V> previous) {
ReferenceEntry<K, V> next = previous.getNextEvictable();
@@ -3351,7 +3396,7 @@ class MapMakerInternalMap<K, V>
@Override
public Iterator<ReferenceEntry<K, V>> iterator() {
- return new AbstractSequentialIterator<ReferenceEntry<K, V>>(peek()) {
+ return new AbstractLinkedIterator<ReferenceEntry<K, V>>(peek()) {
@Override
protected ReferenceEntry<K, V> computeNext(ReferenceEntry<K, V> previous) {
ReferenceEntry<K, V> next = previous.getNextExpirable();
@@ -3446,6 +3491,17 @@ class MapMakerInternalMap<K, V>
return segmentFor(hash).getEntry(key, hash);
}
+ /**
+ * Returns the live internal entry for the specified key. Does not impact recency ordering.
+ */
+ ReferenceEntry<K, V> getLiveEntry(@Nullable Object key) {
+ if (key == null) {
+ return null;
+ }
+ int hash = hash(key);
+ return segmentFor(hash).getLiveEntry(key, hash);
+ }
+
@Override
public boolean containsKey(@Nullable Object key) {
if (key == null) {
@@ -3466,7 +3522,7 @@ class MapMakerInternalMap<K, V>
// such that none of the subsequent iterations observed it, despite the fact that at every point
// in time it was present somewhere int the map. This becomes increasingly unlikely as
// CONTAINS_VALUE_RETRIES increases, though without locking it is theoretically possible.
- final Segment<K, V>[] segments = this.segments;
+ final Segment<K,V>[] segments = this.segments;
long last = -1L;
for (int i = 0; i < CONTAINS_VALUE_RETRIES; i++) {
long sum = 0L;
@@ -3476,7 +3532,7 @@ class MapMakerInternalMap<K, V>
int c = segment.count; // read-volatile
AtomicReferenceArray<ReferenceEntry<K, V>> table = segment.table;
- for (int j = 0; j < table.length(); j++) {
+ for (int j = 0 ; j < table.length(); j++) {
for (ReferenceEntry<K, V> e = table.get(j); e != null; e = e.getNext()) {
V v = segment.getLiveValue(e);
if (v != null && valueEquivalence.equivalent(value, v)) {
@@ -3561,7 +3617,7 @@ class MapMakerInternalMap<K, V>
}
}
- transient Set<K> keySet;
+ Set<K> keySet;
@Override
public Set<K> keySet() {
@@ -3569,7 +3625,7 @@ class MapMakerInternalMap<K, V>
return (ks != null) ? ks : (keySet = new KeySet());
}
- transient Collection<V> values;
+ Collection<V> values;
@Override
public Collection<V> values() {
@@ -3577,7 +3633,7 @@ class MapMakerInternalMap<K, V>
return (vs != null) ? vs : (values = new Values());
}
- transient Set<Entry<K, V>> entrySet;
+ Set<Entry<K, V>> entrySet;
@Override
public Set<Entry<K, V>> entrySet() {
@@ -3587,7 +3643,7 @@ class MapMakerInternalMap<K, V>
// Iterator Support
- abstract class HashIterator<E> implements Iterator<E> {
+ abstract class HashIterator {
int nextSegmentIndex;
int nextTableIndex;
@@ -3603,8 +3659,6 @@ class MapMakerInternalMap<K, V>
advance();
}
- public abstract E next();
-
final void advance() {
nextExternal = null;
@@ -3696,7 +3750,7 @@ class MapMakerInternalMap<K, V>
}
}
- final class KeyIterator extends HashIterator<K> {
+ final class KeyIterator extends HashIterator implements Iterator<K> {
@Override
public K next() {
@@ -3704,7 +3758,7 @@ class MapMakerInternalMap<K, V>
}
}
- final class ValueIterator extends HashIterator<V> {
+ final class ValueIterator extends HashIterator implements Iterator<V> {
@Override
public V next() {
@@ -3759,7 +3813,7 @@ class MapMakerInternalMap<K, V>
}
}
- final class EntryIterator extends HashIterator<Entry<K, V>> {
+ final class EntryIterator extends HashIterator implements Iterator<Entry<K, V>> {
@Override
public Entry<K, V> next() {
@@ -3945,6 +3999,7 @@ class MapMakerInternalMap<K, V>
.setKeyStrength(keyStrength)
.setValueStrength(valueStrength)
.keyEquivalence(keyEquivalence)
+ .valueEquivalence(valueEquivalence)
.concurrencyLevel(concurrencyLevel);
mapMaker.removalListener(removalListener);
if (expireAfterWriteNanos > 0) {
diff --git a/guava/src/com/google/common/collect/Maps.java b/guava/src/com/google/common/collect/Maps.java
index 9569a52..4215869 100644
--- a/guava/src/com/google/common/collect/Maps.java
+++ b/guava/src/com/google/common/collect/Maps.java
@@ -23,6 +23,7 @@ import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Equivalence;
+import com.google.common.base.Equivalences;
import com.google.common.base.Function;
import com.google.common.base.Joiner.MapJoiner;
import com.google.common.base.Objects;
@@ -35,6 +36,7 @@ import com.google.common.primitives.Ints;
import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.AbstractMap;
+import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -46,25 +48,17 @@ import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.NavigableMap;
-import java.util.NavigableSet;
import java.util.Properties;
import java.util.Set;
import java.util.SortedMap;
-import java.util.SortedSet;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentMap;
import javax.annotation.Nullable;
/**
- * Static utility methods pertaining to {@link Map} instances (including instances of
- * {@link SortedMap}, {@link BiMap}, etc.). Also see this class's counterparts
- * {@link Lists}, {@link Sets} and {@link Queues}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Maps">
- * {@code Maps}</a>.
+ * Static utility methods pertaining to {@link Map} instances. Also see this
+ * class's counterparts {@link Lists} and {@link Sets}.
*
* @author Kevin Bourrillion
* @author Mike Bostock
@@ -76,60 +70,6 @@ import javax.annotation.Nullable;
public final class Maps {
private Maps() {}
- private enum EntryFunction implements Function<Entry, Object> {
- KEY {
- @Override
- @Nullable
- public Object apply(Entry entry) {
- return entry.getKey();
- }
- },
- VALUE {
- @Override
- @Nullable
- public Object apply(Entry entry) {
- return entry.getValue();
- }
- };
- }
-
- @SuppressWarnings("unchecked")
- static <K> Function<Entry<K, ?>, K> keyFunction() {
- return (Function) EntryFunction.KEY;
- }
-
- static <V> Function<Entry<?, V>, V> valueFunction() {
- return (Function) EntryFunction.VALUE;
- }
-
- /**
- * Returns an immutable map instance containing the given entries.
- * Internally, the returned set will be backed by an {@link EnumMap}.
- *
- * <p>The iteration order of the returned map follows the enum's iteration
- * order, not the order in which the elements appear in the given map.
- *
- * @param map the map to make an immutable copy of
- * @return an immutable map containing those entries
- * @since 14.0
- */
- @GwtCompatible(serializable = true)
- @Beta
- public static <K extends Enum<K>, V> ImmutableMap<K, V> immutableEnumMap(
- Map<K, V> map) {
- if (map instanceof ImmutableEnumMap) {
- return (ImmutableEnumMap<K, V>) map;
- } else if (map.isEmpty()) {
- return ImmutableMap.of();
- } else {
- for (Map.Entry<K, V> entry : map.entrySet()) {
- checkNotNull(entry.getKey());
- checkNotNull(entry.getValue());
- }
- return ImmutableEnumMap.asImmutable(new EnumMap<K, V>(map));
- }
- }
-
/**
* Creates a <i>mutable</i>, empty {@code HashMap} instance.
*
@@ -285,9 +225,9 @@ public final class Maps {
* @param comparator the comparator to sort the keys with
* @return a new, empty {@code TreeMap}
*/
- public static <C, K extends C, V> TreeMap<K, V> newTreeMap(
- @Nullable Comparator<C> comparator) {
- // Ideally, the extra type parameter "C" shouldn't be necessary. It is a
+ public static <K, V> TreeMap<K, V> newTreeMap(
+ @Nullable Comparator<? super K> comparator) {
+ // Ideally, the "? super" shouldn't be necessary. It is a
// work-around of a compiler type inference quirk that prevents the
// following code from being compiled:
// Comparator<Class<?>> comparator = null;
@@ -329,6 +269,38 @@ public final class Maps {
}
/**
+ * Returns a synchronized (thread-safe) bimap backed by the specified bimap.
+ * In order to guarantee serial access, it is critical that <b>all</b> access
+ * to the backing bimap is accomplished through the returned bimap.
+ *
+ * <p>It is imperative that the user manually synchronize on the returned map
+ * when accessing any of its collection views: <pre> {@code
+ *
+ * BiMap<Long, String> map = Maps.synchronizedBiMap(
+ * HashBiMap.<Long, String>create());
+ * ...
+ * Set<Long> set = map.keySet(); // Needn't be in synchronized block
+ * ...
+ * synchronized (map) { // Synchronizing on map, not set!
+ * Iterator<Long> it = set.iterator(); // Must be in synchronized block
+ * while (it.hasNext()) {
+ * foo(it.next());
+ * }
+ * }}</pre>
+ *
+ * Failure to follow this advice may result in non-deterministic behavior.
+ *
+ * <p>The returned bimap will be serializable if the specified bimap is
+ * serializable.
+ *
+ * @param bimap the bimap to be wrapped in a synchronized view
+ * @return a sychronized view of the specified bimap
+ */
+ public static <K, V> BiMap<K, V> synchronizedBiMap(BiMap<K, V> bimap) {
+ return Synchronized.biMap(bimap, null);
+ }
+
+ /**
* Computes the difference between two maps. This difference is an immutable
* snapshot of the state of the maps at the time this method is called. It
* will never change, even if the maps change at a later time.
@@ -352,7 +324,7 @@ public final class Maps {
SortedMapDifference<K, V> result = difference(sortedLeft, right);
return result;
}
- return difference(left, right, Equivalence.equals());
+ return difference(left, right, Equivalences.equals());
}
/**
@@ -524,7 +496,7 @@ public final class Maps {
}
@Override public boolean equals(@Nullable Object object) {
- if (object instanceof MapDifference.ValueDifference) {
+ if (object instanceof MapDifference.ValueDifference<?>) {
MapDifference.ValueDifference<?> that =
(MapDifference.ValueDifference<?>) object;
return Objects.equal(this.left, that.leftValue())
@@ -561,6 +533,7 @@ public final class Maps {
* @return the difference between the two maps
* @since 11.0
*/
+ @Beta
public static <K, V> SortedMapDifference<K, V> difference(
SortedMap<K, ? extends V> left, Map<? extends K, ? extends V> right) {
checkNotNull(left);
@@ -645,484 +618,6 @@ public final class Maps {
}
return (Comparator<E>) Ordering.natural();
}
-
- /**
- * Returns a view of the set as a map, mapping keys from the set according to
- * the specified function.
- *
- * <p>Specifically, for each {@code k} in the backing set, the returned map
- * has an entry mapping {@code k} to {@code function.apply(k)}. The {@code
- * keySet}, {@code values}, and {@code entrySet} views of the returned map
- * iterate in the same order as the backing set.
- *
- * <p>Modifications to the backing set are read through to the returned map.
- * The returned map supports removal operations if the backing set does.
- * Removal operations write through to the backing set. The returned map
- * does not support put operations.
- *
- * <p><b>Warning</b>: If the function rejects {@code null}, caution is
- * required to make sure the set does not contain {@code null}, because the
- * view cannot stop {@code null} from being added to the set.
- *
- * <p><b>Warning:</b> This method assumes that for any instance {@code k} of
- * key type {@code K}, {@code k.equals(k2)} implies that {@code k2} is also
- * of type {@code K}. Using a key type for which this may not hold, such as
- * {@code ArrayList}, may risk a {@code ClassCastException} when calling
- * methods on the resulting map view.
- *
- * @since 14.0
- */
- @Beta
- public static <K, V> Map<K, V> asMap(
- Set<K> set, Function<? super K, V> function) {
- if (set instanceof SortedSet) {
- return asMap((SortedSet<K>) set, function);
- } else {
- return new AsMapView<K, V>(set, function);
- }
- }
-
- /**
- * Returns a view of the sorted set as a map, mapping keys from the set
- * according to the specified function.
- *
- * <p>Specifically, for each {@code k} in the backing set, the returned map
- * has an entry mapping {@code k} to {@code function.apply(k)}. The {@code
- * keySet}, {@code values}, and {@code entrySet} views of the returned map
- * iterate in the same order as the backing set.
- *
- * <p>Modifications to the backing set are read through to the returned map.
- * The returned map supports removal operations if the backing set does.
- * Removal operations write through to the backing set. The returned map does
- * not support put operations.
- *
- * <p><b>Warning</b>: If the function rejects {@code null}, caution is
- * required to make sure the set does not contain {@code null}, because the
- * view cannot stop {@code null} from being added to the set.
- *
- * <p><b>Warning:</b> This method assumes that for any instance {@code k} of
- * key type {@code K}, {@code k.equals(k2)} implies that {@code k2} is also of
- * type {@code K}. Using a key type for which this may not hold, such as
- * {@code ArrayList}, may risk a {@code ClassCastException} when calling
- * methods on the resulting map view.
- *
- * @since 14.0
- */
- @Beta
- public static <K, V> SortedMap<K, V> asMap(
- SortedSet<K> set, Function<? super K, V> function) {
- return Platform.mapsAsMapSortedSet(set, function);
- }
-
- static <K, V> SortedMap<K, V> asMapSortedIgnoreNavigable(SortedSet<K> set,
- Function<? super K, V> function) {
- return new SortedAsMapView<K, V>(set, function);
- }
-
- /**
- * Returns a view of the navigable set as a map, mapping keys from the set
- * according to the specified function.
- *
- * <p>Specifically, for each {@code k} in the backing set, the returned map
- * has an entry mapping {@code k} to {@code function.apply(k)}. The {@code
- * keySet}, {@code values}, and {@code entrySet} views of the returned map
- * iterate in the same order as the backing set.
- *
- * <p>Modifications to the backing set are read through to the returned map.
- * The returned map supports removal operations if the backing set does.
- * Removal operations write through to the backing set. The returned map
- * does not support put operations.
- *
- * <p><b>Warning</b>: If the function rejects {@code null}, caution is
- * required to make sure the set does not contain {@code null}, because the
- * view cannot stop {@code null} from being added to the set.
- *
- * <p><b>Warning:</b> This method assumes that for any instance {@code k} of
- * key type {@code K}, {@code k.equals(k2)} implies that {@code k2} is also
- * of type {@code K}. Using a key type for which this may not hold, such as
- * {@code ArrayList}, may risk a {@code ClassCastException} when calling
- * methods on the resulting map view.
- *
- * @since 14.0
- */
- @Beta
- @GwtIncompatible("NavigableMap")
- public static <K, V> NavigableMap<K, V> asMap(
- NavigableSet<K> set, Function<? super K, V> function) {
- return new NavigableAsMapView<K, V>(set, function);
- }
-
- private static class AsMapView<K, V> extends ImprovedAbstractMap<K, V> {
-
- private final Set<K> set;
- final Function<? super K, V> function;
-
- Set<K> backingSet() {
- return set;
- }
-
- AsMapView(Set<K> set, Function<? super K, V> function) {
- this.set = checkNotNull(set);
- this.function = checkNotNull(function);
- }
-
- @Override
- public Set<K> keySet() {
- // probably not worth caching
- return removeOnlySet(backingSet());
- }
-
- @Override
- public Collection<V> values() {
- // probably not worth caching
- return Collections2.transform(set, function);
- }
-
- @Override
- public int size() {
- return backingSet().size();
- }
-
- @Override
- public boolean containsKey(@Nullable Object key) {
- return backingSet().contains(key);
- }
-
- @Override
- public V get(@Nullable Object key) {
- if (backingSet().contains(key)) {
- @SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it
- K k = (K) key;
- return function.apply(k);
- } else {
- return null;
- }
- }
-
- @Override
- public V remove(@Nullable Object key) {
- if (backingSet().remove(key)) {
- @SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it
- K k = (K) key;
- return function.apply(k);
- } else {
- return null;
- }
- }
-
- @Override
- public void clear() {
- backingSet().clear();
- }
-
- @Override
- protected Set<Entry<K, V>> createEntrySet() {
- return new EntrySet<K, V>() {
- @Override
- Map<K, V> map() {
- return AsMapView.this;
- }
-
- @Override
- public Iterator<Entry<K, V>> iterator() {
- return asSetEntryIterator(backingSet(), function);
- }
- };
- }
- }
-
- private static <K, V> Iterator<Entry<K, V>> asSetEntryIterator(
- Set<K> set, final Function<? super K, V> function) {
- return new TransformedIterator<K, Entry<K,V>>(set.iterator()) {
- @Override
- Entry<K, V> transform(K key) {
- return Maps.immutableEntry(key, function.apply(key));
- }
- };
- }
-
- private static class SortedAsMapView<K, V> extends AsMapView<K, V>
- implements SortedMap<K, V> {
-
- SortedAsMapView(SortedSet<K> set, Function<? super K, V> function) {
- super(set, function);
- }
-
- @Override
- SortedSet<K> backingSet() {
- return (SortedSet<K>) super.backingSet();
- }
-
- @Override
- public Comparator<? super K> comparator() {
- return backingSet().comparator();
- }
-
- @Override
- public Set<K> keySet() {
- return removeOnlySortedSet(backingSet());
- }
-
- @Override
- public SortedMap<K, V> subMap(K fromKey, K toKey) {
- return asMap(backingSet().subSet(fromKey, toKey), function);
- }
-
- @Override
- public SortedMap<K, V> headMap(K toKey) {
- return asMap(backingSet().headSet(toKey), function);
- }
-
- @Override
- public SortedMap<K, V> tailMap(K fromKey) {
- return asMap(backingSet().tailSet(fromKey), function);
- }
-
- @Override
- public K firstKey() {
- return backingSet().first();
- }
-
- @Override
- public K lastKey() {
- return backingSet().last();
- }
- }
-
- @GwtIncompatible("NavigableMap")
- private static final class NavigableAsMapView<K, V>
- extends AbstractNavigableMap<K, V> {
- /*
- * Using AbstractNavigableMap is simpler than extending SortedAsMapView and rewriting all the
- * NavigableMap methods.
- */
-
- private final NavigableSet<K> set;
- private final Function<? super K, V> function;
-
- NavigableAsMapView(NavigableSet<K> ks, Function<? super K, V> vFunction) {
- this.set = checkNotNull(ks);
- this.function = checkNotNull(vFunction);
- }
-
- @Override
- public NavigableMap<K, V> subMap(
- K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
- return asMap(set.subSet(fromKey, fromInclusive, toKey, toInclusive), function);
- }
-
- @Override
- public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
- return asMap(set.headSet(toKey, inclusive), function);
- }
-
- @Override
- public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
- return asMap(set.tailSet(fromKey, inclusive), function);
- }
-
- @Override
- public Comparator<? super K> comparator() {
- return set.comparator();
- }
-
- @Override
- @Nullable
- public V get(@Nullable Object key) {
- if (set.contains(key)) {
- @SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it
- K k = (K) key;
- return function.apply(k);
- } else {
- return null;
- }
- }
-
- @Override
- public void clear() {
- set.clear();
- }
-
- @Override
- Iterator<Entry<K, V>> entryIterator() {
- return asSetEntryIterator(set, function);
- }
-
- @Override
- Iterator<Entry<K, V>> descendingEntryIterator() {
- return descendingMap().entrySet().iterator();
- }
-
- @Override
- public NavigableSet<K> navigableKeySet() {
- return removeOnlyNavigableSet(set);
- }
-
- @Override
- public int size() {
- return set.size();
- }
-
- @Override
- public NavigableMap<K, V> descendingMap() {
- return asMap(set.descendingSet(), function);
- }
- }
-
- private static <E> Set<E> removeOnlySet(final Set<E> set) {
- return new ForwardingSet<E>() {
- @Override
- protected Set<E> delegate() {
- return set;
- }
-
- @Override
- public boolean add(E element) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean addAll(Collection<? extends E> es) {
- throw new UnsupportedOperationException();
- }
- };
- }
-
- private static <E> SortedSet<E> removeOnlySortedSet(final SortedSet<E> set) {
- return new ForwardingSortedSet<E>() {
- @Override
- protected SortedSet<E> delegate() {
- return set;
- }
-
- @Override
- public boolean add(E element) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean addAll(Collection<? extends E> es) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public SortedSet<E> headSet(E toElement) {
- return removeOnlySortedSet(super.headSet(toElement));
- }
-
- @Override
- public SortedSet<E> subSet(E fromElement, E toElement) {
- return removeOnlySortedSet(super.subSet(fromElement, toElement));
- }
-
- @Override
- public SortedSet<E> tailSet(E fromElement) {
- return removeOnlySortedSet(super.tailSet(fromElement));
- }
- };
- }
-
- @GwtIncompatible("NavigableSet")
- private static <E> NavigableSet<E> removeOnlyNavigableSet(final NavigableSet<E> set) {
- return new ForwardingNavigableSet<E>() {
- @Override
- protected NavigableSet<E> delegate() {
- return set;
- }
-
- @Override
- public boolean add(E element) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean addAll(Collection<? extends E> es) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public SortedSet<E> headSet(E toElement) {
- return removeOnlySortedSet(super.headSet(toElement));
- }
-
- @Override
- public SortedSet<E> subSet(E fromElement, E toElement) {
- return removeOnlySortedSet(
- super.subSet(fromElement, toElement));
- }
-
- @Override
- public SortedSet<E> tailSet(E fromElement) {
- return removeOnlySortedSet(super.tailSet(fromElement));
- }
-
- @Override
- public NavigableSet<E> headSet(E toElement, boolean inclusive) {
- return removeOnlyNavigableSet(super.headSet(toElement, inclusive));
- }
-
- @Override
- public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
- return removeOnlyNavigableSet(super.tailSet(fromElement, inclusive));
- }
-
- @Override
- public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
- E toElement, boolean toInclusive) {
- return removeOnlyNavigableSet(super.subSet(
- fromElement, fromInclusive, toElement, toInclusive));
- }
-
- @Override
- public NavigableSet<E> descendingSet() {
- return removeOnlyNavigableSet(super.descendingSet());
- }
- };
- }
-
- /**
- * Returns an immutable map for which the given {@code keys} are mapped to
- * values by the given function in the order they appear in the original
- * iterable. If {@code keys} contains duplicate elements, the returned map
- * will contain each distinct key once in the order it first appears in
- * {@code keys}.
- *
- * @throws NullPointerException if any element of {@code keys} is
- * {@code null}, or if {@code valueFunction} produces {@code null}
- * for any key
- * @since 14.0
- */
- @Beta
- public static <K, V> ImmutableMap<K, V> toMap(Iterable<K> keys,
- Function<? super K, V> valueFunction) {
- return toMap(keys.iterator(), valueFunction);
- }
-
- /**
- * Returns an immutable map for which the given {@code keys} are mapped to
- * values by the given function in the order they appear in the original
- * iterator. If {@code keys} contains duplicate elements, the returned map
- * will contain each distinct key once in the order it first appears in
- * {@code keys}.
- *
- * @throws NullPointerException if any element of {@code keys} is
- * {@code null}, or if {@code valueFunction} produces {@code null}
- * for any key
- * @since 14.0
- */
- @Beta
- public static <K, V> ImmutableMap<K, V> toMap(Iterator<K> keys,
- Function<? super K, V> valueFunction) {
- checkNotNull(valueFunction);
- // Using LHM instead of a builder so as not to fail on duplicate keys
- Map<K, V> builder = newLinkedHashMap();
- while (keys.hasNext()) {
- K key = keys.next();
- builder.put(key, valueFunction.apply(key));
- }
- return ImmutableMap.copyOf(builder);
- }
-
/**
* Returns an immutable map for which the {@link Map#values} are the given
* elements in the given order, and each key is the product of invoking a
@@ -1143,6 +638,24 @@ public final class Maps {
}
/**
+ * <b>Deprecated.</b>
+ *
+ * @since 10.0
+ * @deprecated use {@link #uniqueIndex(Iterator, Function)} by casting {@code
+ * values} to {@code Iterator<V>}, or better yet, by implementing only
+ * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled
+ * for deletion in March 2012.</b>
+ */
+ @Beta
+ @Deprecated
+ public static <K, V, I extends Object & Iterable<V> & Iterator<V>>
+ ImmutableMap<K, V> uniqueIndex(
+ I values, Function<? super V, K> keyFunction) {
+ Iterable<V> valuesIterable = checkNotNull(values);
+ return uniqueIndex(valuesIterable, keyFunction);
+ }
+
+ /**
* Returns an immutable map for which the {@link Map#values} are the given
* elements in the given order, and each key is the product of invoking a
* supplied function on its corresponding value.
@@ -1330,38 +843,6 @@ public final class Maps {
}
/**
- * Returns a synchronized (thread-safe) bimap backed by the specified bimap.
- * In order to guarantee serial access, it is critical that <b>all</b> access
- * to the backing bimap is accomplished through the returned bimap.
- *
- * <p>It is imperative that the user manually synchronize on the returned map
- * when accessing any of its collection views: <pre> {@code
- *
- * BiMap<Long, String> map = Maps.synchronizedBiMap(
- * HashBiMap.<Long, String>create());
- * ...
- * Set<Long> set = map.keySet(); // Needn't be in synchronized block
- * ...
- * synchronized (map) { // Synchronizing on map, not set!
- * Iterator<Long> it = set.iterator(); // Must be in synchronized block
- * while (it.hasNext()) {
- * foo(it.next());
- * }
- * }}</pre>
- *
- * Failure to follow this advice may result in non-deterministic behavior.
- *
- * <p>The returned bimap will be serializable if the specified bimap is
- * serializable.
- *
- * @param bimap the bimap to be wrapped in a synchronized view
- * @return a sychronized view of the specified bimap
- */
- public static <K, V> BiMap<K, V> synchronizedBiMap(BiMap<K, V> bimap) {
- return Synchronized.biMap(bimap, null);
- }
-
- /**
* Returns an unmodifiable view of the specified bimap. This method allows
* modules to provide users with "read-only" access to internal bimaps. Query
* operations on the returned bimap "read through" to the specified bimap, and
@@ -1384,7 +865,7 @@ public final class Maps {
extends ForwardingMap<K, V> implements BiMap<K, V>, Serializable {
final Map<K, V> unmodifiableMap;
final BiMap<? extends K, ? extends V> delegate;
- BiMap<V, K> inverse;
+ transient BiMap<V, K> inverse;
transient Set<V> values;
UnmodifiableBiMap(BiMap<? extends K, ? extends V> delegate,
@@ -1458,8 +939,16 @@ public final class Maps {
* a view, copy the returned map into a new map of your choosing.
*/
public static <K, V1, V2> Map<K, V2> transformValues(
- Map<K, V1> fromMap, Function<? super V1, V2> function) {
- return transformEntries(fromMap, asEntryTransformer(function));
+ Map<K, V1> fromMap, final Function<? super V1, V2> function) {
+ checkNotNull(function);
+ EntryTransformer<K, V1, V2> transformer =
+ new EntryTransformer<K, V1, V2>() {
+ @Override
+ public V2 transformEntry(K key, V1 value) {
+ return function.apply(value);
+ }
+ };
+ return transformEntries(fromMap, transformer);
}
/**
@@ -1501,67 +990,18 @@ public final class Maps {
*
* @since 11.0
*/
+ @Beta
public static <K, V1, V2> SortedMap<K, V2> transformValues(
- SortedMap<K, V1> fromMap, Function<? super V1, V2> function) {
- return transformEntries(fromMap, asEntryTransformer(function));
- }
-
- /**
- * Returns a view of a navigable map where each value is transformed by a
- * function. All other properties of the map, such as iteration order, are
- * left intact. For example, the code: <pre> {@code
- *
- * NavigableMap<String, Integer> map = Maps.newTreeMap();
- * map.put("a", 4);
- * map.put("b", 9);
- * Function<Integer, Double> sqrt =
- * new Function<Integer, Double>() {
- * public Double apply(Integer in) {
- * return Math.sqrt((int) in);
- * }
- * };
- * NavigableMap<String, Double> transformed =
- * Maps.transformNavigableValues(map, sqrt);
- * System.out.println(transformed);}</pre>
- *
- * ... prints {@code {a=2.0, b=3.0}}.
- *
- * Changes in the underlying map are reflected in this view.
- * Conversely, this view supports removal operations, and these are reflected
- * in the underlying map.
- *
- * <p>It's acceptable for the underlying map to contain null keys, and even
- * null values provided that the function is capable of accepting null input.
- * The transformed map might contain null values, if the function sometimes
- * gives a null result.
- *
- * <p>The returned map is not thread-safe or serializable, even if the
- * underlying map is.
- *
- * <p>The function is applied lazily, invoked when needed. This is necessary
- * for the returned map to be a view, but it means that the function will be
- * applied many times for bulk operations like {@link Map#containsValue} and
- * {@code Map.toString()}. For this to perform well, {@code function} should
- * be fast. To avoid lazy evaluation when the returned map doesn't need to be
- * a view, copy the returned map into a new map of your choosing.
- *
- * @since 13.0
- */
- @GwtIncompatible("NavigableMap")
- public static <K, V1, V2> NavigableMap<K, V2> transformValues(
- NavigableMap<K, V1> fromMap, Function<? super V1, V2> function) {
- return transformEntries(fromMap, asEntryTransformer(function));
- }
-
- private static <K, V1, V2> EntryTransformer<K, V1, V2>
- asEntryTransformer(final Function<? super V1, V2> function) {
+ SortedMap<K, V1> fromMap, final Function<? super V1, V2> function) {
checkNotNull(function);
- return new EntryTransformer<K, V1, V2>() {
- @Override
- public V2 transformEntry(K key, V1 value) {
- return function.apply(value);
- }
- };
+ EntryTransformer<K, V1, V2> transformer =
+ new EntryTransformer<K, V1, V2>() {
+ @Override
+ public V2 transformEntry(K key, V1 value) {
+ return function.apply(value);
+ }
+ };
+ return transformEntries(fromMap, transformer);
}
/**
@@ -1676,74 +1116,9 @@ public final class Maps {
*
* @since 11.0
*/
+ @Beta
public static <K, V1, V2> SortedMap<K, V2> transformEntries(
- SortedMap<K, V1> fromMap,
- EntryTransformer<? super K, ? super V1, V2> transformer) {
- return Platform.mapsTransformEntriesSortedMap(fromMap, transformer);
- }
-
- /**
- * Returns a view of a navigable map whose values are derived from the
- * original navigable map's entries. In contrast to {@link
- * #transformValues}, this method's entry-transformation logic may
- * depend on the key as well as the value.
- *
- * <p>All other properties of the transformed map, such as iteration order,
- * are left intact. For example, the code: <pre> {@code
- *
- * NavigableMap<String, Boolean> options = Maps.newTreeMap();
- * options.put("verbose", false);
- * options.put("sort", true);
- * EntryTransformer<String, Boolean, String> flagPrefixer =
- * new EntryTransformer<String, Boolean, String>() {
- * public String transformEntry(String key, Boolean value) {
- * return value ? key : ("yes" + key);
- * }
- * };
- * NavigableMap<String, String> transformed =
- * LabsMaps.transformNavigableEntries(options, flagPrefixer);
- * System.out.println(transformed);}</pre>
- *
- * ... prints {@code {sort=yessort, verbose=verbose}}.
- *
- * <p>Changes in the underlying map are reflected in this view.
- * Conversely, this view supports removal operations, and these are reflected
- * in the underlying map.
- *
- * <p>It's acceptable for the underlying map to contain null keys and null
- * values provided that the transformer is capable of accepting null inputs.
- * The transformed map might contain null values if the transformer sometimes
- * gives a null result.
- *
- * <p>The returned map is not thread-safe or serializable, even if the
- * underlying map is.
- *
- * <p>The transformer is applied lazily, invoked when needed. This is
- * necessary for the returned map to be a view, but it means that the
- * transformer will be applied many times for bulk operations like {@link
- * Map#containsValue} and {@link Object#toString}. For this to perform well,
- * {@code transformer} should be fast. To avoid lazy evaluation when the
- * returned map doesn't need to be a view, copy the returned map into a new
- * map of your choosing.
- *
- * <p><b>Warning:</b> This method assumes that for any instance {@code k} of
- * {@code EntryTransformer} key type {@code K}, {@code k.equals(k2)} implies
- * that {@code k2} is also of type {@code K}. Using an {@code
- * EntryTransformer} key type for which this may not hold, such as {@code
- * ArrayList}, may risk a {@code ClassCastException} when calling methods on
- * the transformed map.
- *
- * @since 13.0
- */
- @GwtIncompatible("NavigableMap")
- public static <K, V1, V2> NavigableMap<K, V2> transformEntries(
- final NavigableMap<K, V1> fromMap,
- EntryTransformer<? super K, ? super V1, V2> transformer) {
- return new TransformedEntriesNavigableMap<K, V1, V2>(fromMap, transformer);
- }
-
- static <K, V1, V2> SortedMap<K, V2> transformEntriesIgnoreNavigable(
- SortedMap<K, V1> fromMap,
+ final SortedMap<K, V1> fromMap,
EntryTransformer<? super K, ? super V1, V2> transformer) {
return new TransformedEntriesSortedMap<K, V1, V2>(fromMap, transformer);
}
@@ -1835,23 +1210,17 @@ public final class Maps {
}
@Override public Iterator<Entry<K, V2>> iterator() {
- return new TransformedIterator<Entry<K, V1>, Entry<K, V2>>(
- fromMap.entrySet().iterator()) {
- @Override
- Entry<K, V2> transform(final Entry<K, V1> entry) {
- return new AbstractMapEntry<K, V2>() {
- @Override
- public K getKey() {
- return entry.getKey();
+ final Iterator<Entry<K, V1>> backingIterator =
+ fromMap.entrySet().iterator();
+ return Iterators.transform(backingIterator,
+ new Function<Entry<K, V1>, Entry<K, V2>>() {
+ @Override public Entry<K, V2> apply(Entry<K, V1> entry) {
+ return immutableEntry(
+ entry.getKey(),
+ transformer.transformEntry(entry.getKey(),
+ entry.getValue()));
}
-
- @Override
- public V2 getValue() {
- return transformer.transformEntry(entry.getKey(), entry.getValue());
- }
- };
- }
- };
+ });
}
};
}
@@ -1909,144 +1278,7 @@ public final class Maps {
@Override public SortedMap<K, V2> tailMap(K fromKey) {
return transformEntries(fromMap().tailMap(fromKey), transformer);
}
- }
-
- @GwtIncompatible("NavigableMap")
- private static class TransformedEntriesNavigableMap<K, V1, V2>
- extends TransformedEntriesSortedMap<K, V1, V2>
- implements NavigableMap<K, V2> {
-
- TransformedEntriesNavigableMap(NavigableMap<K, V1> fromMap,
- EntryTransformer<? super K, ? super V1, V2> transformer) {
- super(fromMap, transformer);
- }
-
- @Override public Entry<K, V2> ceilingEntry(K key) {
- return transformEntry(fromMap().ceilingEntry(key));
- }
-
- @Override public K ceilingKey(K key) {
- return fromMap().ceilingKey(key);
- }
-
- @Override public NavigableSet<K> descendingKeySet() {
- return fromMap().descendingKeySet();
- }
-
- @Override public NavigableMap<K, V2> descendingMap() {
- return transformEntries(fromMap().descendingMap(), transformer);
- }
-
- @Override public Entry<K, V2> firstEntry() {
- return transformEntry(fromMap().firstEntry());
- }
- @Override public Entry<K, V2> floorEntry(K key) {
- return transformEntry(fromMap().floorEntry(key));
- }
-
- @Override public K floorKey(K key) {
- return fromMap().floorKey(key);
- }
-
- @Override public NavigableMap<K, V2> headMap(K toKey) {
- return headMap(toKey, false);
- }
-
- @Override public NavigableMap<K, V2> headMap(K toKey, boolean inclusive) {
- return transformEntries(
- fromMap().headMap(toKey, inclusive), transformer);
- }
-
- @Override public Entry<K, V2> higherEntry(K key) {
- return transformEntry(fromMap().higherEntry(key));
- }
-
- @Override public K higherKey(K key) {
- return fromMap().higherKey(key);
- }
-
- @Override public Entry<K, V2> lastEntry() {
- return transformEntry(fromMap().lastEntry());
- }
-
- @Override public Entry<K, V2> lowerEntry(K key) {
- return transformEntry(fromMap().lowerEntry(key));
- }
- @Override public K lowerKey(K key) {
- return fromMap().lowerKey(key);
- }
-
- @Override public NavigableSet<K> navigableKeySet() {
- return fromMap().navigableKeySet();
- }
-
- @Override public Entry<K, V2> pollFirstEntry() {
- return transformEntry(fromMap().pollFirstEntry());
- }
-
- @Override public Entry<K, V2> pollLastEntry() {
- return transformEntry(fromMap().pollLastEntry());
- }
-
- @Override public NavigableMap<K, V2> subMap(
- K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
- return transformEntries(
- fromMap().subMap(fromKey, fromInclusive, toKey, toInclusive),
- transformer);
- }
-
- @Override public NavigableMap<K, V2> subMap(K fromKey, K toKey) {
- return subMap(fromKey, true, toKey, false);
- }
-
- @Override public NavigableMap<K, V2> tailMap(K fromKey) {
- return tailMap(fromKey, true);
- }
-
- @Override public NavigableMap<K, V2> tailMap(K fromKey, boolean inclusive) {
- return transformEntries(
- fromMap().tailMap(fromKey, inclusive), transformer);
- }
-
- private Entry<K, V2> transformEntry(Entry<K, V1> entry) {
- if (entry == null) {
- return null;
- }
- K key = entry.getKey();
- V2 v2 = transformer.transformEntry(key, entry.getValue());
- return Maps.immutableEntry(key, v2);
- }
-
- @Override protected NavigableMap<K, V1> fromMap() {
- return (NavigableMap<K, V1>) super.fromMap();
- }
- }
-
- private static final class KeyPredicate<K, V> implements Predicate<Entry<K, V>> {
- private final Predicate<? super K> keyPredicate;
-
- KeyPredicate(Predicate<? super K> keyPredicate) {
- this.keyPredicate = checkNotNull(keyPredicate);
- }
-
- @Override
- public boolean apply(Entry<K, V> input) {
- return keyPredicate.apply(input.getKey());
- }
- }
-
- private static final class ValuePredicate<K, V> implements Predicate<Entry<K, V>> {
- private final Predicate<? super V> valuePredicate;
-
- ValuePredicate(Predicate<? super V> valuePredicate) {
- this.valuePredicate = checkNotNull(valuePredicate);
- }
-
- @Override
- public boolean apply(Entry<K, V> input) {
- return valuePredicate.apply(input.getValue());
- }
}
/**
@@ -2081,11 +1313,15 @@ public final class Maps {
Map<K, V> unfiltered, final Predicate<? super K> keyPredicate) {
if (unfiltered instanceof SortedMap) {
return filterKeys((SortedMap<K, V>) unfiltered, keyPredicate);
- } else if (unfiltered instanceof BiMap) {
- return filterKeys((BiMap<K, V>) unfiltered, keyPredicate);
}
checkNotNull(keyPredicate);
- Predicate<Entry<K, V>> entryPredicate = new KeyPredicate<K, V>(keyPredicate);
+ Predicate<Entry<K, V>> entryPredicate =
+ new Predicate<Entry<K, V>>() {
+ @Override
+ public boolean apply(Entry<K, V> input) {
+ return keyPredicate.apply(input.getKey());
+ }
+ };
return (unfiltered instanceof AbstractFilteredMap)
? filterFiltered((AbstractFilteredMap<K, V>) unfiltered, entryPredicate)
: new FilteredKeyMap<K, V>(
@@ -2122,80 +1358,19 @@ public final class Maps {
*
* @since 11.0
*/
+ @Beta
public static <K, V> SortedMap<K, V> filterKeys(
SortedMap<K, V> unfiltered, final Predicate<? super K> keyPredicate) {
- // TODO(user): Return a subclass of Maps.FilteredKeyMap for slightly better
- // performance.
- return filterEntries(unfiltered, new KeyPredicate<K, V>(keyPredicate));
- }
-
- /**
- * Returns a navigable map containing the mappings in {@code unfiltered} whose
- * keys satisfy a predicate. The returned map is a live view of {@code
- * unfiltered}; changes to one affect the other.
- *
- * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
- * values()} views have iterators that don't support {@code remove()}, but all
- * other methods are supported by the map and its views. When given a key that
- * doesn't satisfy the predicate, the map's {@code put()} and {@code putAll()}
- * methods throw an {@link IllegalArgumentException}.
- *
- * <p>When methods such as {@code removeAll()} and {@code clear()} are called
- * on the filtered map or its views, only mappings whose keys satisfy the
- * filter will be removed from the underlying map.
- *
- * <p>The returned map isn't threadsafe or serializable, even if {@code
- * unfiltered} is.
- *
- * <p>Many of the filtered map's methods, such as {@code size()},
- * iterate across every key/value mapping in the underlying map and determine
- * which satisfy the filter. When a live view is <i>not</i> needed, it may be
- * faster to copy the filtered map and use the copy.
- *
- * <p><b>Warning:</b> {@code keyPredicate} must be <i>consistent with
- * equals</i>, as documented at {@link Predicate#apply}. Do not provide a
- * predicate such as {@code Predicates.instanceOf(ArrayList.class)}, which is
- * inconsistent with equals.
- *
- * @since 14.0
- */
- @GwtIncompatible("NavigableMap")
- public static <K, V> NavigableMap<K, V> filterKeys(
- NavigableMap<K, V> unfiltered, final Predicate<? super K> keyPredicate) {
- // TODO(user): Return a subclass of Maps.FilteredKeyMap for slightly better
+ // TODO: Return a subclass of Maps.FilteredKeyMap for slightly better
// performance.
- return filterEntries(unfiltered, new KeyPredicate<K, V>(keyPredicate));
- }
-
- /**
- * Returns a bimap containing the mappings in {@code unfiltered} whose keys satisfy a predicate.
- * The returned bimap is a live view of {@code unfiltered}; changes to one affect the other.
- *
- * <p>The resulting bimap's {@code keySet()}, {@code entrySet()}, and {@code values()} views have
- * iterators that don't support {@code remove()}, but all other methods are supported by the
- * bimap and its views. When given a key that doesn't satisfy the predicate, the bimap's {@code
- * put()}, {@code forcePut()} and {@code putAll()} methods throw an {@link
- * IllegalArgumentException}.
- *
- * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered
- * bimap or its views, only mappings that satisfy the filter will be removed from the underlying
- * bimap.
- *
- * <p>The returned bimap isn't threadsafe or serializable, even if {@code unfiltered} is.
- *
- * <p>Many of the filtered bimap's methods, such as {@code size()}, iterate across every key in
- * the underlying bimap and determine which satisfy the filter. When a live view is <i>not</i>
- * needed, it may be faster to copy the filtered bimap and use the copy.
- *
- * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with equals </i>, as
- * documented at {@link Predicate#apply}.
- *
- * @since 14.0
- */
- public static <K, V> BiMap<K, V> filterKeys(
- BiMap<K, V> unfiltered, final Predicate<? super K> keyPredicate) {
checkNotNull(keyPredicate);
- return filterEntries(unfiltered, new KeyPredicate<K, V>(keyPredicate));
+ Predicate<Entry<K, V>> entryPredicate = new Predicate<Entry<K, V>>() {
+ @Override
+ public boolean apply(Entry<K, V> input) {
+ return keyPredicate.apply(input.getKey());
+ }
+ };
+ return filterEntries(unfiltered, entryPredicate);
}
/**
@@ -2231,10 +1406,16 @@ public final class Maps {
Map<K, V> unfiltered, final Predicate<? super V> valuePredicate) {
if (unfiltered instanceof SortedMap) {
return filterValues((SortedMap<K, V>) unfiltered, valuePredicate);
- } else if (unfiltered instanceof BiMap) {
- return filterValues((BiMap<K, V>) unfiltered, valuePredicate);
}
- return filterEntries(unfiltered, new ValuePredicate<K, V>(valuePredicate));
+ checkNotNull(valuePredicate);
+ Predicate<Entry<K, V>> entryPredicate =
+ new Predicate<Entry<K, V>>() {
+ @Override
+ public boolean apply(Entry<K, V> input) {
+ return valuePredicate.apply(input.getValue());
+ }
+ };
+ return filterEntries(unfiltered, entryPredicate);
}
/**
@@ -2268,79 +1449,18 @@ public final class Maps {
*
* @since 11.0
*/
+ @Beta
public static <K, V> SortedMap<K, V> filterValues(
SortedMap<K, V> unfiltered, final Predicate<? super V> valuePredicate) {
- return filterEntries(unfiltered, new ValuePredicate<K, V>(valuePredicate));
- }
-
- /**
- * Returns a navigable map containing the mappings in {@code unfiltered} whose
- * values satisfy a predicate. The returned map is a live view of {@code
- * unfiltered}; changes to one affect the other.
- *
- * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
- * values()} views have iterators that don't support {@code remove()}, but all
- * other methods are supported by the map and its views. When given a value
- * that doesn't satisfy the predicate, the map's {@code put()}, {@code
- * putAll()}, and {@link Entry#setValue} methods throw an {@link
- * IllegalArgumentException}.
- *
- * <p>When methods such as {@code removeAll()} and {@code clear()} are called
- * on the filtered map or its views, only mappings whose values satisfy the
- * filter will be removed from the underlying map.
- *
- * <p>The returned map isn't threadsafe or serializable, even if {@code
- * unfiltered} is.
- *
- * <p>Many of the filtered map's methods, such as {@code size()},
- * iterate across every key/value mapping in the underlying map and determine
- * which satisfy the filter. When a live view is <i>not</i> needed, it may be
- * faster to copy the filtered map and use the copy.
- *
- * <p><b>Warning:</b> {@code valuePredicate} must be <i>consistent with
- * equals</i>, as documented at {@link Predicate#apply}. Do not provide a
- * predicate such as {@code Predicates.instanceOf(ArrayList.class)}, which is
- * inconsistent with equals.
- *
- * @since 14.0
- */
- @GwtIncompatible("NavigableMap")
- public static <K, V> NavigableMap<K, V> filterValues(
- NavigableMap<K, V> unfiltered, final Predicate<? super V> valuePredicate) {
- return filterEntries(unfiltered, new ValuePredicate<K, V>(valuePredicate));
- }
-
- /**
- * Returns a bimap containing the mappings in {@code unfiltered} whose values satisfy a
- * predicate. The returned bimap is a live view of {@code unfiltered}; changes to one affect the
- * other.
- *
- * <p>The resulting bimap's {@code keySet()}, {@code entrySet()}, and {@code values()} views have
- * iterators that don't support {@code remove()}, but all other methods are supported by the
- * bimap and its views. When given a value that doesn't satisfy the predicate, the bimap's
- * {@code put()}, {@code forcePut()} and {@code putAll()} methods throw an {@link
- * IllegalArgumentException}. Similarly, the map's entries have a {@link Entry#setValue} method
- * that throws an {@link IllegalArgumentException} when the provided value doesn't satisfy the
- * predicate.
- *
- * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered
- * bimap or its views, only mappings that satisfy the filter will be removed from the underlying
- * bimap.
- *
- * <p>The returned bimap isn't threadsafe or serializable, even if {@code unfiltered} is.
- *
- * <p>Many of the filtered bimap's methods, such as {@code size()}, iterate across every value in
- * the underlying bimap and determine which satisfy the filter. When a live view is <i>not</i>
- * needed, it may be faster to copy the filtered bimap and use the copy.
- *
- * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with equals </i>, as
- * documented at {@link Predicate#apply}.
- *
- * @since 14.0
- */
- public static <K, V> BiMap<K, V> filterValues(
- BiMap<K, V> unfiltered, final Predicate<? super V> valuePredicate) {
- return filterEntries(unfiltered, new ValuePredicate<K, V>(valuePredicate));
+ checkNotNull(valuePredicate);
+ Predicate<Entry<K, V>> entryPredicate =
+ new Predicate<Entry<K, V>>() {
+ @Override
+ public boolean apply(Entry<K, V> input) {
+ return valuePredicate.apply(input.getValue());
+ }
+ };
+ return filterEntries(unfiltered, entryPredicate);
}
/**
@@ -2376,8 +1496,6 @@ public final class Maps {
Map<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) {
if (unfiltered instanceof SortedMap) {
return filterEntries((SortedMap<K, V>) unfiltered, entryPredicate);
- } else if (unfiltered instanceof BiMap) {
- return filterEntries((BiMap<K, V>) unfiltered, entryPredicate);
}
checkNotNull(entryPredicate);
return (unfiltered instanceof AbstractFilteredMap)
@@ -2416,15 +1534,10 @@ public final class Maps {
*
* @since 11.0
*/
+ @Beta
public static <K, V> SortedMap<K, V> filterEntries(
SortedMap<K, V> unfiltered,
Predicate<? super Entry<K, V>> entryPredicate) {
- return Platform.mapsFilterSortedMap(unfiltered, entryPredicate);
- }
-
- static <K, V> SortedMap<K, V> filterSortedIgnoreNavigable(
- SortedMap<K, V> unfiltered,
- Predicate<? super Entry<K, V>> entryPredicate) {
checkNotNull(entryPredicate);
return (unfiltered instanceof FilteredEntrySortedMap)
? filterFiltered((FilteredEntrySortedMap<K, V>) unfiltered, entryPredicate)
@@ -2432,83 +1545,6 @@ public final class Maps {
}
/**
- * Returns a sorted map containing the mappings in {@code unfiltered} that
- * satisfy a predicate. The returned map is a live view of {@code unfiltered};
- * changes to one affect the other.
- *
- * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
- * values()} views have iterators that don't support {@code remove()}, but all
- * other methods are supported by the map and its views. When given a
- * key/value pair that doesn't satisfy the predicate, the map's {@code put()}
- * and {@code putAll()} methods throw an {@link IllegalArgumentException}.
- * Similarly, the map's entries have a {@link Entry#setValue} method that
- * throws an {@link IllegalArgumentException} when the existing key and the
- * provided value don't satisfy the predicate.
- *
- * <p>When methods such as {@code removeAll()} and {@code clear()} are called
- * on the filtered map or its views, only mappings that satisfy the filter
- * will be removed from the underlying map.
- *
- * <p>The returned map isn't threadsafe or serializable, even if {@code
- * unfiltered} is.
- *
- * <p>Many of the filtered map's methods, such as {@code size()},
- * iterate across every key/value mapping in the underlying map and determine
- * which satisfy the filter. When a live view is <i>not</i> needed, it may be
- * faster to copy the filtered map and use the copy.
- *
- * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with
- * equals</i>, as documented at {@link Predicate#apply}.
- *
- * @since 14.0
- */
- @GwtIncompatible("NavigableMap")
- public static <K, V> NavigableMap<K, V> filterEntries(
- NavigableMap<K, V> unfiltered,
- Predicate<? super Entry<K, V>> entryPredicate) {
- checkNotNull(entryPredicate);
- return (unfiltered instanceof FilteredEntryNavigableMap)
- ? filterFiltered((FilteredEntryNavigableMap<K, V>) unfiltered, entryPredicate)
- : new FilteredEntryNavigableMap<K, V>(checkNotNull(unfiltered), entryPredicate);
- }
-
- /**
- * Returns a bimap containing the mappings in {@code unfiltered} that satisfy a predicate. The
- * returned bimap is a live view of {@code unfiltered}; changes to one affect the other.
- *
- * <p>The resulting bimap's {@code keySet()}, {@code entrySet()}, and {@code values()} views have
- * iterators that don't support {@code remove()}, but all other methods are supported by the bimap
- * and its views. When given a key/value pair that doesn't satisfy the predicate, the bimap's
- * {@code put()}, {@code forcePut()} and {@code putAll()} methods throw an
- * {@link IllegalArgumentException}. Similarly, the map's entries have an {@link Entry#setValue}
- * method that throws an {@link IllegalArgumentException} when the existing key and the provided
- * value don't satisfy the predicate.
- *
- * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered
- * bimap or its views, only mappings that satisfy the filter will be removed from the underlying
- * bimap.
- *
- * <p>The returned bimap isn't threadsafe or serializable, even if {@code unfiltered} is.
- *
- * <p>Many of the filtered bimap's methods, such as {@code size()}, iterate across every
- * key/value mapping in the underlying bimap and determine which satisfy the filter. When a live
- * view is <i>not</i> needed, it may be faster to copy the filtered bimap and use the copy.
- *
- * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with equals </i>, as
- * documented at {@link Predicate#apply}.
- *
- * @since 14.0
- */
- public static <K, V> BiMap<K, V> filterEntries(
- BiMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) {
- checkNotNull(unfiltered);
- checkNotNull(entryPredicate);
- return (unfiltered instanceof FilteredEntryBiMap)
- ? filterFiltered((FilteredEntryBiMap<K, V>) unfiltered, entryPredicate)
- : new FilteredEntryBiMap<K, V>(unfiltered, entryPredicate);
- }
-
- /**
* Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when
* filtering a filtered map.
*/
@@ -2653,7 +1689,6 @@ public final class Maps {
}
}
}
-
/**
* Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when
* filtering a filtered sorted map.
@@ -2714,251 +1749,6 @@ public final class Maps {
}
}
- /**
- * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when
- * filtering a filtered navigable map.
- */
- @GwtIncompatible("NavigableMap")
- private static <K, V> NavigableMap<K, V> filterFiltered(
- FilteredEntryNavigableMap<K, V> map,
- Predicate<? super Entry<K, V>> entryPredicate) {
- Predicate<Entry<K, V>> predicate
- = Predicates.and(map.predicate, entryPredicate);
- return new FilteredEntryNavigableMap<K, V>(map.sortedMap(), predicate);
- }
-
- @GwtIncompatible("NavigableMap")
- private static class FilteredEntryNavigableMap<K, V> extends FilteredEntrySortedMap<K, V>
- implements NavigableMap<K, V> {
-
- FilteredEntryNavigableMap(
- NavigableMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) {
- super(unfiltered, entryPredicate);
- }
-
- @Override
- NavigableMap<K, V> sortedMap() {
- return (NavigableMap<K, V>) super.sortedMap();
- }
-
- @Override
- public Entry<K, V> lowerEntry(K key) {
- return headMap(key, false).lastEntry();
- }
-
- @Override
- public K lowerKey(K key) {
- return keyOrNull(lowerEntry(key));
- }
-
- @Override
- public Entry<K, V> floorEntry(K key) {
- return headMap(key, true).lastEntry();
- }
-
- @Override
- public K floorKey(K key) {
- return keyOrNull(floorEntry(key));
- }
-
- @Override
- public Entry<K, V> ceilingEntry(K key) {
- return tailMap(key, true).firstEntry();
- }
-
- @Override
- public K ceilingKey(K key) {
- return keyOrNull(ceilingEntry(key));
- }
-
- @Override
- public Entry<K, V> higherEntry(K key) {
- return tailMap(key, false).firstEntry();
- }
-
- @Override
- public K higherKey(K key) {
- return keyOrNull(higherEntry(key));
- }
-
- @Override
- public Entry<K, V> firstEntry() {
- return Iterables.getFirst(entrySet(), null);
- }
-
- @Override
- public Entry<K, V> lastEntry() {
- return Iterables.getFirst(descendingMap().entrySet(), null);
- }
-
- @Override
- public Entry<K, V> pollFirstEntry() {
- return pollFirstSatisfyingEntry(sortedMap().entrySet().iterator());
- }
-
- @Override
- public Entry<K, V> pollLastEntry() {
- return pollFirstSatisfyingEntry(sortedMap().descendingMap().entrySet().iterator());
- }
-
- @Nullable
- Entry<K, V> pollFirstSatisfyingEntry(Iterator<Entry<K, V>> entryIterator) {
- while (entryIterator.hasNext()) {
- Entry<K, V> entry = entryIterator.next();
- if (predicate.apply(entry)) {
- entryIterator.remove();
- return entry;
- }
- }
- return null;
- }
-
- @Override
- public NavigableMap<K, V> descendingMap() {
- return filterEntries(sortedMap().descendingMap(), predicate);
- }
-
- @Override
- public NavigableSet<K> keySet() {
- return (NavigableSet<K>) super.keySet();
- }
-
- @Override
- NavigableSet<K> createKeySet() {
- return new NavigableKeySet<K, V>(this) {
- @Override
- public boolean removeAll(Collection<?> c) {
- boolean changed = false;
- Iterator<Entry<K, V>> entryIterator = sortedMap().entrySet().iterator();
- while (entryIterator.hasNext()) {
- Entry<K, V> entry = entryIterator.next();
- if (c.contains(entry.getKey()) && predicate.apply(entry)) {
- entryIterator.remove();
- changed = true;
- }
- }
- return changed;
- }
-
- @Override
- public boolean retainAll(Collection<?> c) {
- boolean changed = false;
- Iterator<Entry<K, V>> entryIterator = sortedMap().entrySet().iterator();
- while (entryIterator.hasNext()) {
- Entry<K, V> entry = entryIterator.next();
- if (!c.contains(entry.getKey()) && predicate.apply(entry)) {
- entryIterator.remove();
- changed = true;
- }
- }
- return changed;
- }
- };
- }
-
- @Override
- public NavigableSet<K> navigableKeySet() {
- return keySet();
- }
-
- @Override
- public NavigableSet<K> descendingKeySet() {
- return descendingMap().navigableKeySet();
- }
-
- @Override
- public NavigableMap<K, V> subMap(K fromKey, K toKey) {
- return subMap(fromKey, true, toKey, false);
- }
-
- @Override
- public NavigableMap<K, V> subMap(
- K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
- return filterEntries(
- sortedMap().subMap(fromKey, fromInclusive, toKey, toInclusive), predicate);
- }
-
- @Override
- public NavigableMap<K, V> headMap(K toKey) {
- return headMap(toKey, false);
- }
-
- @Override
- public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
- return filterEntries(sortedMap().headMap(toKey, inclusive), predicate);
- }
-
- @Override
- public NavigableMap<K, V> tailMap(K fromKey) {
- return tailMap(fromKey, true);
- }
-
- @Override
- public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
- return filterEntries(sortedMap().tailMap(fromKey, inclusive), predicate);
- }
- }
-
- /**
- * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when
- * filtering a filtered map.
- */
- private static <K, V> BiMap<K, V> filterFiltered(
- FilteredEntryBiMap<K, V> map, Predicate<? super Entry<K, V>> entryPredicate) {
- Predicate<Entry<K, V>> predicate = Predicates.and(map.predicate, entryPredicate);
- return new FilteredEntryBiMap<K, V>(map.unfiltered(), predicate);
- }
-
- static final class FilteredEntryBiMap<K, V> extends FilteredEntryMap<K, V>
- implements BiMap<K, V> {
- private final BiMap<V, K> inverse;
-
- private static <K, V> Predicate<Entry<V, K>> inversePredicate(
- final Predicate<? super Entry<K, V>> forwardPredicate) {
- return new Predicate<Entry<V, K>>() {
- @Override
- public boolean apply(Entry<V, K> input) {
- return forwardPredicate.apply(
- Maps.immutableEntry(input.getValue(), input.getKey()));
- }
- };
- }
-
- FilteredEntryBiMap(BiMap<K, V> delegate,
- Predicate<? super Entry<K, V>> predicate) {
- super(delegate, predicate);
- this.inverse = new FilteredEntryBiMap<V, K>(
- delegate.inverse(), inversePredicate(predicate), this);
- }
-
- private FilteredEntryBiMap(
- BiMap<K, V> delegate, Predicate<? super Entry<K, V>> predicate,
- BiMap<V, K> inverse) {
- super(delegate, predicate);
- this.inverse = inverse;
- }
-
- BiMap<K, V> unfiltered() {
- return (BiMap<K, V>) unfiltered;
- }
-
- @Override
- public V forcePut(@Nullable K key, @Nullable V value) {
- checkArgument(predicate.apply(Maps.immutableEntry(key, value)));
- return unfiltered().forcePut(key, value);
- }
-
- @Override
- public BiMap<V, K> inverse() {
- return inverse;
- }
-
- @Override
- public Set<V> values() {
- return inverse.keySet();
- }
- }
-
private static class FilteredKeyMap<K, V> extends AbstractFilteredMap<K, V> {
Predicate<? super K> keyPredicate;
@@ -3050,14 +1840,10 @@ public final class Maps {
@Override public Set<K> keySet() {
Set<K> result = keySet;
- return (result == null) ? keySet = createKeySet() : result;
+ return (result == null) ? keySet = new KeySet() : result;
}
- Set<K> createKeySet() {
- return new KeySet();
- }
-
- private class KeySet extends Sets.ImprovedAbstractSet<K> {
+ private class KeySet extends AbstractSet<K> {
@Override public Iterator<K> iterator() {
final Iterator<Entry<K, V>> iterator = filteredEntrySet.iterator();
return new UnmodifiableIterator<K>() {
@@ -3093,13 +1879,22 @@ public final class Maps {
return false;
}
+ @Override public boolean removeAll(Collection<?> collection) {
+ checkNotNull(collection); // for GWT
+ boolean changed = false;
+ for (Object obj : collection) {
+ changed |= remove(obj);
+ }
+ return changed;
+ }
+
@Override public boolean retainAll(Collection<?> collection) {
checkNotNull(collection); // for GWT
boolean changed = false;
Iterator<Entry<K, V>> iterator = unfiltered.entrySet().iterator();
while (iterator.hasNext()) {
Entry<K, V> entry = iterator.next();
- if (predicate.apply(entry) && !collection.contains(entry.getKey())) {
+ if (!collection.contains(entry.getKey()) && predicate.apply(entry)) {
iterator.remove();
changed = true;
}
@@ -3119,224 +1914,6 @@ public final class Maps {
}
/**
- * Returns an unmodifiable view of the specified navigable map. Query operations on the returned
- * map read through to the specified map, and attempts to modify the returned map, whether direct
- * or via its views, result in an {@code UnsupportedOperationException}.
- *
- * <p>The returned navigable map will be serializable if the specified navigable map is
- * serializable.
- *
- * @param map the navigable map for which an unmodifiable view is to be returned
- * @return an unmodifiable view of the specified navigable map
- * @since 12.0
- */
- @GwtIncompatible("NavigableMap")
- public static <K, V> NavigableMap<K, V> unmodifiableNavigableMap(NavigableMap<K, V> map) {
- checkNotNull(map);
- if (map instanceof UnmodifiableNavigableMap) {
- return map;
- } else {
- return new UnmodifiableNavigableMap<K, V>(map);
- }
- }
-
- @Nullable private static <K, V> Entry<K, V> unmodifiableOrNull(@Nullable Entry<K, V> entry) {
- return (entry == null) ? null : Maps.unmodifiableEntry(entry);
- }
-
- @GwtIncompatible("NavigableMap")
- static class UnmodifiableNavigableMap<K, V>
- extends ForwardingSortedMap<K, V> implements NavigableMap<K, V>, Serializable {
- private final NavigableMap<K, V> delegate;
-
- UnmodifiableNavigableMap(NavigableMap<K, V> delegate) {
- this.delegate = delegate;
- }
-
- @Override
- protected SortedMap<K, V> delegate() {
- return Collections.unmodifiableSortedMap(delegate);
- }
-
- @Override
- public Entry<K, V> lowerEntry(K key) {
- return unmodifiableOrNull(delegate.lowerEntry(key));
- }
-
- @Override
- public K lowerKey(K key) {
- return delegate.lowerKey(key);
- }
-
- @Override
- public Entry<K, V> floorEntry(K key) {
- return unmodifiableOrNull(delegate.floorEntry(key));
- }
-
- @Override
- public K floorKey(K key) {
- return delegate.floorKey(key);
- }
-
- @Override
- public Entry<K, V> ceilingEntry(K key) {
- return unmodifiableOrNull(delegate.ceilingEntry(key));
- }
-
- @Override
- public K ceilingKey(K key) {
- return delegate.ceilingKey(key);
- }
-
- @Override
- public Entry<K, V> higherEntry(K key) {
- return unmodifiableOrNull(delegate.higherEntry(key));
- }
-
- @Override
- public K higherKey(K key) {
- return delegate.higherKey(key);
- }
-
- @Override
- public Entry<K, V> firstEntry() {
- return unmodifiableOrNull(delegate.firstEntry());
- }
-
- @Override
- public Entry<K, V> lastEntry() {
- return unmodifiableOrNull(delegate.lastEntry());
- }
-
- @Override
- public final Entry<K, V> pollFirstEntry() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public final Entry<K, V> pollLastEntry() {
- throw new UnsupportedOperationException();
- }
-
- private transient UnmodifiableNavigableMap<K, V> descendingMap;
-
- @Override
- public NavigableMap<K, V> descendingMap() {
- UnmodifiableNavigableMap<K, V> result = descendingMap;
- if (result == null) {
- descendingMap = result = new UnmodifiableNavigableMap<K, V>(delegate.descendingMap());
- result.descendingMap = this;
- }
- return result;
- }
-
- @Override
- public Set<K> keySet() {
- return navigableKeySet();
- }
-
- @Override
- public NavigableSet<K> navigableKeySet() {
- return Sets.unmodifiableNavigableSet(delegate.navigableKeySet());
- }
-
- @Override
- public NavigableSet<K> descendingKeySet() {
- return Sets.unmodifiableNavigableSet(delegate.descendingKeySet());
- }
-
- @Override
- public SortedMap<K, V> subMap(K fromKey, K toKey) {
- return subMap(fromKey, true, toKey, false);
- }
-
- @Override
- public SortedMap<K, V> headMap(K toKey) {
- return headMap(toKey, false);
- }
-
- @Override
- public SortedMap<K, V> tailMap(K fromKey) {
- return tailMap(fromKey, true);
- }
-
- @Override
- public
- NavigableMap<K, V>
- subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
- return Maps.unmodifiableNavigableMap(delegate.subMap(
- fromKey,
- fromInclusive,
- toKey,
- toInclusive));
- }
-
- @Override
- public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
- return Maps.unmodifiableNavigableMap(delegate.headMap(toKey, inclusive));
- }
-
- @Override
- public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
- return Maps.unmodifiableNavigableMap(delegate.tailMap(fromKey, inclusive));
- }
- }
-
- /**
- * Returns a synchronized (thread-safe) navigable map backed by the specified
- * navigable map. In order to guarantee serial access, it is critical that
- * <b>all</b> access to the backing navigable map is accomplished
- * through the returned navigable map (or its views).
- *
- * <p>It is imperative that the user manually synchronize on the returned
- * navigable map when iterating over any of its collection views, or the
- * collections views of any of its {@code descendingMap}, {@code subMap},
- * {@code headMap} or {@code tailMap} views. <pre> {@code
- *
- * NavigableMap<K, V> map = synchronizedNavigableMap(new TreeMap<K, V>());
- *
- * // Needn't be in synchronized block
- * NavigableSet<K> set = map.navigableKeySet();
- *
- * synchronized (map) { // Synchronizing on map, not set!
- * Iterator<K> it = set.iterator(); // Must be in synchronized block
- * while (it.hasNext()){
- * foo(it.next());
- * }
- * }}</pre>
- *
- * or: <pre> {@code
- *
- * NavigableMap<K, V> map = synchronizedNavigableMap(new TreeMap<K, V>());
- * NavigableMap<K, V> map2 = map.subMap(foo, false, bar, true);
- *
- * // Needn't be in synchronized block
- * NavigableSet<K> set2 = map2.descendingKeySet();
- *
- * synchronized (map) { // Synchronizing on map, not map2 or set2!
- * Iterator<K> it = set2.iterator(); // Must be in synchronized block
- * while (it.hasNext()){
- * foo(it.next());
- * }
- * }}</pre>
- *
- * Failure to follow this advice may result in non-deterministic behavior.
- *
- * <p>The returned navigable map will be serializable if the specified
- * navigable map is serializable.
- *
- * @param navigableMap the navigable map to be "wrapped" in a synchronized
- * navigable map.
- * @return a synchronized view of the specified navigable map.
- * @since 13.0
- */
- @GwtIncompatible("NavigableMap")
- public static <K, V> NavigableMap<K, V> synchronizedNavigableMap(
- NavigableMap<K, V> navigableMap) {
- return Synchronized.navigableMap(navigableMap);
- }
-
- /**
* {@code AbstractMap} extension that implements {@link #isEmpty()} as {@code
* entrySet().isEmpty()} instead of {@code size() == 0} to speed up
* implementations where {@code size()} is O(n), and it delegates the {@code
@@ -3344,7 +1921,7 @@ public final class Maps {
* implementation.
*/
@GwtCompatible
- abstract static class ImprovedAbstractMap<K, V> extends AbstractMap<K, V> {
+ static abstract class ImprovedAbstractMap<K, V> extends AbstractMap<K, V> {
/**
* Creates the entry set to be returned by {@link #entrySet()}. This method
* is invoked at most once on a given map, at the time when {@code entrySet}
@@ -3381,7 +1958,7 @@ public final class Maps {
@Override public Collection<V> values() {
Collection<V> result = values;
if (result == null) {
- return values = new Values<K, V>() {
+ return values = new Values<K, V>(){
@Override Map<K, V> map() {
return ImprovedAbstractMap.this;
}
@@ -3389,6 +1966,17 @@ public final class Maps {
}
return result;
}
+
+ /**
+ * Returns {@code true} if this map contains no key-value mappings.
+ *
+ * <p>The implementation returns {@code entrySet().isEmpty()}.
+ *
+ * @return {@code true} if this map contains no key-value mappings
+ */
+ @Override public boolean isEmpty() {
+ return entrySet().isEmpty();
+ }
}
static final MapJoiner STANDARD_JOINER =
@@ -3396,46 +1984,25 @@ public final class Maps {
/**
* Delegates to {@link Map#get}. Returns {@code null} on {@code
- * ClassCastException} and {@code NullPointerException}.
+ * ClassCastException}.
*/
static <V> V safeGet(Map<?, V> map, Object key) {
- checkNotNull(map);
try {
return map.get(key);
} catch (ClassCastException e) {
return null;
- } catch (NullPointerException e) {
- return null;
}
}
/**
* Delegates to {@link Map#containsKey}. Returns {@code false} on {@code
- * ClassCastException} and {@code NullPointerException}.
+ * ClassCastException}
*/
static boolean safeContainsKey(Map<?, ?> map, Object key) {
- checkNotNull(map);
try {
return map.containsKey(key);
} catch (ClassCastException e) {
return false;
- } catch (NullPointerException e) {
- return false;
- }
- }
-
- /**
- * Delegates to {@link Map#remove}. Returns {@code null} on {@code
- * ClassCastException} and {@code NullPointerException}.
- */
- static <V> V safeRemove(Map<?, V> map, Object key) {
- checkNotNull(map);
- try {
- return map.remove(key);
- } catch (ClassCastException e) {
- return null;
- } catch (NullPointerException e) {
- return null;
}
}
@@ -3494,6 +2061,13 @@ public final class Maps {
}
/**
+ * An implementation of {@link Map#hashCode}.
+ */
+ static int hashCodeImpl(Map<?, ?> map) {
+ return Sets.hashCodeImpl(map.entrySet());
+ }
+
+ /**
* An implementation of {@link Map#toString}.
*/
static String toStringImpl(Map<?, ?> map) {
@@ -3517,30 +2091,36 @@ public final class Maps {
* An admittedly inefficient implementation of {@link Map#containsKey}.
*/
static boolean containsKeyImpl(Map<?, ?> map, @Nullable Object key) {
- return Iterators.contains(keyIterator(map.entrySet().iterator()), key);
+ for (Entry<?, ?> entry : map.entrySet()) {
+ if (Objects.equal(entry.getKey(), key)) {
+ return true;
+ }
+ }
+ return false;
}
/**
* An implementation of {@link Map#containsValue}.
*/
static boolean containsValueImpl(Map<?, ?> map, @Nullable Object value) {
- return Iterators.contains(valueIterator(map.entrySet().iterator()), value);
- }
-
- static <K, V> Iterator<K> keyIterator(Iterator<Entry<K, V>> entryIterator) {
- return new TransformedIterator<Entry<K, V>, K>(entryIterator) {
- @Override
- K transform(Entry<K, V> entry) {
- return entry.getKey();
+ for (Entry<?, ?> entry : map.entrySet()) {
+ if (Objects.equal(entry.getValue(), value)) {
+ return true;
}
- };
+ }
+ return false;
}
- abstract static class KeySet<K, V> extends Sets.ImprovedAbstractSet<K> {
+ abstract static class KeySet<K, V> extends AbstractSet<K> {
abstract Map<K, V> map();
@Override public Iterator<K> iterator() {
- return keyIterator(map().entrySet().iterator());
+ return Iterators.transform(map().entrySet().iterator(),
+ new Function<Map.Entry<K, V>, K>() {
+ @Override public K apply(Entry<K, V> entry) {
+ return entry.getKey();
+ }
+ });
}
@Override public int size() {
@@ -3563,153 +2143,27 @@ public final class Maps {
return false;
}
- @Override public void clear() {
- map().clear();
- }
- }
-
- @Nullable
- static <K> K keyOrNull(@Nullable Entry<K, ?> entry) {
- return (entry == null) ? null : entry.getKey();
- }
-
- @Nullable
- static <V> V valueOrNull(@Nullable Entry<?, V> entry) {
- return (entry == null) ? null : entry.getValue();
- }
-
- @GwtIncompatible("NavigableMap")
- static class NavigableKeySet<K, V> extends KeySet<K, V> implements NavigableSet<K> {
- private final NavigableMap<K, V> map;
-
- NavigableKeySet(NavigableMap<K, V> map) {
- this.map = checkNotNull(map);
- }
-
- @Override
- NavigableMap<K, V> map() {
- return map;
- }
-
- @Override
- public Comparator<? super K> comparator() {
- return map().comparator();
- }
-
- @Override
- public K first() {
- return map().firstKey();
- }
-
- @Override
- public K last() {
- return map().lastKey();
- }
-
- @Override
- public K lower(K e) {
- return map().lowerKey(e);
- }
-
- @Override
- public K floor(K e) {
- return map().floorKey(e);
- }
-
- @Override
- public K ceiling(K e) {
- return map().ceilingKey(e);
- }
-
- @Override
- public K higher(K e) {
- return map().higherKey(e);
- }
-
- @Override
- public K pollFirst() {
- return keyOrNull(map().pollFirstEntry());
- }
-
- @Override
- public K pollLast() {
- return keyOrNull(map().pollLastEntry());
- }
-
- @Override
- public NavigableSet<K> descendingSet() {
- return map().descendingKeySet();
- }
-
- @Override
- public Iterator<K> descendingIterator() {
- return descendingSet().iterator();
- }
-
- @Override
- public NavigableSet<K> subSet(
- K fromElement,
- boolean fromInclusive,
- K toElement,
- boolean toInclusive) {
- return map().subMap(fromElement, fromInclusive, toElement, toInclusive).navigableKeySet();
- }
-
- @Override
- public NavigableSet<K> headSet(K toElement, boolean inclusive) {
- return map().headMap(toElement, inclusive).navigableKeySet();
- }
-
- @Override
- public NavigableSet<K> tailSet(K fromElement, boolean inclusive) {
- return map().tailMap(fromElement, inclusive).navigableKeySet();
- }
-
- @Override
- public SortedSet<K> subSet(K fromElement, K toElement) {
- return subSet(fromElement, true, toElement, false);
- }
-
@Override
- public SortedSet<K> headSet(K toElement) {
- return headSet(toElement, false);
+ public boolean removeAll(Collection<?> c) {
+ // TODO(user): find out why this is necessary to make GWT tests pass.
+ return super.removeAll(checkNotNull(c));
}
- @Override
- public SortedSet<K> tailSet(K fromElement) {
- return tailSet(fromElement, true);
+ @Override public void clear() {
+ map().clear();
}
}
- static <K, V> Iterator<V> valueIterator(Iterator<Entry<K, V>> entryIterator) {
- return new TransformedIterator<Entry<K, V>, V>(entryIterator) {
- @Override
- V transform(Entry<K, V> entry) {
- return entry.getValue();
- }
- };
- }
-
- static <K, V> UnmodifiableIterator<V> valueIterator(
- final UnmodifiableIterator<Entry<K, V>> entryIterator) {
- return new UnmodifiableIterator<V>() {
- @Override
- public boolean hasNext() {
- return entryIterator.hasNext();
- }
-
- @Override
- public V next() {
- return entryIterator.next().getValue();
- }
- };
- }
-
abstract static class Values<K, V> extends AbstractCollection<V> {
abstract Map<K, V> map();
@Override public Iterator<V> iterator() {
- return valueIterator(map().entrySet().iterator());
+ return Iterators.transform(map().entrySet().iterator(),
+ new Function<Entry<K, V>, V>() {
+ @Override public V apply(Entry<K, V> entry) {
+ return entry.getValue();
+ }
+ });
}
@Override public boolean remove(Object o) {
@@ -3771,8 +2225,7 @@ public final class Maps {
}
}
- abstract static class EntrySet<K, V>
- extends Sets.ImprovedAbstractSet<Entry<K, V>> {
+ abstract static class EntrySet<K, V> extends AbstractSet<Entry<K, V>> {
abstract Map<K, V> map();
@Override public int size() {
@@ -3835,197 +2288,4 @@ public final class Maps {
}
}
}
-
- @GwtIncompatible("NavigableMap")
- abstract static class DescendingMap<K, V> extends ForwardingMap<K, V>
- implements NavigableMap<K, V> {
-
- abstract NavigableMap<K, V> forward();
-
- @Override
- protected final Map<K, V> delegate() {
- return forward();
- }
-
- private transient Comparator<? super K> comparator;
-
- @SuppressWarnings("unchecked")
- @Override
- public Comparator<? super K> comparator() {
- Comparator<? super K> result = comparator;
- if (result == null) {
- Comparator<? super K> forwardCmp = forward().comparator();
- if (forwardCmp == null) {
- forwardCmp = (Comparator) Ordering.natural();
- }
- result = comparator = reverse(forwardCmp);
- }
- return result;
- }
-
- // If we inline this, we get a javac error.
- private static <T> Ordering<T> reverse(Comparator<T> forward) {
- return Ordering.from(forward).reverse();
- }
-
- @Override
- public K firstKey() {
- return forward().lastKey();
- }
-
- @Override
- public K lastKey() {
- return forward().firstKey();
- }
-
- @Override
- public Entry<K, V> lowerEntry(K key) {
- return forward().higherEntry(key);
- }
-
- @Override
- public K lowerKey(K key) {
- return forward().higherKey(key);
- }
-
- @Override
- public Entry<K, V> floorEntry(K key) {
- return forward().ceilingEntry(key);
- }
-
- @Override
- public K floorKey(K key) {
- return forward().ceilingKey(key);
- }
-
- @Override
- public Entry<K, V> ceilingEntry(K key) {
- return forward().floorEntry(key);
- }
-
- @Override
- public K ceilingKey(K key) {
- return forward().floorKey(key);
- }
-
- @Override
- public Entry<K, V> higherEntry(K key) {
- return forward().lowerEntry(key);
- }
-
- @Override
- public K higherKey(K key) {
- return forward().lowerKey(key);
- }
-
- @Override
- public Entry<K, V> firstEntry() {
- return forward().lastEntry();
- }
-
- @Override
- public Entry<K, V> lastEntry() {
- return forward().firstEntry();
- }
-
- @Override
- public Entry<K, V> pollFirstEntry() {
- return forward().pollLastEntry();
- }
-
- @Override
- public Entry<K, V> pollLastEntry() {
- return forward().pollFirstEntry();
- }
-
- @Override
- public NavigableMap<K, V> descendingMap() {
- return forward();
- }
-
- private transient Set<Entry<K, V>> entrySet;
-
- @Override
- public Set<Entry<K, V>> entrySet() {
- Set<Entry<K, V>> result = entrySet;
- return (result == null) ? entrySet = createEntrySet() : result;
- }
-
- abstract Iterator<Entry<K, V>> entryIterator();
-
- Set<Entry<K, V>> createEntrySet() {
- return new EntrySet<K, V>() {
-
- @Override
- Map<K, V> map() {
- return DescendingMap.this;
- }
-
- @Override
- public Iterator<Entry<K, V>> iterator() {
- return entryIterator();
- }
- };
- }
-
- @Override
- public Set<K> keySet() {
- return navigableKeySet();
- }
-
- private transient NavigableSet<K> navigableKeySet;
-
- @Override
- public NavigableSet<K> navigableKeySet() {
- NavigableSet<K> result = navigableKeySet;
- return (result == null) ? navigableKeySet = new NavigableKeySet<K, V>(this) : result;
- }
-
- @Override
- public NavigableSet<K> descendingKeySet() {
- return forward().navigableKeySet();
- }
-
- @Override
- public
- NavigableMap<K, V>
- subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
- return forward().subMap(toKey, toInclusive, fromKey, fromInclusive).descendingMap();
- }
-
- @Override
- public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
- return forward().tailMap(toKey, inclusive).descendingMap();
- }
-
- @Override
- public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
- return forward().headMap(fromKey, inclusive).descendingMap();
- }
-
- @Override
- public SortedMap<K, V> subMap(K fromKey, K toKey) {
- return subMap(fromKey, true, toKey, false);
- }
-
- @Override
- public SortedMap<K, V> headMap(K toKey) {
- return headMap(toKey, false);
- }
-
- @Override
- public SortedMap<K, V> tailMap(K fromKey) {
- return tailMap(fromKey, true);
- }
-
- @Override
- public Collection<V> values() {
- return new Values<K, V>() {
- @Override
- Map<K, V> map() {
- return DescendingMap.this;
- }
- };
- }
- }
}
diff --git a/guava/src/com/google/common/collect/MinMaxPriorityQueue.java b/guava/src/com/google/common/collect/MinMaxPriorityQueue.java
index f9c2d92..4429c34 100644
--- a/guava/src/com/google/common/collect/MinMaxPriorityQueue.java
+++ b/guava/src/com/google/common/collect/MinMaxPriorityQueue.java
@@ -26,13 +26,13 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.math.IntMath;
import java.util.AbstractQueue;
-import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.PriorityQueue;
@@ -85,7 +85,7 @@ import java.util.Queue;
* @author Torbjorn Gannholm
* @since 8.0
*/
-// TODO(kevinb): GWT compatibility
+// TODO(kevinb): @GwtCompatible
@Beta
public final class MinMaxPriorityQueue<E> extends AbstractQueue<E> {
@@ -747,6 +747,7 @@ public final class MinMaxPriorityQueue<E> extends AbstractQueue<E> {
private class QueueIterator implements Iterator<E> {
private int cursor = -1;
private int expectedModCount = modCount;
+ // TODO(user): Switch to ArrayDeque once Guava supports it.
private Queue<E> forgetMeNot;
private List<E> skipMe;
private E lastFromForgetMeNot;
@@ -787,7 +788,7 @@ public final class MinMaxPriorityQueue<E> extends AbstractQueue<E> {
MoveDesc<E> moved = removeAt(cursor);
if (moved != null) {
if (forgetMeNot == null) {
- forgetMeNot = new ArrayDeque<E>();
+ forgetMeNot = new LinkedList<E>();
skipMe = new ArrayList<E>(3);
}
forgetMeNot.add(moved.toTrickle);
diff --git a/guava/src/com/google/common/collect/Multimap.java b/guava/src/com/google/common/collect/Multimap.java
index ed5afb3..900f820 100644
--- a/guava/src/com/google/common/collect/Multimap.java
+++ b/guava/src/com/google/common/collect/Multimap.java
@@ -19,139 +19,40 @@ package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
import java.util.Collection;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
/**
- * A collection that maps keys to values, similar to {@link Map}, but in which
- * each key may be associated with <i>multiple</i> values. You can visualize the
- * contents of a multimap either as a map from keys to <i>nonempty</i>
- * collections of values:
+ * A collection similar to a {@code Map}, but which may associate multiple
+ * values with a single key. If you call {@link #put} twice, with the same key
+ * but different values, the multimap contains mappings from the key to both
+ * values.
*
- * <ul>
- * <li>a → 1, 2
- * <li>b → 3
- * </ul>
+ * <p>The methods {@link #get}, {@link #keySet}, {@link #keys}, {@link #values},
+ * {@link #entries}, and {@link #asMap} return collections that are views of the
+ * multimap. If the multimap is modifiable, updating it can change the contents
+ * of those collections, and updating the collections will change the multimap.
+ * In contrast, {@link #replaceValues} and {@link #removeAll} return collections
+ * that are independent of subsequent multimap changes.
*
- * ... or as a single "flattened" collection of key-value pairs:
+ * <p>Depending on the implementation, a multimap may or may not allow duplicate
+ * key-value pairs. In other words, the multimap contents after adding the same
+ * key and value twice varies between implementations. In multimaps allowing
+ * duplicates, the multimap will contain two mappings, and {@code get} will
+ * return a collection that includes the value twice. In multimaps not
+ * supporting duplicates, the multimap will contain a single mapping from the
+ * key to the value, and {@code get} will return a collection that includes the
+ * value once.
*
- * <ul>
- * <li>a → 1
- * <li>a → 2
- * <li>b → 3
- * </ul>
- *
- * <p><b>Important:</b> although the first interpretation resembles how most
- * multimaps are <i>implemented</i>, the design of the {@code Multimap} API is
- * based on the <i>second</i> form. So, using the multimap shown above as an
- * example, the {@link #size} is {@code 3}, not {@code 2}, and the {@link
- * #values} collection is {@code [1, 2, 3]}, not {@code [[1, 2], [3]]}. For
- * those times when the first style is more useful, use the multimap's {@link
- * #asMap} view (or create a {@code Map<K, Collection<V>>} in the first place).
- *
- * <h3>Example</h3>
- *
- * <p>The following code: <pre> {@code
- *
- * ListMultimap<String, String> multimap = ArrayListMultimap.create();
- * for (President pres : US_PRESIDENTS_IN_ORDER) {
- * multimap.put(pres.firstName(), pres.lastName());
- * }
- * for (String firstName : multimap.keySet()) {
- * List<String> lastNames = multimap.get(firstName);
- * out.println(firstName + ": " + lastNames);
- * }}</pre>
- *
- * ... produces output such as: <pre> {@code
- *
- * Zachary: [Taylor]
- * John: [Adams, Adams, Tyler, Kennedy]
- * George: [Washington, Bush, Bush]
- * Grover: [Cleveland]
- * ...}</pre>
- *
- * <h3>Views</h3>
- *
- * <p>Much of the power of the multimap API comes from the <i>view
- * collections</i> it provides. These always reflect the latest state of the
- * multimap itself. When they support modification, the changes are
- * <i>write-through</i> (they automatically update the backing multimap). These
- * view collections are:
- *
- * <ul>
- * <li>{@link #asMap}, mentioned above</li>
- * <li>{@link #keys}, {@link #keySet}, {@link #values}, {@link #entries}, which
- * are similar to the corresponding view collections of {@link Map}
- * <li>and, notably, even the collection returned by {@link #get get(key)} is an
- * active view of the values corresponding to {@code key}
- * </ul>
- *
- * <p>The collections returned by the {@link #replaceValues replaceValues} and
- * {@link #removeAll removeAll} methods, which contain values that have just
- * been removed from the multimap, are naturally <i>not</i> views.
- *
- * <h3>Subinterfaces</h3>
- *
- * <p>Instead of using the {@code Multimap} interface directly, prefer the
- * subinterfaces {@link ListMultimap} and {@link SetMultimap}. These take their
- * names from the fact that the collections they return from {@code get} behave
- * like (and, of course, implement) {@link List} and {@link Set}, respectively.
- *
- * <p>For example, the "presidents" code snippet above used a {@code
- * ListMultimap}; if it had used a {@code SetMultimap} instead, two presidents
- * would have vanished, and last names might or might not appear in
- * chronological order.
- *
- * <p><b>Warning:</b> instances of type {@code Multimap} may not implement
- * {@link Object#equals} in the way you expect (multimaps containing the same
- * key-value pairs, even in the same order, may or may not be equal). The
- * recommended subinterfaces provide a much stronger guarantee.
- *
- * <h3>Comparison to a map of collections</h3>
- *
- * <p>Multimaps are commonly used in places where a {@code Map<K,
- * Collection<V>>} would otherwise have appeared. The differences include:
- *
- * <ul>
- * <li>There is no need to populate an empty collection before adding an entry
- * with {@link #put put}.
- * <li>{@code get} never returns {@code null}, only an empty collection.
- * <li>A key contained in the multimap always maps to at least one value. Any
- * operation that causes a key to have zero associated values has the effect
- * of <i>removing</i> that key from the multimap.
- * <li>The total entry count is available as {@link #size}.
- * <li>Many complex operations become easier; for example, {@code
- * Collections.min(multimap.values())} finds the smallest value across all
- * keys.
- * </ul>
- *
- * <h3>Implementations</h3>
- *
- * <p>As always, prefer the immutable implementations, {@link
- * ImmutableListMultimap} and {@link ImmutableSetMultimap}. General-purpose
- * mutable implementations are listed above under "All Known Implementing
- * Classes". You can also create a <i>custom</i> multimap, backed by any {@code
- * Map} and {@link Collection} types, using the {@link Multimaps#newMultimap
- * Multimaps.newMultimap} family of methods. Finally, another popular way to
- * obtain a multimap is using {@link Multimaps#index Multimaps.index}. See
- * the {@link Multimaps} class for these and other static utilities related
- * to multimaps.
- *
- * <h3>Other Notes</h3>
- *
- * <p>All methods that modify the multimap are optional. The view collections
- * returned by the multimap may or may not be modifiable. Any modification
- * method that is not supported will throw {@link
- * UnsupportedOperationException}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap">
- * {@code Multimap}</a>.
+ * <p>All methods that alter the multimap are optional, and the views returned
+ * by the multimap may or may not be modifiable. When modification isn't
+ * supported, those methods will throw an {@link UnsupportedOperationException}.
*
* @author Jared Levy
+ * @param <K> the type of keys maintained by this multimap
+ * @param <V> the type of mapped values
* @since 2.0 (imported from Google Collections Library)
*/
@GwtCompatible
@@ -207,7 +108,7 @@ public interface Multimap<K, V> {
boolean put(@Nullable K key, @Nullable V value);
/**
- * Removes a single key-value pair from the multimap.
+ * Removes a key-value pair from the multimap.
*
* @param key key of entry to remove from the multimap
* @param value value of entry to remove the multimap
@@ -268,17 +169,15 @@ public interface Multimap<K, V> {
// Views
/**
- * Returns a collection view containing the values associated with {@code key}
- * in this multimap, if any. Note that even when ({@code containsKey(key)} is
- * false, {@code get(key)} still returns an empty collection, not {@code
- * null}.
+ * Returns a collection view of all values associated with a key. If no
+ * mappings in the multimap have the provided key, an empty collection is
+ * returned.
*
* <p>Changes to the returned collection will update the underlying multimap,
* and vice versa.
*
* @param key key to search for in multimap
- * @return a view collection containing the zero or more values that the key
- * maps to
+ * @return the collection of values that the key maps to
*/
Collection<V> get(@Nullable K key);
diff --git a/guava/src/com/google/common/collect/Multimaps.java b/guava/src/com/google/common/collect/Multimaps.java
index 92e5d06..e2f593e 100644
--- a/guava/src/com/google/common/collect/Multimaps.java
+++ b/guava/src/com/google/common/collect/Multimaps.java
@@ -20,14 +20,17 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Joiner.MapJoiner;
+import com.google.common.base.Objects;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
+import com.google.common.collect.Collections2.TransformedCollection;
import com.google.common.collect.Maps.EntryTransformer;
import java.io.IOException;
@@ -35,6 +38,7 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.AbstractCollection;
+import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -52,10 +56,6 @@ import javax.annotation.Nullable;
/**
* Provides static methods acting on or generating a {@code Multimap}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Multimaps">
- * {@code Multimaps}</a>.
- *
* @author Jared Levy
* @author Robert Konigsberg
* @author Mike Bostock
@@ -67,14 +67,9 @@ public final class Multimaps {
private Multimaps() {}
/**
- * Creates a new {@code Multimap} backed by {@code map}, whose internal value
- * collections are generated by {@code factory}.
- *
- * <b>Warning: do not use</b> this method when the collections returned by
- * {@code factory} implement either {@link List} or {@code Set}! Use the more
- * specific method {@link #newListMultimap}, {@link #newSetMultimap} or {@link
- * #newSortedSetMultimap} instead, to avoid very surprising behavior from
- * {@link Multimap#equals}.
+ * Creates a new {@code Multimap} that uses the provided map and factory. It
+ * can generate a multimap based on arbitrary {@link Map} and
+ * {@link Collection} classes.
*
* <p>The {@code factory}-generated and {@code map} classes determine the
* multimap iteration order. They also specify the behavior of the
@@ -114,7 +109,7 @@ public final class Multimaps {
return new CustomMultimap<K, V>(map, factory);
}
- private static class CustomMultimap<K, V> extends AbstractMapBasedMultimap<K, V> {
+ private static class CustomMultimap<K, V> extends AbstractMultimap<K, V> {
transient Supplier<? extends Collection<V>> factory;
CustomMultimap(Map<K, Collection<V>> map,
@@ -423,13 +418,13 @@ public final class Multimaps {
* <p>It is imperative that the user manually synchronize on the returned
* multimap when accessing any of its collection views: <pre> {@code
*
- * Multimap<K, V> multimap = Multimaps.synchronizedMultimap(
+ * Multimap<K, V> m = Multimaps.synchronizedMultimap(
* HashMultimap.<K, V>create());
* ...
- * Collection<V> values = multimap.get(key); // Needn't be in synchronized block
+ * Set<K> s = m.keySet(); // Needn't be in synchronized block
* ...
- * synchronized (multimap) { // Synchronizing on multimap, not values!
- * Iterator<V> i = values.iterator(); // Must be in synchronized block
+ * synchronized (m) { // Synchronizing on m, not s!
+ * Iterator<K> i = s.iterator(); // Must be in synchronized block
* while (i.hasNext()) {
* foo(i.next());
* }
@@ -630,7 +625,7 @@ public final class Multimaps {
}
@Override public Iterator<Collection<V>> iterator() {
final Iterator<Collection<V>> iterator = delegate.iterator();
- return new UnmodifiableIterator<Collection<V>>() {
+ return new Iterator<Collection<V>>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
@@ -639,6 +634,10 @@ public final class Multimaps {
public Collection<V> next() {
return unmodifiableValueCollection(iterator.next());
}
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
};
}
@Override public Object[] toArray() {
@@ -1061,7 +1060,7 @@ public final class Multimaps {
@Override
public Set<V> get(final K key) {
- return new Sets.ImprovedAbstractSet<V>() {
+ return new AbstractSet<V>() {
@Override public Iterator<V> iterator() {
return new Iterator<V>() {
int i;
@@ -1142,7 +1141,7 @@ public final class Multimaps {
@Override
public Multiset<K> keys() {
- return new Multimaps.Keys<K, V>(this);
+ return Multisets.forSet(map.keySet());
}
@Override
@@ -1193,27 +1192,35 @@ public final class Multimaps {
}
/** @see MapMultimap#asMap */
- class AsMapEntries extends Sets.ImprovedAbstractSet<Entry<K, Collection<V>>> {
+ class AsMapEntries extends AbstractSet<Entry<K, Collection<V>>> {
@Override public int size() {
return map.size();
}
@Override public Iterator<Entry<K, Collection<V>>> iterator() {
- return new TransformedIterator<K, Entry<K, Collection<V>>>(map.keySet().iterator()) {
+ return new Iterator<Entry<K, Collection<V>>>() {
+ final Iterator<K> keys = map.keySet().iterator();
+
@Override
- Entry<K, Collection<V>> transform(final K key) {
+ public boolean hasNext() {
+ return keys.hasNext();
+ }
+ @Override
+ public Entry<K, Collection<V>> next() {
+ final K key = keys.next();
return new AbstractMapEntry<K, Collection<V>>() {
- @Override
- public K getKey() {
+ @Override public K getKey() {
return key;
}
-
- @Override
- public Collection<V> getValue() {
+ @Override public Collection<V> getValue() {
return get(key);
}
};
}
+ @Override
+ public void remove() {
+ keys.remove();
+ }
};
}
@@ -1315,6 +1322,7 @@ public final class Multimaps {
*
* @since 7.0
*/
+ @Beta
public static <K, V1, V2> Multimap<K, V2> transformValues(
Multimap<K, V1> fromMultimap, final Function<? super V1, V2> function) {
checkNotNull(function);
@@ -1383,29 +1391,15 @@ public final class Multimaps {
*
* @since 7.0
*/
+ @Beta
public static <K, V1, V2> Multimap<K, V2> transformEntries(
Multimap<K, V1> fromMap,
EntryTransformer<? super K, ? super V1, V2> transformer) {
return new TransformedEntriesMultimap<K, V1, V2>(fromMap, transformer);
}
-
- static final class ValueFunction<K, V1, V2> implements Function<V1, V2> {
- private final K key;
- private final EntryTransformer<? super K, ? super V1, V2> transformer;
-
- ValueFunction(K key, EntryTransformer<? super K, ? super V1, V2> transformer) {
- this.key = key;
- this.transformer = transformer;
- }
-
- @Override
- public V2 apply(@Nullable V1 value) {
- return transformer.transformEntry(key, value);
- }
- }
private static class TransformedEntriesMultimap<K, V1, V2>
- extends AbstractMultimap<K, V2> {
+ implements Multimap<K, V2> {
final Multimap<K, V1> fromMultimap;
final EntryTransformer<? super K, ? super V1, V2> transformer;
@@ -1415,25 +1409,30 @@ public final class Multimaps {
this.transformer = checkNotNull(transformer);
}
- Collection<V2> transform(K key, Collection<V1> values) {
- Function<V1, V2> function = new ValueFunction<K, V1, V2>(key, transformer);
- if (values instanceof List) {
- return Lists.transform((List<V1>) values, function);
- } else {
- return Collections2.transform(values, function);
- }
+ Collection<V2> transform(final K key, Collection<V1> values) {
+ return Collections2.transform(values, new Function<V1, V2>() {
+ @Override public V2 apply(V1 value) {
+ return transformer.transformEntry(key, value);
+ }
+ });
}
- @Override
- Map<K, Collection<V2>> createAsMap() {
- return Maps.transformEntries(fromMultimap.asMap(),
- new EntryTransformer<K, Collection<V1>, Collection<V2>>() {
+ private transient Map<K, Collection<V2>> asMap;
- @Override public Collection<V2> transformEntry(
- K key, Collection<V1> value) {
- return transform(key, value);
- }
- });
+ @Override public Map<K, Collection<V2>> asMap() {
+ if (asMap == null) {
+ Map<K, Collection<V2>> aM = Maps.transformEntries(fromMultimap.asMap(),
+ new EntryTransformer<K, Collection<V1>, Collection<V2>>() {
+
+ @Override public Collection<V2> transformEntry(
+ K key, Collection<V1> value) {
+ return transform(key, value);
+ }
+ });
+ asMap = aM;
+ return aM;
+ }
+ return asMap;
}
@Override public void clear() {
@@ -1454,25 +1453,58 @@ public final class Multimaps {
return values().contains(value);
}
- @Override
- Iterator<Entry<K, V2>> entryIterator() {
- return Iterators.transform(
- fromMultimap.entries().iterator(), new Function<Entry<K, V1>, Entry<K, V2>>() {
- @Override
- public Entry<K, V2> apply(final Entry<K, V1> entry) {
- return new AbstractMapEntry<K, V2>() {
- @Override
- public K getKey() {
- return entry.getKey();
- }
+ private transient Collection<Entry<K, V2>> entries;
+
+ @Override public Collection<Entry<K, V2>> entries() {
+ if (entries == null) {
+ Collection<Entry<K, V2>> es = new TransformedEntries(transformer);
+ entries = es;
+ return es;
+ }
+ return entries;
+ }
+
+ private class TransformedEntries
+ extends TransformedCollection<Entry<K, V1>, Entry<K, V2>> {
+
+ TransformedEntries(
+ final EntryTransformer<? super K, ? super V1, V2> transformer) {
+ super(fromMultimap.entries(),
+ new Function<Entry<K, V1>, Entry<K, V2>>() {
+ @Override public Entry<K, V2> apply(final Entry<K, V1> entry) {
+ return new AbstractMapEntry<K, V2>() {
+
+ @Override public K getKey() {
+ return entry.getKey();
+ }
+
+ @Override public V2 getValue() {
+ return transformer.transformEntry(
+ entry.getKey(), entry.getValue());
+ }
+ };
+ }
+ });
+ }
+
+ @Override public boolean contains(Object o) {
+ if (o instanceof Entry) {
+ Entry<?, ?> entry = (Entry<?, ?>) o;
+ return containsEntry(entry.getKey(), entry.getValue());
+ }
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public boolean remove(Object o) {
+ if (o instanceof Entry) {
+ Entry<?, ?> entry = (Entry<?, ?>) o;
+ Collection<V2> values = get((K) entry.getKey());
+ return values.remove(entry.getValue());
+ }
+ return false;
+ }
- @Override
- public V2 getValue() {
- return transformer.transformEntry(entry.getKey(), entry.getValue());
- }
- };
- }
- });
}
@Override public Collection<V2> get(final K key) {
@@ -1522,16 +1554,39 @@ public final class Multimaps {
@Override public int size() {
return fromMultimap.size();
}
-
- @Override
- Collection<V2> createValues() {
- return Collections2.transform(
- fromMultimap.entries(), new Function<Entry<K, V1>, V2>() {
- @Override public V2 apply(Entry<K, V1> entry) {
- return transformer.transformEntry(
- entry.getKey(), entry.getValue());
- }
- });
+
+ private transient Collection<V2> values;
+
+ @Override public Collection<V2> values() {
+ if (values == null) {
+ Collection<V2> vs = Collections2.transform(
+ fromMultimap.entries(), new Function<Entry<K, V1>, V2>() {
+
+ @Override public V2 apply(Entry<K, V1> entry) {
+ return transformer.transformEntry(
+ entry.getKey(), entry.getValue());
+ }
+ });
+ values = vs;
+ return vs;
+ }
+ return values;
+ }
+
+ @Override public boolean equals(Object obj) {
+ if (obj instanceof Multimap) {
+ Multimap<?, ?> other = (Multimap<?, ?>) obj;
+ return asMap().equals(other.asMap());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return asMap().hashCode();
+ }
+
+ @Override public String toString() {
+ return asMap().toString();
}
}
@@ -1576,6 +1631,7 @@ public final class Multimaps {
*
* @since 7.0
*/
+ @Beta
public static <K, V1, V2> ListMultimap<K, V2> transformValues(
ListMultimap<K, V1> fromMultimap,
final Function<? super V1, V2> function) {
@@ -1642,6 +1698,7 @@ public final class Multimaps {
*
* @since 7.0
*/
+ @Beta
public static <K, V1, V2> ListMultimap<K, V2> transformEntries(
ListMultimap<K, V1> fromMap,
EntryTransformer<? super K, ? super V1, V2> transformer) {
@@ -1728,6 +1785,24 @@ public final class Multimaps {
}
/**
+ * <b>Deprecated.</b>
+ *
+ * @since 10.0
+ * @deprecated use {@link #index(Iterator, Function)} by casting {@code
+ * values} to {@code Iterator<V>}, or better yet, by implementing only
+ * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled
+ * for deletion in March 2012.</b>
+ */
+ @Beta
+ @Deprecated
+ public static <K, V, I extends Object & Iterable<V> & Iterator<V>>
+ ImmutableListMultimap<K, V> index(
+ I values, Function<? super V, K> keyFunction) {
+ Iterable<V> valuesIterable = checkNotNull(values);
+ return index(valuesIterable, keyFunction);
+ }
+
+ /**
* Creates an index {@code ImmutableListMultimap} that contains the results of
* applying a specified function to each item in an {@code Iterator} of
* values. Each value will be stored as a value in the resulting multimap,
@@ -1783,36 +1858,39 @@ public final class Multimaps {
return builder.build();
}
- static class Keys<K, V> extends AbstractMultiset<K> {
- final Multimap<K, V> multimap;
-
- Keys(Multimap<K, V> multimap) {
- this.multimap = multimap;
- }
+ static abstract class Keys<K, V> extends AbstractMultiset<K> {
+ abstract Multimap<K, V> multimap();
@Override Iterator<Multiset.Entry<K>> entryIterator() {
- return new TransformedIterator<Map.Entry<K, Collection<V>>, Multiset.Entry<K>>(
- multimap.asMap().entrySet().iterator()) {
- @Override
- Multiset.Entry<K> transform(
- final Map.Entry<K, Collection<V>> backingEntry) {
+ final Iterator<Map.Entry<K, Collection<V>>> backingIterator =
+ multimap().asMap().entrySet().iterator();
+ return new Iterator<Multiset.Entry<K>>() {
+ @Override public boolean hasNext() {
+ return backingIterator.hasNext();
+ }
+
+ @Override public Multiset.Entry<K> next() {
+ final Map.Entry<K, Collection<V>> backingEntry =
+ backingIterator.next();
return new Multisets.AbstractEntry<K>() {
- @Override
- public K getElement() {
+ @Override public K getElement() {
return backingEntry.getKey();
}
- @Override
- public int getCount() {
+ @Override public int getCount() {
return backingEntry.getValue().size();
}
};
}
+
+ @Override public void remove() {
+ backingIterator.remove();
+ }
};
}
@Override int distinctElements() {
- return multimap.asMap().size();
+ return multimap().asMap().size();
}
@Override Set<Multiset.Entry<K>> createEntrySet() {
@@ -1833,22 +1911,22 @@ public final class Multimaps {
}
@Override public boolean isEmpty() {
- return multimap.isEmpty();
+ return multimap().isEmpty();
}
@Override public boolean contains(@Nullable Object o) {
- if (o instanceof Multiset.Entry) {
+ if (o instanceof Multiset.Entry<?>) {
Multiset.Entry<?> entry = (Multiset.Entry<?>) o;
- Collection<V> collection = multimap.asMap().get(entry.getElement());
+ Collection<V> collection = multimap().asMap().get(entry.getElement());
return collection != null && collection.size() == entry.getCount();
}
return false;
}
@Override public boolean remove(@Nullable Object o) {
- if (o instanceof Multiset.Entry) {
+ if (o instanceof Multiset.Entry<?>) {
Multiset.Entry<?> entry = (Multiset.Entry<?>) o;
- Collection<V> collection = multimap.asMap().get(entry.getElement());
+ Collection<V> collection = multimap().asMap().get(entry.getElement());
if (collection != null && collection.size() == entry.getCount()) {
collection.clear();
return true;
@@ -1859,16 +1937,30 @@ public final class Multimaps {
}
@Override public boolean contains(@Nullable Object element) {
- return multimap.containsKey(element);
+ return multimap().containsKey(element);
}
@Override public Iterator<K> iterator() {
- return Maps.keyIterator(multimap.entries().iterator());
+ return Iterators.transform(multimap().entries().iterator(),
+ new Function<Map.Entry<K, V>, K>() {
+ @Override public K apply(Map.Entry<K, V> entry) {
+ return entry.getKey();
+ }
+ });
}
@Override public int count(@Nullable Object element) {
- Collection<V> values = Maps.safeGet(multimap.asMap(), element);
- return (values == null) ? 0 : values.size();
+ try {
+ if (multimap().containsKey(element)) {
+ Collection<V> values = multimap().asMap().get(element);
+ return (values == null) ? 0 : values.size();
+ }
+ return 0;
+ } catch (ClassCastException e) {
+ return 0;
+ } catch (NullPointerException e) {
+ return 0;
+ }
}
@Override public int remove(@Nullable Object element, int occurrences) {
@@ -1877,7 +1969,14 @@ public final class Multimaps {
return count(element);
}
- Collection<V> values = Maps.safeGet(multimap.asMap(), element);
+ Collection<V> values;
+ try {
+ values = multimap().asMap().get(element);
+ } catch (ClassCastException e) {
+ return 0;
+ } catch (NullPointerException e) {
+ return 0;
+ }
if (values == null) {
return 0;
@@ -1897,35 +1996,45 @@ public final class Multimaps {
}
@Override public void clear() {
- multimap.clear();
+ multimap().clear();
}
@Override public Set<K> elementSet() {
- return multimap.keySet();
+ return multimap().keySet();
}
}
- static class Values<K, V> extends AbstractCollection<V> {
- final Multimap<K, V> multimap;
-
- Values(Multimap<K, V> multimap) {
- this.multimap = multimap;
- }
+ static abstract class Values<K, V> extends AbstractCollection<V> {
+ abstract Multimap<K, V> multimap();
@Override public Iterator<V> iterator() {
- return Maps.valueIterator(multimap.entries().iterator());
+ final Iterator<Map.Entry<K, V>> backingIterator =
+ multimap().entries().iterator();
+ return new Iterator<V>() {
+ @Override public boolean hasNext() {
+ return backingIterator.hasNext();
+ }
+
+ @Override public V next() {
+ return backingIterator.next().getValue();
+ }
+
+ @Override public void remove() {
+ backingIterator.remove();
+ }
+ };
}
@Override public int size() {
- return multimap.size();
+ return multimap().size();
}
@Override public boolean contains(@Nullable Object o) {
- return multimap.containsValue(o);
+ return multimap().containsValue(o);
}
@Override public void clear() {
- multimap.clear();
+ multimap().clear();
}
}
@@ -1941,7 +2050,7 @@ public final class Multimaps {
}
@Override public boolean contains(@Nullable Object o) {
- if (o instanceof Map.Entry) {
+ if (o instanceof Map.Entry<?, ?>) {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
return multimap().containsEntry(entry.getKey(), entry.getValue());
}
@@ -1949,7 +2058,7 @@ public final class Multimaps {
}
@Override public boolean remove(@Nullable Object o) {
- if (o instanceof Map.Entry) {
+ if (o instanceof Map.Entry<?, ?>) {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
return multimap().remove(entry.getKey(), entry.getValue());
}
@@ -2047,8 +2156,8 @@ public final class Multimaps {
* <p>The resulting multimap's views have iterators that don't support
* {@code remove()}, but all other methods are supported by the multimap and
* its views. When adding a key that doesn't satisfy the predicate, the
- * multimap's {@code put()}, {@code putAll()}, and {@code replaceValues()}
- * methods throw an {@link IllegalArgumentException}.
+ * multimap's {@code put()}, {@code putAll()}, and {@replaceValues()} methods
+ * throw an {@link IllegalArgumentException}.
*
* <p>When methods such as {@code removeAll()} and {@code clear()} are called on
* the filtered multimap or its views, only mappings whose keys satisfy the
@@ -2069,21 +2178,19 @@ public final class Multimaps {
*
* @since 11.0
*/
+ @Beta
@GwtIncompatible(value = "untested")
public static <K, V> Multimap<K, V> filterKeys(
- Multimap<K, V> unfiltered, final Predicate<? super K> keyPredicate) {
- if (unfiltered instanceof FilteredKeyMultimap) {
- FilteredKeyMultimap<K, V> prev = (FilteredKeyMultimap<K, V>) unfiltered;
- return new FilteredKeyMultimap<K, V>(prev.unfiltered,
- Predicates.and(prev.keyPredicate, keyPredicate));
- } else if (unfiltered instanceof FilteredMultimap) {
- FilteredMultimap<K, V> prev = (FilteredMultimap<K, V>) unfiltered;
- return new FilteredEntryMultimap<K, V>(prev.unfiltered,
- Predicates.<Entry<K, V>>and(prev.entryPredicate(),
- Predicates.compose(keyPredicate, Maps.<K>keyFunction())));
- } else {
- return new FilteredKeyMultimap<K, V>(unfiltered, keyPredicate);
- }
+ Multimap<K, V> unfiltered, final Predicate<? super K> keyPredicate) {
+ checkNotNull(keyPredicate);
+ Predicate<Entry<K, V>> entryPredicate =
+ new Predicate<Entry<K, V>>() {
+ @Override
+ public boolean apply(Entry<K, V> input) {
+ return keyPredicate.apply(input.getKey());
+ }
+ };
+ return filterEntries(unfiltered, entryPredicate);
}
/**
@@ -2094,8 +2201,8 @@ public final class Multimaps {
* <p>The resulting multimap's views have iterators that don't support
* {@code remove()}, but all other methods are supported by the multimap and
* its views. When adding a value that doesn't satisfy the predicate, the
- * multimap's {@code put()}, {@code putAll()}, and {@code replaceValues()}
- * methods throw an {@link IllegalArgumentException}.
+ * multimap's {@code put()}, {@code putAll()}, and {@replaceValues()} methods
+ * throw an {@link IllegalArgumentException}.
*
* <p>When methods such as {@code removeAll()} and {@code clear()} are called on
* the filtered multimap or its views, only mappings whose value satisfy the
@@ -2116,10 +2223,19 @@ public final class Multimaps {
*
* @since 11.0
*/
+ @Beta
@GwtIncompatible(value = "untested")
public static <K, V> Multimap<K, V> filterValues(
- Multimap<K, V> unfiltered, final Predicate<? super V> valuePredicate) {
- return filterEntries(unfiltered, Predicates.compose(valuePredicate, Maps.<V>valueFunction()));
+ Multimap<K, V> unfiltered, final Predicate<? super V> valuePredicate) {
+ checkNotNull(valuePredicate);
+ Predicate<Entry<K, V>> entryPredicate =
+ new Predicate<Entry<K, V>>() {
+ @Override
+ public boolean apply(Entry<K, V> input) {
+ return valuePredicate.apply(input.getValue());
+ }
+ };
+ return filterEntries(unfiltered, entryPredicate);
}
/**
@@ -2130,8 +2246,8 @@ public final class Multimaps {
* <p>The resulting multimap's views have iterators that don't support
* {@code remove()}, but all other methods are supported by the multimap and
* its views. When adding a key/value pair that doesn't satisfy the predicate,
- * multimap's {@code put()}, {@code putAll()}, and {@code replaceValues()}
- * methods throw an {@link IllegalArgumentException}.
+ * multimap's {@code put()}, {@code putAll()}, and {@replaceValues()} methods
+ * throw an {@link IllegalArgumentException}.
*
* <p>When methods such as {@code removeAll()} and {@code clear()} are called on
* the filtered multimap or its views, only mappings whose keys satisfy the
@@ -2150,27 +2266,489 @@ public final class Multimaps {
*
* @since 11.0
*/
+ @Beta
@GwtIncompatible(value = "untested")
public static <K, V> Multimap<K, V> filterEntries(
- Multimap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) {
+ Multimap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) {
checkNotNull(entryPredicate);
return (unfiltered instanceof FilteredMultimap)
? filterFiltered((FilteredMultimap<K, V>) unfiltered, entryPredicate)
- : new FilteredEntryMultimap<K, V>(checkNotNull(unfiltered), entryPredicate);
+ : new FilteredMultimap<K, V>(checkNotNull(unfiltered), entryPredicate);
}
/**
* Support removal operations when filtering a filtered multimap. Since a
* filtered multimap has iterators that don't support remove, passing one to
- * the FilteredEntryMultimap constructor would lead to a multimap whose removal
+ * the FilteredMultimap constructor would lead to a multimap whose removal
* operations would fail. This method combines the predicates to avoid that
* problem.
*/
- private static <K, V> Multimap<K, V> filterFiltered(FilteredMultimap<K, V> multimap,
+ private static <K, V> Multimap<K, V> filterFiltered(FilteredMultimap<K, V> map,
Predicate<? super Entry<K, V>> entryPredicate) {
Predicate<Entry<K, V>> predicate
- = Predicates.and(multimap.entryPredicate(), entryPredicate);
- return new FilteredEntryMultimap<K, V>(multimap.unfiltered, predicate);
+ = Predicates.and(map.predicate, entryPredicate);
+ return new FilteredMultimap<K, V>(map.unfiltered, predicate);
+ }
+
+ private static class FilteredMultimap<K, V> implements Multimap<K, V> {
+ final Multimap<K, V> unfiltered;
+ final Predicate<? super Entry<K, V>> predicate;
+
+ FilteredMultimap(Multimap<K, V> unfiltered, Predicate<? super Entry<K, V>> predicate) {
+ this.unfiltered = unfiltered;
+ this.predicate = predicate;
+ }
+
+ @Override public int size() {
+ return entries().size();
+ }
+
+ @Override public boolean isEmpty() {
+ return entries().isEmpty();
+ }
+
+ @Override public boolean containsKey(Object key) {
+ return asMap().containsKey(key);
+ }
+
+ @Override public boolean containsValue(Object value) {
+ return values().contains(value);
+ }
+
+ // This method should be called only when key is a K and value is a V.
+ @SuppressWarnings("unchecked")
+ boolean satisfiesPredicate(Object key, Object value) {
+ return predicate.apply(Maps.immutableEntry((K) key, (V) value));
+ }
+
+ @Override public boolean containsEntry(Object key, Object value) {
+ return unfiltered.containsEntry(key, value) && satisfiesPredicate(key, value);
+ }
+
+ @Override public boolean put(K key, V value) {
+ checkArgument(satisfiesPredicate(key, value));
+ return unfiltered.put(key, value);
+ }
+
+ @Override public boolean remove(Object key, Object value) {
+ return containsEntry(key, value) ? unfiltered.remove(key, value) : false;
+ }
+
+ @Override public boolean putAll(K key, Iterable<? extends V> values) {
+ for (V value : values) {
+ checkArgument(satisfiesPredicate(key, value));
+ }
+ return unfiltered.putAll(key, values);
+ }
+
+ @Override public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
+ for (Entry<? extends K, ? extends V> entry : multimap.entries()) {
+ checkArgument(satisfiesPredicate(entry.getKey(), entry.getValue()));
+ }
+ return unfiltered.putAll(multimap);
+ }
+
+ @Override public Collection<V> replaceValues(K key, Iterable<? extends V> values) {
+ for (V value : values) {
+ checkArgument(satisfiesPredicate(key, value));
+ }
+ // Not calling unfiltered.replaceValues() since values that don't satisify
+ // the filter should remain in the multimap.
+ Collection<V> oldValues = removeAll(key);
+ unfiltered.putAll(key, values);
+ return oldValues;
+ }
+
+ @Override public Collection<V> removeAll(Object key) {
+ List<V> removed = Lists.newArrayList();
+ Collection<V> values = unfiltered.asMap().get(key);
+ if (values != null) {
+ Iterator<V> iterator = values.iterator();
+ while (iterator.hasNext()) {
+ V value = iterator.next();
+ if (satisfiesPredicate(key, value)) {
+ removed.add(value);
+ iterator.remove();
+ }
+ }
+ }
+ if (unfiltered instanceof SetMultimap) {
+ return Collections.unmodifiableSet(Sets.newLinkedHashSet(removed));
+ } else {
+ return Collections.unmodifiableList(removed);
+ }
+ }
+
+ @Override public void clear() {
+ entries().clear();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof Multimap) {
+ Multimap<?, ?> that = (Multimap<?, ?>) object;
+ return asMap().equals(that.asMap());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return asMap().hashCode();
+ }
+
+ @Override public String toString() {
+ return asMap().toString();
+ }
+
+ class ValuePredicate implements Predicate<V> {
+ final K key;
+ ValuePredicate(K key) {
+ this.key = key;
+ }
+ @Override public boolean apply(V value) {
+ return satisfiesPredicate(key, value);
+ }
+ }
+
+ Collection<V> filterCollection(Collection<V> collection, Predicate<V> predicate) {
+ if (collection instanceof Set) {
+ return Sets.filter((Set<V>) collection, predicate);
+ } else {
+ return Collections2.filter(collection, predicate);
+ }
+ }
+
+ @Override public Collection<V> get(K key) {
+ return filterCollection(unfiltered.get(key), new ValuePredicate(key));
+ }
+
+ @Override public Set<K> keySet() {
+ return asMap().keySet();
+ }
+
+ Collection<V> values;
+
+ @Override public Collection<V> values() {
+ return (values == null) ? values = new Values() : values;
+ }
+
+ class Values extends Multimaps.Values<K, V> {
+ @Override Multimap<K, V> multimap() {
+ return FilteredMultimap.this;
+ }
+
+ @Override public boolean contains(@Nullable Object o) {
+ return Iterators.contains(iterator(), o);
+ }
+
+ // Override remove methods since iterator doesn't support remove.
+
+ @Override public boolean remove(Object o) {
+ Iterator<Entry<K, V>> iterator = unfiltered.entries().iterator();
+ while (iterator.hasNext()) {
+ Entry<K, V> entry = iterator.next();
+ if (Objects.equal(o, entry.getValue()) && predicate.apply(entry)) {
+ iterator.remove();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ boolean changed = false;
+ Iterator<Entry<K, V>> iterator = unfiltered.entries().iterator();
+ while (iterator.hasNext()) {
+ Entry<K, V> entry = iterator.next();
+ if (c.contains(entry.getValue()) && predicate.apply(entry)) {
+ iterator.remove();
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ boolean changed = false;
+ Iterator<Entry<K, V>> iterator = unfiltered.entries().iterator();
+ while (iterator.hasNext()) {
+ Entry<K, V> entry = iterator.next();
+ if (!c.contains(entry.getValue()) && predicate.apply(entry)) {
+ iterator.remove();
+ changed = true;
+ }
+ }
+ return changed;
+ }
+ }
+
+ Collection<Entry<K, V>> entries;
+
+ @Override public Collection<Entry<K, V>> entries() {
+ return (entries == null)
+ ? entries = Collections2.filter(unfiltered.entries(), predicate)
+ : entries;
+ }
+
+ /**
+ * Remove all filtered asMap() entries that satisfy the predicate.
+ */
+ boolean removeEntriesIf(Predicate<Map.Entry<K, Collection<V>>> removalPredicate) {
+ Iterator<Map.Entry<K, Collection<V>>> iterator = unfiltered.asMap().entrySet().iterator();
+ boolean changed = false;
+ while (iterator.hasNext()) {
+ // Determine whether to remove the filtered values with this key.
+ Map.Entry<K, Collection<V>> entry = iterator.next();
+ K key = entry.getKey();
+ Collection<V> collection = entry.getValue();
+ Predicate<V> valuePredicate = new ValuePredicate(key);
+ Collection<V> filteredCollection = filterCollection(collection, valuePredicate);
+ Map.Entry<K, Collection<V>> filteredEntry = Maps.immutableEntry(key, filteredCollection);
+ if (removalPredicate.apply(filteredEntry) && !filteredCollection.isEmpty()) {
+ changed = true;
+ if (Iterables.all(collection, valuePredicate)) {
+ iterator.remove(); // Remove all values for the key.
+ } else {
+ filteredCollection.clear(); // Remove the filtered values only.
+ }
+ }
+ }
+ return changed;
+ }
+
+ Map<K, Collection<V>> asMap;
+
+ @Override public Map<K, Collection<V>> asMap() {
+ return (asMap == null) ? asMap = createAsMap() : asMap;
+ }
+
+ static final Predicate<Collection<?>> NOT_EMPTY = new Predicate<Collection<?>>() {
+ @Override public boolean apply(Collection<?> input) {
+ return !input.isEmpty();
+ }
+ };
+
+ Map<K, Collection<V>> createAsMap() {
+ // Select the values that satisify the predicate.
+ EntryTransformer<K, Collection<V>, Collection<V>> transformer
+ = new EntryTransformer<K, Collection<V>, Collection<V>>() {
+ @Override public Collection<V> transformEntry(K key, Collection<V> collection) {
+ return filterCollection(collection, new ValuePredicate(key));
+ }
+ };
+ Map<K, Collection<V>> transformed
+ = Maps.transformEntries(unfiltered.asMap(), transformer);
+
+ // Select the keys that have at least one value remaining.
+ Map<K, Collection<V>> filtered = Maps.filterValues(transformed, NOT_EMPTY);
+
+ // Override the removal methods, since removing a map entry should not
+ // affect values that don't satisfy the filter.
+ return new AsMap(filtered);
+ }
+
+ class AsMap extends ForwardingMap<K, Collection<V>> {
+ final Map<K, Collection<V>> delegate;
+
+ AsMap(Map<K, Collection<V>> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override protected Map<K, Collection<V>> delegate() {
+ return delegate;
+ }
+
+ @Override public Collection<V> remove(Object o) {
+ Collection<V> output = FilteredMultimap.this.removeAll(o);
+ return output.isEmpty() ? null : output;
+ }
+
+ @Override public void clear() {
+ FilteredMultimap.this.clear();
+ }
+
+ Set<K> keySet;
+
+ @Override public Set<K> keySet() {
+ return (keySet == null) ? keySet = new KeySet() : keySet;
+ }
+
+ class KeySet extends Maps.KeySet<K, Collection<V>> {
+ @Override Map<K, Collection<V>> map() {
+ return AsMap.this;
+ }
+
+ @Override public boolean remove(Object o) {
+ Collection<V> collection = delegate.get(o);
+ if (collection == null) {
+ return false;
+ }
+ collection.clear();
+ return true;
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ return Sets.removeAllImpl(this, c);
+ }
+
+ @Override public boolean retainAll(final Collection<?> c) {
+ Predicate<Map.Entry<K, Collection<V>>> removalPredicate
+ = new Predicate<Map.Entry<K, Collection<V>>>() {
+ @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
+ return !c.contains(entry.getKey());
+ }
+ };
+ return removeEntriesIf(removalPredicate);
+ }
+ }
+
+ Values asMapValues;
+
+ @Override public Collection<Collection<V>> values() {
+ return (asMapValues == null) ? asMapValues = new Values() : asMapValues;
+ }
+
+ class Values extends Maps.Values<K, Collection<V>> {
+ @Override Map<K, Collection<V>> map() {
+ return AsMap.this;
+ }
+
+ @Override public boolean remove(Object o) {
+ for (Collection<V> collection : this) {
+ if (collection.equals(o)) {
+ collection.clear();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override public boolean removeAll(final Collection<?> c) {
+ Predicate<Map.Entry<K, Collection<V>>> removalPredicate
+ = new Predicate<Map.Entry<K, Collection<V>>>() {
+ @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
+ return c.contains(entry.getValue());
+ }
+ };
+ return removeEntriesIf(removalPredicate);
+ }
+
+ @Override public boolean retainAll(final Collection<?> c) {
+ Predicate<Map.Entry<K, Collection<V>>> removalPredicate
+ = new Predicate<Map.Entry<K, Collection<V>>>() {
+ @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
+ return !c.contains(entry.getValue());
+ }
+ };
+ return removeEntriesIf(removalPredicate);
+ }
+ }
+
+ EntrySet entrySet;
+
+ @Override public Set<Map.Entry<K, Collection<V>>> entrySet() {
+ return (entrySet == null) ? entrySet = new EntrySet(super.entrySet()) : entrySet;
+ }
+
+ class EntrySet extends Maps.EntrySet<K, Collection<V>> {
+ Set<Map.Entry<K, Collection<V>>> delegateEntries;
+
+ public EntrySet(Set<Map.Entry<K, Collection<V>>> delegateEntries) {
+ this.delegateEntries = delegateEntries;
+ }
+
+ @Override Map<K, Collection<V>> map() {
+ return AsMap.this;
+ }
+
+ @Override public Iterator<Map.Entry<K, Collection<V>>> iterator() {
+ return delegateEntries.iterator();
+ }
+
+ @Override public boolean remove(Object o) {
+ if (o instanceof Entry<?, ?>) {
+ Entry<?, ?> entry = (Entry<?, ?>) o;
+ Collection<V> collection = delegate.get(entry.getKey());
+ if (collection != null && collection.equals(entry.getValue())) {
+ collection.clear();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ return Sets.removeAllImpl(this, c);
+ }
+
+ @Override public boolean retainAll(final Collection<?> c) {
+ Predicate<Map.Entry<K, Collection<V>>> removalPredicate
+ = new Predicate<Map.Entry<K, Collection<V>>>() {
+ @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
+ return !c.contains(entry);
+ }
+ };
+ return removeEntriesIf(removalPredicate);
+ }
+ }
+ }
+
+ AbstractMultiset<K> keys;
+
+ @Override public Multiset<K> keys() {
+ return (keys == null) ? keys = new Keys() : keys;
+ }
+
+ class Keys extends Multimaps.Keys<K, V> {
+ @Override Multimap<K, V> multimap() {
+ return FilteredMultimap.this;
+ }
+
+ @Override public int remove(Object o, int occurrences) {
+ checkArgument(occurrences >= 0);
+ Collection<V> values = unfiltered.asMap().get(o);
+ if (values == null) {
+ return 0;
+ }
+ int priorCount = 0;
+ int removed = 0;
+ Iterator<V> iterator = values.iterator();
+ while (iterator.hasNext()) {
+ if (satisfiesPredicate(o, iterator.next())) {
+ priorCount++;
+ if (removed < occurrences) {
+ iterator.remove();
+ removed++;
+ }
+ }
+ }
+ return priorCount;
+ }
+
+ @Override Set<Multiset.Entry<K>> createEntrySet() {
+ return new EntrySet();
+ }
+
+ class EntrySet extends Multimaps.Keys<K, V>.KeysEntrySet {
+ @Override public boolean removeAll(Collection<?> c) {
+ return Sets.removeAllImpl(this, c);
+ }
+
+ @Override public boolean retainAll(final Collection<?> c) {
+ Predicate<Map.Entry<K, Collection<V>>> removalPredicate
+ = new Predicate<Map.Entry<K, Collection<V>>>() {
+ @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
+ Multiset.Entry<K> multisetEntry
+ = Multisets.immutableEntry(entry.getKey(), entry.getValue().size());
+ return !c.contains(multisetEntry);
+ }
+ };
+ return removeEntriesIf(removalPredicate);
+ }
+ }
+ }
}
// TODO(jlevy): Create methods that filter a SetMultimap or SortedSetMultimap.
diff --git a/guava/src/com/google/common/collect/Multiset.java b/guava/src/com/google/common/collect/Multiset.java
index bb254c9..823750e 100644
--- a/guava/src/com/google/common/collect/Multiset.java
+++ b/guava/src/com/google/common/collect/Multiset.java
@@ -31,13 +31,13 @@ import javax.annotation.Nullable;
* may have duplicate elements. A multiset is also sometimes called a
* <i>bag</i>.
*
- * <p>Elements of a multiset that are equal to one another are referred to as
- * <i>occurrences</i> of the same single element. The total number of
- * occurrences of an element in a multiset is called the <i>count</i> of that
- * element (the terms "frequency" and "multiplicity" are equivalent, but not
- * used in this API). Since the count of an element is represented as an {@code
- * int}, a multiset may never contain more than {@link Integer#MAX_VALUE}
- * occurrences of any one element.
+ * <p>Elements of a multiset that are equal to one another (see "Note on
+ * element equivalence", below) are referred to as <i>occurrences</i> of the
+ * same single element. The total number of occurrences of an element in a
+ * multiset is called the <i>count</i> of that element (the terms "frequency"
+ * and "multiplicity" are equivalent, but not used in this API). Since the count
+ * of an element is represented as an {@code int}, a multiset may never contain
+ * more than {@link Integer#MAX_VALUE} occurrences of any one element.
*
* <p>{@code Multiset} refines the specifications of several methods from
* {@code Collection}. It also defines an additional query operation, {@link
@@ -77,10 +77,6 @@ import javax.annotation.Nullable;
* may wish to use {@link com.google.common.util.concurrent.AtomicLongMap}
* instead. Note, however, that unlike {@code Multiset}, {@code AtomicLongMap}
* does not automatically remove zeros.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset">
- * {@code Multiset}</a>.
*
* @author Kevin Bourrillion
* @since 2.0 (imported from Google Collections Library)
diff --git a/guava/src/com/google/common/collect/Multisets.java b/guava/src/com/google/common/collect/Multisets.java
index d0ab028..dbd54c3 100644
--- a/guava/src/com/google/common/collect/Multisets.java
+++ b/guava/src/com/google/common/collect/Multisets.java
@@ -18,33 +18,32 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Objects;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Multiset.Entry;
-import com.google.common.primitives.Ints;
+import static com.google.common.base.Preconditions.checkState;
import java.io.Serializable;
+import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
+import java.util.SortedSet;
import javax.annotation.Nullable;
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.collect.Multiset.Entry;
+import com.google.common.primitives.Ints;
+
/**
* Provides static utility methods for creating and working with {@link
* Multiset} instances.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Multisets">
- * {@code Multisets}</a>.
- *
* @author Kevin Bourrillion
* @author Mike Bostock
* @author Louis Wasserman
@@ -194,10 +193,92 @@ public final class Multisets {
@Beta
public static <E> SortedMultiset<E> unmodifiableSortedMultiset(
SortedMultiset<E> sortedMultiset) {
- // it's in its own file so it can be emulated for GWT
return new UnmodifiableSortedMultiset<E>(checkNotNull(sortedMultiset));
}
+ private static final class UnmodifiableSortedMultiset<E>
+ extends UnmodifiableMultiset<E> implements SortedMultiset<E> {
+ private UnmodifiableSortedMultiset(SortedMultiset<E> delegate) {
+ super(delegate);
+ }
+
+ @Override
+ protected SortedMultiset<E> delegate() {
+ return (SortedMultiset<E>) super.delegate();
+ }
+
+ @Override
+ public Comparator<? super E> comparator() {
+ return delegate().comparator();
+ }
+
+ @Override
+ SortedSet<E> createElementSet() {
+ return Collections.unmodifiableSortedSet(delegate().elementSet());
+ }
+
+ @Override
+ public SortedSet<E> elementSet() {
+ return (SortedSet<E>) super.elementSet();
+ }
+
+ private transient UnmodifiableSortedMultiset<E> descendingMultiset;
+
+ @Override
+ public SortedMultiset<E> descendingMultiset() {
+ UnmodifiableSortedMultiset<E> result = descendingMultiset;
+ if (result == null) {
+ result = new UnmodifiableSortedMultiset<E>(
+ delegate().descendingMultiset());
+ result.descendingMultiset = this;
+ return descendingMultiset = result;
+ }
+ return result;
+ }
+
+ @Override
+ public Entry<E> firstEntry() {
+ return delegate().firstEntry();
+ }
+
+ @Override
+ public Entry<E> lastEntry() {
+ return delegate().lastEntry();
+ }
+
+ @Override
+ public Entry<E> pollFirstEntry() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Entry<E> pollLastEntry() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SortedMultiset<E> headMultiset(E upperBound, BoundType boundType) {
+ return unmodifiableSortedMultiset(
+ delegate().headMultiset(upperBound, boundType));
+ }
+
+ @Override
+ public SortedMultiset<E> subMultiset(
+ E lowerBound, BoundType lowerBoundType,
+ E upperBound, BoundType upperBoundType) {
+ return unmodifiableSortedMultiset(delegate().subMultiset(
+ lowerBound, lowerBoundType, upperBound, upperBoundType));
+ }
+
+ @Override
+ public SortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType) {
+ return unmodifiableSortedMultiset(
+ delegate().tailMultiset(lowerBound, boundType));
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
/**
* Returns an immutable multiset entry with the specified element and count.
* The entry will be serializable if {@code e} is.
@@ -235,125 +316,152 @@ public final class Multisets {
}
/**
- * Returns a view of the elements of {@code unfiltered} that satisfy a predicate. The returned
- * multiset is a live view of {@code unfiltered}; changes to one affect the other.
- *
- * <p>The resulting multiset's iterators, and those of its {@code entrySet()} and
- * {@code elementSet()}, do not support {@code remove()}. However, all other multiset methods
- * supported by {@code unfiltered} are supported by the returned multiset. When given an element
- * that doesn't satisfy the predicate, the multiset's {@code add()} and {@code addAll()} methods
- * throw an {@link IllegalArgumentException}. When methods such as {@code removeAll()} and
- * {@code clear()} are called on the filtered multiset, only elements that satisfy the filter
- * will be removed from the underlying multiset.
+ * Returns a multiset view of the specified set. The multiset is backed by the
+ * set, so changes to the set are reflected in the multiset, and vice versa.
+ * If the set is modified while an iteration over the multiset is in progress
+ * (except through the iterator's own {@code remove} operation) the results of
+ * the iteration are undefined.
*
- * <p>The returned multiset isn't threadsafe or serializable, even if {@code unfiltered} is.
+ * <p>The multiset supports element removal, which removes the corresponding
+ * element from the set. It does not support the {@code add} or {@code addAll}
+ * operations, nor does it support the use of {@code setCount} to add
+ * elements.
*
- * <p>Many of the filtered multiset's methods, such as {@code size()}, iterate across every
- * element in the underlying multiset and determine which elements satisfy the filter. When a
- * live view is <i>not</i> needed, it may be faster to copy the returned multiset and use the
- * copy.
+ * <p>The returned multiset will be serializable if the specified set is
+ * serializable. The multiset is threadsafe if the set is threadsafe.
*
- * <p><b>Warning:</b> {@code predicate} must be <i>consistent with equals</i>, as documented at
- * {@link Predicate#apply}. Do not provide a predicate such as
- * {@code Predicates.instanceOf(ArrayList.class)}, which is inconsistent with equals. (See
- * {@link Iterables#filter(Iterable, Class)} for related functionality.)
- *
- * @since 14.0
+ * @param set the backing set for the returned multiset view
*/
- @Beta
- public static <E> Multiset<E> filter(Multiset<E> unfiltered, Predicate<? super E> predicate) {
- if (unfiltered instanceof FilteredMultiset) {
- // Support clear(), removeAll(), and retainAll() when filtering a filtered
- // collection.
- FilteredMultiset<E> filtered = (FilteredMultiset<E>) unfiltered;
- Predicate<E> combinedPredicate
- = Predicates.<E>and(filtered.predicate, predicate);
- return new FilteredMultiset<E>(filtered.unfiltered, combinedPredicate);
- }
- return new FilteredMultiset<E>(unfiltered, predicate);
+ static <E> Multiset<E> forSet(Set<E> set) {
+ return new SetMultiset<E>(set);
}
- private static final class FilteredMultiset<E> extends AbstractMultiset<E> {
- final Multiset<E> unfiltered;
- final Predicate<? super E> predicate;
+ /** @see Multisets#forSet */
+ private static class SetMultiset<E> extends ForwardingCollection<E>
+ implements Multiset<E>, Serializable {
+ final Set<E> delegate;
- FilteredMultiset(Multiset<E> unfiltered, Predicate<? super E> predicate) {
- this.unfiltered = checkNotNull(unfiltered);
- this.predicate = checkNotNull(predicate);
+ SetMultiset(Set<E> set) {
+ delegate = checkNotNull(set);
}
- @Override
- Set<E> createElementSet() {
- return Sets.filter(unfiltered.elementSet(), predicate);
+ @Override protected Set<E> delegate() {
+ return delegate;
}
@Override
- Set<Entry<E>> createEntrySet() {
- return Sets.filter(unfiltered.entrySet(), new Predicate<Entry<E>>() {
- @Override
- public boolean apply(Entry<E> entry) {
- return predicate.apply(entry.getElement());
- }
- });
+ public int count(Object element) {
+ return delegate.contains(element) ? 1 : 0;
}
@Override
- Iterator<Entry<E>> entryIterator() {
- throw new AssertionError("should never be called");
+ public int add(E element, int occurrences) {
+ throw new UnsupportedOperationException();
}
@Override
- int distinctElements() {
- return elementSet().size();
+ public int remove(Object element, int occurrences) {
+ if (occurrences == 0) {
+ return count(element);
+ }
+ checkArgument(occurrences > 0);
+ return delegate.remove(element) ? 1 : 0;
}
+ transient Set<E> elementSet;
+
@Override
- public boolean contains(@Nullable Object element) {
- return count(element) > 0;
+ public Set<E> elementSet() {
+ Set<E> es = elementSet;
+ return (es == null) ? elementSet = new ElementSet() : es;
}
- @Override
- public int count(@Nullable Object element) {
- int count = unfiltered.count(element);
- if (count > 0) {
- @SuppressWarnings("unchecked") // element is equal to an E
- E e = (E) element;
- return predicate.apply(e) ? count : 0;
+ transient Set<Entry<E>> entrySet;
+
+ @Override public Set<Entry<E>> entrySet() {
+ Set<Entry<E>> es = entrySet;
+ if (es == null) {
+ es = entrySet = new EntrySet<E>() {
+ @Override Multiset<E> multiset() {
+ return SetMultiset.this;
+ }
+
+ @Override public Iterator<Entry<E>> iterator() {
+ return Iterators.transform(delegate.iterator(),
+ new Function<E, Entry<E>>() {
+ @Override public Entry<E> apply(E elem) {
+ return immutableEntry(elem, 1);
+ }
+ });
+ }
+
+ @Override public int size() {
+ return delegate.size();
+ }
+ };
}
- return 0;
+ return es;
}
- @Override
- public int add(@Nullable E element, int occurrences) {
- checkArgument(predicate.apply(element),
- "Element %s does not match predicate %s", element, predicate);
- return unfiltered.add(element, occurrences);
+ @Override public boolean add(E o) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean addAll(Collection<? extends E> c) {
+ throw new UnsupportedOperationException();
}
@Override
- public int remove(@Nullable Object element, int occurrences) {
- Multisets.checkNonnegative(occurrences, "occurrences");
- if (occurrences == 0) {
- return count(element);
+ public int setCount(E element, int count) {
+ checkNonnegative(count, "count");
+
+ if (count == count(element)) {
+ return count;
+ } else if (count == 0) {
+ remove(element);
+ return 1;
} else {
- return contains(element) ? unfiltered.remove(element, occurrences) : 0;
+ throw new UnsupportedOperationException();
}
}
@Override
- public boolean removeAll(Collection<?> c) {
- return elementSet().removeAll(c);
+ public boolean setCount(E element, int oldCount, int newCount) {
+ return setCountImpl(this, element, oldCount, newCount);
}
- @Override
- public boolean retainAll(Collection<?> c) {
- return elementSet().retainAll(c);
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof Multiset) {
+ Multiset<?> that = (Multiset<?>) object;
+ return this.size() == that.size() && delegate.equals(that.elementSet());
+ }
+ return false;
}
- @Override
- public void clear() {
- elementSet().clear();
+ @Override public int hashCode() {
+ int sum = 0;
+ for (E e : this) {
+ sum += ((e == null) ? 0 : e.hashCode()) ^ 1;
+ }
+ return sum;
+ }
+
+ /** @see SetMultiset#elementSet */
+ class ElementSet extends ForwardingSet<E> {
+ @Override protected Set<E> delegate() {
+ return delegate;
+ }
+
+ @Override public boolean add(E o) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean addAll(Collection<? extends E> c) {
+ throw new UnsupportedOperationException();
+ }
}
+
+ private static final long serialVersionUID = 0;
}
/**
@@ -370,93 +478,16 @@ public final class Multisets {
}
/**
- * Returns an unmodifiable view of the union of two multisets.
- * In the returned multiset, the count of each element is the <i>maximum</i>
- * of its counts in the two backing multisets. The iteration order of the
- * returned multiset matches that of the element set of {@code multiset1}
- * followed by the members of the element set of {@code multiset2} that are
- * not contained in {@code multiset1}, with repeated occurrences of the same
+ * Returns an unmodifiable <b>view</b> of the intersection of two multisets.
+ * An element's count in the multiset is the smaller of its counts in the two
+ * backing multisets. The iteration order of the returned multiset matches the
+ * element set of {@code multiset1}, with repeated occurrences of the same
* element appearing consecutively.
*
* <p>Results are undefined if {@code multiset1} and {@code multiset2} are
* based on different equivalence relations (as {@code HashMultiset} and
* {@code TreeMultiset} are).
*
- * @since 14.0
- */
- @Beta
- public static <E> Multiset<E> union(
- final Multiset<? extends E> multiset1, final Multiset<? extends E> multiset2) {
- checkNotNull(multiset1);
- checkNotNull(multiset2);
-
- return new AbstractMultiset<E>() {
- @Override
- public boolean contains(@Nullable Object element) {
- return multiset1.contains(element) || multiset2.contains(element);
- }
-
- @Override
- public boolean isEmpty() {
- return multiset1.isEmpty() && multiset2.isEmpty();
- }
-
- @Override
- public int count(Object element) {
- return Math.max(multiset1.count(element), multiset2.count(element));
- }
-
- @Override
- Set<E> createElementSet() {
- return Sets.union(multiset1.elementSet(), multiset2.elementSet());
- }
-
- @Override
- Iterator<Entry<E>> entryIterator() {
- final Iterator<? extends Entry<? extends E>> iterator1
- = multiset1.entrySet().iterator();
- final Iterator<? extends Entry<? extends E>> iterator2
- = multiset2.entrySet().iterator();
- return new AbstractIterator<Entry<E>>() {
- @Override
- protected Entry<E> computeNext() {
- if (iterator1.hasNext()) {
- Entry<? extends E> entry1 = iterator1.next();
- E element = entry1.getElement();
- int count = Math.max(entry1.getCount(), multiset2.count(element));
- return immutableEntry(element, count);
- }
- while (iterator2.hasNext()) {
- Entry<? extends E> entry2 = iterator2.next();
- E element = entry2.getElement();
- if (!multiset1.contains(element)) {
- return immutableEntry(element, entry2.getCount());
- }
- }
- return endOfData();
- }
- };
- }
-
- @Override
- int distinctElements() {
- return elementSet().size();
- }
- };
- }
-
- /**
- * Returns an unmodifiable view of the intersection of two multisets.
- * In the returned multiset, the count of each element is the <i>minimum</i>
- * of its counts in the two backing multisets, with elements that would have
- * a count of 0 not included. The iteration order of the returned multiset
- * matches that of the element set of {@code multiset1}, with repeated
- * occurrences of the same element appearing consecutively.
- *
- * <p>Results are undefined if {@code multiset1} and {@code multiset2} are
- * based on different equivalence relations (as {@code HashMultiset} and
- * {@code TreeMultiset} are).
- *
* @since 2.0
*/
public static <E> Multiset<E> intersection(
@@ -488,88 +519,7 @@ public final class Multisets {
E element = entry1.getElement();
int count = Math.min(entry1.getCount(), multiset2.count(element));
if (count > 0) {
- return immutableEntry(element, count);
- }
- }
- return endOfData();
- }
- };
- }
-
- @Override
- int distinctElements() {
- return elementSet().size();
- }
- };
- }
-
- /**
- * Returns an unmodifiable view of the sum of two multisets.
- * In the returned multiset, the count of each element is the <i>sum</i> of
- * its counts in the two backing multisets. The iteration order of the
- * returned multiset matches that of the element set of {@code multiset1}
- * followed by the members of the element set of {@code multiset2} that that
- * are not contained in {@code multiset1}, with repeated occurrences of the
- * same element appearing consecutively.
- *
- * <p>Results are undefined if {@code multiset1} and {@code multiset2} are
- * based on different equivalence relations (as {@code HashMultiset} and
- * {@code TreeMultiset} are).
- *
- * @since 14.0
- */
- @Beta
- public static <E> Multiset<E> sum(
- final Multiset<? extends E> multiset1, final Multiset<? extends E> multiset2) {
- checkNotNull(multiset1);
- checkNotNull(multiset2);
-
- return new AbstractMultiset<E>() {
- @Override
- public boolean contains(@Nullable Object element) {
- return multiset1.contains(element) || multiset2.contains(element);
- }
-
- @Override
- public boolean isEmpty() {
- return multiset1.isEmpty() && multiset2.isEmpty();
- }
-
- @Override
- public int size() {
- return multiset1.size() + multiset2.size();
- }
-
- @Override
- public int count(Object element) {
- return multiset1.count(element) + multiset2.count(element);
- }
-
- @Override
- Set<E> createElementSet() {
- return Sets.union(multiset1.elementSet(), multiset2.elementSet());
- }
-
- @Override
- Iterator<Entry<E>> entryIterator() {
- final Iterator<? extends Entry<? extends E>> iterator1
- = multiset1.entrySet().iterator();
- final Iterator<? extends Entry<? extends E>> iterator2
- = multiset2.entrySet().iterator();
- return new AbstractIterator<Entry<E>>() {
- @Override
- protected Entry<E> computeNext() {
- if (iterator1.hasNext()) {
- Entry<? extends E> entry1 = iterator1.next();
- E element = entry1.getElement();
- int count = entry1.getCount() + multiset2.count(element);
- return immutableEntry(element, count);
- }
- while (iterator2.hasNext()) {
- Entry<? extends E> entry2 = iterator2.next();
- E element = entry2.getElement();
- if (!multiset1.contains(element)) {
- return immutableEntry(element, entry2.getCount());
+ return Multisets.immutableEntry(element, count);
}
}
return endOfData();
@@ -585,66 +535,12 @@ public final class Multisets {
}
/**
- * Returns an unmodifiable view of the difference of two multisets.
- * In the returned multiset, the count of each element is the result of the
- * <i>zero-truncated subtraction</i> of its count in the second multiset from
- * its count in the first multiset, with elements that would have a count of
- * 0 not included. The iteration order of the returned multiset matches that
- * of the element set of {@code multiset1}, with repeated occurrences of the
- * same element appearing consecutively.
- *
- * <p>Results are undefined if {@code multiset1} and {@code multiset2} are
- * based on different equivalence relations (as {@code HashMultiset} and
- * {@code TreeMultiset} are).
- *
- * @since 14.0
- */
- @Beta
- public static <E> Multiset<E> difference(
- final Multiset<E> multiset1, final Multiset<?> multiset2) {
- checkNotNull(multiset1);
- checkNotNull(multiset2);
-
- return new AbstractMultiset<E>() {
- @Override
- public int count(@Nullable Object element) {
- int count1 = multiset1.count(element);
- return (count1 == 0) ? 0 :
- Math.max(0, count1 - multiset2.count(element));
- }
-
- @Override
- Iterator<Entry<E>> entryIterator() {
- final Iterator<Entry<E>> iterator1 = multiset1.entrySet().iterator();
- return new AbstractIterator<Entry<E>>() {
- @Override
- protected Entry<E> computeNext() {
- while (iterator1.hasNext()) {
- Entry<E> entry1 = iterator1.next();
- E element = entry1.getElement();
- int count = entry1.getCount() - multiset2.count(element);
- if (count > 0) {
- return immutableEntry(element, count);
- }
- }
- return endOfData();
- }
- };
- }
-
- @Override
- int distinctElements() {
- return Iterators.size(entryIterator());
- }
- };
- }
-
- /**
* Returns {@code true} if {@code subMultiset.count(o) <=
* superMultiset.count(o)} for all {@code o}.
*
* @since 10.0
*/
+ @Beta
public static boolean containsOccurrences(
Multiset<?> superMultiset, Multiset<?> subMultiset) {
checkNotNull(superMultiset);
@@ -677,7 +573,7 @@ public final class Multisets {
* of this operation
* @since 10.0
*/
- public static boolean retainOccurrences(Multiset<?> multisetToModify,
+ @Beta public static boolean retainOccurrences(Multiset<?> multisetToModify,
Multiset<?> multisetToRetain) {
return retainOccurrencesImpl(multisetToModify, multisetToRetain);
}
@@ -729,7 +625,7 @@ public final class Multisets {
* this operation
* @since 10.0
*/
- public static boolean removeOccurrences(
+ @Beta public static boolean removeOccurrences(
Multiset<?> multisetToModify, Multiset<?> occurrencesToRemove) {
return removeOccurrencesImpl(multisetToModify, occurrencesToRemove);
}
@@ -864,7 +760,6 @@ public final class Multisets {
*/
static boolean retainAllImpl(
Multiset<?> self, Collection<?> elementsToRetain) {
- checkNotNull(elementsToRetain);
Collection<?> collection = (elementsToRetain instanceof Multiset)
? ((Multiset<?>) elementsToRetain).elementSet() : elementsToRetain;
@@ -905,7 +800,7 @@ public final class Multisets {
}
}
- abstract static class ElementSet<E> extends Sets.ImprovedAbstractSet<E> {
+ static abstract class ElementSet<E> extends AbstractSet<E> {
abstract Multiset<E> multiset();
@Override public void clear() {
@@ -925,12 +820,12 @@ public final class Multisets {
}
@Override public Iterator<E> iterator() {
- return new TransformedIterator<Entry<E>, E>(multiset().entrySet().iterator()) {
- @Override
- E transform(Entry<E> entry) {
- return entry.getElement();
- }
- };
+ return Iterators.transform(multiset().entrySet().iterator(),
+ new Function<Entry<E>, E>() {
+ @Override public E apply(Entry<E> entry) {
+ return entry.getElement();
+ }
+ });
}
@Override
@@ -948,14 +843,11 @@ public final class Multisets {
}
}
- abstract static class EntrySet<E> extends Sets.ImprovedAbstractSet<Entry<E>> {
+ static abstract class EntrySet<E> extends AbstractSet<Entry<E>>{
abstract Multiset<E> multiset();
@Override public boolean contains(@Nullable Object o) {
if (o instanceof Entry) {
- /*
- * The GWT compiler wrongly issues a warning here.
- */
@SuppressWarnings("cast")
Entry<?> entry = (Entry<?>) o;
if (entry.getCount() <= 0) {
@@ -968,21 +860,10 @@ public final class Multisets {
return false;
}
- // GWT compiler warning; see contains().
@SuppressWarnings("cast")
- @Override public boolean remove(Object object) {
- if (object instanceof Multiset.Entry) {
- Entry<?> entry = (Entry<?>) object;
- Object element = entry.getElement();
- int entryCount = entry.getCount();
- if (entryCount != 0) {
- // Safe as long as we never add a new entry, which we won't.
- @SuppressWarnings("unchecked")
- Multiset<Object> multiset = (Multiset) multiset();
- return multiset.setCount(element, entryCount, 0);
- }
- }
- return false;
+ @Override public boolean remove(Object o) {
+ return contains(o)
+ && multiset().elementSet().remove(((Entry<?>) o).getElement());
}
@Override public void clear() {
@@ -1035,7 +916,8 @@ public final class Multisets {
@Override
public void remove() {
- Iterators.checkRemove(canRemove);
+ checkState(
+ canRemove, "no calls to next() since the last call to remove()");
if (totalCount == 1) {
entryIterator.remove();
} else {
diff --git a/guava/src/com/google/common/collect/MutableClassToInstanceMap.java b/guava/src/com/google/common/collect/MutableClassToInstanceMap.java
index c723cea..b40e801 100644
--- a/guava/src/com/google/common/collect/MutableClassToInstanceMap.java
+++ b/guava/src/com/google/common/collect/MutableClassToInstanceMap.java
@@ -25,10 +25,6 @@ import java.util.Map;
/**
* A mutable class-to-instance map backed by an arbitrary user-provided map.
* See also {@link ImmutableClassToInstanceMap}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#ClassToInstanceMap">
- * {@code ClassToInstanceMap}</a>.
*
* @author Kevin Bourrillion
* @since 2.0 (imported from Google Collections Library)
diff --git a/guava/src/com/google/common/collect/ObjectArrays.java b/guava/src/com/google/common/collect/ObjectArrays.java
index dfd1fe9..954a30e 100644
--- a/guava/src/com/google/common/collect/ObjectArrays.java
+++ b/guava/src/com/google/common/collect/ObjectArrays.java
@@ -19,7 +19,6 @@ package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
-import java.lang.reflect.Array;
import java.util.Collection;
import javax.annotation.Nullable;
@@ -32,8 +31,6 @@ import javax.annotation.Nullable;
*/
@GwtCompatible(emulated = true)
public final class ObjectArrays {
- static final Object[] EMPTY_ARRAY = new Object[0];
-
private ObjectArrays() {}
/**
@@ -43,9 +40,8 @@ public final class ObjectArrays {
* @param length the length of the new array
*/
@GwtIncompatible("Array.newInstance(Class, int)")
- @SuppressWarnings("unchecked")
public static <T> T[] newArray(Class<T> type, int length) {
- return (T[]) Array.newInstance(type, length);
+ return Platform.newArray(type, length);
}
/**
@@ -69,8 +65,8 @@ public final class ObjectArrays {
@GwtIncompatible("Array.newInstance(Class, int)")
public static <T> T[] concat(T[] first, T[] second, Class<T> type) {
T[] result = newArray(type, first.length + second.length);
- System.arraycopy(first, 0, result, 0, first.length);
- System.arraycopy(second, 0, result, first.length, second.length);
+ Platform.unsafeArrayCopy(first, 0, result, 0, first.length);
+ Platform.unsafeArrayCopy(second, 0, result, first.length, second.length);
return result;
}
@@ -86,7 +82,7 @@ public final class ObjectArrays {
public static <T> T[] concat(@Nullable T element, T[] array) {
T[] result = newArray(array, array.length + 1);
result[0] = element;
- System.arraycopy(array, 0, result, 1, array.length);
+ Platform.unsafeArrayCopy(array, 0, result, 1, array.length);
return result;
}
@@ -108,7 +104,7 @@ public final class ObjectArrays {
/** GWT safe version of Arrays.copyOf. */
static <T> T[] arraysCopyOf(T[] original, int newLength) {
T[] copy = newArray(original, newLength);
- System.arraycopy(
+ Platform.unsafeArrayCopy(
original, 0, copy, 0, Math.min(original.length, newLength));
return copy;
}
@@ -183,13 +179,4 @@ public final class ObjectArrays {
array[i] = array[j];
array[j] = temp;
}
-
- // We do this instead of Preconditions.checkNotNull to save boxing and array
- // creation cost.
- static Object checkElementNotNull(Object element, int index) {
- if (element == null) {
- throw new NullPointerException("at index " + index);
- }
- return element;
- }
}
diff --git a/guava/src/com/google/common/collect/Ordering.java b/guava/src/com/google/common/collect/Ordering.java
index 9ee9c48..1f0c6e3 100644
--- a/guava/src/com/google/common/collect/Ordering.java
+++ b/guava/src/com/google/common/collect/Ordering.java
@@ -19,13 +19,12 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
@@ -35,15 +34,13 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.SortedMap;
import java.util.SortedSet;
-import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nullable;
/**
- * A comparator, with additional methods to support common operations. This is
- * an "enriched" version of {@code Comparator}, in the same sense that {@link
- * FluentIterable} is an enriched {@link Iterable}). For example: <pre> {@code
+ * A comparator with added methods to support common functions. For example:
+ * <pre> {@code
*
* if (Ordering.from(comparator).reverse().isOrdered(list)) { ... }}</pre>
*
@@ -62,17 +59,13 @@ import javax.annotation.Nullable;
* are. For example, if {@code ordering} and {@code function} can themselves be
* serialized, then {@code ordering.onResultOf(function)} can as well.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/OrderingExplained">
- * {@code Ordering}</a>.
- *
* @author Jesse Wilson
* @author Kevin Bourrillion
* @since 2.0 (imported from Google Collections Library)
*/
@GwtCompatible
public abstract class Ordering<T> implements Comparator<T> {
- // Natural order
+ // Static factories
/**
* Returns a serializable ordering that uses the natural order of the values.
@@ -89,17 +82,13 @@ public abstract class Ordering<T> implements Comparator<T> {
return (Ordering<C>) NaturalOrdering.INSTANCE;
}
- // Static factories
-
/**
- * Returns an ordering based on an <i>existing</i> comparator instance. Note
- * that there's no need to create a <i>new</i> comparator just to pass it in
- * here; simply subclass {@code Ordering} and implement its {@code compareTo}
- * method directly instead.
+ * Returns an ordering for a pre-existing {@code comparator}. Note
+ * that if the comparator is not pre-existing, and you don't require
+ * serialization, you can subclass {@code Ordering} and implement its
+ * {@link #compare(Object, Object) compare} method instead.
*
* @param comparator the comparator that defines the order
- * @return comparator itself if it is already an {@code Ordering}; otherwise
- * an ordering that wraps that comparator
*/
@GwtCompatible(serializable = true)
public static <T> Ordering<T> from(Comparator<T> comparator) {
@@ -173,48 +162,23 @@ public abstract class Ordering<T> implements Comparator<T> {
return explicit(Lists.asList(leastValue, remainingValuesInOrder));
}
- // Ordering<Object> singletons
-
/**
- * Returns an ordering which treats all values as equal, indicating "no
- * ordering." Passing this ordering to any <i>stable</i> sort algorithm
- * results in no change to the order of elements. Note especially that {@link
- * #sortedCopy} and {@link #immutableSortedCopy} are stable, and in the
- * returned instance these are implemented by simply copying the source list.
- *
- * <p>Example: <pre> {@code
- *
- * Ordering.allEqual().nullsLast().sortedCopy(
- * asList(t, null, e, s, null, t, null))}</pre>
- *
- * Assuming {@code t}, {@code e} and {@code s} are non-null, this returns
- * {@code [t, e, s, t, null, null, null]} regardlesss of the true comparison
- * order of those three values (which might not even implement {@link
- * Comparable} at all).
- *
- * <p><b>Warning:</b> by definition, this comparator is not <i>consistent with
- * equals</i> (as defined {@linkplain Comparator here}). Avoid its use in
- * APIs, such as {@link TreeSet#TreeSet(Comparator)}, where such consistency
- * is expected.
- *
- * <p>The returned comparator is serializable.
+ * Exception thrown by a {@link Ordering#explicit(List)} or {@link
+ * Ordering#explicit(Object, Object[])} comparator when comparing a value
+ * outside the set of values it can compare. Extending {@link
+ * ClassCastException} may seem odd, but it is required.
*/
- @GwtCompatible(serializable = true)
- @SuppressWarnings("unchecked")
- public static Ordering<Object> allEqual() {
- return AllEqualOrdering.INSTANCE;
- }
+ // TODO(kevinb): make this public, document it right
+ @VisibleForTesting
+ static class IncomparableValueException extends ClassCastException {
+ final Object value;
- /**
- * Returns an ordering that compares objects by the natural ordering of their
- * string representations as returned by {@code toString()}. It does not
- * support null values.
- *
- * <p>The comparator is serializable.
- */
- @GwtCompatible(serializable = true)
- public static Ordering<Object> usingToString() {
- return UsingToStringOrdering.INSTANCE;
+ IncomparableValueException(Object value) {
+ super("Cannot compare value: " + value);
+ this.value = value;
+ }
+
+ private static final long serialVersionUID = 0;
}
/**
@@ -256,10 +220,6 @@ public abstract class Ordering<T> implements Comparator<T> {
@Override public int compare(Object left, Object right) {
if (left == right) {
return 0;
- } else if (left == null) {
- return -1;
- } else if (right == null) {
- return 1;
}
int leftCode = identityHashCode(left);
int rightCode = identityHashCode(right);
@@ -292,62 +252,46 @@ public abstract class Ordering<T> implements Comparator<T> {
}
}
- // Constructor
-
/**
- * Constructs a new instance of this class (only invokable by the subclass
- * constructor, typically implicit).
- */
- protected Ordering() {}
-
- // Instance-based factories (and any static equivalents)
-
- /**
- * Returns the reverse of this ordering; the {@code Ordering} equivalent to
- * {@link Collections#reverseOrder(Comparator)}.
+ * Returns an ordering that compares objects by the natural ordering of their
+ * string representations as returned by {@code toString()}. It does not
+ * support null values.
+ *
+ * <p>The comparator is serializable.
*/
- // type parameter <S> lets us avoid the extra <String> in statements like:
- // Ordering<String> o = Ordering.<String>natural().reverse();
@GwtCompatible(serializable = true)
- public <S extends T> Ordering<S> reverse() {
- return new ReverseOrdering<S>(this);
+ public static Ordering<Object> usingToString() {
+ return UsingToStringOrdering.INSTANCE;
}
/**
- * Returns an ordering that treats {@code null} as less than all other values
- * and uses {@code this} to compare non-null values.
+ * Returns an ordering which tries each given comparator in order until a
+ * non-zero result is found, returning that result, and returning zero only if
+ * all comparators return zero. The returned ordering is based on the state of
+ * the {@code comparators} iterable at the time it was provided to this
+ * method.
+ *
+ * <p>The returned ordering is equivalent to that produced using {@code
+ * Ordering.from(comp1).compound(comp2).compound(comp3) . . .}.
+ *
+ * <p><b>Warning:</b> Supplying an argument with undefined iteration order,
+ * such as a {@link HashSet}, will produce non-deterministic results.
+ *
+ * @param comparators the comparators to try in order
*/
- // type parameter <S> lets us avoid the extra <String> in statements like:
- // Ordering<String> o = Ordering.<String>natural().nullsFirst();
@GwtCompatible(serializable = true)
- public <S extends T> Ordering<S> nullsFirst() {
- return new NullsFirstOrdering<S>(this);
+ public static <T> Ordering<T> compound(
+ Iterable<? extends Comparator<? super T>> comparators) {
+ return new CompoundOrdering<T>(comparators);
}
/**
- * Returns an ordering that treats {@code null} as greater than all other
- * values and uses this ordering to compare non-null values.
+ * Constructs a new instance of this class (only invokable by the subclass
+ * constructor, typically implicit).
*/
- // type parameter <S> lets us avoid the extra <String> in statements like:
- // Ordering<String> o = Ordering.<String>natural().nullsLast();
- @GwtCompatible(serializable = true)
- public <S extends T> Ordering<S> nullsLast() {
- return new NullsLastOrdering<S>(this);
- }
+ protected Ordering() {}
- /**
- * Returns a new ordering on {@code F} which orders elements by first applying
- * a function to them, then comparing those results using {@code this}. For
- * example, to compare objects by their string forms, in a case-insensitive
- * manner, use: <pre> {@code
- *
- * Ordering.from(String.CASE_INSENSITIVE_ORDER)
- * .onResultOf(Functions.toStringFunction())}</pre>
- */
- @GwtCompatible(serializable = true)
- public <F> Ordering<F> onResultOf(Function<F, ? extends T> function) {
- return new ByFunctionOrdering<F, T>(function, this);
- }
+ // Non-static factories
/**
* Returns an ordering which first uses the ordering {@code this}, but which
@@ -367,24 +311,28 @@ public abstract class Ordering<T> implements Comparator<T> {
}
/**
- * Returns an ordering which tries each given comparator in order until a
- * non-zero result is found, returning that result, and returning zero only if
- * all comparators return zero. The returned ordering is based on the state of
- * the {@code comparators} iterable at the time it was provided to this
- * method.
- *
- * <p>The returned ordering is equivalent to that produced using {@code
- * Ordering.from(comp1).compound(comp2).compound(comp3) . . .}.
- *
- * <p><b>Warning:</b> Supplying an argument with undefined iteration order,
- * such as a {@link HashSet}, will produce non-deterministic results.
+ * Returns the reverse of this ordering; the {@code Ordering} equivalent to
+ * {@link Collections#reverseOrder(Comparator)}.
+ */
+ // type parameter <S> lets us avoid the extra <String> in statements like:
+ // Ordering<String> o = Ordering.<String>natural().reverse();
+ @GwtCompatible(serializable = true)
+ public <S extends T> Ordering<S> reverse() {
+ return new ReverseOrdering<S>(this);
+ }
+
+ /**
+ * Returns a new ordering on {@code F} which orders elements by first applying
+ * a function to them, then comparing those results using {@code this}. For
+ * example, to compare objects by their string forms, in a case-insensitive
+ * manner, use: <pre> {@code
*
- * @param comparators the comparators to try in order
+ * Ordering.from(String.CASE_INSENSITIVE_ORDER)
+ * .onResultOf(Functions.toStringFunction())}</pre>
*/
@GwtCompatible(serializable = true)
- public static <T> Ordering<T> compound(
- Iterable<? extends Comparator<? super T>> comparators) {
- return new CompoundOrdering<T>(comparators);
+ public <F> Ordering<F> onResultOf(Function<F, ? extends T> function) {
+ return new ByFunctionOrdering<F, T>(function, this);
}
/**
@@ -416,162 +364,32 @@ public abstract class Ordering<T> implements Comparator<T> {
return new LexicographicalOrdering<S>(this);
}
- // Regular instance methods
-
- // Override to add @Nullable
- @Override public abstract int compare(@Nullable T left, @Nullable T right);
-
- /**
- * Returns the least of the specified values according to this ordering. If
- * there are multiple least values, the first of those is returned. The
- * iterator will be left exhausted: its {@code hasNext()} method will return
- * {@code false}.
- *
- * @param iterator the iterator whose minimum element is to be determined
- * @throws NoSuchElementException if {@code iterator} is empty
- * @throws ClassCastException if the parameters are not <i>mutually
- * comparable</i> under this ordering.
- *
- * @since 11.0
- */
- public <E extends T> E min(Iterator<E> iterator) {
- // let this throw NoSuchElementException as necessary
- E minSoFar = iterator.next();
-
- while (iterator.hasNext()) {
- minSoFar = min(minSoFar, iterator.next());
- }
-
- return minSoFar;
- }
-
- /**
- * Returns the least of the specified values according to this ordering. If
- * there are multiple least values, the first of those is returned.
- *
- * @param iterable the iterable whose minimum element is to be determined
- * @throws NoSuchElementException if {@code iterable} is empty
- * @throws ClassCastException if the parameters are not <i>mutually
- * comparable</i> under this ordering.
- */
- public <E extends T> E min(Iterable<E> iterable) {
- return min(iterable.iterator());
- }
-
- /**
- * Returns the lesser of the two values according to this ordering. If the
- * values compare as 0, the first is returned.
- *
- * <p><b>Implementation note:</b> this method is invoked by the default
- * implementations of the other {@code min} overloads, so overriding it will
- * affect their behavior.
- *
- * @param a value to compare, returned if less than or equal to b.
- * @param b value to compare.
- * @throws ClassCastException if the parameters are not <i>mutually
- * comparable</i> under this ordering.
- */
- public <E extends T> E min(@Nullable E a, @Nullable E b) {
- return (compare(a, b) <= 0) ? a : b;
- }
-
- /**
- * Returns the least of the specified values according to this ordering. If
- * there are multiple least values, the first of those is returned.
- *
- * @param a value to compare, returned if less than or equal to the rest.
- * @param b value to compare
- * @param c value to compare
- * @param rest values to compare
- * @throws ClassCastException if the parameters are not <i>mutually
- * comparable</i> under this ordering.
- */
- public <E extends T> E min(
- @Nullable E a, @Nullable E b, @Nullable E c, E... rest) {
- E minSoFar = min(min(a, b), c);
-
- for (E r : rest) {
- minSoFar = min(minSoFar, r);
- }
-
- return minSoFar;
- }
-
/**
- * Returns the greatest of the specified values according to this ordering. If
- * there are multiple greatest values, the first of those is returned. The
- * iterator will be left exhausted: its {@code hasNext()} method will return
- * {@code false}.
- *
- * @param iterator the iterator whose maximum element is to be determined
- * @throws NoSuchElementException if {@code iterator} is empty
- * @throws ClassCastException if the parameters are not <i>mutually
- * comparable</i> under this ordering.
- *
- * @since 11.0
- */
- public <E extends T> E max(Iterator<E> iterator) {
- // let this throw NoSuchElementException as necessary
- E maxSoFar = iterator.next();
-
- while (iterator.hasNext()) {
- maxSoFar = max(maxSoFar, iterator.next());
- }
-
- return maxSoFar;
- }
-
- /**
- * Returns the greatest of the specified values according to this ordering. If
- * there are multiple greatest values, the first of those is returned.
- *
- * @param iterable the iterable whose maximum element is to be determined
- * @throws NoSuchElementException if {@code iterable} is empty
- * @throws ClassCastException if the parameters are not <i>mutually
- * comparable</i> under this ordering.
+ * Returns an ordering that treats {@code null} as less than all other values
+ * and uses {@code this} to compare non-null values.
*/
- public <E extends T> E max(Iterable<E> iterable) {
- return max(iterable.iterator());
+ // type parameter <S> lets us avoid the extra <String> in statements like:
+ // Ordering<String> o = Ordering.<String>natural().nullsFirst();
+ @GwtCompatible(serializable = true)
+ public <S extends T> Ordering<S> nullsFirst() {
+ return new NullsFirstOrdering<S>(this);
}
/**
- * Returns the greater of the two values according to this ordering. If the
- * values compare as 0, the first is returned.
- *
- * <p><b>Implementation note:</b> this method is invoked by the default
- * implementations of the other {@code max} overloads, so overriding it will
- * affect their behavior.
- *
- * @param a value to compare, returned if greater than or equal to b.
- * @param b value to compare.
- * @throws ClassCastException if the parameters are not <i>mutually
- * comparable</i> under this ordering.
+ * Returns an ordering that treats {@code null} as greater than all other
+ * values and uses this ordering to compare non-null values.
*/
- public <E extends T> E max(@Nullable E a, @Nullable E b) {
- return (compare(a, b) >= 0) ? a : b;
+ // type parameter <S> lets us avoid the extra <String> in statements like:
+ // Ordering<String> o = Ordering.<String>natural().nullsLast();
+ @GwtCompatible(serializable = true)
+ public <S extends T> Ordering<S> nullsLast() {
+ return new NullsLastOrdering<S>(this);
}
- /**
- * Returns the greatest of the specified values according to this ordering. If
- * there are multiple greatest values, the first of those is returned.
- *
- * @param a value to compare, returned if greater than or equal to the rest.
- * @param b value to compare
- * @param c value to compare
- * @param rest values to compare
- * @throws ClassCastException if the parameters are not <i>mutually
- * comparable</i> under this ordering.
- */
- public <E extends T> E max(
- @Nullable E a, @Nullable E b, @Nullable E c, E... rest) {
- E maxSoFar = max(max(a, b), c);
-
- for (E r : rest) {
- maxSoFar = max(maxSoFar, r);
- }
+ // Regular instance methods
- return maxSoFar;
- }
+ // Override to add @Nullable
+ @Override public abstract int compare(@Nullable T left, @Nullable T right);
/**
* Returns the {@code k} least elements of the given iterable according to
@@ -587,130 +405,64 @@ public abstract class Ordering<T> implements Comparator<T> {
* @throws IllegalArgumentException if {@code k} is negative
* @since 8.0
*/
+ @Beta
public <E extends T> List<E> leastOf(Iterable<E> iterable, int k) {
- if (iterable instanceof Collection) {
- Collection<E> collection = (Collection<E>) iterable;
- if (collection.size() <= 2L * k) {
- // In this case, just dumping the collection to an array and sorting is
- // faster than using the implementation for Iterator, which is
- // specialized for k much smaller than n.
-
- @SuppressWarnings("unchecked") // c only contains E's and doesn't escape
- E[] array = (E[]) collection.toArray();
- Arrays.sort(array, this);
- if (array.length > k) {
- array = ObjectArrays.arraysCopyOf(array, k);
- }
- return Collections.unmodifiableList(Arrays.asList(array));
- }
+ checkArgument(k >= 0, "%d is negative", k);
+
+ // values is not an E[], but we use it as such for readability. Hack.
+ @SuppressWarnings("unchecked")
+ E[] values = (E[]) Iterables.toArray(iterable);
+
+ // TODO(nshupe): also sort whole list if k is *near* values.length?
+ // TODO(kevinb): benchmark this impl against hand-coded heap
+ E[] resultArray;
+ if (values.length <= k) {
+ Arrays.sort(values, this);
+ resultArray = values;
+ } else {
+ quicksortLeastK(values, 0, values.length - 1, k);
+
+ // this is not an E[], but we use it as such for readability. Hack.
+ @SuppressWarnings("unchecked")
+ E[] tmp = (E[]) new Object[k];
+ resultArray = tmp;
+ System.arraycopy(values, 0, resultArray, 0, k);
}
- return leastOf(iterable.iterator(), k);
+
+ return Collections.unmodifiableList(Arrays.asList(resultArray));
}
/**
- * Returns the {@code k} least elements from the given iterator according to
- * this ordering, in order from least to greatest. If there are fewer than
+ * Returns the {@code k} greatest elements of the given iterable according to
+ * this ordering, in order from greatest to least. If there are fewer than
* {@code k} elements present, all will be included.
*
* <p>The implementation does not necessarily use a <i>stable</i> sorting
* algorithm; when multiple elements are equivalent, it is undefined which
* will come first.
*
- * @return an immutable {@code RandomAccess} list of the {@code k} least
- * elements in ascending order
+ * @return an immutable {@code RandomAccess} list of the {@code k} greatest
+ * elements in <i>descending order</i>
* @throws IllegalArgumentException if {@code k} is negative
- * @since 14.0
+ * @since 8.0
*/
- public <E extends T> List<E> leastOf(Iterator<E> elements, int k) {
- checkNotNull(elements);
- checkArgument(k >= 0, "k (%s) must be nonnegative", k);
-
- if (k == 0 || !elements.hasNext()) {
- return ImmutableList.of();
- } else if (k >= Integer.MAX_VALUE / 2) {
- // k is really large; just do a straightforward sorted-copy-and-sublist
- ArrayList<E> list = Lists.newArrayList(elements);
- Collections.sort(list, this);
- if (list.size() > k) {
- list.subList(k, list.size()).clear();
- }
- list.trimToSize();
- return Collections.unmodifiableList(list);
- }
-
- /*
- * Our goal is an O(n) algorithm using only one pass and O(k) additional
- * memory.
- *
- * We use the following algorithm: maintain a buffer of size 2*k. Every time
- * the buffer gets full, find the median and partition around it, keeping
- * only the lowest k elements. This requires n/k find-median-and-partition
- * steps, each of which take O(k) time with a traditional quickselect.
- *
- * After sorting the output, the whole algorithm is O(n + k log k). It
- * degrades gracefully for worst-case input (descending order), performs
- * competitively or wins outright for randomly ordered input, and doesn't
- * require the whole collection to fit into memory.
- */
- int bufferCap = k * 2;
- @SuppressWarnings("unchecked") // we'll only put E's in
- E[] buffer = (E[]) new Object[bufferCap];
- E threshold = elements.next();
- buffer[0] = threshold;
- int bufferSize = 1;
- // threshold is the kth smallest element seen so far. Once bufferSize >= k,
- // anything larger than threshold can be ignored immediately.
-
- while (bufferSize < k && elements.hasNext()) {
- E e = elements.next();
- buffer[bufferSize++] = e;
- threshold = max(threshold, e);
- }
-
- while (elements.hasNext()) {
- E e = elements.next();
- if (compare(e, threshold) >= 0) {
- continue;
- }
-
- buffer[bufferSize++] = e;
- if (bufferSize == bufferCap) {
- // We apply the quickselect algorithm to partition about the median,
- // and then ignore the last k elements.
- int left = 0;
- int right = bufferCap - 1;
-
- int minThresholdPosition = 0;
- // The leftmost position at which the greatest of the k lower elements
- // -- the new value of threshold -- might be found.
-
- while (left < right) {
- int pivotIndex = (left + right + 1) >>> 1;
- int pivotNewIndex = partition(buffer, left, right, pivotIndex);
- if (pivotNewIndex > k) {
- right = pivotNewIndex - 1;
- } else if (pivotNewIndex < k) {
- left = Math.max(pivotNewIndex, left + 1);
- minThresholdPosition = pivotNewIndex;
- } else {
- break;
- }
- }
- bufferSize = k;
+ @Beta
+ public <E extends T> List<E> greatestOf(Iterable<E> iterable, int k) {
+ // TODO(kevinb): see if delegation is hurting performance noticeably
+ // TODO(kevinb): if we change this implementation, add full unit tests.
+ return reverse().leastOf(iterable, k);
+ }
- threshold = buffer[minThresholdPosition];
- for (int i = minThresholdPosition + 1; i < bufferSize; i++) {
- threshold = max(threshold, buffer[i]);
- }
+ private <E extends T> void quicksortLeastK(
+ E[] values, int left, int right, int k) {
+ if (right > left) {
+ int pivotIndex = (left + right) >>> 1; // left + ((right - left) / 2)
+ int pivotNewIndex = partition(values, left, right, pivotIndex);
+ quicksortLeastK(values, left, pivotNewIndex - 1, k);
+ if (pivotNewIndex < k) {
+ quicksortLeastK(values, pivotNewIndex + 1, right, k);
}
}
-
- Arrays.sort(buffer, 0, bufferSize, this);
-
- bufferSize = Math.min(bufferSize, k);
- return Collections.unmodifiableList(
- Arrays.asList(ObjectArrays.arraysCopyOf(buffer, bufferSize)));
- // We can't use ImmutableList; we have to be null-friendly!
}
private <E extends T> int partition(
@@ -732,41 +484,15 @@ public abstract class Ordering<T> implements Comparator<T> {
}
/**
- * Returns the {@code k} greatest elements of the given iterable according to
- * this ordering, in order from greatest to least. If there are fewer than
- * {@code k} elements present, all will be included.
- *
- * <p>The implementation does not necessarily use a <i>stable</i> sorting
- * algorithm; when multiple elements are equivalent, it is undefined which
- * will come first.
- *
- * @return an immutable {@code RandomAccess} list of the {@code k} greatest
- * elements in <i>descending order</i>
- * @throws IllegalArgumentException if {@code k} is negative
- * @since 8.0
- */
- public <E extends T> List<E> greatestOf(Iterable<E> iterable, int k) {
- // TODO(kevinb): see if delegation is hurting performance noticeably
- // TODO(kevinb): if we change this implementation, add full unit tests.
- return reverse().leastOf(iterable, k);
- }
-
- /**
- * Returns the {@code k} greatest elements from the given iterator according to
- * this ordering, in order from greatest to least. If there are fewer than
- * {@code k} elements present, all will be included.
- *
- * <p>The implementation does not necessarily use a <i>stable</i> sorting
- * algorithm; when multiple elements are equivalent, it is undefined which
- * will come first.
+ * {@link Collections#binarySearch(List, Object, Comparator) Searches}
+ * {@code sortedList} for {@code key} using the binary search algorithm. The
+ * list must be sorted using this ordering.
*
- * @return an immutable {@code RandomAccess} list of the {@code k} greatest
- * elements in <i>descending order</i>
- * @throws IllegalArgumentException if {@code k} is negative
- * @since 14.0
+ * @param sortedList the list to be searched
+ * @param key the key to be searched for
*/
- public <E extends T> List<E> greatestOf(Iterator<E> iterator, int k) {
- return reverse().leastOf(iterator, k);
+ public int binarySearch(List<? extends T> sortedList, @Nullable T key) {
+ return Collections.binarySearch(sortedList, key, this);
}
/**
@@ -783,10 +509,9 @@ public abstract class Ordering<T> implements Comparator<T> {
* @return a new list containing the given elements in sorted order
*/
public <E extends T> List<E> sortedCopy(Iterable<E> iterable) {
- @SuppressWarnings("unchecked") // does not escape, and contains only E's
- E[] array = (E[]) Iterables.toArray(iterable);
- Arrays.sort(array, this);
- return Lists.newArrayList(Arrays.asList(array));
+ List<E> list = Lists.newArrayList(iterable);
+ Collections.sort(list, this);
+ return list;
}
/**
@@ -806,13 +531,7 @@ public abstract class Ordering<T> implements Comparator<T> {
*/
public <E extends T> ImmutableList<E> immutableSortedCopy(
Iterable<E> iterable) {
- @SuppressWarnings("unchecked") // we'll only ever have E's in here
- E[] elements = (E[]) Iterables.toArray(iterable);
- for (E e : elements) {
- checkNotNull(e);
- }
- Arrays.sort(elements, this);
- return ImmutableList.asImmutableList(elements);
+ return ImmutableList.copyOf(sortedCopy(iterable));
}
/**
@@ -858,34 +577,157 @@ public abstract class Ordering<T> implements Comparator<T> {
}
/**
- * {@link Collections#binarySearch(List, Object, Comparator) Searches}
- * {@code sortedList} for {@code key} using the binary search algorithm. The
- * list must be sorted using this ordering.
+ * Returns the greatest of the specified values according to this ordering. If
+ * there are multiple greatest values, the first of those is returned. The
+ * iterator will be left exhausted: its {@code hasNext()} method will return
+ * {@code false}.
*
- * @param sortedList the list to be searched
- * @param key the key to be searched for
+ * @param iterator the iterator whose maximum element is to be determined
+ * @throws NoSuchElementException if {@code iterator} is empty
+ * @throws ClassCastException if the parameters are not <i>mutually
+ * comparable</i> under this ordering.
+ *
+ * @since 11.0
*/
- public int binarySearch(List<? extends T> sortedList, @Nullable T key) {
- return Collections.binarySearch(sortedList, key, this);
+ @Beta
+ public <E extends T> E max(Iterator<E> iterator) {
+ // let this throw NoSuchElementException as necessary
+ E maxSoFar = iterator.next();
+
+ while (iterator.hasNext()) {
+ maxSoFar = max(maxSoFar, iterator.next());
+ }
+
+ return maxSoFar;
}
/**
- * Exception thrown by a {@link Ordering#explicit(List)} or {@link
- * Ordering#explicit(Object, Object[])} comparator when comparing a value
- * outside the set of values it can compare. Extending {@link
- * ClassCastException} may seem odd, but it is required.
+ * Returns the greatest of the specified values according to this ordering. If
+ * there are multiple greatest values, the first of those is returned.
+ *
+ * @param iterable the iterable whose maximum element is to be determined
+ * @throws NoSuchElementException if {@code iterable} is empty
+ * @throws ClassCastException if the parameters are not <i>mutually
+ * comparable</i> under this ordering.
*/
- // TODO(kevinb): make this public, document it right
- @VisibleForTesting
- static class IncomparableValueException extends ClassCastException {
- final Object value;
+ public <E extends T> E max(Iterable<E> iterable) {
+ return max(iterable.iterator());
+ }
- IncomparableValueException(Object value) {
- super("Cannot compare value: " + value);
- this.value = value;
+ /**
+ * Returns the greatest of the specified values according to this ordering. If
+ * there are multiple greatest values, the first of those is returned.
+ *
+ * @param a value to compare, returned if greater than or equal to the rest.
+ * @param b value to compare
+ * @param c value to compare
+ * @param rest values to compare
+ * @throws ClassCastException if the parameters are not <i>mutually
+ * comparable</i> under this ordering.
+ */
+ public <E extends T> E max(
+ @Nullable E a, @Nullable E b, @Nullable E c, E... rest) {
+ E maxSoFar = max(max(a, b), c);
+
+ for (E r : rest) {
+ maxSoFar = max(maxSoFar, r);
}
- private static final long serialVersionUID = 0;
+ return maxSoFar;
+ }
+
+ /**
+ * Returns the greater of the two values according to this ordering. If the
+ * values compare as 0, the first is returned.
+ *
+ * <p><b>Implementation note:</b> this method is invoked by the default
+ * implementations of the other {@code max} overloads, so overriding it will
+ * affect their behavior.
+ *
+ * @param a value to compare, returned if greater than or equal to b.
+ * @param b value to compare.
+ * @throws ClassCastException if the parameters are not <i>mutually
+ * comparable</i> under this ordering.
+ */
+ public <E extends T> E max(@Nullable E a, @Nullable E b) {
+ return compare(a, b) >= 0 ? a : b;
+ }
+
+ /**
+ * Returns the least of the specified values according to this ordering. If
+ * there are multiple least values, the first of those is returned. The
+ * iterator will be left exhausted: its {@code hasNext()} method will return
+ * {@code false}.
+ *
+ * @param iterator the iterator whose minimum element is to be determined
+ * @throws NoSuchElementException if {@code iterator} is empty
+ * @throws ClassCastException if the parameters are not <i>mutually
+ * comparable</i> under this ordering.
+ *
+ * @since 11.0
+ */
+ @Beta
+ public <E extends T> E min(Iterator<E> iterator) {
+ // let this throw NoSuchElementException as necessary
+ E minSoFar = iterator.next();
+
+ while (iterator.hasNext()) {
+ minSoFar = min(minSoFar, iterator.next());
+ }
+
+ return minSoFar;
+ }
+
+ /**
+ * Returns the least of the specified values according to this ordering. If
+ * there are multiple least values, the first of those is returned.
+ *
+ * @param iterable the iterable whose minimum element is to be determined
+ * @throws NoSuchElementException if {@code iterable} is empty
+ * @throws ClassCastException if the parameters are not <i>mutually
+ * comparable</i> under this ordering.
+ */
+ public <E extends T> E min(Iterable<E> iterable) {
+ return min(iterable.iterator());
+ }
+
+ /**
+ * Returns the least of the specified values according to this ordering. If
+ * there are multiple least values, the first of those is returned.
+ *
+ * @param a value to compare, returned if less than or equal to the rest.
+ * @param b value to compare
+ * @param c value to compare
+ * @param rest values to compare
+ * @throws ClassCastException if the parameters are not <i>mutually
+ * comparable</i> under this ordering.
+ */
+ public <E extends T> E min(
+ @Nullable E a, @Nullable E b, @Nullable E c, E... rest) {
+ E minSoFar = min(min(a, b), c);
+
+ for (E r : rest) {
+ minSoFar = min(minSoFar, r);
+ }
+
+ return minSoFar;
+ }
+
+ /**
+ * Returns the lesser of the two values according to this ordering. If the
+ * values compare as 0, the first is returned.
+ *
+ * <p><b>Implementation note:</b> this method is invoked by the default
+ * implementations of the other {@code min} overloads, so overriding it will
+ * affect their behavior.
+ *
+ * @param a value to compare, returned if less than or equal to b.
+ * @param b value to compare.
+ * @throws ClassCastException if the parameters are not <i>mutually
+ * comparable</i> under this ordering.
+ */
+ public <E extends T> E min(@Nullable E a, @Nullable E b) {
+ return compare(a, b) <= 0 ? a : b;
}
// Never make these public
diff --git a/guava/src/com/google/common/collect/PeekingIterator.java b/guava/src/com/google/common/collect/PeekingIterator.java
index 294b2e6..be8989d 100644
--- a/guava/src/com/google/common/collect/PeekingIterator.java
+++ b/guava/src/com/google/common/collect/PeekingIterator.java
@@ -23,10 +23,6 @@ import java.util.NoSuchElementException;
/**
* An iterator that supports a one-element lookahead while iterating.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionHelpersExplained#PeekingIterator">
- * {@code PeekingIterator}</a>.
*
* @author Mick Killianey
* @since 2.0 (imported from Google Collections Library)
diff --git a/guava/src/com/google/common/collect/Platform.java b/guava/src/com/google/common/collect/Platform.java
index cd321e8..408563b 100644
--- a/guava/src/com/google/common/collect/Platform.java
+++ b/guava/src/com/google/common/collect/Platform.java
@@ -17,16 +17,9 @@
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Maps.EntryTransformer;
+import com.google.common.annotations.GwtIncompatible;
import java.lang.reflect.Array;
-import java.util.Map;
-import java.util.NavigableMap;
-import java.util.NavigableSet;
-import java.util.SortedMap;
-import java.util.SortedSet;
/**
* Methods factored out so that they can be emulated differently in GWT.
@@ -44,6 +37,35 @@ class Platform {
}
/**
+ * Wrapper around {@link System#arraycopy} so that it can be emulated
+ * correctly in GWT.
+ *
+ * <p>It is only intended for the case {@code src} and {@code dest} are
+ * different. It also doesn't validate the types and indices.
+ *
+ * <p>As of GWT 2.0, The built-in {@link System#arraycopy} doesn't work
+ * in general case. See
+ * http://code.google.com/p/google-web-toolkit/issues/detail?id=3621
+ * for more details.
+ */
+ static void unsafeArrayCopy(
+ Object[] src, int srcPos, Object[] dest, int destPos, int length) {
+ System.arraycopy(src, srcPos, dest, destPos, length);
+ }
+
+ /**
+ * Returns a new array of the given length with the specified component type.
+ *
+ * @param type the component type
+ * @param length the length of the new array
+ */
+ @GwtIncompatible("Array.newInstance(Class, int)")
+ @SuppressWarnings("unchecked")
+ static <T> T[] newArray(Class<T> type, int length) {
+ return (T[]) Array.newInstance(type, length);
+ }
+
+ /**
* Returns a new array of the given length with the same type as a reference
* array.
*
@@ -70,34 +92,5 @@ class Platform {
return mapMaker.weakKeys();
}
- static <K, V1, V2> SortedMap<K, V2> mapsTransformEntriesSortedMap(
- SortedMap<K, V1> fromMap,
- EntryTransformer<? super K, ? super V1, V2> transformer) {
- return (fromMap instanceof NavigableMap)
- ? Maps.transformEntries((NavigableMap<K, V1>) fromMap, transformer)
- : Maps.transformEntriesIgnoreNavigable(fromMap, transformer);
- }
-
- static <K, V> SortedMap<K, V> mapsAsMapSortedSet(SortedSet<K> set,
- Function<? super K, V> function) {
- return (set instanceof NavigableSet)
- ? Maps.asMap((NavigableSet<K>) set, function)
- : Maps.asMapSortedIgnoreNavigable(set, function);
- }
-
- static <E> SortedSet<E> setsFilterSortedSet(SortedSet<E> set,
- Predicate<? super E> predicate) {
- return (set instanceof NavigableSet)
- ? Sets.filter((NavigableSet<E>) set, predicate)
- : Sets.filterSortedIgnoreNavigable(set, predicate);
- }
-
- static <K, V> SortedMap<K, V> mapsFilterSortedMap(SortedMap<K, V> map,
- Predicate<? super Map.Entry<K, V>> predicate) {
- return (map instanceof NavigableMap)
- ? Maps.filterEntries((NavigableMap<K, V>) map, predicate)
- : Maps.filterSortedIgnoreNavigable(map, predicate);
- }
-
private Platform() {}
}
diff --git a/guava/src/com/google/common/collect/Queues.java b/guava/src/com/google/common/collect/Queues.java
index d2bf4ad..d68146a 100644
--- a/guava/src/com/google/common/collect/Queues.java
+++ b/guava/src/com/google/common/collect/Queues.java
@@ -19,7 +19,6 @@ import com.google.common.base.Preconditions;
import java.util.ArrayDeque;
import java.util.Collection;
-import java.util.Deque;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
@@ -32,12 +31,14 @@ import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
/**
- * Static utility methods pertaining to {@link Queue} and {@link Deque} instances.
- * Also see this class's counterparts {@link Lists}, {@link Sets}, and {@link Maps}.
+ * Static utility methods pertaining to {@link Queue}
+ * instances. Also see this class's counterparts
+ * {@link Lists}, {@link Sets}, and {@link Maps}.
*
* @author Kurt Alfred Kluever
* @since 11.0
*/
+@Beta
public final class Queues {
private Queues() {}
@@ -54,32 +55,6 @@ public final class Queues {
// ArrayDeque
- /**
- * Creates an empty {@code ArrayDeque} instance.
- *
- * @return a new, empty {@code ArrayDeque}
- * @since 12.0
- */
- public static <E> ArrayDeque<E> newArrayDeque() {
- return new ArrayDeque<E>();
- }
-
- /**
- * Creates an {@code ArrayDeque} instance containing the given elements.
- *
- * @param elements the elements that the queue should contain, in order
- * @return a new {@code ArrayDeque} containing those elements
- * @since 12.0
- */
- public static <E> ArrayDeque<E> newArrayDeque(Iterable<? extends E> elements) {
- if (elements instanceof Collection) {
- return new ArrayDeque<E>(Collections2.cast(elements));
- }
- ArrayDeque<E> deque = new ArrayDeque<E>();
- Iterables.addAll(deque, elements);
- return deque;
- }
-
// ConcurrentLinkedQueue
/**
@@ -109,44 +84,6 @@ public final class Queues {
// LinkedBlockingDeque
- /**
- * Creates an empty {@code LinkedBlockingDeque} instance.
- *
- * @return a new, empty {@code LinkedBlockingDeque}
- * @since 12.0
- */
- public static <E> LinkedBlockingDeque<E> newLinkedBlockingDeque() {
- return new LinkedBlockingDeque<E>();
- }
-
- /**
- * Creates a {@code LinkedBlockingDeque} with the given (fixed) capacity.
- *
- * @param capacity the capacity of this deque
- * @return a new, empty {@code LinkedBlockingDeque}
- * @throws IllegalArgumentException if {@code capacity} is less than 1
- * @since 12.0
- */
- public static <E> LinkedBlockingDeque<E> newLinkedBlockingDeque(int capacity) {
- return new LinkedBlockingDeque<E>(capacity);
- }
-
- /**
- * Creates an {@code LinkedBlockingDeque} instance containing the given elements.
- *
- * @param elements the elements that the queue should contain, in order
- * @return a new {@code LinkedBlockingDeque} containing those elements
- * @since 12.0
- */
- public static <E> LinkedBlockingDeque<E> newLinkedBlockingDeque(Iterable<? extends E> elements) {
- if (elements instanceof Collection) {
- return new LinkedBlockingDeque<E>(Collections2.cast(elements));
- }
- LinkedBlockingDeque<E> deque = new LinkedBlockingDeque<E>();
- Iterables.addAll(deque, elements);
- return deque;
- }
-
// LinkedBlockingQueue
/**
@@ -249,12 +186,12 @@ public final class Queues {
public static <E> SynchronousQueue<E> newSynchronousQueue() {
return new SynchronousQueue<E>();
}
-
+
/**
- * Drains the queue as {@link BlockingQueue#drainTo(Collection, int)}, but if the requested
+ * Drains the queue as {@link BlockingQueue#drainTo(Collection, int)}, but if the requested
* {@code numElements} elements are not available, it will wait for them up to the specified
* timeout.
- *
+ *
* @param q the blocking queue to be drained
* @param buffer where to add the transferred elements
* @param numElements the number of elements to be waited for
@@ -263,7 +200,6 @@ public final class Queues {
* @return the number of elements transferred
* @throws InterruptedException if interrupted while waiting
*/
- @Beta
public static <E> int drain(BlockingQueue<E> q, Collection<? super E> buffer, int numElements,
long timeout, TimeUnit unit) throws InterruptedException {
Preconditions.checkNotNull(buffer);
@@ -289,13 +225,13 @@ public final class Queues {
}
return added;
}
-
+
/**
- * Drains the queue as {@linkplain #drain(BlockingQueue, Collection, int, long, TimeUnit)},
- * but with a different behavior in case it is interrupted while waiting. In that case, the
- * operation will continue as usual, and in the end the thread's interruption status will be set
- * (no {@code InterruptedException} is thrown).
- *
+ * Drains the queue as {@linkplain #drain(BlockingQueue, Collection, int, long, TimeUnit)},
+ * but with a different behavior in case it is interrupted while waiting. In that case, the
+ * operation will continue as usual, and in the end the thread's interruption status will be set
+ * (no {@code InterruptedException} is thrown).
+ *
* @param q the blocking queue to be drained
* @param buffer where to add the transferred elements
* @param numElements the number of elements to be waited for
@@ -303,8 +239,7 @@ public final class Queues {
* @param unit a {@code TimeUnit} determining how to interpret the timeout parameter
* @return the number of elements transferred
*/
- @Beta
- public static <E> int drainUninterruptibly(BlockingQueue<E> q, Collection<? super E> buffer,
+ public static <E> int drainUninterruptibly(BlockingQueue<E> q, Collection<? super E> buffer,
int numElements, long timeout, TimeUnit unit) {
Preconditions.checkNotNull(buffer);
long deadline = System.nanoTime() + unit.toNanos(timeout);
@@ -312,7 +247,7 @@ public final class Queues {
boolean interrupted = false;
try {
while (added < numElements) {
- // we could rely solely on #poll, but #drainTo might be more efficient when there are
+ // we could rely solely on #poll, but #drainTo might be more efficient when there are
// multiple elements already available (e.g. LinkedBlockingQueue#drainTo locks only once)
added += q.drainTo(buffer, numElements - added);
if (added < numElements) { // not enough elements immediately available; will have to poll
@@ -339,36 +274,4 @@ public final class Queues {
}
return added;
}
-
- /**
- * Returns a synchronized (thread-safe) queue backed by the specified queue. In order to
- * guarantee serial access, it is critical that <b>all</b> access to the backing queue is
- * accomplished through the returned queue.
- *
- * <p>It is imperative that the user manually synchronize on the returned queue when accessing
- * the queue's iterator: <pre> {@code
- *
- * Queue<E> queue = Queues.synchronizedQueue(MinMaxPriorityQueue<E>.create());
- * ...
- * queue.add(element); // Needn't be in synchronized block
- * ...
- * synchronized (queue) { // Must synchronize on queue!
- * Iterator<E> i = queue.iterator(); // Must be in synchronized block
- * while (i.hasNext()) {
- * foo(i.next());
- * }
- * }}</pre>
- *
- * Failure to follow this advice may result in non-deterministic behavior.
- *
- * <p>The returned queue will be serializable if the specified queue is serializable.
- *
- * @param queue the queue to be wrapped in a synchronized view
- * @return a synchronized view of the specified queue
- * @since 14.0
- */
- @Beta
- public static <E> Queue<E> synchronizedQueue(Queue<E> queue) {
- return Synchronized.queue(queue, null);
- }
}
diff --git a/guava/src/com/google/common/collect/Range.java b/guava/src/com/google/common/collect/Range.java
index e70c34f..c6a9189 100644
--- a/guava/src/com/google/common/collect/Range.java
+++ b/guava/src/com/google/common/collect/Range.java
@@ -17,17 +17,15 @@
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Ranges.create;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Equivalence;
-import com.google.common.base.Function;
import com.google.common.base.Predicate;
import java.io.Serializable;
import java.util.Collections;
import java.util.Comparator;
-import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedSet;
@@ -35,338 +33,94 @@ import java.util.SortedSet;
import javax.annotation.Nullable;
/**
- * A range (or "interval") defines the <i>boundaries</i> around a contiguous span of values of some
- * {@code Comparable} type; for example, "integers from 1 to 100 inclusive." Note that it is not
- * possible to <i>iterate</i> over these contained values. To do so, pass this range instance and
- * an appropriate {@link DiscreteDomain} to {@link ContiguousSet#create}.
+ * A range, sometimes known as an <i>interval</i>, is a <i>convex</i>
+ * (informally, "contiguous" or "unbroken") portion of a particular domain.
+ * Formally, convexity means that for any {@code a <= b <= c},
+ * {@code range.contains(a) && range.contains(c)} implies that {@code
+ * range.contains(b)}.
*
- * <h3>Types of ranges</h3>
+ * <p>A range is characterized by its lower and upper <i>bounds</i> (extremes),
+ * each of which can <i>open</i> (exclusive of its endpoint), <i>closed</i>
+ * (inclusive of its endpoint), or <i>unbounded</i>. This yields nine basic
+ * types of ranges:
*
- * <p>Each end of the range may be bounded or unbounded. If bounded, there is an associated
- * <i>endpoint</i> value, and the range is considered to be either <i>open</i> (does not include the
- * endpoint) or <i>closed</i> (includes the endpoint) on that side. With three possibilities on each
- * side, this yields nine basic types of ranges, enumerated below. (Notation: a square bracket
- * ({@code [ ]}) indicates that the range is closed on that side; a parenthesis ({@code ( )}) means
- * it is either open or unbounded. The construct {@code {x | statement}} is read "the set of all
- * <i>x</i> such that <i>statement</i>.")
+ * <ul>
+ * <li>{@code (a..b) = {x | a < x < b}}
+ * <li>{@code [a..b] = {x | a <= x <= b}}
+ * <li>{@code [a..b) = {x | a <= x < b}}
+ * <li>{@code (a..b] = {x | a < x <= b}}
+ * <li>{@code (a..+∞) = {x | x > a}}
+ * <li>{@code [a..+∞) = {x | x >= a}}
+ * <li>{@code (-∞..b) = {x | x < b}}
+ * <li>{@code (-∞..b] = {x | x <= b}}
+ * <li>{@code (-∞..+∞) = all values}
+ * </ul>
+ *
+ * (The notation {@code {x | statement}} is read "the set of all <i>x</i> such
+ * that <i>statement</i>.")
*
- * <blockquote><table>
- * <tr><td><b>Notation</b> <td><b>Definition</b> <td><b>Factory method</b>
- * <tr><td>{@code (a..b)} <td>{@code {x | a < x < b}} <td>{@link Range#open open}
- * <tr><td>{@code [a..b]} <td>{@code {x | a <= x <= b}}<td>{@link Range#closed closed}
- * <tr><td>{@code (a..b]} <td>{@code {x | a < x <= b}} <td>{@link Range#openClosed openClosed}
- * <tr><td>{@code [a..b)} <td>{@code {x | a <= x < b}} <td>{@link Range#closedOpen closedOpen}
- * <tr><td>{@code (a..+∞)} <td>{@code {x | x > a}} <td>{@link Range#greaterThan greaterThan}
- * <tr><td>{@code [a..+∞)} <td>{@code {x | x >= a}} <td>{@link Range#atLeast atLeast}
- * <tr><td>{@code (-∞..b)} <td>{@code {x | x < b}} <td>{@link Range#lessThan lessThan}
- * <tr><td>{@code (-∞..b]} <td>{@code {x | x <= b}} <td>{@link Range#atMost atMost}
- * <tr><td>{@code (-∞..+∞)}<td>{@code {x}} <td>{@link Range#all all}
- * </table></blockquote>
+ * <p>Notice that we use a square bracket ({@code [ ]}) to denote that an range
+ * is closed on that end, and a parenthesis ({@code ( )}) when it is open or
+ * unbounded.
*
- * <p>When both endpoints exist, the upper endpoint may not be less than the lower. The endpoints
- * may be equal only if at least one of the bounds is closed:
+ * <p>The values {@code a} and {@code b} used above are called <i>endpoints</i>.
+ * The upper endpoint may not be less than the lower endpoint. The endpoints may
+ * be equal only if at least one of the bounds is closed:
*
* <ul>
- * <li>{@code [a..a]} : a singleton range
- * <li>{@code [a..a); (a..a]} : {@linkplain #isEmpty empty} ranges; also valid
- * <li>{@code (a..a)} : <b>invalid</b>; an exception will be thrown
+ * <li>{@code [a..a]} : singleton range
+ * <li>{@code [a..a); (a..a]} : {@linkplain #isEmpty empty}, but valid
+ * <li>{@code (a..a)} : <b>invalid</b>
* </ul>
*
- * <h3>Warnings</h3>
+ * <p>Instances of this type can be obtained using the static factory methods in
+ * the {@link Ranges} class.
*
- * <ul>
- * <li>Use immutable value types only, if at all possible. If you must use a mutable type, <b>do
- * not</b> allow the endpoint instances to mutate after the range is created!
- * <li>Your value type's comparison method should be {@linkplain Comparable consistent with equals}
- * if at all possible. Otherwise, be aware that concepts used throughout this documentation such
- * as "equal", "same", "unique" and so on actually refer to whether {@link Comparable#compareTo
- * compareTo} returns zero, not whether {@link Object#equals equals} returns {@code true}.
- * <li>A class which implements {@code Comparable<UnrelatedType>} is very broken, and will cause
- * undefined horrible things to happen in {@code Range}. For now, the Range API does not prevent
- * its use, because this would also rule out all ungenerified (pre-JDK1.5) data types. <b>This
- * may change in the future.</b>
- * </ul>
+ * <p>Instances of {@code Range} are immutable. It is strongly encouraged to
+ * use this class only with immutable data types. When creating a range over a
+ * mutable type, take great care not to allow the value objects to mutate after
+ * the range is created.
*
- * <h3>Other notes</h3>
+ * <p>In this and other range-related specifications, concepts like "equal",
+ * "same", "unique" and so on are based on {@link Comparable#compareTo}
+ * returning zero, not on {@link Object#equals} returning {@code true}. Of
+ * course, when these methods are kept <i>consistent</i> (as defined in {@link
+ * Comparable}), this is not an issue.
*
- * <ul>
- * <li>Instances of this type are obtained using the static factory methods in this class.
- * <li>Ranges are <i>convex</i>: whenever two values are contained, all values in between them must
- * also be contained. More formally, for any {@code c1 <= c2 <= c3} of type {@code C}, {@code
- * r.contains(c1) && r.contains(c3)} implies {@code r.contains(c2)}). This means that a {@code
- * Range<Integer>} can never be used to represent, say, "all <i>prime</i> numbers from 1 to
- * 100."
- * <li>When evaluated as a {@link Predicate}, a range yields the same result as invoking {@link
- * #contains}.
- * <li>Terminology note: a range {@code a} is said to be the <i>maximal</i> range having property
- * <i>P</i> if, for all ranges {@code b} also having property <i>P</i>, {@code a.encloses(b)}.
- * Likewise, {@code a} is <i>minimal</i> when {@code b.encloses(a)} for all {@code b} having
- * property <i>P</i>. See, for example, the definition of {@link #intersection intersection}.
- * </ul>
+ * <p>A range {@code a} is said to be the <i>maximal</i> range having property
+ * <i>P</i> if, for all ranges {@code b} also having property <i>P</i>, {@code
+ * a.encloses(b)}. Likewise, {@code a} is <i>minimal</i> when {@code
+ * b.encloses(a)} for all {@code b} having property <i>P</i>. See, for example,
+ * the definition of {@link #intersection}.
*
- * <h3>Further reading</h3>
+ * <p>This class can be used with any type which implements {@code Comparable};
+ * it does not require {@code Comparable<? super C>} because this would be
+ * incompatible with pre-Java 5 types. If this class is used with a perverse
+ * {@code Comparable} type ({@code Foo implements Comparable<Bar>} where {@code
+ * Bar} is not a supertype of {@code Foo}), any of its methods may throw {@link
+ * ClassCastException}. (There is no good reason for such a type to exist.)
*
- * <p>See the Guava User Guide article on
- * <a href="http://code.google.com/p/guava-libraries/wiki/RangesExplained">{@code Range}</a>.
+ * <p>When evaluated as a {@link Predicate}, a range yields the same result as
+ * invoking {@link #contains}.
*
* @author Kevin Bourrillion
* @author Gregory Kick
* @since 10.0
*/
@GwtCompatible
-@SuppressWarnings("rawtypes")
-public final class Range<C extends Comparable> implements Predicate<C>, Serializable {
-
- private static final Function<Range, Cut> LOWER_BOUND_FN = new Function<Range, Cut>() {
- @Override
- public Cut apply(Range range) {
- return range.lowerBound;
- }
- };
-
- @SuppressWarnings("unchecked")
- static <C extends Comparable<?>> Function<Range<C>, Cut<C>> lowerBoundFn() {
- return (Function) LOWER_BOUND_FN;
- }
-
- private static final Function<Range, Cut> UPPER_BOUND_FN = new Function<Range, Cut>() {
- @Override
- public Cut apply(Range range) {
- return range.upperBound;
- }
- };
-
- @SuppressWarnings("unchecked")
- static <C extends Comparable<?>> Function<Range<C>, Cut<C>> upperBoundFn() {
- return (Function) UPPER_BOUND_FN;
- }
-
- static final Ordering<Range<?>> RANGE_LEX_ORDERING = new Ordering<Range<?>>() {
- @Override
- public int compare(Range<?> left, Range<?> right) {
- return ComparisonChain.start()
- .compare(left.lowerBound, right.lowerBound)
- .compare(left.upperBound, right.upperBound)
- .result();
- }
- };
-
- static <C extends Comparable<?>> Range<C> create(
- Cut<C> lowerBound, Cut<C> upperBound) {
- return new Range<C>(lowerBound, upperBound);
- }
-
- /**
- * Returns a range that contains all values strictly greater than {@code
- * lower} and strictly less than {@code upper}.
- *
- * @throws IllegalArgumentException if {@code lower} is greater than <i>or
- * equal to</i> {@code upper}
- * @since 14.0
- */
- public static <C extends Comparable<?>> Range<C> open(C lower, C upper) {
- return create(Cut.aboveValue(lower), Cut.belowValue(upper));
- }
-
- /**
- * Returns a range that contains all values greater than or equal to
- * {@code lower} and less than or equal to {@code upper}.
- *
- * @throws IllegalArgumentException if {@code lower} is greater than {@code
- * upper}
- * @since 14.0
- */
- public static <C extends Comparable<?>> Range<C> closed(C lower, C upper) {
- return create(Cut.belowValue(lower), Cut.aboveValue(upper));
- }
-
- /**
- * Returns a range that contains all values greater than or equal to
- * {@code lower} and strictly less than {@code upper}.
- *
- * @throws IllegalArgumentException if {@code lower} is greater than {@code
- * upper}
- * @since 14.0
- */
- public static <C extends Comparable<?>> Range<C> closedOpen(
- C lower, C upper) {
- return create(Cut.belowValue(lower), Cut.belowValue(upper));
- }
-
- /**
- * Returns a range that contains all values strictly greater than {@code
- * lower} and less than or equal to {@code upper}.
- *
- * @throws IllegalArgumentException if {@code lower} is greater than {@code
- * upper}
- * @since 14.0
- */
- public static <C extends Comparable<?>> Range<C> openClosed(
- C lower, C upper) {
- return create(Cut.aboveValue(lower), Cut.aboveValue(upper));
- }
-
- /**
- * Returns a range that contains any value from {@code lower} to {@code
- * upper}, where each endpoint may be either inclusive (closed) or exclusive
- * (open).
- *
- * @throws IllegalArgumentException if {@code lower} is greater than {@code
- * upper}
- * @since 14.0
- */
- public static <C extends Comparable<?>> Range<C> range(
- C lower, BoundType lowerType, C upper, BoundType upperType) {
- checkNotNull(lowerType);
- checkNotNull(upperType);
-
- Cut<C> lowerBound = (lowerType == BoundType.OPEN)
- ? Cut.aboveValue(lower)
- : Cut.belowValue(lower);
- Cut<C> upperBound = (upperType == BoundType.OPEN)
- ? Cut.belowValue(upper)
- : Cut.aboveValue(upper);
- return create(lowerBound, upperBound);
- }
-
- /**
- * Returns a range that contains all values strictly less than {@code
- * endpoint}.
- *
- * @since 14.0
- */
- public static <C extends Comparable<?>> Range<C> lessThan(C endpoint) {
- return create(Cut.<C>belowAll(), Cut.belowValue(endpoint));
- }
-
- /**
- * Returns a range that contains all values less than or equal to
- * {@code endpoint}.
- *
- * @since 14.0
- */
- public static <C extends Comparable<?>> Range<C> atMost(C endpoint) {
- return create(Cut.<C>belowAll(), Cut.aboveValue(endpoint));
- }
-
- /**
- * Returns a range with no lower bound up to the given endpoint, which may be
- * either inclusive (closed) or exclusive (open).
- *
- * @since 14.0
- */
- public static <C extends Comparable<?>> Range<C> upTo(
- C endpoint, BoundType boundType) {
- switch (boundType) {
- case OPEN:
- return lessThan(endpoint);
- case CLOSED:
- return atMost(endpoint);
- default:
- throw new AssertionError();
- }
- }
-
- /**
- * Returns a range that contains all values strictly greater than {@code
- * endpoint}.
- *
- * @since 14.0
- */
- public static <C extends Comparable<?>> Range<C> greaterThan(C endpoint) {
- return create(Cut.aboveValue(endpoint), Cut.<C>aboveAll());
- }
-
- /**
- * Returns a range that contains all values greater than or equal to
- * {@code endpoint}.
- *
- * @since 14.0
- */
- public static <C extends Comparable<?>> Range<C> atLeast(C endpoint) {
- return create(Cut.belowValue(endpoint), Cut.<C>aboveAll());
- }
-
- /**
- * Returns a range from the given endpoint, which may be either inclusive
- * (closed) or exclusive (open), with no upper bound.
- *
- * @since 14.0
- */
- public static <C extends Comparable<?>> Range<C> downTo(
- C endpoint, BoundType boundType) {
- switch (boundType) {
- case OPEN:
- return greaterThan(endpoint);
- case CLOSED:
- return atLeast(endpoint);
- default:
- throw new AssertionError();
- }
- }
-
- private static final Range<Comparable> ALL =
- new Range<Comparable>(Cut.belowAll(), Cut.aboveAll());
-
- /**
- * Returns a range that contains every value of type {@code C}.
- *
- * @since 14.0
- */
- @SuppressWarnings("unchecked")
- public static <C extends Comparable<?>> Range<C> all() {
- return (Range) ALL;
- }
-
- /**
- * Returns a range that {@linkplain Range#contains(Comparable) contains} only
- * the given value. The returned range is {@linkplain BoundType#CLOSED closed}
- * on both ends.
- *
- * @since 14.0
- */
- public static <C extends Comparable<?>> Range<C> singleton(C value) {
- return closed(value, value);
- }
-
- /**
- * Returns the minimal range that
- * {@linkplain Range#contains(Comparable) contains} all of the given values.
- * The returned range is {@linkplain BoundType#CLOSED closed} on both ends.
- *
- * @throws ClassCastException if the parameters are not <i>mutually
- * comparable</i>
- * @throws NoSuchElementException if {@code values} is empty
- * @throws NullPointerException if any of {@code values} is null
- * @since 14.0
- */
- public static <C extends Comparable<?>> Range<C> encloseAll(
- Iterable<C> values) {
- checkNotNull(values);
- if (values instanceof ContiguousSet) {
- return ((ContiguousSet<C>) values).range();
- }
- Iterator<C> valueIterator = values.iterator();
- C min = checkNotNull(valueIterator.next());
- C max = min;
- while (valueIterator.hasNext()) {
- C value = checkNotNull(valueIterator.next());
- min = Ordering.natural().min(min, value);
- max = Ordering.natural().max(max, value);
- }
- return closed(min, max);
- }
-
+@Beta
+public final class Range<C extends Comparable>
+ implements Predicate<C>, Serializable {
final Cut<C> lowerBound;
final Cut<C> upperBound;
- private Range(Cut<C> lowerBound, Cut<C> upperBound) {
- if (lowerBound.compareTo(upperBound) > 0 || lowerBound == Cut.<C>aboveAll()
- || upperBound == Cut.<C>belowAll()) {
- throw new IllegalArgumentException("Invalid range: " + toString(lowerBound, upperBound));
+ Range(Cut<C> lowerBound, Cut<C> upperBound) {
+ if (lowerBound.compareTo(upperBound) > 0) {
+ throw new IllegalArgumentException(
+ "Invalid range: " + toString(lowerBound, upperBound));
}
- this.lowerBound = checkNotNull(lowerBound);
- this.upperBound = checkNotNull(upperBound);
+ this.lowerBound = lowerBound;
+ this.upperBound = upperBound;
}
/**
@@ -379,19 +133,20 @@ public final class Range<C extends Comparable> implements Predicate<C>, Serializ
/**
* Returns the lower endpoint of this range.
*
- * @throws IllegalStateException if this range is unbounded below (that is, {@link
- * #hasLowerBound()} returns {@code false})
+ * @throws IllegalStateException if this range is unbounded below (that is,
+ * {@link #hasLowerBound()} returns {@code false})
*/
public C lowerEndpoint() {
return lowerBound.endpoint();
}
/**
- * Returns the type of this range's lower bound: {@link BoundType#CLOSED} if the range includes
- * its lower endpoint, {@link BoundType#OPEN} if it does not.
+ * Returns the type of this range's lower bound: {@link BoundType#CLOSED} if
+ * the range includes its lower endpoint, {@link BoundType#OPEN} if it does
+ * not.
*
- * @throws IllegalStateException if this range is unbounded below (that is, {@link
- * #hasLowerBound()} returns {@code false})
+ * @throws IllegalStateException if this range is unbounded below (that is,
+ * {@link #hasLowerBound()} returns {@code false})
*/
public BoundType lowerBoundType() {
return lowerBound.typeAsLowerBound();
@@ -407,41 +162,42 @@ public final class Range<C extends Comparable> implements Predicate<C>, Serializ
/**
* Returns the upper endpoint of this range.
*
- * @throws IllegalStateException if this range is unbounded above (that is, {@link
- * #hasUpperBound()} returns {@code false})
+ * @throws IllegalStateException if this range is unbounded above (that is,
+ * {@link #hasUpperBound()} returns {@code false})
*/
public C upperEndpoint() {
return upperBound.endpoint();
}
/**
- * Returns the type of this range's upper bound: {@link BoundType#CLOSED} if the range includes
- * its upper endpoint, {@link BoundType#OPEN} if it does not.
+ * Returns the type of this range's upper bound: {@link BoundType#CLOSED} if
+ * the range includes its upper endpoint, {@link BoundType#OPEN} if it does
+ * not.
*
- * @throws IllegalStateException if this range is unbounded above (that is, {@link
- * #hasUpperBound()} returns {@code false})
+ * @throws IllegalStateException if this range is unbounded above (that is,
+ * {@link #hasUpperBound()} returns {@code false})
*/
public BoundType upperBoundType() {
return upperBound.typeAsUpperBound();
}
/**
- * Returns {@code true} if this range is of the form {@code [v..v)} or {@code (v..v]}. (This does
- * not encompass ranges of the form {@code (v..v)}, because such ranges are <i>invalid</i> and
- * can't be constructed at all.)
+ * Returns {@code true} if this range is of the form {@code [v..v)} or {@code
+ * (v..v]}. (This does not encompass ranges of the form {@code (v..v)},
+ * because such ranges are <i>invalid</i> and can't be constructed at all.)
*
- * <p>Note that certain discrete ranges such as the integer range {@code (3..4)} are <b>not</b>
- * considered empty, even though they contain no actual values. In these cases, it may be
- * helpful to preprocess ranges with {@link #canonical(DiscreteDomain)}.
+ * <p>Note that certain discrete ranges such as the integer range {@code
+ * (3..4)} are <b>not</b> considered empty, even though they contain no actual
+ * values.
*/
public boolean isEmpty() {
return lowerBound.equals(upperBound);
}
/**
- * Returns {@code true} if {@code value} is within the bounds of this range. For example, on the
- * range {@code [0..2)}, {@code contains(1)} returns {@code true}, while {@code contains(2)}
- * returns {@code false}.
+ * Returns {@code true} if {@code value} is within the bounds of this
+ * range. For example, on the range {@code [0..2)}, {@code contains(1)}
+ * returns {@code true}, while {@code contains(2)} returns {@code false}.
*/
public boolean contains(C value) {
checkNotNull(value);
@@ -450,16 +206,17 @@ public final class Range<C extends Comparable> implements Predicate<C>, Serializ
}
/**
- * Equivalent to {@link #contains}; provided only to satisfy the {@link Predicate} interface. When
- * using a reference of type {@code Range}, always invoke {@link #contains} directly instead.
+ * Equivalent to {@link #contains}; provided only to satisfy the {@link
+ * Predicate} interface. When using a reference of type {@code Range}, always
+ * invoke {@link #contains} directly instead.
*/
@Override public boolean apply(C input) {
return contains(input);
}
/**
- * Returns {@code true} if every element in {@code values} is {@linkplain #contains contained} in
- * this range.
+ * Returns {@code true} if every element in {@code values} is {@linkplain
+ * #contains contained} in this range.
*/
public boolean containsAll(Iterable<? extends C> values) {
if (Iterables.isEmpty(values)) {
@@ -484,27 +241,42 @@ public final class Range<C extends Comparable> implements Predicate<C>, Serializ
}
/**
- * Returns {@code true} if the bounds of {@code other} do not extend outside the bounds of this
- * range. Examples:
+ * Returns {@code true} if the bounds of {@code other} do not extend outside
+ * the bounds of this range. Examples:
*
* <ul>
* <li>{@code [3..6]} encloses {@code [4..5]}
* <li>{@code (3..6)} encloses {@code (3..6)}
- * <li>{@code [3..6]} encloses {@code [4..4)} (even though the latter is empty)
+ * <li>{@code [3..6]} encloses {@code [4..4)} (even though the latter is
+ * empty)
* <li>{@code (3..6]} does not enclose {@code [3..6]}
- * <li>{@code [4..5]} does not enclose {@code (3..6)} (even though it contains every value
- * contained by the latter range)
- * <li>{@code [3..6]} does not enclose {@code (1..1]} (even though it contains every value
- * contained by the latter range)
+ * <li>{@code [4..5]} does not enclose {@code (3..6)} (even though it contains
+ * every value contained by the latter range)
+ * <li>{@code [3..6]} does not enclose {@code (1..1]} (even though it contains
+ * every value contained by the latter range)
* </ul>
*
- * Note that if {@code a.encloses(b)}, then {@code b.contains(v)} implies {@code a.contains(v)},
- * but as the last two examples illustrate, the converse is not always true.
+ * Note that if {@code a.encloses(b)}, then {@code b.contains(v)} implies
+ * {@code a.contains(v)}, but as the last two examples illustrate, the
+ * converse is not always true.
*
- * <p>Being reflexive, antisymmetric and transitive, the {@code encloses} relation defines a
- * <i>partial order</i> over ranges. There exists a unique {@linkplain Range#all maximal} range
- * according to this relation, and also numerous {@linkplain #isEmpty minimal} ranges. Enclosure
- * also implies {@linkplain #isConnected connectedness}.
+ * <p>The encloses relation has the following properties:
+ *
+ * <ul>
+ * <li>reflexive: {@code a.encloses(a)} is always true
+ * <li>antisymmetric: {@code a.encloses(b) && b.encloses(a)} implies {@code
+ * a.equals(b)}
+ * <li>transitive: {@code a.encloses(b) && b.encloses(c)} implies {@code
+ * a.encloses(c)}
+ * <li>not a total ordering: {@code !a.encloses(b)} does not imply {@code
+ * b.encloses(a)}
+ * <li>there exists a {@linkplain Ranges#all maximal} range, for which
+ * {@code encloses} is always true
+ * <li>there also exist {@linkplain #isEmpty minimal} ranges, for
+ * which {@code encloses(b)} is always false when {@code !equals(b)}
+ * <li>if {@code a.encloses(b)}, then {@link #isConnected a.isConnected(b)}
+ * is {@code true}.
+ * </ul>
*/
public boolean encloses(Range<C> other) {
return lowerBound.compareTo(other.lowerBound) <= 0
@@ -512,133 +284,160 @@ public final class Range<C extends Comparable> implements Predicate<C>, Serializ
}
/**
- * Returns {@code true} if there exists a (possibly empty) range which is {@linkplain #encloses
- * enclosed} by both this range and {@code other}.
+ * Returns the maximal range {@linkplain #encloses enclosed} by both this
+ * range and {@code other}, if such a range exists.
+ *
+ * <p>For example, the intersection of {@code [1..5]} and {@code (3..7)} is
+ * {@code (3..5]}. The resulting range may be empty; for example,
+ * {@code [1..5)} intersected with {@code [5..7)} yields the empty range
+ * {@code [5..5)}.
+ *
+ * <p>Generally, the intersection exists if and only if this range and
+ * {@code other} are {@linkplain #isConnected connected}.
+ *
+ * <p>The intersection operation has the following properties:
*
- * <p>For example,
* <ul>
- * <li>{@code [2, 4)} and {@code [5, 7)} are not connected
- * <li>{@code [2, 4)} and {@code [3, 5)} are connected, because both enclose {@code [3, 4)}
- * <li>{@code [2, 4)} and {@code [4, 6)} are connected, because both enclose the empty range
- * {@code [4, 4)}
+ * <li>commutative: {@code a.intersection(b)} produces the same result as
+ * {@code b.intersection(a)}
+ * <li>associative: {@code a.intersection(b).intersection(c)} produces the
+ * same result as {@code a.intersection(b.intersection(c))}
+ * <li>idempotent: {@code a.intersection(a)} equals {@code a}
+ * <li>identity ({@link Ranges#all}): {@code a.intersection(Ranges.all())}
+ * equals {@code a}
* </ul>
*
- * <p>Note that this range and {@code other} have a well-defined {@linkplain #span union} and
- * {@linkplain #intersection intersection} (as a single, possibly-empty range) if and only if this
- * method returns {@code true}.
- *
- * <p>The connectedness relation is both reflexive and symmetric, but does not form an {@linkplain
- * Equivalence equivalence relation} as it is not transitive.
- *
- * <p>Note that certain discrete ranges are not considered connected, even though there are no
- * elements "between them." For example, {@code [3, 5]} is not considered connected to {@code
- * [6, 10]}. In these cases, it may be desirable for both input ranges to be preprocessed with
- * {@link #canonical(DiscreteDomain)} before testing for connectedness.
+ * @throws IllegalArgumentException if no range exists that is enclosed by
+ * both these ranges
*/
- public boolean isConnected(Range<C> other) {
- return lowerBound.compareTo(other.upperBound) <= 0
- && other.lowerBound.compareTo(upperBound) <= 0;
+ public Range<C> intersection(Range<C> other) {
+ Cut<C> newLower = Ordering.natural().max(lowerBound, other.lowerBound);
+ Cut<C> newUpper = Ordering.natural().min(upperBound, other.upperBound);
+ return create(newLower, newUpper);
}
/**
- * Returns the maximal range {@linkplain #encloses enclosed} by both this range and {@code
- * connectedRange}, if such a range exists.
- *
- * <p>For example, the intersection of {@code [1..5]} and {@code (3..7)} is {@code (3..5]}. The
- * resulting range may be empty; for example, {@code [1..5)} intersected with {@code [5..7)}
- * yields the empty range {@code [5..5)}.
- *
- * <p>The intersection exists if and only if the two ranges are {@linkplain #isConnected
- * connected}.
- *
- * <p>The intersection operation is commutative, associative and idempotent, and its identity
- * element is {@link Range#all}).
+ * Returns {@code true} if there exists a (possibly empty) range which is
+ * {@linkplain #encloses enclosed} by both this range and {@code other}.
+ *
+ * <p>For example,
+ * <ul>
+ * <li>{@code [2, 4)} and {@code [5, 7)} are not connected
+ * <li>{@code [2, 4)} and {@code [3, 5)} are connected, because both enclose
+ * {@code [3, 4)}
+ * <li>{@code [2, 4)} and {@code [4, 6)} are connected, because both enclose
+ * the empty range {@code [4, 4)}
+ * </ul>
+ *
+ * <p>Note that this range and {@code other} have a well-defined {@linkplain
+ * #span union} and {@linkplain #intersection intersection} (as a single,
+ * possibly-empty range) if and only if this method returns {@code true}.
+ *
+ * <p>The connectedness relation has the following properties:
*
- * @throws IllegalArgumentException if {@code isConnected(connectedRange)} is {@code false}
+ * <ul>
+ * <li>symmetric: {@code a.isConnected(b)} produces the same result as
+ * {@code b.isConnected(a)}
+ * <li>reflexive: {@code a.isConnected(a)} returns {@code true}
+ * </ul>
*/
- public Range<C> intersection(Range<C> connectedRange) {
- int lowerCmp = lowerBound.compareTo(connectedRange.lowerBound);
- int upperCmp = upperBound.compareTo(connectedRange.upperBound);
- if (lowerCmp >= 0 && upperCmp <= 0) {
- return this;
- } else if (lowerCmp <= 0 && upperCmp >= 0) {
- return connectedRange;
- } else {
- Cut<C> newLower = (lowerCmp >= 0) ? lowerBound : connectedRange.lowerBound;
- Cut<C> newUpper = (upperCmp <= 0) ? upperBound : connectedRange.upperBound;
- return create(newLower, newUpper);
- }
+ public boolean isConnected(Range<C> other) {
+ return lowerBound.compareTo(other.upperBound) <= 0
+ && other.lowerBound.compareTo(upperBound) <= 0;
}
/**
- * Returns the minimal range that {@linkplain #encloses encloses} both this range and {@code
- * other}. For example, the span of {@code [1..3]} and {@code (5..7)} is {@code [1..7)}.
+ * Returns the minimal range that {@linkplain #encloses encloses} both this
+ * range and {@code other}. For example, the span of {@code [1..3]} and
+ * {@code (5..7)} is {@code [1..7)}. Note that the span may contain values
+ * that are not contained by either original range.
*
- * <p><i>If</i> the input ranges are {@linkplain #isConnected connected}, the returned range can
- * also be called their <i>union</i>. If they are not, note that the span might contain values
- * that are not contained in either input range.
+ * <p>The span operation has the following properties:
*
- * <p>Like {@link #intersection(Range) intersection}, this operation is commutative, associative
- * and idempotent. Unlike it, it is always well-defined for any two input ranges.
+ * <ul>
+ * <li>closed: the range {@code a.span(b)} exists for all ranges {@code a} and
+ * {@code b}
+ * <li>commutative: {@code a.span(b)} equals {@code b.span(a)}
+ * <li>associative: {@code a.span(b).span(c)} equals {@code a.span(b.span(c))}
+ * <li>idempotent: {@code a.span(a)} equals {@code a}
+ * </ul>
+ *
+ * <p>Note that the returned range is also called the <i>union</i> of this
+ * range and {@code other} if and only if the ranges are
+ * {@linkplain #isConnected connected}.
*/
public Range<C> span(Range<C> other) {
- int lowerCmp = lowerBound.compareTo(other.lowerBound);
- int upperCmp = upperBound.compareTo(other.upperBound);
- if (lowerCmp <= 0 && upperCmp >= 0) {
- return this;
- } else if (lowerCmp >= 0 && upperCmp <= 0) {
- return other;
- } else {
- Cut<C> newLower = (lowerCmp <= 0) ? lowerBound : other.lowerBound;
- Cut<C> newUpper = (upperCmp >= 0) ? upperBound : other.upperBound;
- return create(newLower, newUpper);
- }
+ Cut<C> newLower = Ordering.natural().min(lowerBound, other.lowerBound);
+ Cut<C> newUpper = Ordering.natural().max(upperBound, other.upperBound);
+ return create(newLower, newUpper);
}
/**
- * Returns an {@link ContiguousSet} containing the same values in the given domain
- * {@linkplain Range#contains contained} by this range.
+ * Returns an {@link ImmutableSortedSet} containing the same values in the
+ * given domain {@linkplain Range#contains contained} by this range.
*
- * <p><b>Note:</b> {@code a.asSet(d).equals(b.asSet(d))} does not imply {@code a.equals(b)}! For
- * example, {@code a} and {@code b} could be {@code [2..4]} and {@code (1..5)}, or the empty
- * ranges {@code [3..3)} and {@code [4..4)}.
+ * <p><b>Note:</b> {@code a.asSet().equals(b.asSet())} does not imply {@code
+ * a.equals(b)}! For example, {@code a} and {@code b} could be {@code [2..4]}
+ * and {@code (1..5)}, or the empty ranges {@code [3..3)} and {@code [4..4)}.
*
- * <p><b>Warning:</b> Be extremely careful what you do with the {@code asSet} view of a large
- * range (such as {@code Range.greaterThan(0)}). Certain operations on such a set can be
- * performed efficiently, but others (such as {@link Set#hashCode} or {@link
- * Collections#frequency}) can cause major performance problems.
+ * <p><b>Warning:</b> Be extremely careful what you do with the {@code asSet}
+ * view of a large range (such as {@code Ranges.greaterThan(0)}). Certain
+ * operations on such a set can be performed efficiently, but others (such as
+ * {@link Set#hashCode} or {@link Collections#frequency}) can cause major
+ * performance problems.
*
- * <p>The returned set's {@link Object#toString} method returns a short-hand form of the set's
- * contents, such as {@code "[1..100]}"}.
+ * <p>The returned set's {@link Object#toString} method returns a short-hand
+ * form of set's contents such as {@code "[1..100]}"}.
*
- * @throws IllegalArgumentException if neither this range nor the domain has a lower bound, or if
- * neither has an upper bound
- * @deprecated Use {@code ContiguousSet.create(range, domain)} instead.
+ * @throws IllegalArgumentException if neither this range nor the domain has a
+ * lower bound, or if neither has an upper bound
*/
// TODO(kevinb): commit in spec to which methods are efficient?
- @Beta
@GwtCompatible(serializable = false)
- @Deprecated
public ContiguousSet<C> asSet(DiscreteDomain<C> domain) {
- return ContiguousSet.create(this, domain);
+ checkNotNull(domain);
+ Range<C> effectiveRange = this;
+ try {
+ if (!hasLowerBound()) {
+ effectiveRange = effectiveRange.intersection(
+ Ranges.atLeast(domain.minValue()));
+ }
+ if (!hasUpperBound()) {
+ effectiveRange = effectiveRange.intersection(
+ Ranges.atMost(domain.maxValue()));
+ }
+ } catch (NoSuchElementException e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ // Per class spec, we are allowed to throw CCE if necessary
+ boolean empty = effectiveRange.isEmpty()
+ || compareOrThrow(
+ lowerBound.leastValueAbove(domain),
+ upperBound.greatestValueBelow(domain)) > 0;
+
+ return empty
+ ? new EmptyContiguousSet<C>(domain)
+ : new RegularContiguousSet<C>(effectiveRange, domain);
}
/**
- * Returns the canonical form of this range in the given domain. The canonical form has the
- * following properties:
+ * Returns the canonical form of this range in the given domain. The canonical
+ * form has the following properties:
*
* <ul>
- * <li>equivalence: {@code a.canonical().contains(v) == a.contains(v)} for all {@code v} (in other
- * words, {@code ContiguousSet.create(a.canonical(domain), domain).equals(
- * ContiguousSet.create(a, domain))}
+ * <li>equivalence: {@code a.canonical().contains(v) == a.contains(v)} for
+ * all {@code v} (in other words, {@code
+ * a.canonical(domain).asSet(domain).equals(a.asSet(domain))}
* <li>uniqueness: unless {@code a.isEmpty()},
- * {@code ContiguousSet.create(a, domain).equals(ContiguousSet.create(b, domain))} implies
+ * {@code a.asSet(domain).equals(b.asSet(domain))} implies
* {@code a.canonical(domain).equals(b.canonical(domain))}
- * <li>idempotence: {@code a.canonical(domain).canonical(domain).equals(a.canonical(domain))}
+ * <li>idempotence: {@code
+ * a.canonical(domain).canonical(domain).equals(a.canonical(domain))}
* </ul>
*
- * Furthermore, this method guarantees that the range returned will be one of the following
- * canonical forms:
+ * Furthermore, this method guarantees that the range returned will be one
+ * of the following canonical forms:
*
* <ul>
* <li>[start..end)
@@ -651,15 +450,18 @@ public final class Range<C extends Comparable> implements Predicate<C>, Serializ
checkNotNull(domain);
Cut<C> lower = lowerBound.canonical(domain);
Cut<C> upper = upperBound.canonical(domain);
- return (lower == lowerBound && upper == upperBound) ? this : create(lower, upper);
+ return (lower == lowerBound && upper == upperBound)
+ ? this : create(lower, upper);
}
/**
- * Returns {@code true} if {@code object} is a range having the same endpoints and bound types as
- * this range. Note that discrete ranges such as {@code (1..4)} and {@code [2..3]} are <b>not</b>
- * equal to one another, despite the fact that they each contain precisely the same set of values.
- * Similarly, empty ranges are not equal unless they have exactly the same representation, so
- * {@code [3..3)}, {@code (3..3]}, {@code (4..4]} are all unequal.
+ * Returns {@code true} if {@code object} is a range having the same
+ * endpoints and bound types as this range. Note that discrete ranges
+ * such as {@code (1..4)} and {@code [2..3]} are <b>not</b> equal to one
+ * another, despite the fact that they each contain precisely the same set of
+ * values. Similarly, empty ranges are not equal unless they have exactly
+ * the same representation, so {@code [3..3)}, {@code (3..3]}, {@code (4..4]}
+ * are all unequal.
*/
@Override public boolean equals(@Nullable Object object) {
if (object instanceof Range) {
@@ -676,8 +478,8 @@ public final class Range<C extends Comparable> implements Predicate<C>, Serializ
}
/**
- * Returns a string representation of this range, such as {@code "[3..5)"} (other examples are
- * listed in the class documentation).
+ * Returns a string representation of this range, such as {@code "[3..5)"}
+ * (other examples are listed in the class documentation).
*/
@Override public String toString() {
return toString(lowerBound, upperBound);
@@ -698,14 +500,6 @@ public final class Range<C extends Comparable> implements Predicate<C>, Serializ
return (SortedSet<T>) iterable;
}
- Object readResolve() {
- if (this.equals(ALL)) {
- return all();
- } else {
- return this;
- }
- }
-
@SuppressWarnings("unchecked") // this method may throw CCE
static int compareOrThrow(Comparable left, Comparable right) {
return left.compareTo(right);
diff --git a/guava/src/com/google/common/collect/RangeMap.java b/guava/src/com/google/common/collect/RangeMap.java
deleted file mode 100644
index ba42985..0000000
--- a/guava/src/com/google/common/collect/RangeMap.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.Beta;
-
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-/**
- * A mapping from disjoint nonempty ranges to non-null values. Queries look up the value
- * associated with the range (if any) that contains a specified key.
- *
- * <p>In contrast to {@link RangeSet}, no "coalescing" is done of {@linkplain
- * Range#isConnected(Range) connected} ranges, even if they are mapped to the same value.
- *
- * @author Louis Wasserman
- * @since 14.0
- */
-@Beta
-public interface RangeMap<K extends Comparable, V> {
- /**
- * Returns the value associated with the specified key, or {@code null} if there is no
- * such value.
- *
- * <p>Specifically, if any range in this range map contains the specified key, the value
- * associated with that range is returned.
- */
- @Nullable
- V get(K key);
-
- /**
- * Returns the range containing this key and its associated value, if such a range is present
- * in the range map, or {@code null} otherwise.
- */
- @Nullable
- Map.Entry<Range<K>, V> getEntry(K key);
-
- /**
- * Returns the minimal range {@linkplain Range#encloses(Range) enclosing} the ranges
- * in this {@code RangeMap}.
- *
- * @throws NoSuchElementException if this range map is empty
- */
- Range<K> span();
-
- /**
- * Maps a range to a specified value (optional operation).
- *
- * <p>Specifically, after a call to {@code put(range, value)}, if
- * {@link Range#contains(Comparable) range.contains(k)}, then {@link #get(Comparable) get(k)}
- * will return {@code value}.
- *
- * <p>If {@code range} {@linkplain Range#isEmpty() is empty}, then this is a no-op.
- */
- void put(Range<K> range, V value);
-
- /**
- * Puts all the associations from {@code rangeMap} into this range map (optional operation).
- */
- void putAll(RangeMap<K, V> rangeMap);
-
- /**
- * Removes all associations from this range map (optional operation).
- */
- void clear();
-
- /**
- * Removes all associations from this range map in the specified range (optional operation).
- *
- * <p>If {@code !range.contains(k)}, {@link #get(Comparable) get(k)} will return the same result
- * before and after a call to {@code remove(range)}. If {@code range.contains(k)}, then
- * after a call to {@code remove(range)}, {@code get(k)} will return {@code null}.
- */
- void remove(Range<K> range);
-
- /**
- * Returns a view of this range map as an unmodifiable {@code Map<Range<K>, V>}.
- * Modifications to this range map are guaranteed to read through to the returned {@code Map}.
- *
- * <p>It is guaranteed that no empty ranges will be in the returned {@code Map}.
- */
- Map<Range<K>, V> asMapOfRanges();
-
- /**
- * Returns a view of the part of this range map that intersects with {@code range}.
- *
- * <p>For example, if {@code rangeMap} had the entries
- * {@code [1, 5] => "foo", (6, 8) => "bar", (10, \u2025) => "baz"}
- * then {@code rangeMap.subRangeMap(Range.open(3, 12))} would return a range map
- * with the entries {@code (3, 5) => "foo", (6, 8) => "bar", (10, 12) => "baz"}.
- *
- * <p>The returned range map supports all optional operations that this range map supports,
- * except for {@code asMapOfRanges().iterator().remove()}.
- *
- * <p>The returned range map will throw an {@link IllegalArgumentException} on an attempt to
- * insert a range not {@linkplain Range#encloses(Range) enclosed} by {@code range}.
- */
- RangeMap<K, V> subRangeMap(Range<K> range);
-
- /**
- * Returns {@code true} if {@code obj} is another {@code RangeMap} that has an equivalent
- * {@link #asMapOfRanges()}.
- */
- @Override
- boolean equals(@Nullable Object o);
-
- /**
- * Returns {@code asMapOfRanges().hashCode()}.
- */
- @Override
- int hashCode();
-
- /**
- * Returns a readable string representation of this range map.
- */
- @Override
- String toString();
-}
diff --git a/guava/src/com/google/common/collect/RangeSet.java b/guava/src/com/google/common/collect/RangeSet.java
deleted file mode 100644
index f07c1fc..0000000
--- a/guava/src/com/google/common/collect/RangeSet.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2011 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.Beta;
-
-import java.util.NoSuchElementException;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-/**
- * A set comprising zero or more {@linkplain Range#isEmpty nonempty},
- * {@linkplain Range#isConnected(Range) disconnected} ranges of type {@code C}.
- *
- * <p>Implementations that choose to support the {@link #add(Range)} operation are required to
- * ignore empty ranges and coalesce connected ranges. For example: <pre> {@code
- *
- * RangeSet<Integer> rangeSet = TreeRangeSet.create();
- * rangeSet.add(Range.closed(1, 10)); // {[1, 10]}
- * rangeSet.add(Range.closedOpen(11, 15)); // {[1, 10], [11, 15)}
- * rangeSet.add(Range.open(15, 20)); // disconnected range; {[1, 10], [11, 20)}
- * rangeSet.add(Range.openClosed(0, 0)); // empty range; {[1, 10], [11, 20)}
- * rangeSet.remove(Range.open(5, 10)); // splits [1, 10]; {[1, 5], [10, 10], [11, 20)}}</pre>
- *
- * <p>Note that the behavior of {@link Range#isEmpty()} and {@link Range#isConnected(Range)} may
- * not be as expected on discrete ranges. See the Javadoc of those methods for details.
- *
- * <p>For a {@link Set} whose contents are specified by a {@link Range}, see {@link ContiguousSet}.
- *
- * @author Kevin Bourrillion
- * @author Louis Wasserman
- * @since 14.0
- */
-@Beta
-public interface RangeSet<C extends Comparable> {
-
- // Query methods
-
- /**
- * Determines whether any of this range set's member ranges contains {@code value}.
- */
- boolean contains(C value);
-
- /**
- * Returns the unique range from this range set that {@linkplain Range#contains contains}
- * {@code value}, or {@code null} if this range set does not contain {@code value}.
- */
- Range<C> rangeContaining(C value);
-
- /**
- * Returns {@code true} if there exists a member range in this range set which
- * {@linkplain Range#encloses encloses} the specified range.
- */
- boolean encloses(Range<C> otherRange);
-
- /**
- * Returns {@code true} if for each member range in {@code other} there exists a member range in
- * this range set which {@linkplain Range#encloses encloses} it. It follows that
- * {@code this.contains(value)} whenever {@code other.contains(value)}. Returns {@code true} if
- * {@code other} is empty.
- *
- * <p>This is equivalent to checking if this range set {@link #encloses} each of the ranges in
- * {@code other}.
- */
- boolean enclosesAll(RangeSet<C> other);
-
- /**
- * Returns {@code true} if this range set contains no ranges.
- */
- boolean isEmpty();
-
- /**
- * Returns the minimal range which {@linkplain Range#encloses(Range) encloses} all ranges
- * in this range set.
- *
- * @throws NoSuchElementException if this range set is {@linkplain #isEmpty() empty}
- */
- Range<C> span();
-
- // Views
-
- /**
- * Returns a view of the {@linkplain Range#isConnected disconnected} ranges that make up this
- * range set. The returned set may be empty. The iterators returned by its
- * {@link Iterable#iterator} method return the ranges in increasing order of lower bound
- * (equivalently, of upper bound).
- */
- Set<Range<C>> asRanges();
-
- /**
- * Returns a view of the complement of this {@code RangeSet}.
- *
- * <p>The returned view supports the {@link #add} operation if this {@code RangeSet} supports
- * {@link #remove}, and vice versa.
- */
- RangeSet<C> complement();
-
- /**
- * Returns a view of the intersection of this {@code RangeSet} with the specified range.
- *
- * <p>The returned view supports all optional operations supported by this {@code RangeSet}, with
- * the caveat that an {@link IllegalArgumentException} is thrown on an attempt to
- * {@linkplain #add(Range) add} any range not {@linkplain Range#encloses(Range) enclosed} by
- * {@code view}.
- */
- RangeSet<C> subRangeSet(Range<C> view);
-
- // Modification
-
- /**
- * Adds the specified range to this {@code RangeSet} (optional operation). That is, for equal
- * range sets a and b, the result of {@code a.add(range)} is that {@code a} will be the minimal
- * range set for which both {@code a.enclosesAll(b)} and {@code a.encloses(range)}.
- *
- * <p>Note that {@code range} will be {@linkplain Range#span(Range) coalesced} with any ranges in
- * the range set that are {@linkplain Range#isConnected(Range) connected} with it. Moreover,
- * if {@code range} is empty, this is a no-op.
- *
- * @throws UnsupportedOperationException if this range set does not support the {@code add}
- * operation
- */
- void add(Range<C> range);
-
- /**
- * Removes the specified range from this {@code RangeSet} (optional operation). After this
- * operation, if {@code range.contains(c)}, {@code this.contains(c)} will return {@code false}.
- *
- * <p>If {@code range} is empty, this is a no-op.
- *
- * @throws UnsupportedOperationException if this range set does not support the {@code remove}
- * operation
- */
- void remove(Range<C> range);
-
- /**
- * Removes all ranges from this {@code RangeSet} (optional operation). After this operation,
- * {@code this.contains(c)} will return false for all {@code c}.
- *
- * <p>This is equivalent to {@code remove(Range.all())}.
- *
- * @throws UnsupportedOperationException if this range set does not support the {@code clear}
- * operation
- */
- void clear();
-
- /**
- * Adds all of the ranges from the specified range set to this range set (optional operation).
- * After this operation, this range set is the minimal range set that
- * {@linkplain #enclosesAll(RangeSet) encloses} both the original range set and {@code other}.
- *
- * <p>This is equivalent to calling {@link #add} on each of the ranges in {@code other} in turn.
- *
- * @throws UnsupportedOperationException if this range set does not support the {@code addAll}
- * operation
- */
- void addAll(RangeSet<C> other);
-
- /**
- * Removes all of the ranges from the specified range set from this range set (optional
- * operation). After this operation, if {@code other.contains(c)}, {@code this.contains(c)} will
- * return {@code false}.
- *
- * <p>This is equivalent to calling {@link #remove} on each of the ranges in {@code other} in
- * turn.
- *
- * @throws UnsupportedOperationException if this range set does not support the {@code removeAll}
- * operation
- */
- void removeAll(RangeSet<C> other);
-
- // Object methods
-
- /**
- * Returns {@code true} if {@code obj} is another {@code RangeSet} that contains the same ranges
- * according to {@link Range#equals(Object)}.
- */
- @Override
- boolean equals(@Nullable Object obj);
-
- /**
- * Returns {@code asRanges().hashCode()}.
- */
- @Override
- int hashCode();
-
- /**
- * Returns a readable string representation of this range set. For example, if this
- * {@code RangeSet} consisted of {@code Ranges.closed(1, 3)} and {@code Ranges.greaterThan(4)},
- * this might return {@code " [1‥3](4‥+∞)}"}.
- */
- @Override
- String toString();
-}
diff --git a/guava/src/com/google/common/collect/Ranges.java b/guava/src/com/google/common/collect/Ranges.java
index 75cbc1e..131bf3b 100644
--- a/guava/src/com/google/common/collect/Ranges.java
+++ b/guava/src/com/google/common/collect/Ranges.java
@@ -16,9 +16,12 @@
package com.google.common.collect;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
+import java.util.Iterator;
import java.util.NoSuchElementException;
/**
@@ -59,21 +62,20 @@ import java.util.NoSuchElementException;
* <dd>{@link #upTo}
* </dl>
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/RangesExplained">
- * {@code Range}</a>.
- *
* @author Kevin Bourrillion
* @author Gregory Kick
* @since 10.0
- * @deprecated Use the corresponding method in {@link Range}.
*/
-@Deprecated
@GwtCompatible
@Beta
public final class Ranges {
private Ranges() {}
+ static <C extends Comparable<?>> Range<C> create(
+ Cut<C> lowerBound, Cut<C> upperBound) {
+ return new Range<C>(lowerBound, upperBound);
+ }
+
/**
* Returns a range that contains all values strictly greater than {@code
* lower} and strictly less than {@code upper}.
@@ -82,7 +84,7 @@ public final class Ranges {
* equal to</i> {@code upper}
*/
public static <C extends Comparable<?>> Range<C> open(C lower, C upper) {
- return Range.open(lower, upper);
+ return create(Cut.aboveValue(lower), Cut.belowValue(upper));
}
/**
@@ -93,7 +95,7 @@ public final class Ranges {
* upper}
*/
public static <C extends Comparable<?>> Range<C> closed(C lower, C upper) {
- return Range.closed(lower, upper);
+ return create(Cut.belowValue(lower), Cut.aboveValue(upper));
}
/**
@@ -105,7 +107,7 @@ public final class Ranges {
*/
public static <C extends Comparable<?>> Range<C> closedOpen(
C lower, C upper) {
- return Range.closedOpen(lower, upper);
+ return create(Cut.belowValue(lower), Cut.belowValue(upper));
}
/**
@@ -117,7 +119,7 @@ public final class Ranges {
*/
public static <C extends Comparable<?>> Range<C> openClosed(
C lower, C upper) {
- return Range.openClosed(lower, upper);
+ return create(Cut.aboveValue(lower), Cut.aboveValue(upper));
}
/**
@@ -130,7 +132,16 @@ public final class Ranges {
*/
public static <C extends Comparable<?>> Range<C> range(
C lower, BoundType lowerType, C upper, BoundType upperType) {
- return Range.range(lower, lowerType, upper, upperType);
+ checkNotNull(lowerType);
+ checkNotNull(upperType);
+
+ Cut<C> lowerBound = (lowerType == BoundType.OPEN)
+ ? Cut.aboveValue(lower)
+ : Cut.belowValue(lower);
+ Cut<C> upperBound = (upperType == BoundType.OPEN)
+ ? Cut.belowValue(upper)
+ : Cut.aboveValue(upper);
+ return create(lowerBound, upperBound);
}
/**
@@ -138,7 +149,7 @@ public final class Ranges {
* endpoint}.
*/
public static <C extends Comparable<?>> Range<C> lessThan(C endpoint) {
- return Range.lessThan(endpoint);
+ return create(Cut.<C>belowAll(), Cut.belowValue(endpoint));
}
/**
@@ -146,7 +157,7 @@ public final class Ranges {
* {@code endpoint}.
*/
public static <C extends Comparable<?>> Range<C> atMost(C endpoint) {
- return Range.atMost(endpoint);
+ return create(Cut.<C>belowAll(), Cut.aboveValue(endpoint));
}
/**
@@ -155,7 +166,14 @@ public final class Ranges {
*/
public static <C extends Comparable<?>> Range<C> upTo(
C endpoint, BoundType boundType) {
- return Range.upTo(endpoint, boundType);
+ switch (boundType) {
+ case OPEN:
+ return lessThan(endpoint);
+ case CLOSED:
+ return atMost(endpoint);
+ default:
+ throw new AssertionError();
+ }
}
/**
@@ -163,7 +181,7 @@ public final class Ranges {
* endpoint}.
*/
public static <C extends Comparable<?>> Range<C> greaterThan(C endpoint) {
- return Range.greaterThan(endpoint);
+ return create(Cut.aboveValue(endpoint), Cut.<C>aboveAll());
}
/**
@@ -171,7 +189,7 @@ public final class Ranges {
* {@code endpoint}.
*/
public static <C extends Comparable<?>> Range<C> atLeast(C endpoint) {
- return Range.atLeast(endpoint);
+ return create(Cut.belowValue(endpoint), Cut.<C>aboveAll());
}
/**
@@ -180,12 +198,19 @@ public final class Ranges {
*/
public static <C extends Comparable<?>> Range<C> downTo(
C endpoint, BoundType boundType) {
- return Range.downTo(endpoint, boundType);
+ switch (boundType) {
+ case OPEN:
+ return greaterThan(endpoint);
+ case CLOSED:
+ return atLeast(endpoint);
+ default:
+ throw new AssertionError();
+ }
}
/** Returns a range that contains every value of type {@code C}. */
public static <C extends Comparable<?>> Range<C> all() {
- return Range.all();
+ return create(Cut.<C>belowAll(), Cut.<C>aboveAll());
}
/**
@@ -194,7 +219,7 @@ public final class Ranges {
* on both ends.
*/
public static <C extends Comparable<?>> Range<C> singleton(C value) {
- return Range.singleton(value);
+ return closed(value, value);
}
/**
@@ -209,6 +234,18 @@ public final class Ranges {
*/
public static <C extends Comparable<?>> Range<C> encloseAll(
Iterable<C> values) {
- return Range.encloseAll(values);
+ checkNotNull(values);
+ if (values instanceof ContiguousSet) {
+ return ((ContiguousSet<C>) values).range();
+ }
+ Iterator<C> valueIterator = values.iterator();
+ C min = checkNotNull(valueIterator.next());
+ C max = min;
+ while (valueIterator.hasNext()) {
+ C value = checkNotNull(valueIterator.next());
+ min = Ordering.natural().min(min, value);
+ max = Ordering.natural().max(max, value);
+ }
+ return closed(min, max);
}
}
diff --git a/guava/src/com/google/common/collect/RegularContiguousSet.java b/guava/src/com/google/common/collect/RegularContiguousSet.java
index 7948fe8..10b26f9 100644
--- a/guava/src/com/google/common/collect/RegularContiguousSet.java
+++ b/guava/src/com/google/common/collect/RegularContiguousSet.java
@@ -41,38 +41,32 @@ final class RegularContiguousSet<C extends Comparable> extends ContiguousSet<C>
this.range = range;
}
- private ContiguousSet<C> intersectionInCurrentDomain(Range<C> other) {
- return (range.isConnected(other))
- ? ContiguousSet.create(range.intersection(other), domain)
- : new EmptyContiguousSet<C>(domain);
+ // Abstract method doesn't exist in GWT emulation
+ /* @Override */ ContiguousSet<C> headSetImpl(C toElement, boolean inclusive) {
+ return range.intersection(Ranges.upTo(toElement, BoundType.forBoolean(inclusive)))
+ .asSet(domain);
}
- @Override ContiguousSet<C> headSetImpl(C toElement, boolean inclusive) {
- return intersectionInCurrentDomain(Range.upTo(toElement, BoundType.forBoolean(inclusive)));
+ // Abstract method doesn't exist in GWT emulation
+ /* @Override */ int indexOf(Object target) {
+ return contains(target) ? (int) domain.distance(first(), (C) target) : -1;
}
- @Override ContiguousSet<C> subSetImpl(C fromElement, boolean fromInclusive, C toElement,
+ // Abstract method doesn't exist in GWT emulation
+ /* @Override */ ContiguousSet<C> subSetImpl(C fromElement, boolean fromInclusive, C toElement,
boolean toInclusive) {
- if (fromElement.compareTo(toElement) == 0 && !fromInclusive && !toInclusive) {
- // Range would reject our attempt to create (x, x).
- return new EmptyContiguousSet<C>(domain);
- }
- return intersectionInCurrentDomain(Range.range(
- fromElement, BoundType.forBoolean(fromInclusive),
- toElement, BoundType.forBoolean(toInclusive)));
+ return range.intersection(Ranges.range(fromElement, BoundType.forBoolean(fromInclusive),
+ toElement, BoundType.forBoolean(toInclusive))).asSet(domain);
}
- @Override ContiguousSet<C> tailSetImpl(C fromElement, boolean inclusive) {
- return intersectionInCurrentDomain(Range.downTo(fromElement, BoundType.forBoolean(inclusive)));
- }
-
- @GwtIncompatible("not used by GWT emulation")
- @Override int indexOf(Object target) {
- return contains(target) ? (int) domain.distance(first(), (C) target) : -1;
+ // Abstract method doesn't exist in GWT emulation
+ /* @Override */ ContiguousSet<C> tailSetImpl(C fromElement, boolean inclusive) {
+ return range.intersection(Ranges.downTo(fromElement, BoundType.forBoolean(inclusive)))
+ .asSet(domain);
}
@Override public UnmodifiableIterator<C> iterator() {
- return new AbstractSequentialIterator<C>(first()) {
+ return new AbstractLinkedIterator<C>(first()) {
final C last = last();
@Override
@@ -82,18 +76,6 @@ final class RegularContiguousSet<C extends Comparable> extends ContiguousSet<C>
};
}
- @GwtIncompatible("NavigableSet")
- @Override public UnmodifiableIterator<C> descendingIterator() {
- return new AbstractSequentialIterator<C>(last()) {
- final C first = first();
-
- @Override
- protected C computeNext(C previous) {
- return equalsOrThrow(previous, first) ? null : domain.previous(previous);
- }
- };
- }
-
private static boolean equalsOrThrow(Comparable<?> left, @Nullable Comparable<?> right) {
return right != null && Range.compareOrThrow(left, right) == 0;
}
@@ -115,10 +97,7 @@ final class RegularContiguousSet<C extends Comparable> extends ContiguousSet<C>
return (distance >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) distance + 1;
}
- @Override public boolean contains(@Nullable Object object) {
- if (object == null) {
- return false;
- }
+ @Override public boolean contains(Object object) {
try {
return range.contains((C) object);
} catch (ClassCastException e) {
@@ -127,7 +106,11 @@ final class RegularContiguousSet<C extends Comparable> extends ContiguousSet<C>
}
@Override public boolean containsAll(Collection<?> targets) {
- return Collections2.containsAllImpl(this, targets);
+ try {
+ return range.containsAll((Iterable<? extends C>) targets);
+ } catch (ClassCastException e) {
+ return false;
+ }
}
@Override public boolean isEmpty() {
@@ -153,7 +136,7 @@ final class RegularContiguousSet<C extends Comparable> extends ContiguousSet<C>
C lowerEndpoint = Ordering.natural().max(this.first(), other.first());
C upperEndpoint = Ordering.natural().min(this.last(), other.last());
return (lowerEndpoint.compareTo(upperEndpoint) < 0)
- ? ContiguousSet.create(Range.closed(lowerEndpoint, upperEndpoint), domain)
+ ? Ranges.closed(lowerEndpoint, upperEndpoint).asSet(domain)
: new EmptyContiguousSet<C>(domain);
}
}
@@ -163,14 +146,14 @@ final class RegularContiguousSet<C extends Comparable> extends ContiguousSet<C>
}
@Override public Range<C> range(BoundType lowerBoundType, BoundType upperBoundType) {
- return Range.create(range.lowerBound.withLowerBoundType(lowerBoundType, domain),
+ return Ranges.create(range.lowerBound.withLowerBoundType(lowerBoundType, domain),
range.upperBound.withUpperBoundType(upperBoundType, domain));
}
- @Override public boolean equals(@Nullable Object object) {
+ @Override public boolean equals(Object object) {
if (object == this) {
return true;
- } else if (object instanceof RegularContiguousSet) {
+ } else if (object instanceof RegularContiguousSet<?>) {
RegularContiguousSet<?> that = (RegularContiguousSet<?>) object;
if (this.domain.equals(that.domain)) {
return this.first().equals(that.first())
diff --git a/guava/src/com/google/common/collect/RegularImmutableAsList.java b/guava/src/com/google/common/collect/RegularImmutableAsList.java
deleted file mode 100644
index c137d6b..0000000
--- a/guava/src/com/google/common/collect/RegularImmutableAsList.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-/**
- * An {@link ImmutableAsList} implementation specialized for when the delegate collection is
- * already backed by an {@code ImmutableList} or array.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible
-@SuppressWarnings("serial") // uses writeReplace, not default serialization
-class RegularImmutableAsList<E> extends ImmutableAsList<E> {
- private final ImmutableCollection<E> delegate;
- private final ImmutableList<? extends E> delegateList;
-
- RegularImmutableAsList(ImmutableCollection<E> delegate, ImmutableList<? extends E> delegateList) {
- this.delegate = delegate;
- this.delegateList = delegateList;
- }
-
- RegularImmutableAsList(ImmutableCollection<E> delegate, Object[] array) {
- this(delegate, ImmutableList.<E>asImmutableList(array));
- }
-
- @Override
- ImmutableCollection<E> delegateCollection() {
- return delegate;
- }
-
- ImmutableList<? extends E> delegateList() {
- return delegateList;
- }
-
- @SuppressWarnings("unchecked") // safe covariant cast!
- @Override
- public UnmodifiableListIterator<E> listIterator(int index) {
- return (UnmodifiableListIterator<E>) delegateList.listIterator(index);
- }
-
- @Override
- public Object[] toArray() {
- return delegateList.toArray();
- }
-
- @Override
- public <T> T[] toArray(T[] other) {
- return delegateList.toArray(other);
- }
-
- @Override
- public int indexOf(Object object) {
- return delegateList.indexOf(object);
- }
-
- @Override
- public int lastIndexOf(Object object) {
- return delegateList.lastIndexOf(object);
- }
-
- @Override
- public boolean equals(Object obj) {
- return delegateList.equals(obj);
- }
-
- @Override
- public int hashCode() {
- return delegateList.hashCode();
- }
-
- @Override
- public E get(int index) {
- return delegateList.get(index);
- }
-}
diff --git a/guava/src/com/google/common/collect/RegularImmutableBiMap.java b/guava/src/com/google/common/collect/RegularImmutableBiMap.java
index b67aa76..dca1f05 100644
--- a/guava/src/com/google/common/collect/RegularImmutableBiMap.java
+++ b/guava/src/com/google/common/collect/RegularImmutableBiMap.java
@@ -16,283 +16,45 @@
package com.google.common.collect;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.annotations.GwtCompatible;
-import java.io.Serializable;
-import java.util.Collection;
-
-import javax.annotation.Nullable;
-
/**
- * Bimap with two or more mappings.
- *
- * @author Louis Wasserman
+ * Bimap with one or more mappings.
+ *
+ * @author Jared Levy
*/
@GwtCompatible(serializable = true, emulated = true)
@SuppressWarnings("serial") // uses writeReplace(), not default serialization
class RegularImmutableBiMap<K, V> extends ImmutableBiMap<K, V> {
- private static class BiMapEntry<K, V> extends ImmutableEntry<K, V> {
- BiMapEntry(K key, V value) {
- super(key, value);
- }
-
- @Nullable
- BiMapEntry<K, V> getNextInKToVBucket() {
- return null;
- }
-
- @Nullable
- BiMapEntry<K, V> getNextInVToKBucket() {
- return null;
- }
- }
-
- private static class NonTerminalBiMapEntry<K, V> extends BiMapEntry<K, V> {
- @Nullable private final BiMapEntry<K, V> nextInKToVBucket;
- @Nullable private final BiMapEntry<K, V> nextInVToKBucket;
-
- NonTerminalBiMapEntry(K key, V value, @Nullable BiMapEntry<K, V> nextInKToVBucket,
- @Nullable BiMapEntry<K, V> nextInVToKBucket) {
- super(key, value);
- this.nextInKToVBucket = nextInKToVBucket;
- this.nextInVToKBucket = nextInVToKBucket;
- }
+ final transient ImmutableMap<K, V> delegate;
+ final transient ImmutableBiMap<V, K> inverse;
- @Override
- @Nullable
- BiMapEntry<K, V> getNextInKToVBucket() {
- return nextInKToVBucket;
- }
-
- @Override
- @Nullable
- BiMapEntry<K, V> getNextInVToKBucket() {
- return nextInVToKBucket;
- }
- }
-
- static final double MAX_LOAD_FACTOR = 1.2;
-
- private transient final BiMapEntry<K, V>[] kToVTable;
- private transient final BiMapEntry<K, V>[] vToKTable;
- private transient final BiMapEntry<K, V>[] entries;
- private transient final int mask;
- private transient final int hashCode;
-
- RegularImmutableBiMap(Collection<? extends Entry<? extends K, ? extends V>> entriesToAdd) {
- int n = entriesToAdd.size();
- int tableSize = Hashing.closedTableSize(n, MAX_LOAD_FACTOR);
- this.mask = tableSize - 1;
- BiMapEntry<K, V>[] kToVTable = createEntryArray(tableSize);
- BiMapEntry<K, V>[] vToKTable = createEntryArray(tableSize);
- BiMapEntry<K, V>[] entries = createEntryArray(n);
- int i = 0;
- int hashCode = 0;
-
- for (Entry<? extends K, ? extends V> entry : entriesToAdd) {
- K key = checkNotNull(entry.getKey());
- V value = checkNotNull(entry.getValue());
-
- int keyHash = key.hashCode();
- int valueHash = value.hashCode();
- int keyBucket = Hashing.smear(keyHash) & mask;
- int valueBucket = Hashing.smear(valueHash) & mask;
-
- BiMapEntry<K, V> nextInKToVBucket = kToVTable[keyBucket];
- for (BiMapEntry<K, V> kToVEntry = nextInKToVBucket; kToVEntry != null;
- kToVEntry = kToVEntry.getNextInKToVBucket()) {
- if (key.equals(kToVEntry.getKey())) {
- throw new IllegalArgumentException("Multiple entries with same key: " +
- entry + " and " + kToVEntry);
- }
- }
- BiMapEntry<K, V> nextInVToKBucket = vToKTable[valueBucket];
- for (BiMapEntry<K, V> vToKEntry = nextInVToKBucket; vToKEntry != null;
- vToKEntry = vToKEntry.getNextInVToKBucket()) {
- if (value.equals(vToKEntry.getValue())) {
- throw new IllegalArgumentException("Multiple entries with same value: "
- + entry + " and " + vToKEntry);
- }
- }
- BiMapEntry<K, V> newEntry =
- (nextInKToVBucket == null && nextInVToKBucket == null)
- ? new BiMapEntry<K, V>(key, value)
- : new NonTerminalBiMapEntry<K, V>(key, value, nextInKToVBucket, nextInVToKBucket);
- kToVTable[keyBucket] = newEntry;
- vToKTable[valueBucket] = newEntry;
- entries[i++] = newEntry;
- hashCode += keyHash ^ valueHash;
- }
-
- this.kToVTable = kToVTable;
- this.vToKTable = vToKTable;
- this.entries = entries;
- this.hashCode = hashCode;
- }
-
- @SuppressWarnings("unchecked")
- private static <K, V> BiMapEntry<K, V>[] createEntryArray(int length) {
- return new BiMapEntry[length];
- }
+ RegularImmutableBiMap(ImmutableMap<K, V> delegate) {
+ this.delegate = delegate;
- @Override
- @Nullable
- public V get(@Nullable Object key) {
- if (key == null) {
- return null;
- }
- int bucket = Hashing.smear(key.hashCode()) & mask;
- for (BiMapEntry<K, V> entry = kToVTable[bucket]; entry != null;
- entry = entry.getNextInKToVBucket()) {
- if (key.equals(entry.getKey())) {
- return entry.getValue();
- }
+ ImmutableMap.Builder<V, K> builder = ImmutableMap.builder();
+ for (Entry<K, V> entry : delegate.entrySet()) {
+ builder.put(entry.getValue(), entry.getKey());
}
- return null;
- }
-
- @Override
- ImmutableSet<Entry<K, V>> createEntrySet() {
- return new ImmutableMapEntrySet<K, V>() {
- @Override
- ImmutableMap<K, V> map() {
- return RegularImmutableBiMap.this;
- }
-
- @Override
- public UnmodifiableIterator<Entry<K, V>> iterator() {
- return asList().iterator();
- }
-
- @Override
- ImmutableList<Entry<K, V>> createAsList() {
- return new RegularImmutableAsList<Entry<K, V>>(this, entries);
- }
-
- @Override
- boolean isHashCodeFast() {
- return true;
- }
-
- @Override
- public int hashCode() {
- return hashCode;
- }
- };
+ ImmutableMap<V, K> backwardMap = builder.build();
+ this.inverse = new RegularImmutableBiMap<V, K>(backwardMap, this);
}
- @Override
- boolean isPartialView() {
- return false;
+ RegularImmutableBiMap(ImmutableMap<K, V> delegate,
+ ImmutableBiMap<V, K> inverse) {
+ this.delegate = delegate;
+ this.inverse = inverse;
}
- @Override
- public int size() {
- return entries.length;
+ @Override ImmutableMap<K, V> delegate() {
+ return delegate;
}
-
- private transient ImmutableBiMap<V, K> inverse;
- @Override
- public ImmutableBiMap<V, K> inverse() {
- ImmutableBiMap<V, K> result = inverse;
- return (result == null) ? inverse = new Inverse() : result;
+ @Override public ImmutableBiMap<V, K> inverse() {
+ return inverse;
}
-
- private final class Inverse extends ImmutableBiMap<V, K> {
-
- @Override
- public int size() {
- return inverse().size();
- }
-
- @Override
- public ImmutableBiMap<K, V> inverse() {
- return RegularImmutableBiMap.this;
- }
-
- @Override
- public K get(@Nullable Object value) {
- if (value == null) {
- return null;
- }
- int bucket = Hashing.smear(value.hashCode()) & mask;
- for (BiMapEntry<K, V> entry = vToKTable[bucket]; entry != null;
- entry = entry.getNextInVToKBucket()) {
- if (value.equals(entry.getValue())) {
- return entry.getKey();
- }
- }
- return null;
- }
-
- @Override
- ImmutableSet<Entry<V, K>> createEntrySet() {
- return new InverseEntrySet();
- }
-
- final class InverseEntrySet extends ImmutableMapEntrySet<V, K> {
- @Override
- ImmutableMap<V, K> map() {
- return Inverse.this;
- }
- @Override
- boolean isHashCodeFast() {
- return true;
- }
-
- @Override
- public int hashCode() {
- return hashCode;
- }
-
- @Override
- public UnmodifiableIterator<Entry<V, K>> iterator() {
- return asList().iterator();
- }
-
- @Override
- ImmutableList<Entry<V, K>> createAsList() {
- return new ImmutableAsList<Entry<V, K>>() {
- @Override
- public Entry<V, K> get(int index) {
- Entry<K, V> entry = entries[index];
- return Maps.immutableEntry(entry.getValue(), entry.getKey());
- }
-
- @Override
- ImmutableCollection<Entry<V, K>> delegateCollection() {
- return InverseEntrySet.this;
- }
- };
- }
- }
-
- @Override
- boolean isPartialView() {
- return false;
- }
-
- @Override
- Object writeReplace() {
- return new InverseSerializedForm<K, V>(RegularImmutableBiMap.this);
- }
- }
-
- private static class InverseSerializedForm<K, V> implements Serializable {
- private final ImmutableBiMap<K, V> forward;
-
- InverseSerializedForm(ImmutableBiMap<K, V> forward) {
- this.forward = forward;
- }
-
- Object readResolve() {
- return forward.inverse();
- }
-
- private static final long serialVersionUID = 1;
+ @Override boolean isPartialView() {
+ return delegate.isPartialView() || inverse.delegate().isPartialView();
}
}
diff --git a/guava/src/com/google/common/collect/RegularImmutableList.java b/guava/src/com/google/common/collect/RegularImmutableList.java
index 4314b6e..27f47f5 100644
--- a/guava/src/com/google/common/collect/RegularImmutableList.java
+++ b/guava/src/com/google/common/collect/RegularImmutableList.java
@@ -58,6 +58,16 @@ class RegularImmutableList<E> extends ImmutableList<E> {
return offset != 0 || size != array.length;
}
+ @Override public boolean contains(@Nullable Object target) {
+ return indexOf(target) != -1;
+ }
+
+ // The fake cast to E is safe because the creation methods only allow E's
+ @SuppressWarnings("unchecked")
+ @Override public UnmodifiableIterator<E> iterator() {
+ return (UnmodifiableIterator<E>) Iterators.forArray(array, offset, size);
+ }
+
@Override public Object[] toArray() {
Object[] newArray = new Object[size()];
System.arraycopy(array, offset, newArray, 0, size);
@@ -82,19 +92,45 @@ class RegularImmutableList<E> extends ImmutableList<E> {
return (E) array[index + offset];
}
- @Override
- ImmutableList<E> subListUnchecked(int fromIndex, int toIndex) {
- return new RegularImmutableList<E>(
- array, offset + fromIndex, toIndex - fromIndex);
+ @Override public int indexOf(@Nullable Object target) {
+ if (target != null) {
+ for (int i = offset; i < offset + size; i++) {
+ if (array[i].equals(target)) {
+ return i - offset;
+ }
+ }
+ }
+ return -1;
}
- @SuppressWarnings("unchecked")
- @Override
- public UnmodifiableListIterator<E> listIterator(int index) {
- // for performance
- // The fake cast to E is safe because the creation methods only allow E's
- return (UnmodifiableListIterator<E>)
- Iterators.forArray(array, offset, size, index);
+ @Override public int lastIndexOf(@Nullable Object target) {
+ if (target != null) {
+ for (int i = offset + size - 1; i >= offset; i--) {
+ if (array[i].equals(target)) {
+ return i - offset;
+ }
+ }
+ }
+ return -1;
+ }
+
+ @Override public ImmutableList<E> subList(int fromIndex, int toIndex) {
+ Preconditions.checkPositionIndexes(fromIndex, toIndex, size);
+ return (fromIndex == toIndex)
+ ? ImmutableList.<E>of()
+ : new RegularImmutableList<E>(
+ array, offset + fromIndex, toIndex - fromIndex);
+ }
+
+ @Override public UnmodifiableListIterator<E> listIterator(final int start) {
+ return new AbstractIndexedListIterator<E>(size, start) {
+ // The fake cast to E is safe because the creation methods only allow E's
+ @SuppressWarnings("unchecked")
+ @Override protected E get(int index) {
+ return (E) array[index + offset];
+ }
+
+ };
}
@Override public boolean equals(@Nullable Object object) {
@@ -128,6 +164,16 @@ class RegularImmutableList<E> extends ImmutableList<E> {
return true;
}
+ @Override public int hashCode() {
+ // not caching hash code since it could change if the elements are mutable
+ // in a way that modifies their hash codes
+ int hashCode = 1;
+ for (int i = offset; i < offset + size; i++) {
+ hashCode = 31 * hashCode + array[i].hashCode();
+ }
+ return hashCode;
+ }
+
@Override public String toString() {
StringBuilder sb = Collections2.newStringBuilderForCollection(size())
.append('[').append(array[offset]);
diff --git a/guava/src/com/google/common/collect/RegularImmutableMap.java b/guava/src/com/google/common/collect/RegularImmutableMap.java
index 6d9be99..e2b7150 100644
--- a/guava/src/com/google/common/collect/RegularImmutableMap.java
+++ b/guava/src/com/google/common/collect/RegularImmutableMap.java
@@ -19,6 +19,8 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.annotations.GwtCompatible;
+import com.google.common.collect.ImmutableSet.ArrayImmutableSet;
+import com.google.common.collect.ImmutableSet.TransformedImmutableSet;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@@ -39,6 +41,7 @@ final class RegularImmutableMap<K, V> extends ImmutableMap<K, V> {
private final transient LinkedEntry<K, V>[] table;
// 'and' with an int to get a table index
private final transient int mask;
+ private final transient int keySetHashCode;
// TODO(gak): investigate avoiding the creation of ImmutableEntries since we
// re-copy them anyway.
@@ -46,16 +49,18 @@ final class RegularImmutableMap<K, V> extends ImmutableMap<K, V> {
int size = immutableEntries.length;
entries = createEntryArray(size);
- int tableSize = Hashing.closedTableSize(size, MAX_LOAD_FACTOR);
+ int tableSize = chooseTableSize(size);
table = createEntryArray(tableSize);
mask = tableSize - 1;
+ int keySetHashCodeMutable = 0;
for (int entryIndex = 0; entryIndex < size; entryIndex++) {
// each of our 6 callers carefully put only Entry<K, V>s into the array!
@SuppressWarnings("unchecked")
Entry<K, V> entry = (Entry<K, V>) immutableEntries[entryIndex];
K key = entry.getKey();
int keyHashCode = key.hashCode();
+ keySetHashCodeMutable += keyHashCode;
int tableIndex = Hashing.smear(keyHashCode) & mask;
@Nullable LinkedEntry<K, V> existing = table[tableIndex];
// prepend, not append, so the entries can be immutable
@@ -68,14 +73,15 @@ final class RegularImmutableMap<K, V> extends ImmutableMap<K, V> {
existing = existing.next();
}
}
+ keySetHashCode = keySetHashCodeMutable;
}
- /**
- * Closed addressing tends to perform well even with high load factors.
- * Being conservative here ensures that the table is still likely to be
- * relatively sparse (hence it misses fast) while saving space.
- */
- private static final double MAX_LOAD_FACTOR = 1.2;
+ private static int chooseTableSize(int size) {
+ // least power of 2 greater than size
+ int tableSize = Integer.highestOneBit(size) << 1;
+ checkArgument(tableSize > 0, "table too large: %s", size);
+ return tableSize;
+ }
/**
* Creates a {@link LinkedEntry} array to hold parameterized entries. The
@@ -160,31 +166,125 @@ final class RegularImmutableMap<K, V> extends ImmutableMap<K, V> {
public int size() {
return entries.length;
}
-
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public boolean containsValue(@Nullable Object value) {
+ if (value == null) {
+ return false;
+ }
+ for (Entry<K, V> entry : entries) {
+ if (entry.getValue().equals(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override boolean isPartialView() {
return false;
}
- @Override
- ImmutableSet<Entry<K, V>> createEntrySet() {
- return new EntrySet();
+ private transient ImmutableSet<Entry<K, V>> entrySet;
+
+ @Override public ImmutableSet<Entry<K, V>> entrySet() {
+ ImmutableSet<Entry<K, V>> es = entrySet;
+ return (es == null) ? (entrySet = new EntrySet<K, V>(this)) : es;
}
@SuppressWarnings("serial") // uses writeReplace(), not default serialization
- private class EntrySet extends ImmutableMapEntrySet<K, V> {
- @Override ImmutableMap<K, V> map() {
- return RegularImmutableMap.this;
+ private static class EntrySet<K, V> extends ArrayImmutableSet<Entry<K, V>> {
+ final transient RegularImmutableMap<K, V> map;
+
+ EntrySet(RegularImmutableMap<K, V> map) {
+ super(map.entries);
+ this.map = map;
}
- @Override
- public UnmodifiableIterator<Entry<K, V>> iterator() {
- return asList().iterator();
+ @Override public boolean contains(Object target) {
+ if (target instanceof Entry) {
+ Entry<?, ?> entry = (Entry<?, ?>) target;
+ V mappedValue = map.get(entry.getKey());
+ return mappedValue != null && mappedValue.equals(entry.getValue());
+ }
+ return false;
+ }
+ }
+
+ private transient ImmutableSet<K> keySet;
+
+ @Override public ImmutableSet<K> keySet() {
+ ImmutableSet<K> ks = keySet;
+ return (ks == null) ? (keySet = new KeySet<K, V>(this)) : ks;
+ }
+
+ @SuppressWarnings("serial") // uses writeReplace(), not default serialization
+ private static class KeySet<K, V>
+ extends TransformedImmutableSet<Entry<K, V>, K> {
+ final RegularImmutableMap<K, V> map;
+
+ KeySet(RegularImmutableMap<K, V> map) {
+ super(map.entries, map.keySetHashCode);
+ this.map = map;
+ }
+
+ @Override K transform(Entry<K, V> element) {
+ return element.getKey();
+ }
+
+ @Override public boolean contains(Object target) {
+ return map.containsKey(target);
+ }
+
+ @Override boolean isPartialView() {
+ return true;
+ }
+ }
+
+ private transient ImmutableCollection<V> values;
+
+ @Override public ImmutableCollection<V> values() {
+ ImmutableCollection<V> v = values;
+ return (v == null) ? (values = new Values<V>(this)) : v;
+ }
+
+ @SuppressWarnings("serial") // uses writeReplace(), not default serialization
+ private static class Values<V> extends ImmutableCollection<V> {
+ final RegularImmutableMap<?, V> map;
+
+ Values(RegularImmutableMap<?, V> map) {
+ this.map = map;
}
@Override
- ImmutableList<Entry<K, V>> createAsList() {
- return new RegularImmutableAsList<Entry<K, V>>(this, entries);
+ public int size() {
+ return map.entries.length;
+ }
+
+ @Override public UnmodifiableIterator<V> iterator() {
+ return new AbstractIndexedListIterator<V>(map.entries.length) {
+ @Override protected V get(int index) {
+ return map.entries[index].getValue();
+ }
+ };
}
+
+ @Override public boolean contains(Object target) {
+ return map.containsValue(target);
+ }
+
+ @Override boolean isPartialView() {
+ return true;
+ }
+ }
+
+ @Override public String toString() {
+ StringBuilder result
+ = Collections2.newStringBuilderForCollection(size()).append('{');
+ Collections2.STANDARD_JOINER.appendTo(result, entries);
+ return result.append('}').toString();
}
// This class is never actually serialized directly, but we have to make the
diff --git a/guava/src/com/google/common/collect/RegularImmutableMultiset.java b/guava/src/com/google/common/collect/RegularImmutableMultiset.java
index e46f424..090c091 100644
--- a/guava/src/com/google/common/collect/RegularImmutableMultiset.java
+++ b/guava/src/com/google/common/collect/RegularImmutableMultiset.java
@@ -18,13 +18,14 @@ package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
+import java.util.Iterator;
import java.util.Map;
import javax.annotation.Nullable;
/**
* Implementation of {@link ImmutableMultiset} with one or more elements.
- *
+ *
* @author Jared Levy
* @author Louis Wasserman
*/
@@ -66,45 +67,31 @@ class RegularImmutableMultiset<E> extends ImmutableMultiset<E> {
return map.keySet();
}
- private static <E> Entry<E> entryFromMapEntry(Map.Entry<E, Integer> entry) {
- return Multisets.immutableEntry(entry.getKey(), entry.getValue());
- }
-
@Override
- ImmutableSet<Entry<E>> createEntrySet() {
- return new EntrySet();
- }
-
- private class EntrySet extends ImmutableMultiset<E>.EntrySet {
- @Override
- public int size() {
- return map.size();
- }
-
- @Override
- public UnmodifiableIterator<Entry<E>> iterator() {
- return asList().iterator();
- }
-
- @Override
- ImmutableList<Entry<E>> createAsList() {
- final ImmutableList<Map.Entry<E, Integer>> entryList = map.entrySet().asList();
- return new ImmutableAsList<Entry<E>>() {
- @Override
- public Entry<E> get(int index) {
- return entryFromMapEntry(entryList.get(index));
- }
-
- @Override
- ImmutableCollection<Entry<E>> delegateCollection() {
- return EntrySet.this;
- }
- };
- }
+ UnmodifiableIterator<Entry<E>> entryIterator() {
+ final Iterator<Map.Entry<E, Integer>> mapIterator =
+ map.entrySet().iterator();
+ return new UnmodifiableIterator<Entry<E>>() {
+ @Override
+ public boolean hasNext() {
+ return mapIterator.hasNext();
+ }
+
+ @Override
+ public Entry<E> next() {
+ Map.Entry<E, Integer> mapEntry = mapIterator.next();
+ return Multisets.immutableEntry(mapEntry.getKey(), mapEntry.getValue());
+ }
+ };
}
@Override
public int hashCode() {
return map.hashCode();
}
+
+ @Override
+ int distinctElements() {
+ return map.size();
+ }
}
diff --git a/guava/src/com/google/common/collect/RegularImmutableSortedMap.java b/guava/src/com/google/common/collect/RegularImmutableSortedMap.java
deleted file mode 100644
index dd93b7f..0000000
--- a/guava/src/com/google/common/collect/RegularImmutableSortedMap.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.GwtCompatible;
-
-import javax.annotation.Nullable;
-
-/**
- * An implementation of an immutable sorted map with one or more entries.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible(emulated = true)
-@SuppressWarnings("serial") // uses writeReplace, not default serialization
-final class RegularImmutableSortedMap<K, V> extends ImmutableSortedMap<K, V> {
- private final transient RegularImmutableSortedSet<K> keySet;
- private final transient ImmutableList<V> valueList;
-
- RegularImmutableSortedMap(RegularImmutableSortedSet<K> keySet, ImmutableList<V> valueList) {
- this.keySet = keySet;
- this.valueList = valueList;
- }
-
- RegularImmutableSortedMap(
- RegularImmutableSortedSet<K> keySet,
- ImmutableList<V> valueList,
- ImmutableSortedMap<K, V> descendingMap) {
- super(descendingMap);
- this.keySet = keySet;
- this.valueList = valueList;
- }
-
- @Override
- ImmutableSet<Entry<K, V>> createEntrySet() {
- return new EntrySet();
- }
-
- private class EntrySet extends ImmutableMapEntrySet<K, V> {
- @Override
- public UnmodifiableIterator<Entry<K, V>> iterator() {
- return asList().iterator();
- }
-
- @Override
- ImmutableList<Entry<K, V>> createAsList() {
- return new ImmutableAsList<Entry<K, V>>() {
- // avoid additional indirection
- private final ImmutableList<K> keyList = keySet().asList();
-
- @Override
- public Entry<K, V> get(int index) {
- return Maps.immutableEntry(keyList.get(index), valueList.get(index));
- }
-
- @Override
- ImmutableCollection<Entry<K, V>> delegateCollection() {
- return EntrySet.this;
- }
- };
- }
-
- @Override
- ImmutableMap<K, V> map() {
- return RegularImmutableSortedMap.this;
- }
- }
-
- @Override
- public ImmutableSortedSet<K> keySet() {
- return keySet;
- }
-
- @Override
- public ImmutableCollection<V> values() {
- return valueList;
- }
-
- @Override
- public V get(@Nullable Object key) {
- int index = keySet.indexOf(key);
- return (index == -1) ? null : valueList.get(index);
- }
-
- private ImmutableSortedMap<K, V> getSubMap(int fromIndex, int toIndex) {
- if (fromIndex == 0 && toIndex == size()) {
- return this;
- } else if (fromIndex == toIndex) {
- return emptyMap(comparator());
- } else {
- return from(
- keySet.getSubSet(fromIndex, toIndex),
- valueList.subList(fromIndex, toIndex));
- }
- }
-
- @Override
- public ImmutableSortedMap<K, V> headMap(K toKey, boolean inclusive) {
- return getSubMap(0, keySet.headIndex(checkNotNull(toKey), inclusive));
- }
-
- @Override
- public ImmutableSortedMap<K, V> tailMap(K fromKey, boolean inclusive) {
- return getSubMap(keySet.tailIndex(checkNotNull(fromKey), inclusive), size());
- }
-
- @Override
- ImmutableSortedMap<K, V> createDescendingMap() {
- return new RegularImmutableSortedMap<K, V>(
- (RegularImmutableSortedSet<K>) keySet.descendingSet(),
- valueList.reverse(),
- this);
- }
-
-}
diff --git a/guava/src/com/google/common/collect/RegularImmutableSortedMultiset.java b/guava/src/com/google/common/collect/RegularImmutableSortedMultiset.java
index 3db3405..7318d9b 100644
--- a/guava/src/com/google/common/collect/RegularImmutableSortedMultiset.java
+++ b/guava/src/com/google/common/collect/RegularImmutableSortedMultiset.java
@@ -15,11 +15,16 @@
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkPositionIndexes;
-import static com.google.common.collect.BoundType.CLOSED;
+import static com.google.common.collect.SortedLists.KeyAbsentBehavior.INVERTED_INSERTION_INDEX;
+import static com.google.common.collect.SortedLists.KeyAbsentBehavior.NEXT_HIGHER;
+import static com.google.common.collect.SortedLists.KeyAbsentBehavior.NEXT_LOWER;
+import static com.google.common.collect.SortedLists.KeyPresentBehavior.ANY_PRESENT;
import com.google.common.primitives.Ints;
+import java.util.Comparator;
+import java.util.List;
+
import javax.annotation.Nullable;
/**
@@ -27,119 +32,167 @@ import javax.annotation.Nullable;
*
* @author Louis Wasserman
*/
-@SuppressWarnings("serial") // uses writeReplace, not default serialization
final class RegularImmutableSortedMultiset<E> extends ImmutableSortedMultiset<E> {
- private final transient RegularImmutableSortedSet<E> elementSet;
- private final transient int[] counts;
- private final transient long[] cumulativeCounts;
- private final transient int offset;
- private final transient int length;
+ private static final class CumulativeCountEntry<E> extends Multisets.AbstractEntry<E> {
+ final E element;
+ final int count;
+ final long cumulativeCount;
+
+ CumulativeCountEntry(E element, int count, @Nullable CumulativeCountEntry<E> previous) {
+ this.element = element;
+ this.count = count;
+ this.cumulativeCount = count + ((previous == null) ? 0 : previous.cumulativeCount);
+ }
+
+ @Override
+ public E getElement() {
+ return element;
+ }
+
+ @Override
+ public int getCount() {
+ return count;
+ }
+ }
+
+ static <E> RegularImmutableSortedMultiset<E> createFromSorted(Comparator<? super E> comparator,
+ List<? extends Multiset.Entry<E>> entries) {
+ List<CumulativeCountEntry<E>> newEntries = Lists.newArrayListWithCapacity(entries.size());
+ CumulativeCountEntry<E> previous = null;
+ for (Multiset.Entry<E> entry : entries) {
+ newEntries.add(
+ previous = new CumulativeCountEntry<E>(entry.getElement(), entry.getCount(), previous));
+ }
+ return new RegularImmutableSortedMultiset<E>(comparator, ImmutableList.copyOf(newEntries));
+ }
+
+ final transient ImmutableList<CumulativeCountEntry<E>> entries;
RegularImmutableSortedMultiset(
- RegularImmutableSortedSet<E> elementSet,
- int[] counts,
- long[] cumulativeCounts,
- int offset,
- int length) {
- this.elementSet = elementSet;
- this.counts = counts;
- this.cumulativeCounts = cumulativeCounts;
- this.offset = offset;
- this.length = length;
+ Comparator<? super E> comparator, ImmutableList<CumulativeCountEntry<E>> entries) {
+ super(comparator);
+ this.entries = entries;
+ assert !entries.isEmpty();
}
- private Entry<E> getEntry(int index) {
- return Multisets.immutableEntry(
- elementSet.asList().get(index),
- counts[offset + index]);
+ ImmutableList<E> elementList() {
+ return new TransformedImmutableList<CumulativeCountEntry<E>, E>(entries) {
+ @Override
+ E transform(CumulativeCountEntry<E> entry) {
+ return entry.getElement();
+ }
+ };
}
@Override
- public Entry<E> firstEntry() {
- return getEntry(0);
+ ImmutableSortedSet<E> createElementSet() {
+ return new RegularImmutableSortedSet<E>(elementList(), comparator());
}
@Override
- public Entry<E> lastEntry() {
- return getEntry(length - 1);
+ ImmutableSortedSet<E> createDescendingElementSet() {
+ return new RegularImmutableSortedSet<E>(elementList().reverse(), reverseComparator());
}
+ @SuppressWarnings("unchecked")
@Override
- public int count(@Nullable Object element) {
- int index = elementSet.indexOf(element);
- return (index == -1) ? 0 : counts[index + offset];
+ UnmodifiableIterator<Multiset.Entry<E>> entryIterator() {
+ return (UnmodifiableIterator) entries.iterator();
}
+ @SuppressWarnings("unchecked")
@Override
- public int size() {
- long size = cumulativeCounts[offset + length] - cumulativeCounts[offset];
- return Ints.saturatedCast(size);
+ UnmodifiableIterator<Multiset.Entry<E>> descendingEntryIterator() {
+ return (UnmodifiableIterator) entries.reverse().iterator();
}
@Override
- public ImmutableSortedSet<E> elementSet() {
- return elementSet;
+ public CumulativeCountEntry<E> firstEntry() {
+ return entries.get(0);
}
@Override
- public ImmutableSortedMultiset<E> headMultiset(E upperBound, BoundType boundType) {
- return getSubMultiset(0, elementSet.headIndex(upperBound, checkNotNull(boundType) == CLOSED));
+ public CumulativeCountEntry<E> lastEntry() {
+ return entries.get(entries.size() - 1);
}
@Override
- public ImmutableSortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType) {
- return getSubMultiset(elementSet.tailIndex(lowerBound, checkNotNull(boundType) == CLOSED),
- length);
+ public int size() {
+ CumulativeCountEntry<E> firstEntry = firstEntry();
+ CumulativeCountEntry<E> lastEntry = lastEntry();
+ return Ints.saturatedCast(
+ lastEntry.cumulativeCount - firstEntry.cumulativeCount + firstEntry.count);
}
- ImmutableSortedMultiset<E> getSubMultiset(int from, int to) {
- checkPositionIndexes(from, to, length);
- if (from == to) {
- return emptyMultiset(comparator());
- } else if (from == 0 && to == length) {
- return this;
- } else {
- RegularImmutableSortedSet<E> subElementSet =
- (RegularImmutableSortedSet<E>) elementSet.getSubSet(from, to);
- return new RegularImmutableSortedMultiset<E>(
- subElementSet, counts, cumulativeCounts, offset + from, to - from);
- }
+ @Override
+ int distinctElements() {
+ return entries.size();
}
@Override
- ImmutableSet<Entry<E>> createEntrySet() {
- return new EntrySet();
+ boolean isPartialView() {
+ return entries.isPartialView();
}
- private final class EntrySet extends ImmutableMultiset<E>.EntrySet {
- @Override
- public int size() {
- return length;
+ @SuppressWarnings("unchecked")
+ @Override
+ public int count(@Nullable Object element) {
+ if (element == null) {
+ return 0;
}
-
- @Override
- public UnmodifiableIterator<Entry<E>> iterator() {
- return asList().iterator();
+ try {
+ int index = SortedLists.binarySearch(
+ elementList(), (E) element, comparator(), ANY_PRESENT, INVERTED_INSERTION_INDEX);
+ return (index >= 0) ? entries.get(index).getCount() : 0;
+ } catch (ClassCastException e) {
+ return 0;
}
+ }
- @Override
- ImmutableList<Entry<E>> createAsList() {
- return new ImmutableAsList<Entry<E>>() {
- @Override
- public Entry<E> get(int index) {
- return getEntry(index);
- }
-
- @Override
- ImmutableCollection<Entry<E>> delegateCollection() {
- return EntrySet.this;
- }
- };
+ @Override
+ public ImmutableSortedMultiset<E> headMultiset(E upperBound, BoundType boundType) {
+ int index;
+ switch (boundType) {
+ case OPEN:
+ index = SortedLists.binarySearch(
+ elementList(), checkNotNull(upperBound), comparator(), ANY_PRESENT, NEXT_HIGHER);
+ break;
+ case CLOSED:
+ index = SortedLists.binarySearch(
+ elementList(), checkNotNull(upperBound), comparator(), ANY_PRESENT, NEXT_LOWER) + 1;
+ break;
+ default:
+ throw new AssertionError();
}
+ return createSubMultiset(0, index);
}
@Override
- boolean isPartialView() {
- return offset > 0 || length < counts.length;
+ public ImmutableSortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType) {
+ int index;
+ switch (boundType) {
+ case OPEN:
+ index = SortedLists.binarySearch(
+ elementList(), checkNotNull(lowerBound), comparator(), ANY_PRESENT, NEXT_LOWER) + 1;
+ break;
+ case CLOSED:
+ index = SortedLists.binarySearch(
+ elementList(), checkNotNull(lowerBound), comparator(), ANY_PRESENT, NEXT_HIGHER);
+ break;
+ default:
+ throw new AssertionError();
+ }
+ return createSubMultiset(index, distinctElements());
+ }
+
+ private ImmutableSortedMultiset<E> createSubMultiset(int newFromIndex, int newToIndex) {
+ if (newFromIndex == 0 && newToIndex == entries.size()) {
+ return this;
+ } else if (newFromIndex >= newToIndex) {
+ return emptyMultiset(comparator());
+ } else {
+ return new RegularImmutableSortedMultiset<E>(
+ comparator(), entries.subList(newFromIndex, newToIndex));
+ }
}
}
diff --git a/guava/src/com/google/common/collect/RegularImmutableSortedSet.java b/guava/src/com/google/common/collect/RegularImmutableSortedSet.java
index 9dc2e5c..3d2b7e0 100644
--- a/guava/src/com/google/common/collect/RegularImmutableSortedSet.java
+++ b/guava/src/com/google/common/collect/RegularImmutableSortedSet.java
@@ -25,7 +25,6 @@ import static com.google.common.collect.SortedLists.KeyPresentBehavior.FIRST_AFT
import static com.google.common.collect.SortedLists.KeyPresentBehavior.FIRST_PRESENT;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
import java.util.Collection;
import java.util.Collections;
@@ -60,11 +59,6 @@ final class RegularImmutableSortedSet<E> extends ImmutableSortedSet<E> {
return elements.iterator();
}
- @GwtIncompatible("NavigableSet")
- @Override public UnmodifiableIterator<E> descendingIterator() {
- return elements.reverse().iterator();
- }
-
@Override public boolean isEmpty() {
return false;
}
@@ -75,8 +69,11 @@ final class RegularImmutableSortedSet<E> extends ImmutableSortedSet<E> {
}
@Override public boolean contains(Object o) {
+ if (o == null) {
+ return false;
+ }
try {
- return o != null && unsafeBinarySearch(o) >= 0;
+ return binarySearch(o) >= 0;
} catch (ClassCastException e) {
return false;
}
@@ -87,7 +84,7 @@ final class RegularImmutableSortedSet<E> extends ImmutableSortedSet<E> {
// targets.size() < size() / log(size())
// TODO(kevinb): see if we can share code with OrderedIterator after it
// graduates from labs.
- if (!SortedIterables.hasSameComparator(comparator(), targets)
+ if (!SortedIterables.hasSameComparator(comparator(), targets)
|| (targets.size() <= 1)) {
return super.containsAll(targets);
}
@@ -128,8 +125,18 @@ final class RegularImmutableSortedSet<E> extends ImmutableSortedSet<E> {
return false;
}
- private int unsafeBinarySearch(Object key) throws ClassCastException {
- return Collections.binarySearch(elements, key, unsafeComparator());
+ private int binarySearch(Object key) {
+ // TODO(kevinb): split this into binarySearch(E) and
+ // unsafeBinarySearch(Object), use each appropriately. name all methods that
+ // might throw CCE "unsafe*".
+
+ // Pretend the comparator can compare anything. If it turns out it can't
+ // compare a and b, we should get a CCE on the subsequent line. Only methods
+ // that are spec'd to throw CCE should call this.
+ @SuppressWarnings("unchecked")
+ Comparator<Object> unsafeComparator = (Comparator<Object>) comparator;
+
+ return Collections.binarySearch(elements, key, unsafeComparator);
}
@Override boolean isPartialView() {
@@ -190,38 +197,16 @@ final class RegularImmutableSortedSet<E> extends ImmutableSortedSet<E> {
}
@Override
- public E lower(E element) {
- int index = headIndex(element, false) - 1;
- return (index == -1) ? null : elements.get(index);
- }
-
- @Override
- public E floor(E element) {
- int index = headIndex(element, true) - 1;
- return (index == -1) ? null : elements.get(index);
- }
-
- @Override
- public E ceiling(E element) {
- int index = tailIndex(element, true);
- return (index == size()) ? null : elements.get(index);
- }
-
- @Override
- public E higher(E element) {
- int index = tailIndex(element, false);
- return (index == size()) ? null : elements.get(index);
- }
-
- @Override
ImmutableSortedSet<E> headSetImpl(E toElement, boolean inclusive) {
- return getSubSet(0, headIndex(toElement, inclusive));
- }
-
- int headIndex(E toElement, boolean inclusive) {
- return SortedLists.binarySearch(
- elements, checkNotNull(toElement), comparator(),
- inclusive ? FIRST_AFTER : FIRST_PRESENT, NEXT_HIGHER);
+ int index;
+ if (inclusive) {
+ index = SortedLists.binarySearch(
+ elements, checkNotNull(toElement), comparator(), FIRST_AFTER, NEXT_HIGHER);
+ } else {
+ index = SortedLists.binarySearch(
+ elements, checkNotNull(toElement), comparator(), FIRST_PRESENT, NEXT_HIGHER);
+ }
+ return createSubset(0, index);
}
@Override
@@ -233,15 +218,15 @@ final class RegularImmutableSortedSet<E> extends ImmutableSortedSet<E> {
@Override
ImmutableSortedSet<E> tailSetImpl(E fromElement, boolean inclusive) {
- return getSubSet(tailIndex(fromElement, inclusive), size());
- }
-
- int tailIndex(E fromElement, boolean inclusive) {
- return SortedLists.binarySearch(
- elements,
- checkNotNull(fromElement),
- comparator(),
- inclusive ? FIRST_PRESENT : FIRST_AFTER, NEXT_HIGHER);
+ int index;
+ if (inclusive) {
+ index = SortedLists.binarySearch(
+ elements, checkNotNull(fromElement), comparator(), FIRST_PRESENT, NEXT_HIGHER);
+ } else {
+ index = SortedLists.binarySearch(
+ elements, checkNotNull(fromElement), comparator(), FIRST_AFTER, NEXT_HIGHER);
+ }
+ return createSubset(index, size());
}
// Pretend the comparator can compare anything. If it turns out it can't
@@ -252,7 +237,7 @@ final class RegularImmutableSortedSet<E> extends ImmutableSortedSet<E> {
return (Comparator<Object>) comparator;
}
- ImmutableSortedSet<E> getSubSet(int newFromIndex, int newToIndex) {
+ private ImmutableSortedSet<E> createSubset(int newFromIndex, int newToIndex) {
if (newFromIndex == 0 && newToIndex == size()) {
return this;
} else if (newFromIndex < newToIndex) {
@@ -263,27 +248,28 @@ final class RegularImmutableSortedSet<E> extends ImmutableSortedSet<E> {
}
}
+ @SuppressWarnings("unchecked")
@Override int indexOf(@Nullable Object target) {
if (target == null) {
return -1;
}
int position;
try {
- position = SortedLists.binarySearch(elements, target, unsafeComparator(),
+ position = SortedLists.binarySearch(elements, (E) target, comparator(),
ANY_PRESENT, INVERTED_INSERTION_INDEX);
} catch (ClassCastException e) {
return -1;
}
- return (position >= 0) ? position : -1;
+ // TODO(kevinb): reconsider if it's really worth making feeble attempts at
+ // sanity for inconsistent comparators.
+
+ // The equals() check is needed when the comparator isn't compatible with
+ // equals().
+ return (position >= 0 && elements.get(position).equals(target))
+ ? position : -1;
}
@Override ImmutableList<E> createAsList() {
return new ImmutableSortedAsList<E>(this, elements);
}
-
- @Override
- ImmutableSortedSet<E> createDescendingSet() {
- return new RegularImmutableSortedSet<E>(elements.reverse(),
- Ordering.from(comparator).reverse());
- }
}
diff --git a/guava/src/com/google/common/collect/RegularImmutableTable.java b/guava/src/com/google/common/collect/RegularImmutableTable.java
index e4bfb70..c6ae3eb 100644
--- a/guava/src/com/google/common/collect/RegularImmutableTable.java
+++ b/guava/src/com/google/common/collect/RegularImmutableTable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Guava Authors
+ * Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,11 +21,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
import com.google.common.base.Objects;
import java.util.Collections;
import java.util.Comparator;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -36,63 +36,56 @@ import javax.annotation.concurrent.Immutable;
* An implementation of {@link ImmutableTable} holding an arbitrary number of
* cells.
*
- * @author Gregory Kick
+ * @author gak@google.com (Gregory Kick)
*/
@GwtCompatible
abstract class RegularImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
- private RegularImmutableTable() {}
-
- private transient ImmutableCollection<V> values;
+ private final ImmutableSet<Cell<R, C, V>> cellSet;
- @Override public final ImmutableCollection<V> values() {
- ImmutableCollection<V> result = values;
- return (result == null) ? values = createValues() : result;
+ private RegularImmutableTable(ImmutableSet<Cell<R, C, V>> cellSet) {
+ this.cellSet = cellSet;
}
-
- abstract ImmutableCollection<V> createValues();
- @Override public abstract int size();
+ private static final Function<Cell<Object, Object, Object>, Object>
+ GET_VALUE_FUNCTION =
+ new Function<Cell<Object, Object, Object>, Object>() {
+ @Override public Object apply(Cell<Object, Object, Object> from) {
+ return from.getValue();
+ }
+ };
+
+ @SuppressWarnings("unchecked")
+ private Function<Cell<R, C, V>, V> getValueFunction() {
+ return (Function) GET_VALUE_FUNCTION;
+ }
- @Override public final boolean containsValue(@Nullable Object value) {
- return values().contains(value);
+ @Nullable private transient volatile ImmutableList<V> valueList;
+
+ @Override public final ImmutableCollection<V> values() {
+ ImmutableList<V> result = valueList;
+ if (result == null) {
+ valueList = result = ImmutableList.copyOf(
+ Iterables.transform(cellSet(), getValueFunction()));
+ }
+ return result;
}
-
- private transient ImmutableSet<Cell<R, C, V>> cellSet;
- @Override
- public final ImmutableSet<Cell<R, C, V>> cellSet() {
- ImmutableSet<Cell<R, C, V>> result = cellSet;
- return (result == null) ? cellSet = createCellSet() : result;
+ @Override public final int size() {
+ return cellSet().size();
}
-
- abstract ImmutableSet<Cell<R, C, V>> createCellSet();
-
- abstract class CellSet extends ImmutableSet<Cell<R, C, V>> {
- @Override
- public int size() {
- return RegularImmutableTable.this.size();
- }
-
- @Override
- public boolean contains(@Nullable Object object) {
- if (object instanceof Cell) {
- Cell<?, ?, ?> cell = (Cell<?, ?, ?>) object;
- Object value = get(cell.getRowKey(), cell.getColumnKey());
- return value != null && value.equals(cell.getValue());
- }
- return false;
- }
- @Override
- boolean isPartialView() {
- return false;
- }
+ @Override public final boolean containsValue(@Nullable Object value) {
+ return values().contains(value);
}
@Override public final boolean isEmpty() {
return false;
}
+ @Override public final ImmutableSet<Cell<R, C, V>> cellSet() {
+ return cellSet;
+ }
+
static final <R, C, V> RegularImmutableTable<R, C, V> forCells(
List<Cell<R, C, V>> cells,
@Nullable final Comparator<? super R> rowComparator,
@@ -137,13 +130,15 @@ abstract class RegularImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
forCellsInternal(Iterable<Cell<R, C, V>> cells,
@Nullable Comparator<? super R> rowComparator,
@Nullable Comparator<? super C> columnComparator) {
+ ImmutableSet.Builder<Cell<R, C, V>> cellSetBuilder = ImmutableSet.builder();
ImmutableSet.Builder<R> rowSpaceBuilder = ImmutableSet.builder();
ImmutableSet.Builder<C> columnSpaceBuilder = ImmutableSet.builder();
- ImmutableList<Cell<R, C, V>> cellList = ImmutableList.copyOf(cells);
- for (Cell<R, C, V> cell : cellList) {
+ for (Cell<R, C, V> cell : cells) {
+ cellSetBuilder.add(cell);
rowSpaceBuilder.add(cell.getRowKey());
columnSpaceBuilder.add(cell.getColumnKey());
}
+ ImmutableSet<Cell<R, C, V>> cellSet = cellSetBuilder.build();
ImmutableSet<R> rowSpace = rowSpaceBuilder.build();
if (rowComparator != null) {
@@ -160,9 +155,9 @@ abstract class RegularImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
// use a dense table if more than half of the cells have values
// TODO(gak): tune this condition based on empirical evidence
- return (cellList.size() > ((rowSpace.size() * columnSpace.size()) / 2)) ?
- new DenseImmutableTable<R, C, V>(cellList, rowSpace, columnSpace) :
- new SparseImmutableTable<R, C, V>(cellList, rowSpace, columnSpace);
+ return (cellSet.size() > ((rowSpace.size() * columnSpace.size()) / 2 )) ?
+ new DenseImmutableTable<R, C, V>(cellSet, rowSpace, columnSpace) :
+ new SparseImmutableTable<R, C, V>(cellSet, rowSpace, columnSpace);
}
/**
@@ -175,52 +170,50 @@ abstract class RegularImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
private final ImmutableMap<R, Map<C, V>> rowMap;
private final ImmutableMap<C, Map<R, V>> columnMap;
- private final int[] iterationOrderRow;
- private final int[] iterationOrderColumn;
- SparseImmutableTable(ImmutableList<Cell<R, C, V>> cellList,
- ImmutableSet<R> rowSpace, ImmutableSet<C> columnSpace) {
- Map<R, Integer> rowIndex = Maps.newHashMap();
- Map<R, Map<C, V>> rows = Maps.newLinkedHashMap();
- for (R row : rowSpace) {
- rowIndex.put(row, rows.size());
- rows.put(row, new LinkedHashMap<C, V>());
- }
- Map<C, Map<R, V>> columns = Maps.newLinkedHashMap();
- for (C col : columnSpace) {
- columns.put(col, new LinkedHashMap<R, V>());
+ /**
+ * Creates a {@link Map} over the key space with
+ * {@link ImmutableMap.Builder}s ready for values.
+ */
+ private static final <A, B, V> Map<A, ImmutableMap.Builder<B, V>>
+ makeIndexBuilder(ImmutableSet<A> keySpace) {
+ Map<A, ImmutableMap.Builder<B, V>> indexBuilder = Maps.newLinkedHashMap();
+ for (A key : keySpace) {
+ indexBuilder.put(key, ImmutableMap.<B, V>builder());
}
- int[] iterationOrderRow = new int[cellList.size()];
- int[] iterationOrderColumn = new int[cellList.size()];
- for (int i = 0; i < cellList.size(); i++) {
- Cell<R, C, V> cell = cellList.get(i);
+ return indexBuilder;
+ }
+
+ /**
+ * Builds the value maps of the index and creates an immutable copy of the
+ * map.
+ */
+ private static final <A, B, V> ImmutableMap<A, Map<B, V>> buildIndex(
+ Map<A, ImmutableMap.Builder<B, V>> indexBuilder) {
+ return ImmutableMap.copyOf(Maps.transformValues(indexBuilder,
+ new Function<ImmutableMap.Builder<B, V>, Map<B, V>>() {
+ @Override public Map<B, V> apply(ImmutableMap.Builder<B, V> from) {
+ return from.build();
+ }
+ }));
+ }
+
+ SparseImmutableTable(ImmutableSet<Cell<R, C, V>> cellSet,
+ ImmutableSet<R> rowSpace, ImmutableSet<C> columnSpace) {
+ super(cellSet);
+ Map<R, ImmutableMap.Builder<C, V>> rowIndexBuilder
+ = makeIndexBuilder(rowSpace);
+ Map<C, ImmutableMap.Builder<R, V>> columnIndexBuilder
+ = makeIndexBuilder(columnSpace);
+ for (Cell<R, C, V> cell : cellSet) {
R rowKey = cell.getRowKey();
C columnKey = cell.getColumnKey();
V value = cell.getValue();
-
- iterationOrderRow[i] = rowIndex.get(rowKey);
- Map<C, V> thisRow = rows.get(rowKey);
- iterationOrderColumn[i] = thisRow.size();
- V oldValue = thisRow.put(columnKey, value);
- if (oldValue != null) {
- throw new IllegalArgumentException("Duplicate value for row=" + rowKey + ", column="
- + columnKey + ": " + value + ", " + oldValue);
- }
- columns.get(columnKey).put(rowKey, value);
- }
- this.iterationOrderRow = iterationOrderRow;
- this.iterationOrderColumn = iterationOrderColumn;
- ImmutableMap.Builder<R, Map<C, V>> rowBuilder = ImmutableMap.builder();
- for (Map.Entry<R, Map<C, V>> row : rows.entrySet()) {
- rowBuilder.put(row.getKey(), ImmutableMap.copyOf(row.getValue()));
+ rowIndexBuilder.get(rowKey).put(columnKey, value);
+ columnIndexBuilder.get(columnKey).put(rowKey, value);
}
- this.rowMap = rowBuilder.build();
-
- ImmutableMap.Builder<C, Map<R, V>> columnBuilder = ImmutableMap.builder();
- for (Map.Entry<C, Map<R, V>> col : columns.entrySet()) {
- columnBuilder.put(col.getKey(), ImmutableMap.copyOf(col.getValue()));
- }
- this.columnMap = columnBuilder.build();
+ this.rowMap = buildIndex(rowIndexBuilder);
+ this.columnMap = buildIndex(columnIndexBuilder);
}
@Override public ImmutableMap<R, V> column(C columnKey) {
@@ -272,153 +265,6 @@ abstract class RegularImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
Map<C, V> row = rowMap.get(rowKey);
return (row == null) ? null : row.get(columnKey);
}
-
- @Override
- ImmutableCollection<V> createValues() {
- return new ImmutableList<V>() {
- @Override
- public int size() {
- return iterationOrderRow.length;
- }
-
- @Override
- public V get(int index) {
- int rowIndex = iterationOrderRow[index];
- ImmutableMap<C, V> row = (ImmutableMap<C, V>) rowMap.values().asList().get(rowIndex);
- int columnIndex = iterationOrderColumn[index];
- return row.values().asList().get(columnIndex);
- }
-
- @Override
- boolean isPartialView() {
- return true;
- }
- };
- }
-
- @Override
- public int size() {
- return iterationOrderRow.length;
- }
-
- @Override
- ImmutableSet<Cell<R, C, V>> createCellSet() {
- return new SparseCellSet();
- }
-
- class SparseCellSet extends CellSet {
- @Override
- public UnmodifiableIterator<Cell<R, C, V>> iterator() {
- return asList().iterator();
- }
-
- @Override
- ImmutableList<Cell<R, C, V>> createAsList() {
- return new ImmutableAsList<Cell<R, C, V>>() {
- @Override
- public Cell<R, C, V> get(int index) {
- int rowIndex = iterationOrderRow[index];
- Map.Entry<R, Map<C, V>> rowEntry = rowMap.entrySet().asList().get(rowIndex);
- ImmutableMap<C, V> row = (ImmutableMap<C, V>) rowEntry.getValue();
- int columnIndex = iterationOrderColumn[index];
- Map.Entry<C, V> colEntry = row.entrySet().asList().get(columnIndex);
- return Tables.immutableCell(rowEntry.getKey(), colEntry.getKey(), colEntry.getValue());
- }
-
- @Override
- ImmutableCollection<Cell<R, C, V>> delegateCollection() {
- return SparseCellSet.this;
- }
- };
- }
- }
- }
-
- /**
- * An immutable map implementation backed by an indexed nullable array, used in
- * DenseImmutableTable.
- */
- private abstract static class ImmutableArrayMap<K, V> extends ImmutableMap<K, V> {
- private final int size;
-
- ImmutableArrayMap(int size) {
- this.size = size;
- }
-
- abstract ImmutableMap<K, Integer> keyToIndex();
-
- // True if getValue never returns null.
- private boolean isFull() {
- return size == keyToIndex().size();
- }
-
- K getKey(int index) {
- return keyToIndex().keySet().asList().get(index);
- }
-
- @Nullable abstract V getValue(int keyIndex);
-
- @Override
- ImmutableSet<K> createKeySet() {
- return isFull() ? keyToIndex().keySet() : super.createKeySet();
- }
-
- @Override
- public int size() {
- return size;
- }
-
- @Override
- public V get(@Nullable Object key) {
- Integer keyIndex = keyToIndex().get(key);
- return (keyIndex == null) ? null : getValue(keyIndex);
- }
-
- @Override
- ImmutableSet<Entry<K, V>> createEntrySet() {
- if (isFull()) {
- return new ImmutableMapEntrySet<K, V>() {
- @Override ImmutableMap<K, V> map() {
- return ImmutableArrayMap.this;
- }
-
- @Override
- public UnmodifiableIterator<Entry<K, V>> iterator() {
- return new AbstractIndexedListIterator<Entry<K, V>>(size()) {
- @Override
- protected Entry<K, V> get(int index) {
- return Maps.immutableEntry(getKey(index), getValue(index));
- }
- };
- }
- };
- } else {
- return new ImmutableMapEntrySet<K, V>() {
- @Override ImmutableMap<K, V> map() {
- return ImmutableArrayMap.this;
- }
-
- @Override
- public UnmodifiableIterator<Entry<K, V>> iterator() {
- return new AbstractIterator<Entry<K, V>>() {
- private int index = -1;
- private final int maxIndex = keyToIndex().size();
-
- @Override
- protected Entry<K, V> computeNext() {
- for (index++; index < maxIndex; index++) {
- V value = getValue(index);
- if (value != null) {
- return Maps.immutableEntry(getKey(index), value);
- }
- }
- return endOfData();
- }
- };
- }
- };
- }
- }
}
/**
@@ -428,20 +274,14 @@ abstract class RegularImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
static final class DenseImmutableTable<R, C, V>
extends RegularImmutableTable<R, C, V> {
- private final ImmutableMap<R, Integer> rowKeyToIndex;
- private final ImmutableMap<C, Integer> columnKeyToIndex;
- private final ImmutableMap<R, Map<C, V>> rowMap;
- private final ImmutableMap<C, Map<R, V>> columnMap;
- private final int[] rowCounts;
- private final int[] columnCounts;
+ private final ImmutableBiMap<R, Integer> rowKeyToIndex;
+ private final ImmutableBiMap<C, Integer> columnKeyToIndex;
private final V[][] values;
- private final int[] iterationOrderRow;
- private final int[] iterationOrderColumn;
- private static <E> ImmutableMap<E, Integer> makeIndex(
+ private static <E> ImmutableBiMap<E, Integer> makeIndex(
ImmutableSet<E> set) {
- ImmutableMap.Builder<E, Integer> indexBuilder =
- ImmutableMap.builder();
+ ImmutableBiMap.Builder<E, Integer> indexBuilder =
+ ImmutableBiMap.builder();
int i = 0;
for (E key : set) {
indexBuilder.put(key, i);
@@ -450,19 +290,15 @@ abstract class RegularImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
return indexBuilder.build();
}
- DenseImmutableTable(ImmutableList<Cell<R, C, V>> cellList,
+ DenseImmutableTable(ImmutableSet<Cell<R, C, V>> cellSet,
ImmutableSet<R> rowSpace, ImmutableSet<C> columnSpace) {
+ super(cellSet);
@SuppressWarnings("unchecked")
V[][] array = (V[][]) new Object[rowSpace.size()][columnSpace.size()];
this.values = array;
this.rowKeyToIndex = makeIndex(rowSpace);
this.columnKeyToIndex = makeIndex(columnSpace);
- rowCounts = new int[rowKeyToIndex.size()];
- columnCounts = new int[columnKeyToIndex.size()];
- int[] iterationOrderRow = new int[cellList.size()];
- int[] iterationOrderColumn = new int[cellList.size()];
- for (int i = 0; i < cellList.size(); i++) {
- Cell<R, C, V> cell = cellList.get(i);
+ for (Cell<R, C, V> cell : cellSet) {
R rowKey = cell.getRowKey();
C columnKey = cell.getColumnKey();
int rowIndex = rowKeyToIndex.get(rowKey);
@@ -471,113 +307,25 @@ abstract class RegularImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
checkArgument(existingValue == null, "duplicate key: (%s, %s)", rowKey,
columnKey);
values[rowIndex][columnIndex] = cell.getValue();
- rowCounts[rowIndex]++;
- columnCounts[columnIndex]++;
- iterationOrderRow[i] = rowIndex;
- iterationOrderColumn[i] = columnIndex;
- }
- this.iterationOrderRow = iterationOrderRow;
- this.iterationOrderColumn = iterationOrderColumn;
- this.rowMap = new RowMap();
- this.columnMap = new ColumnMap();
- }
-
- private final class Row extends ImmutableArrayMap<C, V> {
- private final int rowIndex;
-
- Row(int rowIndex) {
- super(rowCounts[rowIndex]);
- this.rowIndex = rowIndex;
- }
-
- @Override
- ImmutableMap<C, Integer> keyToIndex() {
- return columnKeyToIndex;
- }
-
- @Override
- V getValue(int keyIndex) {
- return values[rowIndex][keyIndex];
- }
-
- @Override
- boolean isPartialView() {
- return true;
- }
- }
-
- private final class Column extends ImmutableArrayMap<R, V> {
- private final int columnIndex;
-
- Column(int columnIndex) {
- super(columnCounts[columnIndex]);
- this.columnIndex = columnIndex;
- }
-
- @Override
- ImmutableMap<R, Integer> keyToIndex() {
- return rowKeyToIndex;
- }
-
- @Override
- V getValue(int keyIndex) {
- return values[keyIndex][columnIndex];
- }
-
- @Override
- boolean isPartialView() {
- return true;
- }
- }
-
- private final class RowMap extends ImmutableArrayMap<R, Map<C, V>> {
- private RowMap() {
- super(rowCounts.length);
- }
-
- @Override
- ImmutableMap<R, Integer> keyToIndex() {
- return rowKeyToIndex;
- }
-
- @Override
- Map<C, V> getValue(int keyIndex) {
- return new Row(keyIndex);
- }
-
- @Override
- boolean isPartialView() {
- return false;
- }
- }
-
- private final class ColumnMap extends ImmutableArrayMap<C, Map<R, V>> {
- private ColumnMap() {
- super(columnCounts.length);
- }
-
- @Override
- ImmutableMap<C, Integer> keyToIndex() {
- return columnKeyToIndex;
- }
-
- @Override
- Map<R, V> getValue(int keyIndex) {
- return new Column(keyIndex);
- }
-
- @Override
- boolean isPartialView() {
- return false;
}
}
@Override public ImmutableMap<R, V> column(C columnKey) {
- Integer columnIndex = columnKeyToIndex.get(checkNotNull(columnKey));
- if (columnIndex == null) {
+ checkNotNull(columnKey);
+ Integer columnIndexInteger = columnKeyToIndex.get(columnKey);
+ if (columnIndexInteger == null) {
return ImmutableMap.of();
} else {
- return new Column(columnIndex);
+ // unbox only once
+ int columnIndex = columnIndexInteger;
+ ImmutableMap.Builder<R, V> columnBuilder = ImmutableMap.builder();
+ for (int i = 0; i < values.length; i++) {
+ V value = values[i][columnIndex];
+ if (value != null) {
+ columnBuilder.put(rowKeyToIndex.inverse().get(i), value);
+ }
+ }
+ return columnBuilder.build();
}
}
@@ -585,8 +333,31 @@ abstract class RegularImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
return columnKeyToIndex.keySet();
}
+ private transient volatile ImmutableMap<C, Map<R, V>> columnMap;
+
+ private ImmutableMap<C, Map<R, V>> makeColumnMap() {
+ ImmutableMap.Builder<C, Map<R, V>> columnMapBuilder =
+ ImmutableMap.builder();
+ for (int c = 0; c < columnKeyToIndex.size(); c++) {
+ ImmutableMap.Builder<R, V> rowMapBuilder = ImmutableMap.builder();
+ for (int r = 0; r < rowKeyToIndex.size(); r++) {
+ V value = values[r][c];
+ if (value != null) {
+ rowMapBuilder.put(rowKeyToIndex.inverse().get(r), value);
+ }
+ }
+ columnMapBuilder.put(columnKeyToIndex.inverse().get(c),
+ rowMapBuilder.build());
+ }
+ return columnMapBuilder.build();
+ }
+
@Override public ImmutableMap<C, Map<R, V>> columnMap() {
- return columnMap;
+ ImmutableMap<C, Map<R, V>> result = columnMap;
+ if (result == null) {
+ columnMap = result = makeColumnMap();
+ }
+ return result;
}
@Override public boolean contains(@Nullable Object rowKey,
@@ -616,7 +387,15 @@ abstract class RegularImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
if (rowIndex == null) {
return ImmutableMap.of();
} else {
- return new Row(rowIndex);
+ ImmutableMap.Builder<C, V> rowBuilder = ImmutableMap.builder();
+ V[] row = values[rowIndex];
+ for (int r = 0; r < row.length; r++) {
+ V value = row[r];
+ if (value != null) {
+ rowBuilder.put(columnKeyToIndex.inverse().get(r), value);
+ }
+ }
+ return rowBuilder.build();
}
}
@@ -624,66 +403,31 @@ abstract class RegularImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
return rowKeyToIndex.keySet();
}
- @Override
- public ImmutableMap<R, Map<C, V>> rowMap() {
- return rowMap;
- }
+ private transient volatile ImmutableMap<R, Map<C, V>> rowMap;
- @Override
- ImmutableCollection<V> createValues() {
- return new ImmutableList<V>() {
- @Override
- public int size() {
- return iterationOrderRow.length;
- }
-
- @Override
- public V get(int index) {
- return values[iterationOrderRow[index]][iterationOrderColumn[index]];
- }
-
- @Override
- boolean isPartialView() {
- return true;
+ private ImmutableMap<R, Map<C, V>> makeRowMap() {
+ ImmutableMap.Builder<R, Map<C, V>> rowMapBuilder = ImmutableMap.builder();
+ for (int r = 0; r < values.length; r++) {
+ V[] row = values[r];
+ ImmutableMap.Builder<C, V> columnMapBuilder = ImmutableMap.builder();
+ for (int c = 0; c < row.length; c++) {
+ V value = row[c];
+ if (value != null) {
+ columnMapBuilder.put(columnKeyToIndex.inverse().get(c), value);
+ }
}
- };
- }
-
- @Override
- public int size() {
- return iterationOrderRow.length;
- }
-
- @Override
- ImmutableSet<Cell<R, C, V>> createCellSet() {
- return new DenseCellSet();
- }
-
- class DenseCellSet extends CellSet {
- @Override
- public UnmodifiableIterator<Cell<R, C, V>> iterator() {
- return asList().iterator();
+ rowMapBuilder.put(rowKeyToIndex.inverse().get(r),
+ columnMapBuilder.build());
}
+ return rowMapBuilder.build();
+ }
- @Override
- ImmutableList<Cell<R, C, V>> createAsList() {
- return new ImmutableAsList<Cell<R, C, V>>() {
- @Override
- public Cell<R, C, V> get(int index) {
- int rowIndex = iterationOrderRow[index];
- int columnIndex = iterationOrderColumn[index];
- R rowKey = rowKeySet().asList().get(rowIndex);
- C columnKey = columnKeySet().asList().get(columnIndex);
- V value = values[rowIndex][columnIndex];
- return Tables.immutableCell(rowKey, columnKey, value);
- }
-
- @Override
- ImmutableCollection<Cell<R, C, V>> delegateCollection() {
- return DenseCellSet.this;
- }
- };
+ @Override public ImmutableMap<R, Map<C, V>> rowMap() {
+ ImmutableMap<R, Map<C, V>> result = rowMap;
+ if (result == null) {
+ rowMap = result = makeRowMap();
}
+ return result;
}
}
}
diff --git a/guava/src/com/google/common/collect/SetMultimap.java b/guava/src/com/google/common/collect/SetMultimap.java
index 18f4a18..1409d8d 100644
--- a/guava/src/com/google/common/collect/SetMultimap.java
+++ b/guava/src/com/google/common/collect/SetMultimap.java
@@ -26,22 +26,13 @@ import javax.annotation.Nullable;
/**
* A {@code Multimap} that cannot hold duplicate key-value pairs. Adding a
- * key-value pair that's already in the multimap has no effect. See the {@link
- * Multimap} documentation for information common to all multimaps.
+ * key-value pair that's already in the multimap has no effect.
*
* <p>The {@link #get}, {@link #removeAll}, and {@link #replaceValues} methods
* each return a {@link Set} of values, while {@link #entries} returns a {@code
* Set} of map entries. Though the method signature doesn't say so explicitly,
* the map returned by {@link #asMap} has {@code Set} values.
*
- * <p>If the values corresponding to a single key should be ordered according to
- * a {@link java.util.Comparator} (or the natural order), see the
- * {@link SortedSetMultimap} subinterface.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap">
- * {@code Multimap}</a>.
- *
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
*/
diff --git a/guava/src/com/google/common/collect/Sets.java b/guava/src/com/google/common/collect/Sets.java
index 95298e7..14ad867 100644
--- a/guava/src/com/google/common/collect/Sets.java
+++ b/guava/src/com/google/common/collect/Sets.java
@@ -19,11 +19,16 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2.FilteredCollection;
+import com.google.common.math.IntMath;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -39,22 +44,16 @@ import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
-import java.util.NavigableSet;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
-import java.util.concurrent.CopyOnWriteArraySet;
import javax.annotation.Nullable;
/**
* Static utility methods pertaining to {@link Set} instances. Also see this
- * class's counterparts {@link Lists}, {@link Maps} and {@link Queues}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Sets">
- * {@code Sets}</a>.
+ * class's counterparts {@link Lists} and {@link Maps}.
*
* @author Kevin Bourrillion
* @author Jared Levy
@@ -66,22 +65,6 @@ public final class Sets {
private Sets() {}
/**
- * {@link AbstractSet} substitute without the potentially-quadratic
- * {@code removeAll} implementation.
- */
- abstract static class ImprovedAbstractSet<E> extends AbstractSet<E> {
- @Override
- public boolean removeAll(Collection<?> c) {
- return removeAllImpl(this, c);
- }
-
- @Override
- public boolean retainAll(Collection<?> c) {
- return super.retainAll(checkNotNull(c)); // GWT compatibility
- }
- }
-
- /**
* Returns an immutable set instance containing the given enum elements.
* Internally, the returned set will be backed by an {@link EnumSet}.
*
@@ -96,7 +79,7 @@ public final class Sets {
@GwtCompatible(serializable = true)
public static <E extends Enum<E>> ImmutableSet<E> immutableEnumSet(
E anElement, E... otherElements) {
- return ImmutableEnumSet.asImmutable(EnumSet.of(anElement, otherElements));
+ return new ImmutableEnumSet<E>(EnumSet.of(anElement, otherElements));
}
/**
@@ -114,25 +97,20 @@ public final class Sets {
@GwtCompatible(serializable = true)
public static <E extends Enum<E>> ImmutableSet<E> immutableEnumSet(
Iterable<E> elements) {
- if (elements instanceof ImmutableEnumSet) {
- return (ImmutableEnumSet<E>) elements;
- } else if (elements instanceof Collection) {
- Collection<E> collection = (Collection<E>) elements;
- if (collection.isEmpty()) {
- return ImmutableSet.of();
- } else {
- return ImmutableEnumSet.asImmutable(EnumSet.copyOf(collection));
- }
- } else {
- Iterator<E> itr = elements.iterator();
- if (itr.hasNext()) {
- EnumSet<E> enumSet = EnumSet.of(itr.next());
- Iterators.addAll(enumSet, itr);
- return ImmutableEnumSet.asImmutable(enumSet);
- } else {
- return ImmutableSet.of();
- }
+ Iterator<E> iterator = elements.iterator();
+ if (!iterator.hasNext()) {
+ return ImmutableSet.of();
+ }
+ if (elements instanceof EnumSet) {
+ EnumSet<E> enumSetClone = EnumSet.copyOf((EnumSet<E>) elements);
+ return new ImmutableEnumSet<E>(enumSetClone);
}
+ E first = iterator.next();
+ EnumSet<E> set = EnumSet.of(first);
+ while (iterator.hasNext()) {
+ set.add(iterator.next());
+ }
+ return new ImmutableEnumSet<E>(set);
}
/**
@@ -143,6 +121,20 @@ public final class Sets {
*/
public static <E extends Enum<E>> EnumSet<E> newEnumSet(Iterable<E> iterable,
Class<E> elementType) {
+ /*
+ * TODO(cpovirk): noneOf() and addAll() will both throw
+ * NullPointerExceptions when appropriate. However, NullPointerTester will
+ * fail on this method because it passes in Class.class instead of an enum
+ * type. This means that, when iterable is null but elementType is not,
+ * noneOf() will throw a ClassCastException before addAll() has a chance to
+ * throw a NullPointerException. NullPointerTester considers this a failure.
+ * Ideally the test would be fixed, but it would require a special case for
+ * Class<E> where E extends Enum. Until that happens (if ever), leave
+ * checkNotNull() here. For now, contemplate the irony that checking
+ * elementType, the problem argument, is harmful, while checking iterable,
+ * the innocent bystander, is effective.
+ */
+ checkNotNull(iterable);
EnumSet<E> set = EnumSet.noneOf(elementType);
Iterables.addAll(set, iterable);
return set;
@@ -367,38 +359,6 @@ public final class Sets {
}
/**
- * Creates an empty {@code CopyOnWriteArraySet} instance.
- *
- * <p><b>Note:</b> if you need an immutable empty {@link Set}, use
- * {@link Collections#emptySet} instead.
- *
- * @return a new, empty {@code CopyOnWriteArraySet}
- * @since 12.0
- */
- @GwtIncompatible("CopyOnWriteArraySet")
- public static <E> CopyOnWriteArraySet<E> newCopyOnWriteArraySet() {
- return new CopyOnWriteArraySet<E>();
- }
-
- /**
- * Creates a {@code CopyOnWriteArraySet} instance containing the given elements.
- *
- * @param elements the elements that the set should contain, in order
- * @return a new {@code CopyOnWriteArraySet} containing those elements
- * @since 12.0
- */
- @GwtIncompatible("CopyOnWriteArraySet")
- public static <E> CopyOnWriteArraySet<E> newCopyOnWriteArraySet(
- Iterable<? extends E> elements) {
- // We copy elements to an ArrayList first, rather than incurring the
- // quadratic cost of adding them to the COWAS directly.
- Collection<? extends E> elementsCollection = (elements instanceof Collection)
- ? Collections2.cast(elements)
- : Lists.newArrayList(elements);
- return new CopyOnWriteArraySet<E>(elementsCollection);
- }
-
- /**
* Creates an {@code EnumSet} consisting of all enum values that are not in
* the specified collection. If the collection is an {@link EnumSet}, this
* method has the same behavior as {@link EnumSet#complementOf}. Otherwise,
@@ -618,11 +578,6 @@ public final class Sets {
* <p><b>Note:</b> The returned view performs better when {@code set1} is the
* smaller of the two sets. If you have reason to believe one of your sets
* will generally be smaller than the other, pass it first.
- *
- * <p>Further, note that the current implementation is not suitable for nested
- * {@code union} views, i.e. the following should be avoided when in a loop:
- * {@code union = Sets.union(union, anotherSet);}, since iterating over the resulting
- * set has a cubic complexity to the depth of the nesting.
*/
public static <E> SetView<E> union(
final Set<? extends E> set1, final Set<? extends E> set2) {
@@ -853,13 +808,10 @@ public final class Sets {
*
* @since 11.0
*/
+ @Beta
+ @SuppressWarnings("unchecked")
public static <E> SortedSet<E> filter(
SortedSet<E> unfiltered, Predicate<? super E> predicate) {
- return Platform.setsFilterSortedSet(unfiltered, predicate);
- }
-
- static <E> SortedSet<E> filterSortedIgnoreNavigable(
- SortedSet<E> unfiltered, Predicate<? super E> predicate) {
if (unfiltered instanceof FilteredSet) {
// Support clear(), removeAll(), and retainAll() when filtering a filtered
// collection.
@@ -874,13 +826,21 @@ public final class Sets {
checkNotNull(unfiltered), checkNotNull(predicate));
}
- private static class FilteredSortedSet<E> extends FilteredSet<E>
+ private static class FilteredSortedSet<E> extends FilteredCollection<E>
implements SortedSet<E> {
FilteredSortedSet(SortedSet<E> unfiltered, Predicate<? super E> predicate) {
super(unfiltered, predicate);
}
+ @Override public boolean equals(@Nullable Object object) {
+ return equalsImpl(this, object);
+ }
+
+ @Override public int hashCode() {
+ return hashCodeImpl(this);
+ }
+
@Override
public Comparator<? super E> comparator() {
return ((SortedSet<E>) unfiltered).comparator();
@@ -921,145 +881,6 @@ public final class Sets {
}
/**
- * Returns the elements of a {@code NavigableSet}, {@code unfiltered}, that
- * satisfy a predicate. The returned set is a live view of {@code unfiltered};
- * changes to one affect the other.
- *
- * <p>The resulting set's iterator does not support {@code remove()}, but all
- * other set methods are supported. When given an element that doesn't satisfy
- * the predicate, the set's {@code add()} and {@code addAll()} methods throw
- * an {@link IllegalArgumentException}. When methods such as
- * {@code removeAll()} and {@code clear()} are called on the filtered set,
- * only elements that satisfy the filter will be removed from the underlying
- * set.
- *
- * <p>The returned set isn't threadsafe or serializable, even if
- * {@code unfiltered} is.
- *
- * <p>Many of the filtered set's methods, such as {@code size()}, iterate across
- * every element in the underlying set and determine which elements satisfy
- * the filter. When a live view is <i>not</i> needed, it may be faster to copy
- * {@code Iterables.filter(unfiltered, predicate)} and use the copy.
- *
- * <p><b>Warning:</b> {@code predicate} must be <i>consistent with equals</i>,
- * as documented at {@link Predicate#apply}. Do not provide a predicate such as
- * {@code Predicates.instanceOf(ArrayList.class)}, which is inconsistent with
- * equals. (See {@link Iterables#filter(Iterable, Class)} for related
- * functionality.)
- *
- * @since 14.0
- */
- @GwtIncompatible("NavigableSet")
- @SuppressWarnings("unchecked")
- public static <E> NavigableSet<E> filter(
- NavigableSet<E> unfiltered, Predicate<? super E> predicate) {
- if (unfiltered instanceof FilteredSet) {
- // Support clear(), removeAll(), and retainAll() when filtering a filtered
- // collection.
- FilteredSet<E> filtered = (FilteredSet<E>) unfiltered;
- Predicate<E> combinedPredicate
- = Predicates.<E>and(filtered.predicate, predicate);
- return new FilteredNavigableSet<E>(
- (NavigableSet<E>) filtered.unfiltered, combinedPredicate);
- }
-
- return new FilteredNavigableSet<E>(
- checkNotNull(unfiltered), checkNotNull(predicate));
- }
-
- @GwtIncompatible("NavigableSet")
- private static class FilteredNavigableSet<E> extends FilteredSortedSet<E>
- implements NavigableSet<E> {
- FilteredNavigableSet(NavigableSet<E> unfiltered, Predicate<? super E> predicate) {
- super(unfiltered, predicate);
- }
-
- NavigableSet<E> unfiltered() {
- return (NavigableSet<E>) unfiltered;
- }
-
- @Override
- @Nullable
- public E lower(E e) {
- return Iterators.getNext(headSet(e, false).descendingIterator(), null);
- }
-
- @Override
- @Nullable
- public E floor(E e) {
- return Iterators.getNext(headSet(e, true).descendingIterator(), null);
- }
-
- @Override
- public E ceiling(E e) {
- return Iterables.getFirst(tailSet(e, true), null);
- }
-
- @Override
- public E higher(E e) {
- return Iterables.getFirst(tailSet(e, false), null);
- }
-
- @Override
- public E pollFirst() {
- Iterator<E> unfilteredIterator = unfiltered().iterator();
- while (unfilteredIterator.hasNext()) {
- E e = unfilteredIterator.next();
- if (predicate.apply(e)) {
- unfilteredIterator.remove();
- return e;
- }
- }
- return null;
- }
-
- @Override
- public E pollLast() {
- Iterator<E> unfilteredIterator = unfiltered().descendingIterator();
- while (unfilteredIterator.hasNext()) {
- E e = unfilteredIterator.next();
- if (predicate.apply(e)) {
- unfilteredIterator.remove();
- return e;
- }
- }
- return null;
- }
-
- @Override
- public NavigableSet<E> descendingSet() {
- return Sets.filter(unfiltered().descendingSet(), predicate);
- }
-
- @Override
- public Iterator<E> descendingIterator() {
- return Iterators.filter(unfiltered().descendingIterator(), predicate);
- }
-
- @Override
- public E last() {
- return descendingIterator().next();
- }
-
- @Override
- public NavigableSet<E> subSet(
- E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
- return filter(
- unfiltered().subSet(fromElement, fromInclusive, toElement, toInclusive), predicate);
- }
-
- @Override
- public NavigableSet<E> headSet(E toElement, boolean inclusive) {
- return filter(unfiltered().headSet(toElement, inclusive), predicate);
- }
-
- @Override
- public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
- return filter(unfiltered().tailSet(fromElement, inclusive), predicate);
- }
- }
-
- /**
* Returns every possible list that can be formed by choosing one element
* from each of the given sets in order; the "n-ary
* <a href="http://en.wikipedia.org/wiki/Cartesian_product">Cartesian
@@ -1080,22 +901,12 @@ public final class Sets {
* <li>{@code ImmutableList.of(2, "C")}
* </ul>
*
- * The result is guaranteed to be in the "traditional", lexicographical
- * order for Cartesian products that you would get from nesting for loops:
- * <pre> {@code
- *
- * for (B b0 : sets.get(0)) {
- * for (B b1 : sets.get(1)) {
- * ...
- * ImmutableList<B> tuple = ImmutableList.of(b0, b1, ...);
- * // operate on tuple
- * }
- * }}</pre>
- *
- * Note that if any input set is empty, the Cartesian product will also be
- * empty. If no sets at all are provided (an empty list), the resulting
- * Cartesian product has one element, an empty list (counter-intuitive, but
- * mathematically consistent).
+ * The order in which these lists are returned is not guaranteed, however the
+ * position of an element inside a tuple always corresponds to the position of
+ * the set from which it came in the input list. Note that if any input set is
+ * empty, the Cartesian product will also be empty. If no sets at all are
+ * provided (an empty list), the resulting Cartesian product has one element,
+ * an empty list (counter-intuitive, but mathematically consistent).
*
* <p><i>Performance notes:</i> while the cartesian product of sets of size
* {@code m, n, p} is a set of size {@code m x n x p}, its actual memory
@@ -1121,7 +932,8 @@ public final class Sets {
return ImmutableSet.of();
}
}
- return CartesianSet.create(sets);
+ CartesianSet<B> cartesianSet = new CartesianSet<B>(sets);
+ return cartesianSet;
}
/**
@@ -1145,22 +957,12 @@ public final class Sets {
* <li>{@code ImmutableList.of(2, "C")}
* </ul>
*
- * The result is guaranteed to be in the "traditional", lexicographical
- * order for Cartesian products that you would get from nesting for loops:
- * <pre> {@code
- *
- * for (B b0 : sets.get(0)) {
- * for (B b1 : sets.get(1)) {
- * ...
- * ImmutableList<B> tuple = ImmutableList.of(b0, b1, ...);
- * // operate on tuple
- * }
- * }}</pre>
- *
- * Note that if any input set is empty, the Cartesian product will also be
- * empty. If no sets at all are provided (an empty list), the resulting
- * Cartesian product has one element, an empty list (counter-intuitive, but
- * mathematically consistent).
+ * The order in which these lists are returned is not guaranteed, however the
+ * position of an element inside a tuple always corresponds to the position of
+ * the set from which it came in the input list. Note that if any input set is
+ * empty, the Cartesian product will also be empty. If no sets at all are
+ * provided, the resulting Cartesian product has one element, an empty list
+ * (counter-intuitive, but mathematically consistent).
*
* <p><i>Performance notes:</i> while the cartesian product of sets of size
* {@code m, n, p} is a set of size {@code m x n x p}, its actual memory
@@ -1184,51 +986,73 @@ public final class Sets {
return cartesianProduct(Arrays.asList(sets));
}
- private static final class CartesianSet<E>
- extends ForwardingCollection<List<E>> implements Set<List<E>> {
- private transient final ImmutableList<ImmutableSet<E>> axes;
- private transient final CartesianList<E> delegate;
-
- static <E> Set<List<E>> create(List<? extends Set<? extends E>> sets) {
- ImmutableList.Builder<ImmutableSet<E>> axesBuilder =
- new ImmutableList.Builder<ImmutableSet<E>>(sets.size());
- for (Set<? extends E> set : sets) {
- ImmutableSet<E> copy = ImmutableSet.copyOf(set);
- if (copy.isEmpty()) {
- return ImmutableSet.of();
+ private static class CartesianSet<B> extends AbstractSet<List<B>> {
+ final ImmutableList<Axis> axes;
+ final int size;
+
+ CartesianSet(List<? extends Set<? extends B>> sets) {
+ int dividend = 1;
+ ImmutableList.Builder<Axis> builder = ImmutableList.builder();
+ try {
+ for (Set<? extends B> set : sets) {
+ Axis axis = new Axis(set, dividend);
+ builder.add(axis);
+ dividend = IntMath.checkedMultiply(dividend, axis.size());
}
- axesBuilder.add(copy);
+ } catch (ArithmeticException overflow) {
+ throw new IllegalArgumentException("cartesian product too big");
}
- final ImmutableList<ImmutableSet<E>> axes = axesBuilder.build();
- ImmutableList<List<E>> listAxes = new ImmutableList<List<E>>() {
+ this.axes = builder.build();
+ size = dividend;
+ }
- @Override
- public int size() {
- return axes.size();
- }
+ @Override public int size() {
+ return size;
+ }
+
+ @Override public UnmodifiableIterator<List<B>> iterator() {
+ return new UnmodifiableIterator<List<B>>() {
+ int index;
@Override
- public List<E> get(int index) {
- return axes.get(index).asList();
+ public boolean hasNext() {
+ return index < size;
}
@Override
- boolean isPartialView() {
- return true;
+ public List<B> next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+
+ Object[] tuple = new Object[axes.size()];
+ for (int i = 0 ; i < tuple.length; i++) {
+ tuple[i] = axes.get(i).getForIndex(index);
+ }
+ index++;
+
+ @SuppressWarnings("unchecked") // only B's are put in here
+ List<B> result = (ImmutableList<B>) ImmutableList.copyOf(tuple);
+ return result;
}
};
- return new CartesianSet<E>(axes, new CartesianList<E>(listAxes));
}
- private CartesianSet(
- ImmutableList<ImmutableSet<E>> axes, CartesianList<E> delegate) {
- this.axes = axes;
- this.delegate = delegate;
- }
-
- @Override
- protected Collection<List<E>> delegate() {
- return delegate;
+ @Override public boolean contains(Object element) {
+ if (!(element instanceof List<?>)) {
+ return false;
+ }
+ List<?> tuple = (List<?>) element;
+ int dimensions = axes.size();
+ if (tuple.size() != dimensions) {
+ return false;
+ }
+ for (int i = 0; i < dimensions; i++) {
+ if (!axes.get(i).contains(tuple.get(i))) {
+ return false;
+ }
+ }
+ return true;
}
@Override public boolean equals(@Nullable Object object) {
@@ -1241,26 +1065,56 @@ public final class Sets {
return super.equals(object);
}
- @Override
- public int hashCode() {
+ @Override public int hashCode() {
// Warning: this is broken if size() == 0, so it is critical that we
// substitute an empty ImmutableSet to the user in place of this
// It's a weird formula, but tests prove it works.
- int adjust = size() - 1;
+ int adjust = size - 1;
for (int i = 0; i < axes.size(); i++) {
adjust *= 31;
- adjust = ~~adjust;
- // in GWT, we have to deal with integer overflow carefully
}
- int hash = 1;
- for (Set<E> axis : axes) {
- hash = 31 * hash + (size() / axis.size() * axis.hashCode());
+ return axes.hashCode() + adjust;
+ }
+
+ private class Axis {
+ final ImmutableSet<? extends B> choices;
+ final ImmutableList<? extends B> choicesList;
+ final int dividend;
+
+ Axis(Set<? extends B> set, int dividend) {
+ choices = ImmutableSet.copyOf(set);
+ choicesList = choices.asList();
+ this.dividend = dividend;
+ }
+
+ int size() {
+ return choices.size();
+ }
+
+ B getForIndex(int index) {
+ return choicesList.get(index / dividend % size());
+ }
+
+ boolean contains(Object target) {
+ return choices.contains(target);
+ }
+
+ @Override public boolean equals(Object obj) {
+ if (obj instanceof CartesianSet.Axis) {
+ CartesianSet.Axis that = (CartesianSet.Axis) obj;
+ return this.choices.equals(that.choices);
+ // dividends must be equal or we wouldn't have gotten this far
+ }
+ return false;
+ }
- hash = ~~hash;
+ @Override public int hashCode() {
+ // Because Axis instances are not exposed, we can
+ // opportunistically choose whatever bizarre formula happens
+ // to make CartesianSet.hashCode() as simple as possible.
+ return size / choices.size() * choices.hashCode();
}
- hash += adjust;
- return ~~hash;
}
}
@@ -1398,9 +1252,6 @@ public final class Sets {
int hashCode = 0;
for (Object o : s) {
hashCode += o != null ? o.hashCode() : 0;
-
- hashCode = ~~hashCode;
- // Needed to deal with unusual integer overflow in GWT.
}
return hashCode;
}
@@ -1427,345 +1278,117 @@ public final class Sets {
}
/**
- * Returns an unmodifiable view of the specified navigable set. This method
- * allows modules to provide users with "read-only" access to internal
- * navigable sets. Query operations on the returned set "read through" to the
- * specified set, and attempts to modify the returned set, whether direct or
- * via its collection views, result in an
- * {@code UnsupportedOperationException}.
- *
- * <p>The returned navigable set will be serializable if the specified
- * navigable set is serializable.
- *
- * @param set the navigable set for which an unmodifiable view is to be
- * returned
- * @return an unmodifiable view of the specified navigable set
- * @since 12.0
+ * Creates a view of Set<B> for a Set<A>, given a bijection between A and B.
+ * (Modelled for now as InvertibleFunction<A, B>, can't be Converter<A, B>
+ * because that's not in Guava, though both designs are less than optimal).
+ * Note that the bijection is treated as undefined for values not in the
+ * given Set<A> - it doesn't have to define a true bijection for those.
+ *
+ * <p>Note that the returned Set's contains method is unsafe -
+ * you *must* pass an instance of B to it, since the bijection
+ * can only invert B's (not any Object) back to A, so we can
+ * then delegate the call to the original Set<A>.
*/
- @GwtIncompatible("NavigableSet")
- public static <E> NavigableSet<E> unmodifiableNavigableSet(
- NavigableSet<E> set) {
- if (set instanceof ImmutableSortedSet
- || set instanceof UnmodifiableNavigableSet) {
- return set;
- }
- return new UnmodifiableNavigableSet<E>(set);
+ static <A, B> Set<B> transform(
+ Set<A> set, InvertibleFunction<A, B> bijection) {
+ return new TransformedSet<A, B>(
+ Preconditions.checkNotNull(set, "set"),
+ Preconditions.checkNotNull(bijection, "bijection")
+ );
}
- @GwtIncompatible("NavigableSet")
- static final class UnmodifiableNavigableSet<E>
- extends ForwardingSortedSet<E> implements NavigableSet<E>, Serializable {
- private final NavigableSet<E> delegate;
-
- UnmodifiableNavigableSet(NavigableSet<E> delegate) {
- this.delegate = checkNotNull(delegate);
- }
-
- @Override
- protected SortedSet<E> delegate() {
- return Collections.unmodifiableSortedSet(delegate);
- }
+ /**
+ * Stop-gap measure since there is no bijection related type in Guava.
+ */
+ abstract static class InvertibleFunction<A, B> implements Function<A, B> {
+ abstract A invert(B b);
- @Override
- public E lower(E e) {
- return delegate.lower(e);
- }
+ public InvertibleFunction<B, A> inverse() {
+ return new InvertibleFunction<B, A>() {
+ @Override public A apply(B b) {
+ return InvertibleFunction.this.invert(b);
+ }
- @Override
- public E floor(E e) {
- return delegate.floor(e);
- }
+ @Override B invert(A a) {
+ return InvertibleFunction.this.apply(a);
+ }
- @Override
- public E ceiling(E e) {
- return delegate.ceiling(e);
+ // Not required per se, but just for good karma.
+ @Override public InvertibleFunction<A, B> inverse() {
+ return InvertibleFunction.this;
+ }
+ };
}
+ }
- @Override
- public E higher(E e) {
- return delegate.higher(e);
- }
+ private static class TransformedSet<A, B> extends AbstractSet<B> {
+ final Set<A> delegate;
+ final InvertibleFunction<A, B> bijection;
- @Override
- public E pollFirst() {
- throw new UnsupportedOperationException();
+ TransformedSet(Set<A> delegate, InvertibleFunction<A, B> bijection) {
+ this.delegate = delegate;
+ this.bijection = bijection;
}
- @Override
- public E pollLast() {
- throw new UnsupportedOperationException();
+ @Override public Iterator<B> iterator() {
+ return Iterators.transform(delegate.iterator(), bijection);
}
- private transient UnmodifiableNavigableSet<E> descendingSet;
-
- @Override
- public NavigableSet<E> descendingSet() {
- UnmodifiableNavigableSet<E> result = descendingSet;
- if (result == null) {
- result = descendingSet = new UnmodifiableNavigableSet<E>(
- delegate.descendingSet());
- result.descendingSet = this;
- }
- return result;
+ @Override public int size() {
+ return delegate.size();
}
- @Override
- public Iterator<E> descendingIterator() {
- return Iterators.unmodifiableIterator(delegate.descendingIterator());
+ @SuppressWarnings("unchecked") // unsafe, passed object *must* be B
+ @Override public boolean contains(Object o) {
+ B b = (B) o;
+ A a = bijection.invert(b);
+ /*
+ * Mathematically, Converter<A, B> defines a bijection between ALL A's
+ * on ALL B's. Here we concern ourselves with a subset
+ * of this relation: we only want the part that is defined by a *subset*
+ * of all A's (defined by that Set<A> delegate), and the image
+ * of *that* on B (which is this set). We don't care whether
+ * the converter is *not* a bijection for A's that are not in Set<A>
+ * or B's not in this Set<B>.
+ *
+ * We only want to return true if and only f the user passes a B instance
+ * that is contained in precisely in the image of Set<A>.
+ *
+ * The first test is whether the inverse image of this B is indeed
+ * in Set<A>. But we don't know whether that B belongs in this Set<B>
+ * or not; if not, the converter is free to return
+ * anything it wants, even an element of Set<A> (and this relationship
+ * is not part of the Set<A> <--> Set<B> bijection), and we must not
+ * be confused by that. So we have to do a final check to see if the
+ * image of that A is really equivalent to the passed B, which proves
+ * that the given B belongs indeed in the image of Set<A>.
+ */
+ return delegate.contains(a) && Objects.equal(bijection.apply(a), o);
}
- @Override
- public NavigableSet<E> subSet(
- E fromElement,
- boolean fromInclusive,
- E toElement,
- boolean toInclusive) {
- return unmodifiableNavigableSet(delegate.subSet(
- fromElement,
- fromInclusive,
- toElement,
- toInclusive));
+ @Override public boolean add(B b) {
+ return delegate.add(bijection.invert(b));
}
- @Override
- public NavigableSet<E> headSet(E toElement, boolean inclusive) {
- return unmodifiableNavigableSet(delegate.headSet(toElement, inclusive));
+ @SuppressWarnings("unchecked") // unsafe, passed object *must* be B
+ @Override public boolean remove(Object o) {
+ return contains(o) && delegate.remove(bijection.invert((B) o));
}
- @Override
- public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
- return unmodifiableNavigableSet(
- delegate.tailSet(fromElement, inclusive));
+ @Override public void clear() {
+ delegate.clear();
}
-
- private static final long serialVersionUID = 0;
- }
-
- /**
- * Returns a synchronized (thread-safe) navigable set backed by the specified
- * navigable set. In order to guarantee serial access, it is critical that
- * <b>all</b> access to the backing navigable set is accomplished
- * through the returned navigable set (or its views).
- *
- * <p>It is imperative that the user manually synchronize on the returned
- * sorted set when iterating over it or any of its {@code descendingSet},
- * {@code subSet}, {@code headSet}, or {@code tailSet} views. <pre> {@code
- *
- * NavigableSet<E> set = synchronizedNavigableSet(new TreeSet<E>());
- * ...
- * synchronized (set) {
- * // Must be in the synchronized block
- * Iterator<E> it = set.iterator();
- * while (it.hasNext()){
- * foo(it.next());
- * }
- * }}</pre>
- *
- * or: <pre> {@code
- *
- * NavigableSet<E> set = synchronizedNavigableSet(new TreeSet<E>());
- * NavigableSet<E> set2 = set.descendingSet().headSet(foo);
- * ...
- * synchronized (set) { // Note: set, not set2!!!
- * // Must be in the synchronized block
- * Iterator<E> it = set2.descendingIterator();
- * while (it.hasNext())
- * foo(it.next());
- * }
- * }}</pre>
- *
- * Failure to follow this advice may result in non-deterministic behavior.
- *
- * <p>The returned navigable set will be serializable if the specified
- * navigable set is serializable.
- *
- * @param navigableSet the navigable set to be "wrapped" in a synchronized
- * navigable set.
- * @return a synchronized view of the specified navigable set.
- * @since 13.0
- */
- @GwtIncompatible("NavigableSet")
- public static <E> NavigableSet<E> synchronizedNavigableSet(
- NavigableSet<E> navigableSet) {
- return Synchronized.navigableSet(navigableSet);
}
/**
* Remove each element in an iterable from a set.
*/
- static boolean removeAllImpl(Set<?> set, Iterator<?> iterator) {
+ static boolean removeAllImpl(Set<?> set, Iterable<?> iterable) {
+ // TODO(jlevy): Have ForwardingSet.standardRemoveAll() call this method.
boolean changed = false;
- while (iterator.hasNext()) {
- changed |= set.remove(iterator.next());
+ for (Object o : iterable) {
+ changed |= set.remove(o);
}
return changed;
}
-
- static boolean removeAllImpl(Set<?> set, Collection<?> collection) {
- checkNotNull(collection); // for GWT
- if (collection instanceof Multiset) {
- collection = ((Multiset<?>) collection).elementSet();
- }
- /*
- * AbstractSet.removeAll(List) has quadratic behavior if the list size
- * is just less than the set's size. We augment the test by
- * assuming that sets have fast contains() performance, and other
- * collections don't. See
- * http://code.google.com/p/guava-libraries/issues/detail?id=1013
- */
- if (collection instanceof Set && collection.size() > set.size()) {
- Iterator<?> setIterator = set.iterator();
- boolean changed = false;
- while (setIterator.hasNext()) {
- if (collection.contains(setIterator.next())) {
- changed = true;
- setIterator.remove();
- }
- }
- return changed;
- } else {
- return removeAllImpl(set, collection.iterator());
- }
- }
-
- @GwtIncompatible("NavigableSet")
- static class DescendingSet<E> extends ForwardingNavigableSet<E> {
- private final NavigableSet<E> forward;
-
- DescendingSet(NavigableSet<E> forward) {
- this.forward = forward;
- }
-
- @Override
- protected NavigableSet<E> delegate() {
- return forward;
- }
-
- @Override
- public E lower(E e) {
- return forward.higher(e);
- }
-
- @Override
- public E floor(E e) {
- return forward.ceiling(e);
- }
-
- @Override
- public E ceiling(E e) {
- return forward.floor(e);
- }
-
- @Override
- public E higher(E e) {
- return forward.lower(e);
- }
-
- @Override
- public E pollFirst() {
- return forward.pollLast();
- }
-
- @Override
- public E pollLast() {
- return forward.pollFirst();
- }
-
- @Override
- public NavigableSet<E> descendingSet() {
- return forward;
- }
-
- @Override
- public Iterator<E> descendingIterator() {
- return forward.iterator();
- }
-
- @Override
- public NavigableSet<E> subSet(
- E fromElement,
- boolean fromInclusive,
- E toElement,
- boolean toInclusive) {
- return forward.subSet(toElement, toInclusive, fromElement, fromInclusive).descendingSet();
- }
-
- @Override
- public NavigableSet<E> headSet(E toElement, boolean inclusive) {
- return forward.tailSet(toElement, inclusive).descendingSet();
- }
-
- @Override
- public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
- return forward.headSet(fromElement, inclusive).descendingSet();
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Comparator<? super E> comparator() {
- Comparator<? super E> forwardComparator = forward.comparator();
- if (forwardComparator == null) {
- return (Comparator) Ordering.natural().reverse();
- } else {
- return reverse(forwardComparator);
- }
- }
-
- // If we inline this, we get a javac error.
- private static <T> Ordering<T> reverse(Comparator<T> forward) {
- return Ordering.from(forward).reverse();
- }
-
- @Override
- public E first() {
- return forward.last();
- }
-
- @Override
- public SortedSet<E> headSet(E toElement) {
- return standardHeadSet(toElement);
- }
-
- @Override
- public E last() {
- return forward.first();
- }
-
- @Override
- public SortedSet<E> subSet(E fromElement, E toElement) {
- return standardSubSet(fromElement, toElement);
- }
-
- @Override
- public SortedSet<E> tailSet(E fromElement) {
- return standardTailSet(fromElement);
- }
-
- @Override
- public Iterator<E> iterator() {
- return forward.descendingIterator();
- }
-
- @Override
- public Object[] toArray() {
- return standardToArray();
- }
-
- @Override
- public <T> T[] toArray(T[] array) {
- return standardToArray(array);
- }
-
- @Override
- public String toString() {
- return standardToString();
- }
- }
-
- /**
- * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
- */
- static <T> SortedSet<T> cast(Iterable<T> iterable) {
- return (SortedSet<T>) iterable;
- }
}
diff --git a/guava/src/com/google/common/collect/SingletonImmutableBiMap.java b/guava/src/com/google/common/collect/SingletonImmutableBiMap.java
deleted file mode 100644
index 2b6f462..0000000
--- a/guava/src/com/google/common/collect/SingletonImmutableBiMap.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-import javax.annotation.Nullable;
-
-/**
- * Implementation of {@link ImmutableMap} with exactly one entry.
- *
- * @author Jesse Wilson
- * @author Kevin Bourrillion
- */
-@GwtCompatible(serializable = true, emulated = true)
-@SuppressWarnings("serial") // uses writeReplace(), not default serialization
-final class SingletonImmutableBiMap<K, V> extends ImmutableBiMap<K, V> {
-
- final transient K singleKey;
- final transient V singleValue;
-
- SingletonImmutableBiMap(K singleKey, V singleValue) {
- this.singleKey = singleKey;
- this.singleValue = singleValue;
- }
-
- private SingletonImmutableBiMap(K singleKey, V singleValue,
- ImmutableBiMap<V, K> inverse) {
- this.singleKey = singleKey;
- this.singleValue = singleValue;
- this.inverse = inverse;
- }
-
- SingletonImmutableBiMap(Entry<K, V> entry) {
- this(entry.getKey(), entry.getValue());
- }
-
- @Override public V get(@Nullable Object key) {
- return singleKey.equals(key) ? singleValue : null;
- }
-
- @Override
- public int size() {
- return 1;
- }
-
- @Override public boolean containsKey(@Nullable Object key) {
- return singleKey.equals(key);
- }
-
- @Override public boolean containsValue(@Nullable Object value) {
- return singleValue.equals(value);
- }
-
- @Override boolean isPartialView() {
- return false;
- }
-
- @Override
- ImmutableSet<Entry<K, V>> createEntrySet() {
- return ImmutableSet.of(Maps.immutableEntry(singleKey, singleValue));
- }
-
- @Override
- ImmutableSet<K> createKeySet() {
- return ImmutableSet.of(singleKey);
- }
-
- transient ImmutableBiMap<V, K> inverse;
-
- @Override
- public ImmutableBiMap<V, K> inverse() {
- // racy single-check idiom
- ImmutableBiMap<V, K> result = inverse;
- if (result == null) {
- return inverse = new SingletonImmutableBiMap<V, K>(
- singleValue, singleKey, this);
- } else {
- return result;
- }
- }
-}
diff --git a/guava/src/com/google/common/collect/SingletonImmutableList.java b/guava/src/com/google/common/collect/SingletonImmutableList.java
index 2e20c41..e546d2b 100644
--- a/guava/src/com/google/common/collect/SingletonImmutableList.java
+++ b/guava/src/com/google/common/collect/SingletonImmutableList.java
@@ -22,6 +22,7 @@ import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Preconditions;
import java.util.List;
+import java.util.NoSuchElementException;
import javax.annotation.Nullable;
@@ -55,7 +56,47 @@ final class SingletonImmutableList<E> extends ImmutableList<E> {
}
@Override public int lastIndexOf(@Nullable Object object) {
- return indexOf(object);
+ return element.equals(object) ? 0 : -1;
+ }
+
+ @Override public UnmodifiableListIterator<E> listIterator(final int start) {
+ Preconditions.checkPositionIndex(start, 1);
+ return new UnmodifiableListIterator<E>() {
+
+ boolean hasNext = start == 0;
+
+ @Override public boolean hasNext() {
+ return hasNext;
+ }
+
+ @Override public boolean hasPrevious() {
+ return !hasNext;
+ }
+
+ @Override public E next() {
+ if (!hasNext) {
+ throw new NoSuchElementException();
+ }
+ hasNext = false;
+ return element;
+ }
+
+ @Override public int nextIndex() {
+ return hasNext ? 0 : 1;
+ }
+
+ @Override public E previous() {
+ if (hasNext) {
+ throw new NoSuchElementException();
+ }
+ hasNext = true;
+ return element;
+ }
+
+ @Override public int previousIndex() {
+ return hasNext ? -1 : 0;
+ }
+ };
}
@Override
@@ -76,7 +117,7 @@ final class SingletonImmutableList<E> extends ImmutableList<E> {
return element.equals(object);
}
- @Override public boolean equals(@Nullable Object object) {
+ @Override public boolean equals(Object object) {
if (object == this) {
return true;
}
diff --git a/guava/src/com/google/common/collect/SingletonImmutableMap.java b/guava/src/com/google/common/collect/SingletonImmutableMap.java
new file mode 100644
index 0000000..9dd6e60
--- /dev/null
+++ b/guava/src/com/google/common/collect/SingletonImmutableMap.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2008 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * Implementation of {@link ImmutableMap} with exactly one entry.
+ *
+ * @author Jesse Wilson
+ * @author Kevin Bourrillion
+ */
+@GwtCompatible(serializable = true, emulated = true)
+@SuppressWarnings("serial") // uses writeReplace(), not default serialization
+final class SingletonImmutableMap<K, V> extends ImmutableMap<K, V> {
+
+ final transient K singleKey;
+ final transient V singleValue;
+
+ private transient Entry<K, V> entry;
+
+ SingletonImmutableMap(K singleKey, V singleValue) {
+ this.singleKey = singleKey;
+ this.singleValue = singleValue;
+ }
+
+ SingletonImmutableMap(Entry<K, V> entry) {
+ this.entry = entry;
+ this.singleKey = entry.getKey();
+ this.singleValue = entry.getValue();
+ }
+
+ private Entry<K, V> entry() {
+ Entry<K, V> e = entry;
+ return (e == null)
+ ? (entry = Maps.immutableEntry(singleKey, singleValue)) : e;
+ }
+
+ @Override public V get(@Nullable Object key) {
+ return singleKey.equals(key) ? singleValue : null;
+ }
+
+ @Override
+ public int size() {
+ return 1;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public boolean containsKey(@Nullable Object key) {
+ return singleKey.equals(key);
+ }
+
+ @Override public boolean containsValue(@Nullable Object value) {
+ return singleValue.equals(value);
+ }
+
+ @Override boolean isPartialView() {
+ return false;
+ }
+
+ private transient ImmutableSet<Entry<K, V>> entrySet;
+
+ @Override public ImmutableSet<Entry<K, V>> entrySet() {
+ ImmutableSet<Entry<K, V>> es = entrySet;
+ return (es == null) ? (entrySet = ImmutableSet.of(entry())) : es;
+ }
+
+ private transient ImmutableSet<K> keySet;
+
+ @Override public ImmutableSet<K> keySet() {
+ ImmutableSet<K> ks = keySet;
+ return (ks == null) ? (keySet = ImmutableSet.of(singleKey)) : ks;
+ }
+
+ private transient ImmutableCollection<V> values;
+
+ @Override public ImmutableCollection<V> values() {
+ ImmutableCollection<V> v = values;
+ return (v == null) ? (values = new Values<V>(singleValue)) : v;
+ }
+
+ @SuppressWarnings("serial") // uses writeReplace(), not default serialization
+ private static class Values<V> extends ImmutableCollection<V> {
+ final V singleValue;
+
+ Values(V singleValue) {
+ this.singleValue = singleValue;
+ }
+
+ @Override public boolean contains(Object object) {
+ return singleValue.equals(object);
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public int size() {
+ return 1;
+ }
+
+ @Override public UnmodifiableIterator<V> iterator() {
+ return Iterators.singletonIterator(singleValue);
+ }
+
+ @Override boolean isPartialView() {
+ return true;
+ }
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof Map) {
+ Map<?, ?> that = (Map<?, ?>) object;
+ if (that.size() != 1) {
+ return false;
+ }
+ Entry<?, ?> entry = that.entrySet().iterator().next();
+ return singleKey.equals(entry.getKey())
+ && singleValue.equals(entry.getValue());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return singleKey.hashCode() ^ singleValue.hashCode();
+ }
+
+ @Override public String toString() {
+ return new StringBuilder()
+ .append('{')
+ .append(singleKey.toString())
+ .append('=')
+ .append(singleValue.toString())
+ .append('}')
+ .toString();
+ }
+}
diff --git a/guava/src/com/google/common/collect/SingletonImmutableTable.java b/guava/src/com/google/common/collect/SingletonImmutableTable.java
index e6e850c..4e33aea 100644
--- a/guava/src/com/google/common/collect/SingletonImmutableTable.java
+++ b/guava/src/com/google/common/collect/SingletonImmutableTable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Guava Authors
+ * Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@ import javax.annotation.Nullable;
/**
* An implementation of {@link ImmutableTable} that holds a single cell.
*
- * @author Gregory Kick
+ * @author gak@google.com (Gregory Kick)
*/
@GwtCompatible
final class SingletonImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
@@ -119,7 +119,7 @@ final class SingletonImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
@Override public boolean equals(@Nullable Object obj) {
if (obj == this) {
return true;
- } else if (obj instanceof Table) {
+ } else if (obj instanceof Table<?, ?, ?>) {
Table<?, ?, ?> that = (Table<?, ?, ?>) obj;
if (that.size() == 1) {
Cell<?, ?, ?> thatCell = that.cellSet().iterator().next();
diff --git a/guava/src/com/google/common/collect/SortedIterables.java b/guava/src/com/google/common/collect/SortedIterables.java
index 2158e9f..8089b10 100644
--- a/guava/src/com/google/common/collect/SortedIterables.java
+++ b/guava/src/com/google/common/collect/SortedIterables.java
@@ -17,8 +17,16 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Function;
+import com.google.common.collect.Multiset.Entry;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
import java.util.SortedSet;
/**
@@ -39,22 +47,149 @@ final class SortedIterables {
checkNotNull(elements);
Comparator<?> comparator2;
if (elements instanceof SortedSet) {
- comparator2 = comparator((SortedSet<?>) elements);
+ SortedSet<?> sortedSet = (SortedSet<?>) elements;
+ comparator2 = sortedSet.comparator();
+ if (comparator2 == null) {
+ comparator2 = (Comparator) Ordering.natural();
+ }
} else if (elements instanceof SortedIterable) {
comparator2 = ((SortedIterable<?>) elements).comparator();
} else {
- return false;
+ comparator2 = null;
}
return comparator.equals(comparator2);
}
+ /**
+ * Returns a sorted collection of the unique elements according to the specified comparator. Does
+ * not check for null.
+ */
+ @SuppressWarnings("unchecked")
+ public static <E> Collection<E> sortedUnique(
+ Comparator<? super E> comparator, Iterator<E> elements) {
+ SortedSet<E> sortedSet = Sets.newTreeSet(comparator);
+ Iterators.addAll(sortedSet, elements);
+ return sortedSet;
+ }
+
+ /**
+ * Returns a sorted collection of the unique elements according to the specified comparator. Does
+ * not check for null.
+ */
@SuppressWarnings("unchecked")
- // if sortedSet.comparator() is null, the set must be naturally ordered
- public static <E> Comparator<? super E> comparator(SortedSet<E> sortedSet) {
- Comparator<? super E> result = sortedSet.comparator();
- if (result == null) {
- result = (Comparator<? super E>) Ordering.natural();
+ public static <E> Collection<E> sortedUnique(
+ Comparator<? super E> comparator, Iterable<E> elements) {
+ if (elements instanceof Multiset) {
+ elements = ((Multiset<E>) elements).elementSet();
+ }
+ if (elements instanceof Set) {
+ if (hasSameComparator(comparator, elements)) {
+ return (Set<E>) elements;
+ }
+ List<E> list = Lists.newArrayList(elements);
+ Collections.sort(list, comparator);
+ return list;
+ }
+ E[] array = (E[]) Iterables.toArray(elements);
+ if (!hasSameComparator(comparator, elements)) {
+ Arrays.sort(array, comparator);
+ }
+ return uniquifySortedArray(comparator, array);
+ }
+
+ private static <E> Collection<E> uniquifySortedArray(
+ Comparator<? super E> comparator, E[] array) {
+ if (array.length == 0) {
+ return Collections.emptySet();
}
- return result;
+ int length = 1;
+ for (int i = 1; i < array.length; i++) {
+ int cmp = comparator.compare(array[i], array[length - 1]);
+ if (cmp != 0) {
+ array[length++] = array[i];
+ }
+ }
+ if (length < array.length) {
+ array = ObjectArrays.arraysCopyOf(array, length);
+ }
+ return Arrays.asList(array);
+ }
+
+ /**
+ * Returns a collection of multiset entries representing the counts of the distinct elements, in
+ * sorted order. Does not check for null.
+ */
+ public static <E> Collection<Multiset.Entry<E>> sortedCounts(
+ Comparator<? super E> comparator, Iterator<E> elements) {
+ TreeMultiset<E> multiset = TreeMultiset.create(comparator);
+ Iterators.addAll(multiset, elements);
+ return multiset.entrySet();
+ }
+
+ /**
+ * Returns a collection of multiset entries representing the counts of the distinct elements, in
+ * sorted order. Does not check for null.
+ */
+ public static <E> Collection<Multiset.Entry<E>> sortedCounts(
+ Comparator<? super E> comparator, Iterable<E> elements) {
+ if (elements instanceof Multiset) {
+ Multiset<E> multiset = (Multiset<E>) elements;
+ if (hasSameComparator(comparator, elements)) {
+ return multiset.entrySet();
+ }
+ List<Multiset.Entry<E>> entries = Lists.newArrayList(multiset.entrySet());
+ Collections.sort(
+ entries, Ordering.from(comparator).onResultOf(new Function<Multiset.Entry<E>, E>() {
+ @Override
+ public E apply(Entry<E> entry) {
+ return entry.getElement();
+ }
+ }));
+ return entries;
+ } else if (elements instanceof Set) { // known distinct
+ Collection<E> sortedElements;
+ if (hasSameComparator(comparator, elements)) {
+ sortedElements = (Collection<E>) elements;
+ } else {
+ List<E> list = Lists.newArrayList(elements);
+ Collections.sort(list, comparator);
+ sortedElements = list;
+ }
+ return singletonEntries(sortedElements);
+ } else if (hasSameComparator(comparator, elements)) {
+ E current = null;
+ int currentCount = 0;
+ List<Multiset.Entry<E>> sortedEntries = Lists.newArrayList();
+ for (E e : elements) {
+ if (currentCount > 0) {
+ if (comparator.compare(current, e) == 0) {
+ currentCount++;
+ } else {
+ sortedEntries.add(Multisets.immutableEntry(current, currentCount));
+ current = e;
+ currentCount = 1;
+ }
+ } else {
+ current = e;
+ currentCount = 1;
+ }
+ }
+ if (currentCount > 0) {
+ sortedEntries.add(Multisets.immutableEntry(current, currentCount));
+ }
+ return sortedEntries;
+ }
+ TreeMultiset<E> multiset = TreeMultiset.create(comparator);
+ Iterables.addAll(multiset, elements);
+ return multiset.entrySet();
+ }
+
+ static <E> Collection<Multiset.Entry<E>> singletonEntries(Collection<E> set) {
+ return Collections2.transform(set, new Function<E, Multiset.Entry<E>>() {
+ @Override
+ public Entry<E> apply(E elem) {
+ return Multisets.immutableEntry(elem, 1);
+ }
+ });
}
}
diff --git a/guava/src/com/google/common/collect/SortedLists.java b/guava/src/com/google/common/collect/SortedLists.java
index 6fc0d71..afcec59 100644
--- a/guava/src/com/google/common/collect/SortedLists.java
+++ b/guava/src/com/google/common/collect/SortedLists.java
@@ -143,7 +143,7 @@ import javax.annotation.Nullable;
*/
NEXT_LOWER {
@Override
- int resultIndex(int higherIndex) {
+ <E> int resultIndex(int higherIndex) {
return higherIndex - 1;
}
},
@@ -153,7 +153,7 @@ import javax.annotation.Nullable;
*/
NEXT_HIGHER {
@Override
- public int resultIndex(int higherIndex) {
+ public <E> int resultIndex(int higherIndex) {
return higherIndex;
}
},
@@ -171,12 +171,12 @@ import javax.annotation.Nullable;
*/
INVERTED_INSERTION_INDEX {
@Override
- public int resultIndex(int higherIndex) {
+ public <E> int resultIndex(int higherIndex) {
return ~higherIndex;
}
};
- abstract int resultIndex(int higherIndex);
+ abstract <E> int resultIndex(int higherIndex);
}
/**
@@ -200,7 +200,7 @@ import javax.annotation.Nullable;
* KeyAbsentBehavior)} using {@link Ordering#natural}.
*/
public static <E, K extends Comparable> int binarySearch(List<E> list,
- Function<? super E, K> keyFunction, @Nullable K key, KeyPresentBehavior presentBehavior,
+ Function<? super E, K> keyFunction, K key, KeyPresentBehavior presentBehavior,
KeyAbsentBehavior absentBehavior) {
return binarySearch(
list,
@@ -221,7 +221,7 @@ import javax.annotation.Nullable;
public static <E, K> int binarySearch(
List<E> list,
Function<? super E, K> keyFunction,
- @Nullable K key,
+ K key,
Comparator<? super K> keyComparator,
KeyPresentBehavior presentBehavior,
KeyAbsentBehavior absentBehavior) {
diff --git a/guava/src/com/google/common/collect/SortedMapDifference.java b/guava/src/com/google/common/collect/SortedMapDifference.java
index 07f75ee..f44aa1a 100644
--- a/guava/src/com/google/common/collect/SortedMapDifference.java
+++ b/guava/src/com/google/common/collect/SortedMapDifference.java
@@ -16,6 +16,7 @@
package com.google.common.collect;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import java.util.SortedMap;
@@ -26,6 +27,7 @@ import java.util.SortedMap;
* @author Louis Wasserman
* @since 8.0
*/
+@Beta
@GwtCompatible
public interface SortedMapDifference<K, V> extends MapDifference<K, V> {
diff --git a/guava/src/com/google/common/collect/SortedMaps.java b/guava/src/com/google/common/collect/SortedMaps.java
new file mode 100644
index 0000000..0055cbd
--- /dev/null
+++ b/guava/src/com/google/common/collect/SortedMaps.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2010 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.SortedMap;
+
+import javax.annotation.Nullable;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Maps.EntryTransformer;
+
+/**
+ * Static utility methods pertaining to {@link SortedMap} instances.
+ *
+ * @author Louis Wasserman
+ * @since 8.0
+ * @deprecated Use the identical methods in {@link Maps}. This class is
+ * scheduled for deletion from Guava in Guava release 12.0.
+ */
+@Beta
+@Deprecated
+@GwtCompatible
+public final class SortedMaps {
+ private SortedMaps() {}
+
+ /**
+ * Returns a view of a sorted map where each value is transformed by a
+ * function. All other properties of the map, such as iteration order, are
+ * left intact. For example, the code: <pre> {@code
+ *
+ * SortedMap<String, Integer> map = ImmutableSortedMap.of("a", 4, "b", 9);
+ * Function<Integer, Double> sqrt =
+ * new Function<Integer, Double>() {
+ * public Double apply(Integer in) {
+ * return Math.sqrt((int) in);
+ * }
+ * };
+ * SortedMap<String, Double> transformed =
+ * Maps.transformSortedValues(map, sqrt);
+ * System.out.println(transformed);}</pre>
+ *
+ * ... prints {@code {a=2.0, b=3.0}}.
+ *
+ * <p>Changes in the underlying map are reflected in this view. Conversely,
+ * this view supports removal operations, and these are reflected in the
+ * underlying map.
+ *
+ * <p>It's acceptable for the underlying map to contain null keys, and even
+ * null values provided that the function is capable of accepting null input.
+ * The transformed map might contain null values, if the function sometimes
+ * gives a null result.
+ *
+ * <p>The returned map is not thread-safe or serializable, even if the
+ * underlying map is.
+ *
+ * <p>The function is applied lazily, invoked when needed. This is necessary
+ * for the returned map to be a view, but it means that the function will be
+ * applied many times for bulk operations like {@link Map#containsValue} and
+ * {@code Map.toString()}. For this to perform well, {@code function} should
+ * be fast. To avoid lazy evaluation when the returned map doesn't need to be
+ * a view, copy the returned map into a new map of your choosing.
+ *
+ * @deprecated Use {@link Maps#transformValues(SortedMap, Function)}
+ */
+ @Deprecated public static <K, V1, V2> SortedMap<K, V2> transformValues(
+ SortedMap<K, V1> fromMap, final Function<? super V1, V2> function) {
+ return Maps.transformValues(fromMap, function);
+ }
+
+ /**
+ * Returns a view of a sorted map whose values are derived from the original
+ * sorted map's entries. In contrast to {@link #transformValues}, this
+ * method's entry-transformation logic may depend on the key as well as the
+ * value.
+ *
+ * <p>All other properties of the transformed map, such as iteration order,
+ * are left intact. For example, the code: <pre> {@code
+ *
+ * Map<String, Boolean> options =
+ * ImmutableSortedMap.of("verbose", true, "sort", false);
+ * EntryTransformer<String, Boolean, String> flagPrefixer =
+ * new EntryTransformer<String, Boolean, String>() {
+ * public String transformEntry(String key, Boolean value) {
+ * return value ? key : "yes" + key;
+ * }
+ * };
+ * SortedMap<String, String> transformed =
+ * LabsMaps.transformSortedEntries(options, flagPrefixer);
+ * System.out.println(transformed);}</pre>
+ *
+ * ... prints {@code {sort=yessort, verbose=verbose}}.
+ *
+ * <p>Changes in the underlying map are reflected in this view. Conversely,
+ * this view supports removal operations, and these are reflected in the
+ * underlying map.
+ *
+ * <p>It's acceptable for the underlying map to contain null keys and null
+ * values provided that the transformer is capable of accepting null inputs.
+ * The transformed map might contain null values if the transformer sometimes
+ * gives a null result.
+ *
+ * <p>The returned map is not thread-safe or serializable, even if the
+ * underlying map is.
+ *
+ * <p>The transformer is applied lazily, invoked when needed. This is
+ * necessary for the returned map to be a view, but it means that the
+ * transformer will be applied many times for bulk operations like {@link
+ * Map#containsValue} and {@link Object#toString}. For this to perform well,
+ * {@code transformer} should be fast. To avoid lazy evaluation when the
+ * returned map doesn't need to be a view, copy the returned map into a new
+ * map of your choosing.
+ *
+ * <p><b>Warning:</b> This method assumes that for any instance {@code k} of
+ * {@code EntryTransformer} key type {@code K}, {@code k.equals(k2)} implies
+ * that {@code k2} is also of type {@code K}. Using an {@code
+ * EntryTransformer} key type for which this may not hold, such as {@code
+ * ArrayList}, may risk a {@code ClassCastException} when calling methods on
+ * the transformed map.
+ *
+ * @deprecated Use {@link Maps#transformEntries(SortedMap, EntryTransformer)}
+ */
+ @Deprecated public static <K, V1, V2> SortedMap<K, V2> transformEntries(
+ final SortedMap<K, V1> fromMap,
+ EntryTransformer<? super K, ? super V1, V2> transformer) {
+ return Maps.transformEntries(fromMap, transformer);
+ }
+
+ /**
+ * Computes the difference between two sorted maps, using the comparator of
+ * the left map, or {@code Ordering.natural()} if the left map uses the
+ * natural ordering of its elements. This difference is an immutable snapshot
+ * of the state of the maps at the time this method is called. It will never
+ * change, even if the maps change at a later time.
+ *
+ * <p>Since this method uses {@code TreeMap} instances internally, the keys of
+ * the right map must all compare as distinct according to the comparator
+ * of the left map.
+ *
+ * <p><b>Note:</b>If you only need to know whether two sorted maps have the
+ * same mappings, call {@code left.equals(right)} instead of this method.
+ *
+ * @param left the map to treat as the "left" map for purposes of comparison
+ * @param right the map to treat as the "right" map for purposes of comparison
+ * @return the difference between the two maps
+ * @deprecated Use {@link Maps#difference(SortedMap, Map)}
+ */
+ @Deprecated public static <K, V> SortedMapDifference<K, V> difference(
+ SortedMap<K, ? extends V> left, Map<? extends K, ? extends V> right) {
+ return Maps.difference(left, right);
+ }
+
+ /**
+ * Returns the specified comparator if not null; otherwise returns {@code
+ * Ordering.natural()}. This method is an abomination of generics; the only
+ * purpose of this method is to contain the ugly type-casting in one place.
+ */
+ @SuppressWarnings("unchecked")
+ static <E> Comparator<? super E> orNaturalOrder(
+ @Nullable Comparator<? super E> comparator) {
+ if (comparator != null) { // can't use ? : because of javac bug 5080917
+ return comparator;
+ }
+ return (Comparator<E>) Ordering.natural();
+ }
+
+ /**
+ * Returns a sorted map containing the mappings in {@code unfiltered} whose
+ * keys satisfy a predicate. The returned map is a live view of {@code
+ * unfiltered}; changes to one affect the other.
+ *
+ * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
+ * values()} views have iterators that don't support {@code remove()}, but all
+ * other methods are supported by the map and its views. When given a key that
+ * doesn't satisfy the predicate, the map's {@code put()} and {@code putAll()}
+ * methods throw an {@link IllegalArgumentException}.
+ *
+ * <p>When methods such as {@code removeAll()} and {@code clear()} are called
+ * on the filtered map or its views, only mappings whose keys satisfy the
+ * filter will be removed from the underlying map.
+ *
+ * <p>The returned map isn't threadsafe or serializable, even if {@code
+ * unfiltered} is.
+ *
+ * <p>Many of the filtered map's methods, such as {@code size()},
+ * iterate across every key/value mapping in the underlying map and determine
+ * which satisfy the filter. When a live view is <i>not</i> needed, it may be
+ * faster to copy the filtered map and use the copy.
+ *
+ * <p><b>Warning:</b> {@code keyPredicate} must be <i>consistent with
+ * equals</i>, as documented at {@link Predicate#apply}. Do not provide a
+ * predicate such as {@code Predicates.instanceOf(ArrayList.class)}, which is
+ * inconsistent with equals.
+ */
+ @GwtIncompatible("untested")
+ public static <K, V> SortedMap<K, V> filterKeys(
+ SortedMap<K, V> unfiltered, final Predicate<? super K> keyPredicate) {
+ // TODO: Return a subclass of Maps.FilteredKeyMap for slightly better
+ // performance.
+ checkNotNull(keyPredicate);
+ Predicate<Entry<K, V>> entryPredicate = new Predicate<Entry<K, V>>() {
+ @Override
+ public boolean apply(Entry<K, V> input) {
+ return keyPredicate.apply(input.getKey());
+ }
+ };
+ return filterEntries(unfiltered, entryPredicate);
+ }
+
+ /**
+ * Returns a sorted map containing the mappings in {@code unfiltered} whose
+ * values satisfy a predicate. The returned map is a live view of {@code
+ * unfiltered}; changes to one affect the other.
+ *
+ * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
+ * values()} views have iterators that don't support {@code remove()}, but all
+ * other methods are supported by the map and its views. When given a value
+ * that doesn't satisfy the predicate, the map's {@code put()}, {@code
+ * putAll()}, and {@link Entry#setValue} methods throw an {@link
+ * IllegalArgumentException}.
+ *
+ * <p>When methods such as {@code removeAll()} and {@code clear()} are called
+ * on the filtered map or its views, only mappings whose values satisfy the
+ * filter will be removed from the underlying map.
+ *
+ * <p>The returned map isn't threadsafe or serializable, even if {@code
+ * unfiltered} is.
+ *
+ * <p>Many of the filtered map's methods, such as {@code size()},
+ * iterate across every key/value mapping in the underlying map and determine
+ * which satisfy the filter. When a live view is <i>not</i> needed, it may be
+ * faster to copy the filtered map and use the copy.
+ *
+ * <p><b>Warning:</b> {@code valuePredicate} must be <i>consistent with
+ * equals</i>, as documented at {@link Predicate#apply}. Do not provide a
+ * predicate such as {@code Predicates.instanceOf(ArrayList.class)}, which is
+ * inconsistent with equals.
+ */
+ @GwtIncompatible("untested")
+ public static <K, V> SortedMap<K, V> filterValues(
+ SortedMap<K, V> unfiltered, final Predicate<? super V> valuePredicate) {
+ checkNotNull(valuePredicate);
+ Predicate<Entry<K, V>> entryPredicate =
+ new Predicate<Entry<K, V>>() {
+ @Override
+ public boolean apply(Entry<K, V> input) {
+ return valuePredicate.apply(input.getValue());
+ }
+ };
+ return filterEntries(unfiltered, entryPredicate);
+ }
+
+ /**
+ * Returns a sorted map containing the mappings in {@code unfiltered} that
+ * satisfy a predicate. The returned map is a live view of {@code unfiltered};
+ * changes to one affect the other.
+ *
+ * <p>The resulting map's {@code keySet()}, {@code entrySet()}, and {@code
+ * values()} views have iterators that don't support {@code remove()}, but all
+ * other methods are supported by the map and its views. When given a
+ * key/value pair that doesn't satisfy the predicate, the map's {@code put()}
+ * and {@code putAll()} methods throw an {@link IllegalArgumentException}.
+ * Similarly, the map's entries have a {@link Entry#setValue} method that
+ * throws an {@link IllegalArgumentException} when the existing key and the
+ * provided value don't satisfy the predicate.
+ *
+ * <p>When methods such as {@code removeAll()} and {@code clear()} are called
+ * on the filtered map or its views, only mappings that satisfy the filter
+ * will be removed from the underlying map.
+ *
+ * <p>The returned map isn't threadsafe or serializable, even if {@code
+ * unfiltered} is.
+ *
+ * <p>Many of the filtered map's methods, such as {@code size()},
+ * iterate across every key/value mapping in the underlying map and determine
+ * which satisfy the filter. When a live view is <i>not</i> needed, it may be
+ * faster to copy the filtered map and use the copy.
+ *
+ * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with
+ * equals</i>, as documented at {@link Predicate#apply}.
+ */
+ @GwtIncompatible("untested")
+ public static <K, V> SortedMap<K, V> filterEntries(
+ SortedMap<K, V> unfiltered,
+ Predicate<? super Entry<K, V>> entryPredicate) {
+ checkNotNull(entryPredicate);
+ return (unfiltered instanceof FilteredSortedMap)
+ ? filterFiltered((FilteredSortedMap<K, V>) unfiltered, entryPredicate)
+ : new FilteredSortedMap<K, V>(checkNotNull(unfiltered), entryPredicate);
+ }
+
+ /**
+ * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when
+ * filtering a filtered sorted map.
+ */
+ private static <K, V> SortedMap<K, V> filterFiltered(
+ FilteredSortedMap<K, V> map,
+ Predicate<? super Entry<K, V>> entryPredicate) {
+ Predicate<Entry<K, V>> predicate
+ = Predicates.and(map.predicate, entryPredicate);
+ return new FilteredSortedMap<K, V>(map.sortedMap(), predicate);
+ }
+
+ private static class FilteredSortedMap<K, V>
+ extends Maps.FilteredEntryMap<K, V> implements SortedMap<K, V> {
+
+ FilteredSortedMap(SortedMap<K, V> unfiltered,
+ Predicate<? super Entry<K, V>> entryPredicate) {
+ super(unfiltered, entryPredicate);
+ }
+
+ SortedMap<K, V> sortedMap() {
+ return (SortedMap<K, V>) unfiltered;
+ }
+
+ @Override public Comparator<? super K> comparator() {
+ return sortedMap().comparator();
+ }
+
+ @Override public K firstKey() {
+ // correctly throws NoSuchElementException when filtered map is empty.
+ return keySet().iterator().next();
+ }
+
+ @Override public K lastKey() {
+ SortedMap<K, V> headMap = sortedMap();
+ while (true) {
+ // correctly throws NoSuchElementException when filtered map is empty.
+ K key = headMap.lastKey();
+ if (apply(key, unfiltered.get(key))) {
+ return key;
+ }
+ headMap = sortedMap().headMap(key);
+ }
+ }
+
+ @Override public SortedMap<K, V> headMap(K toKey) {
+ return new FilteredSortedMap<K, V>(sortedMap().headMap(toKey), predicate);
+ }
+
+ @Override public SortedMap<K, V> subMap(K fromKey, K toKey) {
+ return new FilteredSortedMap<K, V>(
+ sortedMap().subMap(fromKey, toKey), predicate);
+ }
+
+ @Override public SortedMap<K, V> tailMap(K fromKey) {
+ return new FilteredSortedMap<K, V>(
+ sortedMap().tailMap(fromKey), predicate);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/SortedMultiset.java b/guava/src/com/google/common/collect/SortedMultiset.java
index 9e14a80..0713151 100644
--- a/guava/src/com/google/common/collect/SortedMultiset.java
+++ b/guava/src/com/google/common/collect/SortedMultiset.java
@@ -22,7 +22,7 @@ import com.google.common.annotations.GwtCompatible;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
-import java.util.NavigableSet;
+import java.util.SortedSet;
/**
* A {@link Multiset} which maintains the ordering of its elements, according to
@@ -36,16 +36,12 @@ import java.util.NavigableSet;
* resulting multiset will violate the {@link Collection} contract, which it is
* specified in terms of {@link Object#equals}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset">
- * {@code Multiset}</a>.
- *
* @author Louis Wasserman
* @since 11.0
*/
@Beta
-@GwtCompatible(emulated = true)
-public interface SortedMultiset<E> extends SortedMultisetBridge<E>, SortedIterable<E> {
+@GwtCompatible
+public interface SortedMultiset<E> extends Multiset<E>, SortedIterable<E> {
/**
* Returns the comparator that orders this multiset, or
* {@link Ordering#natural()} if the natural ordering of the elements is used.
@@ -77,11 +73,9 @@ public interface SortedMultiset<E> extends SortedMultisetBridge<E>, SortedIterab
Entry<E> pollLastEntry();
/**
- * Returns a {@link NavigableSet} view of the distinct elements in this multiset.
- *
- * @since 14.0 (present with return type {@code SortedSet} since 11.0)
+ * Returns a {@link SortedSet} view of the distinct elements in this multiset.
*/
- @Override NavigableSet<E> elementSet();
+ @Override SortedSet<E> elementSet();
/**
* {@inheritDoc}
diff --git a/guava/src/com/google/common/collect/SortedMultisetBridge.java b/guava/src/com/google/common/collect/SortedMultisetBridge.java
deleted file mode 100644
index 669b54d..0000000
--- a/guava/src/com/google/common/collect/SortedMultisetBridge.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import java.util.SortedSet;
-
-/**
- * Superinterface of {@link SortedMultiset} to introduce a bridge method for
- * {@code elementSet()}, to ensure binary compatibility with older Guava versions
- * that specified {@code elementSet()} to return {@code SortedSet}.
- *
- * @author Louis Wasserman
- */
-interface SortedMultisetBridge<E> extends Multiset<E> {
- @Override
- SortedSet<E> elementSet();
-}
diff --git a/guava/src/com/google/common/collect/SortedMultisets.java b/guava/src/com/google/common/collect/SortedMultisets.java
index 1055664..ff18b74 100644
--- a/guava/src/com/google/common/collect/SortedMultisets.java
+++ b/guava/src/com/google/common/collect/SortedMultisets.java
@@ -1,12 +1,12 @@
/*
* Copyright (C) 2011 The Guava Authors
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -16,28 +16,22 @@
package com.google.common.collect;
-import static com.google.common.collect.BoundType.CLOSED;
-import static com.google.common.collect.BoundType.OPEN;
-
import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
import com.google.common.collect.Multiset.Entry;
import java.util.Comparator;
import java.util.Iterator;
-import java.util.NavigableSet;
import java.util.NoSuchElementException;
+import java.util.Set;
import java.util.SortedSet;
-import javax.annotation.Nullable;
-
/**
* Provides static utility methods for creating and working with
* {@link SortedMultiset} instances.
- *
+ *
* @author Louis Wasserman
*/
-@GwtCompatible(emulated = true)
+@GwtCompatible
final class SortedMultisets {
private SortedMultisets() {
}
@@ -45,32 +39,26 @@ final class SortedMultisets {
/**
* A skeleton implementation for {@link SortedMultiset#elementSet}.
*/
- static class ElementSet<E> extends Multisets.ElementSet<E> implements
+ static abstract class ElementSet<E> extends Multisets.ElementSet<E> implements
SortedSet<E> {
- private final SortedMultiset<E> multiset;
-
- ElementSet(SortedMultiset<E> multiset) {
- this.multiset = multiset;
- }
-
- @Override final SortedMultiset<E> multiset() {
- return multiset;
- }
+ @Override abstract SortedMultiset<E> multiset();
@Override public Comparator<? super E> comparator() {
return multiset().comparator();
}
@Override public SortedSet<E> subSet(E fromElement, E toElement) {
- return multiset().subMultiset(fromElement, CLOSED, toElement, OPEN).elementSet();
+ return multiset().subMultiset(fromElement, BoundType.CLOSED, toElement,
+ BoundType.OPEN).elementSet();
}
@Override public SortedSet<E> headSet(E toElement) {
- return multiset().headMultiset(toElement, OPEN).elementSet();
+ return multiset().headMultiset(toElement, BoundType.OPEN).elementSet();
}
@Override public SortedSet<E> tailSet(E fromElement) {
- return multiset().tailMultiset(fromElement, CLOSED).elementSet();
+ return multiset().tailMultiset(fromElement, BoundType.CLOSED)
+ .elementSet();
}
@Override public E first() {
@@ -82,84 +70,127 @@ final class SortedMultisets {
}
}
+ private static <E> E getElementOrThrow(Entry<E> entry) {
+ if (entry == null) {
+ throw new NoSuchElementException();
+ }
+ return entry.getElement();
+ }
+
/**
- * A skeleton navigable implementation for {@link SortedMultiset#elementSet}.
+ * A skeleton implementation of a descending multiset. Only needs
+ * {@code forwardMultiset()} and {@code entryIterator()}.
*/
- @GwtIncompatible("Navigable")
- static class NavigableElementSet<E> extends ElementSet<E> implements NavigableSet<E> {
- NavigableElementSet(SortedMultiset<E> multiset) {
- super(multiset);
+ static abstract class DescendingMultiset<E> extends ForwardingMultiset<E>
+ implements SortedMultiset<E> {
+ abstract SortedMultiset<E> forwardMultiset();
+
+ private transient Comparator<? super E> comparator;
+
+ @Override public Comparator<? super E> comparator() {
+ Comparator<? super E> result = comparator;
+ if (result == null) {
+ return comparator =
+ Ordering.from(forwardMultiset().comparator()).<E>reverse();
+ }
+ return result;
}
- @Override
- public E lower(E e) {
- return getElementOrNull(multiset().headMultiset(e, OPEN).lastEntry());
+ private transient SortedSet<E> elementSet;
+
+ @Override public SortedSet<E> elementSet() {
+ SortedSet<E> result = elementSet;
+ if (result == null) {
+ return elementSet = new SortedMultisets.ElementSet<E>() {
+ @Override SortedMultiset<E> multiset() {
+ return DescendingMultiset.this;
+ }
+ };
+ }
+ return result;
}
- @Override
- public E floor(E e) {
- return getElementOrNull(multiset().headMultiset(e, CLOSED).lastEntry());
+ @Override public Entry<E> pollFirstEntry() {
+ return forwardMultiset().pollLastEntry();
}
- @Override
- public E ceiling(E e) {
- return getElementOrNull(multiset().tailMultiset(e, CLOSED).firstEntry());
+ @Override public Entry<E> pollLastEntry() {
+ return forwardMultiset().pollFirstEntry();
}
- @Override
- public E higher(E e) {
- return getElementOrNull(multiset().tailMultiset(e, OPEN).firstEntry());
+ @Override public SortedMultiset<E> headMultiset(E toElement,
+ BoundType boundType) {
+ return forwardMultiset().tailMultiset(toElement, boundType)
+ .descendingMultiset();
}
- @Override
- public NavigableSet<E> descendingSet() {
- return new NavigableElementSet<E>(multiset().descendingMultiset());
+ @Override public SortedMultiset<E> subMultiset(E fromElement,
+ BoundType fromBoundType, E toElement, BoundType toBoundType) {
+ return forwardMultiset().subMultiset(toElement, toBoundType, fromElement,
+ fromBoundType).descendingMultiset();
}
- @Override
- public Iterator<E> descendingIterator() {
- return descendingSet().iterator();
+ @Override public SortedMultiset<E> tailMultiset(E fromElement,
+ BoundType boundType) {
+ return forwardMultiset().headMultiset(fromElement, boundType)
+ .descendingMultiset();
}
- @Override
- public E pollFirst() {
- return getElementOrNull(multiset().pollFirstEntry());
+ @Override protected Multiset<E> delegate() {
+ return forwardMultiset();
}
- @Override
- public E pollLast() {
- return getElementOrNull(multiset().pollLastEntry());
+ @Override public SortedMultiset<E> descendingMultiset() {
+ return forwardMultiset();
}
- @Override
- public NavigableSet<E> subSet(
- E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
- return new NavigableElementSet<E>(multiset().subMultiset(
- fromElement, BoundType.forBoolean(fromInclusive),
- toElement, BoundType.forBoolean(toInclusive)));
+ @Override public Entry<E> firstEntry() {
+ return forwardMultiset().lastEntry();
}
- @Override
- public NavigableSet<E> headSet(E toElement, boolean inclusive) {
- return new NavigableElementSet<E>(
- multiset().headMultiset(toElement, BoundType.forBoolean(inclusive)));
+ @Override public Entry<E> lastEntry() {
+ return forwardMultiset().firstEntry();
}
- @Override
- public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
- return new NavigableElementSet<E>(
- multiset().tailMultiset(fromElement, BoundType.forBoolean(inclusive)));
+ abstract Iterator<Entry<E>> entryIterator();
+
+ private transient Set<Entry<E>> entrySet;
+
+ @Override public Set<Entry<E>> entrySet() {
+ Set<Entry<E>> result = entrySet;
+ return (result == null) ? entrySet = createEntrySet() : result;
}
- }
- private static <E> E getElementOrThrow(Entry<E> entry) {
- if (entry == null) {
- throw new NoSuchElementException();
+ Set<Entry<E>> createEntrySet() {
+ return new Multisets.EntrySet<E>() {
+ @Override Multiset<E> multiset() {
+ return DescendingMultiset.this;
+ }
+
+ @Override public Iterator<Entry<E>> iterator() {
+ return entryIterator();
+ }
+
+ @Override public int size() {
+ return forwardMultiset().entrySet().size();
+ }
+ };
+ }
+
+ @Override public Iterator<E> iterator() {
+ return Multisets.iteratorImpl(this);
+ }
+
+ @Override public Object[] toArray() {
+ return standardToArray();
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return standardToArray(array);
}
- return entry.getElement();
- }
- private static <E> E getElementOrNull(@Nullable Entry<E> entry) {
- return (entry == null) ? null : entry.getElement();
+ @Override public String toString() {
+ return entrySet().toString();
+ }
}
}
diff --git a/guava/src/com/google/common/collect/SortedSetMultimap.java b/guava/src/com/google/common/collect/SortedSetMultimap.java
index 1b9c641..4785de3 100644
--- a/guava/src/com/google/common/collect/SortedSetMultimap.java
+++ b/guava/src/com/google/common/collect/SortedSetMultimap.java
@@ -31,18 +31,13 @@ import javax.annotation.Nullable;
* that is, they comprise a {@link SortedSet}. It cannot hold duplicate
* key-value pairs; adding a key-value pair that's already in the multimap has
* no effect. This interface does not specify the ordering of the multimap's
- * keys. See the {@link Multimap} documentation for information common to all
- * multimaps.
+ * keys.
*
* <p>The {@link #get}, {@link #removeAll}, and {@link #replaceValues} methods
* each return a {@link SortedSet} of values, while {@link Multimap#entries()}
* returns a {@link Set} of map entries. Though the method signature doesn't say
* so explicitly, the map returned by {@link #asMap} has {@code SortedSet}
* values.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap">
- * {@code Multimap}</a>.
*
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
diff --git a/guava/src/com/google/common/collect/StandardTable.java b/guava/src/com/google/common/collect/StandardTable.java
index 22c0a90..5edee5b 100644
--- a/guava/src/com/google/common/collect/StandardTable.java
+++ b/guava/src/com/google/common/collect/StandardTable.java
@@ -391,13 +391,17 @@ class StandardTable<R, C, V> implements Table<R, C, V>, Serializable {
@Override
public V remove(Object key) {
- Map<C, V> backingRowMap = backingRowMap();
- if (backingRowMap == null) {
+ try {
+ Map<C, V> backingRowMap = backingRowMap();
+ if (backingRowMap == null) {
+ return null;
+ }
+ V result = backingRowMap.remove(key);
+ maintainEmptyInvariant();
+ return result;
+ } catch (ClassCastException e) {
return null;
}
- V result = Maps.safeRemove(backingRowMap, key);
- maintainEmptyInvariant();
- return result;
}
@Override
@@ -555,7 +559,7 @@ class StandardTable<R, C, V> implements Table<R, C, V>, Serializable {
return changed;
}
- class EntrySet extends Sets.ImprovedAbstractSet<Entry<R, V>> {
+ class EntrySet extends AbstractSet<Entry<R, V>> {
@Override public Iterator<Entry<R, V>> iterator() {
return new EntrySetIterator();
}
@@ -595,6 +599,14 @@ class StandardTable<R, C, V> implements Table<R, C, V>, Serializable {
return false;
}
+ @Override public boolean removeAll(Collection<?> c) {
+ boolean changed = false;
+ for (Object obj : c) {
+ changed |= remove(obj);
+ }
+ return changed;
+ }
+
@Override public boolean retainAll(Collection<?> c) {
return removePredicate(Predicates.not(Predicates.in(c)));
}
@@ -631,9 +643,9 @@ class StandardTable<R, C, V> implements Table<R, C, V>, Serializable {
return result == null ? keySet = new KeySet() : result;
}
- class KeySet extends Sets.ImprovedAbstractSet<R> {
+ class KeySet extends AbstractSet<R> {
@Override public Iterator<R> iterator() {
- return Maps.keyIterator(Column.this.entrySet().iterator());
+ return keyIteratorImpl(Column.this);
}
@Override public int size() {
@@ -656,6 +668,14 @@ class StandardTable<R, C, V> implements Table<R, C, V>, Serializable {
entrySet().clear();
}
+ @Override public boolean removeAll(final Collection<?> c) {
+ boolean changed = false;
+ for (Object obj : c) {
+ changed |= remove(obj);
+ }
+ return changed;
+ }
+
@Override public boolean retainAll(final Collection<?> c) {
checkNotNull(c);
Predicate<Entry<R, V>> predicate = new Predicate<Entry<R, V>>() {
@@ -670,7 +690,7 @@ class StandardTable<R, C, V> implements Table<R, C, V>, Serializable {
class Values extends AbstractCollection<V> {
@Override public Iterator<V> iterator() {
- return Maps.valueIterator(Column.this.entrySet().iterator());
+ return valueIteratorImpl(Column.this);
}
@Override public int size() {
@@ -736,7 +756,7 @@ class StandardTable<R, C, V> implements Table<R, C, V>, Serializable {
class RowKeySet extends TableSet<R> {
@Override public Iterator<R> iterator() {
- return Maps.keyIterator(rowMap().entrySet().iterator());
+ return keyIteratorImpl(rowMap());
}
@Override public int size() {
@@ -890,10 +910,16 @@ class StandardTable<R, C, V> implements Table<R, C, V>, Serializable {
private class Values extends TableCollection<V> {
@Override public Iterator<V> iterator() {
- return new TransformedIterator<Cell<R, C, V>, V>(cellSet().iterator()) {
- @Override
- V transform(Cell<R, C, V> cell) {
- return cell.getValue();
+ final Iterator<Cell<R, C, V>> cellIterator = cellSet().iterator();
+ return new Iterator<V>() {
+ @Override public boolean hasNext() {
+ return cellIterator.hasNext();
+ }
+ @Override public V next() {
+ return cellIterator.next().getValue();
+ }
+ @Override public void remove() {
+ cellIterator.remove();
}
};
}
@@ -935,13 +961,7 @@ class StandardTable<R, C, V> implements Table<R, C, V>, Serializable {
class EntrySet extends TableSet<Entry<R, Map<C, V>>> {
@Override public Iterator<Entry<R, Map<C, V>>> iterator() {
- return new TransformedIterator<R, Entry<R, Map<C, V>>>(
- backingMap.keySet().iterator()) {
- @Override
- Entry<R, Map<C, V>> transform(R rowKey) {
- return new ImmutableEntry<R, Map<C, V>>(rowKey, row(rowKey));
- }
- };
+ return new EntryIterator();
}
@Override public int size() {
@@ -968,6 +988,23 @@ class StandardTable<R, C, V> implements Table<R, C, V>, Serializable {
return false;
}
}
+
+ class EntryIterator implements Iterator<Entry<R, Map<C, V>>> {
+ final Iterator<R> delegate = backingMap.keySet().iterator();
+
+ @Override public boolean hasNext() {
+ return delegate.hasNext();
+ }
+
+ @Override public Entry<R, Map<C, V>> next() {
+ R rowKey = delegate.next();
+ return new ImmutableEntry<R, Map<C, V>>(rowKey, row(rowKey));
+ }
+
+ @Override public void remove() {
+ delegate.remove();
+ }
+ }
}
private transient ColumnMap columnMap;
@@ -1011,10 +1048,13 @@ class StandardTable<R, C, V> implements Table<R, C, V>, Serializable {
class ColumnMapEntrySet extends TableSet<Entry<C, Map<R, V>>> {
@Override public Iterator<Entry<C, Map<R, V>>> iterator() {
- return new TransformedIterator<C, Entry<C, Map<R, V>>>(
- columnKeySet().iterator()) {
- @Override
- Entry<C, Map<R, V>> transform(C columnKey) {
+ final Iterator<C> columnIterator = columnKeySet().iterator();
+ return new UnmodifiableIterator<Entry<C, Map<R, V>>>() {
+ @Override public boolean hasNext() {
+ return columnIterator.hasNext();
+ }
+ @Override public Entry<C, Map<R, V>> next() {
+ C columnKey = columnIterator.next();
return new ImmutableEntry<C, Map<R, V>>(
columnKey, column(columnKey));
}
@@ -1071,7 +1111,7 @@ class StandardTable<R, C, V> implements Table<R, C, V>, Serializable {
private class ColumnMapValues extends TableCollection<Map<R, V>> {
@Override public Iterator<Map<R, V>> iterator() {
- return Maps.valueIterator(ColumnMap.this.entrySet().iterator());
+ return valueIteratorImpl(ColumnMap.this);
}
@Override public boolean remove(Object obj) {
@@ -1115,4 +1155,44 @@ class StandardTable<R, C, V> implements Table<R, C, V>, Serializable {
}
private static final long serialVersionUID = 0;
+
+ // TODO(kevinb): Move keyIteratorImpl and valueIteratorImpl to Maps, reuse
+
+ /**
+ * Generates the iterator of a map's key set from the map's entry set
+ * iterator.
+ */
+ static <K, V> Iterator<K> keyIteratorImpl(Map<K, V> map) {
+ final Iterator<Entry<K, V>> entryIterator = map.entrySet().iterator();
+ return new Iterator<K>() {
+ @Override public boolean hasNext() {
+ return entryIterator.hasNext();
+ }
+ @Override public K next() {
+ return entryIterator.next().getKey();
+ }
+ @Override public void remove() {
+ entryIterator.remove();
+ }
+ };
+ }
+
+ /**
+ * Generates the iterator of a map's value collection from the map's entry set
+ * iterator.
+ */
+ static <K, V> Iterator<V> valueIteratorImpl(Map<K, V> map) {
+ final Iterator<Entry<K, V>> entryIterator = map.entrySet().iterator();
+ return new Iterator<V>() {
+ @Override public boolean hasNext() {
+ return entryIterator.hasNext();
+ }
+ @Override public V next() {
+ return entryIterator.next().getValue();
+ }
+ @Override public void remove() {
+ entryIterator.remove();
+ }
+ };
+ }
}
diff --git a/guava/src/com/google/common/collect/Synchronized.java b/guava/src/com/google/common/collect/Synchronized.java
index bbf4c1e..c021c55 100644
--- a/guava/src/com/google/common/collect/Synchronized.java
+++ b/guava/src/com/google/common/collect/Synchronized.java
@@ -31,10 +31,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
-import java.util.Map.Entry;
-import java.util.NavigableMap;
-import java.util.NavigableSet;
-import java.util.Queue;
import java.util.RandomAccess;
import java.util.Set;
import java.util.SortedMap;
@@ -211,7 +207,7 @@ final class Synchronized {
static class SynchronizedSet<E>
extends SynchronizedCollection<E> implements Set<E> {
-
+
SynchronizedSet(Set<E> delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
@@ -851,7 +847,7 @@ final class Synchronized {
}
@Override public Map.Entry<K, Collection<V>> next() {
- final Map.Entry<K, Collection<V>> entry = super.next();
+ final Map.Entry<K, Collection<V>> entry = iterator.next();
return new ForwardingMapEntry<K, Collection<V>>() {
@Override protected Map.Entry<K, Collection<V>> delegate() {
return entry;
@@ -1043,12 +1039,12 @@ final class Synchronized {
private static final long serialVersionUID = 0;
}
-
+
static <K, V> SortedMap<K, V> sortedMap(
SortedMap<K, V> sortedMap, @Nullable Object mutex) {
return new SynchronizedSortedMap<K, V>(sortedMap, mutex);
}
-
+
static class SynchronizedSortedMap<K, V> extends SynchronizedMap<K, V>
implements SortedMap<K, V> {
@@ -1212,410 +1208,11 @@ final class Synchronized {
return iterator;
}
@Override public Collection<V> next() {
- return typePreservingCollection(super.next(), mutex);
+ return typePreservingCollection(iterator.next(), mutex);
}
};
}
private static final long serialVersionUID = 0;
}
-
- @GwtIncompatible("NavigableSet")
- @VisibleForTesting
- static class SynchronizedNavigableSet<E> extends SynchronizedSortedSet<E>
- implements NavigableSet<E> {
- SynchronizedNavigableSet(NavigableSet<E> delegate, @Nullable Object mutex) {
- super(delegate, mutex);
- }
-
- @Override NavigableSet<E> delegate() {
- return (NavigableSet<E>) super.delegate();
- }
-
- @Override public E ceiling(E e) {
- synchronized (mutex) {
- return delegate().ceiling(e);
- }
- }
-
- @Override public Iterator<E> descendingIterator() {
- return delegate().descendingIterator(); // manually synchronized
- }
-
- transient NavigableSet<E> descendingSet;
-
- @Override public NavigableSet<E> descendingSet() {
- synchronized (mutex) {
- if (descendingSet == null) {
- NavigableSet<E> dS =
- Synchronized.navigableSet(delegate().descendingSet(), mutex);
- descendingSet = dS;
- return dS;
- }
- return descendingSet;
- }
- }
-
- @Override public E floor(E e) {
- synchronized (mutex) {
- return delegate().floor(e);
- }
- }
-
- @Override public NavigableSet<E> headSet(E toElement, boolean inclusive) {
- synchronized (mutex) {
- return Synchronized.navigableSet(
- delegate().headSet(toElement, inclusive), mutex);
- }
- }
-
- @Override public E higher(E e) {
- synchronized (mutex) {
- return delegate().higher(e);
- }
- }
-
- @Override public E lower(E e) {
- synchronized (mutex) {
- return delegate().lower(e);
- }
- }
-
- @Override public E pollFirst() {
- synchronized (mutex) {
- return delegate().pollFirst();
- }
- }
-
- @Override public E pollLast() {
- synchronized (mutex) {
- return delegate().pollLast();
- }
- }
-
- @Override public NavigableSet<E> subSet(E fromElement,
- boolean fromInclusive, E toElement, boolean toInclusive) {
- synchronized (mutex) {
- return Synchronized.navigableSet(delegate().subSet(
- fromElement, fromInclusive, toElement, toInclusive), mutex);
- }
- }
-
- @Override public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
- synchronized (mutex) {
- return Synchronized.navigableSet(
- delegate().tailSet(fromElement, inclusive), mutex);
- }
- }
-
- @Override public SortedSet<E> headSet(E toElement) {
- return headSet(toElement, false);
- }
-
- @Override public SortedSet<E> subSet(E fromElement, E toElement) {
- return subSet(fromElement, true, toElement, false);
- }
-
- @Override public SortedSet<E> tailSet(E fromElement) {
- return tailSet(fromElement, true);
- }
-
- private static final long serialVersionUID = 0;
- }
-
- @GwtIncompatible("NavigableSet")
- static <E> NavigableSet<E> navigableSet(
- NavigableSet<E> navigableSet, @Nullable Object mutex) {
- return new SynchronizedNavigableSet<E>(navigableSet, mutex);
- }
-
- @GwtIncompatible("NavigableSet")
- static <E> NavigableSet<E> navigableSet(NavigableSet<E> navigableSet) {
- return navigableSet(navigableSet, null);
- }
-
- @GwtIncompatible("NavigableMap")
- static <K, V> NavigableMap<K, V> navigableMap(
- NavigableMap<K, V> navigableMap) {
- return navigableMap(navigableMap, null);
- }
-
- @GwtIncompatible("NavigableMap")
- static <K, V> NavigableMap<K, V> navigableMap(
- NavigableMap<K, V> navigableMap, @Nullable Object mutex) {
- return new SynchronizedNavigableMap<K, V>(navigableMap, mutex);
- }
-
- @GwtIncompatible("NavigableMap")
- @VisibleForTesting static class SynchronizedNavigableMap<K, V>
- extends SynchronizedSortedMap<K, V> implements NavigableMap<K, V> {
-
- SynchronizedNavigableMap(
- NavigableMap<K, V> delegate, @Nullable Object mutex) {
- super(delegate, mutex);
- }
-
- @Override NavigableMap<K, V> delegate() {
- return (NavigableMap<K, V>) super.delegate();
- }
-
- @Override public Entry<K, V> ceilingEntry(K key) {
- synchronized (mutex) {
- return nullableSynchronizedEntry(delegate().ceilingEntry(key), mutex);
- }
- }
-
- @Override public K ceilingKey(K key) {
- synchronized (mutex) {
- return delegate().ceilingKey(key);
- }
- }
-
- transient NavigableSet<K> descendingKeySet;
-
- @Override public NavigableSet<K> descendingKeySet() {
- synchronized (mutex) {
- if (descendingKeySet == null) {
- return descendingKeySet =
- Synchronized.navigableSet(delegate().descendingKeySet(), mutex);
- }
- return descendingKeySet;
- }
- }
-
- transient NavigableMap<K, V> descendingMap;
-
- @Override public NavigableMap<K, V> descendingMap() {
- synchronized (mutex) {
- if (descendingMap == null) {
- return descendingMap =
- navigableMap(delegate().descendingMap(), mutex);
- }
- return descendingMap;
- }
- }
-
- @Override public Entry<K, V> firstEntry() {
- synchronized (mutex) {
- return nullableSynchronizedEntry(delegate().firstEntry(), mutex);
- }
- }
-
- @Override public Entry<K, V> floorEntry(K key) {
- synchronized (mutex) {
- return nullableSynchronizedEntry(delegate().floorEntry(key), mutex);
- }
- }
-
- @Override public K floorKey(K key) {
- synchronized (mutex) {
- return delegate().floorKey(key);
- }
- }
-
- @Override public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
- synchronized (mutex) {
- return navigableMap(
- delegate().headMap(toKey, inclusive), mutex);
- }
- }
-
- @Override public Entry<K, V> higherEntry(K key) {
- synchronized (mutex) {
- return nullableSynchronizedEntry(delegate().higherEntry(key), mutex);
- }
- }
-
- @Override public K higherKey(K key) {
- synchronized (mutex) {
- return delegate().higherKey(key);
- }
- }
-
- @Override public Entry<K, V> lastEntry() {
- synchronized (mutex) {
- return nullableSynchronizedEntry(delegate().lastEntry(), mutex);
- }
- }
-
- @Override public Entry<K, V> lowerEntry(K key) {
- synchronized (mutex) {
- return nullableSynchronizedEntry(delegate().lowerEntry(key), mutex);
- }
- }
-
- @Override public K lowerKey(K key) {
- synchronized (mutex) {
- return delegate().lowerKey(key);
- }
- }
-
- @Override public Set<K> keySet() {
- return navigableKeySet();
- }
-
- transient NavigableSet<K> navigableKeySet;
-
- @Override public NavigableSet<K> navigableKeySet() {
- synchronized (mutex) {
- if (navigableKeySet == null) {
- return navigableKeySet =
- Synchronized.navigableSet(delegate().navigableKeySet(), mutex);
- }
- return navigableKeySet;
- }
- }
-
- @Override public Entry<K, V> pollFirstEntry() {
- synchronized (mutex) {
- return nullableSynchronizedEntry(delegate().pollFirstEntry(), mutex);
- }
- }
-
- @Override public Entry<K, V> pollLastEntry() {
- synchronized (mutex) {
- return nullableSynchronizedEntry(delegate().pollLastEntry(), mutex);
- }
- }
-
- @Override public NavigableMap<K, V> subMap(
- K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
- synchronized (mutex) {
- return navigableMap(
- delegate().subMap(fromKey, fromInclusive, toKey, toInclusive),
- mutex);
- }
- }
-
- @Override public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
- synchronized (mutex) {
- return navigableMap(
- delegate().tailMap(fromKey, inclusive), mutex);
- }
- }
-
- @Override public SortedMap<K, V> headMap(K toKey) {
- return headMap(toKey, false);
- }
-
- @Override public SortedMap<K, V> subMap(K fromKey, K toKey) {
- return subMap(fromKey, true, toKey, false);
- }
-
- @Override public SortedMap<K, V> tailMap(K fromKey) {
- return tailMap(fromKey, true);
- }
-
- private static final long serialVersionUID = 0;
- }
-
- @GwtIncompatible("works but is needed only for NavigableMap")
- private static <K, V> Entry<K, V> nullableSynchronizedEntry(
- @Nullable Entry<K, V> entry, @Nullable Object mutex) {
- if (entry == null) {
- return null;
- }
- return new SynchronizedEntry<K, V>(entry, mutex);
- }
-
- @GwtIncompatible("works but is needed only for NavigableMap")
- private static class SynchronizedEntry<K, V> extends SynchronizedObject
- implements Entry<K, V> {
-
- SynchronizedEntry(Entry<K, V> delegate, @Nullable Object mutex) {
- super(delegate, mutex);
- }
-
- @SuppressWarnings("unchecked") // guaranteed by the constructor
- @Override Entry<K, V> delegate() {
- return (Entry<K, V>) super.delegate();
- }
-
- @Override public boolean equals(Object obj) {
- synchronized (mutex) {
- return delegate().equals(obj);
- }
- }
-
- @Override public int hashCode() {
- synchronized (mutex) {
- return delegate().hashCode();
- }
- }
-
- @Override public K getKey() {
- synchronized (mutex) {
- return delegate().getKey();
- }
- }
-
- @Override public V getValue() {
- synchronized (mutex) {
- return delegate().getValue();
- }
- }
-
- @Override public V setValue(V value) {
- synchronized (mutex) {
- return delegate().setValue(value);
- }
- }
-
- private static final long serialVersionUID = 0;
- }
-
- static <E> Queue<E> queue(Queue<E> queue, @Nullable Object mutex) {
- return (queue instanceof SynchronizedQueue)
- ? queue
- : new SynchronizedQueue<E>(queue, mutex);
- }
-
- private static class SynchronizedQueue<E> extends SynchronizedCollection<E>
- implements Queue<E> {
-
- SynchronizedQueue(Queue<E> delegate, @Nullable Object mutex) {
- super(delegate, mutex);
- }
-
- @Override Queue<E> delegate() {
- return (Queue<E>) super.delegate();
- }
-
- @Override
- public E element() {
- synchronized (mutex) {
- return delegate().element();
- }
- }
-
- @Override
- public boolean offer(E e) {
- synchronized (mutex) {
- return delegate().offer(e);
- }
- }
-
- @Override
- public E peek() {
- synchronized (mutex) {
- return delegate().peek();
- }
- }
-
- @Override
- public E poll() {
- synchronized (mutex) {
- return delegate().poll();
- }
- }
-
- @Override
- public E remove() {
- synchronized (mutex) {
- return delegate().remove();
- }
- }
-
- private static final long serialVersionUID = 0;
- }
}
diff --git a/guava/src/com/google/common/collect/Table.java b/guava/src/com/google/common/collect/Table.java
index c384bf8..f2313be 100644
--- a/guava/src/com/google/common/collect/Table.java
+++ b/guava/src/com/google/common/collect/Table.java
@@ -16,6 +16,7 @@
package com.google.common.collect;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Objects;
@@ -43,10 +44,6 @@ import javax.annotation.Nullable;
* <p>All methods that modify the table are optional, and the views returned by
* the table may or may not be modifiable. When modification isn't supported,
* those methods will throw an {@link UnsupportedOperationException}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table">
- * {@code Table}</a>.
*
* @author Jared Levy
* @param <R> the type of the table row keys
@@ -55,6 +52,7 @@ import javax.annotation.Nullable;
* @since 7.0
*/
@GwtCompatible
+@Beta
public interface Table<R, C, V> {
// TODO(jlevy): Consider adding methods similar to ConcurrentMap methods.
@@ -261,6 +259,7 @@ public interface Table<R, C, V> {
*
* @since 7.0
*/
+ @Beta
interface Cell<R, C, V> {
/**
* Returns the row key of this cell.
diff --git a/guava/src/com/google/common/collect/Tables.java b/guava/src/com/google/common/collect/Tables.java
index 028aba3..a9c69b9 100644
--- a/guava/src/com/google/common/collect/Tables.java
+++ b/guava/src/com/google/common/collect/Tables.java
@@ -39,16 +39,13 @@ import javax.annotation.Nullable;
/**
* Provides static methods that involve a {@code Table}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Tables">
- * {@code Tables}</a>.
*
* @author Jared Levy
* @author Louis Wasserman
* @since 7.0
*/
@GwtCompatible
+@Beta
public final class Tables {
private Tables() {}
@@ -364,7 +361,6 @@ public final class Tables {
* @throws IllegalArgumentException if {@code backingMap} is not empty
* @since 10.0
*/
- @Beta
public static <R, C, V> Table<R, C, V> newCustomTable(
Map<R, Map<C, V>> backingMap, Supplier<? extends Map<C, V>> factory) {
checkArgument(backingMap.isEmpty());
@@ -399,7 +395,6 @@ public final class Tables {
*
* @since 10.0
*/
- @Beta
public static <R, C, V1, V2> Table<R, C, V2> transformValues(
Table<R, C, V1> fromTable, Function<? super V1, V2> function) {
return new TransformedTable<R, C, V1, V2>(fromTable, function);
@@ -701,7 +696,6 @@ public final class Tables {
* @return an unmodifiable view of the specified table
* @since 11.0
*/
- @Beta
public static <R, C, V> RowSortedTable<R, C, V> unmodifiableRowSortedTable(
RowSortedTable<R, ? extends C, ? extends V> table) {
/*
diff --git a/guava/src/com/google/common/collect/TransformedImmutableList.java b/guava/src/com/google/common/collect/TransformedImmutableList.java
new file mode 100644
index 0000000..d9e8588
--- /dev/null
+++ b/guava/src/com/google/common/collect/TransformedImmutableList.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+/**
+ * A transforming wrapper around an ImmutableList. For internal use only. {@link
+ * #transform(Object)} must be functional.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+@SuppressWarnings("serial") // uses writeReplace(), not default serialization
+abstract class TransformedImmutableList<D, E> extends ImmutableList<E> {
+ private class TransformedView extends TransformedImmutableList<D, E> {
+ TransformedView(ImmutableList<D> backingList) {
+ super(backingList);
+ }
+
+ @Override E transform(D d) {
+ return TransformedImmutableList.this.transform(d);
+ }
+ }
+
+ private transient final ImmutableList<D> backingList;
+
+ TransformedImmutableList(ImmutableList<D> backingList) {
+ this.backingList = checkNotNull(backingList);
+ }
+
+ abstract E transform(D d);
+
+ @Override public int indexOf(@Nullable Object object) {
+ if (object == null) {
+ return -1;
+ }
+ for (int i = 0; i < size(); i++) {
+ if (get(i).equals(object)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override public int lastIndexOf(@Nullable Object object) {
+ if (object == null) {
+ return -1;
+ }
+ for (int i = size() - 1; i >= 0; i--) {
+ if (get(i).equals(object)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override public E get(int index) {
+ return transform(backingList.get(index));
+ }
+
+ @Override public UnmodifiableListIterator<E> listIterator(int index) {
+ return new AbstractIndexedListIterator<E>(size(), index) {
+ @Override protected E get(int index) {
+ return TransformedImmutableList.this.get(index);
+ }
+ };
+ }
+
+ @Override public int size() {
+ return backingList.size();
+ }
+
+ @Override public ImmutableList<E> subList(int fromIndex, int toIndex) {
+ return new TransformedView(backingList.subList(fromIndex, toIndex));
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof List) {
+ List<?> list = (List<?>) obj;
+ return size() == list.size()
+ && Iterators.elementsEqual(iterator(), list.iterator());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ int hashCode = 1;
+ for (E e : this) {
+ hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
+ }
+ return hashCode;
+ }
+
+ @Override public Object[] toArray() {
+ return ObjectArrays.toArrayImpl(this);
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return ObjectArrays.toArrayImpl(this, array);
+ }
+
+ @Override boolean isPartialView() {
+ return true;
+ }
+}
diff --git a/guava/src/com/google/common/collect/TransformedIterator.java b/guava/src/com/google/common/collect/TransformedIterator.java
deleted file mode 100644
index c082d7d..0000000
--- a/guava/src/com/google/common/collect/TransformedIterator.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.Iterator;
-
-/**
- * An iterator that transforms a backing iterator; for internal use. This avoids
- * the object overhead of constructing a {@link Function} for internal methods.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible
-abstract class TransformedIterator<F, T> implements Iterator<T> {
- final Iterator<? extends F> backingIterator;
-
- TransformedIterator(Iterator<? extends F> backingIterator) {
- this.backingIterator = checkNotNull(backingIterator);
- }
-
- abstract T transform(F from);
-
- @Override
- public final boolean hasNext() {
- return backingIterator.hasNext();
- }
-
- @Override
- public final T next() {
- return transform(backingIterator.next());
- }
-
- @Override
- public final void remove() {
- backingIterator.remove();
- }
-}
diff --git a/guava/src/com/google/common/collect/TransformedListIterator.java b/guava/src/com/google/common/collect/TransformedListIterator.java
deleted file mode 100644
index c743030..0000000
--- a/guava/src/com/google/common/collect/TransformedListIterator.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Function;
-
-import java.util.ListIterator;
-
-/**
- * An iterator that transforms a backing list iterator; for internal use. This
- * avoids the object overhead of constructing a {@link Function} for internal
- * methods.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible
-abstract class TransformedListIterator<F, T> extends TransformedIterator<F, T>
- implements ListIterator<T> {
- TransformedListIterator(ListIterator<? extends F> backingIterator) {
- super(backingIterator);
- }
-
- private ListIterator<? extends F> backingIterator() {
- return Iterators.cast(backingIterator);
- }
-
- @Override
- public final boolean hasPrevious() {
- return backingIterator().hasPrevious();
- }
-
- @Override
- public final T previous() {
- return transform(backingIterator().previous());
- }
-
- @Override
- public final int nextIndex() {
- return backingIterator().nextIndex();
- }
-
- @Override
- public final int previousIndex() {
- return backingIterator().previousIndex();
- }
-
- @Override
- public void set(T element) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void add(T element) {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/guava/src/com/google/common/collect/TreeBasedTable.java b/guava/src/com/google/common/collect/TreeBasedTable.java
index 2ead64e..d996c27 100644
--- a/guava/src/com/google/common/collect/TreeBasedTable.java
+++ b/guava/src/com/google/common/collect/TreeBasedTable.java
@@ -66,10 +66,6 @@ import javax.annotation.Nullable;
* access this table concurrently and one of the threads modifies the table, it
* must be synchronized externally.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table">
- * {@code Table}</a>.
- *
* @author Jared Levy
* @author Louis Wasserman
* @since 7.0
diff --git a/guava/src/com/google/common/collect/TreeMultimap.java b/guava/src/com/google/common/collect/TreeMultimap.java
index 433774d..efd11be 100644
--- a/guava/src/com/google/common/collect/TreeMultimap.java
+++ b/guava/src/com/google/common/collect/TreeMultimap.java
@@ -26,14 +26,11 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Collection;
import java.util.Comparator;
-import java.util.NavigableMap;
-import java.util.NavigableSet;
+import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
-import javax.annotation.Nullable;
-
/**
* Implementation of {@code Multimap} whose keys and values are ordered by
* their natural ordering or by supplied comparators. In all cases, this
@@ -67,16 +64,11 @@ import javax.annotation.Nullable;
* update operations, wrap your multimap with a call to {@link
* Multimaps#synchronizedSortedSetMultimap}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap">
- * {@code Multimap}</a>.
- *
* @author Jared Levy
- * @author Louis Wasserman
* @since 2.0 (imported from Google Collections Library)
*/
@GwtCompatible(serializable = true, emulated = true)
-public class TreeMultimap<K, V> extends AbstractSortedKeySortedSetMultimap<K, V> {
+public class TreeMultimap<K, V> extends AbstractSortedSetMultimap<K, V> {
private transient Comparator<? super K> keyComparator;
private transient Comparator<? super V> valueComparator;
@@ -142,14 +134,6 @@ public class TreeMultimap<K, V> extends AbstractSortedKeySortedSetMultimap<K, V>
return new TreeSet<V>(valueComparator);
}
- @Override
- Collection<V> createCollection(@Nullable K key) {
- if (key == null) {
- keyComparator().compare(key, key);
- }
- return super.createCollection(key);
- }
-
/**
* Returns the comparator that orders the multimap keys.
*/
@@ -162,79 +146,26 @@ public class TreeMultimap<K, V> extends AbstractSortedKeySortedSetMultimap<K, V>
return valueComparator;
}
- /*
- * The following @GwtIncompatible methods override the methods in
- * AbstractSortedKeySortedSetMultimap, so GWT will fall back to the ASKSSM implementations,
- * which return SortedSets and SortedMaps.
- */
-
- @Override
- @GwtIncompatible("NavigableMap")
- NavigableMap<K, Collection<V>> backingMap() {
- return (NavigableMap<K, Collection<V>>) super.backingMap();
- }
-
- /**
- * @since 14.0 (present with return type {@code SortedSet} since 2.0)
- */
- @Override
- @GwtIncompatible("NavigableSet")
- public NavigableSet<V> get(@Nullable K key) {
- return (NavigableSet<V>) super.get(key);
- }
-
- @Override
- @GwtIncompatible("NavigableSet")
- Collection<V> unmodifiableCollectionSubclass(Collection<V> collection) {
- return Sets.unmodifiableNavigableSet((NavigableSet<V>) collection);
- }
-
- @Override
- @GwtIncompatible("NavigableSet")
- Collection<V> wrapCollection(K key, Collection<V> collection) {
- return new WrappedNavigableSet(key, (NavigableSet<V>) collection, null);
- }
-
/**
* {@inheritDoc}
*
* <p>Because a {@code TreeMultimap} has unique sorted keys, this method
- * returns a {@link NavigableSet}, instead of the {@link java.util.Set} specified
+ * returns a {@link SortedSet}, instead of the {@link java.util.Set} specified
* in the {@link Multimap} interface.
- *
- * @since 14.0 (present with return type {@code SortedSet} since 2.0)
*/
- @Override
- @GwtIncompatible("NavigableSet")
- public NavigableSet<K> keySet() {
- return (NavigableSet<K>) super.keySet();
- }
-
- @Override
- @GwtIncompatible("NavigableSet")
- NavigableSet<K> createKeySet() {
- return new NavigableKeySet(backingMap());
+ @Override public SortedSet<K> keySet() {
+ return (SortedSet<K>) super.keySet();
}
/**
* {@inheritDoc}
*
* <p>Because a {@code TreeMultimap} has unique sorted keys, this method
- * returns a {@link NavigableMap}, instead of the {@link java.util.Map} specified
+ * returns a {@link SortedMap}, instead of the {@link java.util.Map} specified
* in the {@link Multimap} interface.
- *
- * @since 14.0 (present with return type {@code SortedMap} since 2.0)
*/
- @Override
- @GwtIncompatible("NavigableMap")
- public NavigableMap<K, Collection<V>> asMap() {
- return (NavigableMap<K, Collection<V>>) super.asMap();
- }
-
- @Override
- @GwtIncompatible("NavigableMap")
- NavigableMap<K, Collection<V>> createAsMap() {
- return new NavigableAsMap(backingMap());
+ @Override public SortedMap<K, Collection<V>> asMap() {
+ return (SortedMap<K, Collection<V>>) super.asMap();
}
/**
diff --git a/guava/src/com/google/common/collect/TreeMultiset.java b/guava/src/com/google/common/collect/TreeMultiset.java
index 6876cd0..d44a4bb 100644
--- a/guava/src/com/google/common/collect/TreeMultiset.java
+++ b/guava/src/com/google/common/collect/TreeMultiset.java
@@ -17,12 +17,10 @@
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
-import com.google.common.base.Objects;
-import com.google.common.primitives.Ints;
+import static com.google.common.collect.BstSide.LEFT;
+import static com.google.common.collect.BstSide.RIGHT;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -31,207 +29,160 @@ import java.io.Serializable;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
-import java.util.NoSuchElementException;
import javax.annotation.Nullable;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.primitives.Ints;
+
/**
- * A multiset which maintains the ordering of its elements, according to either their natural order
- * or an explicit {@link Comparator}. In all cases, this implementation uses
- * {@link Comparable#compareTo} or {@link Comparator#compare} instead of {@link Object#equals} to
- * determine equivalence of instances.
+ * A multiset which maintains the ordering of its elements, according to either
+ * their natural order or an explicit {@link Comparator}. In all cases, this
+ * implementation uses {@link Comparable#compareTo} or {@link
+ * Comparator#compare} instead of {@link Object#equals} to determine
+ * equivalence of instances.
*
- * <p><b>Warning:</b> The comparison must be <i>consistent with equals</i> as explained by the
- * {@link Comparable} class specification. Otherwise, the resulting multiset will violate the
- * {@link java.util.Collection} contract, which is specified in terms of {@link Object#equals}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset">
- * {@code Multiset}</a>.
+ * <p><b>Warning:</b> The comparison must be <i>consistent with equals</i> as
+ * explained by the {@link Comparable} class specification. Otherwise, the
+ * resulting multiset will violate the {@link java.util.Collection} contract,
+ * which is specified in terms of {@link Object#equals}.
*
* @author Louis Wasserman
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
*/
@GwtCompatible(emulated = true)
-public final class TreeMultiset<E> extends AbstractSortedMultiset<E> implements Serializable {
+public final class TreeMultiset<E> extends AbstractSortedMultiset<E>
+ implements Serializable {
/**
- * Creates a new, empty multiset, sorted according to the elements' natural order. All elements
- * inserted into the multiset must implement the {@code Comparable} interface. Furthermore, all
- * such elements must be <i>mutually comparable</i>: {@code e1.compareTo(e2)} must not throw a
- * {@code ClassCastException} for any elements {@code e1} and {@code e2} in the multiset. If the
- * user attempts to add an element to the multiset that violates this constraint (for example,
- * the user attempts to add a string element to a set whose elements are integers), the
- * {@code add(Object)} call will throw a {@code ClassCastException}.
+ * Creates a new, empty multiset, sorted according to the elements' natural
+ * order. All elements inserted into the multiset must implement the
+ * {@code Comparable} interface. Furthermore, all such elements must be
+ * <i>mutually comparable</i>: {@code e1.compareTo(e2)} must not throw a
+ * {@code ClassCastException} for any elements {@code e1} and {@code e2} in
+ * the multiset. If the user attempts to add an element to the multiset that
+ * violates this constraint (for example, the user attempts to add a string
+ * element to a set whose elements are integers), the {@code add(Object)}
+ * call will throw a {@code ClassCastException}.
*
- * <p>The type specification is {@code <E extends Comparable>}, instead of the more specific
- * {@code <E extends Comparable<? super E>>}, to support classes defined without generics.
+ * <p>The type specification is {@code <E extends Comparable>}, instead of the
+ * more specific {@code <E extends Comparable<? super E>>}, to support
+ * classes defined without generics.
*/
public static <E extends Comparable> TreeMultiset<E> create() {
return new TreeMultiset<E>(Ordering.natural());
}
/**
- * Creates a new, empty multiset, sorted according to the specified comparator. All elements
- * inserted into the multiset must be <i>mutually comparable</i> by the specified comparator:
- * {@code comparator.compare(e1,
- * e2)} must not throw a {@code ClassCastException} for any elements {@code e1} and {@code e2} in
- * the multiset. If the user attempts to add an element to the multiset that violates this
- * constraint, the {@code add(Object)} call will throw a {@code ClassCastException}.
+ * Creates a new, empty multiset, sorted according to the specified
+ * comparator. All elements inserted into the multiset must be <i>mutually
+ * comparable</i> by the specified comparator: {@code comparator.compare(e1,
+ * e2)} must not throw a {@code ClassCastException} for any elements {@code
+ * e1} and {@code e2} in the multiset. If the user attempts to add an element
+ * to the multiset that violates this constraint, the {@code add(Object)} call
+ * will throw a {@code ClassCastException}.
*
- * @param comparator
- * the comparator that will be used to sort this multiset. A null value indicates that
- * the elements' <i>natural ordering</i> should be used.
+ * @param comparator the comparator that will be used to sort this multiset. A
+ * null value indicates that the elements' <i>natural ordering</i> should
+ * be used.
*/
@SuppressWarnings("unchecked")
- public static <E> TreeMultiset<E> create(@Nullable Comparator<? super E> comparator) {
+ public static <E> TreeMultiset<E> create(
+ @Nullable Comparator<? super E> comparator) {
return (comparator == null)
- ? new TreeMultiset<E>((Comparator) Ordering.natural())
- : new TreeMultiset<E>(comparator);
+ ? new TreeMultiset<E>((Comparator) Ordering.natural())
+ : new TreeMultiset<E>(comparator);
}
/**
- * Creates an empty multiset containing the given initial elements, sorted according to the
- * elements' natural order.
+ * Creates an empty multiset containing the given initial elements, sorted
+ * according to the elements' natural order.
*
- * <p>This implementation is highly efficient when {@code elements} is itself a {@link Multiset}.
+ * <p>This implementation is highly efficient when {@code elements} is itself
+ * a {@link Multiset}.
*
- * <p>The type specification is {@code <E extends Comparable>}, instead of the more specific
- * {@code <E extends Comparable<? super E>>}, to support classes defined without generics.
+ * <p>The type specification is {@code <E extends Comparable>}, instead of the
+ * more specific {@code <E extends Comparable<? super E>>}, to support
+ * classes defined without generics.
*/
- public static <E extends Comparable> TreeMultiset<E> create(Iterable<? extends E> elements) {
+ public static <E extends Comparable> TreeMultiset<E> create(
+ Iterable<? extends E> elements) {
TreeMultiset<E> multiset = create();
Iterables.addAll(multiset, elements);
return multiset;
}
- private final transient Reference<AvlNode<E>> rootReference;
- private final transient GeneralRange<E> range;
- private final transient AvlNode<E> header;
-
- TreeMultiset(Reference<AvlNode<E>> rootReference, GeneralRange<E> range, AvlNode<E> endLink) {
- super(range.comparator());
- this.rootReference = rootReference;
- this.range = range;
- this.header = endLink;
+ /**
+ * Returns an iterator over the elements contained in this collection.
+ */
+ @Override
+ public Iterator<E> iterator() {
+ // Needed to avoid Javadoc bug.
+ return super.iterator();
}
- TreeMultiset(Comparator<? super E> comparator) {
+ private TreeMultiset(Comparator<? super E> comparator) {
super(comparator);
this.range = GeneralRange.all(comparator);
- this.header = new AvlNode<E>(null, 1);
- successor(header, header);
- this.rootReference = new Reference<AvlNode<E>>();
+ this.rootReference = new Reference<Node<E>>();
}
- /**
- * A function which can be summed across a subtree.
- */
- private enum Aggregate {
- SIZE {
- @Override
- int nodeAggregate(AvlNode<?> node) {
- return node.elemCount;
- }
+ private TreeMultiset(GeneralRange<E> range, Reference<Node<E>> root) {
+ super(range.comparator());
+ this.range = range;
+ this.rootReference = root;
+ }
- @Override
- long treeAggregate(@Nullable AvlNode<?> root) {
- return (root == null) ? 0 : root.totalCount;
- }
- },
- DISTINCT {
- @Override
- int nodeAggregate(AvlNode<?> node) {
- return 1;
- }
+ @SuppressWarnings("unchecked")
+ E checkElement(Object o) {
+ return (E) o;
+ }
- @Override
- long treeAggregate(@Nullable AvlNode<?> root) {
- return (root == null) ? 0 : root.distinctElements;
- }
- };
- abstract int nodeAggregate(AvlNode<?> node);
+ private transient final GeneralRange<E> range;
- abstract long treeAggregate(@Nullable AvlNode<?> root);
- }
+ private transient final Reference<Node<E>> rootReference;
- private long aggregateForEntries(Aggregate aggr) {
- AvlNode<E> root = rootReference.get();
- long total = aggr.treeAggregate(root);
- if (range.hasLowerBound()) {
- total -= aggregateBelowRange(aggr, root);
- }
- if (range.hasUpperBound()) {
- total -= aggregateAboveRange(aggr, root);
- }
- return total;
- }
+ static final class Reference<T> {
+ T value;
- private long aggregateBelowRange(Aggregate aggr, @Nullable AvlNode<E> node) {
- if (node == null) {
- return 0;
- }
- int cmp = comparator().compare(range.getLowerEndpoint(), node.elem);
- if (cmp < 0) {
- return aggregateBelowRange(aggr, node.left);
- } else if (cmp == 0) {
- switch (range.getLowerBoundType()) {
- case OPEN:
- return aggr.nodeAggregate(node) + aggr.treeAggregate(node.left);
- case CLOSED:
- return aggr.treeAggregate(node.left);
- default:
- throw new AssertionError();
- }
- } else {
- return aggr.treeAggregate(node.left) + aggr.nodeAggregate(node)
- + aggregateBelowRange(aggr, node.right);
- }
- }
+ public Reference() {}
- private long aggregateAboveRange(Aggregate aggr, @Nullable AvlNode<E> node) {
- if (node == null) {
- return 0;
+ public T get() {
+ return value;
}
- int cmp = comparator().compare(range.getUpperEndpoint(), node.elem);
- if (cmp > 0) {
- return aggregateAboveRange(aggr, node.right);
- } else if (cmp == 0) {
- switch (range.getUpperBoundType()) {
- case OPEN:
- return aggr.nodeAggregate(node) + aggr.treeAggregate(node.right);
- case CLOSED:
- return aggr.treeAggregate(node.right);
- default:
- throw new AssertionError();
+
+ public boolean compareAndSet(T expected, T newValue) {
+ if (value == expected) {
+ value = newValue;
+ return true;
}
- } else {
- return aggr.treeAggregate(node.right) + aggr.nodeAggregate(node)
- + aggregateAboveRange(aggr, node.left);
+ return false;
}
}
@Override
- public int size() {
- return Ints.saturatedCast(aggregateForEntries(Aggregate.SIZE));
+ int distinctElements() {
+ Node<E> root = rootReference.get();
+ return Ints.checkedCast(BstRangeOps.totalInRange(distinctAggregate(), range, root));
}
@Override
- int distinctElements() {
- return Ints.saturatedCast(aggregateForEntries(Aggregate.DISTINCT));
+ public int size() {
+ Node<E> root = rootReference.get();
+ return Ints.saturatedCast(BstRangeOps.totalInRange(sizeAggregate(), range, root));
}
@Override
public int count(@Nullable Object element) {
try {
- @SuppressWarnings("unchecked")
- E e = (E) element;
- AvlNode<E> root = rootReference.get();
- if (!range.contains(e) || root == null) {
- return 0;
+ E e = checkElement(element);
+ if (range.contains(e)) {
+ Node<E> node = BstOperations.seek(comparator(), rootReference.get(), e);
+ return countOrZero(node);
}
- return root.count(comparator(), e);
+ return 0;
} catch (ClassCastException e) {
return 0;
} catch (NullPointerException e) {
@@ -239,718 +190,360 @@ public final class TreeMultiset<E> extends AbstractSortedMultiset<E> implements
}
}
+ private int mutate(@Nullable E e, MultisetModifier modifier) {
+ BstMutationRule<E, Node<E>> mutationRule = BstMutationRule.createRule(
+ modifier,
+ BstCountBasedBalancePolicies.
+ <E, Node<E>>singleRebalancePolicy(distinctAggregate()),
+ nodeFactory());
+ BstMutationResult<E, Node<E>> mutationResult =
+ BstOperations.mutate(comparator(), mutationRule, rootReference.get(), e);
+ if (!rootReference.compareAndSet(
+ mutationResult.getOriginalRoot(), mutationResult.getChangedRoot())) {
+ throw new ConcurrentModificationException();
+ }
+ Node<E> original = mutationResult.getOriginalTarget();
+ return countOrZero(original);
+ }
+
@Override
- public int add(@Nullable E element, int occurrences) {
- checkArgument(occurrences >= 0, "occurrences must be >= 0 but was %s", occurrences);
+ public int add(E element, int occurrences) {
+ checkElement(element);
if (occurrences == 0) {
return count(element);
}
checkArgument(range.contains(element));
- AvlNode<E> root = rootReference.get();
- if (root == null) {
- comparator().compare(element, element);
- AvlNode<E> newRoot = new AvlNode<E>(element, occurrences);
- successor(header, newRoot, header);
- rootReference.checkAndSet(root, newRoot);
- return 0;
- }
- int[] result = new int[1]; // used as a mutable int reference to hold result
- AvlNode<E> newRoot = root.add(comparator(), element, occurrences, result);
- rootReference.checkAndSet(root, newRoot);
- return result[0];
+ return mutate(element, new AddModifier(occurrences));
}
@Override
public int remove(@Nullable Object element, int occurrences) {
- checkArgument(occurrences >= 0, "occurrences must be >= 0 but was %s", occurrences);
- if (occurrences == 0) {
+ if (element == null) {
+ return 0;
+ } else if (occurrences == 0) {
return count(element);
}
- AvlNode<E> root = rootReference.get();
- int[] result = new int[1]; // used as a mutable int reference to hold result
- AvlNode<E> newRoot;
try {
- @SuppressWarnings("unchecked")
- E e = (E) element;
- if (!range.contains(e) || root == null) {
- return 0;
- }
- newRoot = root.remove(comparator(), e, occurrences, result);
+ E e = checkElement(element);
+ return range.contains(e) ? mutate(e, new RemoveModifier(occurrences)) : 0;
} catch (ClassCastException e) {
return 0;
- } catch (NullPointerException e) {
- return 0;
}
- rootReference.checkAndSet(root, newRoot);
- return result[0];
}
@Override
- public int setCount(@Nullable E element, int count) {
- checkArgument(count >= 0);
- if (!range.contains(element)) {
- checkArgument(count == 0);
- return 0;
- }
-
- AvlNode<E> root = rootReference.get();
- if (root == null) {
- if (count > 0) {
- add(element, count);
- }
- return 0;
- }
- int[] result = new int[1]; // used as a mutable int reference to hold result
- AvlNode<E> newRoot = root.setCount(comparator(), element, count, result);
- rootReference.checkAndSet(root, newRoot);
- return result[0];
+ public boolean setCount(E element, int oldCount, int newCount) {
+ checkElement(element);
+ checkArgument(range.contains(element));
+ return mutate(element, new ConditionalSetCountModifier(oldCount, newCount))
+ == oldCount;
}
@Override
- public boolean setCount(@Nullable E element, int oldCount, int newCount) {
- checkArgument(newCount >= 0);
- checkArgument(oldCount >= 0);
+ public int setCount(E element, int count) {
+ checkElement(element);
checkArgument(range.contains(element));
-
- AvlNode<E> root = rootReference.get();
- if (root == null) {
- if (oldCount == 0) {
- if (newCount > 0) {
- add(element, newCount);
- }
- return true;
- } else {
- return false;
- }
- }
- int[] result = new int[1]; // used as a mutable int reference to hold result
- AvlNode<E> newRoot = root.setCount(comparator(), element, oldCount, newCount, result);
- rootReference.checkAndSet(root, newRoot);
- return result[0] == oldCount;
+ return mutate(element, new SetCountModifier(count));
}
- private Entry<E> wrapEntry(final AvlNode<E> baseEntry) {
- return new Multisets.AbstractEntry<E>() {
- @Override
- public E getElement() {
- return baseEntry.getElement();
- }
-
- @Override
- public int getCount() {
- int result = baseEntry.getCount();
- if (result == 0) {
- return count(getElement());
- } else {
- return result;
- }
- }
- };
+ private BstPathFactory<Node<E>, BstInOrderPath<Node<E>>> pathFactory() {
+ return BstInOrderPath.inOrderFactory();
}
- /**
- * Returns the first node in the tree that is in range.
- */
- @Nullable private AvlNode<E> firstNode() {
- AvlNode<E> root = rootReference.get();
- if (root == null) {
- return null;
- }
- AvlNode<E> node;
- if (range.hasLowerBound()) {
- E endpoint = range.getLowerEndpoint();
- node = rootReference.get().ceiling(comparator(), endpoint);
- if (node == null) {
- return null;
- }
- if (range.getLowerBoundType() == BoundType.OPEN
- && comparator().compare(endpoint, node.getElement()) == 0) {
- node = node.succ;
- }
- } else {
- node = header.succ;
- }
- return (node == header || !range.contains(node.getElement())) ? null : node;
+ @Override
+ Iterator<Entry<E>> entryIterator() {
+ Node<E> root = rootReference.get();
+ final BstInOrderPath<Node<E>> startingPath =
+ BstRangeOps.furthestPath(range, LEFT, pathFactory(), root);
+ return iteratorInDirection(startingPath, RIGHT);
}
- @Nullable private AvlNode<E> lastNode() {
- AvlNode<E> root = rootReference.get();
- if (root == null) {
- return null;
- }
- AvlNode<E> node;
- if (range.hasUpperBound()) {
- E endpoint = range.getUpperEndpoint();
- node = rootReference.get().floor(comparator(), endpoint);
- if (node == null) {
- return null;
- }
- if (range.getUpperBoundType() == BoundType.OPEN
- && comparator().compare(endpoint, node.getElement()) == 0) {
- node = node.pred;
- }
- } else {
- node = header.pred;
- }
- return (node == header || !range.contains(node.getElement())) ? null : node;
+ @Override
+ Iterator<Entry<E>> descendingEntryIterator() {
+ Node<E> root = rootReference.get();
+ final BstInOrderPath<Node<E>> startingPath =
+ BstRangeOps.furthestPath(range, RIGHT, pathFactory(), root);
+ return iteratorInDirection(startingPath, LEFT);
}
- @Override
- Iterator<Entry<E>> entryIterator() {
+ private Iterator<Entry<E>> iteratorInDirection(
+ @Nullable BstInOrderPath<Node<E>> start, final BstSide direction) {
+ final Iterator<BstInOrderPath<Node<E>>> pathIterator =
+ new AbstractLinkedIterator<BstInOrderPath<Node<E>>>(start) {
+ @Override
+ protected BstInOrderPath<Node<E>> computeNext(BstInOrderPath<Node<E>> previous) {
+ if (!previous.hasNext(direction)) {
+ return null;
+ }
+ BstInOrderPath<Node<E>> next = previous.next(direction);
+ // TODO(user): only check against one side
+ return range.contains(next.getTip().getKey()) ? next : null;
+ }
+ };
return new Iterator<Entry<E>>() {
- AvlNode<E> current = firstNode();
- Entry<E> prevEntry;
+ E toRemove = null;
@Override
public boolean hasNext() {
- if (current == null) {
- return false;
- } else if (range.tooHigh(current.getElement())) {
- current = null;
- return false;
- } else {
- return true;
- }
+ return pathIterator.hasNext();
}
@Override
public Entry<E> next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- Entry<E> result = wrapEntry(current);
- prevEntry = result;
- if (current.succ == header) {
- current = null;
- } else {
- current = current.succ;
- }
- return result;
+ BstInOrderPath<Node<E>> path = pathIterator.next();
+ return new LiveEntry(
+ toRemove = path.getTip().getKey(), path.getTip().elemCount());
}
@Override
public void remove() {
- checkState(prevEntry != null);
- setCount(prevEntry.getElement(), 0);
- prevEntry = null;
+ checkState(toRemove != null);
+ setCount(toRemove, 0);
+ toRemove = null;
}
};
}
- @Override
- Iterator<Entry<E>> descendingEntryIterator() {
- return new Iterator<Entry<E>>() {
- AvlNode<E> current = lastNode();
- Entry<E> prevEntry = null;
+ class LiveEntry extends Multisets.AbstractEntry<E> {
+ private Node<E> expectedRoot;
+ private final E element;
+ private int count;
- @Override
- public boolean hasNext() {
- if (current == null) {
- return false;
- } else if (range.tooLow(current.getElement())) {
- current = null;
- return false;
- } else {
- return true;
- }
- }
+ private LiveEntry(E element, int count) {
+ this.expectedRoot = rootReference.get();
+ this.element = element;
+ this.count = count;
+ }
- @Override
- public Entry<E> next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- Entry<E> result = wrapEntry(current);
- prevEntry = result;
- if (current.pred == header) {
- current = null;
- } else {
- current = current.pred;
- }
- return result;
- }
+ @Override
+ public E getElement() {
+ return element;
+ }
- @Override
- public void remove() {
- checkState(prevEntry != null);
- setCount(prevEntry.getElement(), 0);
- prevEntry = null;
+ @Override
+ public int getCount() {
+ if (rootReference.get() == expectedRoot) {
+ return count;
+ } else {
+ // check for updates
+ expectedRoot = rootReference.get();
+ return count = TreeMultiset.this.count(element);
}
- };
+ }
}
@Override
- public SortedMultiset<E> headMultiset(@Nullable E upperBound, BoundType boundType) {
- return new TreeMultiset<E>(rootReference, range.intersect(GeneralRange.upTo(
- comparator(),
- upperBound,
- boundType)), header);
+ public void clear() {
+ Node<E> root = rootReference.get();
+ Node<E> cleared = BstRangeOps.minusRange(range,
+ BstCountBasedBalancePolicies.<E, Node<E>>fullRebalancePolicy(distinctAggregate()),
+ nodeFactory(), root);
+ if (!rootReference.compareAndSet(root, cleared)) {
+ throw new ConcurrentModificationException();
+ }
}
@Override
- public SortedMultiset<E> tailMultiset(@Nullable E lowerBound, BoundType boundType) {
- return new TreeMultiset<E>(rootReference, range.intersect(GeneralRange.downTo(
- comparator(),
- lowerBound,
- boundType)), header);
+ public SortedMultiset<E> headMultiset(E upperBound, BoundType boundType) {
+ checkNotNull(upperBound);
+ return new TreeMultiset<E>(
+ range.intersect(GeneralRange.upTo(comparator, upperBound, boundType)), rootReference);
}
- static int distinctElements(@Nullable AvlNode<?> node) {
- return (node == null) ? 0 : node.distinctElements;
+ @Override
+ public SortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType) {
+ checkNotNull(lowerBound);
+ return new TreeMultiset<E>(
+ range.intersect(GeneralRange.downTo(comparator, lowerBound, boundType)), rootReference);
}
- private static final class Reference<T> {
- @Nullable private T value;
-
- @Nullable public T get() {
- return value;
- }
-
- public void checkAndSet(@Nullable T expected, T newValue) {
- if (value != expected) {
- throw new ConcurrentModificationException();
- }
- value = newValue;
- }
+ /**
+ * {@inheritDoc}
+ *
+ * @since 11.0
+ */
+ @Override
+ public Comparator<? super E> comparator() {
+ return super.comparator();
}
- private static final class AvlNode<E> extends Multisets.AbstractEntry<E> {
- @Nullable private final E elem;
-
- // elemCount is 0 iff this node has been deleted.
- private int elemCount;
+ private static final class Node<E> extends BstNode<E, Node<E>> implements Serializable {
+ private final long size;
+ private final int distinct;
- private int distinctElements;
- private long totalCount;
- private int height;
- private AvlNode<E> left;
- private AvlNode<E> right;
- private AvlNode<E> pred;
- private AvlNode<E> succ;
-
- AvlNode(@Nullable E elem, int elemCount) {
+ private Node(E key, int elemCount, @Nullable Node<E> left,
+ @Nullable Node<E> right) {
+ super(key, left, right);
checkArgument(elemCount > 0);
- this.elem = elem;
- this.elemCount = elemCount;
- this.totalCount = elemCount;
- this.distinctElements = 1;
- this.height = 1;
- this.left = null;
- this.right = null;
- }
-
- public int count(Comparator<? super E> comparator, E e) {
- int cmp = comparator.compare(e, elem);
- if (cmp < 0) {
- return (left == null) ? 0 : left.count(comparator, e);
- } else if (cmp > 0) {
- return (right == null) ? 0 : right.count(comparator, e);
- } else {
- return elemCount;
- }
+ this.size = (long) elemCount + sizeOrZero(left) + sizeOrZero(right);
+ this.distinct = 1 + distinctOrZero(left) + distinctOrZero(right);
}
- private AvlNode<E> addRightChild(E e, int count) {
- right = new AvlNode<E>(e, count);
- successor(this, right, succ);
- height = Math.max(2, height);
- distinctElements++;
- totalCount += count;
- return this;
+ int elemCount() {
+ long result = size - sizeOrZero(childOrNull(LEFT))
+ - sizeOrZero(childOrNull(RIGHT));
+ return Ints.checkedCast(result);
}
- private AvlNode<E> addLeftChild(E e, int count) {
- left = new AvlNode<E>(e, count);
- successor(pred, left, this);
- height = Math.max(2, height);
- distinctElements++;
- totalCount += count;
- return this;
- }
-
- AvlNode<E> add(Comparator<? super E> comparator, @Nullable E e, int count, int[] result) {
- /*
- * It speeds things up considerably to unconditionally add count to totalCount here,
- * but that destroys failure atomicity in the case of count overflow. =(
- */
- int cmp = comparator.compare(e, elem);
- if (cmp < 0) {
- AvlNode<E> initLeft = left;
- if (initLeft == null) {
- result[0] = 0;
- return addLeftChild(e, count);
- }
- int initHeight = initLeft.height;
-
- left = initLeft.add(comparator, e, count, result);
- if (result[0] == 0) {
- distinctElements++;
- }
- this.totalCount += count;
- return (left.height == initHeight) ? this : rebalance();
- } else if (cmp > 0) {
- AvlNode<E> initRight = right;
- if (initRight == null) {
- result[0] = 0;
- return addRightChild(e, count);
- }
- int initHeight = initRight.height;
-
- right = initRight.add(comparator, e, count, result);
- if (result[0] == 0) {
- distinctElements++;
- }
- this.totalCount += count;
- return (right.height == initHeight) ? this : rebalance();
- }
-
- // adding count to me! No rebalance possible.
- result[0] = elemCount;
- long resultCount = (long) elemCount + count;
- checkArgument(resultCount <= Integer.MAX_VALUE);
- this.elemCount += count;
- this.totalCount += count;
- return this;
+ private Node(E key, int elemCount) {
+ this(key, elemCount, null, null);
}
- AvlNode<E> remove(Comparator<? super E> comparator, @Nullable E e, int count, int[] result) {
- int cmp = comparator.compare(e, elem);
- if (cmp < 0) {
- AvlNode<E> initLeft = left;
- if (initLeft == null) {
- result[0] = 0;
- return this;
- }
+ private static final long serialVersionUID = 0;
+ }
- left = initLeft.remove(comparator, e, count, result);
+ private static long sizeOrZero(@Nullable Node<?> node) {
+ return (node == null) ? 0 : node.size;
+ }
- if (result[0] > 0) {
- if (count >= result[0]) {
- this.distinctElements--;
- this.totalCount -= result[0];
- } else {
- this.totalCount -= count;
- }
- }
- return (result[0] == 0) ? this : rebalance();
- } else if (cmp > 0) {
- AvlNode<E> initRight = right;
- if (initRight == null) {
- result[0] = 0;
- return this;
- }
+ private static int distinctOrZero(@Nullable Node<?> node) {
+ return (node == null) ? 0 : node.distinct;
+ }
- right = initRight.remove(comparator, e, count, result);
+ private static int countOrZero(@Nullable Node<?> entry) {
+ return (entry == null) ? 0 : entry.elemCount();
+ }
- if (result[0] > 0) {
- if (count >= result[0]) {
- this.distinctElements--;
- this.totalCount -= result[0];
- } else {
- this.totalCount -= count;
- }
- }
- return rebalance();
- }
+ @SuppressWarnings("unchecked")
+ private BstAggregate<Node<E>> distinctAggregate() {
+ return (BstAggregate) DISTINCT_AGGREGATE;
+ }
- // removing count from me!
- result[0] = elemCount;
- if (count >= elemCount) {
- return deleteMe();
- } else {
- this.elemCount -= count;
- this.totalCount -= count;
- return this;
- }
+ private static final BstAggregate<Node<Object>> DISTINCT_AGGREGATE =
+ new BstAggregate<Node<Object>>() {
+ @Override
+ public int entryValue(Node<Object> entry) {
+ return 1;
}
- AvlNode<E> setCount(Comparator<? super E> comparator, @Nullable E e, int count, int[] result) {
- int cmp = comparator.compare(e, elem);
- if (cmp < 0) {
- AvlNode<E> initLeft = left;
- if (initLeft == null) {
- result[0] = 0;
- return (count > 0) ? addLeftChild(e, count) : this;
- }
-
- left = initLeft.setCount(comparator, e, count, result);
-
- if (count == 0 && result[0] != 0) {
- this.distinctElements--;
- } else if (count > 0 && result[0] == 0) {
- this.distinctElements++;
- }
-
- this.totalCount += count - result[0];
- return rebalance();
- } else if (cmp > 0) {
- AvlNode<E> initRight = right;
- if (initRight == null) {
- result[0] = 0;
- return (count > 0) ? addRightChild(e, count) : this;
- }
-
- right = initRight.setCount(comparator, e, count, result);
-
- if (count == 0 && result[0] != 0) {
- this.distinctElements--;
- } else if (count > 0 && result[0] == 0) {
- this.distinctElements++;
- }
-
- this.totalCount += count - result[0];
- return rebalance();
- }
-
- // setting my count
- result[0] = elemCount;
- if (count == 0) {
- return deleteMe();
- }
- this.totalCount += count - elemCount;
- this.elemCount = count;
- return this;
+ @Override
+ public long treeValue(@Nullable Node<Object> tree) {
+ return distinctOrZero(tree);
}
+ };
- AvlNode<E> setCount(
- Comparator<? super E> comparator,
- @Nullable E e,
- int expectedCount,
- int newCount,
- int[] result) {
- int cmp = comparator.compare(e, elem);
- if (cmp < 0) {
- AvlNode<E> initLeft = left;
- if (initLeft == null) {
- result[0] = 0;
- if (expectedCount == 0 && newCount > 0) {
- return addLeftChild(e, newCount);
- }
- return this;
- }
-
- left = initLeft.setCount(comparator, e, expectedCount, newCount, result);
+ @SuppressWarnings("unchecked")
+ private BstAggregate<Node<E>> sizeAggregate() {
+ return (BstAggregate) SIZE_AGGREGATE;
+ }
- if (result[0] == expectedCount) {
- if (newCount == 0 && result[0] != 0) {
- this.distinctElements--;
- } else if (newCount > 0 && result[0] == 0) {
- this.distinctElements++;
- }
- this.totalCount += newCount - result[0];
- }
- return rebalance();
- } else if (cmp > 0) {
- AvlNode<E> initRight = right;
- if (initRight == null) {
- result[0] = 0;
- if (expectedCount == 0 && newCount > 0) {
- return addRightChild(e, newCount);
- }
- return this;
+ private static final BstAggregate<Node<Object>> SIZE_AGGREGATE =
+ new BstAggregate<Node<Object>>() {
+ @Override
+ public int entryValue(Node<Object> entry) {
+ return entry.elemCount();
}
- right = initRight.setCount(comparator, e, expectedCount, newCount, result);
-
- if (result[0] == expectedCount) {
- if (newCount == 0 && result[0] != 0) {
- this.distinctElements--;
- } else if (newCount > 0 && result[0] == 0) {
- this.distinctElements++;
- }
- this.totalCount += newCount - result[0];
+ @Override
+ public long treeValue(@Nullable Node<Object> tree) {
+ return sizeOrZero(tree);
}
- return rebalance();
- }
+ };
- // setting my count
- result[0] = elemCount;
- if (expectedCount == elemCount) {
- if (newCount == 0) {
- return deleteMe();
- }
- this.totalCount += newCount - elemCount;
- this.elemCount = newCount;
- }
- return this;
- }
+ @SuppressWarnings("unchecked")
+ private BstNodeFactory<Node<E>> nodeFactory() {
+ return (BstNodeFactory) NODE_FACTORY;
+ }
- private AvlNode<E> deleteMe() {
- int oldElemCount = this.elemCount;
- this.elemCount = 0;
- successor(pred, succ);
- if (left == null) {
- return right;
- } else if (right == null) {
- return left;
- } else if (left.height >= right.height) {
- AvlNode<E> newTop = pred;
- // newTop is the maximum node in my left subtree
- newTop.left = left.removeMax(newTop);
- newTop.right = right;
- newTop.distinctElements = distinctElements - 1;
- newTop.totalCount = totalCount - oldElemCount;
- return newTop.rebalance();
- } else {
- AvlNode<E> newTop = succ;
- newTop.right = right.removeMin(newTop);
- newTop.left = left;
- newTop.distinctElements = distinctElements - 1;
- newTop.totalCount = totalCount - oldElemCount;
- return newTop.rebalance();
- }
- }
+ private static final BstNodeFactory<Node<Object>> NODE_FACTORY =
+ new BstNodeFactory<Node<Object>>() {
+ @Override
+ public Node<Object> createNode(Node<Object> source, @Nullable Node<Object> left,
+ @Nullable Node<Object> right) {
+ return new Node<Object>(source.getKey(), source.elemCount(), left, right);
+ }
+ };
- // Removes the minimum node from this subtree to be reused elsewhere
- private AvlNode<E> removeMin(AvlNode<E> node) {
- if (left == null) {
- return right;
- } else {
- left = left.removeMin(node);
- distinctElements--;
- totalCount -= node.elemCount;
- return rebalance();
- }
- }
+ private abstract class MultisetModifier implements BstModifier<E, Node<E>> {
+ abstract int newCount(int oldCount);
- // Removes the maximum node from this subtree to be reused elsewhere
- private AvlNode<E> removeMax(AvlNode<E> node) {
- if (right == null) {
- return left;
+ @Nullable
+ @Override
+ public BstModificationResult<Node<E>> modify(E key, @Nullable Node<E> originalEntry) {
+ int oldCount = countOrZero(originalEntry);
+ int newCount = newCount(oldCount);
+ if (oldCount == newCount) {
+ return BstModificationResult.identity(originalEntry);
+ } else if (newCount == 0) {
+ return BstModificationResult.rebalancingChange(originalEntry, null);
+ } else if (oldCount == 0) {
+ return BstModificationResult.rebalancingChange(null, new Node<E>(key, newCount));
} else {
- right = right.removeMax(node);
- distinctElements--;
- totalCount -= node.elemCount;
- return rebalance();
+ return BstModificationResult.rebuildingChange(originalEntry,
+ new Node<E>(originalEntry.getKey(), newCount));
}
}
+ }
- private void recomputeMultiset() {
- this.distinctElements = 1 + TreeMultiset.distinctElements(left)
- + TreeMultiset.distinctElements(right);
- this.totalCount = elemCount + totalCount(left) + totalCount(right);
- }
-
- private void recomputeHeight() {
- this.height = 1 + Math.max(height(left), height(right));
- }
+ private final class AddModifier extends MultisetModifier {
+ private final int countToAdd;
- private void recompute() {
- recomputeMultiset();
- recomputeHeight();
+ private AddModifier(int countToAdd) {
+ checkArgument(countToAdd > 0);
+ this.countToAdd = countToAdd;
}
- private AvlNode<E> rebalance() {
- switch (balanceFactor()) {
- case -2:
- if (right.balanceFactor() > 0) {
- right = right.rotateRight();
- }
- return rotateLeft();
- case 2:
- if (left.balanceFactor() < 0) {
- left = left.rotateLeft();
- }
- return rotateRight();
- default:
- recomputeHeight();
- return this;
- }
+ @Override
+ int newCount(int oldCount) {
+ checkArgument(countToAdd <= Integer.MAX_VALUE - oldCount, "Cannot add this many elements");
+ return oldCount + countToAdd;
}
+ }
- private int balanceFactor() {
- return height(left) - height(right);
- }
+ private final class RemoveModifier extends MultisetModifier {
+ private final int countToRemove;
- private AvlNode<E> rotateLeft() {
- checkState(right != null);
- AvlNode<E> newTop = right;
- this.right = newTop.left;
- newTop.left = this;
- newTop.totalCount = this.totalCount;
- newTop.distinctElements = this.distinctElements;
- this.recompute();
- newTop.recomputeHeight();
- return newTop;
+ private RemoveModifier(int countToRemove) {
+ checkArgument(countToRemove > 0);
+ this.countToRemove = countToRemove;
}
- private AvlNode<E> rotateRight() {
- checkState(left != null);
- AvlNode<E> newTop = left;
- this.left = newTop.right;
- newTop.right = this;
- newTop.totalCount = this.totalCount;
- newTop.distinctElements = this.distinctElements;
- this.recompute();
- newTop.recomputeHeight();
- return newTop;
+ @Override
+ int newCount(int oldCount) {
+ return Math.max(0, oldCount - countToRemove);
}
+ }
- private static long totalCount(@Nullable AvlNode<?> node) {
- return (node == null) ? 0 : node.totalCount;
- }
+ private final class SetCountModifier extends MultisetModifier {
+ private final int countToSet;
- private static int height(@Nullable AvlNode<?> node) {
- return (node == null) ? 0 : node.height;
- }
-
- @Nullable private AvlNode<E> ceiling(Comparator<? super E> comparator, E e) {
- int cmp = comparator.compare(e, elem);
- if (cmp < 0) {
- return (left == null) ? this : Objects.firstNonNull(left.ceiling(comparator, e), this);
- } else if (cmp == 0) {
- return this;
- } else {
- return (right == null) ? null : right.ceiling(comparator, e);
- }
- }
-
- @Nullable private AvlNode<E> floor(Comparator<? super E> comparator, E e) {
- int cmp = comparator.compare(e, elem);
- if (cmp > 0) {
- return (right == null) ? this : Objects.firstNonNull(right.floor(comparator, e), this);
- } else if (cmp == 0) {
- return this;
- } else {
- return (left == null) ? null : left.floor(comparator, e);
- }
+ private SetCountModifier(int countToSet) {
+ checkArgument(countToSet >= 0);
+ this.countToSet = countToSet;
}
@Override
- public E getElement() {
- return elem;
+ int newCount(int oldCount) {
+ return countToSet;
}
+ }
- @Override
- public int getCount() {
- return elemCount;
+ private final class ConditionalSetCountModifier extends MultisetModifier {
+ private final int expectedCount;
+ private final int setCount;
+
+ private ConditionalSetCountModifier(int expectedCount, int setCount) {
+ checkArgument(setCount >= 0 & expectedCount >= 0);
+ this.expectedCount = expectedCount;
+ this.setCount = setCount;
}
@Override
- public String toString() {
- return Multisets.immutableEntry(getElement(), getCount()).toString();
+ int newCount(int oldCount) {
+ return (oldCount == expectedCount) ? setCount : oldCount;
}
}
- private static <T> void successor(AvlNode<T> a, AvlNode<T> b) {
- a.succ = b;
- b.pred = a;
- }
-
- private static <T> void successor(AvlNode<T> a, AvlNode<T> b, AvlNode<T> c) {
- successor(a, b);
- successor(b, c);
- }
-
/*
- * TODO(jlevy): Decide whether entrySet() should return entries with an equals() method that
- * calls the comparator to compare the two keys. If that change is made,
- * AbstractMultiset.equals() can simply check whether two multisets have equal entry sets.
+ * TODO(jlevy): Decide whether entrySet() should return entries with an
+ * equals() method that calls the comparator to compare the two keys. If that
+ * change is made, AbstractMultiset.equals() can simply check whether two
+ * multisets have equal entry sets.
*/
/**
- * @serialData the comparator, the number of distinct elements, the first element, its count, the
- * second element, its count, and so on
+ * @serialData the comparator, the number of distinct elements, the first
+ * element, its count, the second element, its count, and so on
*/
@GwtIncompatible("java.io.ObjectOutputStream")
private void writeObject(ObjectOutputStream stream) throws IOException {
@@ -960,23 +553,19 @@ public final class TreeMultiset<E> extends AbstractSortedMultiset<E> implements
}
@GwtIncompatible("java.io.ObjectInputStream")
- private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
stream.defaultReadObject();
- @SuppressWarnings("unchecked")
- // reading data stored by writeObject
+ @SuppressWarnings("unchecked") // reading data stored by writeObject
Comparator<? super E> comparator = (Comparator<? super E>) stream.readObject();
Serialization.getFieldSetter(AbstractSortedMultiset.class, "comparator").set(this, comparator);
- Serialization.getFieldSetter(TreeMultiset.class, "range").set(
- this,
+ Serialization.getFieldSetter(TreeMultiset.class, "range").set(this,
GeneralRange.all(comparator));
- Serialization.getFieldSetter(TreeMultiset.class, "rootReference").set(
- this,
- new Reference<AvlNode<E>>());
- AvlNode<E> header = new AvlNode<E>(null, 1);
- Serialization.getFieldSetter(TreeMultiset.class, "header").set(this, header);
- successor(header, header);
+ Serialization.getFieldSetter(TreeMultiset.class, "rootReference").set(this,
+ new Reference<Node<E>>());
Serialization.populateMultiset(this, stream);
}
- @GwtIncompatible("not needed in emulated source") private static final long serialVersionUID = 1;
+ @GwtIncompatible("not needed in emulated source")
+ private static final long serialVersionUID = 1;
}
diff --git a/guava/src/com/google/common/collect/TreeRangeMap.java b/guava/src/com/google/common/collect/TreeRangeMap.java
deleted file mode 100644
index e5b5f47..0000000
--- a/guava/src/com/google/common/collect/TreeRangeMap.java
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Predicates.compose;
-import static com.google.common.base.Predicates.in;
-import static com.google.common.base.Predicates.not;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtIncompatible;
-import com.google.common.base.Objects;
-import com.google.common.base.Predicate;
-
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.NavigableMap;
-import java.util.NoSuchElementException;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-/**
- * An implementation of {@code RangeMap} based on a {@code TreeMap}, supporting
- * all optional operations.
- *
- * <p>Like all {@code RangeMap} implementations, this supports neither null
- * keys nor null values.
- *
- * @author Louis Wasserman
- * @since 14.0
- */
-@Beta
-@GwtIncompatible("NavigableMap")
-public final class TreeRangeMap<K extends Comparable, V> implements RangeMap<K, V> {
-
- private final NavigableMap<Cut<K>, RangeMapEntry<K, V>> entriesByLowerBound;
-
- public static <K extends Comparable, V> TreeRangeMap<K, V> create() {
- return new TreeRangeMap<K, V>();
- }
-
- private TreeRangeMap() {
- this.entriesByLowerBound = Maps.newTreeMap();
- }
-
- private static final class RangeMapEntry<K extends Comparable, V>
- extends AbstractMapEntry<Range<K>, V> {
- private final Range<K> range;
- private final V value;
-
- RangeMapEntry(Cut<K> lowerBound, Cut<K> upperBound, V value) {
- this(Range.create(lowerBound, upperBound), value);
- }
-
- RangeMapEntry(Range<K> range, V value) {
- this.range = range;
- this.value = value;
- }
-
- @Override
- public Range<K> getKey() {
- return range;
- }
-
- @Override
- public V getValue() {
- return value;
- }
-
- public boolean contains(K value) {
- return range.contains(value);
- }
-
- Cut<K> getLowerBound() {
- return range.lowerBound;
- }
-
- Cut<K> getUpperBound() {
- return range.upperBound;
- }
- }
-
- @Override
- @Nullable
- public V get(K key) {
- Entry<Range<K>, V> entry = getEntry(key);
- return (entry == null) ? null : entry.getValue();
- }
-
- @Override
- @Nullable
- public Entry<Range<K>, V> getEntry(K key) {
- Map.Entry<Cut<K>, RangeMapEntry<K, V>> mapEntry =
- entriesByLowerBound.floorEntry(Cut.belowValue(key));
- if (mapEntry != null && mapEntry.getValue().contains(key)) {
- return mapEntry.getValue();
- } else {
- return null;
- }
- }
-
- @Override
- public void put(Range<K> range, V value) {
- if (!range.isEmpty()) {
- checkNotNull(value);
- remove(range);
- entriesByLowerBound.put(range.lowerBound, new RangeMapEntry<K, V>(range, value));
- }
- }
-
- @Override
- public void putAll(RangeMap<K, V> rangeMap) {
- for (Map.Entry<Range<K>, V> entry : rangeMap.asMapOfRanges().entrySet()) {
- put(entry.getKey(), entry.getValue());
- }
- }
-
- @Override
- public void clear() {
- entriesByLowerBound.clear();
- }
-
- @Override
- public Range<K> span() {
- Entry<Cut<K>, RangeMapEntry<K, V>> firstEntry = entriesByLowerBound.firstEntry();
- Entry<Cut<K>, RangeMapEntry<K, V>> lastEntry = entriesByLowerBound.lastEntry();
- if (firstEntry == null) {
- throw new NoSuchElementException();
- }
- return Range.create(
- firstEntry.getValue().getKey().lowerBound,
- lastEntry.getValue().getKey().upperBound);
- }
-
- private void putRangeMapEntry(Cut<K> lowerBound, Cut<K> upperBound, V value) {
- entriesByLowerBound.put(lowerBound, new RangeMapEntry<K, V>(lowerBound, upperBound, value));
- }
-
- @Override
- public void remove(Range<K> rangeToRemove) {
- if (rangeToRemove.isEmpty()) {
- return;
- }
-
- /*
- * The comments for this method will use [ ] to indicate the bounds of rangeToRemove and ( ) to
- * indicate the bounds of ranges in the range map.
- */
- Map.Entry<Cut<K>, RangeMapEntry<K, V>> mapEntryBelowToTruncate =
- entriesByLowerBound.lowerEntry(rangeToRemove.lowerBound);
- if (mapEntryBelowToTruncate != null) {
- // we know ( [
- RangeMapEntry<K, V> rangeMapEntry = mapEntryBelowToTruncate.getValue();
- if (rangeMapEntry.getUpperBound().compareTo(rangeToRemove.lowerBound) > 0) {
- // we know ( [ )
- if (rangeMapEntry.getUpperBound().compareTo(rangeToRemove.upperBound) > 0) {
- // we know ( [ ] ), so insert the range ] ) back into the map --
- // it's being split apart
- putRangeMapEntry(rangeToRemove.upperBound, rangeMapEntry.getUpperBound(),
- mapEntryBelowToTruncate.getValue().getValue());
- }
- // overwrite mapEntryToTruncateBelow with a truncated range
- putRangeMapEntry(rangeMapEntry.getLowerBound(), rangeToRemove.lowerBound,
- mapEntryBelowToTruncate.getValue().getValue());
- }
- }
-
- Map.Entry<Cut<K>, RangeMapEntry<K, V>> mapEntryAboveToTruncate =
- entriesByLowerBound.lowerEntry(rangeToRemove.upperBound);
- if (mapEntryAboveToTruncate != null) {
- // we know ( ]
- RangeMapEntry<K, V> rangeMapEntry = mapEntryAboveToTruncate.getValue();
- if (rangeMapEntry.getUpperBound().compareTo(rangeToRemove.upperBound) > 0) {
- // we know ( ] ), and since we dealt with truncating below already,
- // we know [ ( ] )
- putRangeMapEntry(rangeToRemove.upperBound, rangeMapEntry.getUpperBound(),
- mapEntryAboveToTruncate.getValue().getValue());
- entriesByLowerBound.remove(rangeToRemove.lowerBound);
- }
- }
- entriesByLowerBound.subMap(rangeToRemove.lowerBound, rangeToRemove.upperBound).clear();
- }
-
- @Override
- public Map<Range<K>, V> asMapOfRanges() {
- return new AsMapOfRanges();
- }
-
- private final class AsMapOfRanges extends AbstractMap<Range<K>, V> {
-
- @Override
- public boolean containsKey(@Nullable Object key) {
- return get(key) != null;
- }
-
- @Override
- public V get(@Nullable Object key) {
- if (key instanceof Range) {
- Range<?> range = (Range<?>) key;
- RangeMapEntry<K, V> rangeMapEntry = entriesByLowerBound.get(range.lowerBound);
- if (rangeMapEntry != null && rangeMapEntry.getKey().equals(range)) {
- return rangeMapEntry.getValue();
- }
- }
- return null;
- }
-
- @Override
- public Set<Entry<Range<K>, V>> entrySet() {
- return new AbstractSet<Entry<Range<K>, V>>() {
-
- @SuppressWarnings("unchecked") // it's safe to upcast iterators
- @Override
- public Iterator<Entry<Range<K>, V>> iterator() {
- return (Iterator) entriesByLowerBound.values().iterator();
- }
-
- @Override
- public int size() {
- return entriesByLowerBound.size();
- }
- };
- }
- }
-
- @Override
- public RangeMap<K, V> subRangeMap(Range<K> subRange) {
- if (subRange.equals(Range.all())) {
- return this;
- } else {
- return new SubRangeMap(subRange);
- }
- }
-
- @SuppressWarnings("unchecked")
- private RangeMap<K, V> emptySubRangeMap() {
- return EMPTY_SUB_RANGE_MAP;
- }
-
- private static final RangeMap EMPTY_SUB_RANGE_MAP =
- new RangeMap() {
- @Override
- @Nullable
- public Object get(Comparable key) {
- return null;
- }
-
- @Override
- @Nullable
- public Entry<Range, Object> getEntry(Comparable key) {
- return null;
- }
-
- @Override
- public Range span() {
- throw new NoSuchElementException();
- }
-
- @Override
- public void put(Range range, Object value) {
- checkNotNull(range);
- throw new IllegalArgumentException(
- "Cannot insert range " + range + " into an empty subRangeMap");
- }
-
- @Override
- public void putAll(RangeMap rangeMap) {
- if (!rangeMap.asMapOfRanges().isEmpty()) {
- throw new IllegalArgumentException(
- "Cannot putAll(nonEmptyRangeMap) into an empty " + "subRangeMap");
- }
- }
-
- @Override
- public void clear() {}
-
- @Override
- public void remove(Range range) {
- checkNotNull(range);
- }
-
- @Override
- public Map<Range, Object> asMapOfRanges() {
- return Collections.emptyMap();
- }
-
- @Override
- public RangeMap subRangeMap(Range range) {
- checkNotNull(range);
- return this;
- }
- };
-
- private class SubRangeMap implements RangeMap<K, V> {
-
- private final Range<K> subRange;
-
- SubRangeMap(Range<K> subRange) {
- this.subRange = subRange;
- }
-
- @Override
- @Nullable
- public V get(K key) {
- return subRange.contains(key)
- ? TreeRangeMap.this.get(key)
- : null;
- }
-
- @Override
- @Nullable
- public Entry<Range<K>, V> getEntry(K key) {
- if (subRange.contains(key)) {
- Entry<Range<K>, V> entry = TreeRangeMap.this.getEntry(key);
- if (entry != null) {
- return Maps.immutableEntry(entry.getKey().intersection(subRange), entry.getValue());
- }
- }
- return null;
- }
-
- @Override
- public Range<K> span() {
- Cut<K> lowerBound;
- Entry<Cut<K>, RangeMapEntry<K, V>> lowerEntry =
- entriesByLowerBound.floorEntry(subRange.lowerBound);
- if (lowerEntry != null &&
- lowerEntry.getValue().getUpperBound().compareTo(subRange.lowerBound) > 0) {
- lowerBound = subRange.lowerBound;
- } else {
- lowerBound = entriesByLowerBound.ceilingKey(subRange.lowerBound);
- if (lowerBound == null || lowerBound.compareTo(subRange.upperBound) >= 0) {
- throw new NoSuchElementException();
- }
- }
-
- Cut<K> upperBound;
- Entry<Cut<K>, RangeMapEntry<K, V>> upperEntry =
- entriesByLowerBound.lowerEntry(subRange.upperBound);
- if (upperEntry == null) {
- throw new NoSuchElementException();
- } else if (upperEntry.getValue().getUpperBound().compareTo(subRange.upperBound) >= 0) {
- upperBound = subRange.upperBound;
- } else {
- upperBound = upperEntry.getValue().getUpperBound();
- }
- return Range.create(lowerBound, upperBound);
- }
-
- @Override
- public void put(Range<K> range, V value) {
- checkArgument(subRange.encloses(range),
- "Cannot put range %s into a subRangeMap(%s)", range, subRange);
- TreeRangeMap.this.put(range, value);
- }
-
- @Override
- public void putAll(RangeMap<K, V> rangeMap) {
- if (rangeMap.asMapOfRanges().isEmpty()) {
- return;
- }
- Range<K> span = rangeMap.span();
- checkArgument(subRange.encloses(span),
- "Cannot putAll rangeMap with span %s into a subRangeMap(%s)", span, subRange);
- TreeRangeMap.this.putAll(rangeMap);
- }
-
- @Override
- public void clear() {
- TreeRangeMap.this.remove(subRange);
- }
-
- @Override
- public void remove(Range<K> range) {
- if (range.isConnected(subRange)) {
- TreeRangeMap.this.remove(range.intersection(subRange));
- }
- }
-
- @Override
- public RangeMap<K, V> subRangeMap(Range<K> range) {
- if (!range.isConnected(subRange)) {
- return emptySubRangeMap();
- } else {
- return TreeRangeMap.this.subRangeMap(range.intersection(subRange));
- }
- }
-
- @Override
- public Map<Range<K>, V> asMapOfRanges() {
- return new SubRangeMapAsMap();
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (o instanceof RangeMap) {
- RangeMap<?, ?> rangeMap = (RangeMap<?, ?>) o;
- return asMapOfRanges().equals(rangeMap.asMapOfRanges());
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return asMapOfRanges().hashCode();
- }
-
- @Override
- public String toString() {
- return asMapOfRanges().toString();
- }
-
- class SubRangeMapAsMap extends AbstractMap<Range<K>, V> {
-
- @Override
- public boolean containsKey(Object key) {
- return get(key) != null;
- }
-
- @Override
- public V get(Object key) {
- try {
- if (key instanceof Range) {
- @SuppressWarnings("unchecked") // we catch ClassCastExceptions
- Range<K> r = (Range<K>) key;
- if (!subRange.encloses(r) || r.isEmpty()) {
- return null;
- }
- RangeMapEntry<K, V> candidate = null;
- if (r.lowerBound.compareTo(subRange.lowerBound) == 0) {
- // r could be truncated on the left
- Entry<Cut<K>, RangeMapEntry<K, V>> entry =
- entriesByLowerBound.floorEntry(r.lowerBound);
- if (entry != null) {
- candidate = entry.getValue();
- }
- } else {
- candidate = entriesByLowerBound.get(r.lowerBound);
- }
-
- if (candidate != null && candidate.getKey().isConnected(subRange)
- && candidate.getKey().intersection(subRange).equals(r)) {
- return candidate.getValue();
- }
- }
- } catch (ClassCastException e) {
- return null;
- }
- return null;
- }
-
- @Override
- public V remove(Object key) {
- V value = get(key);
- if (value != null) {
- @SuppressWarnings("unchecked") // it's definitely in the map, so safe
- Range<K> range = (Range<K>) key;
- TreeRangeMap.this.remove(range);
- return value;
- }
- return null;
- }
-
- @Override
- public void clear() {
- SubRangeMap.this.clear();
- }
-
- private boolean removeIf(Predicate<? super Entry<Range<K>, V>> predicate) {
- List<Range<K>> toRemove = Lists.newArrayList();
- for (Entry<Range<K>, V> entry : entrySet()) {
- if (predicate.apply(entry)) {
- toRemove.add(entry.getKey());
- }
- }
- for (Range<K> range : toRemove) {
- TreeRangeMap.this.remove(range);
- }
- return !toRemove.isEmpty();
- }
-
- @Override
- public Set<Range<K>> keySet() {
- return new Maps.KeySet<Range<K>, V>() {
- @Override
- Map<Range<K>, V> map() {
- return SubRangeMapAsMap.this;
- }
-
- @Override
- public boolean remove(@Nullable Object o) {
- return SubRangeMapAsMap.this.remove(o) != null;
- }
-
- @Override
- public boolean retainAll(Collection<?> c) {
- return removeIf(compose(not(in(c)), Maps.<Range<K>>keyFunction()));
- }
- };
- }
-
- @Override
- public Set<Entry<Range<K>, V>> entrySet() {
- return new Maps.EntrySet<Range<K>, V>() {
- @Override
- Map<Range<K>, V> map() {
- return SubRangeMapAsMap.this;
- }
-
- @Override
- public Iterator<Entry<Range<K>, V>> iterator() {
- if (subRange.isEmpty()) {
- return Iterators.emptyIterator();
- }
- Cut<K> cutToStart = Objects.firstNonNull(
- entriesByLowerBound.floorKey(subRange.lowerBound),
- subRange.lowerBound);
- final Iterator<RangeMapEntry<K, V>> backingItr =
- entriesByLowerBound.tailMap(cutToStart, true).values().iterator();
- return new AbstractIterator<Entry<Range<K>, V>>() {
-
- @Override
- protected Entry<Range<K>, V> computeNext() {
- while (backingItr.hasNext()) {
- RangeMapEntry<K, V> entry = backingItr.next();
- if (entry.getLowerBound().compareTo(subRange.upperBound) >= 0) {
- break;
- } else if (entry.getUpperBound().compareTo(subRange.lowerBound) > 0) {
- // this might not be true e.g. at the start of the iteration
- return Maps.immutableEntry(
- entry.getKey().intersection(subRange), entry.getValue());
- }
- }
- return endOfData();
- }
- };
- }
-
- @Override
- public boolean retainAll(Collection<?> c) {
- return removeIf(not(in(c)));
- }
-
- @Override
- public int size() {
- return Iterators.size(iterator());
- }
-
- @Override
- public boolean isEmpty() {
- return !iterator().hasNext();
- }
- };
- }
-
- @Override
- public Collection<V> values() {
- return new Maps.Values<Range<K>, V>() {
- @Override
- Map<Range<K>, V> map() {
- return SubRangeMapAsMap.this;
- }
-
- @Override
- public boolean removeAll(Collection<?> c) {
- return removeIf(compose(in(c), Maps.<V>valueFunction()));
- }
-
- @Override
- public boolean retainAll(Collection<?> c) {
- return removeIf(compose(not(in(c)), Maps.<V>valueFunction()));
- }
- };
- }
- }
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (o instanceof RangeMap) {
- RangeMap<?, ?> rangeMap = (RangeMap<?, ?>) o;
- return asMapOfRanges().equals(rangeMap.asMapOfRanges());
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return asMapOfRanges().hashCode();
- }
-
- @Override
- public String toString() {
- return entriesByLowerBound.values().toString();
- }
-}
diff --git a/guava/src/com/google/common/collect/TreeRangeSet.java b/guava/src/com/google/common/collect/TreeRangeSet.java
deleted file mode 100644
index d67c5f4..0000000
--- a/guava/src/com/google/common/collect/TreeRangeSet.java
+++ /dev/null
@@ -1,851 +0,0 @@
-/*
- * Copyright (C) 2011 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtIncompatible;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
-
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.Map.Entry;
-import java.util.NavigableMap;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.TreeMap;
-
-import javax.annotation.Nullable;
-
-/**
- * An implementation of {@link RangeSet} backed by a {@link TreeMap}.
- *
- * @author Louis Wasserman
- * @since 14.0
- */
-@Beta
-@GwtIncompatible("uses NavigableMap")
-public class TreeRangeSet<C extends Comparable<?>>
- extends AbstractRangeSet<C> {
-
- @VisibleForTesting
- final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound;
-
- /**
- * Creates an empty {@code TreeRangeSet} instance.
- */
- public static <C extends Comparable<?>> TreeRangeSet<C> create() {
- return new TreeRangeSet<C>(new TreeMap<Cut<C>, Range<C>>());
- }
-
- /**
- * Returns a {@code TreeRangeSet} initialized with the ranges in the specified range set.
- */
- public static <C extends Comparable<?>> TreeRangeSet<C> create(RangeSet<C> rangeSet) {
- TreeRangeSet<C> result = create();
- result.addAll(rangeSet);
- return result;
- }
-
- private TreeRangeSet(NavigableMap<Cut<C>, Range<C>> rangesByLowerCut) {
- this.rangesByLowerBound = rangesByLowerCut;
- }
-
- private transient Set<Range<C>> asRanges;
-
- @Override
- public Set<Range<C>> asRanges() {
- Set<Range<C>> result = asRanges;
- return (result == null) ? asRanges = new AsRanges() : result;
- }
-
- final class AsRanges extends ForwardingCollection<Range<C>> implements Set<Range<C>> {
- @Override
- protected Collection<Range<C>> delegate() {
- return rangesByLowerBound.values();
- }
-
- @Override
- public int hashCode() {
- return Sets.hashCodeImpl(this);
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- return Sets.equalsImpl(this, o);
- }
- }
-
- @Override
- @Nullable
- public Range<C> rangeContaining(C value) {
- checkNotNull(value);
- Entry<Cut<C>, Range<C>> floorEntry = rangesByLowerBound.floorEntry(Cut.belowValue(value));
- if (floorEntry != null && floorEntry.getValue().contains(value)) {
- return floorEntry.getValue();
- } else {
- // TODO(kevinb): revisit this design choice
- return null;
- }
- }
-
- @Override
- public boolean encloses(Range<C> range) {
- checkNotNull(range);
- Entry<Cut<C>, Range<C>> floorEntry = rangesByLowerBound.floorEntry(range.lowerBound);
- return floorEntry != null && floorEntry.getValue().encloses(range);
- }
-
- @Nullable
- private Range<C> rangeEnclosing(Range<C> range) {
- checkNotNull(range);
- Entry<Cut<C>, Range<C>> floorEntry = rangesByLowerBound.floorEntry(range.lowerBound);
- return (floorEntry != null && floorEntry.getValue().encloses(range))
- ? floorEntry.getValue()
- : null;
- }
-
- @Override
- public Range<C> span() {
- Entry<Cut<C>, Range<C>> firstEntry = rangesByLowerBound.firstEntry();
- Entry<Cut<C>, Range<C>> lastEntry = rangesByLowerBound.lastEntry();
- if (firstEntry == null) {
- throw new NoSuchElementException();
- }
- return Range.create(firstEntry.getValue().lowerBound, lastEntry.getValue().upperBound);
- }
-
- @Override
- public void add(Range<C> rangeToAdd) {
- checkNotNull(rangeToAdd);
-
- if (rangeToAdd.isEmpty()) {
- return;
- }
-
- // We will use { } to illustrate ranges currently in the range set, and < >
- // to illustrate rangeToAdd.
- Cut<C> lbToAdd = rangeToAdd.lowerBound;
- Cut<C> ubToAdd = rangeToAdd.upperBound;
-
- Entry<Cut<C>, Range<C>> entryBelowLB = rangesByLowerBound.lowerEntry(lbToAdd);
- if (entryBelowLB != null) {
- // { <
- Range<C> rangeBelowLB = entryBelowLB.getValue();
- if (rangeBelowLB.upperBound.compareTo(lbToAdd) >= 0) {
- // { < }, and we will need to coalesce
- if (rangeBelowLB.upperBound.compareTo(ubToAdd) >= 0) {
- // { < > }
- ubToAdd = rangeBelowLB.upperBound;
- /*
- * TODO(cpovirk): can we just "return;" here? Or, can we remove this if() entirely? If
- * not, add tests to demonstrate the problem with each approach
- */
- }
- lbToAdd = rangeBelowLB.lowerBound;
- }
- }
-
- Entry<Cut<C>, Range<C>> entryBelowUB = rangesByLowerBound.floorEntry(ubToAdd);
- if (entryBelowUB != null) {
- // { >
- Range<C> rangeBelowUB = entryBelowUB.getValue();
- if (rangeBelowUB.upperBound.compareTo(ubToAdd) >= 0) {
- // { > }, and we need to coalesce
- ubToAdd = rangeBelowUB.upperBound;
- }
- }
-
- // Remove ranges which are strictly enclosed.
- rangesByLowerBound.subMap(lbToAdd, ubToAdd).clear();
-
- replaceRangeWithSameLowerBound(Range.create(lbToAdd, ubToAdd));
- }
-
- @Override
- public void remove(Range<C> rangeToRemove) {
- checkNotNull(rangeToRemove);
-
- if (rangeToRemove.isEmpty()) {
- return;
- }
-
- // We will use { } to illustrate ranges currently in the range set, and < >
- // to illustrate rangeToRemove.
-
- Entry<Cut<C>, Range<C>> entryBelowLB = rangesByLowerBound.lowerEntry(rangeToRemove.lowerBound);
- if (entryBelowLB != null) {
- // { <
- Range<C> rangeBelowLB = entryBelowLB.getValue();
- if (rangeBelowLB.upperBound.compareTo(rangeToRemove.lowerBound) >= 0) {
- // { < }, and we will need to subdivide
- if (rangeToRemove.hasUpperBound()
- && rangeBelowLB.upperBound.compareTo(rangeToRemove.upperBound) >= 0) {
- // { < > }
- replaceRangeWithSameLowerBound(
- Range.create(rangeToRemove.upperBound, rangeBelowLB.upperBound));
- }
- replaceRangeWithSameLowerBound(
- Range.create(rangeBelowLB.lowerBound, rangeToRemove.lowerBound));
- }
- }
-
- Entry<Cut<C>, Range<C>> entryBelowUB = rangesByLowerBound.floorEntry(rangeToRemove.upperBound);
- if (entryBelowUB != null) {
- // { >
- Range<C> rangeBelowUB = entryBelowUB.getValue();
- if (rangeToRemove.hasUpperBound()
- && rangeBelowUB.upperBound.compareTo(rangeToRemove.upperBound) >= 0) {
- // { > }
- replaceRangeWithSameLowerBound(
- Range.create(rangeToRemove.upperBound, rangeBelowUB.upperBound));
- }
- }
-
- rangesByLowerBound.subMap(rangeToRemove.lowerBound, rangeToRemove.upperBound).clear();
- }
-
- private void replaceRangeWithSameLowerBound(Range<C> range) {
- if (range.isEmpty()) {
- rangesByLowerBound.remove(range.lowerBound);
- } else {
- rangesByLowerBound.put(range.lowerBound, range);
- }
- }
-
- private transient RangeSet<C> complement;
-
- @Override
- public RangeSet<C> complement() {
- RangeSet<C> result = complement;
- return (result == null) ? complement = new Complement() : result;
- }
-
- @VisibleForTesting
- static final class RangesByUpperBound<C extends Comparable<?>>
- extends AbstractNavigableMap<Cut<C>, Range<C>> {
- private final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound;
-
- /**
- * upperBoundWindow represents the headMap/subMap/tailMap view of the entire "ranges by upper
- * bound" map; it's a constraint on the *keys*, and does not affect the values.
- */
- private final Range<Cut<C>> upperBoundWindow;
-
- RangesByUpperBound(NavigableMap<Cut<C>, Range<C>> rangesByLowerBound) {
- this.rangesByLowerBound = rangesByLowerBound;
- this.upperBoundWindow = Range.all();
- }
-
- private RangesByUpperBound(
- NavigableMap<Cut<C>, Range<C>> rangesByLowerBound, Range<Cut<C>> upperBoundWindow) {
- this.rangesByLowerBound = rangesByLowerBound;
- this.upperBoundWindow = upperBoundWindow;
- }
-
- private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> window) {
- if (window.isConnected(upperBoundWindow)) {
- return new RangesByUpperBound<C>(rangesByLowerBound, window.intersection(upperBoundWindow));
- } else {
- return ImmutableSortedMap.of();
- }
- }
-
- @Override
- public NavigableMap<Cut<C>, Range<C>> subMap(
- Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) {
- return subMap(Range.range(
- fromKey, BoundType.forBoolean(fromInclusive),
- toKey, BoundType.forBoolean(toInclusive)));
- }
-
- @Override
- public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) {
- return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
- }
-
- @Override
- public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean inclusive) {
- return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
- }
-
- @Override
- public Comparator<? super Cut<C>> comparator() {
- return Ordering.<Cut<C>>natural();
- }
-
- @Override
- public boolean containsKey(@Nullable Object key) {
- return get(key) != null;
- }
-
- @Override
- public Range<C> get(@Nullable Object key) {
- if (key instanceof Cut) {
- try {
- @SuppressWarnings("unchecked") // we catch CCEs
- Cut<C> cut = (Cut<C>) key;
- if (!upperBoundWindow.contains(cut)) {
- return null;
- }
- Entry<Cut<C>, Range<C>> candidate = rangesByLowerBound.lowerEntry(cut);
- if (candidate != null && candidate.getValue().upperBound.equals(cut)) {
- return candidate.getValue();
- }
- } catch (ClassCastException e) {
- return null;
- }
- }
- return null;
- }
-
- @Override
- Iterator<Entry<Cut<C>, Range<C>>> entryIterator() {
- /*
- * We want to start the iteration at the first range where the upper bound is in
- * upperBoundWindow.
- */
- final Iterator<Range<C>> backingItr;
- if (!upperBoundWindow.hasLowerBound()) {
- backingItr = rangesByLowerBound.values().iterator();
- } else {
- Entry<Cut<C>, Range<C>> lowerEntry =
- rangesByLowerBound.lowerEntry(upperBoundWindow.lowerEndpoint());
- if (lowerEntry == null) {
- backingItr = rangesByLowerBound.values().iterator();
- } else if (upperBoundWindow.lowerBound.isLessThan(lowerEntry.getValue().upperBound)) {
- backingItr = rangesByLowerBound.tailMap(lowerEntry.getKey(), true).values().iterator();
- } else {
- backingItr = rangesByLowerBound.tailMap(upperBoundWindow.lowerEndpoint(), true)
- .values().iterator();
- }
- }
- return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
- @Override
- protected Entry<Cut<C>, Range<C>> computeNext() {
- if (!backingItr.hasNext()) {
- return endOfData();
- }
- Range<C> range = backingItr.next();
- if (upperBoundWindow.upperBound.isLessThan(range.upperBound)) {
- return endOfData();
- } else {
- return Maps.immutableEntry(range.upperBound, range);
- }
- }
- };
- }
-
- @Override
- Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() {
- Collection<Range<C>> candidates;
- if (upperBoundWindow.hasUpperBound()) {
- candidates = rangesByLowerBound.headMap(upperBoundWindow.upperEndpoint(), false)
- .descendingMap().values();
- } else {
- candidates = rangesByLowerBound.descendingMap().values();
- }
- final PeekingIterator<Range<C>> backingItr = Iterators.peekingIterator(candidates.iterator());
- if (backingItr.hasNext()
- && upperBoundWindow.upperBound.isLessThan(backingItr.peek().upperBound)) {
- backingItr.next();
- }
- return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
- @Override
- protected Entry<Cut<C>, Range<C>> computeNext() {
- if (!backingItr.hasNext()) {
- return endOfData();
- }
- Range<C> range = backingItr.next();
- return upperBoundWindow.lowerBound.isLessThan(range.upperBound)
- ? Maps.immutableEntry(range.upperBound, range)
- : endOfData();
- }
- };
- }
-
- @Override
- public int size() {
- if (upperBoundWindow.equals(Range.all())) {
- return rangesByLowerBound.size();
- }
- return Iterators.size(entryIterator());
- }
-
- @Override
- public boolean isEmpty() {
- return upperBoundWindow.equals(Range.all())
- ? rangesByLowerBound.isEmpty()
- : !entryIterator().hasNext();
- }
- }
-
- private static final class ComplementRangesByLowerBound<C extends Comparable<?>>
- extends AbstractNavigableMap<Cut<C>, Range<C>> {
- private final NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound;
- private final NavigableMap<Cut<C>, Range<C>> positiveRangesByUpperBound;
-
- /**
- * complementLowerBoundWindow represents the headMap/subMap/tailMap view of the entire
- * "complement ranges by lower bound" map; it's a constraint on the *keys*, and does not affect
- * the values.
- */
- private final Range<Cut<C>> complementLowerBoundWindow;
-
- ComplementRangesByLowerBound(NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound) {
- this(positiveRangesByLowerBound, Range.<Cut<C>>all());
- }
-
- private ComplementRangesByLowerBound(NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound,
- Range<Cut<C>> window) {
- this.positiveRangesByLowerBound = positiveRangesByLowerBound;
- this.positiveRangesByUpperBound = new RangesByUpperBound<C>(positiveRangesByLowerBound);
- this.complementLowerBoundWindow = window;
- }
-
- private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> subWindow) {
- if (!complementLowerBoundWindow.isConnected(subWindow)) {
- return ImmutableSortedMap.of();
- } else {
- subWindow = subWindow.intersection(complementLowerBoundWindow);
- return new ComplementRangesByLowerBound<C>(positiveRangesByLowerBound, subWindow);
- }
- }
-
- @Override
- public NavigableMap<Cut<C>, Range<C>> subMap(
- Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) {
- return subMap(Range.range(
- fromKey, BoundType.forBoolean(fromInclusive),
- toKey, BoundType.forBoolean(toInclusive)));
- }
-
- @Override
- public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) {
- return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
- }
-
- @Override
- public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean inclusive) {
- return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
- }
-
- @Override
- public Comparator<? super Cut<C>> comparator() {
- return Ordering.<Cut<C>>natural();
- }
-
- @Override
- Iterator<Entry<Cut<C>, Range<C>>> entryIterator() {
- /*
- * firstComplementRangeLowerBound is the first complement range lower bound inside
- * complementLowerBoundWindow. Complement range lower bounds are either positive range upper
- * bounds, or Cut.belowAll().
- *
- * positiveItr starts at the first positive range with lower bound greater than
- * firstComplementRangeLowerBound. (Positive range lower bounds correspond to complement range
- * upper bounds.)
- */
- Collection<Range<C>> positiveRanges;
- if (complementLowerBoundWindow.hasLowerBound()) {
- positiveRanges = positiveRangesByUpperBound.tailMap(
- complementLowerBoundWindow.lowerEndpoint(),
- complementLowerBoundWindow.lowerBoundType() == BoundType.CLOSED).values();
- } else {
- positiveRanges = positiveRangesByUpperBound.values();
- }
- final PeekingIterator<Range<C>> positiveItr = Iterators.peekingIterator(
- positiveRanges.iterator());
- final Cut<C> firstComplementRangeLowerBound;
- if (complementLowerBoundWindow.contains(Cut.<C>belowAll()) &&
- (!positiveItr.hasNext() || positiveItr.peek().lowerBound != Cut.<C>belowAll())) {
- firstComplementRangeLowerBound = Cut.belowAll();
- } else if (positiveItr.hasNext()) {
- firstComplementRangeLowerBound = positiveItr.next().upperBound;
- } else {
- return Iterators.emptyIterator();
- }
- return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
- Cut<C> nextComplementRangeLowerBound = firstComplementRangeLowerBound;
-
- @Override
- protected Entry<Cut<C>, Range<C>> computeNext() {
- if (complementLowerBoundWindow.upperBound.isLessThan(nextComplementRangeLowerBound)
- || nextComplementRangeLowerBound == Cut.<C>aboveAll()) {
- return endOfData();
- }
- Range<C> negativeRange;
- if (positiveItr.hasNext()) {
- Range<C> positiveRange = positiveItr.next();
- negativeRange = Range.create(nextComplementRangeLowerBound, positiveRange.lowerBound);
- nextComplementRangeLowerBound = positiveRange.upperBound;
- } else {
- negativeRange = Range.create(nextComplementRangeLowerBound, Cut.<C>aboveAll());
- nextComplementRangeLowerBound = Cut.aboveAll();
- }
- return Maps.immutableEntry(negativeRange.lowerBound, negativeRange);
- }
- };
- }
-
- @Override
- Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() {
- Iterator<Range<C>> itr;
- /*
- * firstComplementRangeUpperBound is the upper bound of the last complement range with lower
- * bound inside complementLowerBoundWindow.
- *
- * positiveItr starts at the first positive range with upper bound less than
- * firstComplementRangeUpperBound. (Positive range upper bounds correspond to complement range
- * lower bounds.)
- */
- Cut<C> startingPoint = complementLowerBoundWindow.hasUpperBound()
- ? complementLowerBoundWindow.upperEndpoint()
- : Cut.<C>aboveAll();
- boolean inclusive = complementLowerBoundWindow.hasUpperBound()
- && complementLowerBoundWindow.upperBoundType() == BoundType.CLOSED;
- final PeekingIterator<Range<C>> positiveItr =
- Iterators.peekingIterator(positiveRangesByUpperBound.headMap(startingPoint, inclusive)
- .descendingMap().values().iterator());
- Cut<C> cut;
- if (positiveItr.hasNext()) {
- cut = (positiveItr.peek().upperBound == Cut.<C>aboveAll())
- ? positiveItr.next().lowerBound
- : positiveRangesByLowerBound.higherKey(positiveItr.peek().upperBound);
- } else if (!complementLowerBoundWindow.contains(Cut.<C>belowAll())
- || positiveRangesByLowerBound.containsKey(Cut.belowAll())) {
- return Iterators.emptyIterator();
- } else {
- cut = positiveRangesByLowerBound.higherKey(Cut.<C>belowAll());
- }
- final Cut<C> firstComplementRangeUpperBound = Objects.firstNonNull(cut, Cut.<C>aboveAll());
- return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
- Cut<C> nextComplementRangeUpperBound = firstComplementRangeUpperBound;
-
- @Override
- protected Entry<Cut<C>, Range<C>> computeNext() {
- if (nextComplementRangeUpperBound == Cut.<C>belowAll()) {
- return endOfData();
- } else if (positiveItr.hasNext()) {
- Range<C> positiveRange = positiveItr.next();
- Range<C> negativeRange =
- Range.create(positiveRange.upperBound, nextComplementRangeUpperBound);
- nextComplementRangeUpperBound = positiveRange.lowerBound;
- if (complementLowerBoundWindow.lowerBound.isLessThan(negativeRange.lowerBound)) {
- return Maps.immutableEntry(negativeRange.lowerBound, negativeRange);
- }
- } else if (complementLowerBoundWindow.lowerBound.isLessThan(Cut.<C>belowAll())) {
- Range<C> negativeRange =
- Range.create(Cut.<C>belowAll(), nextComplementRangeUpperBound);
- nextComplementRangeUpperBound = Cut.belowAll();
- return Maps.immutableEntry(Cut.<C>belowAll(), negativeRange);
- }
- return endOfData();
- }
- };
- }
-
- @Override
- public int size() {
- return Iterators.size(entryIterator());
- }
-
- @Override
- @Nullable
- public Range<C> get(Object key) {
- if (key instanceof Cut) {
- try {
- @SuppressWarnings("unchecked")
- Cut<C> cut = (Cut<C>) key;
- // tailMap respects the current window
- Entry<Cut<C>, Range<C>> firstEntry = tailMap(cut, true).firstEntry();
- if (firstEntry != null && firstEntry.getKey().equals(cut)) {
- return firstEntry.getValue();
- }
- } catch (ClassCastException e) {
- return null;
- }
- }
- return null;
- }
-
- @Override
- public boolean containsKey(Object key) {
- return get(key) != null;
- }
- }
-
- private final class Complement extends TreeRangeSet<C> {
- Complement() {
- super(new ComplementRangesByLowerBound<C>(TreeRangeSet.this.rangesByLowerBound));
- }
-
- @Override
- public void add(Range<C> rangeToAdd) {
- TreeRangeSet.this.remove(rangeToAdd);
- }
-
- @Override
- public void remove(Range<C> rangeToRemove) {
- TreeRangeSet.this.add(rangeToRemove);
- }
-
- @Override
- public boolean contains(C value) {
- return !TreeRangeSet.this.contains(value);
- }
-
- @Override
- public RangeSet<C> complement() {
- return TreeRangeSet.this;
- }
- }
-
- private static final class SubRangeSetRangesByLowerBound<C extends Comparable<?>>
- extends AbstractNavigableMap<Cut<C>, Range<C>> {
- /**
- * lowerBoundWindow is the headMap/subMap/tailMap view; it only restricts the keys, and does not
- * affect the values.
- */
- private final Range<Cut<C>> lowerBoundWindow;
-
- /**
- * restriction is the subRangeSet view; ranges are truncated to their intersection with
- * restriction.
- */
- private final Range<C> restriction;
-
- private final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound;
- private final NavigableMap<Cut<C>, Range<C>> rangesByUpperBound;
-
- private SubRangeSetRangesByLowerBound(Range<Cut<C>> lowerBoundWindow, Range<C> restriction,
- NavigableMap<Cut<C>, Range<C>> rangesByLowerBound) {
- this.lowerBoundWindow = checkNotNull(lowerBoundWindow);
- this.restriction = checkNotNull(restriction);
- this.rangesByLowerBound = checkNotNull(rangesByLowerBound);
- this.rangesByUpperBound = new RangesByUpperBound<C>(rangesByLowerBound);
- }
-
- private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> window) {
- if (!window.isConnected(lowerBoundWindow)) {
- return ImmutableSortedMap.of();
- } else {
- return new SubRangeSetRangesByLowerBound<C>(
- lowerBoundWindow.intersection(window), restriction, rangesByLowerBound);
- }
- }
-
- @Override
- public NavigableMap<Cut<C>, Range<C>> subMap(
- Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) {
- return subMap(Range.range(
- fromKey, BoundType.forBoolean(fromInclusive), toKey, BoundType.forBoolean(toInclusive)));
- }
-
- @Override
- public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) {
- return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
- }
-
- @Override
- public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean inclusive) {
- return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
- }
-
- @Override
- public Comparator<? super Cut<C>> comparator() {
- return Ordering.<Cut<C>>natural();
- }
-
- @Override
- public boolean containsKey(@Nullable Object key) {
- return get(key) != null;
- }
-
- @Override
- @Nullable
- public Range<C> get(@Nullable Object key) {
- if (key instanceof Cut) {
- try {
- @SuppressWarnings("unchecked") // we catch CCE's
- Cut<C> cut = (Cut<C>) key;
- if (!lowerBoundWindow.contains(cut) || cut.compareTo(restriction.lowerBound) < 0
- || cut.compareTo(restriction.upperBound) >= 0) {
- return null;
- } else if (cut.equals(restriction.lowerBound)) {
- // it might be present, truncated on the left
- Range<C> candidate = Maps.valueOrNull(rangesByLowerBound.floorEntry(cut));
- if (candidate != null && candidate.upperBound.compareTo(restriction.lowerBound) > 0) {
- return candidate.intersection(restriction);
- }
- } else {
- Range<C> result = rangesByLowerBound.get(cut);
- if (result != null) {
- return result.intersection(restriction);
- }
- }
- } catch (ClassCastException e) {
- return null;
- }
- }
- return null;
- }
-
- @Override
- Iterator<Entry<Cut<C>, Range<C>>> entryIterator() {
- if (restriction.isEmpty()) {
- return Iterators.emptyIterator();
- }
- final Iterator<Range<C>> completeRangeItr;
- if (lowerBoundWindow.upperBound.isLessThan(restriction.lowerBound)) {
- return Iterators.emptyIterator();
- } else if (lowerBoundWindow.lowerBound.isLessThan(restriction.lowerBound)) {
- // starts at the first range with upper bound strictly greater than restriction.lowerBound
- completeRangeItr =
- rangesByUpperBound.tailMap(restriction.lowerBound, false).values().iterator();
- } else {
- // starts at the first range with lower bound above lowerBoundWindow.lowerBound
- completeRangeItr = rangesByLowerBound.tailMap(lowerBoundWindow.lowerBound.endpoint(),
- lowerBoundWindow.lowerBoundType() == BoundType.CLOSED).values().iterator();
- }
- final Cut<Cut<C>> upperBoundOnLowerBounds = Ordering.natural()
- .min(lowerBoundWindow.upperBound, Cut.belowValue(restriction.upperBound));
- return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
- @Override
- protected Entry<Cut<C>, Range<C>> computeNext() {
- if (!completeRangeItr.hasNext()) {
- return endOfData();
- }
- Range<C> nextRange = completeRangeItr.next();
- if (upperBoundOnLowerBounds.isLessThan(nextRange.lowerBound)) {
- return endOfData();
- } else {
- nextRange = nextRange.intersection(restriction);
- return Maps.immutableEntry(nextRange.lowerBound, nextRange);
- }
- }
- };
- }
-
- @Override
- Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() {
- if (restriction.isEmpty()) {
- return Iterators.emptyIterator();
- }
- Cut<Cut<C>> upperBoundOnLowerBounds = Ordering.natural()
- .min(lowerBoundWindow.upperBound, Cut.belowValue(restriction.upperBound));
- final Iterator<Range<C>> completeRangeItr = rangesByLowerBound.headMap(
- upperBoundOnLowerBounds.endpoint(),
- upperBoundOnLowerBounds.typeAsUpperBound() == BoundType.CLOSED)
- .descendingMap().values().iterator();
- return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
- @Override
- protected Entry<Cut<C>, Range<C>> computeNext() {
- if (!completeRangeItr.hasNext()) {
- return endOfData();
- }
- Range<C> nextRange = completeRangeItr.next();
- if (restriction.lowerBound.compareTo(nextRange.upperBound) >= 0) {
- return endOfData();
- }
- nextRange = nextRange.intersection(restriction);
- if (lowerBoundWindow.contains(nextRange.lowerBound)) {
- return Maps.immutableEntry(nextRange.lowerBound, nextRange);
- } else {
- return endOfData();
- }
- }
- };
- }
-
- @Override
- public int size() {
- return Iterators.size(entryIterator());
- }
- }
-
- @Override
- public RangeSet<C> subRangeSet(Range<C> view) {
- return view.equals(Range.<C>all()) ? this : new SubRangeSet(view);
- }
-
- private final class SubRangeSet extends TreeRangeSet<C> {
- private final Range<C> restriction;
-
- SubRangeSet(Range<C> restriction) {
- super(new SubRangeSetRangesByLowerBound<C>(
- Range.<Cut<C>>all(), restriction, TreeRangeSet.this.rangesByLowerBound));
- this.restriction = restriction;
- }
-
- @Override
- public boolean encloses(Range<C> range) {
- if (!restriction.isEmpty() && restriction.encloses(range)) {
- Range<C> enclosing = TreeRangeSet.this.rangeEnclosing(range);
- return enclosing != null && !enclosing.intersection(restriction).isEmpty();
- }
- return false;
- }
-
- @Override
- @Nullable
- public Range<C> rangeContaining(C value) {
- if (!restriction.contains(value)) {
- return null;
- }
- Range<C> result = TreeRangeSet.this.rangeContaining(value);
- return (result == null) ? null : result.intersection(restriction);
- }
-
- @Override
- public void add(Range<C> rangeToAdd) {
- checkArgument(restriction.encloses(rangeToAdd), "Cannot add range %s to subRangeSet(%s)",
- rangeToAdd, restriction);
- super.add(rangeToAdd);
- }
-
- @Override
- public void remove(Range<C> rangeToRemove) {
- if (rangeToRemove.isConnected(restriction)) {
- TreeRangeSet.this.remove(rangeToRemove.intersection(restriction));
- }
- }
-
- @Override
- public boolean contains(C value) {
- return restriction.contains(value) && TreeRangeSet.this.contains(value);
- }
-
- @Override
- public void clear() {
- TreeRangeSet.this.remove(restriction);
- }
-
- @Override
- public RangeSet<C> subRangeSet(Range<C> view) {
- if (view.encloses(restriction)) {
- return this;
- } else if (view.isConnected(restriction)) {
- return new SubRangeSet(restriction.intersection(view));
- } else {
- return ImmutableRangeSet.of();
- }
- }
- }
-}
diff --git a/guava/src/com/google/common/collect/UnmodifiableIterator.java b/guava/src/com/google/common/collect/UnmodifiableIterator.java
index 55ceef9..5cff61b 100644
--- a/guava/src/com/google/common/collect/UnmodifiableIterator.java
+++ b/guava/src/com/google/common/collect/UnmodifiableIterator.java
@@ -30,14 +30,12 @@ import java.util.Iterator;
public abstract class UnmodifiableIterator<E> implements Iterator<E> {
/** Constructor for use by subclasses. */
protected UnmodifiableIterator() {}
-
+
/**
* Guaranteed to throw an exception and leave the underlying data unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public final void remove() {
throw new UnsupportedOperationException();
diff --git a/guava/src/com/google/common/collect/UnmodifiableListIterator.java b/guava/src/com/google/common/collect/UnmodifiableListIterator.java
index 8e535a3..fa71bdc 100644
--- a/guava/src/com/google/common/collect/UnmodifiableListIterator.java
+++ b/guava/src/com/google/common/collect/UnmodifiableListIterator.java
@@ -37,9 +37,8 @@ public abstract class UnmodifiableListIterator<E>
* Guaranteed to throw an exception and leave the underlying data unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated @Override public final void add(E e) {
+ @Override public final void add(E e) {
throw new UnsupportedOperationException();
}
@@ -47,9 +46,8 @@ public abstract class UnmodifiableListIterator<E>
* Guaranteed to throw an exception and leave the underlying data unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated @Override public final void set(E e) {
+ @Override public final void set(E e) {
throw new UnsupportedOperationException();
}
}
diff --git a/guava/src/com/google/common/collect/UnmodifiableSortedMultiset.java b/guava/src/com/google/common/collect/UnmodifiableSortedMultiset.java
deleted file mode 100644
index 4b353cb..0000000
--- a/guava/src/com/google/common/collect/UnmodifiableSortedMultiset.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.collect.Multisets.UnmodifiableMultiset;
-
-import java.util.Comparator;
-import java.util.NavigableSet;
-
-/**
- * Implementation of {@link Multisets#unmodifiableSortedMultiset(SortedMultiset)},
- * split out into its own file so it can be GWT emulated (to deal with the differing
- * elementSet() types in GWT and non-GWT).
- *
- * @author Louis Wasserman
- */
-@GwtCompatible(emulated = true)
-final class UnmodifiableSortedMultiset<E>
- extends UnmodifiableMultiset<E> implements SortedMultiset<E> {
- UnmodifiableSortedMultiset(SortedMultiset<E> delegate) {
- super(delegate);
- }
-
- @Override
- protected SortedMultiset<E> delegate() {
- return (SortedMultiset<E>) super.delegate();
- }
-
- @Override
- public Comparator<? super E> comparator() {
- return delegate().comparator();
- }
-
- @Override
- NavigableSet<E> createElementSet() {
- return Sets.unmodifiableNavigableSet(delegate().elementSet());
- }
-
- @Override
- public NavigableSet<E> elementSet() {
- return (NavigableSet<E>) super.elementSet();
- }
-
- private transient UnmodifiableSortedMultiset<E> descendingMultiset;
-
- @Override
- public SortedMultiset<E> descendingMultiset() {
- UnmodifiableSortedMultiset<E> result = descendingMultiset;
- if (result == null) {
- result = new UnmodifiableSortedMultiset<E>(
- delegate().descendingMultiset());
- result.descendingMultiset = this;
- return descendingMultiset = result;
- }
- return result;
- }
-
- @Override
- public Entry<E> firstEntry() {
- return delegate().firstEntry();
- }
-
- @Override
- public Entry<E> lastEntry() {
- return delegate().lastEntry();
- }
-
- @Override
- public Entry<E> pollFirstEntry() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Entry<E> pollLastEntry() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public SortedMultiset<E> headMultiset(E upperBound, BoundType boundType) {
- return Multisets.unmodifiableSortedMultiset(
- delegate().headMultiset(upperBound, boundType));
- }
-
- @Override
- public SortedMultiset<E> subMultiset(
- E lowerBound, BoundType lowerBoundType,
- E upperBound, BoundType upperBoundType) {
- return Multisets.unmodifiableSortedMultiset(delegate().subMultiset(
- lowerBound, lowerBoundType, upperBound, upperBoundType));
- }
-
- @Override
- public SortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType) {
- return Multisets.unmodifiableSortedMultiset(
- delegate().tailMultiset(lowerBound, boundType));
- }
-
- private static final long serialVersionUID = 0;
-} \ No newline at end of file
diff --git a/guava/src/com/google/common/collect/UsingToStringOrdering.java b/guava/src/com/google/common/collect/UsingToStringOrdering.java
index adb6aa7..d1c9feb 100644
--- a/guava/src/com/google/common/collect/UsingToStringOrdering.java
+++ b/guava/src/com/google/common/collect/UsingToStringOrdering.java
@@ -20,10 +20,7 @@ import com.google.common.annotations.GwtCompatible;
import java.io.Serializable;
-/**
- * An ordering that uses the natural order of the string representation of the
- * values.
- */
+/** An ordering that uses the reverse of the natural order of the values. */
@GwtCompatible(serializable = true)
final class UsingToStringOrdering
extends Ordering<Object> implements Serializable {
diff --git a/guava/src/com/google/common/collect/WellBehavedMap.java b/guava/src/com/google/common/collect/WellBehavedMap.java
index c68cc5e..e8aa1f6 100644
--- a/guava/src/com/google/common/collect/WellBehavedMap.java
+++ b/guava/src/com/google/common/collect/WellBehavedMap.java
@@ -18,35 +18,32 @@ package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
-import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
- * Workaround for
+ * Workaround for
* <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6312706">
* EnumMap bug</a>. If you want to pass an {@code EnumMap}, with the
* intention of using its {@code entrySet()} method, you should
- * wrap the {@code EnumMap} in this class instead.
- *
- * <p>This class is not thread-safe even if the underlying map is.
- *
+ * wrap the {@code EnumMap} in this class instead.
+ *
* @author Dimitris Andreou
*/
@GwtCompatible
final class WellBehavedMap<K, V> extends ForwardingMap<K, V> {
private final Map<K, V> delegate;
private Set<Entry<K, V>> entrySet;
-
+
private WellBehavedMap(Map<K, V> delegate) {
this.delegate = delegate;
}
-
+
/**
* Wraps the given map into a {@code WellBehavedEntriesMap}, which
- * intercepts its {@code entrySet()} method by taking the
+ * intercepts its {@code entrySet()} method by taking the
* {@code Set<K> keySet()} and transforming it to
- * {@code Set<Entry<K, V>>}. All other invocations are delegated as-is.
+ * {@code Set<Entry<K, V>>}. All other invocations are delegated as-is.
*/
static <K, V> WellBehavedMap<K, V> wrap(Map<K, V> delegate) {
return new WellBehavedMap<K, V>(delegate);
@@ -61,38 +58,34 @@ final class WellBehavedMap<K, V> extends ForwardingMap<K, V> {
if (es != null) {
return es;
}
- return entrySet = new EntrySet();
+ return entrySet = Sets.transform(
+ delegate.keySet(), new KeyToEntryConverter<K, V>(this));
}
-
- private final class EntrySet extends Maps.EntrySet<K, V> {
- @Override
- Map<K, V> map() {
- return WellBehavedMap.this;
+
+ private static class KeyToEntryConverter<K, V>
+ extends Sets.InvertibleFunction<K, Map.Entry<K, V>> {
+ final Map<K, V> map;
+
+ KeyToEntryConverter(Map<K, V> map) {
+ this.map = map;
}
- @Override
- public Iterator<Entry<K, V>> iterator() {
- return new TransformedIterator<K, Entry<K, V>>(keySet().iterator()) {
- @Override
- Entry<K, V> transform(final K key) {
- return new AbstractMapEntry<K, V>() {
- @Override
- public K getKey() {
- return key;
- }
-
- @Override
- public V getValue() {
- return get(key);
- }
-
- @Override
- public V setValue(V value) {
- return put(key, value);
- }
- };
+ @Override public Map.Entry<K, V> apply(final K key) {
+ return new AbstractMapEntry<K, V>() {
+ @Override public K getKey() {
+ return key;
+ }
+ @Override public V getValue() {
+ return map.get(key);
+ }
+ @Override public V setValue(V value) {
+ return map.put(key, value);
}
};
}
+
+ @Override public K invert(Map.Entry<K, V> entry) {
+ return entry.getKey();
+ }
}
}
diff --git a/guava/src/com/google/common/collect/package-info.java b/guava/src/com/google/common/collect/package-info.java
index 3ffbad9..f5c833c 100644
--- a/guava/src/com/google/common/collect/package-info.java
+++ b/guava/src/com/google/common/collect/package-info.java
@@ -85,7 +85,7 @@
* <ul>
* <li>{@link com.google.common.collect.ImmutableSet}
* <li>{@link com.google.common.collect.ImmutableSortedSet}
- * <li>{@link com.google.common.collect.ContiguousSet} (see {@code Range})
+ * <li>{@link com.google.common.collect.ContiguousSet} (see {@code Ranges})
* </ul>
*
* <h3>of {@link java.util.Map}</h3>
@@ -147,10 +147,10 @@
* <li>{@link com.google.common.collect.Iterables}
* <li>{@link com.google.common.collect.Lists}
* <li>{@link com.google.common.collect.Maps}
- * <li>{@link com.google.common.collect.Queues}
* <li>{@link com.google.common.collect.Sets}
* <li>{@link com.google.common.collect.Multisets}
* <li>{@link com.google.common.collect.Multimaps}
+ * <li>{@link com.google.common.collect.SortedMaps}
* <li>{@link com.google.common.collect.Tables}
* <li>{@link com.google.common.collect.ObjectArrays}
* </ul>
@@ -166,7 +166,7 @@
*
* <ul>
* <li>{@link com.google.common.collect.AbstractIterator}
- * <li>{@link com.google.common.collect.AbstractSequentialIterator}
+ * <li>{@link com.google.common.collect.AbstractLinkedIterator}
* <li>{@link com.google.common.collect.ImmutableCollection}
* <li>{@link com.google.common.collect.UnmodifiableIterator}
* <li>{@link com.google.common.collect.UnmodifiableListIterator}
@@ -176,6 +176,7 @@
*
* <ul>
* <li>{@link com.google.common.collect.Range}
+ * <li>{@link com.google.common.collect.Ranges}
* <li>{@link com.google.common.collect.DiscreteDomain}
* <li>{@link com.google.common.collect.DiscreteDomains}
* <li>{@link com.google.common.collect.ContiguousSet}
@@ -209,13 +210,12 @@
* <li>{@link com.google.common.collect.ForwardingMapEntry}
* <li>{@link com.google.common.collect.ForwardingMultimap}
* <li>{@link com.google.common.collect.ForwardingMultiset}
- * <li>{@link com.google.common.collect.ForwardingNavigableMap}
- * <li>{@link com.google.common.collect.ForwardingNavigableSet}
* <li>{@link com.google.common.collect.ForwardingObject}
* <li>{@link com.google.common.collect.ForwardingQueue}
* <li>{@link com.google.common.collect.ForwardingSet}
* <li>{@link com.google.common.collect.ForwardingSetMultimap}
* <li>{@link com.google.common.collect.ForwardingSortedMap}
+ * <li>{@link com.google.common.collect.ForwardingSortedMultiset}
* <li>{@link com.google.common.collect.ForwardingSortedSet}
* <li>{@link com.google.common.collect.ForwardingSortedSetMultimap}
* <li>{@link com.google.common.collect.ForwardingTable}